1use std::collections::HashMap;
9
10use crate::environment::Environment;
11use crate::{
12 ArrayElement, ArrayPatternElement, BasicBlock, BlockId, HirFunction, IdentifierId, Instruction,
13 InstructionKind, InstructionValue, JsxAttribute, JsxTag,
14 ManualMemoDependencyRoot, ObjectPropertyKey, ObjectPropertyOrSpread, Pattern, Place,
15 PlaceOrSpread, ScopeId, Terminal,
16};
17
18pub fn each_instruction_lvalue(instr: &Instruction) -> Vec<Place> {
25 let mut result = Vec::new();
26 result.push(instr.lvalue.clone());
27 result.extend(each_instruction_value_lvalue(&instr.value));
28 result
29}
30
31pub fn each_instruction_value_lvalue(value: &InstructionValue) -> Vec<Place> {
34 let mut result = Vec::new();
35 match value {
36 InstructionValue::DeclareContext { lvalue, .. }
37 | InstructionValue::StoreContext { lvalue, .. }
38 | InstructionValue::DeclareLocal { lvalue, .. }
39 | InstructionValue::StoreLocal { lvalue, .. } => {
40 result.push(lvalue.place.clone());
41 }
42 InstructionValue::Destructure { lvalue, .. } => {
43 result.extend(each_pattern_operand(&lvalue.pattern));
44 }
45 InstructionValue::PostfixUpdate { lvalue, .. }
46 | InstructionValue::PrefixUpdate { lvalue, .. } => {
47 result.push(lvalue.clone());
48 }
49 InstructionValue::LoadLocal { .. }
51 | InstructionValue::LoadContext { .. }
52 | InstructionValue::Primitive { .. }
53 | InstructionValue::JSXText { .. }
54 | InstructionValue::BinaryExpression { .. }
55 | InstructionValue::NewExpression { .. }
56 | InstructionValue::CallExpression { .. }
57 | InstructionValue::MethodCall { .. }
58 | InstructionValue::UnaryExpression { .. }
59 | InstructionValue::TypeCastExpression { .. }
60 | InstructionValue::JsxExpression { .. }
61 | InstructionValue::ObjectExpression { .. }
62 | InstructionValue::ObjectMethod { .. }
63 | InstructionValue::ArrayExpression { .. }
64 | InstructionValue::JsxFragment { .. }
65 | InstructionValue::RegExpLiteral { .. }
66 | InstructionValue::MetaProperty { .. }
67 | InstructionValue::PropertyStore { .. }
68 | InstructionValue::PropertyLoad { .. }
69 | InstructionValue::PropertyDelete { .. }
70 | InstructionValue::ComputedStore { .. }
71 | InstructionValue::ComputedLoad { .. }
72 | InstructionValue::ComputedDelete { .. }
73 | InstructionValue::LoadGlobal { .. }
74 | InstructionValue::StoreGlobal { .. }
75 | InstructionValue::FunctionExpression { .. }
76 | InstructionValue::TaggedTemplateExpression { .. }
77 | InstructionValue::TemplateLiteral { .. }
78 | InstructionValue::Await { .. }
79 | InstructionValue::GetIterator { .. }
80 | InstructionValue::IteratorNext { .. }
81 | InstructionValue::NextPropertyOf { .. }
82 | InstructionValue::Debugger { .. }
83 | InstructionValue::StartMemoize { .. }
84 | InstructionValue::FinishMemoize { .. }
85 | InstructionValue::UnsupportedNode { .. } => {}
86 }
87 result
88}
89
90pub fn each_instruction_lvalue_with_kind(
93 value: &InstructionValue,
94) -> Vec<(Place, InstructionKind)> {
95 let mut result = Vec::new();
96 match value {
97 InstructionValue::DeclareContext { lvalue, .. }
98 | InstructionValue::StoreContext { lvalue, .. }
99 | InstructionValue::DeclareLocal { lvalue, .. }
100 | InstructionValue::StoreLocal { lvalue, .. } => {
101 result.push((lvalue.place.clone(), lvalue.kind));
102 }
103 InstructionValue::Destructure { lvalue, .. } => {
104 let kind = lvalue.kind;
105 for place in each_pattern_operand(&lvalue.pattern) {
106 result.push((place, kind));
107 }
108 }
109 InstructionValue::PostfixUpdate { lvalue, .. }
110 | InstructionValue::PrefixUpdate { lvalue, .. } => {
111 result.push((lvalue.clone(), InstructionKind::Reassign));
112 }
113 InstructionValue::LoadLocal { .. }
115 | InstructionValue::LoadContext { .. }
116 | InstructionValue::Primitive { .. }
117 | InstructionValue::JSXText { .. }
118 | InstructionValue::BinaryExpression { .. }
119 | InstructionValue::NewExpression { .. }
120 | InstructionValue::CallExpression { .. }
121 | InstructionValue::MethodCall { .. }
122 | InstructionValue::UnaryExpression { .. }
123 | InstructionValue::TypeCastExpression { .. }
124 | InstructionValue::JsxExpression { .. }
125 | InstructionValue::ObjectExpression { .. }
126 | InstructionValue::ObjectMethod { .. }
127 | InstructionValue::ArrayExpression { .. }
128 | InstructionValue::JsxFragment { .. }
129 | InstructionValue::RegExpLiteral { .. }
130 | InstructionValue::MetaProperty { .. }
131 | InstructionValue::PropertyStore { .. }
132 | InstructionValue::PropertyLoad { .. }
133 | InstructionValue::PropertyDelete { .. }
134 | InstructionValue::ComputedStore { .. }
135 | InstructionValue::ComputedLoad { .. }
136 | InstructionValue::ComputedDelete { .. }
137 | InstructionValue::LoadGlobal { .. }
138 | InstructionValue::StoreGlobal { .. }
139 | InstructionValue::FunctionExpression { .. }
140 | InstructionValue::TaggedTemplateExpression { .. }
141 | InstructionValue::TemplateLiteral { .. }
142 | InstructionValue::Await { .. }
143 | InstructionValue::GetIterator { .. }
144 | InstructionValue::IteratorNext { .. }
145 | InstructionValue::NextPropertyOf { .. }
146 | InstructionValue::Debugger { .. }
147 | InstructionValue::StartMemoize { .. }
148 | InstructionValue::FinishMemoize { .. }
149 | InstructionValue::UnsupportedNode { .. } => {}
150 }
151 result
152}
153
154pub fn each_instruction_operand(instr: &Instruction, env: &Environment) -> Vec<Place> {
157 each_instruction_value_operand(&instr.value, env)
158}
159
160pub fn each_instruction_operand_with_functions(
163 instr: &Instruction,
164 functions: &[HirFunction],
165) -> Vec<Place> {
166 each_instruction_value_operand_with_functions(&instr.value, functions)
167}
168
169pub fn each_instruction_value_operand(
172 value: &InstructionValue,
173 env: &Environment,
174) -> Vec<Place> {
175 each_instruction_value_operand_with_functions(value, &env.functions)
176}
177
178pub fn each_instruction_value_operand_with_functions(
181 value: &InstructionValue,
182 functions: &[HirFunction],
183) -> Vec<Place> {
184 let mut result = Vec::new();
185 match value {
186 InstructionValue::NewExpression { callee, args, .. }
187 | InstructionValue::CallExpression { callee, args, .. } => {
188 result.push(callee.clone());
189 result.extend(each_call_argument(args));
190 }
191 InstructionValue::BinaryExpression { left, right, .. } => {
192 result.push(left.clone());
193 result.push(right.clone());
194 }
195 InstructionValue::MethodCall {
196 receiver,
197 property,
198 args,
199 ..
200 } => {
201 result.push(receiver.clone());
202 result.push(property.clone());
203 result.extend(each_call_argument(args));
204 }
205 InstructionValue::DeclareContext { .. } | InstructionValue::DeclareLocal { .. } => {
206 }
208 InstructionValue::LoadLocal { place, .. }
209 | InstructionValue::LoadContext { place, .. } => {
210 result.push(place.clone());
211 }
212 InstructionValue::StoreLocal { value: val, .. } => {
213 result.push(val.clone());
214 }
215 InstructionValue::StoreContext {
216 lvalue, value: val, ..
217 } => {
218 result.push(lvalue.place.clone());
219 result.push(val.clone());
220 }
221 InstructionValue::StoreGlobal { value: val, .. } => {
222 result.push(val.clone());
223 }
224 InstructionValue::Destructure { value: val, .. } => {
225 result.push(val.clone());
226 }
227 InstructionValue::PropertyLoad { object, .. } => {
228 result.push(object.clone());
229 }
230 InstructionValue::PropertyDelete { object, .. } => {
231 result.push(object.clone());
232 }
233 InstructionValue::PropertyStore {
234 object,
235 value: val,
236 ..
237 } => {
238 result.push(object.clone());
239 result.push(val.clone());
240 }
241 InstructionValue::ComputedLoad {
242 object, property, ..
243 } => {
244 result.push(object.clone());
245 result.push(property.clone());
246 }
247 InstructionValue::ComputedDelete {
248 object, property, ..
249 } => {
250 result.push(object.clone());
251 result.push(property.clone());
252 }
253 InstructionValue::ComputedStore {
254 object,
255 property,
256 value: val,
257 ..
258 } => {
259 result.push(object.clone());
260 result.push(property.clone());
261 result.push(val.clone());
262 }
263 InstructionValue::UnaryExpression { value: val, .. } => {
264 result.push(val.clone());
265 }
266 InstructionValue::JsxExpression {
267 tag,
268 props,
269 children,
270 ..
271 } => {
272 if let JsxTag::Place(place) = tag {
273 result.push(place.clone());
274 }
275 for attribute in props {
276 match attribute {
277 JsxAttribute::Attribute { place, .. } => {
278 result.push(place.clone());
279 }
280 JsxAttribute::SpreadAttribute { argument, .. } => {
281 result.push(argument.clone());
282 }
283 }
284 }
285 if let Some(children) = children {
286 for child in children {
287 result.push(child.clone());
288 }
289 }
290 }
291 InstructionValue::JsxFragment { children, .. } => {
292 for child in children {
293 result.push(child.clone());
294 }
295 }
296 InstructionValue::ObjectExpression { properties, .. } => {
297 for property in properties {
298 match property {
299 ObjectPropertyOrSpread::Property(prop) => {
300 if let ObjectPropertyKey::Computed { name } = &prop.key {
301 result.push(name.clone());
302 }
303 result.push(prop.place.clone());
304 }
305 ObjectPropertyOrSpread::Spread(spread) => {
306 result.push(spread.place.clone());
307 }
308 }
309 }
310 }
311 InstructionValue::ArrayExpression { elements, .. } => {
312 for element in elements {
313 match element {
314 ArrayElement::Place(place) => {
315 result.push(place.clone());
316 }
317 ArrayElement::Spread(spread) => {
318 result.push(spread.place.clone());
319 }
320 ArrayElement::Hole => {}
321 }
322 }
323 }
324 InstructionValue::ObjectMethod { lowered_func, .. }
325 | InstructionValue::FunctionExpression { lowered_func, .. } => {
326 let func = &functions[lowered_func.func.0 as usize];
327 for ctx_place in &func.context {
328 result.push(ctx_place.clone());
329 }
330 }
331 InstructionValue::TaggedTemplateExpression { tag, .. } => {
332 result.push(tag.clone());
333 }
334 InstructionValue::TypeCastExpression { value: val, .. } => {
335 result.push(val.clone());
336 }
337 InstructionValue::TemplateLiteral { subexprs, .. } => {
338 for subexpr in subexprs {
339 result.push(subexpr.clone());
340 }
341 }
342 InstructionValue::Await { value: val, .. } => {
343 result.push(val.clone());
344 }
345 InstructionValue::GetIterator { collection, .. } => {
346 result.push(collection.clone());
347 }
348 InstructionValue::IteratorNext {
349 iterator,
350 collection,
351 ..
352 } => {
353 result.push(iterator.clone());
354 result.push(collection.clone());
355 }
356 InstructionValue::NextPropertyOf { value: val, .. } => {
357 result.push(val.clone());
358 }
359 InstructionValue::PostfixUpdate { value: val, .. }
360 | InstructionValue::PrefixUpdate { value: val, .. } => {
361 result.push(val.clone());
362 }
363 InstructionValue::StartMemoize { deps, .. } => {
364 if let Some(deps) = deps {
365 for dep in deps {
366 if let ManualMemoDependencyRoot::NamedLocal { value, .. } = &dep.root {
367 result.push(value.clone());
368 }
369 }
370 }
371 }
372 InstructionValue::FinishMemoize { decl, .. } => {
373 result.push(decl.clone());
374 }
375 InstructionValue::Debugger { .. }
376 | InstructionValue::RegExpLiteral { .. }
377 | InstructionValue::MetaProperty { .. }
378 | InstructionValue::LoadGlobal { .. }
379 | InstructionValue::UnsupportedNode { .. }
380 | InstructionValue::Primitive { .. }
381 | InstructionValue::JSXText { .. } => {
382 }
384 }
385 result
386}
387
388pub fn each_call_argument(args: &[PlaceOrSpread]) -> Vec<Place> {
391 let mut result = Vec::new();
392 for arg in args {
393 match arg {
394 PlaceOrSpread::Place(place) => {
395 result.push(place.clone());
396 }
397 PlaceOrSpread::Spread(spread) => {
398 result.push(spread.place.clone());
399 }
400 }
401 }
402 result
403}
404
405pub fn each_pattern_operand(pattern: &Pattern) -> Vec<Place> {
408 let mut result = Vec::new();
409 match pattern {
410 Pattern::Array(arr) => {
411 for item in &arr.items {
412 match item {
413 ArrayPatternElement::Place(place) => {
414 result.push(place.clone());
415 }
416 ArrayPatternElement::Spread(spread) => {
417 result.push(spread.place.clone());
418 }
419 ArrayPatternElement::Hole => {}
420 }
421 }
422 }
423 Pattern::Object(obj) => {
424 for property in &obj.properties {
425 match property {
426 ObjectPropertyOrSpread::Property(prop) => {
427 result.push(prop.place.clone());
428 }
429 ObjectPropertyOrSpread::Spread(spread) => {
430 result.push(spread.place.clone());
431 }
432 }
433 }
434 }
435 }
436 result
437}
438
439pub fn does_pattern_contain_spread_element(pattern: &Pattern) -> bool {
442 match pattern {
443 Pattern::Array(arr) => {
444 for item in &arr.items {
445 if matches!(item, ArrayPatternElement::Spread(_)) {
446 return true;
447 }
448 }
449 }
450 Pattern::Object(obj) => {
451 for property in &obj.properties {
452 if matches!(property, ObjectPropertyOrSpread::Spread(_)) {
453 return true;
454 }
455 }
456 }
457 }
458 false
459}
460
461pub fn each_terminal_successor(terminal: &Terminal) -> Vec<BlockId> {
464 let mut result = Vec::new();
465 match terminal {
466 Terminal::Goto { block, .. } => {
467 result.push(*block);
468 }
469 Terminal::If {
470 consequent,
471 alternate,
472 ..
473 } => {
474 result.push(*consequent);
475 result.push(*alternate);
476 }
477 Terminal::Branch {
478 consequent,
479 alternate,
480 ..
481 } => {
482 result.push(*consequent);
483 result.push(*alternate);
484 }
485 Terminal::Switch { cases, .. } => {
486 for case in cases {
487 result.push(case.block);
488 }
489 }
490 Terminal::Optional { test, .. }
491 | Terminal::Ternary { test, .. }
492 | Terminal::Logical { test, .. } => {
493 result.push(*test);
494 }
495 Terminal::Return { .. } => {}
496 Terminal::Throw { .. } => {}
497 Terminal::DoWhile { loop_block, .. } => {
498 result.push(*loop_block);
499 }
500 Terminal::While { test, .. } => {
501 result.push(*test);
502 }
503 Terminal::For { init, .. } => {
504 result.push(*init);
505 }
506 Terminal::ForOf { init, .. } => {
507 result.push(*init);
508 }
509 Terminal::ForIn { init, .. } => {
510 result.push(*init);
511 }
512 Terminal::Label { block, .. } => {
513 result.push(*block);
514 }
515 Terminal::Sequence { block, .. } => {
516 result.push(*block);
517 }
518 Terminal::MaybeThrow {
519 continuation,
520 handler,
521 ..
522 } => {
523 result.push(*continuation);
524 if let Some(handler) = handler {
525 result.push(*handler);
526 }
527 }
528 Terminal::Try { block, .. } => {
529 result.push(*block);
530 }
531 Terminal::Scope { block, .. } | Terminal::PrunedScope { block, .. } => {
532 result.push(*block);
533 }
534 Terminal::Unreachable { .. } | Terminal::Unsupported { .. } => {}
535 }
536 result
537}
538
539pub fn each_terminal_operand(terminal: &Terminal) -> Vec<Place> {
542 let mut result = Vec::new();
543 match terminal {
544 Terminal::If { test, .. } => {
545 result.push(test.clone());
546 }
547 Terminal::Branch { test, .. } => {
548 result.push(test.clone());
549 }
550 Terminal::Switch { test, cases, .. } => {
551 result.push(test.clone());
552 for case in cases {
553 if let Some(test) = &case.test {
554 result.push(test.clone());
555 }
556 }
557 }
558 Terminal::Return { value, .. } | Terminal::Throw { value, .. } => {
559 result.push(value.clone());
560 }
561 Terminal::Try {
562 handler_binding, ..
563 } => {
564 if let Some(binding) = handler_binding {
565 result.push(binding.clone());
566 }
567 }
568 Terminal::MaybeThrow { .. }
569 | Terminal::Sequence { .. }
570 | Terminal::Label { .. }
571 | Terminal::Optional { .. }
572 | Terminal::Ternary { .. }
573 | Terminal::Logical { .. }
574 | Terminal::DoWhile { .. }
575 | Terminal::While { .. }
576 | Terminal::For { .. }
577 | Terminal::ForOf { .. }
578 | Terminal::ForIn { .. }
579 | Terminal::Goto { .. }
580 | Terminal::Unreachable { .. }
581 | Terminal::Unsupported { .. }
582 | Terminal::Scope { .. }
583 | Terminal::PrunedScope { .. } => {
584 }
586 }
587 result
588}
589
590pub fn map_instruction_lvalues(instr: &mut Instruction, f: &mut impl FnMut(Place) -> Place) {
597 match &mut instr.value {
598 InstructionValue::DeclareLocal { lvalue, .. }
599 | InstructionValue::StoreLocal { lvalue, .. }
600 | InstructionValue::DeclareContext { lvalue, .. }
601 | InstructionValue::StoreContext { lvalue, .. } => {
602 lvalue.place = f(lvalue.place.clone());
603 }
604 InstructionValue::Destructure { lvalue, .. } => {
605 map_pattern_operands(&mut lvalue.pattern, f);
606 }
607 InstructionValue::PostfixUpdate { lvalue, .. }
608 | InstructionValue::PrefixUpdate { lvalue, .. } => {
609 *lvalue = f(lvalue.clone());
610 }
611 _ => {}
612 }
613 instr.lvalue = f(instr.lvalue.clone());
614}
615
616pub fn map_instruction_operands(
619 instr: &mut Instruction,
620 env: &mut Environment,
621 f: &mut impl FnMut(Place) -> Place,
622) {
623 map_instruction_value_operands(&mut instr.value, env, f);
624}
625
626pub fn map_instruction_value_operands(
629 value: &mut InstructionValue,
630 env: &mut Environment,
631 f: &mut impl FnMut(Place) -> Place,
632) {
633 match value {
634 InstructionValue::BinaryExpression {
635 left, right, ..
636 } => {
637 *left = f(left.clone());
638 *right = f(right.clone());
639 }
640 InstructionValue::PropertyLoad { object, .. } => {
641 *object = f(object.clone());
642 }
643 InstructionValue::PropertyDelete { object, .. } => {
644 *object = f(object.clone());
645 }
646 InstructionValue::PropertyStore {
647 object,
648 value: val,
649 ..
650 } => {
651 *object = f(object.clone());
652 *val = f(val.clone());
653 }
654 InstructionValue::ComputedLoad {
655 object, property, ..
656 } => {
657 *object = f(object.clone());
658 *property = f(property.clone());
659 }
660 InstructionValue::ComputedDelete {
661 object, property, ..
662 } => {
663 *object = f(object.clone());
664 *property = f(property.clone());
665 }
666 InstructionValue::ComputedStore {
667 object,
668 property,
669 value: val,
670 ..
671 } => {
672 *object = f(object.clone());
673 *property = f(property.clone());
674 *val = f(val.clone());
675 }
676 InstructionValue::DeclareContext { .. } | InstructionValue::DeclareLocal { .. } => {
677 }
679 InstructionValue::LoadLocal { place, .. }
680 | InstructionValue::LoadContext { place, .. } => {
681 *place = f(place.clone());
682 }
683 InstructionValue::StoreLocal { value: val, .. } => {
684 *val = f(val.clone());
685 }
686 InstructionValue::StoreContext {
687 lvalue, value: val, ..
688 } => {
689 lvalue.place = f(lvalue.place.clone());
690 *val = f(val.clone());
691 }
692 InstructionValue::StoreGlobal { value: val, .. } => {
693 *val = f(val.clone());
694 }
695 InstructionValue::Destructure { value: val, .. } => {
696 *val = f(val.clone());
697 }
698 InstructionValue::NewExpression { callee, args, .. }
699 | InstructionValue::CallExpression { callee, args, .. } => {
700 *callee = f(callee.clone());
701 map_call_arguments(args, f);
702 }
703 InstructionValue::MethodCall {
704 receiver,
705 property,
706 args,
707 ..
708 } => {
709 *receiver = f(receiver.clone());
710 *property = f(property.clone());
711 map_call_arguments(args, f);
712 }
713 InstructionValue::UnaryExpression { value: val, .. } => {
714 *val = f(val.clone());
715 }
716 InstructionValue::JsxExpression {
717 tag,
718 props,
719 children,
720 ..
721 } => {
722 if let JsxTag::Place(place) = tag {
723 *place = f(place.clone());
724 }
725 for attribute in props.iter_mut() {
726 match attribute {
727 JsxAttribute::Attribute { place, .. } => {
728 *place = f(place.clone());
729 }
730 JsxAttribute::SpreadAttribute { argument, .. } => {
731 *argument = f(argument.clone());
732 }
733 }
734 }
735 if let Some(children) = children {
736 *children = children.iter().map(|p| f(p.clone())).collect();
737 }
738 }
739 InstructionValue::ObjectExpression { properties, .. } => {
740 for property in properties.iter_mut() {
741 match property {
742 ObjectPropertyOrSpread::Property(prop) => {
743 if let ObjectPropertyKey::Computed { name } = &mut prop.key {
744 *name = f(name.clone());
745 }
746 prop.place = f(prop.place.clone());
747 }
748 ObjectPropertyOrSpread::Spread(spread) => {
749 spread.place = f(spread.place.clone());
750 }
751 }
752 }
753 }
754 InstructionValue::ArrayExpression { elements, .. } => {
755 *elements = elements
756 .iter()
757 .map(|element| match element {
758 ArrayElement::Place(place) => ArrayElement::Place(f(place.clone())),
759 ArrayElement::Spread(spread) => {
760 let mut spread = spread.clone();
761 spread.place = f(spread.place.clone());
762 ArrayElement::Spread(spread)
763 }
764 ArrayElement::Hole => ArrayElement::Hole,
765 })
766 .collect();
767 }
768 InstructionValue::JsxFragment { children, .. } => {
769 *children = children.iter().map(|e| f(e.clone())).collect();
770 }
771 InstructionValue::ObjectMethod { lowered_func, .. }
772 | InstructionValue::FunctionExpression { lowered_func, .. } => {
773 let func = &mut env.functions[lowered_func.func.0 as usize];
774 func.context = func.context.iter().map(|d| f(d.clone())).collect();
775 }
776 InstructionValue::TaggedTemplateExpression { tag, .. } => {
777 *tag = f(tag.clone());
778 }
779 InstructionValue::TypeCastExpression { value: val, .. } => {
780 *val = f(val.clone());
781 }
782 InstructionValue::TemplateLiteral { subexprs, .. } => {
783 *subexprs = subexprs.iter().map(|s| f(s.clone())).collect();
784 }
785 InstructionValue::Await { value: val, .. } => {
786 *val = f(val.clone());
787 }
788 InstructionValue::GetIterator { collection, .. } => {
789 *collection = f(collection.clone());
790 }
791 InstructionValue::IteratorNext {
792 iterator,
793 collection,
794 ..
795 } => {
796 *iterator = f(iterator.clone());
797 *collection = f(collection.clone());
798 }
799 InstructionValue::NextPropertyOf { value: val, .. } => {
800 *val = f(val.clone());
801 }
802 InstructionValue::PostfixUpdate { value: val, .. }
803 | InstructionValue::PrefixUpdate { value: val, .. } => {
804 *val = f(val.clone());
805 }
806 InstructionValue::StartMemoize { deps, .. } => {
807 if let Some(deps) = deps {
808 for dep in deps.iter_mut() {
809 if let ManualMemoDependencyRoot::NamedLocal { value, .. } = &mut dep.root {
810 *value = f(value.clone());
811 }
812 }
813 }
814 }
815 InstructionValue::FinishMemoize { decl, .. } => {
816 *decl = f(decl.clone());
817 }
818 InstructionValue::Debugger { .. }
819 | InstructionValue::RegExpLiteral { .. }
820 | InstructionValue::MetaProperty { .. }
821 | InstructionValue::LoadGlobal { .. }
822 | InstructionValue::UnsupportedNode { .. }
823 | InstructionValue::Primitive { .. }
824 | InstructionValue::JSXText { .. } => {
825 }
827 }
828}
829
830pub fn map_call_arguments(args: &mut Vec<PlaceOrSpread>, f: &mut impl FnMut(Place) -> Place) {
833 for arg in args.iter_mut() {
834 match arg {
835 PlaceOrSpread::Place(place) => {
836 *place = f(place.clone());
837 }
838 PlaceOrSpread::Spread(spread) => {
839 spread.place = f(spread.place.clone());
840 }
841 }
842 }
843}
844
845pub fn map_pattern_operands(pattern: &mut Pattern, f: &mut impl FnMut(Place) -> Place) {
848 match pattern {
849 Pattern::Array(arr) => {
850 arr.items = arr
851 .items
852 .iter()
853 .map(|item| match item {
854 ArrayPatternElement::Place(place) => {
855 ArrayPatternElement::Place(f(place.clone()))
856 }
857 ArrayPatternElement::Spread(spread) => {
858 let mut spread = spread.clone();
859 spread.place = f(spread.place.clone());
860 ArrayPatternElement::Spread(spread)
861 }
862 ArrayPatternElement::Hole => ArrayPatternElement::Hole,
863 })
864 .collect();
865 }
866 Pattern::Object(obj) => {
867 for property in obj.properties.iter_mut() {
868 match property {
869 ObjectPropertyOrSpread::Property(prop) => {
870 prop.place = f(prop.place.clone());
871 }
872 ObjectPropertyOrSpread::Spread(spread) => {
873 spread.place = f(spread.place.clone());
874 }
875 }
876 }
877 }
878 }
879}
880
881pub fn map_terminal_successors(terminal: &mut Terminal, f: &mut impl FnMut(BlockId) -> BlockId) {
884 match terminal {
885 Terminal::Goto { block, .. } => {
886 *block = f(*block);
887 }
888 Terminal::If {
889 consequent,
890 alternate,
891 fallthrough,
892 ..
893 } => {
894 *consequent = f(*consequent);
895 *alternate = f(*alternate);
896 *fallthrough = f(*fallthrough);
897 }
898 Terminal::Branch {
899 consequent,
900 alternate,
901 fallthrough,
902 ..
903 } => {
904 *consequent = f(*consequent);
905 *alternate = f(*alternate);
906 *fallthrough = f(*fallthrough);
907 }
908 Terminal::Switch {
909 cases,
910 fallthrough,
911 ..
912 } => {
913 for case in cases.iter_mut() {
914 case.block = f(case.block);
915 }
916 *fallthrough = f(*fallthrough);
917 }
918 Terminal::Logical {
919 test, fallthrough, ..
920 } => {
921 *test = f(*test);
922 *fallthrough = f(*fallthrough);
923 }
924 Terminal::Ternary {
925 test, fallthrough, ..
926 } => {
927 *test = f(*test);
928 *fallthrough = f(*fallthrough);
929 }
930 Terminal::Optional {
931 test, fallthrough, ..
932 } => {
933 *test = f(*test);
934 *fallthrough = f(*fallthrough);
935 }
936 Terminal::Return { .. } => {}
937 Terminal::Throw { .. } => {}
938 Terminal::DoWhile {
939 loop_block,
940 test,
941 fallthrough,
942 ..
943 } => {
944 *loop_block = f(*loop_block);
945 *test = f(*test);
946 *fallthrough = f(*fallthrough);
947 }
948 Terminal::While {
949 test,
950 loop_block,
951 fallthrough,
952 ..
953 } => {
954 *test = f(*test);
955 *loop_block = f(*loop_block);
956 *fallthrough = f(*fallthrough);
957 }
958 Terminal::For {
959 init,
960 test,
961 update,
962 loop_block,
963 fallthrough,
964 ..
965 } => {
966 *init = f(*init);
967 *test = f(*test);
968 if let Some(update) = update {
969 *update = f(*update);
970 }
971 *loop_block = f(*loop_block);
972 *fallthrough = f(*fallthrough);
973 }
974 Terminal::ForOf {
975 init,
976 test,
977 loop_block,
978 fallthrough,
979 ..
980 } => {
981 *init = f(*init);
982 *test = f(*test);
983 *loop_block = f(*loop_block);
984 *fallthrough = f(*fallthrough);
985 }
986 Terminal::ForIn {
987 init,
988 loop_block,
989 fallthrough,
990 ..
991 } => {
992 *init = f(*init);
993 *loop_block = f(*loop_block);
994 *fallthrough = f(*fallthrough);
995 }
996 Terminal::Label {
997 block,
998 fallthrough,
999 ..
1000 } => {
1001 *block = f(*block);
1002 *fallthrough = f(*fallthrough);
1003 }
1004 Terminal::Sequence {
1005 block,
1006 fallthrough,
1007 ..
1008 } => {
1009 *block = f(*block);
1010 *fallthrough = f(*fallthrough);
1011 }
1012 Terminal::MaybeThrow {
1013 continuation,
1014 handler,
1015 ..
1016 } => {
1017 *continuation = f(*continuation);
1018 if let Some(handler) = handler {
1019 *handler = f(*handler);
1020 }
1021 }
1022 Terminal::Try {
1023 block,
1024 handler,
1025 fallthrough,
1026 ..
1027 } => {
1028 *block = f(*block);
1029 *handler = f(*handler);
1030 *fallthrough = f(*fallthrough);
1031 }
1032 Terminal::Scope {
1033 block,
1034 fallthrough,
1035 ..
1036 }
1037 | Terminal::PrunedScope {
1038 block,
1039 fallthrough,
1040 ..
1041 } => {
1042 *block = f(*block);
1043 *fallthrough = f(*fallthrough);
1044 }
1045 Terminal::Unreachable { .. } | Terminal::Unsupported { .. } => {}
1046 }
1047}
1048
1049pub fn map_terminal_operands(terminal: &mut Terminal, f: &mut impl FnMut(Place) -> Place) {
1052 match terminal {
1053 Terminal::If { test, .. } => {
1054 *test = f(test.clone());
1055 }
1056 Terminal::Branch { test, .. } => {
1057 *test = f(test.clone());
1058 }
1059 Terminal::Switch { test, cases, .. } => {
1060 *test = f(test.clone());
1061 for case in cases.iter_mut() {
1062 if let Some(t) = &mut case.test {
1063 *t = f(t.clone());
1064 }
1065 }
1066 }
1067 Terminal::Return { value, .. } | Terminal::Throw { value, .. } => {
1068 *value = f(value.clone());
1069 }
1070 Terminal::Try {
1071 handler_binding, ..
1072 } => {
1073 if let Some(binding) = handler_binding {
1074 *binding = f(binding.clone());
1075 }
1076 }
1077 Terminal::MaybeThrow { .. }
1078 | Terminal::Sequence { .. }
1079 | Terminal::Label { .. }
1080 | Terminal::Optional { .. }
1081 | Terminal::Ternary { .. }
1082 | Terminal::Logical { .. }
1083 | Terminal::DoWhile { .. }
1084 | Terminal::While { .. }
1085 | Terminal::For { .. }
1086 | Terminal::ForOf { .. }
1087 | Terminal::ForIn { .. }
1088 | Terminal::Goto { .. }
1089 | Terminal::Unreachable { .. }
1090 | Terminal::Unsupported { .. }
1091 | Terminal::Scope { .. }
1092 | Terminal::PrunedScope { .. } => {
1093 }
1095 }
1096}
1097
1098pub fn each_terminal_all_successors(terminal: &Terminal) -> Vec<BlockId> {
1102 let mut result = Vec::new();
1103 match terminal {
1104 Terminal::Goto { block, .. } => {
1105 result.push(*block);
1106 }
1107 Terminal::If {
1108 consequent,
1109 alternate,
1110 fallthrough,
1111 ..
1112 } => {
1113 result.push(*consequent);
1114 result.push(*alternate);
1115 result.push(*fallthrough);
1116 }
1117 Terminal::Branch {
1118 consequent,
1119 alternate,
1120 fallthrough,
1121 ..
1122 } => {
1123 result.push(*consequent);
1124 result.push(*alternate);
1125 result.push(*fallthrough);
1126 }
1127 Terminal::Switch {
1128 cases,
1129 fallthrough,
1130 ..
1131 } => {
1132 for case in cases {
1133 result.push(case.block);
1134 }
1135 result.push(*fallthrough);
1136 }
1137 Terminal::Logical {
1138 test, fallthrough, ..
1139 }
1140 | Terminal::Ternary {
1141 test, fallthrough, ..
1142 }
1143 | Terminal::Optional {
1144 test, fallthrough, ..
1145 } => {
1146 result.push(*test);
1147 result.push(*fallthrough);
1148 }
1149 Terminal::Return { .. } | Terminal::Throw { .. } => {}
1150 Terminal::DoWhile {
1151 loop_block,
1152 test,
1153 fallthrough,
1154 ..
1155 } => {
1156 result.push(*loop_block);
1157 result.push(*test);
1158 result.push(*fallthrough);
1159 }
1160 Terminal::While {
1161 test,
1162 loop_block,
1163 fallthrough,
1164 ..
1165 } => {
1166 result.push(*test);
1167 result.push(*loop_block);
1168 result.push(*fallthrough);
1169 }
1170 Terminal::For {
1171 init,
1172 test,
1173 update,
1174 loop_block,
1175 fallthrough,
1176 ..
1177 } => {
1178 result.push(*init);
1179 result.push(*test);
1180 if let Some(update) = update {
1181 result.push(*update);
1182 }
1183 result.push(*loop_block);
1184 result.push(*fallthrough);
1185 }
1186 Terminal::ForOf {
1187 init,
1188 test,
1189 loop_block,
1190 fallthrough,
1191 ..
1192 } => {
1193 result.push(*init);
1194 result.push(*test);
1195 result.push(*loop_block);
1196 result.push(*fallthrough);
1197 }
1198 Terminal::ForIn {
1199 init,
1200 loop_block,
1201 fallthrough,
1202 ..
1203 } => {
1204 result.push(*init);
1205 result.push(*loop_block);
1206 result.push(*fallthrough);
1207 }
1208 Terminal::Label {
1209 block,
1210 fallthrough,
1211 ..
1212 }
1213 | Terminal::Sequence {
1214 block,
1215 fallthrough,
1216 ..
1217 } => {
1218 result.push(*block);
1219 result.push(*fallthrough);
1220 }
1221 Terminal::MaybeThrow {
1222 continuation,
1223 handler,
1224 ..
1225 } => {
1226 result.push(*continuation);
1227 if let Some(handler) = handler {
1228 result.push(*handler);
1229 }
1230 }
1231 Terminal::Try {
1232 block,
1233 handler,
1234 fallthrough,
1235 ..
1236 } => {
1237 result.push(*block);
1238 result.push(*handler);
1239 result.push(*fallthrough);
1240 }
1241 Terminal::Scope {
1242 block,
1243 fallthrough,
1244 ..
1245 }
1246 | Terminal::PrunedScope {
1247 block,
1248 fallthrough,
1249 ..
1250 } => {
1251 result.push(*block);
1252 result.push(*fallthrough);
1253 }
1254 Terminal::Unreachable { .. } | Terminal::Unsupported { .. } => {}
1255 }
1256 result
1257}
1258
1259pub fn terminal_fallthrough(terminal: &Terminal) -> Option<BlockId> {
1266 match terminal {
1267 Terminal::MaybeThrow { .. }
1269 | Terminal::Goto { .. }
1270 | Terminal::Return { .. }
1271 | Terminal::Throw { .. }
1272 | Terminal::Unreachable { .. }
1273 | Terminal::Unsupported { .. } => None,
1274
1275 Terminal::Branch { fallthrough, .. }
1277 | Terminal::Try { fallthrough, .. }
1278 | Terminal::DoWhile { fallthrough, .. }
1279 | Terminal::ForOf { fallthrough, .. }
1280 | Terminal::ForIn { fallthrough, .. }
1281 | Terminal::For { fallthrough, .. }
1282 | Terminal::If { fallthrough, .. }
1283 | Terminal::Label { fallthrough, .. }
1284 | Terminal::Logical { fallthrough, .. }
1285 | Terminal::Optional { fallthrough, .. }
1286 | Terminal::Sequence { fallthrough, .. }
1287 | Terminal::Switch { fallthrough, .. }
1288 | Terminal::Ternary { fallthrough, .. }
1289 | Terminal::While { fallthrough, .. }
1290 | Terminal::Scope { fallthrough, .. }
1291 | Terminal::PrunedScope { fallthrough, .. } => Some(*fallthrough),
1292 }
1293}
1294
1295pub fn terminal_has_fallthrough(terminal: &Terminal) -> bool {
1298 terminal_fallthrough(terminal).is_some()
1299}
1300
1301#[derive(Debug, Clone)]
1307pub enum ScopeBlockInfo {
1308 Begin {
1309 scope: ScopeId,
1310 pruned: bool,
1311 fallthrough: BlockId,
1312 },
1313 End {
1314 scope: ScopeId,
1315 pruned: bool,
1316 },
1317}
1318
1319pub struct ScopeBlockTraversal {
1322 active_scopes: Vec<ScopeId>,
1324 pub block_infos: HashMap<BlockId, ScopeBlockInfo>,
1326}
1327
1328impl ScopeBlockTraversal {
1329 pub fn new() -> Self {
1330 ScopeBlockTraversal {
1331 active_scopes: Vec::new(),
1332 block_infos: HashMap::new(),
1333 }
1334 }
1335
1336 pub fn record_scopes(&mut self, block: &BasicBlock) {
1339 if let Some(block_info) = self.block_infos.get(&block.id) {
1340 match block_info {
1341 ScopeBlockInfo::Begin { scope, .. } => {
1342 self.active_scopes.push(*scope);
1343 }
1344 ScopeBlockInfo::End { scope, .. } => {
1345 let top = self.active_scopes.last();
1346 assert_eq!(
1347 Some(scope),
1348 top,
1349 "Expected traversed block fallthrough to match top-most active scope"
1350 );
1351 self.active_scopes.pop();
1352 }
1353 }
1354 }
1355
1356 match &block.terminal {
1357 Terminal::Scope {
1358 block: scope_block,
1359 fallthrough,
1360 scope,
1361 ..
1362 } => {
1363 assert!(
1364 !self.block_infos.contains_key(scope_block)
1365 && !self.block_infos.contains_key(fallthrough),
1366 "Expected unique scope blocks and fallthroughs"
1367 );
1368 self.block_infos.insert(
1369 *scope_block,
1370 ScopeBlockInfo::Begin {
1371 scope: *scope,
1372 pruned: false,
1373 fallthrough: *fallthrough,
1374 },
1375 );
1376 self.block_infos.insert(
1377 *fallthrough,
1378 ScopeBlockInfo::End {
1379 scope: *scope,
1380 pruned: false,
1381 },
1382 );
1383 }
1384 Terminal::PrunedScope {
1385 block: scope_block,
1386 fallthrough,
1387 scope,
1388 ..
1389 } => {
1390 assert!(
1391 !self.block_infos.contains_key(scope_block)
1392 && !self.block_infos.contains_key(fallthrough),
1393 "Expected unique scope blocks and fallthroughs"
1394 );
1395 self.block_infos.insert(
1396 *scope_block,
1397 ScopeBlockInfo::Begin {
1398 scope: *scope,
1399 pruned: true,
1400 fallthrough: *fallthrough,
1401 },
1402 );
1403 self.block_infos.insert(
1404 *fallthrough,
1405 ScopeBlockInfo::End {
1406 scope: *scope,
1407 pruned: true,
1408 },
1409 );
1410 }
1411 _ => {}
1412 }
1413 }
1414
1415 pub fn is_scope_active(&self, scope_id: ScopeId) -> bool {
1418 self.active_scopes.contains(&scope_id)
1419 }
1420
1421 pub fn current_scope(&self) -> Option<ScopeId> {
1423 self.active_scopes.last().copied()
1424 }
1425}
1426
1427impl Default for ScopeBlockTraversal {
1428 fn default() -> Self {
1429 Self::new()
1430 }
1431}
1432
1433pub fn each_instruction_lvalue_ids(instr: &Instruction) -> Vec<IdentifierId> {
1440 each_instruction_lvalue(instr)
1441 .into_iter()
1442 .map(|p| p.identifier)
1443 .collect()
1444}
1445
1446pub fn each_instruction_operand_ids(instr: &Instruction, env: &Environment) -> Vec<IdentifierId> {
1449 each_instruction_operand(instr, env)
1450 .into_iter()
1451 .map(|p| p.identifier)
1452 .collect()
1453}
1454
1455pub fn each_instruction_value_operand_ids(value: &InstructionValue, env: &Environment) -> Vec<IdentifierId> {
1458 each_instruction_value_operand(value, env)
1459 .into_iter()
1460 .map(|p| p.identifier)
1461 .collect()
1462}
1463
1464pub fn each_terminal_operand_ids(terminal: &Terminal) -> Vec<IdentifierId> {
1467 each_terminal_operand(terminal)
1468 .into_iter()
1469 .map(|p| p.identifier)
1470 .collect()
1471}
1472
1473pub fn each_pattern_operand_ids(pattern: &Pattern) -> Vec<IdentifierId> {
1476 each_pattern_operand(pattern)
1477 .into_iter()
1478 .map(|p| p.identifier)
1479 .collect()
1480}
1481
1482pub fn for_each_instruction_value_operand_mut(
1503 value: &mut InstructionValue,
1504 f: &mut impl FnMut(&mut Place),
1505) {
1506 match value {
1507 InstructionValue::BinaryExpression { left, right, .. } => {
1508 f(left);
1509 f(right);
1510 }
1511 InstructionValue::PropertyLoad { object, .. }
1512 | InstructionValue::PropertyDelete { object, .. } => {
1513 f(object);
1514 }
1515 InstructionValue::PropertyStore {
1516 object,
1517 value: val,
1518 ..
1519 } => {
1520 f(object);
1521 f(val);
1522 }
1523 InstructionValue::ComputedLoad {
1524 object, property, ..
1525 }
1526 | InstructionValue::ComputedDelete {
1527 object, property, ..
1528 } => {
1529 f(object);
1530 f(property);
1531 }
1532 InstructionValue::ComputedStore {
1533 object,
1534 property,
1535 value: val,
1536 ..
1537 } => {
1538 f(object);
1539 f(property);
1540 f(val);
1541 }
1542 InstructionValue::DeclareContext { .. } | InstructionValue::DeclareLocal { .. } => {}
1543 InstructionValue::LoadLocal { place, .. }
1544 | InstructionValue::LoadContext { place, .. } => {
1545 f(place);
1546 }
1547 InstructionValue::StoreLocal { value: val, .. } => {
1548 f(val);
1549 }
1550 InstructionValue::StoreContext {
1551 lvalue, value: val, ..
1552 } => {
1553 f(&mut lvalue.place);
1554 f(val);
1555 }
1556 InstructionValue::StoreGlobal { value: val, .. } => {
1557 f(val);
1558 }
1559 InstructionValue::Destructure { value: val, .. } => {
1560 f(val);
1561 }
1562 InstructionValue::NewExpression { callee, args, .. }
1563 | InstructionValue::CallExpression { callee, args, .. } => {
1564 f(callee);
1565 for_each_call_argument_mut(args, f);
1566 }
1567 InstructionValue::MethodCall {
1568 receiver,
1569 property,
1570 args,
1571 ..
1572 } => {
1573 f(receiver);
1574 f(property);
1575 for_each_call_argument_mut(args, f);
1576 }
1577 InstructionValue::UnaryExpression { value: val, .. } => {
1578 f(val);
1579 }
1580 InstructionValue::JsxExpression {
1581 tag,
1582 props,
1583 children,
1584 ..
1585 } => {
1586 if let JsxTag::Place(place) = tag {
1587 f(place);
1588 }
1589 for attribute in props.iter_mut() {
1590 match attribute {
1591 JsxAttribute::Attribute { place, .. } => f(place),
1592 JsxAttribute::SpreadAttribute { argument, .. } => f(argument),
1593 }
1594 }
1595 if let Some(children) = children {
1596 for child in children.iter_mut() {
1597 f(child);
1598 }
1599 }
1600 }
1601 InstructionValue::ObjectExpression { properties, .. } => {
1602 for property in properties.iter_mut() {
1603 match property {
1604 ObjectPropertyOrSpread::Property(prop) => {
1605 if let ObjectPropertyKey::Computed { name } = &mut prop.key {
1606 f(name);
1607 }
1608 f(&mut prop.place);
1609 }
1610 ObjectPropertyOrSpread::Spread(spread) => {
1611 f(&mut spread.place);
1612 }
1613 }
1614 }
1615 }
1616 InstructionValue::ArrayExpression { elements, .. } => {
1617 for elem in elements.iter_mut() {
1618 match elem {
1619 ArrayElement::Place(p) => f(p),
1620 ArrayElement::Spread(s) => f(&mut s.place),
1621 ArrayElement::Hole => {}
1622 }
1623 }
1624 }
1625 InstructionValue::JsxFragment { children, .. } => {
1626 for child in children.iter_mut() {
1627 f(child);
1628 }
1629 }
1630 InstructionValue::FunctionExpression { .. }
1631 | InstructionValue::ObjectMethod { .. } => {
1632 }
1634 InstructionValue::TaggedTemplateExpression { tag, .. } => {
1635 f(tag);
1636 }
1637 InstructionValue::TypeCastExpression { value: val, .. } => {
1638 f(val);
1639 }
1640 InstructionValue::TemplateLiteral { subexprs, .. } => {
1641 for expr in subexprs.iter_mut() {
1642 f(expr);
1643 }
1644 }
1645 InstructionValue::Await { value: val, .. } => {
1646 f(val);
1647 }
1648 InstructionValue::GetIterator { collection, .. } => {
1649 f(collection);
1650 }
1651 InstructionValue::IteratorNext {
1652 iterator,
1653 collection,
1654 ..
1655 } => {
1656 f(iterator);
1657 f(collection);
1658 }
1659 InstructionValue::NextPropertyOf { value: val, .. } => {
1660 f(val);
1661 }
1662 InstructionValue::PostfixUpdate { value: val, .. }
1663 | InstructionValue::PrefixUpdate { value: val, .. } => {
1664 f(val);
1665 }
1666 InstructionValue::StartMemoize { deps, .. } => {
1667 if let Some(deps) = deps {
1668 for dep in deps.iter_mut() {
1669 if let ManualMemoDependencyRoot::NamedLocal { value, .. } = &mut dep.root {
1670 f(value);
1671 }
1672 }
1673 }
1674 }
1675 InstructionValue::FinishMemoize { decl, .. } => {
1676 f(decl);
1677 }
1678 InstructionValue::Debugger { .. }
1679 | InstructionValue::RegExpLiteral { .. }
1680 | InstructionValue::MetaProperty { .. }
1681 | InstructionValue::LoadGlobal { .. }
1682 | InstructionValue::UnsupportedNode { .. }
1683 | InstructionValue::Primitive { .. }
1684 | InstructionValue::JSXText { .. } => {}
1685 }
1686}
1687
1688pub fn for_each_call_argument_mut(args: &mut [PlaceOrSpread], f: &mut impl FnMut(&mut Place)) {
1690 for arg in args.iter_mut() {
1691 match arg {
1692 PlaceOrSpread::Place(place) => f(place),
1693 PlaceOrSpread::Spread(spread) => f(&mut spread.place),
1694 }
1695 }
1696}
1697
1698pub fn for_each_instruction_value_lvalue_mut(
1702 value: &mut InstructionValue,
1703 f: &mut impl FnMut(&mut Place),
1704) {
1705 match value {
1706 InstructionValue::DeclareContext { lvalue, .. }
1707 | InstructionValue::StoreContext { lvalue, .. }
1708 | InstructionValue::DeclareLocal { lvalue, .. }
1709 | InstructionValue::StoreLocal { lvalue, .. } => {
1710 f(&mut lvalue.place);
1711 }
1712 InstructionValue::Destructure { lvalue, .. } => {
1713 for_each_pattern_operand_mut(&mut lvalue.pattern, f);
1714 }
1715 InstructionValue::PostfixUpdate { lvalue, .. }
1716 | InstructionValue::PrefixUpdate { lvalue, .. } => {
1717 f(lvalue);
1718 }
1719 _ => {}
1720 }
1721}
1722
1723pub fn for_each_instruction_lvalue_mut(instr: &mut Instruction, f: &mut impl FnMut(&mut Place)) {
1726 match &mut instr.value {
1727 InstructionValue::DeclareLocal { lvalue, .. }
1728 | InstructionValue::StoreLocal { lvalue, .. } => {
1729 f(&mut lvalue.place);
1730 }
1731 InstructionValue::Destructure { lvalue, .. } => {
1732 for_each_pattern_operand_mut(&mut lvalue.pattern, f);
1733 }
1734 InstructionValue::PostfixUpdate { lvalue, .. }
1735 | InstructionValue::PrefixUpdate { lvalue, .. } => {
1736 f(lvalue);
1737 }
1738 _ => {}
1739 }
1740 f(&mut instr.lvalue);
1741}
1742
1743pub fn for_each_pattern_operand_mut(pattern: &mut Pattern, f: &mut impl FnMut(&mut Place)) {
1745 match pattern {
1746 Pattern::Array(arr) => {
1747 for item in arr.items.iter_mut() {
1748 match item {
1749 ArrayPatternElement::Place(p) => f(p),
1750 ArrayPatternElement::Spread(s) => f(&mut s.place),
1751 ArrayPatternElement::Hole => {}
1752 }
1753 }
1754 }
1755 Pattern::Object(obj) => {
1756 for property in obj.properties.iter_mut() {
1757 match property {
1758 ObjectPropertyOrSpread::Property(prop) => f(&mut prop.place),
1759 ObjectPropertyOrSpread::Spread(spread) => f(&mut spread.place),
1760 }
1761 }
1762 }
1763 }
1764}
1765
1766pub fn for_each_terminal_operand_mut(terminal: &mut Terminal, f: &mut impl FnMut(&mut Place)) {
1768 match terminal {
1769 Terminal::If { test, .. } | Terminal::Branch { test, .. } => {
1770 f(test);
1771 }
1772 Terminal::Switch { test, cases, .. } => {
1773 f(test);
1774 for case in cases.iter_mut() {
1775 if let Some(t) = &mut case.test {
1776 f(t);
1777 }
1778 }
1779 }
1780 Terminal::Return { value, .. } | Terminal::Throw { value, .. } => {
1781 f(value);
1782 }
1783 Terminal::Try {
1784 handler_binding, ..
1785 } => {
1786 if let Some(binding) = handler_binding {
1787 f(binding);
1788 }
1789 }
1790 Terminal::MaybeThrow { .. }
1791 | Terminal::Sequence { .. }
1792 | Terminal::Label { .. }
1793 | Terminal::Optional { .. }
1794 | Terminal::Ternary { .. }
1795 | Terminal::Logical { .. }
1796 | Terminal::DoWhile { .. }
1797 | Terminal::While { .. }
1798 | Terminal::For { .. }
1799 | Terminal::ForOf { .. }
1800 | Terminal::ForIn { .. }
1801 | Terminal::Goto { .. }
1802 | Terminal::Unreachable { .. }
1803 | Terminal::Unsupported { .. }
1804 | Terminal::Scope { .. }
1805 | Terminal::PrunedScope { .. } => {}
1806 }
1807}