QueryBranchOp.cs 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Dispatcher
  5. {
  6. using System.Collections.Generic;
  7. using System.Runtime;
  8. abstract class JumpOpcode : Opcode
  9. {
  10. Opcode jump;
  11. internal JumpOpcode(OpcodeID id, Opcode jump)
  12. : base(id)
  13. {
  14. this.Jump = jump;
  15. this.flags |= OpcodeFlags.Jump;
  16. }
  17. internal Opcode Jump
  18. {
  19. get
  20. {
  21. return this.jump;
  22. }
  23. set
  24. {
  25. Fx.Assert(value.ID == OpcodeID.BlockEnd, "");
  26. this.AddJump((BlockEndOpcode)value);
  27. }
  28. }
  29. internal void AddJump(BlockEndOpcode jumpTo)
  30. {
  31. bool conditional = this.IsReachableFromConditional();
  32. if (conditional)
  33. {
  34. this.prev.DelinkFromConditional(this);
  35. }
  36. if (null == this.jump)
  37. {
  38. this.jump = jumpTo;
  39. }
  40. else
  41. {
  42. BranchOpcode jumpBranch;
  43. if (this.jump.ID == OpcodeID.Branch)
  44. {
  45. // already a branch
  46. jumpBranch = (BranchOpcode)this.jump;
  47. }
  48. else
  49. {
  50. BlockEndOpcode currentJump = (BlockEndOpcode)this.jump;
  51. jumpBranch = new BranchOpcode();
  52. jumpBranch.Branches.Add(currentJump);
  53. this.jump = jumpBranch;
  54. }
  55. jumpBranch.Branches.Add(jumpTo);
  56. }
  57. jumpTo.LinkJump(this);
  58. if (conditional && null != this.jump)
  59. {
  60. this.prev.LinkToConditional(this);
  61. }
  62. }
  63. internal override void Remove()
  64. {
  65. if (null == this.jump)
  66. {
  67. base.Remove();
  68. }
  69. }
  70. internal void RemoveJump(BlockEndOpcode jumpTo)
  71. {
  72. Fx.Assert(null != this.jump, "");
  73. bool conditional = this.IsReachableFromConditional();
  74. if (conditional)
  75. {
  76. this.prev.DelinkFromConditional(this);
  77. }
  78. if (this.jump.ID == OpcodeID.Branch)
  79. {
  80. BranchOpcode jumpBranch = (BranchOpcode)this.jump;
  81. jumpTo.DeLinkJump(this);
  82. jumpBranch.RemoveChild(jumpTo);
  83. if (0 == jumpBranch.Branches.Count)
  84. {
  85. this.jump = null;
  86. }
  87. }
  88. else
  89. {
  90. Fx.Assert(object.ReferenceEquals(jumpTo, this.jump), "");
  91. jumpTo.DeLinkJump(this);
  92. this.jump = null;
  93. }
  94. if (conditional && null != this.jump)
  95. {
  96. this.prev.LinkToConditional(this);
  97. }
  98. }
  99. internal override void Trim()
  100. {
  101. if (this.jump.ID == OpcodeID.Branch)
  102. {
  103. this.jump.Trim();
  104. }
  105. }
  106. }
  107. class JumpIfOpcode : JumpOpcode
  108. {
  109. protected bool test;
  110. internal JumpIfOpcode(Opcode jump, bool test)
  111. : this(OpcodeID.JumpIfNot, jump, test)
  112. {
  113. }
  114. protected JumpIfOpcode(OpcodeID id, Opcode jump, bool test)
  115. : base(id, jump)
  116. {
  117. this.test = test;
  118. }
  119. internal bool Test
  120. {
  121. get
  122. {
  123. return this.test;
  124. }
  125. }
  126. internal override bool Equals(Opcode op)
  127. {
  128. if (base.Equals(op))
  129. {
  130. return (this.test == ((JumpIfOpcode)op).test);
  131. }
  132. return false;
  133. }
  134. internal override Opcode Eval(ProcessingContext context)
  135. {
  136. Fx.Assert(null != context, "");
  137. StackFrame arg = context.TopArg;
  138. for (int i = arg.basePtr; i <= arg.endPtr; ++i)
  139. {
  140. Fx.Assert(context.Values[i].IsType(ValueDataType.Boolean), "");
  141. if (this.test == context.Values[i].Boolean)
  142. {
  143. // At least one result satisfies the test. Don't branch
  144. return this.next;
  145. }
  146. }
  147. // Jump, since no result is satisfactory..
  148. return this.Jump;
  149. }
  150. #if DEBUG_FILTER
  151. public override string ToString()
  152. {
  153. return string.Format("{0} {1}", base.ToString(), this.test);
  154. }
  155. #endif
  156. }
  157. class ApplyBooleanOpcode : JumpIfOpcode
  158. {
  159. internal ApplyBooleanOpcode(Opcode jump, bool test)
  160. : this(OpcodeID.ApplyBoolean, jump, test)
  161. {
  162. }
  163. protected ApplyBooleanOpcode(OpcodeID id, Opcode jump, bool test)
  164. : base(id, jump, test)
  165. {
  166. }
  167. internal override Opcode Eval(ProcessingContext context)
  168. {
  169. int matchCount = this.UpdateResultMask(context);
  170. context.PopFrame();
  171. if (0 == matchCount)
  172. {
  173. return this.Jump;
  174. }
  175. return this.next;
  176. }
  177. protected int UpdateResultMask(ProcessingContext context)
  178. {
  179. StackFrame results = context.TopArg;
  180. StackFrame resultMask = context.SecondArg;
  181. Value[] values = context.Values;
  182. int testCount = 0;
  183. for (int maskIndex = resultMask.basePtr, resultIndex = results.basePtr; maskIndex <= resultMask.endPtr; ++maskIndex)
  184. {
  185. if (this.test == values[maskIndex].Boolean)
  186. {
  187. bool boolResult = values[resultIndex].Boolean;
  188. if (this.test == boolResult)
  189. {
  190. testCount++;
  191. }
  192. values[maskIndex].Boolean = boolResult;
  193. ++resultIndex;
  194. }
  195. }
  196. return testCount;
  197. }
  198. #if DEBUG_FILTER
  199. public override string ToString()
  200. {
  201. return string.Format("{0} {1}", base.ToString(), this.test);
  202. }
  203. #endif
  204. }
  205. // 'And' booleans: test is true
  206. // 'Or' booleans: test is false
  207. class StartBooleanOpcode : Opcode
  208. {
  209. bool test;
  210. internal StartBooleanOpcode(bool test)
  211. : base(OpcodeID.StartBoolean)
  212. {
  213. this.test = test;
  214. }
  215. internal override bool Equals(Opcode op)
  216. {
  217. if (base.Equals(op))
  218. {
  219. return (((StartBooleanOpcode)op).test == this.test);
  220. }
  221. return false;
  222. }
  223. internal override Opcode Eval(ProcessingContext context)
  224. {
  225. StackFrame sequences = context.TopSequenceArg;
  226. Value[] values = context.Values;
  227. StackFrame resultMask = context.TopArg;
  228. Value[] sequenceBuffer = context.Sequences;
  229. context.PushSequenceFrame();
  230. for (int seqIndex = sequences.basePtr; seqIndex <= sequences.endPtr; ++seqIndex)
  231. {
  232. NodeSequence sourceSeq = sequenceBuffer[seqIndex].Sequence;
  233. if (sourceSeq.Count > 0)
  234. {
  235. NodeSequenceItem[] items = sourceSeq.Items;
  236. NodeSequence newSeq = null;
  237. // Loop over the sequence, selecting those items for which the previous expression returned a result that
  238. // matches the test value. Only those items will be processed further
  239. // Note that the original position and size information is retained.
  240. for (int i = resultMask.basePtr, n = 0; i <= resultMask.endPtr; ++i, ++n)
  241. {
  242. if (this.test == values[i].Boolean)
  243. {
  244. if (null == newSeq)
  245. {
  246. newSeq = context.CreateSequence();
  247. }
  248. newSeq.AddCopy(ref items[n], NodeSequence.GetContextSize(sourceSeq, n));
  249. }
  250. else
  251. {
  252. if (items[n].Last && null != newSeq)
  253. {
  254. newSeq.Items[newSeq.Count - 1].Last = true; // maintain nodeset boundaries...
  255. }
  256. }
  257. }
  258. context.PushSequence((null == newSeq) ? NodeSequence.Empty : newSeq);
  259. newSeq = null;
  260. }
  261. }
  262. return this.next;
  263. }
  264. #if DEBUG_FILTER
  265. public override string ToString()
  266. {
  267. return string.Format("{0} {1}", base.ToString(), this.test);
  268. }
  269. #endif
  270. }
  271. // 'And' booleans: test is true
  272. // 'Or' booleans: test is false
  273. class EndBooleanOpcode : ApplyBooleanOpcode
  274. {
  275. internal EndBooleanOpcode(Opcode jump, bool test)
  276. : base(OpcodeID.EndBoolean, jump, test)
  277. {
  278. }
  279. internal override Opcode Eval(ProcessingContext context)
  280. {
  281. int matchCount = this.UpdateResultMask(context);
  282. context.PopFrame();
  283. context.PopSequenceFrame();
  284. if (0 == matchCount)
  285. {
  286. return this.Jump;
  287. }
  288. return this.next;
  289. }
  290. }
  291. class NoOpOpcode : Opcode
  292. {
  293. internal NoOpOpcode(OpcodeID id)
  294. : base(id)
  295. {
  296. }
  297. }
  298. class BlockEndOpcode : Opcode
  299. {
  300. QueryBuffer<Opcode> sourceJumps;
  301. internal BlockEndOpcode()
  302. : base(OpcodeID.BlockEnd)
  303. {
  304. this.sourceJumps = new QueryBuffer<Opcode>(1);
  305. }
  306. internal void DeLinkJump(Opcode jump)
  307. {
  308. this.sourceJumps.Remove(jump);
  309. }
  310. internal void LinkJump(Opcode jump)
  311. {
  312. this.sourceJumps.Add(jump);
  313. }
  314. internal override void Remove()
  315. {
  316. // Before we can remove this blockEnd from the query tree, we have delink all jumps to it
  317. while (this.sourceJumps.Count > 0)
  318. {
  319. ((JumpOpcode)this.sourceJumps[0]).RemoveJump(this);
  320. }
  321. base.Remove();
  322. }
  323. }
  324. class TypecastOpcode : Opcode
  325. {
  326. ValueDataType newType;
  327. #if NO
  328. internal TypecastOpcode(OpcodeID opcode, ValueDataType newType)
  329. : base(opcode)
  330. {
  331. this.newType = newType;
  332. }
  333. #endif
  334. internal TypecastOpcode(ValueDataType newType)
  335. : base(OpcodeID.Cast)
  336. {
  337. this.newType = newType;
  338. }
  339. internal override bool Equals(Opcode op)
  340. {
  341. if (base.Equals(op))
  342. {
  343. return (this.newType == ((TypecastOpcode)op).newType);
  344. }
  345. return false;
  346. }
  347. internal override Opcode Eval(ProcessingContext context)
  348. {
  349. StackFrame frame = context.TopArg;
  350. Value[] values = context.Values;
  351. for (int i = frame.basePtr; i <= frame.endPtr; ++i)
  352. {
  353. values[i].ConvertTo(context, newType);
  354. }
  355. return this.next;
  356. }
  357. #if DEBUG_FILTER
  358. public override string ToString()
  359. {
  360. return string.Format("{0} {1}", base.ToString(), this.newType.ToString());
  361. }
  362. #endif
  363. }
  364. struct BranchContext
  365. {
  366. ProcessingContext branchContext;
  367. ProcessingContext sourceContext;
  368. internal BranchContext(ProcessingContext context)
  369. {
  370. this.sourceContext = context;
  371. this.branchContext = null;
  372. }
  373. internal ProcessingContext Create()
  374. {
  375. if (null == this.branchContext)
  376. {
  377. this.branchContext = this.sourceContext.Clone();
  378. }
  379. else
  380. {
  381. this.branchContext.CopyFrom(this.sourceContext);
  382. }
  383. return this.branchContext;
  384. }
  385. internal void Release()
  386. {
  387. if (null != this.branchContext)
  388. {
  389. this.branchContext.Release();
  390. }
  391. }
  392. }
  393. class QueryBranch
  394. {
  395. internal Opcode branch;
  396. internal int id;
  397. #if NO
  398. internal QueryBranch(Opcode branch)
  399. : this(branch, int.MinValue)
  400. {
  401. }
  402. #endif
  403. internal QueryBranch(Opcode branch, int id)
  404. {
  405. this.branch = branch;
  406. this.id = id;
  407. }
  408. internal Opcode Branch
  409. {
  410. get
  411. {
  412. return this.branch;
  413. }
  414. #if NO
  415. set
  416. {
  417. this.branch = value;
  418. }
  419. #endif
  420. }
  421. internal int ID
  422. {
  423. get
  424. {
  425. return this.id;
  426. }
  427. }
  428. }
  429. class QueryBranchTable
  430. {
  431. int count;
  432. QueryBranch[] branches;
  433. internal QueryBranchTable()
  434. : this(1)
  435. {
  436. }
  437. internal QueryBranchTable(int capacity)
  438. {
  439. this.branches = new QueryBranch[capacity];
  440. }
  441. internal int Count
  442. {
  443. get
  444. {
  445. return this.count;
  446. }
  447. }
  448. internal QueryBranch this[int index]
  449. {
  450. get
  451. {
  452. return this.branches[index];
  453. }
  454. }
  455. #if NO
  456. internal void Add(QueryBranch entry)
  457. {
  458. Fx.Assert(null != entry, "");
  459. this.InsertAt(this.count, entry);
  460. }
  461. #endif
  462. internal void AddInOrder(QueryBranch branch)
  463. {
  464. // Insert in sorted order always
  465. int index;
  466. for (index = 0; index < this.count; ++index)
  467. {
  468. // if current node is >= key, we've found the spot
  469. if (this.branches[index].ID >= branch.ID)
  470. {
  471. break;
  472. }
  473. }
  474. this.InsertAt(index, branch);
  475. }
  476. void Grow()
  477. {
  478. QueryBranch[] branches = new QueryBranch[this.branches.Length + 1];
  479. Array.Copy(this.branches, branches, this.branches.Length);
  480. this.branches = branches;
  481. }
  482. public int IndexOf(Opcode opcode)
  483. {
  484. for (int i = 0; i < this.count; ++i)
  485. {
  486. if (object.ReferenceEquals(opcode, this.branches[i].Branch))
  487. {
  488. return i;
  489. }
  490. }
  491. return -1;
  492. }
  493. public int IndexOfID(int id)
  494. {
  495. for (int i = 0; i < this.count; ++i)
  496. {
  497. if (this.branches[i].ID == id)
  498. {
  499. return i;
  500. }
  501. }
  502. return -1;
  503. }
  504. #if NO
  505. public int IndexOfEquals(Opcode opcode)
  506. {
  507. for (int i = 0; i < this.count; ++i)
  508. {
  509. if (this.branches[i].Branch.Equals(opcode))
  510. {
  511. return i;
  512. }
  513. }
  514. return -1;
  515. }
  516. #endif
  517. internal void InsertAt(int index, QueryBranch branch)
  518. {
  519. if (this.count == this.branches.Length)
  520. {
  521. this.Grow();
  522. }
  523. if (index < this.count)
  524. {
  525. Array.Copy(this.branches, index, this.branches, index + 1, this.count - index);
  526. }
  527. this.branches[index] = branch;
  528. this.count++;
  529. }
  530. internal bool Remove(Opcode branch)
  531. {
  532. Fx.Assert(null != branch, "");
  533. int index = this.IndexOf(branch);
  534. if (index >= 0)
  535. {
  536. this.RemoveAt(index);
  537. return true;
  538. }
  539. return false;
  540. }
  541. internal void RemoveAt(int index)
  542. {
  543. Fx.Assert(index < this.count, "");
  544. if (index < this.count - 1)
  545. {
  546. Array.Copy(this.branches, index + 1, this.branches, index, this.count - index - 1);
  547. }
  548. else
  549. {
  550. this.branches[index] = null;
  551. }
  552. this.count--;
  553. }
  554. internal void Trim()
  555. {
  556. if (this.count < this.branches.Length)
  557. {
  558. QueryBranch[] branches = new QueryBranch[this.count];
  559. Array.Copy(this.branches, branches, this.count);
  560. this.branches = branches;
  561. }
  562. for (int i = 0; i < this.branches.Length; ++i)
  563. {
  564. if (this.branches[i] != null && this.branches[i].Branch != null)
  565. {
  566. this.branches[i].Branch.Trim();
  567. }
  568. }
  569. }
  570. }
  571. class BranchOpcode : Opcode
  572. {
  573. OpcodeList branches;
  574. internal BranchOpcode()
  575. : this(OpcodeID.Branch)
  576. {
  577. }
  578. internal BranchOpcode(OpcodeID id)
  579. : base(id)
  580. {
  581. this.flags |= OpcodeFlags.Branch;
  582. this.branches = new OpcodeList(2);
  583. }
  584. internal OpcodeList Branches
  585. {
  586. get
  587. {
  588. return this.branches;
  589. }
  590. }
  591. internal override void Add(Opcode opcode)
  592. {
  593. // Add with maximum affinity.. find a similar opcode, if we can, and call its Add method
  594. for (int i = 0; i < this.branches.Count; ++i)
  595. {
  596. if (this.branches[i].IsEquivalentForAdd(opcode))
  597. {
  598. this.branches[i].Add(opcode);
  599. return;
  600. }
  601. }
  602. // Ok.. no similar opcode. Add it just like any other branch
  603. this.AddBranch(opcode);
  604. }
  605. internal override void AddBranch(Opcode opcode)
  606. {
  607. Fx.Assert(null != opcode, "");
  608. // Make sure the same opcode doesn't already exist..
  609. Fx.Assert(-1 == this.branches.IndexOf(opcode), "");
  610. this.branches.Add(opcode);
  611. opcode.Prev = this;
  612. // If this branch is in a conditional, then this new opcode must be added to that conditional..
  613. if (this.IsInConditional())
  614. {
  615. this.LinkToConditional(opcode);
  616. }
  617. }
  618. internal override void CollectXPathFilters(ICollection<MessageFilter> filters)
  619. {
  620. for (int i = 0; i < this.branches.Count; ++i)
  621. {
  622. this.branches[i].CollectXPathFilters(filters);
  623. }
  624. }
  625. internal override void DelinkFromConditional(Opcode child)
  626. {
  627. if (null != this.prev)
  628. {
  629. this.prev.DelinkFromConditional(child);
  630. }
  631. }
  632. internal override Opcode Eval(ProcessingContext context)
  633. {
  634. QueryProcessor processor = context.Processor;
  635. SeekableXPathNavigator contextNode = processor.ContextNode;
  636. int marker = processor.CounterMarker;
  637. long pos = contextNode.CurrentPosition;
  638. Opcode branch;
  639. int i = 0;
  640. int branchCount = this.branches.Count;
  641. try
  642. {
  643. if (context.StacksInUse)
  644. {
  645. // If we have N branches, eval N-1 in a cloned context and the remainder in the
  646. // original one
  647. if (--branchCount > 0)
  648. {
  649. // Evaluate all but the first branch with a clone of the current context
  650. // The first branch (right most) can be evaluated with the current context
  651. BranchContext branchContext = new BranchContext(context); // struct. fast
  652. for (; i < branchCount; ++i)
  653. {
  654. branch = this.branches[i];
  655. if (0 != (branch.Flags & OpcodeFlags.Fx))
  656. {
  657. branch.Eval(context);
  658. }
  659. else
  660. {
  661. // This allocates a solitary context and then reuses it repeatedly
  662. ProcessingContext newContext = branchContext.Create();
  663. while (null != branch)
  664. {
  665. branch = branch.Eval(newContext);
  666. }
  667. }
  668. contextNode.CurrentPosition = pos; // restore the navigator to its original position
  669. processor.CounterMarker = marker; // and the node count marker
  670. }
  671. branchContext.Release();
  672. }
  673. // Do the final branch with the existing context
  674. branch = branches[i];
  675. while (null != branch)
  676. {
  677. branch = branch.Eval(context);
  678. }
  679. }
  680. else // since there is nothing on the stack, there is nothing to clone
  681. {
  682. int nodeCountSav = context.NodeCount;
  683. for (; i < branchCount; ++i)
  684. {
  685. branch = branches[i];
  686. // Evaluate this branch
  687. while (null != branch)
  688. {
  689. branch = branch.Eval(context);
  690. }
  691. // Restore the current context to its pristine state, so we can reuse it
  692. context.ClearContext();
  693. context.NodeCount = nodeCountSav;
  694. contextNode.CurrentPosition = pos;
  695. processor.CounterMarker = marker;
  696. }
  697. }
  698. }
  699. catch (XPathNavigatorException e)
  700. {
  701. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(branches[i]));
  702. }
  703. catch (NavigatorInvalidBodyAccessException e)
  704. {
  705. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(branches[i]));
  706. }
  707. processor.CounterMarker = marker;
  708. return this.next;
  709. }
  710. internal override bool IsInConditional()
  711. {
  712. if (null != this.prev)
  713. {
  714. return this.prev.IsInConditional();
  715. }
  716. return true;
  717. }
  718. internal override void LinkToConditional(Opcode child)
  719. {
  720. if (null != this.prev)
  721. {
  722. this.prev.LinkToConditional(child);
  723. }
  724. }
  725. /// <summary>
  726. /// Loop over all branches, trying to locate one that is equal to the given opcode
  727. /// If the branch is a branch itself, perform the locate recursively.
  728. /// </summary>
  729. /// <param name="opcode"></param>
  730. /// <returns></returns>
  731. internal override Opcode Locate(Opcode opcode)
  732. {
  733. Fx.Assert(!opcode.TestFlag(OpcodeFlags.Branch), "");
  734. for (int i = 0, count = this.branches.Count; i < count; ++i)
  735. {
  736. Opcode branch = this.branches[i];
  737. if (branch.TestFlag(OpcodeFlags.Branch))
  738. {
  739. // The branch is itself a branch. Since branch opcodes serve as branches in the exection
  740. // path for a query, but don't comprise one of the opcodes used to actually perform it, we
  741. // recursively try to locate an equivalent opcode inside the branch
  742. Opcode subBranch = branch.Locate(opcode);
  743. if (null != subBranch)
  744. {
  745. return subBranch;
  746. }
  747. }
  748. else if (branch.Equals(opcode))
  749. {
  750. return branch;
  751. }
  752. }
  753. return null;
  754. }
  755. internal override void Remove()
  756. {
  757. if (0 == this.branches.Count)
  758. {
  759. base.Remove();
  760. }
  761. }
  762. internal override void RemoveChild(Opcode opcode)
  763. {
  764. Fx.Assert(null != opcode, "");
  765. if (this.IsInConditional())
  766. {
  767. this.DelinkFromConditional(opcode);
  768. }
  769. this.branches.Remove(opcode);
  770. this.branches.Trim();
  771. }
  772. internal override void Replace(Opcode replace, Opcode with)
  773. {
  774. int i = this.branches.IndexOf(replace);
  775. if (i >= 0)
  776. {
  777. replace.Prev = null;
  778. this.branches[i] = with;
  779. with.Prev = this;
  780. }
  781. }
  782. internal override void Trim()
  783. {
  784. this.branches.Trim();
  785. for (int i = 0; i < this.branches.Count; ++i)
  786. {
  787. this.branches[i].Trim();
  788. }
  789. }
  790. }
  791. struct QueryBranchResult
  792. {
  793. internal QueryBranch branch;
  794. int valIndex;
  795. internal QueryBranchResult(QueryBranch branch, int valIndex)
  796. {
  797. this.branch = branch;
  798. this.valIndex = valIndex;
  799. }
  800. internal QueryBranch Branch
  801. {
  802. get
  803. {
  804. return this.branch;
  805. }
  806. }
  807. internal int ValIndex
  808. {
  809. get
  810. {
  811. return this.valIndex;
  812. }
  813. }
  814. #if NO
  815. internal void Set(QueryBranch branch, int valIndex)
  816. {
  817. this.branch = branch;
  818. this.valIndex = valIndex;
  819. }
  820. #endif
  821. }
  822. internal class QueryBranchResultSet
  823. {
  824. QueryBuffer<QueryBranchResult> results;
  825. QueryBranchResultSet next;
  826. internal static SortComparer comparer = new SortComparer();
  827. internal QueryBranchResultSet()
  828. : this(2)
  829. {
  830. }
  831. internal QueryBranchResultSet(int capacity)
  832. {
  833. this.results = new QueryBuffer<QueryBranchResult>(capacity);
  834. }
  835. internal int Count
  836. {
  837. get
  838. {
  839. return this.results.count;
  840. }
  841. }
  842. internal QueryBranchResult this[int index]
  843. {
  844. get
  845. {
  846. return this.results[index];
  847. }
  848. }
  849. internal QueryBranchResultSet Next
  850. {
  851. get
  852. {
  853. return this.next;
  854. }
  855. set
  856. {
  857. this.next = value;
  858. }
  859. }
  860. internal void Add(QueryBranch branch, int valIndex)
  861. {
  862. this.results.Add(new QueryBranchResult(branch, valIndex));
  863. }
  864. internal void Clear()
  865. {
  866. this.results.count = 0;
  867. }
  868. internal void Sort()
  869. {
  870. this.results.Sort(QueryBranchResultSet.comparer);
  871. }
  872. internal class SortComparer : IComparer<QueryBranchResult>
  873. {
  874. public bool Equals(QueryBranchResult x, QueryBranchResult y)
  875. {
  876. return x.branch.id == y.branch.id;
  877. }
  878. public int Compare(QueryBranchResult x, QueryBranchResult y)
  879. {
  880. return x.branch.id - y.branch.id;
  881. }
  882. public int GetHashCode(QueryBranchResult obj)
  883. {
  884. return obj.branch.id;
  885. }
  886. }
  887. }
  888. struct BranchMatcher
  889. {
  890. int resultCount;
  891. QueryBranchResultSet resultTable;
  892. internal BranchMatcher(int resultCount, QueryBranchResultSet resultTable)
  893. {
  894. this.resultCount = resultCount;
  895. this.resultTable = resultTable;
  896. }
  897. internal QueryBranchResultSet ResultTable
  898. {
  899. get
  900. {
  901. return this.resultTable;
  902. }
  903. }
  904. void InitResults(ProcessingContext context)
  905. {
  906. context.PushFrame();
  907. // Push this.resultsCount booleans onto the stack, all set to false
  908. context.Push(false, this.resultCount);
  909. }
  910. internal void InvokeMatches(ProcessingContext context)
  911. {
  912. Fx.Assert(null != context, "");
  913. switch (this.resultTable.Count)
  914. {
  915. default:
  916. this.InvokeMultiMatch(context);
  917. break;
  918. case 0:
  919. break;
  920. case 1:
  921. this.InvokeSingleMatch(context);
  922. break;
  923. }
  924. }
  925. void InvokeMultiMatch(ProcessingContext context)
  926. {
  927. int marker = context.Processor.CounterMarker;
  928. BranchContext branchContext = new BranchContext(context); // struct. quick.
  929. int resultTableCount = this.resultTable.Count;
  930. for (int i = 0; i < resultTableCount; )
  931. {
  932. QueryBranchResult result = this.resultTable[i];
  933. QueryBranch branch = result.Branch;
  934. // Branches can arbitrarily alter context stacks, rendering them unuseable to other branches.
  935. // Therefore, before following a branch, we have to clone the context. Cloning is relatively efficient because
  936. // can avoid allocating memory in most cases. We cannot, unfortunately, avoid Array copies.
  937. //
  938. // Optimization:
  939. // We can avoid cloning altogether when we can predict that the branch does NOT tamper with the stack,
  940. // or does so in a predictable way. If we are sure that we can restore the stack easily after the branch
  941. // completes, we have no reason to copy the stack.
  942. ProcessingContext newContext;
  943. Opcode nextOpcode = branch.Branch.Next;
  944. if (nextOpcode.TestFlag(OpcodeFlags.NoContextCopy))
  945. {
  946. newContext = context;
  947. }
  948. else
  949. {
  950. newContext = branchContext.Create();
  951. }
  952. this.InitResults(newContext);
  953. //
  954. // Matches are sorted by their branch ID.
  955. // It is very possible that the a literal matches multiple times, especially when the value being
  956. // compared is a sequence. A literal may match multiple items in a single sequence
  957. // OR multiple items in multiple sequences. If there were 4 context sequences, the literal may have
  958. // matched one item each in 3 of them. The branchID for that literal will be present 3 times in the
  959. // resultTable.
  960. // Sorting the matches groups them by their branch Ids. We only want to take the branch ONCE, so now we
  961. // iterate over all the duplicate matches..
  962. // result.ValIndex will give us the index of the value that was matched. Thus if the 3rd sequence
  963. // matched, ValIndex == 2 (0 based)
  964. newContext.Values[newContext.TopArg[result.ValIndex]].Boolean = true;
  965. while (++i < resultTableCount)
  966. {
  967. result = this.resultTable[i];
  968. if (branch.ID == result.Branch.ID)
  969. {
  970. newContext.Values[newContext.TopArg[result.ValIndex]].Boolean = true;
  971. }
  972. else
  973. {
  974. break;
  975. }
  976. }
  977. try
  978. {
  979. newContext.EvalCodeBlock(nextOpcode);
  980. }
  981. catch (XPathNavigatorException e)
  982. {
  983. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(nextOpcode));
  984. }
  985. catch (NavigatorInvalidBodyAccessException e)
  986. {
  987. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(nextOpcode));
  988. }
  989. context.Processor.CounterMarker = marker;
  990. }
  991. branchContext.Release();
  992. }
  993. internal void InvokeNonMatches(ProcessingContext context, QueryBranchTable nonMatchTable)
  994. {
  995. Fx.Assert(null != context && null != nonMatchTable, "");
  996. int marker = context.Processor.CounterMarker;
  997. BranchContext branchContext = new BranchContext(context);
  998. int nonMatchIndex = 0;
  999. int matchIndex = 0;
  1000. while (matchIndex < this.resultTable.Count && nonMatchIndex < nonMatchTable.Count)
  1001. {
  1002. int compare = this.resultTable[matchIndex].Branch.ID - nonMatchTable[nonMatchIndex].ID;
  1003. if (compare > 0)
  1004. {
  1005. // Nonmatch < match
  1006. // Invoke..
  1007. ProcessingContext newContext = branchContext.Create();
  1008. this.InvokeNonMatch(newContext, nonMatchTable[nonMatchIndex]);
  1009. context.Processor.CounterMarker = marker;
  1010. ++nonMatchIndex;
  1011. }
  1012. else if (0 == compare)
  1013. {
  1014. ++nonMatchIndex;
  1015. }
  1016. else
  1017. {
  1018. ++matchIndex;
  1019. }
  1020. }
  1021. // Add remaining
  1022. while (nonMatchIndex < nonMatchTable.Count)
  1023. {
  1024. ProcessingContext newContext = branchContext.Create();
  1025. this.InvokeNonMatch(newContext, nonMatchTable[nonMatchIndex]);
  1026. context.Processor.CounterMarker = marker;
  1027. ++nonMatchIndex;
  1028. }
  1029. branchContext.Release();
  1030. }
  1031. void InvokeNonMatch(ProcessingContext context, QueryBranch branch)
  1032. {
  1033. context.PushFrame();
  1034. context.Push(false, this.resultCount);
  1035. try
  1036. {
  1037. context.EvalCodeBlock(branch.Branch);
  1038. }
  1039. catch (XPathNavigatorException e)
  1040. {
  1041. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(branch.Branch));
  1042. }
  1043. catch (NavigatorInvalidBodyAccessException e)
  1044. {
  1045. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(branch.Branch));
  1046. }
  1047. }
  1048. void InvokeSingleMatch(ProcessingContext context)
  1049. {
  1050. int marker = context.Processor.CounterMarker;
  1051. QueryBranchResult result = this.resultTable[0];
  1052. this.InitResults(context);
  1053. context.Values[context.TopArg[result.ValIndex]].Boolean = true;
  1054. try
  1055. {
  1056. context.EvalCodeBlock(result.Branch.Branch.Next);
  1057. }
  1058. catch (XPathNavigatorException e)
  1059. {
  1060. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(result.Branch.Branch.Next));
  1061. }
  1062. catch (NavigatorInvalidBodyAccessException e)
  1063. {
  1064. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(result.Branch.Branch.Next));
  1065. }
  1066. context.Processor.CounterMarker = marker;
  1067. }
  1068. internal void Release(ProcessingContext context)
  1069. {
  1070. context.Processor.ReleaseResults(this.resultTable);
  1071. }
  1072. }
  1073. abstract class QueryBranchIndex
  1074. {
  1075. internal abstract int Count
  1076. {
  1077. get;
  1078. }
  1079. internal abstract QueryBranch this[object key]
  1080. {
  1081. get;
  1082. set;
  1083. }
  1084. internal abstract void CollectXPathFilters(ICollection<MessageFilter> filters);
  1085. #if NO
  1086. internal abstract IEnumerator GetEnumerator();
  1087. #endif
  1088. internal abstract void Match(int valIndex, ref Value val, QueryBranchResultSet results);
  1089. internal abstract void Remove(object key);
  1090. internal abstract void Trim();
  1091. }
  1092. class QueryConditionalBranchOpcode : Opcode
  1093. {
  1094. QueryBranchTable alwaysBranches;
  1095. QueryBranchIndex branchIndex;
  1096. int nextID;
  1097. internal QueryConditionalBranchOpcode(OpcodeID id, QueryBranchIndex branchIndex)
  1098. : base(id)
  1099. {
  1100. Fx.Assert(null != branchIndex, "");
  1101. this.flags |= OpcodeFlags.Branch;
  1102. this.branchIndex = branchIndex;
  1103. this.nextID = 0;
  1104. }
  1105. internal QueryBranchTable AlwaysBranches
  1106. {
  1107. get
  1108. {
  1109. if (null == this.alwaysBranches)
  1110. {
  1111. this.alwaysBranches = new QueryBranchTable();
  1112. }
  1113. return this.alwaysBranches;
  1114. }
  1115. }
  1116. #if NO
  1117. internal QueryBranchIndex BranchIndex
  1118. {
  1119. get
  1120. {
  1121. return this.branchIndex;
  1122. }
  1123. }
  1124. #endif
  1125. internal override void Add(Opcode opcode)
  1126. {
  1127. LiteralRelationOpcode literal = this.ValidateOpcode(opcode);
  1128. if (null == literal)
  1129. {
  1130. base.Add(opcode);
  1131. return;
  1132. }
  1133. // Was this literal already added to the index?
  1134. QueryBranch queryBranch = this.branchIndex[literal.Literal];
  1135. if (null == queryBranch)
  1136. {
  1137. // First time. New branch
  1138. this.nextID++;
  1139. queryBranch = new QueryBranch(literal, this.nextID);
  1140. literal.Prev = this;
  1141. this.branchIndex[literal.Literal] = queryBranch;
  1142. }
  1143. else
  1144. {
  1145. Fx.Assert(!object.ReferenceEquals(queryBranch.Branch, literal), "");
  1146. Fx.Assert(literal.ID == queryBranch.Branch.ID, "");
  1147. // literal already exists.. but what follows the literal must be branched
  1148. // Should never get here, but just in case
  1149. queryBranch.Branch.Next.Add(literal.Next);
  1150. }
  1151. literal.Flags |= OpcodeFlags.InConditional;
  1152. this.AddAlwaysBranch(queryBranch, literal.Next);
  1153. }
  1154. internal void AddAlwaysBranch(Opcode literal, Opcode next)
  1155. {
  1156. LiteralRelationOpcode literalOp = this.ValidateOpcode(literal);
  1157. Fx.Assert(null != literalOp, "");
  1158. if (null != literalOp)
  1159. {
  1160. this.AddAlwaysBranch(literalOp, next);
  1161. }
  1162. }
  1163. // Whether or not the given literal matches, we must always take the branch rooted at 'next'
  1164. // Add to the AlwaysBranches table if not already there..
  1165. internal void AddAlwaysBranch(LiteralRelationOpcode literal, Opcode next)
  1166. {
  1167. Fx.Assert(null != literal && null != next, "");
  1168. QueryBranch literalBranch = this.branchIndex[literal.Literal];
  1169. Fx.Assert(null != literalBranch, "");
  1170. this.AddAlwaysBranch(literalBranch, next);
  1171. }
  1172. void AddAlwaysBranch(QueryBranch literalBranch, Opcode next)
  1173. {
  1174. if (OpcodeID.Branch == next.ID)
  1175. {
  1176. BranchOpcode opcode = (BranchOpcode)next;
  1177. OpcodeList branches = opcode.Branches;
  1178. for (int i = 0; i < branches.Count; ++i)
  1179. {
  1180. Opcode branch = branches[i];
  1181. if (this.IsAlwaysBranch(branch))
  1182. {
  1183. this.AlwaysBranches.AddInOrder(new QueryBranch(branch, literalBranch.ID));
  1184. }
  1185. else
  1186. {
  1187. branch.Flags |= OpcodeFlags.NoContextCopy;
  1188. }
  1189. }
  1190. }
  1191. else
  1192. {
  1193. Fx.Assert(!next.TestFlag(OpcodeFlags.Branch), "");
  1194. if (this.IsAlwaysBranch(next))
  1195. {
  1196. this.AlwaysBranches.AddInOrder(new QueryBranch(next, literalBranch.ID));
  1197. }
  1198. else
  1199. {
  1200. next.Flags |= OpcodeFlags.NoContextCopy;
  1201. }
  1202. }
  1203. }
  1204. internal virtual void CollectMatches(int valIndex, ref Value val, QueryBranchResultSet results)
  1205. {
  1206. this.branchIndex.Match(valIndex, ref val, results);
  1207. }
  1208. internal override void CollectXPathFilters(ICollection<MessageFilter> filters)
  1209. {
  1210. if (this.alwaysBranches != null)
  1211. {
  1212. for (int i = 0; i < this.alwaysBranches.Count; ++i)
  1213. {
  1214. this.alwaysBranches[i].Branch.CollectXPathFilters(filters);
  1215. }
  1216. }
  1217. this.branchIndex.CollectXPathFilters(filters);
  1218. }
  1219. internal override Opcode Eval(ProcessingContext context)
  1220. {
  1221. StackFrame arg = context.TopArg;
  1222. int argCount = arg.Count;
  1223. if (argCount > 0)
  1224. {
  1225. QueryBranchResultSet resultSet = context.Processor.CreateResultSet();
  1226. BranchMatcher matcher = new BranchMatcher(argCount, resultSet);
  1227. // Operate on values at the the top frame of the value stack
  1228. // For each source value, find the branch that could be taken
  1229. for (int i = 0; i < argCount; ++i)
  1230. {
  1231. this.CollectMatches(i, ref context.Values[arg[i]], resultSet);
  1232. }
  1233. // Done with whatever we were testing equality against
  1234. context.PopFrame();
  1235. if (resultSet.Count > 1)
  1236. {
  1237. // Sort results
  1238. resultSet.Sort();
  1239. }
  1240. // First, do non-true branches..
  1241. if (null != this.alwaysBranches && this.alwaysBranches.Count > 0)
  1242. {
  1243. matcher.InvokeNonMatches(context, this.alwaysBranches);
  1244. }
  1245. // Iterate through matches, invoking each matched branch
  1246. matcher.InvokeMatches(context);
  1247. matcher.Release(context);
  1248. }
  1249. else
  1250. {
  1251. context.PopFrame();
  1252. }
  1253. return this.next;
  1254. }
  1255. internal QueryBranch GetBranch(Opcode op)
  1256. {
  1257. if (op.TestFlag(OpcodeFlags.Literal))
  1258. {
  1259. LiteralRelationOpcode relOp = this.ValidateOpcode(op);
  1260. if (null != relOp)
  1261. {
  1262. QueryBranch branch = this.branchIndex[relOp.Literal];
  1263. if (null != branch && branch.Branch.ID == op.ID)
  1264. {
  1265. return branch;
  1266. }
  1267. }
  1268. }
  1269. return null;
  1270. }
  1271. bool IsAlwaysBranch(Opcode next)
  1272. {
  1273. Fx.Assert(null != next, "");
  1274. // Opcodes subsequent to matching literals must obviously be branched to.
  1275. // The question is whether we should branch to the opcodes following those literals that do *not* match.
  1276. // Naturally, the answer depends on the sort of opcode that succeeds the literal.
  1277. //
  1278. // If the literal is within a boolean conjunction, the succeeding opcode will either be a JumpIfNot
  1279. // Or a BlockEnd.
  1280. //
  1281. // -If the JumpIfNot is multiway, then always evaluate if it contains ANY non-result only opcodes.
  1282. // -If JumpIfNot(False) -i.e. AND - only evaluate if the opcode succeeding the jump is NOT a result opcode.
  1283. // -If JumpIfNot(True) - i.e. OR - always evaluate
  1284. //
  1285. // -If BlockEnd - evaluate only if not followed by a result
  1286. //
  1287. // When branching for matching literals, we push trues onto the ValueStack corresponding to the items that
  1288. // matched. When branching for non-matching literals, we push ALL FALSE values... and then eval.
  1289. // is it a the termination of a conditional?
  1290. JumpIfOpcode jump = next as JumpIfOpcode;
  1291. if (null != jump)
  1292. {
  1293. // Is the conditional JumpIfNot(False) = i.e. OR?
  1294. if (!jump.Test)
  1295. {
  1296. return true;
  1297. }
  1298. // Does the conditional actually jump to anything? Should never be the case, but paranoia demands..
  1299. Opcode jumpTo = jump.Jump;
  1300. if (null == jumpTo)
  1301. {
  1302. return false;
  1303. }
  1304. // Lets see where the jump will take us
  1305. Opcode postJump;
  1306. if (jumpTo.TestFlag(OpcodeFlags.Branch))
  1307. {
  1308. // Multiway jump
  1309. OpcodeList branches = ((BranchOpcode)jumpTo).Branches;
  1310. for (int i = 0; i < branches.Count; ++i)
  1311. {
  1312. postJump = branches[i].Next;
  1313. if (null != postJump && !postJump.TestFlag(OpcodeFlags.Result))
  1314. {
  1315. // There is at least one jump here that leads to a non-result.
  1316. // For now, this dooms everybody to being branched to, whether or not their respective literals
  1317. // matched
  1318. return true;
  1319. }
  1320. }
  1321. return false;
  1322. }
  1323. // single jump
  1324. postJump = jump.Jump.Next;
  1325. if (null != postJump && postJump.TestFlag(OpcodeFlags.Result))
  1326. {
  1327. return false;
  1328. }
  1329. return true;
  1330. }
  1331. // If the next opcode is a BlockEnd, then only bother processing if what follows the block is not a result
  1332. if (OpcodeID.BlockEnd == next.ID)
  1333. {
  1334. Fx.Assert(null != next.Next, "");
  1335. return (!next.Next.TestFlag(OpcodeFlags.Result));
  1336. }
  1337. // The literal is not inside a boolean conjunction
  1338. // If the literal is not followed by a result, then we must do further processing after the branch
  1339. return (!next.TestFlag(OpcodeFlags.Result));
  1340. }
  1341. /// <summary>
  1342. /// Returns true if this branch can accept 'opcode' being added to it
  1343. /// </summary>
  1344. internal override bool IsEquivalentForAdd(Opcode opcode)
  1345. {
  1346. if (null != this.ValidateOpcode(opcode))
  1347. {
  1348. return true;
  1349. }
  1350. return base.IsEquivalentForAdd(opcode);
  1351. }
  1352. internal override Opcode Locate(Opcode opcode)
  1353. {
  1354. QueryBranch queryBranch = this.GetBranch(opcode);
  1355. if (null != queryBranch)
  1356. {
  1357. return queryBranch.Branch;
  1358. }
  1359. return null;
  1360. }
  1361. internal override void Remove()
  1362. {
  1363. if (null == this.branchIndex || 0 == this.branchIndex.Count)
  1364. {
  1365. base.Remove();
  1366. }
  1367. }
  1368. internal override void RemoveChild(Opcode opcode)
  1369. {
  1370. LiteralRelationOpcode literal = this.ValidateOpcode(opcode);
  1371. Fx.Assert(null != literal, "");
  1372. QueryBranch branch = this.branchIndex[literal.Literal];
  1373. Fx.Assert(null != branch, "");
  1374. this.branchIndex.Remove(literal.Literal);
  1375. branch.Branch.Flags &= (~OpcodeFlags.NoContextCopy);
  1376. if (null != this.alwaysBranches)
  1377. {
  1378. int removeAt = this.alwaysBranches.IndexOfID(branch.ID);
  1379. if (removeAt >= 0)
  1380. {
  1381. this.alwaysBranches.RemoveAt(removeAt);
  1382. if (0 == this.alwaysBranches.Count)
  1383. {
  1384. this.alwaysBranches = null;
  1385. }
  1386. }
  1387. }
  1388. }
  1389. internal void RemoveAlwaysBranch(Opcode opcode)
  1390. {
  1391. if (null == this.alwaysBranches)
  1392. {
  1393. return;
  1394. }
  1395. // Note: if the opcodes below are not in the alwaysBranches table, nothing will happen
  1396. // So arbitrary calls are safe - just makes the removal processor slower (we'll speed it up if necessary)
  1397. if (OpcodeID.Branch == opcode.ID)
  1398. {
  1399. OpcodeList branches = ((BranchOpcode)opcode).Branches;
  1400. for (int i = 0; i < branches.Count; ++i)
  1401. {
  1402. this.alwaysBranches.Remove(branches[i]);
  1403. }
  1404. }
  1405. else
  1406. {
  1407. this.alwaysBranches.Remove(opcode);
  1408. }
  1409. if (0 == this.alwaysBranches.Count)
  1410. {
  1411. this.alwaysBranches = null;
  1412. }
  1413. }
  1414. internal override void Replace(Opcode replace, Opcode with)
  1415. {
  1416. throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new NotImplementedException(SR.GetString(SR.FilterUnexpectedError)));
  1417. }
  1418. internal override void Trim()
  1419. {
  1420. if (this.alwaysBranches != null)
  1421. {
  1422. this.alwaysBranches.Trim();
  1423. }
  1424. this.branchIndex.Trim();
  1425. }
  1426. internal virtual LiteralRelationOpcode ValidateOpcode(Opcode opcode)
  1427. {
  1428. return opcode as LiteralRelationOpcode;
  1429. }
  1430. }
  1431. }