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