v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
bytecode-graph-builder.cc
Go to the documentation of this file.
1// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <optional>
8
9#include "src/ast/ast.h"
35
36namespace v8 {
37namespace internal {
38namespace compiler {
39
41 public:
45 FeedbackCellRef feedback_cell, BytecodeOffset osr_offset,
46 JSGraph* jsgraph, CallFrequency const& invocation_frequency,
48 int inlining_id, CodeKind code_kind, BytecodeGraphBuilderFlags flags,
49 TickCounter* tick_counter, ObserveNodeInfo const& observe_node_info);
50
53
54 // Creates a graph by visiting bytecodes.
55 void CreateGraph();
56
57 private:
58 class Environment;
59 class OsrIteratorState;
61 struct SubEnvironment;
62
63 void RemoveMergeEnvironmentsBeforeOffset(int limit_offset);
65
66 // Advance {bytecode_iterator} to the given offset. If possible, also advance
67 // {source_position_iterator} while updating the source position table.
68 void AdvanceIteratorsTo(int bytecode_offset);
69
71 void VisitBytecodes();
72
75
76 // Get or create the node that represents the outer function closure.
78
79 // Get or create the node for this parameter index. If such a node is
80 // already cached, it is returned directly and the {debug_name_hint} is
81 // ignored.
82 Node* GetParameter(int index, const char* debug_name_hint = nullptr);
83
84 CodeKind code_kind() const { return code_kind_; }
85
86 // The node representing the current feedback vector is generated once prior
87 // to visiting bytecodes, and is later passed as input to other nodes that
88 // may need it.
89 // TODO(jgruber): Remove feedback_vector() and rename feedback_vector_node()
90 // to feedback_vector() once all uses of the direct heap object reference
91 // have been replaced with a Node* reference.
97
98 // Same as above for the feedback vector node.
104
105 Node* BuildLoadFeedbackCell(int index);
106
107 // Builder for loading a native context field.
109
110 // Helper function for creating a feedback source containing type feedback
111 // vector and a feedback slot.
114
116 const Environment* environment() const { return environment_; }
118
119 // Node creation helpers
120 Node* NewNode(const Operator* op, bool incomplete = false) {
121 return MakeNode(op, 0, static_cast<Node**>(nullptr), incomplete);
122 }
123
124 template <class... Args>
125 Node* NewNode(const Operator* op, Node* n0, Args... nodes) {
126 Node* buffer[] = {n0, nodes...};
127 return MakeNode(op, arraysize(buffer), buffer);
128 }
129
130 // Helpers to create new control nodes.
131 Node* NewIfTrue() { return NewNode(common()->IfTrue()); }
132 Node* NewIfFalse() { return NewNode(common()->IfFalse()); }
133 Node* NewIfValue(int32_t value) { return NewNode(common()->IfValue(value)); }
134 Node* NewIfDefault() { return NewNode(common()->IfDefault()); }
135 Node* NewMerge() { return NewNode(common()->Merge(1), true); }
136 Node* NewLoop() { return NewNode(common()->Loop(1), true); }
138 return NewNode(common()->Branch(hint), condition);
139 }
140 Node* NewSwitch(Node* condition, int control_output_count) {
141 return NewNode(common()->Switch(control_output_count), condition);
142 }
143
144 // Creates a new Phi node having {count} input values.
145 Node* NewPhi(int count, Node* input, Node* control);
146 Node* NewEffectPhi(int count, Node* input, Node* control);
147
148 // Helpers for merging control, effect or value dependencies.
149 Node* MergeControl(Node* control, Node* other);
150 Node* MergeEffect(Node* effect, Node* other_effect, Node* control);
151 Node* MergeValue(Node* value, Node* other_value, Node* control);
152
153 // The main node creation chokepoint. Adds context, frame state, effect,
154 // and control dependencies depending on the operator.
155 Node* MakeNode(const Operator* op, int value_input_count,
156 Node* const* value_inputs, bool incomplete = false);
157
158 Node** EnsureInputBufferSize(int size);
159
162 int arg_count);
163 Node* const* ProcessCallVarArgs(ConvertReceiverMode receiver_mode,
164 Node* callee, interpreter::Register first_reg,
165 int arg_count);
168 int arg_count);
169 Node* ProcessCallRuntimeArguments(const Operator* call_runtime_op,
171 size_t reg_count);
172
173 // Prepare information for eager deoptimization. This information is carried
174 // by dedicated {Checkpoint} nodes that are wired into the effect chain.
175 // Conceptually this frame state is "before" a given operation.
177
178 // Prepare information for lazy deoptimization. This information is attached
179 // to the given node and the output value produced by the node is combined.
180 //
181 // The low-level chokepoint - use the variants below instead.
183 BytecodeOffset bailout_id,
184 const BytecodeLivenessState* liveness);
185
186 // In the common case, frame states are conceptually "after" a given
187 // operation and at the current bytecode offset.
189 if (!OperatorProperties::HasFrameStateInput(node->op())) return;
191 return PrepareFrameState(node, combine, BytecodeOffset(offset),
192 bytecode_analysis().GetOutLivenessFor(offset));
193 }
194
195 // For function-entry stack checks, they're conceptually "before" the first
196 // bytecode and at a special marker bytecode offset.
197 // In the case of FE stack checks, the current bytecode is also the first
198 // bytecode, so we use a special marker bytecode offset to signify a virtual
199 // bytecode before the first physical bytecode.
201 DCHECK_EQ(bytecode_iterator().current_offset(), 0);
203 DCHECK(node->opcode() == IrOpcode::kJSStackCheck);
206 bytecode_analysis().GetInLivenessFor(0));
207 }
208
209 // For OSR-entry stack checks, they're conceptually "before" the first
210 // bytecode of the current loop. We implement this in a similar manner to
211 // function-entry (FE) stack checks above, i.e. we deopt at the predecessor
212 // of the current bytecode.
213 // In the case of OSR-entry stack checks, a physical predecessor bytecode
214 // exists: the JumpLoop bytecode. We attach to JumpLoop by using
215 // `bytecode_analysis().osr_bailout_id()` instead of current_offset (the
216 // former points at JumpLoop, the latter at the loop header, i.e. the target
217 // of JumpLoop).
220 DCHECK(node->opcode() == IrOpcode::kJSStackCheck);
224 bytecode_analysis().GetOutLivenessFor(offset));
225 }
226
228 Node* BuildLoadGlobal(NameRef name, uint32_t feedback_slot_index,
229 TypeofMode typeof_mode);
230
231 enum class NamedStoreMode {
232 // Check the prototype chain before storing.
233 kSet,
234 // Define value to the receiver without checking the prototype chain.
236 };
237 void BuildNamedStore(NamedStoreMode store_mode);
238 void BuildLdaLookupSlot(TypeofMode typeof_mode);
239 void BuildLdaLookupContextSlot(ContextKind context_kind,
240 TypeofMode typeof_mode);
241 void BuildLdaLookupGlobalSlot(TypeofMode typeof_mode);
242 void BuildCallVarArgs(ConvertReceiverMode receiver_mode);
243 void BuildCall(ConvertReceiverMode receiver_mode, Node* const* args,
244 size_t arg_count, int slot_id);
245 void BuildCall(ConvertReceiverMode receiver_mode,
246 std::initializer_list<Node*> args, int slot_id) {
247 BuildCall(receiver_mode, args.begin(), args.size(), slot_id);
248 }
249 void BuildUnaryOp(const Operator* op);
250 void BuildBinaryOp(const Operator* op);
251 void BuildBinaryOpWithImmediate(const Operator* op);
252 void BuildCompareOp(const Operator* op);
253 void BuildDelete(LanguageMode language_mode);
254 void BuildCastOperator(const Operator* op);
256 Node* name = nullptr);
257
258 // Optional early lowering to the simplified operator level. Note that
259 // the result has already been wired into the environment just like
260 // any other invocation of {NewNode} would do.
262 const Operator* op, Node* operand, FeedbackSlot slot);
264 const Operator* op, Node* left, Node* right, FeedbackSlot slot);
266 Node* receiver, Node* cache_array, Node* cache_type, Node* index,
267 FeedbackSlot slot);
269 Node* receiver, FeedbackSlot slot);
271 Node* input, FeedbackSlot slot);
273 Node* const* args,
274 int arg_count,
275 FeedbackSlot slot);
277 const Operator* op, Node* const* args, int arg_count, FeedbackSlot slot);
279 const Operator* op, Node* receiver, FeedbackSlot load_slot,
280 FeedbackSlot call_slot);
282 const Operator* op, FeedbackSlot slot);
284 const Operator* op, Node* receiver, Node* key, FeedbackSlot slot);
286 const Operator* op, Node* receiver, Node* value, FeedbackSlot slot);
288 const Operator* op, Node* receiver, Node* key, Node* value,
289 FeedbackSlot slot);
290
291 // Applies the given early reduction onto the current environment.
293
294 // Check the context chain for extensions, for lookup fast paths.
295 Environment* CheckContextExtensions(uint32_t depth);
296 // Slow path taken when we cannot figure out the current scope info.
297 Environment* CheckContextExtensionsSlowPath(uint32_t depth);
298 // Helper function that tries to get the current scope info.
299 OptionalScopeInfoRef TryGetScopeInfo();
300 // Helper function to create a context extension check.
301 Environment* CheckContextExtensionAtDepth(Environment* slow_environment,
302 uint32_t depth);
303
304 // Helper function to create for-in mode from the recorded type feedback.
306
307 // Helper function to compute call frequency from the recorded type
308 // feedback. Returns unknown if invocation count is unknown. Returns 0 if
309 // feedback is insufficient.
310 CallFrequency ComputeCallFrequency(int slot_id) const;
311
312 // Helper function to extract the speculation mode from the recorded type
313 // feedback. Returns kDisallowSpeculation if feedback is insufficient.
314 SpeculationMode GetSpeculationMode(int slot_id) const;
315
316 // Helper function to determine the call feedback relation from the recorded
317 // type feedback. Returns kUnrelated if feedback is insufficient.
319
320 // Helpers for building the implicit FunctionEntry and IterationBody
321 // StackChecks.
325
326 // Control flow plumbing.
327 void BuildJump();
330 void BuildJumpIfEqual(Node* comperand);
331 void BuildJumpIfNotEqual(Node* comperand);
332 void BuildJumpIfTrue();
333 void BuildJumpIfFalse();
336 void BuildJumpIfNotHole();
339
342 const ZoneVector<ResumeJumpTarget>& resume_jump_targets,
343 bool allow_fallthrough_on_executing);
344
345 // Simulates control flow by forward-propagating environments.
346 void MergeIntoSuccessorEnvironment(int target_offset);
347 void BuildLoopHeaderEnvironment(int current_offset);
348 void SwitchToMergeEnvironment(int current_offset);
349
350 // Simulates control flow that exits the function body.
352
353 // Builds loop exit nodes for every exited loop between the current bytecode
354 // offset and {target_offset}.
355 void BuildLoopExitsForBranch(int target_offset);
357 void BuildLoopExitsUntilLoop(int loop_offset,
358 const BytecodeLivenessState* liveness);
359
360 // Helper for building a return (from an actual return or a suspend).
361 void BuildReturn(const BytecodeLivenessState* liveness);
362
363 // Simulates entry and exit of exception handlers.
364 void ExitThenEnterExceptionHandlers(int current_offset);
365
366 // Update the current position of {SourcePositionTable} and
367 // {NodeOriginTable} to that bytecode at {offset}, if any.
369
370 // Growth increment for the temporary buffer used to construct input lists to
371 // new nodes.
372 static const int kInputBufferSizeIncrement = 64;
373
374 // An abstract representation for an exception handler that is being
375 // entered and exited while the graph builder is iterating over the
376 // underlying bytecode. The exception handlers within the bytecode are
377 // well scoped, hence will form a stack during iteration.
379 int start_offset_; // Start offset of the handled area in the bytecode.
380 int end_offset_; // End offset of the handled area in the bytecode.
381 int handler_offset_; // Handler entry offset within the bytecode.
382 int context_register_; // Index of register holding handler context.
383 };
384
385 template <class T = Object>
387 int operand_index) {
388 // The BytecodeArray itself was fetched by using a barrier so all reads
389 // from the constant pool are safe.
391 broker(), broker()->CanonicalPersistentHandle(
392 Cast<T>(bytecode_iterator().GetConstantForIndexOperand(
393 operand_index, local_isolate_))));
394 }
395
396 TFGraph* graph() const { return jsgraph_->graph(); }
398 Zone* graph_zone() const { return graph()->zone(); }
399 JSGraph* jsgraph() const { return jsgraph_; }
400 Isolate* isolate() const { return jsgraph_->isolate(); }
405 Zone* local_zone() const { return local_zone_; }
424 return bytecode_analysis_;
425 }
435 bool skip_tierup_check() const {
437 }
446 JSHeapBroker* broker() const { return broker_; }
449
450#define DECLARE_VISIT_BYTECODE(name, ...) void Visit##name();
452#undef DECLARE_VISIT_BYTECODE
453
458 // The native context for which we optimize.
472 bool const osr_;
474
476
477 // Merge environments are snapshots of the environment at points where the
478 // control flow merges. This models a forward data flow propagation of all
479 // values from all predecessors of the merge in question. They are indexed by
480 // the bytecode offset
482
483 // Generator merge environments are snapshots of the current resume
484 // environment, tracing back through loop headers to the resume switch of a
485 // generator. They allow us to model a single resume jump as several switch
486 // statements across loop headers, keeping those loop headers reducible,
487 // without having to merge the "executing" environments of the generator into
488 // the "resuming" ones. They are indexed by the suspend id of the resume.
490
492
493 // Exception handlers currently entered by the iteration.
496
497 // Temporary storage for building node input lists.
500
504
505 // Optimization to only create checkpoints when the current position in the
506 // control-flow is not effect-dominated by another checkpoint already. All
507 // operations that do not have observable side-effects can be re-evaluated.
509
510 // Nodes representing values in the activation record.
512
513 // Control nodes that exit the function body.
515
517
518 // The node origins table, to store bytecode origins.
520
521 // The source position table, to be populated.
523
525
527
529
530 static constexpr int kBinaryOperationHintIndex = 1;
531 static constexpr int kBinaryOperationSmiHintIndex = 1;
532 static constexpr int kCompareOperationHintIndex = 1;
533 static constexpr int kCountOperationHintIndex = 0;
534 static constexpr int kUnaryOperationHintIndex = 0;
535};
536
537// The abstract execution environment simulates the content of the interpreter
538// register file. The environment performs SSA-renaming of all tracked nodes at
539// split and merge points in the control flow.
541 public:
543 int parameter_count,
544 interpreter::Register incoming_new_target_or_generator,
545 Node* control_dependency);
546
547 // Specifies whether environment binding methods should attach frame state
548 // inputs to nodes representing the value being bound. This is done because
549 // the {OutputFrameStateCombine} is closely related to the binding method.
551
552 int parameter_count() const { return parameter_count_; }
553 int register_count() const { return register_count_; }
554
555 Node* LookupAccumulator() const;
556 Node* LookupRegister(interpreter::Register the_register) const;
557 Node* LookupGeneratorState() const;
558
559 void BindAccumulator(Node* node,
561 void BindRegister(interpreter::Register the_register, Node* node,
564 interpreter::Register first_reg, Node* node,
566 void BindGeneratorState(Node* node);
567 void RecordAfterState(Node* node,
569
570 // Effect dependency tracked by this environment.
572 void UpdateEffectDependency(Node* dependency) {
573 effect_dependency_ = dependency;
574 }
575
576 // Preserve a checkpoint of the environment for the IR graph. Any
577 // further mutation of the environment will not affect checkpoints.
578 Node* Checkpoint(BytecodeOffset bytecode_offset,
580 const BytecodeLivenessState* liveness);
581
582 // Control dependency tracked by this environment.
584 void UpdateControlDependency(Node* dependency) {
585 control_dependency_ = dependency;
586 }
587
588 Node* Context() const { return context_; }
589 void SetContext(Node* new_context) { context_ = new_context; }
590
591 Environment* Copy();
592 void Merge(Environment* other, const BytecodeLivenessState* liveness);
593
594 void FillWithOsrValues();
595 void PrepareForLoop(const BytecodeLoopAssignments& assignments,
596 const BytecodeLivenessState* liveness);
597 void PrepareForLoopExit(Node* loop,
598 const BytecodeLoopAssignments& assignments,
599 const BytecodeLivenessState* liveness);
600
601 private:
602 friend Zone;
603
604 explicit Environment(const Environment* copy);
605
606 bool StateValuesRequireUpdate(Node** state_values, Node** values, int count);
607 void UpdateStateValues(Node** state_values, Node** values, int count);
608 Node* GetStateValuesFromCache(Node** values, int count,
609 const BytecodeLivenessState* liveness);
610
611 int RegisterToValuesIndex(interpreter::Register the_register) const;
612
613 Zone* zone() const { return builder_->local_zone(); }
614 TFGraph* graph() const { return builder_->graph(); }
617 const NodeVector* values() const { return &values_; }
618 NodeVector* values() { return &values_; }
619 int register_base() const { return register_base_; }
620 int accumulator_base() const { return accumulator_base_; }
621
633};
634
635// A helper for creating a temporary sub-environment for simple branches.
647
648// Issues:
649// - Scopes - intimately tied to AST. Need to eval what is needed.
650// - Need to resolve closure parameter treatment.
652 BytecodeGraphBuilder* builder, int register_count, int parameter_count,
653 interpreter::Register incoming_new_target_or_generator,
654 Node* control_dependency)
655 : builder_(builder),
656 register_count_(register_count),
657 parameter_count_(parameter_count),
658 control_dependency_(control_dependency),
659 effect_dependency_(control_dependency),
660 values_(builder->local_zone()),
661 parameters_state_values_(nullptr),
662 generator_state_(nullptr) {
663 // The layout of values_ is:
664 //
665 // [receiver] [parameters] [registers] [accumulator]
666 //
667 // parameter[0] is the receiver (this), parameters 1..N are the
668 // parameters supplied to the method (arg0..argN-1). The accumulator
669 // is stored separately.
670
671 // Parameters including the receiver
672 for (int i = 0; i < parameter_count; i++) {
673 const char* debug_name = (i == 0) ? "%this" : nullptr;
674 Node* parameter = builder->GetParameter(i, debug_name);
675 values()->push_back(parameter);
676 }
677
678 // Registers
679 register_base_ = static_cast<int>(values()->size());
680 Node* undefined_constant = builder->jsgraph()->UndefinedConstant();
681 values()->insert(values()->end(), register_count, undefined_constant);
682
683 // Accumulator
684 accumulator_base_ = static_cast<int>(values()->size());
685 values()->push_back(undefined_constant);
686
687 // Context
689 context_ = builder->GetParameter(context_index, "%context");
690
691 // Incoming new.target or generator register
692 if (incoming_new_target_or_generator.is_valid()) {
693 int new_target_index =
695 Node* new_target_node =
696 builder->GetParameter(new_target_index, "%new.target");
697
698 int values_index = RegisterToValuesIndex(incoming_new_target_or_generator);
699 values()->at(values_index) = new_target_node;
700 }
701}
702
705 : builder_(other->builder_),
706 register_count_(other->register_count_),
707 parameter_count_(other->parameter_count_),
708 context_(other->context_),
709 control_dependency_(other->control_dependency_),
710 effect_dependency_(other->effect_dependency_),
711 values_(other->zone()),
712 parameters_state_values_(other->parameters_state_values_),
713 generator_state_(other->generator_state_),
714 register_base_(other->register_base_),
715 accumulator_base_(other->accumulator_base_) {
716 values_ = other->values_;
717}
718
719
721 interpreter::Register the_register) const {
722 if (the_register.is_parameter()) {
723 return the_register.ToParameterIndex();
724 } else {
725 return the_register.index() + register_base();
726 }
727}
728
730 return values()->at(accumulator_base_);
731}
732
734 DCHECK_NOT_NULL(generator_state_);
735 return generator_state_;
736}
737
739 interpreter::Register the_register) const {
740 if (the_register.is_current_context()) {
741 return Context();
742 } else if (the_register.is_function_closure()) {
743 return builder()->GetFunctionClosure();
744 } else {
745 int values_index = RegisterToValuesIndex(the_register);
746 return values()->at(values_index);
747 }
748}
749
751 Node* node, FrameStateAttachmentMode mode) {
752 if (mode == FrameStateAttachmentMode::kAttachFrameState) {
753 builder()->PrepareFrameState(node, OutputFrameStateCombine::PokeAt(0));
754 }
755 values()->at(accumulator_base_) = node;
756}
757
759 generator_state_ = node;
760}
761
763 interpreter::Register the_register, Node* node,
765 int values_index = RegisterToValuesIndex(the_register);
766 if (mode == FrameStateAttachmentMode::kAttachFrameState) {
767 builder()->PrepareFrameState(node, OutputFrameStateCombine::PokeAt(
768 accumulator_base_ - values_index));
769 }
770 values()->at(values_index) = node;
771}
772
774 interpreter::Register first_reg, Node* node,
776 int values_index = RegisterToValuesIndex(first_reg);
777 if (mode == FrameStateAttachmentMode::kAttachFrameState) {
778 builder()->PrepareFrameState(node, OutputFrameStateCombine::PokeAt(
779 accumulator_base_ - values_index));
780 }
781 for (int i = 0; i < node->op()->ValueOutputCount(); i++) {
782 values()->at(values_index + i) =
783 builder()->NewNode(common()->Projection(i), node);
784 }
785}
786
788 Node* node, FrameStateAttachmentMode mode) {
789 if (mode == FrameStateAttachmentMode::kAttachFrameState) {
790 builder()->PrepareFrameState(node, OutputFrameStateCombine::Ignore());
791 }
792}
793
797
800 const BytecodeLivenessState* liveness) {
801 // Create a merge of the control dependencies of both environments and update
802 // the current environment's control dependency accordingly.
803 Node* control = builder()->MergeControl(GetControlDependency(),
804 other->GetControlDependency());
805 UpdateControlDependency(control);
806
807 // Create a merge of the effect dependencies of both environments and update
808 // the current environment's effect dependency accordingly.
809 Node* effect = builder()->MergeEffect(GetEffectDependency(),
810 other->GetEffectDependency(), control);
811 UpdateEffectDependency(effect);
812
813 // Introduce Phi nodes for values that are live and have differing inputs at
814 // the merge point, potentially extending an existing Phi node if possible.
815 context_ = builder()->MergeValue(context_, other->context_, control);
816 for (int i = 0; i < parameter_count(); i++) {
817 values_[i] = builder()->MergeValue(values_[i], other->values_[i], control);
818 }
819 for (int i = 0; i < register_count(); i++) {
820 int index = register_base() + i;
821 if (liveness == nullptr || liveness->RegisterIsLive(i)) {
822#if DEBUG
823 // We only do these DCHECKs when we are not in the resume path of a
824 // generator -- this is, when either there is no generator state at all,
825 // or the generator state is not the constant "executing" value.
826 if (generator_state_ == nullptr ||
827 NumberMatcher(generator_state_)
829 DCHECK_NE(values_[index], builder()->jsgraph()->OptimizedOutConstant());
830 DCHECK_NE(other->values_[index],
831 builder()->jsgraph()->OptimizedOutConstant());
832 }
833#endif
834
835 values_[index] =
836 builder()->MergeValue(values_[index], other->values_[index], control);
837
838 } else {
839 values_[index] = builder()->jsgraph()->OptimizedOutConstant();
840 }
841 }
842
843 if (liveness == nullptr || liveness->AccumulatorIsLive()) {
844 DCHECK_NE(values_[accumulator_base()],
845 builder()->jsgraph()->OptimizedOutConstant());
846 DCHECK_NE(other->values_[accumulator_base()],
847 builder()->jsgraph()->OptimizedOutConstant());
848
849 values_[accumulator_base()] =
850 builder()->MergeValue(values_[accumulator_base()],
851 other->values_[accumulator_base()], control);
852 } else {
853 values_[accumulator_base()] = builder()->jsgraph()->OptimizedOutConstant();
854 }
855
856 if (generator_state_ != nullptr) {
857 DCHECK_NOT_NULL(other->generator_state_);
858 generator_state_ = builder()->MergeValue(generator_state_,
859 other->generator_state_, control);
860 }
861}
862
864 const BytecodeLoopAssignments& assignments,
865 const BytecodeLivenessState* liveness) {
866 // Create a control node for the loop header.
867 Node* control = builder()->NewLoop();
868
869 // Create a Phi for external effects.
870 Node* effect = builder()->NewEffectPhi(1, GetEffectDependency(), control);
871 UpdateEffectDependency(effect);
872
873 // Create Phis for any values that are live on entry to the loop and may be
874 // updated by the end of the loop.
875 context_ = builder()->NewPhi(1, context_, control);
876 for (int i = 0; i < parameter_count(); i++) {
877 if (assignments.ContainsParameter(i)) {
878 values_[i] = builder()->NewPhi(1, values_[i], control);
879 }
880 }
881 for (int i = 0; i < register_count(); i++) {
882 if (assignments.ContainsLocal(i) &&
883 (liveness == nullptr || liveness->RegisterIsLive(i))) {
884 int index = register_base() + i;
885 values_[index] = builder()->NewPhi(1, values_[index], control);
886 }
887 }
888 // The accumulator should not be live on entry.
889 DCHECK_IMPLIES(liveness != nullptr, !liveness->AccumulatorIsLive());
890
891 if (generator_state_ != nullptr) {
892 generator_state_ = builder()->NewPhi(1, generator_state_, control);
893 }
894
895 // Connect to the loop end.
896 Node* terminate = builder()->graph()->NewNode(
897 builder()->common()->Terminate(), effect, control);
898 builder()->exit_controls_.push_back(terminate);
899}
900
902 Node* start = graph()->start();
903
904 // Create OSR values for each environment value.
905 SetContext(graph()->NewNode(
907 int size = static_cast<int>(values()->size());
908 for (int i = 0; i < size; i++) {
909 int idx = i; // Indexing scheme follows {StandardFrame}, adapt accordingly.
910 if (i >= register_base()) idx += InterpreterFrameConstants::kExtraSlotCount;
911 if (i >= accumulator_base()) idx = Linkage::kOsrAccumulatorRegisterIndex;
912 values()->at(i) = graph()->NewNode(common()->OsrValue(idx), start);
913 }
914}
915
917 Node** state_values, Node** values, int count) {
918 if (*state_values == nullptr) {
919 return true;
920 }
921 Node::Inputs inputs = (*state_values)->inputs();
922 if (inputs.count() != count) return true;
923 for (int i = 0; i < count; i++) {
924 if (inputs[i] != values[i]) {
925 return true;
926 }
927 }
928 return false;
929}
930
932 Node* loop, const BytecodeLoopAssignments& assignments,
933 const BytecodeLivenessState* liveness) {
934 DCHECK_EQ(loop->opcode(), IrOpcode::kLoop);
935
936 Node* control = GetControlDependency();
937
938 // Create the loop exit node.
939 Node* loop_exit = graph()->NewNode(common()->LoopExit(), control, loop);
940 UpdateControlDependency(loop_exit);
941
942 // Rename the effect.
943 Node* effect_rename = graph()->NewNode(common()->LoopExitEffect(),
944 GetEffectDependency(), loop_exit);
945 UpdateEffectDependency(effect_rename);
946
947 // TODO(jarin) We should also rename context here. However, unconditional
948 // renaming confuses global object and native context specialization.
949 // We should only rename if the context is assigned in the loop.
950
951 // Rename the environment values if they were assigned in the loop and are
952 // live after exiting the loop.
953 for (int i = 0; i < parameter_count(); i++) {
954 if (assignments.ContainsParameter(i)) {
955 Node* rename = graph()->NewNode(
956 common()->LoopExitValue(MachineRepresentation::kTagged), values_[i],
957 loop_exit);
958 values_[i] = rename;
959 }
960 }
961 for (int i = 0; i < register_count(); i++) {
962 if (assignments.ContainsLocal(i) &&
963 (liveness == nullptr || liveness->RegisterIsLive(i))) {
964 Node* rename = graph()->NewNode(
965 common()->LoopExitValue(MachineRepresentation::kTagged),
966 values_[register_base() + i], loop_exit);
967 values_[register_base() + i] = rename;
968 }
969 }
970 if (liveness == nullptr || liveness->AccumulatorIsLive()) {
971 Node* rename = graph()->NewNode(
972 common()->LoopExitValue(MachineRepresentation::kTagged),
973 values_[accumulator_base()], loop_exit);
974 values_[accumulator_base()] = rename;
975 }
976
977 if (generator_state_ != nullptr) {
978 generator_state_ = graph()->NewNode(
979 common()->LoopExitValue(MachineRepresentation::kTagged),
980 generator_state_, loop_exit);
981 }
982}
983
985 Node** values,
986 int count) {
987 if (StateValuesRequireUpdate(state_values, values, count)) {
989 (*state_values) = graph()->NewNode(op, count, values);
990 }
991}
992
994 Node** values, int count, const BytecodeLivenessState* liveness) {
995 return builder_->state_values_cache_.GetNodeForValues(
996 values, static_cast<size_t>(count), liveness);
997}
998
1000 BytecodeOffset bailout_id, OutputFrameStateCombine combine,
1001 const BytecodeLivenessState* liveness) {
1002 if (parameter_count() == register_count()) {
1003 // Reuse the state-value cache if the number of local registers happens
1004 // to match the parameter count.
1005 parameters_state_values_ =
1006 GetStateValuesFromCache(&values()->at(0), parameter_count(), nullptr);
1007 } else {
1008 UpdateStateValues(&parameters_state_values_, &values()->at(0),
1009 parameter_count());
1010 }
1011
1012 Node* registers_state_values = GetStateValuesFromCache(
1013 &values()->at(register_base()), register_count(), liveness);
1014
1015 bool accumulator_is_live = !liveness || liveness->AccumulatorIsLive();
1016 Node* accumulator_state_value =
1017 accumulator_is_live && combine != OutputFrameStateCombine::PokeAt(0)
1018 ? values()->at(accumulator_base())
1019 : builder()->jsgraph()->OptimizedOutConstant();
1020
1021 const Operator* op = common()->FrameState(
1022 bailout_id, combine, builder()->frame_state_function_info());
1023 Node* result = graph()->NewNode(
1024 op, parameters_state_values_, registers_state_values,
1025 accumulator_state_value, Context(), builder()->GetFunctionClosure(),
1026 builder()->graph()->start());
1027
1028 return result;
1029}
1030
1032public GraphDecorator {
1033 public:
1035 : node_origins_(node_origins) {}
1036
1037 void Decorate(Node* node) final {
1038 node_origins_->SetNodeOrigin(node->id(), NodeOrigin::kJSBytecode,
1039 node_origins_->GetCurrentBytecodePosition());
1040 }
1041
1042 private:
1044};
1045
1049 FeedbackCellRef feedback_cell, BytecodeOffset osr_offset, JSGraph* jsgraph,
1050 CallFrequency const& invocation_frequency,
1052 int inlining_id, CodeKind code_kind, BytecodeGraphBuilderFlags flags,
1053 TickCounter* tick_counter, ObserveNodeInfo const& observe_node_info)
1054 : broker_(broker),
1055 local_isolate_(broker_->local_isolate()
1056 ? broker_->local_isolate()
1057 : broker_->isolate()->AsLocalIsolate()),
1062 bytecode_array_(bytecode),
1063 feedback_cell_(feedback_cell),
1064 feedback_vector_(feedback_cell.feedback_vector(broker).value()),
1065 invocation_frequency_(invocation_frequency),
1071 frame_state_function_info_(common()->CreateFrameStateFunctionInfo(
1073 bytecode_array().parameter_count(), bytecode_array().max_arguments(),
1074 bytecode_array().register_count(), shared_info.object(),
1075 bytecode_array().object())),
1079 bytecode_array().object(), local_zone, osr_offset,
1081 environment_(nullptr),
1082 decorator_(nullptr),
1083 osr_(!osr_offset.IsNone()),
1093 input_buffer_(nullptr),
1095 feedback_vector_node_(nullptr),
1096 native_context_node_(nullptr),
1100 node_origins_(node_origins),
1102 start_position_(shared_info.StartPosition(), inlining_id),
1103 tick_counter_(tick_counter),
1104 observe_node_info_(observe_node_info) {}
1105
1107 if (!function_closure_.is_set()) {
1109 Node* node = GetParameter(index, "%closure");
1110 function_closure_.set(node);
1111 }
1112 return function_closure_.get();
1113}
1114
1116 const char* debug_name_hint) {
1117 // We use negative indices for some parameters.
1118 DCHECK_LE(ParameterInfo::kMinIndex, parameter_index);
1119 const size_t index =
1120 static_cast<size_t>(parameter_index - ParameterInfo::kMinIndex);
1121
1122 if (cached_parameters_.size() <= index) {
1123 cached_parameters_.resize(index + 1, nullptr);
1124 }
1125
1126 if (cached_parameters_[index] == nullptr) {
1128 NewNode(common()->Parameter(parameter_index, debug_name_hint),
1129 graph()->start());
1130 }
1131
1132 return cached_parameters_[index];
1133}
1134
1140
1142 return jsgraph()->ConstantNoHole(
1143 feedback_vector().GetClosureFeedbackCell(broker(), index), broker());
1144}
1145
1150
1156
1160
1164
1167 if (node_origins_) {
1169 }
1170 // Set up the basic structure of the graph. Outputs for {Start} are the formal
1171 // parameters (including the receiver) plus new target, number of arguments,
1172 // context and closure.
1173 int start_output_arity = StartNode::OutputArityForFormalParameterCount(
1175 graph()->SetStart(graph()->NewNode(common()->Start(start_output_arity)));
1176
1177 Environment env(this, bytecode_array().register_count(),
1179 bytecode_array().incoming_new_target_or_generator_register(),
1180 graph()->start());
1181 set_environment(&env);
1182
1185
1187
1188 // Finish the basic structure of the graph.
1190 int const input_count = static_cast<int>(exit_controls_.size());
1191 Node** const inputs = &exit_controls_.front();
1192 Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs);
1193 graph()->SetEnd(end);
1194 if (node_origins_) {
1196 }
1197}
1198
1200 if (needs_eager_checkpoint()) {
1201 // Create an explicit checkpoint node for before the operation. This only
1202 // needs to happen if we aren't effect-dominated by a {Checkpoint} already.
1204 Node* node = NewNode(common()->Checkpoint());
1206 DCHECK_EQ(IrOpcode::kDead,
1207 NodeProperties::GetFrameStateInput(node)->opcode());
1208 BytecodeOffset bailout_id(bytecode_iterator().current_offset());
1209
1210 const BytecodeLivenessState* liveness_before =
1212 bytecode_iterator().current_offset());
1213
1214 Node* frame_state_before = environment()->Checkpoint(
1215 bailout_id, OutputFrameStateCombine::Ignore(), liveness_before);
1216 NodeProperties::ReplaceFrameStateInput(node, frame_state_before);
1217#ifdef DEBUG
1218 } else {
1219 // In case we skipped checkpoint creation above, we must be able to find an
1220 // existing checkpoint that effect-dominates the nodes about to be created.
1221 // Starting a search from the current effect-dependency has to succeed.
1222 Node* effect = environment()->GetEffectDependency();
1223 while (effect->opcode() != IrOpcode::kCheckpoint) {
1224 DCHECK(effect->op()->HasProperty(Operator::kNoWrite));
1225 DCHECK_EQ(1, effect->op()->EffectInputCount());
1226 effect = NodeProperties::GetEffectInput(effect);
1227 }
1228 }
1229#else
1230 }
1231#endif // DEBUG
1232}
1233
1234void BytecodeGraphBuilder::PrepareFrameState(
1235 Node* node, OutputFrameStateCombine combine, BytecodeOffset bailout_id,
1236 const BytecodeLivenessState* liveness) {
1237 if (OperatorProperties::HasFrameStateInput(node->op())) {
1238 // Add the frame state for after the operation. The node in question has
1239 // already been created and had a {Dead} frame state input up until now.
1240 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
1241 DCHECK_EQ(IrOpcode::kDead,
1242 NodeProperties::GetFrameStateInput(node)->opcode());
1243
1244 Node* frame_state_after =
1245 environment()->Checkpoint(bailout_id, combine, liveness);
1246 NodeProperties::ReplaceFrameStateInput(node, frame_state_after);
1247 }
1248}
1249
1250void BytecodeGraphBuilder::AdvanceIteratorsTo(int bytecode_offset) {
1251 for (; bytecode_iterator().current_offset() != bytecode_offset;
1252 bytecode_iterator().Advance()) {
1253 int current_offset = bytecode_iterator().current_offset();
1254 UpdateSourceAndBytecodePosition(current_offset);
1255 }
1256}
1257
1258// Stores the state of the SourcePosition iterator, and the index to the
1259// current exception handlers stack. We need, during the OSR graph generation,
1260// to backup the states of these iterators at the LoopHeader offset of each
1261// outer loop which contains the OSR loop. The iterators are then restored when
1262// peeling the loops, so that both exception handling and synchronisation with
1263// the source position can be achieved.
1265 public:
1267 : graph_builder_(graph_builder),
1268 saved_states_(graph_builder->local_zone()) {}
1269
1271 ZoneVector<int> outer_loop_offsets(graph_builder_->local_zone());
1272 int osr_entry = graph_builder_->bytecode_analysis().osr_entry_point();
1273
1274 // We find here the outermost loop which contains the OSR loop.
1275 int outermost_loop_offset = osr_entry;
1276 while ((outermost_loop_offset = graph_builder_->bytecode_analysis()
1277 .GetLoopInfoFor(outermost_loop_offset)
1278 .parent_offset()) != -1) {
1279 outer_loop_offsets.push_back(outermost_loop_offset);
1280 }
1281 outermost_loop_offset =
1282 outer_loop_offsets.empty() ? osr_entry : outer_loop_offsets.back();
1283 graph_builder_->AdvanceIteratorsTo(outermost_loop_offset);
1284
1285 // We save some iterators states at the offsets of the loop headers of the
1286 // outer loops (the ones containing the OSR loop). They will be used for
1287 // jumping back in the bytecode.
1289 outer_loop_offsets.crbegin();
1290 it != outer_loop_offsets.crend(); ++it) {
1291 graph_builder_->AdvanceIteratorsTo(*it);
1292 graph_builder_->ExitThenEnterExceptionHandlers(
1293 graph_builder_->bytecode_iterator().current_offset());
1294 saved_states_.push(IteratorsStates(
1295 graph_builder_->current_exception_handler(),
1296 graph_builder_->source_position_iterator().GetState()));
1297 }
1298
1299 // Finishing by advancing to the OSR entry
1300 graph_builder_->AdvanceIteratorsTo(osr_entry);
1301
1302 // Enters all remaining exception handler which end before the OSR loop
1303 // so that on next call of VisitSingleBytecode they will get popped from
1304 // the exception handlers stack.
1305 graph_builder_->ExitThenEnterExceptionHandlers(osr_entry);
1306 graph_builder_->set_currently_peeled_loop_offset(
1307 graph_builder_->bytecode_analysis()
1308 .GetLoopInfoFor(osr_entry)
1309 .parent_offset());
1310 }
1311
1312 void RestoreState(int target_offset, int new_parent_offset) {
1313 graph_builder_->bytecode_iterator().SetOffset(target_offset);
1314 // In case of a return, we must not build loop exits for
1315 // not-yet-built outer loops.
1316 graph_builder_->set_currently_peeled_loop_offset(new_parent_offset);
1317 IteratorsStates saved_state = saved_states_.top();
1318 graph_builder_->source_position_iterator().RestoreState(
1319 saved_state.source_iterator_state_);
1320 graph_builder_->set_current_exception_handler(
1321 saved_state.exception_handler_index_);
1322 saved_states_.pop();
1323 }
1324
1325 private:
1329
1330 IteratorsStates(int exception_handler_index,
1332 source_iterator_state)
1333 : exception_handler_index_(exception_handler_index),
1334 source_iterator_state_(source_iterator_state) {}
1335 };
1336
1339};
1340
1341void BytecodeGraphBuilder::RemoveMergeEnvironmentsBeforeOffset(
1342 int limit_offset) {
1343 if (!merge_environments_.empty()) {
1344 ZoneMap<int, Environment*>::iterator it = merge_environments_.begin();
1345 ZoneMap<int, Environment*>::iterator stop_it = merge_environments_.end();
1346 while (it != stop_it && it->first <= limit_offset) {
1347 it = merge_environments_.erase(it);
1348 }
1349 }
1350}
1351
1352void BytecodeGraphBuilder::BuildFunctionEntryStackCheck() {
1353 if (!skip_first_stack_check()) {
1354 DCHECK(exception_handlers_.empty());
1355 Node* node =
1356 NewNode(javascript()->StackCheck(StackCheckKind::kJSFunctionEntry));
1357 PrepareFrameStateForFunctionEntryStackCheck(node);
1358 }
1359}
1360
1361void BytecodeGraphBuilder::BuildIterationBodyStackCheck() {
1362 Node* node =
1363 NewNode(javascript()->StackCheck(StackCheckKind::kJSIterationBody));
1364 environment()->RecordAfterState(node, Environment::kAttachFrameState);
1365}
1366
1367void BytecodeGraphBuilder::BuildOSREntryStackCheck() {
1368 DCHECK(exception_handlers_.empty());
1369 Node* node =
1370 NewNode(javascript()->StackCheck(StackCheckKind::kJSFunctionEntry));
1371 PrepareFrameStateForOSREntryStackCheck(node);
1372}
1373
1374// We will iterate through the OSR loop, then its parent, and so on
1375// until we have reached the outmost loop containing the OSR loop. We do
1376// not generate nodes for anything before the outermost loop.
1377void BytecodeGraphBuilder::AdvanceToOsrEntryAndPeelLoops() {
1378 environment()->FillWithOsrValues();
1379
1380 // The entry stack check has to happen *before* initialising the OSR prelude;
1381 // it has to happen before setting up exception handlers, so that the
1382 // optimized code can't accidentally catch a failingstack with a OSR-ed loop
1383 // inside a try-catch, e.g.
1384 //
1385 // try {
1386 // loop { OSR(); }
1387 // } catch {
1388 // // Ignore failed stack check.
1389 // }
1390 BuildOSREntryStackCheck();
1391
1392 OsrIteratorState iterator_states(this);
1393 iterator_states.ProcessOsrPrelude();
1394 int osr_entry = bytecode_analysis().osr_entry_point();
1395 CHECK_EQ(bytecode_iterator().current_offset(), osr_entry);
1396
1397 // Suppose we have n nested loops, loop_0 being the outermost one, and
1398 // loop_n being the OSR loop. We start iterating the bytecode at the header
1399 // of loop_n (the OSR loop), and then we peel the part of the the body of
1400 // loop_{n-1} following the end of loop_n. We then rewind the iterator to
1401 // the header of loop_{n-1}, and so on until we have partly peeled loop 0.
1402 // The full loop_0 body will be generating with the rest of the function,
1403 // outside the OSR generation.
1404
1405 // To do so, if we are visiting a loop, we continue to visit what's left
1406 // of its parent, and then when reaching the parent's JumpLoop, we do not
1407 // create any jump for that but rewind the bytecode iterator to visit the
1408 // parent loop entirely, and so on.
1409
1410 int current_parent_offset =
1411 bytecode_analysis().GetLoopInfoFor(osr_entry).parent_offset();
1412 while (current_parent_offset != -1) {
1413 const LoopInfo& current_parent_loop =
1414 bytecode_analysis().GetLoopInfoFor(current_parent_offset);
1415 // We iterate until the back edge of the parent loop, which we detect by
1416 // the offset that the JumpLoop targets.
1417 for (; !bytecode_iterator().done(); bytecode_iterator().Advance()) {
1418 if (bytecode_iterator().current_bytecode() ==
1419 interpreter::Bytecode::kJumpLoop &&
1420 bytecode_iterator().GetJumpTargetOffset() == current_parent_offset) {
1421 // Reached the end of the current parent loop.
1422 break;
1423 }
1424 VisitSingleBytecode();
1425 }
1426 DCHECK(!bytecode_iterator()
1427 .done()); // Should have found the loop's jump target.
1428
1429 // We also need to take care of the merge environments and exceptions
1430 // handlers here because the omitted JumpLoop bytecode can still be the
1431 // target of jumps or the first bytecode after a try block.
1432 ExitThenEnterExceptionHandlers(bytecode_iterator().current_offset());
1433 SwitchToMergeEnvironment(bytecode_iterator().current_offset());
1434
1435 // This jump is the jump of our parent loop, which is not yet created.
1436 // So we do not build the jump nodes, but restore the bytecode and the
1437 // SourcePosition iterators to the values they had when we were visiting
1438 // the offset pointed at by the JumpLoop we've just reached.
1439 // We have already built nodes for inner loops, but now we will
1440 // iterate again over them and build new nodes corresponding to the same
1441 // bytecode offsets. Any jump or reference to this inner loops must now
1442 // point to the new nodes we will build, hence we clear the relevant part
1443 // of the environment.
1444 // Completely clearing the environment is not possible because merge
1445 // environments for forward jumps out of the loop need to be preserved
1446 // (e.g. a return or a labeled break in the middle of a loop).
1447 RemoveMergeEnvironmentsBeforeOffset(bytecode_iterator().current_offset());
1448 iterator_states.RestoreState(current_parent_offset,
1449 current_parent_loop.parent_offset());
1450 current_parent_offset = current_parent_loop.parent_offset();
1451 }
1452}
1453
1454void BytecodeGraphBuilder::VisitSingleBytecode() {
1455 tick_counter_->TickAndMaybeEnterSafepoint();
1456 int current_offset = bytecode_iterator().current_offset();
1457 UpdateSourceAndBytecodePosition(current_offset);
1458 ExitThenEnterExceptionHandlers(current_offset);
1459 DCHECK_GE(exception_handlers_.empty() ? current_offset
1460 : exception_handlers_.top().end_offset_,
1461 current_offset);
1462 SwitchToMergeEnvironment(current_offset);
1463
1464 if (environment() != nullptr) {
1465 BuildLoopHeaderEnvironment(current_offset);
1466
1467 switch (bytecode_iterator().current_bytecode()) {
1468#define BYTECODE_CASE(name, ...) \
1469 case interpreter::Bytecode::k##name: \
1470 Visit##name(); \
1471 break;
1473#undef BYTECODE_CASE
1474 }
1475 }
1476}
1477
1478void BytecodeGraphBuilder::VisitBytecodes() {
1479 if (!bytecode_analysis().resume_jump_targets().empty()) {
1480 environment()->BindGeneratorState(
1482 }
1483
1484 if (osr_) {
1485 // Make sure we're at a valid OSR entrypoint.
1486 // This is also a defense-in-depth check to make sure that we're not
1487 // compiling invalid bytecode if the OSR offset is wrong (e.g. because it
1488 // belongs to different bytecode).
1489 int osr_offset = bytecode_analysis().osr_bailout_id().ToInt();
1490 int osr_entry = bytecode_analysis().osr_entry_point();
1491 interpreter::BytecodeArrayIterator it(bytecode_array().object());
1492 it.AdvanceTo(osr_offset);
1493 CHECK(it.CurrentBytecodeIsValidOSREntry());
1494 CHECK_EQ(osr_entry, it.GetJumpTargetOffset());
1495
1496 // We peel the OSR loop and any outer loop containing it except that we
1497 // leave the nodes corresponding to the whole outermost loop (including
1498 // the last copies of the loops it contains) to be generated by the normal
1499 // bytecode iteration below.
1500 AdvanceToOsrEntryAndPeelLoops();
1501 } else {
1502 BuildFunctionEntryStackCheck();
1503 }
1504
1505 for (; !bytecode_iterator().done(); bytecode_iterator().Advance()) {
1506 VisitSingleBytecode();
1507 }
1508
1509 DCHECK(exception_handlers_.empty());
1510}
1511
1512void BytecodeGraphBuilder::AddBytecodePositionDecorator() {
1513 DCHECK_NULL(decorator_);
1514 decorator_ = graph_zone()->New<BytecodePositionDecorator>(node_origins_);
1515 graph()->AddDecorator(decorator_);
1516}
1517
1518void BytecodeGraphBuilder::RemoveBytecodePositionDecorator() {
1519 DCHECK_NOT_NULL(decorator_);
1520 graph()->RemoveDecorator(decorator_);
1521 decorator_ = nullptr;
1522}
1523
1524void BytecodeGraphBuilder::VisitLdaZero() {
1525 Node* node = jsgraph()->ZeroConstant();
1526 environment()->BindAccumulator(node);
1527}
1528
1529void BytecodeGraphBuilder::VisitLdaSmi() {
1530 Node* node =
1531 jsgraph()->ConstantNoHole(bytecode_iterator().GetImmediateOperand(0));
1532 environment()->BindAccumulator(node);
1533}
1534
1535void BytecodeGraphBuilder::VisitLdaConstant() {
1536 ObjectRef object = MakeRefForConstantForIndexOperand(0);
1537 Node* node = jsgraph()->ConstantNoHole(object, broker());
1538 environment()->BindAccumulator(node);
1539}
1540
1541void BytecodeGraphBuilder::VisitLdaUndefined() {
1542 Node* node = jsgraph()->UndefinedConstant();
1543 environment()->BindAccumulator(node);
1544}
1545
1546void BytecodeGraphBuilder::VisitLdaNull() {
1547 Node* node = jsgraph()->NullConstant();
1548 environment()->BindAccumulator(node);
1549}
1550
1551void BytecodeGraphBuilder::VisitLdaTheHole() {
1552 Node* node = jsgraph()->TheHoleConstant();
1553 environment()->BindAccumulator(node);
1554}
1555
1556void BytecodeGraphBuilder::VisitLdaTrue() {
1557 Node* node = jsgraph()->TrueConstant();
1558 environment()->BindAccumulator(node);
1559}
1560
1561void BytecodeGraphBuilder::VisitLdaFalse() {
1562 Node* node = jsgraph()->FalseConstant();
1563 environment()->BindAccumulator(node);
1564}
1565
1566void BytecodeGraphBuilder::VisitLdar() {
1567 Node* value =
1568 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
1569 environment()->BindAccumulator(value);
1570}
1571
1572void BytecodeGraphBuilder::VisitStar() {
1573 Node* value = environment()->LookupAccumulator();
1574 environment()->BindRegister(bytecode_iterator().GetRegisterOperand(0), value);
1575}
1576
1577#define SHORT_STAR_VISITOR(Name, ...) \
1578 void BytecodeGraphBuilder::Visit##Name() { \
1579 Node* value = environment()->LookupAccumulator(); \
1580 environment()->BindRegister( \
1581 interpreter::Register::FromShortStar(interpreter::Bytecode::k##Name), \
1582 value); \
1583 }
1585#undef SHORT_STAR_VISITOR
1586
1587void BytecodeGraphBuilder::VisitMov() {
1588 Node* value =
1589 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
1590 environment()->BindRegister(bytecode_iterator().GetRegisterOperand(1), value);
1591}
1592
1593Node* BytecodeGraphBuilder::BuildLoadGlobal(NameRef name,
1594 uint32_t feedback_slot_index,
1595 TypeofMode typeof_mode) {
1596 FeedbackSource feedback = CreateFeedbackSource(feedback_slot_index);
1597 DCHECK(IsLoadGlobalICKind(broker()->GetFeedbackSlotKind(feedback)));
1598 const Operator* op = javascript()->LoadGlobal(name, feedback, typeof_mode);
1599 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
1600 return NewNode(op, feedback_vector_node());
1601}
1602
1603void BytecodeGraphBuilder::VisitLdaGlobal() {
1604 PrepareEagerCheckpoint();
1605 NameRef name = MakeRefForConstantForIndexOperand<Name>(0);
1606 uint32_t feedback_slot_index = bytecode_iterator().GetIndexOperand(1);
1607 Node* node =
1608 BuildLoadGlobal(name, feedback_slot_index, TypeofMode::kNotInside);
1609 environment()->BindAccumulator(node, Environment::kAttachFrameState);
1610}
1611
1612void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeof() {
1613 PrepareEagerCheckpoint();
1614 NameRef name = MakeRefForConstantForIndexOperand<Name>(0);
1615 uint32_t feedback_slot_index = bytecode_iterator().GetIndexOperand(1);
1616 Node* node = BuildLoadGlobal(name, feedback_slot_index, TypeofMode::kInside);
1617 environment()->BindAccumulator(node, Environment::kAttachFrameState);
1618}
1619
1620void BytecodeGraphBuilder::VisitStaGlobal() {
1621 PrepareEagerCheckpoint();
1622 NameRef name = MakeRefForConstantForIndexOperand<Name>(0);
1623 FeedbackSource feedback =
1624 CreateFeedbackSource(bytecode_iterator().GetIndexOperand(1));
1625 Node* value = environment()->LookupAccumulator();
1626
1627 LanguageMode language_mode =
1628 GetLanguageModeFromSlotKind(broker()->GetFeedbackSlotKind(feedback));
1629 const Operator* op = javascript()->StoreGlobal(language_mode, name, feedback);
1630 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
1631 Node* node = NewNode(op, value, feedback_vector_node());
1632 environment()->RecordAfterState(node, Environment::kAttachFrameState);
1633}
1634
1635void BytecodeGraphBuilder::VisitStaInArrayLiteral() {
1636 PrepareEagerCheckpoint();
1637 Node* value = environment()->LookupAccumulator();
1638 Node* array =
1639 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
1640 Node* index =
1641 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
1642 FeedbackSource feedback =
1643 CreateFeedbackSource(bytecode_iterator().GetIndexOperand(2));
1644 const Operator* op = javascript()->StoreInArrayLiteral(feedback);
1645
1646 JSTypeHintLowering::LoweringResult lowering =
1647 TryBuildSimplifiedStoreKeyed(op, array, index, value, feedback.slot);
1648 if (lowering.IsExit()) return;
1649
1650 Node* node = nullptr;
1651 if (lowering.IsSideEffectFree()) {
1652 node = lowering.value();
1653 } else {
1654 DCHECK(!lowering.Changed());
1655 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
1656 node = NewNode(op, array, index, value, feedback_vector_node());
1657 }
1658
1659 environment()->RecordAfterState(node, Environment::kAttachFrameState);
1660}
1661
1662void BytecodeGraphBuilder::VisitDefineKeyedOwnPropertyInLiteral() {
1663 PrepareEagerCheckpoint();
1664
1665 Node* object =
1666 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
1667 Node* name =
1668 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
1669 Node* value = environment()->LookupAccumulator();
1670 int flags = bytecode_iterator().GetFlag8Operand(2);
1671 FeedbackSource feedback =
1672 CreateFeedbackSource(bytecode_iterator().GetIndexOperand(3));
1673 const Operator* op = javascript()->DefineKeyedOwnPropertyInLiteral(feedback);
1674
1675 JSTypeHintLowering::LoweringResult lowering =
1676 TryBuildSimplifiedStoreKeyed(op, object, name, value, feedback.slot);
1677 if (lowering.IsExit()) return;
1678
1679 Node* node = nullptr;
1680 if (lowering.IsSideEffectFree()) {
1681 node = lowering.value();
1682 } else {
1683 DCHECK(!lowering.Changed());
1684 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
1685 node = NewNode(op, object, name, value, jsgraph()->ConstantNoHole(flags),
1686 feedback_vector_node());
1687 }
1688
1689 environment()->RecordAfterState(node, Environment::kAttachFrameState);
1690}
1691
1692void BytecodeGraphBuilder::VisitLdaContextSlot() {
1693 const Operator* op = javascript()->LoadContext(
1694 bytecode_iterator().GetUnsignedImmediateOperand(2),
1695 bytecode_iterator().GetIndexOperand(1), false);
1696 Node* node = NewNode(op);
1697 Node* context =
1698 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
1699 NodeProperties::ReplaceContextInput(node, context);
1700 environment()->BindAccumulator(node);
1701}
1702
1703void BytecodeGraphBuilder::VisitLdaScriptContextSlot() {
1704 const Operator* op = javascript()->LoadScriptContext(
1705 bytecode_iterator().GetUnsignedImmediateOperand(2),
1706 bytecode_iterator().GetIndexOperand(1));
1707 Node* node = NewNode(op);
1708 Node* context =
1709 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
1710 NodeProperties::ReplaceContextInput(node, context);
1711 environment()->BindAccumulator(node);
1712}
1713
1714void BytecodeGraphBuilder::VisitLdaImmutableContextSlot() {
1715 const Operator* op = javascript()->LoadContext(
1716 bytecode_iterator().GetUnsignedImmediateOperand(2),
1717 bytecode_iterator().GetIndexOperand(1), true);
1718 Node* node = NewNode(op);
1719 Node* context =
1720 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
1721 NodeProperties::ReplaceContextInput(node, context);
1722 environment()->BindAccumulator(node);
1723}
1724
1725void BytecodeGraphBuilder::VisitLdaCurrentContextSlot() {
1726 const Operator* op = javascript()->LoadContext(
1727 0, bytecode_iterator().GetIndexOperand(0), false);
1728 Node* node = NewNode(op);
1729 environment()->BindAccumulator(node);
1730}
1731
1732void BytecodeGraphBuilder::VisitLdaCurrentScriptContextSlot() {
1733 const Operator* op = javascript()->LoadScriptContext(
1734 0, bytecode_iterator().GetIndexOperand(0));
1735 Node* node = NewNode(op);
1736 environment()->BindAccumulator(node);
1737}
1738
1739void BytecodeGraphBuilder::VisitLdaImmutableCurrentContextSlot() {
1740 const Operator* op = javascript()->LoadContext(
1741 0, bytecode_iterator().GetIndexOperand(0), true);
1742 Node* node = NewNode(op);
1743 environment()->BindAccumulator(node);
1744}
1745
1746void BytecodeGraphBuilder::VisitStaContextSlot() {
1747 const Operator* op = javascript()->StoreContext(
1748 bytecode_iterator().GetUnsignedImmediateOperand(2),
1749 bytecode_iterator().GetIndexOperand(1));
1750 Node* value = environment()->LookupAccumulator();
1751 Node* node = NewNode(op, value);
1752 Node* context =
1753 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
1754 NodeProperties::ReplaceContextInput(node, context);
1755}
1756
1757void BytecodeGraphBuilder::VisitStaCurrentContextSlot() {
1758 const Operator* op =
1759 javascript()->StoreContext(0, bytecode_iterator().GetIndexOperand(0));
1760 Node* value = environment()->LookupAccumulator();
1761 NewNode(op, value);
1762}
1763
1764void BytecodeGraphBuilder::VisitStaScriptContextSlot() {
1765 PrepareEagerCheckpoint();
1766 const Operator* op = javascript()->StoreScriptContext(
1767 bytecode_iterator().GetUnsignedImmediateOperand(2),
1768 bytecode_iterator().GetIndexOperand(1));
1769 Node* value = environment()->LookupAccumulator();
1770 Node* node = NewNode(op, value);
1771 Node* context =
1772 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
1773 NodeProperties::ReplaceContextInput(node, context);
1774}
1775
1776void BytecodeGraphBuilder::VisitStaCurrentScriptContextSlot() {
1777 PrepareEagerCheckpoint();
1778 const Operator* op = javascript()->StoreScriptContext(
1779 0, bytecode_iterator().GetIndexOperand(0));
1780 Node* value = environment()->LookupAccumulator();
1781 NewNode(op, value);
1782}
1783
1784void BytecodeGraphBuilder::BuildLdaLookupSlot(TypeofMode typeof_mode) {
1785 PrepareEagerCheckpoint();
1786 Node* name =
1787 jsgraph()->ConstantNoHole(MakeRefForConstantForIndexOperand(0), broker());
1788 const Operator* op =
1789 javascript()->CallRuntime(typeof_mode == TypeofMode::kNotInside
1790 ? Runtime::kLoadLookupSlot
1791 : Runtime::kLoadLookupSlotInsideTypeof);
1792 Node* value = NewNode(op, name);
1793 environment()->BindAccumulator(value, Environment::kAttachFrameState);
1794}
1795
1796void BytecodeGraphBuilder::VisitLdaLookupSlot() {
1797 BuildLdaLookupSlot(TypeofMode::kNotInside);
1798}
1799
1800void BytecodeGraphBuilder::VisitLdaLookupSlotInsideTypeof() {
1801 BuildLdaLookupSlot(TypeofMode::kInside);
1802}
1803
1804BytecodeGraphBuilder::Environment*
1805BytecodeGraphBuilder::CheckContextExtensionAtDepth(
1806 Environment* slow_environment, uint32_t depth) {
1807 Node* extension_slot = NewNode(
1808 javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false));
1809 Node* check_no_extension =
1810 NewNode(simplified()->ReferenceEqual(), extension_slot,
1811 jsgraph()->UndefinedConstant());
1812 NewBranch(check_no_extension);
1813 {
1814 SubEnvironment sub_environment(this);
1815 NewIfFalse();
1816 // If there is an extension, merge into the slow path.
1817 if (slow_environment == nullptr) {
1818 slow_environment = environment();
1819 NewMerge();
1820 } else {
1821 slow_environment->Merge(environment(),
1822 bytecode_analysis().GetInLivenessFor(
1823 bytecode_iterator().current_offset()));
1824 }
1825 }
1826 NewIfTrue();
1827 // Do nothing on if there is no extension, eventually falling through to
1828 // the fast path.
1829 DCHECK_NOT_NULL(slow_environment);
1830 return slow_environment;
1831}
1832
1833OptionalScopeInfoRef BytecodeGraphBuilder::TryGetScopeInfo() {
1834 Node* context = environment()->Context();
1835 switch (context->opcode()) {
1836 case IrOpcode::kJSCreateFunctionContext:
1837 return CreateFunctionContextParametersOf(context->op()).scope_info();
1838 case IrOpcode::kJSCreateBlockContext:
1839 case IrOpcode::kJSCreateCatchContext:
1840 case IrOpcode::kJSCreateWithContext:
1841 return ScopeInfoOf(context->op());
1842 case IrOpcode::kParameter: {
1843 ScopeInfoRef scope_info = shared_info_.scope_info(broker());
1844 if (scope_info.HasOuterScopeInfo()) {
1845 scope_info = scope_info.OuterScopeInfo(broker());
1846 }
1847 return scope_info;
1848 }
1849 default:
1850 return std::nullopt;
1851 }
1852}
1853
1854BytecodeGraphBuilder::Environment* BytecodeGraphBuilder::CheckContextExtensions(
1855 uint32_t depth) {
1856 OptionalScopeInfoRef maybe_scope_info = TryGetScopeInfo();
1857 if (!maybe_scope_info.has_value()) {
1858 return CheckContextExtensionsSlowPath(depth);
1859 }
1860
1861 ScopeInfoRef scope_info = maybe_scope_info.value();
1862 // We only need to check up to the last-but-one depth, because an eval
1863 // in the same scope as the variable itself has no way of shadowing it.
1864 Environment* slow_environment = nullptr;
1865 for (uint32_t d = 0; d < depth; d++) {
1866 // Const tracking let data is stored in the extension slot of a
1867 // ScriptContext - however, it's unrelated to the sloppy eval variable
1868 // extension. We should never iterate through a ScriptContext here.
1871
1872 if (scope_info.HasContextExtensionSlot() &&
1873 !broker()->dependencies()->DependOnEmptyContextExtension(scope_info)) {
1874 // Using EmptyContextExtension dependency is not possible for this
1875 // scope_info, so generate dynamic checks.
1876 slow_environment = CheckContextExtensionAtDepth(slow_environment, d);
1877 }
1878 DCHECK_IMPLIES(!scope_info.HasOuterScopeInfo(), d + 1 == depth);
1879 if (scope_info.HasOuterScopeInfo()) {
1880 scope_info = scope_info.OuterScopeInfo(broker());
1881 }
1882 }
1883
1884 // There should have been at least one slow path generated, otherwise we
1885 // could have already skipped the lookup in the bytecode. The only exception
1886 // is if we replaced all the dynamic checks with code dependencies.
1887 DCHECK_IMPLIES(!v8_flags.empty_context_extension_dep,
1888 slow_environment != nullptr);
1889 return slow_environment;
1890}
1891
1893BytecodeGraphBuilder::CheckContextExtensionsSlowPath(uint32_t depth) {
1894 // Output environment where the context has an extension
1895 Environment* slow_environment = nullptr;
1896
1897 // We only need to check up to the last-but-one depth, because an eval
1898 // in the same scope as the variable itself has no way of shadowing it.
1899 for (uint32_t d = 0; d < depth; d++) {
1900 Node* has_extension = NewNode(javascript()->HasContextExtension(d));
1901
1902 Environment* undefined_extension_env;
1903 NewBranch(has_extension);
1904 {
1905 SubEnvironment sub_environment(this);
1906 NewIfTrue();
1907 slow_environment = CheckContextExtensionAtDepth(slow_environment, d);
1908 undefined_extension_env = environment();
1909 }
1910 NewIfFalse();
1911 environment()->Merge(undefined_extension_env,
1912 bytecode_analysis().GetInLivenessFor(
1913 bytecode_iterator().current_offset()));
1914 mark_as_needing_eager_checkpoint(true);
1915 // Do nothing on if there is no extension, eventually falling through to
1916 // the fast path.
1917 }
1918
1919 // There should have been at least one slow path generated, otherwise we could
1920 // have already skipped the lookup in the bytecode.
1921 DCHECK_NOT_NULL(slow_environment);
1922 return slow_environment;
1923}
1924
1925void BytecodeGraphBuilder::BuildLdaLookupContextSlot(ContextKind context_kind,
1926 TypeofMode typeof_mode) {
1927 uint32_t depth = bytecode_iterator().GetUnsignedImmediateOperand(2);
1928
1929 // Check if any context in the depth has an extension.
1930 Environment* slow_environment = CheckContextExtensions(depth);
1931
1932 // Fast path, do a context load.
1933 {
1934 uint32_t slot_index = bytecode_iterator().GetIndexOperand(1);
1935
1936 const Operator* op =
1937 context_kind == ContextKind::kScriptContext
1938 ? javascript()->LoadScriptContext(depth, slot_index)
1939 : javascript()->LoadContext(depth, slot_index, false);
1940 environment()->BindAccumulator(NewNode(op));
1941 }
1942 if (!slow_environment) {
1943 // The slow path was fully replaced by a set of compilation dependencies.
1944 return;
1945 }
1946
1947 // Add a merge to the fast environment.
1948 NewMerge();
1949 Environment* fast_environment = environment();
1950
1951 // Slow path, do a runtime load lookup.
1952 set_environment(slow_environment);
1953 {
1954 Node* name = jsgraph()->ConstantNoHole(MakeRefForConstantForIndexOperand(0),
1955 broker());
1956
1957 const Operator* op =
1958 javascript()->CallRuntime(typeof_mode == TypeofMode::kNotInside
1959 ? Runtime::kLoadLookupSlot
1960 : Runtime::kLoadLookupSlotInsideTypeof);
1961 Node* value = NewNode(op, name);
1962 environment()->BindAccumulator(value, Environment::kAttachFrameState);
1963 }
1964
1965 fast_environment->Merge(environment(),
1966 bytecode_analysis().GetOutLivenessFor(
1967 bytecode_iterator().current_offset()));
1968 set_environment(fast_environment);
1969 mark_as_needing_eager_checkpoint(true);
1970}
1971
1972void BytecodeGraphBuilder::VisitLdaLookupContextSlot() {
1973 BuildLdaLookupContextSlot(ContextKind::kDefault, TypeofMode::kNotInside);
1974}
1975
1976void BytecodeGraphBuilder::VisitLdaLookupScriptContextSlot() {
1977 BuildLdaLookupContextSlot(ContextKind::kScriptContext,
1979}
1980
1981void BytecodeGraphBuilder::VisitLdaLookupContextSlotInsideTypeof() {
1982 BuildLdaLookupContextSlot(ContextKind::kDefault, TypeofMode::kInside);
1983}
1984
1985void BytecodeGraphBuilder::VisitLdaLookupScriptContextSlotInsideTypeof() {
1986 BuildLdaLookupContextSlot(ContextKind::kScriptContext, TypeofMode::kInside);
1987}
1988
1989void BytecodeGraphBuilder::BuildLdaLookupGlobalSlot(TypeofMode typeof_mode) {
1990 uint32_t depth = bytecode_iterator().GetUnsignedImmediateOperand(2);
1991
1992 // Check if any context in the depth has an extension.
1993 Environment* slow_environment = CheckContextExtensions(depth);
1994
1995 // Fast path, do a global load.
1996 {
1997 PrepareEagerCheckpoint();
1998 NameRef name = MakeRefForConstantForIndexOperand<Name>(0);
1999 uint32_t feedback_slot_index = bytecode_iterator().GetIndexOperand(1);
2000 Node* node = BuildLoadGlobal(name, feedback_slot_index, typeof_mode);
2001 environment()->BindAccumulator(node, Environment::kAttachFrameState);
2002 }
2003 if (!slow_environment) {
2004 // The slow path was fully replaced by a set of compilation dependencies.
2005 return;
2006 }
2007
2008 // Add a merge to the fast environment.
2009 NewMerge();
2010 Environment* fast_environment = environment();
2011
2012 // Slow path, do a runtime load lookup.
2013 set_environment(slow_environment);
2014 {
2015 Node* name = jsgraph()->ConstantNoHole(
2016 MakeRefForConstantForIndexOperand<Name>(0), broker());
2017
2018 const Operator* op =
2019 javascript()->CallRuntime(typeof_mode == TypeofMode::kNotInside
2020 ? Runtime::kLoadLookupSlot
2021 : Runtime::kLoadLookupSlotInsideTypeof);
2022 Node* value = NewNode(op, name);
2023 environment()->BindAccumulator(value, Environment::kAttachFrameState);
2024 }
2025
2026 fast_environment->Merge(environment(),
2027 bytecode_analysis().GetOutLivenessFor(
2028 bytecode_iterator().current_offset()));
2029 set_environment(fast_environment);
2030 mark_as_needing_eager_checkpoint(true);
2031}
2032
2033void BytecodeGraphBuilder::VisitLdaLookupGlobalSlot() {
2034 BuildLdaLookupGlobalSlot(TypeofMode::kNotInside);
2035}
2036
2037void BytecodeGraphBuilder::VisitLdaLookupGlobalSlotInsideTypeof() {
2038 BuildLdaLookupGlobalSlot(TypeofMode::kInside);
2039}
2040
2041void BytecodeGraphBuilder::VisitStaLookupSlot() {
2042 PrepareEagerCheckpoint();
2043 Node* value = environment()->LookupAccumulator();
2044 Node* name =
2045 jsgraph()->ConstantNoHole(MakeRefForConstantForIndexOperand(0), broker());
2046 int bytecode_flags = bytecode_iterator().GetFlag8Operand(1);
2047 LanguageMode language_mode = static_cast<LanguageMode>(
2049 bytecode_flags));
2050 LookupHoistingMode lookup_hoisting_mode = static_cast<LookupHoistingMode>(
2052 bytecode_flags));
2053 DCHECK_IMPLIES(lookup_hoisting_mode == LookupHoistingMode::kLegacySloppy,
2054 is_sloppy(language_mode));
2055 const Operator* op = javascript()->CallRuntime(
2056 is_strict(language_mode)
2057 ? Runtime::kStoreLookupSlot_Strict
2058 : lookup_hoisting_mode == LookupHoistingMode::kLegacySloppy
2059 ? Runtime::kStoreLookupSlot_SloppyHoisting
2060 : Runtime::kStoreLookupSlot_Sloppy);
2061 Node* store = NewNode(op, name, value);
2062 environment()->BindAccumulator(store, Environment::kAttachFrameState);
2063}
2064
2065void BytecodeGraphBuilder::VisitGetNamedProperty() {
2066 PrepareEagerCheckpoint();
2067 Node* object =
2068 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2069 NameRef name = MakeRefForConstantForIndexOperand<Name>(1);
2070 FeedbackSource feedback =
2071 CreateFeedbackSource(bytecode_iterator().GetIndexOperand(2));
2072 const Operator* op = javascript()->LoadNamed(name, feedback);
2073
2074 JSTypeHintLowering::LoweringResult lowering =
2075 TryBuildSimplifiedLoadNamed(op, feedback.slot);
2076 if (lowering.IsExit()) return;
2077
2078 Node* node = nullptr;
2079 if (lowering.IsSideEffectFree()) {
2080 node = lowering.value();
2081 } else {
2082 DCHECK(!lowering.Changed());
2083 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2084 node = NewNode(op, object, feedback_vector_node());
2085 }
2086 environment()->BindAccumulator(node, Environment::kAttachFrameState);
2087}
2088
2089void BytecodeGraphBuilder::VisitGetNamedPropertyFromSuper() {
2090 PrepareEagerCheckpoint();
2091 Node* receiver =
2092 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2093 Node* home_object = environment()->LookupAccumulator();
2094 NameRef name = MakeRefForConstantForIndexOperand<Name>(1);
2095
2096 FeedbackSource feedback =
2097 CreateFeedbackSource(bytecode_iterator().GetIndexOperand(2));
2098 const Operator* op = javascript()->LoadNamedFromSuper(name, feedback);
2099
2100 JSTypeHintLowering::LoweringResult lowering =
2101 TryBuildSimplifiedLoadNamed(op, feedback.slot);
2102 if (lowering.IsExit()) return;
2103
2104 Node* node = nullptr;
2105 if (lowering.IsSideEffectFree()) {
2106 node = lowering.value();
2107 } else {
2108 DCHECK(!lowering.Changed());
2109 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2110 node = NewNode(op, receiver, home_object, feedback_vector_node());
2111 }
2112 environment()->BindAccumulator(node, Environment::kAttachFrameState);
2113}
2114
2115void BytecodeGraphBuilder::VisitGetKeyedProperty() {
2116 PrepareEagerCheckpoint();
2117 Node* key = environment()->LookupAccumulator();
2118 Node* object =
2119 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2120 FeedbackSource feedback =
2121 CreateFeedbackSource(bytecode_iterator().GetIndexOperand(1));
2122 const Operator* op = javascript()->LoadProperty(feedback);
2123
2124 JSTypeHintLowering::LoweringResult lowering =
2125 TryBuildSimplifiedLoadKeyed(op, object, key, feedback.slot);
2126 if (lowering.IsExit()) return;
2127
2128 Node* node = nullptr;
2129 if (lowering.IsSideEffectFree()) {
2130 node = lowering.value();
2131 } else {
2132 DCHECK(!lowering.Changed());
2133 static_assert(JSLoadPropertyNode::ObjectIndex() == 0);
2134 static_assert(JSLoadPropertyNode::KeyIndex() == 1);
2135 static_assert(JSLoadPropertyNode::FeedbackVectorIndex() == 2);
2136 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2137 node = NewNode(op, object, key, feedback_vector_node());
2138 }
2139 environment()->BindAccumulator(node, Environment::kAttachFrameState);
2140}
2141
2142void BytecodeGraphBuilder::VisitGetEnumeratedKeyedProperty() {
2143 // GetEnumeratedKeyedProperty <object> <enum_index> <cache_type> <slot>
2144 PrepareEagerCheckpoint();
2145 Node* key = environment()->LookupAccumulator();
2146 Node* object =
2147 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2148 FeedbackSource feedback =
2149 CreateFeedbackSource(bytecode_iterator().GetIndexOperand(3));
2150 const Operator* op = javascript()->LoadProperty(feedback);
2151
2152 static_assert(JSLoadPropertyNode::ObjectIndex() == 0);
2153 static_assert(JSLoadPropertyNode::KeyIndex() == 1);
2154 static_assert(JSLoadPropertyNode::FeedbackVectorIndex() == 2);
2155 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2156 Node* node = NewNode(op, object, key, feedback_vector_node());
2157 environment()->BindAccumulator(node, Environment::kAttachFrameState);
2158}
2159
2160void BytecodeGraphBuilder::BuildNamedStore(NamedStoreMode store_mode) {
2161 PrepareEagerCheckpoint();
2162 Node* value = environment()->LookupAccumulator();
2163 Node* object =
2164 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2165 NameRef name = MakeRefForConstantForIndexOperand<Name>(1);
2166 FeedbackSource feedback =
2167 CreateFeedbackSource(bytecode_iterator().GetIndexOperand(2));
2168
2169 const Operator* op;
2170 if (store_mode == NamedStoreMode::kDefineOwn) {
2172 broker()->GetFeedbackSlotKind(feedback));
2173
2174 op = javascript()->DefineNamedOwnProperty(name, feedback);
2175 } else {
2176 DCHECK_EQ(NamedStoreMode::kSet, store_mode);
2177 LanguageMode language_mode =
2178 GetLanguageModeFromSlotKind(broker()->GetFeedbackSlotKind(feedback));
2179 op = javascript()->SetNamedProperty(language_mode, name, feedback);
2180 }
2181
2183 TryBuildSimplifiedStoreNamed(op, object, value, feedback.slot);
2184 if (lowering.IsExit()) return;
2185
2186 Node* node = nullptr;
2187 if (lowering.IsSideEffectFree()) {
2188 node = lowering.value();
2189 } else {
2190 DCHECK(!lowering.Changed());
2191 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2192 node = NewNode(op, object, value, feedback_vector_node());
2193 }
2194 environment()->RecordAfterState(node, Environment::kAttachFrameState);
2195}
2196
2197void BytecodeGraphBuilder::VisitSetNamedProperty() {
2198 BuildNamedStore(NamedStoreMode::kSet);
2199}
2200
2201void BytecodeGraphBuilder::VisitDefineNamedOwnProperty() {
2202 BuildNamedStore(NamedStoreMode::kDefineOwn);
2203}
2204
2205void BytecodeGraphBuilder::VisitSetKeyedProperty() {
2206 PrepareEagerCheckpoint();
2207 Node* value = environment()->LookupAccumulator();
2208 Node* object =
2209 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2210 Node* key =
2211 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
2212 FeedbackSource source =
2213 CreateFeedbackSource(bytecode_iterator().GetIndexOperand(2));
2214 LanguageMode language_mode =
2215 GetLanguageModeFromSlotKind(broker()->GetFeedbackSlotKind(source));
2216 const Operator* op = javascript()->SetKeyedProperty(language_mode, source);
2217
2218 JSTypeHintLowering::LoweringResult lowering =
2219 TryBuildSimplifiedStoreKeyed(op, object, key, value, source.slot);
2220 if (lowering.IsExit()) return;
2221
2222 Node* node = nullptr;
2223 if (lowering.IsSideEffectFree()) {
2224 node = lowering.value();
2225 } else {
2226 DCHECK(!lowering.Changed());
2227 static_assert(JSSetKeyedPropertyNode::ObjectIndex() == 0);
2228 static_assert(JSSetKeyedPropertyNode::KeyIndex() == 1);
2229 static_assert(JSSetKeyedPropertyNode::ValueIndex() == 2);
2230 static_assert(JSSetKeyedPropertyNode::FeedbackVectorIndex() == 3);
2231 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2232 node = NewNode(op, object, key, value, feedback_vector_node());
2233 }
2234
2235 environment()->RecordAfterState(node, Environment::kAttachFrameState);
2236}
2237
2238void BytecodeGraphBuilder::VisitDefineKeyedOwnProperty() {
2239 PrepareEagerCheckpoint();
2240 Node* value = environment()->LookupAccumulator();
2241 Node* object =
2242 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2243 Node* key =
2244 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
2245 int flags = bytecode_iterator().GetFlag8Operand(2);
2246 FeedbackSource source =
2247 CreateFeedbackSource(bytecode_iterator().GetIndexOperand(3));
2248 LanguageMode language_mode =
2249 GetLanguageModeFromSlotKind(broker()->GetFeedbackSlotKind(source));
2250
2251 const Operator* op =
2252 javascript()->DefineKeyedOwnProperty(language_mode, source);
2253
2254 JSTypeHintLowering::LoweringResult lowering =
2255 TryBuildSimplifiedStoreKeyed(op, object, key, value, source.slot);
2256 if (lowering.IsExit()) return;
2257
2258 Node* node = nullptr;
2259 if (lowering.IsSideEffectFree()) {
2260 node = lowering.value();
2261 } else {
2262 DCHECK(!lowering.Changed());
2263 static_assert(JSDefineKeyedOwnPropertyNode::ObjectIndex() == 0);
2264 static_assert(JSDefineKeyedOwnPropertyNode::KeyIndex() == 1);
2265 static_assert(JSDefineKeyedOwnPropertyNode::ValueIndex() == 2);
2266 static_assert(JSDefineKeyedOwnPropertyNode::FlagsIndex() == 3);
2267 static_assert(JSDefineKeyedOwnPropertyNode::FeedbackVectorIndex() == 4);
2268 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2269 node = NewNode(op, object, key, value, jsgraph()->ConstantNoHole(flags),
2270 feedback_vector_node());
2271 }
2272
2273 environment()->RecordAfterState(node, Environment::kAttachFrameState);
2274}
2275
2276void BytecodeGraphBuilder::VisitLdaModuleVariable() {
2277 int32_t cell_index = bytecode_iterator().GetImmediateOperand(0);
2278 uint32_t depth = bytecode_iterator().GetUnsignedImmediateOperand(1);
2279 Node* module =
2280 NewNode(javascript()->LoadContext(depth, Context::EXTENSION_INDEX, true));
2281 Node* value = NewNode(javascript()->LoadModule(cell_index), module);
2282 environment()->BindAccumulator(value);
2283}
2284
2285void BytecodeGraphBuilder::VisitStaModuleVariable() {
2286 int32_t cell_index = bytecode_iterator().GetImmediateOperand(0);
2287 uint32_t depth = bytecode_iterator().GetUnsignedImmediateOperand(1);
2288 Node* module =
2289 NewNode(javascript()->LoadContext(depth, Context::EXTENSION_INDEX, true));
2290 Node* value = environment()->LookupAccumulator();
2291 NewNode(javascript()->StoreModule(cell_index), module, value);
2292}
2293
2294void BytecodeGraphBuilder::VisitPushContext() {
2295 Node* new_context = environment()->LookupAccumulator();
2296 environment()->BindRegister(bytecode_iterator().GetRegisterOperand(0),
2297 environment()->Context());
2298 environment()->SetContext(new_context);
2299}
2300
2301void BytecodeGraphBuilder::VisitPopContext() {
2302 Node* context =
2303 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2304 environment()->SetContext(context);
2305}
2306
2307void BytecodeGraphBuilder::VisitCreateClosure() {
2308 SharedFunctionInfoRef shared_info =
2309 MakeRefForConstantForIndexOperand<SharedFunctionInfo>(0);
2310 AllocationType allocation =
2312 bytecode_iterator().GetFlag8Operand(2))
2315 CodeRef compile_lazy =
2316 MakeRef(broker(), *BUILTIN_CODE(jsgraph()->isolate(), CompileLazy));
2317 const Operator* op =
2318 javascript()->CreateClosure(shared_info, compile_lazy, allocation);
2319 Node* closure = NewNode(
2320 op, BuildLoadFeedbackCell(bytecode_iterator().GetIndexOperand(1)));
2321 environment()->BindAccumulator(closure);
2322}
2323
2324void BytecodeGraphBuilder::VisitCreateBlockContext() {
2325 ScopeInfoRef scope_info = MakeRefForConstantForIndexOperand<ScopeInfo>(0);
2326 const Operator* op = javascript()->CreateBlockContext(scope_info);
2327 Node* context = NewNode(op);
2328 environment()->BindAccumulator(context);
2329}
2330
2331void BytecodeGraphBuilder::VisitCreateFunctionContext() {
2332 ScopeInfoRef scope_info = MakeRefForConstantForIndexOperand<ScopeInfo>(0);
2333 uint32_t slots = bytecode_iterator().GetUnsignedImmediateOperand(1);
2334 const Operator* op =
2335 javascript()->CreateFunctionContext(scope_info, slots, FUNCTION_SCOPE);
2336 Node* context = NewNode(op);
2337 environment()->BindAccumulator(context);
2338}
2339
2340void BytecodeGraphBuilder::VisitCreateEvalContext() {
2341 ScopeInfoRef scope_info = MakeRefForConstantForIndexOperand<ScopeInfo>(0);
2342 uint32_t slots = bytecode_iterator().GetUnsignedImmediateOperand(1);
2343 const Operator* op =
2344 javascript()->CreateFunctionContext(scope_info, slots, EVAL_SCOPE);
2345 Node* context = NewNode(op);
2346 environment()->BindAccumulator(context);
2347}
2348
2349void BytecodeGraphBuilder::VisitCreateCatchContext() {
2350 interpreter::Register reg = bytecode_iterator().GetRegisterOperand(0);
2351 Node* exception = environment()->LookupRegister(reg);
2352 ScopeInfoRef scope_info = MakeRefForConstantForIndexOperand<ScopeInfo>(1);
2353
2354 const Operator* op = javascript()->CreateCatchContext(scope_info);
2355 Node* context = NewNode(op, exception);
2356 environment()->BindAccumulator(context);
2357}
2358
2359void BytecodeGraphBuilder::VisitCreateWithContext() {
2360 Node* object =
2361 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2362 ScopeInfoRef scope_info = MakeRefForConstantForIndexOperand<ScopeInfo>(1);
2363
2364 const Operator* op = javascript()->CreateWithContext(scope_info);
2365 Node* context = NewNode(op, object);
2366 environment()->BindAccumulator(context);
2367}
2368
2369void BytecodeGraphBuilder::BuildCreateArguments(CreateArgumentsType type) {
2370 const Operator* op = javascript()->CreateArguments(type);
2371 Node* object = NewNode(op, GetFunctionClosure());
2372 environment()->BindAccumulator(object, Environment::kAttachFrameState);
2373}
2374
2375void BytecodeGraphBuilder::VisitCreateMappedArguments() {
2376 BuildCreateArguments(CreateArgumentsType::kMappedArguments);
2377}
2378
2379void BytecodeGraphBuilder::VisitCreateUnmappedArguments() {
2380 BuildCreateArguments(CreateArgumentsType::kUnmappedArguments);
2381}
2382
2383void BytecodeGraphBuilder::VisitCreateRestParameter() {
2384 BuildCreateArguments(CreateArgumentsType::kRestParameter);
2385}
2386
2387void BytecodeGraphBuilder::VisitCreateRegExpLiteral() {
2388 StringRef constant_pattern = MakeRefForConstantForIndexOperand<String>(0);
2389 int const slot_id = bytecode_iterator().GetIndexOperand(1);
2390 FeedbackSource pair = CreateFeedbackSource(slot_id);
2391 int literal_flags = bytecode_iterator().GetFlag16Operand(2);
2392 static_assert(JSCreateLiteralRegExpNode::FeedbackVectorIndex() == 0);
2393 const Operator* op =
2394 javascript()->CreateLiteralRegExp(constant_pattern, pair, literal_flags);
2395 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2396 Node* literal = NewNode(op, feedback_vector_node());
2397 environment()->BindAccumulator(literal, Environment::kAttachFrameState);
2398}
2399
2400void BytecodeGraphBuilder::VisitCreateArrayLiteral() {
2401 ArrayBoilerplateDescriptionRef array_boilerplate_description =
2402 MakeRefForConstantForIndexOperand<ArrayBoilerplateDescription>(0);
2403 int const slot_id = bytecode_iterator().GetIndexOperand(1);
2404 FeedbackSource pair = CreateFeedbackSource(slot_id);
2405 int bytecode_flags = bytecode_iterator().GetFlag8Operand(2);
2406 int literal_flags =
2408 // Disable allocation site mementos. Only unoptimized code will collect
2409 // feedback about allocation site. Once the code is optimized we expect the
2410 // data to converge. So, we disable allocation site mementos in optimized
2411 // code. We can revisit this when we have data to the contrary.
2412 literal_flags |= ArrayLiteral::kDisableMementos;
2413 int number_of_elements =
2414 array_boilerplate_description.constants_elements_length();
2415 static_assert(JSCreateLiteralArrayNode::FeedbackVectorIndex() == 0);
2416 const Operator* op = javascript()->CreateLiteralArray(
2417 array_boilerplate_description, pair, literal_flags, number_of_elements);
2418 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2419 Node* literal = NewNode(op, feedback_vector_node());
2420 environment()->BindAccumulator(literal, Environment::kAttachFrameState);
2421}
2422
2423void BytecodeGraphBuilder::VisitCreateEmptyArrayLiteral() {
2424 int const slot_id = bytecode_iterator().GetIndexOperand(0);
2425 FeedbackSource pair = CreateFeedbackSource(slot_id);
2426 const Operator* op = javascript()->CreateEmptyLiteralArray(pair);
2427 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2428 Node* literal = NewNode(op, feedback_vector_node());
2429 environment()->BindAccumulator(literal);
2430}
2431
2432void BytecodeGraphBuilder::VisitCreateArrayFromIterable() {
2433 Node* iterable = NewNode(javascript()->CreateArrayFromIterable(),
2434 environment()->LookupAccumulator());
2435 environment()->BindAccumulator(iterable, Environment::kAttachFrameState);
2436}
2437
2438void BytecodeGraphBuilder::VisitCreateObjectLiteral() {
2439 ObjectBoilerplateDescriptionRef constant_properties =
2440 MakeRefForConstantForIndexOperand<ObjectBoilerplateDescription>(0);
2441 int const slot_id = bytecode_iterator().GetIndexOperand(1);
2442 FeedbackSource pair = CreateFeedbackSource(slot_id);
2443 int bytecode_flags = bytecode_iterator().GetFlag8Operand(2);
2444 int literal_flags =
2446 int number_of_properties = constant_properties.boilerplate_properties_count();
2447 static_assert(JSCreateLiteralObjectNode::FeedbackVectorIndex() == 0);
2448 const Operator* op = javascript()->CreateLiteralObject(
2449 constant_properties, pair, literal_flags, number_of_properties);
2450 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2451 Node* literal = NewNode(op, feedback_vector_node());
2452 environment()->BindAccumulator(literal, Environment::kAttachFrameState);
2453}
2454
2455void BytecodeGraphBuilder::VisitCreateEmptyObjectLiteral() {
2456 Node* literal = NewNode(javascript()->CreateEmptyLiteralObject());
2457 environment()->BindAccumulator(literal);
2458}
2459
2460void BytecodeGraphBuilder::VisitCloneObject() {
2461 PrepareEagerCheckpoint();
2462 Node* source =
2463 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2464 int flags = bytecode_iterator().GetFlag8Operand(1);
2465 int slot = bytecode_iterator().GetIndexOperand(2);
2466 const Operator* op =
2467 javascript()->CloneObject(CreateFeedbackSource(slot), flags);
2468 static_assert(JSCloneObjectNode::SourceIndex() == 0);
2469 static_assert(JSCloneObjectNode::FeedbackVectorIndex() == 1);
2470 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2471 Node* value = NewNode(op, source, feedback_vector_node());
2472 environment()->BindAccumulator(value, Environment::kAttachFrameState);
2473}
2474
2475void BytecodeGraphBuilder::VisitGetTemplateObject() {
2476 FeedbackSource source =
2477 CreateFeedbackSource(bytecode_iterator().GetIndexOperand(1));
2478 TemplateObjectDescriptionRef description =
2479 MakeRefForConstantForIndexOperand<TemplateObjectDescription>(0);
2480 static_assert(JSGetTemplateObjectNode::FeedbackVectorIndex() == 0);
2481 const Operator* op =
2482 javascript()->GetTemplateObject(description, shared_info(), source);
2483 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2484 Node* template_object = NewNode(op, feedback_vector_node());
2485 environment()->BindAccumulator(template_object);
2486}
2487
2488Node* const* BytecodeGraphBuilder::GetCallArgumentsFromRegisters(
2490 int arg_count) {
2491 const int arity = JSCallNode::ArityForArgc(arg_count);
2492 Node** all = local_zone()->AllocateArray<Node*>(static_cast<size_t>(arity));
2493 int cursor = 0;
2494
2495 static_assert(JSCallNode::TargetIndex() == 0);
2496 static_assert(JSCallNode::ReceiverIndex() == 1);
2497 static_assert(JSCallNode::FirstArgumentIndex() == 2);
2498 static_assert(JSCallNode::kFeedbackVectorIsLastInput);
2499
2500 all[cursor++] = callee;
2501 all[cursor++] = receiver;
2502
2503 // The function arguments are in consecutive registers.
2504 const int arg_base = first_arg.index();
2505 for (int i = 0; i < arg_count; ++i) {
2506 all[cursor++] =
2507 environment()->LookupRegister(interpreter::Register(arg_base + i));
2508 }
2509
2510 all[cursor++] = feedback_vector_node();
2511
2512 DCHECK_EQ(cursor, arity);
2513 return all;
2514}
2515
2516void BytecodeGraphBuilder::BuildCall(ConvertReceiverMode receiver_mode,
2517 Node* const* args, size_t arg_count,
2518 int slot_id) {
2520 bytecode_iterator().current_bytecode()),
2521 receiver_mode);
2522 PrepareEagerCheckpoint();
2523
2524 FeedbackSource feedback = CreateFeedbackSource(slot_id);
2525 CallFrequency frequency = ComputeCallFrequency(slot_id);
2526 SpeculationMode speculation_mode = GetSpeculationMode(slot_id);
2527 CallFeedbackRelation call_feedback_relation =
2528 ComputeCallFeedbackRelation(slot_id);
2529 const Operator* op =
2530 javascript()->Call(arg_count, frequency, feedback, receiver_mode,
2531 speculation_mode, call_feedback_relation);
2532 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2533
2534 JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedCall(
2535 op, args, static_cast<int>(arg_count), feedback.slot);
2536 if (lowering.IsExit()) return;
2537
2538 Node* node = nullptr;
2539 if (lowering.IsSideEffectFree()) {
2540 node = lowering.value();
2541 } else {
2542 DCHECK(!lowering.Changed());
2543 node = MakeNode(op, static_cast<int>(arg_count), args);
2544 }
2545 environment()->BindAccumulator(node, Environment::kAttachFrameState);
2546}
2547
2548Node* const* BytecodeGraphBuilder::ProcessCallVarArgs(
2549 ConvertReceiverMode receiver_mode, Node* callee,
2550 interpreter::Register first_reg, int arg_count) {
2551 DCHECK_GE(arg_count, 0);
2552 Node* receiver_node;
2554
2555 if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
2556 // The receiver is implicit (and undefined), the arguments are in
2557 // consecutive registers.
2558 receiver_node = jsgraph()->UndefinedConstant();
2559 first_arg = first_reg;
2560 } else {
2561 // The receiver is the first register, followed by the arguments in the
2562 // consecutive registers.
2563 receiver_node = environment()->LookupRegister(first_reg);
2564 first_arg = interpreter::Register(first_reg.index() + 1);
2565 }
2566
2567 Node* const* call_args = GetCallArgumentsFromRegisters(callee, receiver_node,
2568 first_arg, arg_count);
2569 return call_args;
2570}
2571
2572void BytecodeGraphBuilder::BuildCallVarArgs(ConvertReceiverMode receiver_mode) {
2574 bytecode_iterator().current_bytecode()),
2575 receiver_mode);
2576 Node* callee =
2577 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2578 interpreter::Register first_reg = bytecode_iterator().GetRegisterOperand(1);
2579 size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
2580 int const slot_id = bytecode_iterator().GetIndexOperand(3);
2581
2582 int arg_count = receiver_mode == ConvertReceiverMode::kNullOrUndefined
2583 ? static_cast<int>(reg_count)
2584 : static_cast<int>(reg_count) - 1;
2585 Node* const* call_args =
2586 ProcessCallVarArgs(receiver_mode, callee, first_reg, arg_count);
2587 BuildCall(receiver_mode, call_args, JSCallNode::ArityForArgc(arg_count),
2588 slot_id);
2589}
2590
2591void BytecodeGraphBuilder::VisitCallAnyReceiver() {
2592 BuildCallVarArgs(ConvertReceiverMode::kAny);
2593}
2594
2595void BytecodeGraphBuilder::VisitCallProperty() {
2597}
2598
2599void BytecodeGraphBuilder::VisitCallProperty0() {
2600 Node* callee =
2601 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2602 Node* receiver =
2603 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
2604 int const slot_id = bytecode_iterator().GetIndexOperand(2);
2606 {callee, receiver, feedback_vector_node()}, slot_id);
2607}
2608
2609void BytecodeGraphBuilder::VisitCallProperty1() {
2610 Node* callee =
2611 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2612 Node* receiver =
2613 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
2614 Node* arg0 =
2615 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(2));
2616 int const slot_id = bytecode_iterator().GetIndexOperand(3);
2618 {callee, receiver, arg0, feedback_vector_node()}, slot_id);
2619}
2620
2621void BytecodeGraphBuilder::VisitCallProperty2() {
2622 Node* callee =
2623 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2624 Node* receiver =
2625 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
2626 Node* arg0 =
2627 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(2));
2628 Node* arg1 =
2629 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(3));
2630 int const slot_id = bytecode_iterator().GetIndexOperand(4);
2632 {callee, receiver, arg0, arg1, feedback_vector_node()}, slot_id);
2633}
2634
2635void BytecodeGraphBuilder::VisitCallUndefinedReceiver() {
2636 BuildCallVarArgs(ConvertReceiverMode::kNullOrUndefined);
2637}
2638
2639void BytecodeGraphBuilder::VisitCallUndefinedReceiver0() {
2640 Node* callee =
2641 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2642 Node* receiver = jsgraph()->UndefinedConstant();
2643 int const slot_id = bytecode_iterator().GetIndexOperand(1);
2645 {callee, receiver, feedback_vector_node()}, slot_id);
2646}
2647
2648void BytecodeGraphBuilder::VisitCallUndefinedReceiver1() {
2649 Node* callee =
2650 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2651 Node* receiver = jsgraph()->UndefinedConstant();
2652 Node* arg0 =
2653 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
2654 int const slot_id = bytecode_iterator().GetIndexOperand(2);
2656 {callee, receiver, arg0, feedback_vector_node()}, slot_id);
2657}
2658
2659void BytecodeGraphBuilder::VisitCallUndefinedReceiver2() {
2660 Node* callee =
2661 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2662 Node* receiver = jsgraph()->UndefinedConstant();
2663 Node* arg0 =
2664 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
2665 Node* arg1 =
2666 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(2));
2667 int const slot_id = bytecode_iterator().GetIndexOperand(3);
2669 {callee, receiver, arg0, arg1, feedback_vector_node()}, slot_id);
2670}
2671
2672void BytecodeGraphBuilder::VisitCallWithSpread() {
2673 PrepareEagerCheckpoint();
2674 Node* callee =
2675 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
2676 interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
2677 Node* receiver_node = environment()->LookupRegister(receiver);
2678 size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
2679 interpreter::Register first_arg = interpreter::Register(receiver.index() + 1);
2680 int arg_count = static_cast<int>(reg_count) - 1;
2681 Node* const* args = GetCallArgumentsFromRegisters(callee, receiver_node,
2682 first_arg, arg_count);
2683 int const slot_id = bytecode_iterator().GetIndexOperand(3);
2684 FeedbackSource feedback = CreateFeedbackSource(slot_id);
2685 CallFrequency frequency = ComputeCallFrequency(slot_id);
2686 SpeculationMode speculation_mode = GetSpeculationMode(slot_id);
2687 const Operator* op = javascript()->CallWithSpread(
2688 JSCallWithSpreadNode::ArityForArgc(arg_count), frequency, feedback,
2689 speculation_mode);
2690 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2691
2692 JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedCall(
2693 op, args, static_cast<int>(arg_count), feedback.slot);
2694 if (lowering.IsExit()) return;
2695
2696 Node* node = nullptr;
2697 if (lowering.IsSideEffectFree()) {
2698 node = lowering.value();
2699 } else {
2700 DCHECK(!lowering.Changed());
2701 node = MakeNode(op, JSCallWithSpreadNode::ArityForArgc(arg_count), args);
2702 }
2703 environment()->BindAccumulator(node, Environment::kAttachFrameState);
2704}
2705
2706void BytecodeGraphBuilder::VisitCallJSRuntime() {
2707 PrepareEagerCheckpoint();
2708 Node* callee = BuildLoadNativeContextField(
2709 bytecode_iterator().GetNativeContextIndexOperand(0));
2710 interpreter::Register first_reg = bytecode_iterator().GetRegisterOperand(1);
2711 size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
2712 int arg_count = static_cast<int>(reg_count);
2713 int arity = JSCallNode::ArityForArgc(arg_count);
2714
2715 const Operator* call = javascript()->Call(arity);
2716 Node* const* call_args = ProcessCallVarArgs(
2717 ConvertReceiverMode::kNullOrUndefined, callee, first_reg, arg_count);
2718 Node* value = MakeNode(call, arity, call_args);
2719 environment()->BindAccumulator(value, Environment::kAttachFrameState);
2720}
2721
2722Node* BytecodeGraphBuilder::ProcessCallRuntimeArguments(
2723 const Operator* call_runtime_op, interpreter::Register receiver,
2724 size_t reg_count) {
2725 int arg_count = static_cast<int>(reg_count);
2726 // arity is args.
2727 int arity = arg_count;
2728 Node** all = local_zone()->AllocateArray<Node*>(static_cast<size_t>(arity));
2729 int first_arg_index = receiver.index();
2730 for (int i = 0; i < static_cast<int>(reg_count); ++i) {
2731 all[i] = environment()->LookupRegister(
2732 interpreter::Register(first_arg_index + i));
2733 }
2734 Node* value = MakeNode(call_runtime_op, arity, all);
2735 return value;
2736}
2737
2738void BytecodeGraphBuilder::VisitCallRuntime() {
2739 PrepareEagerCheckpoint();
2740 Runtime::FunctionId function_id = bytecode_iterator().GetRuntimeIdOperand(0);
2741 interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
2742 size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
2743
2744 // Handle %ObserveNode here (rather than in JSIntrinsicLowering) to observe
2745 // the node as early as possible.
2746 if (function_id == Runtime::FunctionId::kObserveNode) {
2747 DCHECK_EQ(1, reg_count);
2748 Node* value = environment()->LookupRegister(receiver);
2749 observe_node_info_.StartObserving(value);
2750 environment()->BindAccumulator(value);
2751 } else {
2752 // Create node to perform the runtime call.
2753 const Operator* call = javascript()->CallRuntime(function_id, reg_count);
2754 Node* value = ProcessCallRuntimeArguments(call, receiver, reg_count);
2755 environment()->BindAccumulator(value, Environment::kAttachFrameState);
2756
2757 // Connect to the end if {function_id} is non-returning.
2758 if (Runtime::IsNonReturning(function_id)) {
2759 // TODO(7099): Investigate if we need LoopExit node here.
2760 Node* control = NewNode(common()->Throw());
2761 MergeControlToLeaveFunction(control);
2762 }
2763 }
2764}
2765
2766void BytecodeGraphBuilder::VisitCallRuntimeForPair() {
2767 PrepareEagerCheckpoint();
2768 Runtime::FunctionId functionId = bytecode_iterator().GetRuntimeIdOperand(0);
2769 interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
2770 size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
2771 interpreter::Register first_return =
2772 bytecode_iterator().GetRegisterOperand(3);
2773
2774 // Create node to perform the runtime call.
2775 const Operator* call = javascript()->CallRuntime(functionId, reg_count);
2776 Node* return_pair = ProcessCallRuntimeArguments(call, receiver, reg_count);
2777 environment()->BindRegistersToProjections(first_return, return_pair,
2778 Environment::kAttachFrameState);
2779}
2780
2781Node* const* BytecodeGraphBuilder::GetConstructArgumentsFromRegister(
2783 int arg_count) {
2784 const int arity = JSConstructNode::ArityForArgc(arg_count);
2785 Node** all = local_zone()->AllocateArray<Node*>(static_cast<size_t>(arity));
2786 int cursor = 0;
2787
2788 static_assert(JSConstructNode::TargetIndex() == 0);
2789 static_assert(JSConstructNode::NewTargetIndex() == 1);
2790 static_assert(JSConstructNode::FirstArgumentIndex() == 2);
2791 static_assert(JSConstructNode::kFeedbackVectorIsLastInput);
2792
2793 all[cursor++] = target;
2794 all[cursor++] = new_target;
2795
2796 // The function arguments are in consecutive registers.
2797 int arg_base = first_arg.index();
2798 for (int i = 0; i < arg_count; ++i) {
2799 all[cursor++] =
2800 environment()->LookupRegister(interpreter::Register(arg_base + i));
2801 }
2802
2803 all[cursor++] = feedback_vector_node();
2804
2805 DCHECK_EQ(cursor, arity);
2806 return all;
2807}
2808
2809void BytecodeGraphBuilder::VisitConstruct() {
2810 PrepareEagerCheckpoint();
2811 interpreter::Register callee_reg = bytecode_iterator().GetRegisterOperand(0);
2812 interpreter::Register first_reg = bytecode_iterator().GetRegisterOperand(1);
2813 size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
2814 int const slot_id = bytecode_iterator().GetIndexOperand(3);
2815 FeedbackSource feedback = CreateFeedbackSource(slot_id);
2816
2817 Node* new_target = environment()->LookupAccumulator();
2818 Node* callee = environment()->LookupRegister(callee_reg);
2819
2820 CallFrequency frequency = ComputeCallFrequency(slot_id);
2821 const uint32_t arg_count = static_cast<uint32_t>(reg_count);
2822 const uint32_t arity = JSConstructNode::ArityForArgc(arg_count);
2823 const Operator* op = javascript()->Construct(arity, frequency, feedback);
2824 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2825 Node* const* args = GetConstructArgumentsFromRegister(callee, new_target,
2826 first_reg, arg_count);
2827 JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedConstruct(
2828 op, args, static_cast<int>(arg_count), feedback.slot);
2829 if (lowering.IsExit()) return;
2830
2831 Node* node = nullptr;
2832 if (lowering.IsSideEffectFree()) {
2833 node = lowering.value();
2834 } else {
2835 DCHECK(!lowering.Changed());
2836 node = MakeNode(op, arity, args);
2837 }
2838 environment()->BindAccumulator(node, Environment::kAttachFrameState);
2839}
2840
2841void BytecodeGraphBuilder::VisitConstructWithSpread() {
2842 PrepareEagerCheckpoint();
2843 interpreter::Register callee_reg = bytecode_iterator().GetRegisterOperand(0);
2844 interpreter::Register first_reg = bytecode_iterator().GetRegisterOperand(1);
2845 size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
2846 int const slot_id = bytecode_iterator().GetIndexOperand(3);
2847 FeedbackSource feedback = CreateFeedbackSource(slot_id);
2848
2849 Node* new_target = environment()->LookupAccumulator();
2850 Node* callee = environment()->LookupRegister(callee_reg);
2851
2852 CallFrequency frequency = ComputeCallFrequency(slot_id);
2853 const uint32_t arg_count = static_cast<uint32_t>(reg_count);
2854 const uint32_t arity = JSConstructNode::ArityForArgc(arg_count);
2855 const Operator* op =
2856 javascript()->ConstructWithSpread(arity, frequency, feedback);
2857 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
2858 Node* const* args = GetConstructArgumentsFromRegister(callee, new_target,
2859 first_reg, arg_count);
2860 JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedConstruct(
2861 op, args, static_cast<int>(arg_count), feedback.slot);
2862 if (lowering.IsExit()) return;
2863
2864 Node* node = nullptr;
2865 if (lowering.IsSideEffectFree()) {
2866 node = lowering.value();
2867 } else {
2868 DCHECK(!lowering.Changed());
2869 node = MakeNode(op, arity, args);
2870 }
2871 environment()->BindAccumulator(node, Environment::kAttachFrameState);
2872}
2873
2874void BytecodeGraphBuilder::VisitConstructForwardAllArgs() {
2875 PrepareEagerCheckpoint();
2876 interpreter::Register callee_reg = bytecode_iterator().GetRegisterOperand(0);
2877 int const slot_id = bytecode_iterator().GetIndexOperand(1);
2878 FeedbackSource feedback = CreateFeedbackSource(slot_id);
2879 Node* new_target = environment()->LookupAccumulator();
2880 Node* callee = environment()->LookupRegister(callee_reg);
2881 CallFrequency frequency = ComputeCallFrequency(slot_id);
2882
2883 // Use 0 as a fake argument count.
2884 //
2885 // This op will be later reduced to either a builtin call (in the case of not
2886 // being inlined) or a normal JSConstruct with the inlined arguments
2887 // forwarded.
2888 constexpr int arg_count = 0;
2889 const int arity = JSConstructForwardAllArgsNode::ArityForArgc(arg_count);
2890 Node** construct_args =
2891 local_zone()->AllocateArray<Node*>(static_cast<size_t>(arity));
2892 static_assert(JSConstructForwardAllArgsNode::TargetIndex() == 0);
2893 static_assert(JSConstructForwardAllArgsNode::NewTargetIndex() == 1);
2894 static_assert(JSConstructNode::kFeedbackVectorIsLastInput);
2895 DCHECK_LT(JSConstructForwardAllArgsNode::NewTargetIndex(), arity);
2896 int cursor = 0;
2897 construct_args[cursor++] = callee;
2898 construct_args[cursor++] = new_target;
2899 construct_args[cursor++] = feedback_vector_node();
2900
2901 const Operator* op =
2902 javascript()->ConstructForwardAllArgs(frequency, feedback);
2903 JSTypeHintLowering::LoweringResult lowering =
2904 TryBuildSimplifiedConstruct(op, construct_args, arg_count, feedback.slot);
2905 if (lowering.IsExit()) return;
2906
2907 Node* node;
2908 if (lowering.IsSideEffectFree()) {
2909 node = lowering.value();
2910 } else {
2911 DCHECK(!lowering.Changed());
2912 node = MakeNode(op, arity, construct_args);
2913 }
2914
2915 environment()->BindAccumulator(node, Environment::kAttachFrameState);
2916}
2917
2918void BytecodeGraphBuilder::VisitInvokeIntrinsic() {
2919 PrepareEagerCheckpoint();
2920 Runtime::FunctionId functionId = bytecode_iterator().GetIntrinsicIdOperand(0);
2921 interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
2922 size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
2923
2924 // Create node to perform the runtime call. Turbofan will take care of the
2925 // lowering.
2926 const Operator* call = javascript()->CallRuntime(functionId, reg_count);
2927 Node* value = ProcessCallRuntimeArguments(call, receiver, reg_count);
2928 environment()->BindAccumulator(value, Environment::kAttachFrameState);
2929}
2930
2931void BytecodeGraphBuilder::VisitThrow() {
2932 BuildLoopExitsForFunctionExit(bytecode_analysis().GetInLivenessFor(
2933 bytecode_iterator().current_offset()));
2934 Node* value = environment()->LookupAccumulator();
2935 Node* call = NewNode(javascript()->CallRuntime(Runtime::kThrow), value);
2936 environment()->BindAccumulator(call, Environment::kAttachFrameState);
2937 Node* control = NewNode(common()->Throw());
2938 MergeControlToLeaveFunction(control);
2939}
2940
2941void BytecodeGraphBuilder::VisitAbort() {
2942 BuildLoopExitsForFunctionExit(bytecode_analysis().GetInLivenessFor(
2943 bytecode_iterator().current_offset()));
2944 AbortReason reason =
2945 static_cast<AbortReason>(bytecode_iterator().GetIndexOperand(0));
2946 NewNode(simplified()->RuntimeAbort(reason));
2947 Node* control = NewNode(common()->Throw());
2948 MergeControlToLeaveFunction(control);
2949}
2950
2951void BytecodeGraphBuilder::VisitReThrow() {
2952 BuildLoopExitsForFunctionExit(bytecode_analysis().GetInLivenessFor(
2953 bytecode_iterator().current_offset()));
2954 Node* value = environment()->LookupAccumulator();
2955 Node* rethrow = NewNode(javascript()->CallRuntime(Runtime::kReThrow), value);
2956 environment()->RecordAfterState(rethrow, Environment::kAttachFrameState);
2957 Node* control = NewNode(common()->Throw());
2958 MergeControlToLeaveFunction(control);
2959}
2960
2961void BytecodeGraphBuilder::BuildHoleCheckAndThrow(
2962 Node* condition, Runtime::FunctionId runtime_id, Node* name) {
2963 Node* accumulator = environment()->LookupAccumulator();
2964 NewBranch(condition, BranchHint::kFalse);
2965 {
2966 SubEnvironment sub_environment(this);
2967
2968 NewIfTrue();
2969 BuildLoopExitsForFunctionExit(bytecode_analysis().GetInLivenessFor(
2970 bytecode_iterator().current_offset()));
2971 Node* node;
2972 const Operator* op = javascript()->CallRuntime(runtime_id);
2973 if (runtime_id == Runtime::kThrowAccessedUninitializedVariable) {
2974 DCHECK_NOT_NULL(name);
2975 node = NewNode(op, name);
2976 } else {
2977 DCHECK(runtime_id == Runtime::kThrowSuperAlreadyCalledError ||
2978 runtime_id == Runtime::kThrowSuperNotCalled);
2979 node = NewNode(op);
2980 }
2981 environment()->RecordAfterState(node, Environment::kAttachFrameState);
2982 Node* control = NewNode(common()->Throw());
2983 MergeControlToLeaveFunction(control);
2984 }
2985 NewIfFalse();
2986 environment()->BindAccumulator(accumulator);
2987}
2988
2989void BytecodeGraphBuilder::VisitThrowReferenceErrorIfHole() {
2990 Node* accumulator = environment()->LookupAccumulator();
2991 Node* check_for_hole = NewNode(simplified()->ReferenceEqual(), accumulator,
2992 jsgraph()->TheHoleConstant());
2993 Node* name =
2994 jsgraph()->ConstantNoHole(MakeRefForConstantForIndexOperand(0), broker());
2995 BuildHoleCheckAndThrow(check_for_hole,
2996 Runtime::kThrowAccessedUninitializedVariable, name);
2997}
2998
2999void BytecodeGraphBuilder::VisitThrowSuperNotCalledIfHole() {
3000 Node* accumulator = environment()->LookupAccumulator();
3001 Node* check_for_hole = NewNode(simplified()->ReferenceEqual(), accumulator,
3002 jsgraph()->TheHoleConstant());
3003 BuildHoleCheckAndThrow(check_for_hole, Runtime::kThrowSuperNotCalled);
3004}
3005
3006void BytecodeGraphBuilder::VisitThrowSuperAlreadyCalledIfNotHole() {
3007 Node* accumulator = environment()->LookupAccumulator();
3008 Node* check_for_hole = NewNode(simplified()->ReferenceEqual(), accumulator,
3009 jsgraph()->TheHoleConstant());
3010 Node* check_for_not_hole =
3011 NewNode(simplified()->BooleanNot(), check_for_hole);
3012 BuildHoleCheckAndThrow(check_for_not_hole,
3013 Runtime::kThrowSuperAlreadyCalledError);
3014}
3015
3016void BytecodeGraphBuilder::VisitThrowIfNotSuperConstructor() {
3017 Node* constructor =
3018 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
3019 Node* check_is_constructor =
3020 NewNode(simplified()->ObjectIsConstructor(), constructor);
3021 NewBranch(check_is_constructor, BranchHint::kTrue);
3022 {
3023 SubEnvironment sub_environment(this);
3024 NewIfFalse();
3025 BuildLoopExitsForFunctionExit(bytecode_analysis().GetInLivenessFor(
3026 bytecode_iterator().current_offset()));
3027 Node* node =
3028 NewNode(javascript()->CallRuntime(Runtime::kThrowNotSuperConstructor),
3029 constructor, GetFunctionClosure());
3030 environment()->RecordAfterState(node, Environment::kAttachFrameState);
3031 Node* control = NewNode(common()->Throw());
3032 MergeControlToLeaveFunction(control);
3033 }
3034 NewIfTrue();
3035
3036 constructor = NewNode(common()->TypeGuard(Type::Callable()), constructor);
3037 environment()->BindRegister(bytecode_iterator().GetRegisterOperand(0),
3038 constructor);
3039}
3040
3041void BytecodeGraphBuilder::BuildUnaryOp(const Operator* op) {
3042 DCHECK(JSOperator::IsUnaryWithFeedback(op->opcode()));
3043 PrepareEagerCheckpoint();
3044 Node* operand = environment()->LookupAccumulator();
3045
3046 FeedbackSlot slot =
3047 bytecode_iterator().GetSlotOperand(kUnaryOperationHintIndex);
3049 TryBuildSimplifiedUnaryOp(op, operand, slot);
3050 if (lowering.IsExit()) return;
3051
3052 Node* node = nullptr;
3053 if (lowering.IsSideEffectFree()) {
3054 node = lowering.value();
3055 } else {
3056 DCHECK(!lowering.Changed());
3057 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
3058 node = NewNode(op, operand, feedback_vector_node());
3059 }
3060
3061 environment()->BindAccumulator(node, Environment::kAttachFrameState);
3062}
3063
3064void BytecodeGraphBuilder::BuildBinaryOp(const Operator* op) {
3065 DCHECK(JSOperator::IsBinaryWithFeedback(op->opcode()));
3066 PrepareEagerCheckpoint();
3067 Node* left =
3068 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
3069 Node* right = environment()->LookupAccumulator();
3070
3071 FeedbackSlot slot =
3072 bytecode_iterator().GetSlotOperand(kBinaryOperationHintIndex);
3074 TryBuildSimplifiedBinaryOp(op, left, right, slot);
3075 if (lowering.IsExit()) return;
3076
3077 Node* node = nullptr;
3078 if (lowering.IsSideEffectFree()) {
3079 node = lowering.value();
3080 } else {
3081 DCHECK(!lowering.Changed());
3082 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
3083 node = NewNode(op, left, right, feedback_vector_node());
3084 }
3085
3086 environment()->BindAccumulator(node, Environment::kAttachFrameState);
3087}
3088
3089// Helper function to create for-in mode from the recorded type feedback.
3090ForInMode BytecodeGraphBuilder::GetForInMode(FeedbackSlot slot) {
3091 FeedbackSource source(feedback_vector(), slot);
3092 switch (broker()->GetFeedbackForForIn(source)) {
3093 case ForInHint::kNone:
3095 return ForInMode::kUseEnumCacheKeysAndIndices;
3097 return ForInMode::kUseEnumCacheKeys;
3098 case ForInHint::kAny:
3099 return ForInMode::kGeneric;
3100 }
3101 UNREACHABLE();
3102}
3103
3104CallFrequency BytecodeGraphBuilder::ComputeCallFrequency(int slot_id) const {
3105 if (invocation_frequency_.IsUnknown()) return CallFrequency();
3106 FeedbackSlot slot = FeedbackVector::ToSlot(slot_id);
3107 FeedbackSource source(feedback_vector(), slot);
3108 ProcessedFeedback const& feedback = broker()->GetFeedbackForCall(source);
3109 float feedback_frequency =
3110 feedback.IsInsufficient() ? 0.0f : feedback.AsCall().frequency();
3111 if (feedback_frequency == 0.0f) { // Prevent multiplying zero and infinity.
3112 return CallFrequency(0.0f);
3113 } else {
3114 return CallFrequency(feedback_frequency * invocation_frequency_.value());
3115 }
3116}
3117
3118SpeculationMode BytecodeGraphBuilder::GetSpeculationMode(int slot_id) const {
3119 FeedbackSlot slot = FeedbackVector::ToSlot(slot_id);
3120 FeedbackSource source(feedback_vector(), slot);
3121 ProcessedFeedback const& feedback = broker()->GetFeedbackForCall(source);
3123 : feedback.AsCall().speculation_mode();
3124}
3125
3126CallFeedbackRelation BytecodeGraphBuilder::ComputeCallFeedbackRelation(
3127 int slot_id) const {
3128 FeedbackSlot slot = FeedbackVector::ToSlot(slot_id);
3129 FeedbackSource source(feedback_vector(), slot);
3130 ProcessedFeedback const& feedback = broker()->GetFeedbackForCall(source);
3131 if (feedback.IsInsufficient()) return CallFeedbackRelation::kUnrelated;
3132 CallFeedbackContent call_feedback_content =
3133 feedback.AsCall().call_feedback_content();
3134 return call_feedback_content == CallFeedbackContent::kTarget
3135 ? CallFeedbackRelation::kTarget
3136 : CallFeedbackRelation::kReceiver;
3137}
3138
3139void BytecodeGraphBuilder::VisitBitwiseNot() {
3140 FeedbackSource feedback = CreateFeedbackSource(
3141 bytecode_iterator().GetSlotOperand(kUnaryOperationHintIndex));
3142 BuildUnaryOp(javascript()->BitwiseNot(feedback));
3143}
3144
3145void BytecodeGraphBuilder::VisitDec() {
3146 FeedbackSource feedback = CreateFeedbackSource(
3147 bytecode_iterator().GetSlotOperand(kUnaryOperationHintIndex));
3148 BuildUnaryOp(javascript()->Decrement(feedback));
3149}
3150
3151void BytecodeGraphBuilder::VisitInc() {
3152 FeedbackSource feedback = CreateFeedbackSource(
3153 bytecode_iterator().GetSlotOperand(kUnaryOperationHintIndex));
3154 BuildUnaryOp(javascript()->Increment(feedback));
3155}
3156
3157void BytecodeGraphBuilder::VisitNegate() {
3158 FeedbackSource feedback = CreateFeedbackSource(
3159 bytecode_iterator().GetSlotOperand(kUnaryOperationHintIndex));
3160 BuildUnaryOp(javascript()->Negate(feedback));
3161}
3162
3163void BytecodeGraphBuilder::VisitAdd() {
3164 FeedbackSource feedback = CreateFeedbackSource(
3165 bytecode_iterator().GetSlotOperand(kBinaryOperationHintIndex));
3166 BuildBinaryOp(javascript()->Add(feedback));
3167}
3168
3169void BytecodeGraphBuilder::VisitSub() {
3170 FeedbackSource feedback = CreateFeedbackSource(
3171 bytecode_iterator().GetSlotOperand(kBinaryOperationHintIndex));
3172 BuildBinaryOp(javascript()->Subtract(feedback));
3173}
3174
3175void BytecodeGraphBuilder::VisitMul() {
3176 FeedbackSource feedback = CreateFeedbackSource(
3177 bytecode_iterator().GetSlotOperand(kBinaryOperationHintIndex));
3178 BuildBinaryOp(javascript()->Multiply(feedback));
3179}
3180
3181void BytecodeGraphBuilder::VisitDiv() {
3182 FeedbackSource feedback = CreateFeedbackSource(
3183 bytecode_iterator().GetSlotOperand(kBinaryOperationHintIndex));
3184 BuildBinaryOp(javascript()->Divide(feedback));
3185}
3186
3187void BytecodeGraphBuilder::VisitMod() {
3188 FeedbackSource feedback = CreateFeedbackSource(
3189 bytecode_iterator().GetSlotOperand(kBinaryOperationHintIndex));
3190 BuildBinaryOp(javascript()->Modulus(feedback));
3191}
3192
3193void BytecodeGraphBuilder::VisitExp() {
3194 FeedbackSource feedback = CreateFeedbackSource(
3195 bytecode_iterator().GetSlotOperand(kBinaryOperationHintIndex));
3196 BuildBinaryOp(javascript()->Exponentiate(feedback));
3197}
3198
3199void BytecodeGraphBuilder::VisitBitwiseOr() {
3200 FeedbackSource feedback = CreateFeedbackSource(
3201 bytecode_iterator().GetSlotOperand(kBinaryOperationHintIndex));
3202 BuildBinaryOp(javascript()->BitwiseOr(feedback));
3203}
3204
3205void BytecodeGraphBuilder::VisitBitwiseXor() {
3206 FeedbackSource feedback = CreateFeedbackSource(
3207 bytecode_iterator().GetSlotOperand(kBinaryOperationHintIndex));
3208 BuildBinaryOp(javascript()->BitwiseXor(feedback));
3209}
3210
3211void BytecodeGraphBuilder::VisitBitwiseAnd() {
3212 FeedbackSource feedback = CreateFeedbackSource(
3213 bytecode_iterator().GetSlotOperand(kBinaryOperationHintIndex));
3214 BuildBinaryOp(javascript()->BitwiseAnd(feedback));
3215}
3216
3217void BytecodeGraphBuilder::VisitShiftLeft() {
3218 FeedbackSource feedback = CreateFeedbackSource(
3219 bytecode_iterator().GetSlotOperand(kBinaryOperationHintIndex));
3220 BuildBinaryOp(javascript()->ShiftLeft(feedback));
3221}
3222
3223void BytecodeGraphBuilder::VisitShiftRight() {
3224 FeedbackSource feedback = CreateFeedbackSource(
3225 bytecode_iterator().GetSlotOperand(kBinaryOperationHintIndex));
3226 BuildBinaryOp(javascript()->ShiftRight(feedback));
3227}
3228
3229void BytecodeGraphBuilder::VisitShiftRightLogical() {
3230 FeedbackSource feedback = CreateFeedbackSource(
3231 bytecode_iterator().GetSlotOperand(kBinaryOperationHintIndex));
3232 BuildBinaryOp(javascript()->ShiftRightLogical(feedback));
3233}
3234
3235void BytecodeGraphBuilder::BuildBinaryOpWithImmediate(const Operator* op) {
3236 DCHECK(JSOperator::IsBinaryWithFeedback(op->opcode()));
3237 PrepareEagerCheckpoint();
3238 Node* left = environment()->LookupAccumulator();
3239 Node* right =
3240 jsgraph()->ConstantNoHole(bytecode_iterator().GetImmediateOperand(0));
3241
3242 FeedbackSlot slot =
3243 bytecode_iterator().GetSlotOperand(kBinaryOperationSmiHintIndex);
3245 TryBuildSimplifiedBinaryOp(op, left, right, slot);
3246 if (lowering.IsExit()) return;
3247
3248 Node* node = nullptr;
3249 if (lowering.IsSideEffectFree()) {
3250 node = lowering.value();
3251 } else {
3252 DCHECK(!lowering.Changed());
3253 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
3254 node = NewNode(op, left, right, feedback_vector_node());
3255 }
3256 environment()->BindAccumulator(node, Environment::kAttachFrameState);
3257}
3258
3259void BytecodeGraphBuilder::VisitAddSmi() {
3260 FeedbackSource feedback = CreateFeedbackSource(
3261 bytecode_iterator().GetSlotOperand(kBinaryOperationSmiHintIndex));
3262 BuildBinaryOpWithImmediate(javascript()->Add(feedback));
3263}
3264
3265void BytecodeGraphBuilder::VisitSubSmi() {
3266 FeedbackSource feedback = CreateFeedbackSource(
3267 bytecode_iterator().GetSlotOperand(kBinaryOperationSmiHintIndex));
3268 BuildBinaryOpWithImmediate(javascript()->Subtract(feedback));
3269}
3270
3271void BytecodeGraphBuilder::VisitMulSmi() {
3272 FeedbackSource feedback = CreateFeedbackSource(
3273 bytecode_iterator().GetSlotOperand(kBinaryOperationSmiHintIndex));
3274 BuildBinaryOpWithImmediate(javascript()->Multiply(feedback));
3275}
3276
3277void BytecodeGraphBuilder::VisitDivSmi() {
3278 FeedbackSource feedback = CreateFeedbackSource(
3279 bytecode_iterator().GetSlotOperand(kBinaryOperationSmiHintIndex));
3280 BuildBinaryOpWithImmediate(javascript()->Divide(feedback));
3281}
3282
3283void BytecodeGraphBuilder::VisitModSmi() {
3284 FeedbackSource feedback = CreateFeedbackSource(
3285 bytecode_iterator().GetSlotOperand(kBinaryOperationSmiHintIndex));
3286 BuildBinaryOpWithImmediate(javascript()->Modulus(feedback));
3287}
3288
3289void BytecodeGraphBuilder::VisitExpSmi() {
3290 FeedbackSource feedback = CreateFeedbackSource(
3291 bytecode_iterator().GetSlotOperand(kBinaryOperationSmiHintIndex));
3292 BuildBinaryOpWithImmediate(javascript()->Exponentiate(feedback));
3293}
3294
3295void BytecodeGraphBuilder::VisitBitwiseOrSmi() {
3296 FeedbackSource feedback = CreateFeedbackSource(
3297 bytecode_iterator().GetSlotOperand(kBinaryOperationSmiHintIndex));
3298 BuildBinaryOpWithImmediate(javascript()->BitwiseOr(feedback));
3299}
3300
3301void BytecodeGraphBuilder::VisitBitwiseXorSmi() {
3302 FeedbackSource feedback = CreateFeedbackSource(
3303 bytecode_iterator().GetSlotOperand(kBinaryOperationSmiHintIndex));
3304 BuildBinaryOpWithImmediate(javascript()->BitwiseXor(feedback));
3305}
3306
3307void BytecodeGraphBuilder::VisitBitwiseAndSmi() {
3308 FeedbackSource feedback = CreateFeedbackSource(
3309 bytecode_iterator().GetSlotOperand(kBinaryOperationSmiHintIndex));
3310 BuildBinaryOpWithImmediate(javascript()->BitwiseAnd(feedback));
3311}
3312
3313void BytecodeGraphBuilder::VisitShiftLeftSmi() {
3314 FeedbackSource feedback = CreateFeedbackSource(
3315 bytecode_iterator().GetSlotOperand(kBinaryOperationSmiHintIndex));
3316 BuildBinaryOpWithImmediate(javascript()->ShiftLeft(feedback));
3317}
3318
3319void BytecodeGraphBuilder::VisitShiftRightSmi() {
3320 FeedbackSource feedback = CreateFeedbackSource(
3321 bytecode_iterator().GetSlotOperand(kBinaryOperationSmiHintIndex));
3322 BuildBinaryOpWithImmediate(javascript()->ShiftRight(feedback));
3323}
3324
3325void BytecodeGraphBuilder::VisitShiftRightLogicalSmi() {
3326 FeedbackSource feedback = CreateFeedbackSource(
3327 bytecode_iterator().GetSlotOperand(kBinaryOperationSmiHintIndex));
3328 BuildBinaryOpWithImmediate(javascript()->ShiftRightLogical(feedback));
3329}
3330
3331void BytecodeGraphBuilder::VisitLogicalNot() {
3332 Node* value = environment()->LookupAccumulator();
3333 Node* node = NewNode(simplified()->BooleanNot(), value);
3334 environment()->BindAccumulator(node);
3335}
3336
3337void BytecodeGraphBuilder::VisitToBooleanLogicalNot() {
3338 Node* value =
3339 NewNode(simplified()->ToBoolean(), environment()->LookupAccumulator());
3340 Node* node = NewNode(simplified()->BooleanNot(), value);
3341 environment()->BindAccumulator(node);
3342}
3343
3344void BytecodeGraphBuilder::VisitTypeOf() {
3345 PrepareEagerCheckpoint();
3346 Node* operand = environment()->LookupAccumulator();
3347
3348 FeedbackSlot slot = bytecode_iterator().GetSlotOperand(0);
3349 JSTypeHintLowering::LoweringResult lowering =
3350 TryBuildSimplifiedUnaryOp(simplified()->TypeOf(), operand, slot);
3351 if (lowering.IsExit()) return;
3352
3353 Node* node = nullptr;
3354 if (lowering.IsSideEffectFree()) {
3355 node = lowering.value();
3356 } else {
3357 DCHECK(!lowering.Changed());
3358 node = NewNode(simplified()->TypeOf(), environment()->LookupAccumulator());
3359 }
3360
3361 environment()->BindAccumulator(node);
3362}
3363
3364void BytecodeGraphBuilder::BuildDelete(LanguageMode language_mode) {
3365 PrepareEagerCheckpoint();
3366 Node* key = environment()->LookupAccumulator();
3367 Node* object =
3368 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
3369 Node* mode = jsgraph()->ConstantNoHole(static_cast<int32_t>(language_mode));
3370 Node* node = NewNode(javascript()->DeleteProperty(), object, key, mode);
3371 environment()->BindAccumulator(node, Environment::kAttachFrameState);
3372}
3373
3374void BytecodeGraphBuilder::VisitDeletePropertyStrict() {
3375 BuildDelete(LanguageMode::kStrict);
3376}
3377
3378void BytecodeGraphBuilder::VisitDeletePropertySloppy() {
3379 BuildDelete(LanguageMode::kSloppy);
3380}
3381
3382void BytecodeGraphBuilder::VisitGetSuperConstructor() {
3383 Node* node = NewNode(javascript()->GetSuperConstructor(),
3384 environment()->LookupAccumulator());
3385 environment()->BindRegister(bytecode_iterator().GetRegisterOperand(0), node,
3386 Environment::kAttachFrameState);
3387}
3388
3389void BytecodeGraphBuilder::VisitFindNonDefaultConstructorOrConstruct() {
3390 Node* this_function =
3391 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
3392 Node* new_target =
3393 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
3394
3395 Node* node = NewNode(javascript()->FindNonDefaultConstructorOrConstruct(),
3396 this_function, new_target);
3397
3398 // The outputs of the JSFindNonDefaultConstructor node are [boolean_thing,
3399 // object_thing]. In some cases we reduce it to JSCreate, which has only one
3400 // output, [object_thing], and we also fix the poke location in that case.
3401 // Here we hard-wire the FrameState for [boolean_thing] to be `true`, which is
3402 // the correct value in the case where JSFindNonDefaultConstructor is reduced
3403 // to JSCreate.
3404 environment()->BindRegister(bytecode_iterator().GetRegisterOperand(2),
3405 jsgraph()->TrueConstant());
3406 environment()->BindRegistersToProjections(
3407 bytecode_iterator().GetRegisterOperand(2), node,
3408 Environment::kAttachFrameState);
3409}
3410
3411void BytecodeGraphBuilder::BuildCompareOp(const Operator* op) {
3412 DCHECK(JSOperator::IsBinaryWithFeedback(op->opcode()));
3413 PrepareEagerCheckpoint();
3414 Node* left =
3415 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
3416 Node* right = environment()->LookupAccumulator();
3417
3418 FeedbackSlot slot = bytecode_iterator().GetSlotOperand(1);
3420 TryBuildSimplifiedBinaryOp(op, left, right, slot);
3421 if (lowering.IsExit()) return;
3422
3423 Node* node = nullptr;
3424 if (lowering.IsSideEffectFree()) {
3425 node = lowering.value();
3426 } else {
3427 DCHECK(!lowering.Changed());
3428 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
3429 node = NewNode(op, left, right, feedback_vector_node());
3430 }
3431 environment()->BindAccumulator(node, Environment::kAttachFrameState);
3432}
3433
3434void BytecodeGraphBuilder::VisitTestEqual() {
3435 FeedbackSource feedback = CreateFeedbackSource(
3436 bytecode_iterator().GetSlotOperand(kCompareOperationHintIndex));
3437 BuildCompareOp(javascript()->Equal(feedback));
3438}
3439
3440void BytecodeGraphBuilder::VisitTestEqualStrict() {
3441 FeedbackSource feedback = CreateFeedbackSource(
3442 bytecode_iterator().GetSlotOperand(kCompareOperationHintIndex));
3443 BuildCompareOp(javascript()->StrictEqual(feedback));
3444}
3445
3446void BytecodeGraphBuilder::VisitTestLessThan() {
3447 FeedbackSource feedback = CreateFeedbackSource(
3448 bytecode_iterator().GetSlotOperand(kCompareOperationHintIndex));
3449 BuildCompareOp(javascript()->LessThan(feedback));
3450}
3451
3452void BytecodeGraphBuilder::VisitTestGreaterThan() {
3453 FeedbackSource feedback = CreateFeedbackSource(
3454 bytecode_iterator().GetSlotOperand(kCompareOperationHintIndex));
3455 BuildCompareOp(javascript()->GreaterThan(feedback));
3456}
3457
3458void BytecodeGraphBuilder::VisitTestLessThanOrEqual() {
3459 FeedbackSource feedback = CreateFeedbackSource(
3460 bytecode_iterator().GetSlotOperand(kCompareOperationHintIndex));
3461 BuildCompareOp(javascript()->LessThanOrEqual(feedback));
3462}
3463
3464void BytecodeGraphBuilder::VisitTestGreaterThanOrEqual() {
3465 FeedbackSource feedback = CreateFeedbackSource(
3466 bytecode_iterator().GetSlotOperand(kCompareOperationHintIndex));
3467 BuildCompareOp(javascript()->GreaterThanOrEqual(feedback));
3468}
3469
3470void BytecodeGraphBuilder::VisitTestReferenceEqual() {
3471 Node* left =
3472 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
3473 Node* right = environment()->LookupAccumulator();
3474 Node* result = NewNode(simplified()->ReferenceEqual(), left, right);
3475 environment()->BindAccumulator(result);
3476}
3477
3478void BytecodeGraphBuilder::VisitTestIn() {
3479 PrepareEagerCheckpoint();
3480 Node* object = environment()->LookupAccumulator();
3481 Node* key =
3482 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
3483 FeedbackSource feedback =
3484 CreateFeedbackSource(bytecode_iterator().GetIndexOperand(1));
3485 static_assert(JSHasPropertyNode::ObjectIndex() == 0);
3486 static_assert(JSHasPropertyNode::KeyIndex() == 1);
3487 static_assert(JSHasPropertyNode::FeedbackVectorIndex() == 2);
3488 const Operator* op = javascript()->HasProperty(feedback);
3489 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
3490 Node* node = NewNode(op, object, key, feedback_vector_node());
3491 environment()->BindAccumulator(node, Environment::kAttachFrameState);
3492}
3493
3494void BytecodeGraphBuilder::VisitTestInstanceOf() {
3495 FeedbackSource feedback = CreateFeedbackSource(
3496 bytecode_iterator().GetSlotOperand(kCompareOperationHintIndex));
3497 BuildCompareOp(javascript()->InstanceOf(feedback));
3498}
3499
3500void BytecodeGraphBuilder::VisitTestUndetectable() {
3501 Node* object = environment()->LookupAccumulator();
3502 Node* node = NewNode(jsgraph()->simplified()->ObjectIsUndetectable(), object);
3503 environment()->BindAccumulator(node);
3504}
3505
3506void BytecodeGraphBuilder::VisitTestNull() {
3507 Node* object = environment()->LookupAccumulator();
3508 Node* result = NewNode(simplified()->ReferenceEqual(), object,
3509 jsgraph()->NullConstant());
3510 environment()->BindAccumulator(result);
3511}
3512
3513void BytecodeGraphBuilder::VisitTestUndefined() {
3514 Node* object = environment()->LookupAccumulator();
3515 Node* result = NewNode(simplified()->ReferenceEqual(), object,
3517 environment()->BindAccumulator(result);
3518}
3519
3520void BytecodeGraphBuilder::VisitTestTypeOf() {
3521 Node* object = environment()->LookupAccumulator();
3522 auto literal_flag = interpreter::TestTypeOfFlags::Decode(
3523 bytecode_iterator().GetFlag8Operand(0));
3524 Node* result;
3525 switch (literal_flag) {
3526 case interpreter::TestTypeOfFlags::LiteralFlag::kNumber:
3527 result = NewNode(simplified()->ObjectIsNumber(), object);
3528 break;
3529 case interpreter::TestTypeOfFlags::LiteralFlag::kString:
3530 result = NewNode(simplified()->ObjectIsString(), object);
3531 break;
3532 case interpreter::TestTypeOfFlags::LiteralFlag::kSymbol:
3533 result = NewNode(simplified()->ObjectIsSymbol(), object);
3534 break;
3535 case interpreter::TestTypeOfFlags::LiteralFlag::kBigInt:
3536 result = NewNode(simplified()->ObjectIsBigInt(), object);
3537 break;
3538 case interpreter::TestTypeOfFlags::LiteralFlag::kBoolean:
3539 result = NewNode(common()->Select(MachineRepresentation::kTagged),
3540 NewNode(simplified()->ReferenceEqual(), object,
3541 jsgraph()->TrueConstant()),
3542 jsgraph()->TrueConstant(),
3543 NewNode(simplified()->ReferenceEqual(), object,
3544 jsgraph()->FalseConstant()));
3545 break;
3546 case interpreter::TestTypeOfFlags::LiteralFlag::kUndefined:
3547 result = graph()->NewNode(
3548 common()->Select(MachineRepresentation::kTagged),
3549 graph()->NewNode(simplified()->ReferenceEqual(), object,
3550 jsgraph()->NullConstant()),
3551 jsgraph()->FalseConstant(),
3552 graph()->NewNode(simplified()->ObjectIsUndetectable(), object));
3553 break;
3554 case interpreter::TestTypeOfFlags::LiteralFlag::kFunction:
3555 result =
3556 graph()->NewNode(simplified()->ObjectIsDetectableCallable(), object);
3557 break;
3558 case interpreter::TestTypeOfFlags::LiteralFlag::kObject:
3559 result = graph()->NewNode(
3560 common()->Select(MachineRepresentation::kTagged),
3561 graph()->NewNode(simplified()->ObjectIsNonCallable(), object),
3562 jsgraph()->TrueConstant(),
3563 graph()->NewNode(simplified()->ReferenceEqual(), object,
3564 jsgraph()->NullConstant()));
3565 break;
3566 case interpreter::TestTypeOfFlags::LiteralFlag::kOther:
3567 UNREACHABLE(); // Should never be emitted.
3568 }
3569 environment()->BindAccumulator(result);
3570}
3571
3572void BytecodeGraphBuilder::BuildCastOperator(const Operator* js_op) {
3573 Node* value = NewNode(js_op, environment()->LookupAccumulator());
3574 environment()->BindRegister(bytecode_iterator().GetRegisterOperand(0), value,
3575 Environment::kAttachFrameState);
3576}
3577
3578void BytecodeGraphBuilder::VisitToName() {
3579 Node* value =
3580 NewNode(javascript()->ToName(), environment()->LookupAccumulator());
3581 environment()->BindAccumulator(value, Environment::kAttachFrameState);
3582}
3583
3584void BytecodeGraphBuilder::VisitToObject() {
3585 BuildCastOperator(javascript()->ToObject());
3586}
3587
3588void BytecodeGraphBuilder::VisitToString() {
3589 Node* value =
3590 NewNode(javascript()->ToString(), environment()->LookupAccumulator());
3591 environment()->BindAccumulator(value, Environment::kAttachFrameState);
3592}
3593
3594void BytecodeGraphBuilder::VisitToBoolean() {
3595 Node* value =
3596 NewNode(simplified()->ToBoolean(), environment()->LookupAccumulator());
3597 environment()->BindAccumulator(value, Environment::kAttachFrameState);
3598}
3599
3600void BytecodeGraphBuilder::VisitToNumber() {
3601 PrepareEagerCheckpoint();
3602 Node* object = environment()->LookupAccumulator();
3603
3604 FeedbackSlot slot = bytecode_iterator().GetSlotOperand(0);
3605 JSTypeHintLowering::LoweringResult lowering =
3606 TryBuildSimplifiedToNumber(object, slot);
3607
3608 Node* node = nullptr;
3609 if (lowering.IsSideEffectFree()) {
3610 node = lowering.value();
3611 } else {
3612 DCHECK(!lowering.Changed());
3613 node = NewNode(javascript()->ToNumber(), object);
3614 }
3615
3616 environment()->BindAccumulator(node, Environment::kAttachFrameState);
3617}
3618
3619void BytecodeGraphBuilder::VisitToNumeric() {
3620 PrepareEagerCheckpoint();
3621 Node* object = environment()->LookupAccumulator();
3622
3623 // If we have some kind of Number feedback, we do the same lowering as for
3624 // ToNumber.
3625 FeedbackSlot slot = bytecode_iterator().GetSlotOperand(0);
3626 JSTypeHintLowering::LoweringResult lowering =
3627 TryBuildSimplifiedToNumber(object, slot);
3628
3629 Node* node = nullptr;
3630 if (lowering.IsSideEffectFree()) {
3631 node = lowering.value();
3632 } else {
3633 DCHECK(!lowering.Changed());
3634 node = NewNode(javascript()->ToNumeric(), object);
3635 }
3636
3637 environment()->BindAccumulator(node, Environment::kAttachFrameState);
3638}
3639
3640void BytecodeGraphBuilder::VisitJump() { BuildJump(); }
3641
3642void BytecodeGraphBuilder::VisitJumpConstant() { BuildJump(); }
3643
3644void BytecodeGraphBuilder::VisitJumpIfTrue() { BuildJumpIfTrue(); }
3645
3646void BytecodeGraphBuilder::VisitJumpIfTrueConstant() { BuildJumpIfTrue(); }
3647
3648void BytecodeGraphBuilder::VisitJumpIfFalse() { BuildJumpIfFalse(); }
3649
3650void BytecodeGraphBuilder::VisitJumpIfFalseConstant() { BuildJumpIfFalse(); }
3651
3652void BytecodeGraphBuilder::VisitJumpIfToBooleanTrue() {
3653 BuildJumpIfToBooleanTrue();
3654}
3655
3656void BytecodeGraphBuilder::VisitJumpIfToBooleanTrueConstant() {
3657 BuildJumpIfToBooleanTrue();
3658}
3659
3660void BytecodeGraphBuilder::VisitJumpIfToBooleanFalse() {
3661 BuildJumpIfToBooleanFalse();
3662}
3663
3664void BytecodeGraphBuilder::VisitJumpIfToBooleanFalseConstant() {
3665 BuildJumpIfToBooleanFalse();
3666}
3667
3668void BytecodeGraphBuilder::VisitJumpIfJSReceiver() { BuildJumpIfJSReceiver(); }
3669
3670void BytecodeGraphBuilder::VisitJumpIfJSReceiverConstant() {
3671 BuildJumpIfJSReceiver();
3672}
3673
3674void BytecodeGraphBuilder::VisitJumpIfForInDone() { BuildJumpIfForInDone(); }
3675
3676void BytecodeGraphBuilder::VisitJumpIfForInDoneConstant() {
3677 BuildJumpIfForInDone();
3678}
3679
3680void BytecodeGraphBuilder::VisitJumpIfNull() {
3681 BuildJumpIfEqual(jsgraph()->NullConstant());
3682}
3683
3684void BytecodeGraphBuilder::VisitJumpIfNullConstant() {
3685 BuildJumpIfEqual(jsgraph()->NullConstant());
3686}
3687
3688void BytecodeGraphBuilder::VisitJumpIfNotNull() {
3689 BuildJumpIfNotEqual(jsgraph()->NullConstant());
3690}
3691
3692void BytecodeGraphBuilder::VisitJumpIfNotNullConstant() {
3693 BuildJumpIfNotEqual(jsgraph()->NullConstant());
3694}
3695
3696void BytecodeGraphBuilder::VisitJumpIfUndefined() {
3697 BuildJumpIfEqual(jsgraph()->UndefinedConstant());
3698}
3699
3700void BytecodeGraphBuilder::VisitJumpIfUndefinedConstant() {
3701 BuildJumpIfEqual(jsgraph()->UndefinedConstant());
3702}
3703
3704void BytecodeGraphBuilder::VisitJumpIfNotUndefined() {
3705 BuildJumpIfNotEqual(jsgraph()->UndefinedConstant());
3706}
3707
3708void BytecodeGraphBuilder::VisitJumpIfNotUndefinedConstant() {
3709 BuildJumpIfNotEqual(jsgraph()->UndefinedConstant());
3710}
3711
3712void BytecodeGraphBuilder::VisitJumpIfUndefinedOrNull() {
3713 BuildJumpIfEqual(jsgraph()->UndefinedConstant());
3714 BuildJumpIfEqual(jsgraph()->NullConstant());
3715}
3716
3717void BytecodeGraphBuilder::VisitJumpIfUndefinedOrNullConstant() {
3718 BuildJumpIfEqual(jsgraph()->UndefinedConstant());
3719 BuildJumpIfEqual(jsgraph()->NullConstant());
3720}
3721
3722void BytecodeGraphBuilder::VisitJumpLoop() {
3723 BuildIterationBodyStackCheck();
3724 BuildJump();
3725}
3726
3727void BytecodeGraphBuilder::BuildSwitchOnSmi(Node* condition) {
3729 bytecode_iterator().GetJumpTableTargetOffsets();
3730
3731 NewSwitch(condition, offsets.size() + 1);
3732 for (interpreter::JumpTableTargetOffset entry : offsets) {
3733 SubEnvironment sub_environment(this);
3734 NewIfValue(entry.case_value);
3735 MergeIntoSuccessorEnvironment(entry.target_offset);
3736 }
3737 NewIfDefault();
3738}
3739
3740void BytecodeGraphBuilder::VisitSwitchOnSmiNoFeedback() {
3741 PrepareEagerCheckpoint();
3742
3743 Node* acc = environment()->LookupAccumulator();
3744 Node* acc_smi = NewNode(simplified()->CheckSmi(FeedbackSource()), acc);
3745 BuildSwitchOnSmi(acc_smi);
3746}
3747
3748void BytecodeGraphBuilder::VisitSetPendingMessage() {
3749 Node* previous_message = NewNode(javascript()->LoadMessage());
3750 NewNode(javascript()->StoreMessage(), environment()->LookupAccumulator());
3751 environment()->BindAccumulator(previous_message);
3752}
3753
3754void BytecodeGraphBuilder::BuildReturn(const BytecodeLivenessState* liveness) {
3755 BuildLoopExitsForFunctionExit(liveness);
3756 Node* pop_node = jsgraph()->ZeroConstant();
3757 Node* control =
3758 NewNode(common()->Return(), pop_node, environment()->LookupAccumulator());
3759 MergeControlToLeaveFunction(control);
3760}
3761
3762void BytecodeGraphBuilder::VisitReturn() {
3763 BuildReturn(bytecode_analysis().GetInLivenessFor(
3764 bytecode_iterator().current_offset()));
3765}
3766
3767void BytecodeGraphBuilder::VisitDebugger() {
3768 PrepareEagerCheckpoint();
3769 Node* call = NewNode(javascript()->Debugger());
3770 environment()->RecordAfterState(call, Environment::kAttachFrameState);
3771}
3772
3773// We cannot create a graph from the debugger copy of the bytecode array.
3774#define DEBUG_BREAK(Name, ...) \
3775 void BytecodeGraphBuilder::Visit##Name() { UNREACHABLE(); }
3777#undef DEBUG_BREAK
3778
3779void BytecodeGraphBuilder::VisitIncBlockCounter() {
3780 Node* closure = GetFunctionClosure();
3781 Node* coverage_array_slot =
3782 jsgraph()->ConstantNoHole(bytecode_iterator().GetIndexOperand(0));
3783
3784 // Lowered by js-intrinsic-lowering to call Builtin::kIncBlockCounter.
3785 const Operator* op =
3786 javascript()->CallRuntime(Runtime::kInlineIncBlockCounter);
3787
3788 NewNode(op, closure, coverage_array_slot);
3789}
3790
3791void BytecodeGraphBuilder::VisitForInEnumerate() {
3792 Node* receiver =
3793 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
3794 Node* enumerator = NewNode(javascript()->ForInEnumerate(), receiver);
3795 environment()->BindAccumulator(enumerator, Environment::kAttachFrameState);
3796}
3797
3798void BytecodeGraphBuilder::VisitForInPrepare() {
3799 PrepareEagerCheckpoint();
3800 Node* enumerator = environment()->LookupAccumulator();
3801
3802 FeedbackSlot slot = bytecode_iterator().GetSlotOperand(1);
3803 JSTypeHintLowering::LoweringResult lowering =
3804 TryBuildSimplifiedForInPrepare(enumerator, slot);
3805 if (lowering.IsExit()) return;
3806 DCHECK(!lowering.Changed());
3807 FeedbackSource feedback = CreateFeedbackSource(slot);
3808 Node* node = NewNode(javascript()->ForInPrepare(GetForInMode(slot), feedback),
3809 enumerator, feedback_vector_node());
3810 environment()->BindRegistersToProjections(
3811 bytecode_iterator().GetRegisterOperand(0), node);
3812}
3813
3814void BytecodeGraphBuilder::VisitForInNext() {
3815 PrepareEagerCheckpoint();
3816 Node* receiver =
3817 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
3818 Node* index =
3819 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
3820 int catch_reg_pair_index = bytecode_iterator().GetRegisterOperand(2).index();
3821 Node* cache_type = environment()->LookupRegister(
3822 interpreter::Register(catch_reg_pair_index));
3823 Node* cache_array = environment()->LookupRegister(
3824 interpreter::Register(catch_reg_pair_index + 1));
3825
3826 // We need to rename the {index} here, as in case of OSR we lose the
3827 // information that the {index} is always a valid unsigned Smi value.
3828 index = NewNode(common()->TypeGuard(Type::UnsignedSmall()), index);
3829
3830 FeedbackSlot slot = bytecode_iterator().GetSlotOperand(3);
3831 JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedForInNext(
3832 receiver, cache_array, cache_type, index, slot);
3833 if (lowering.IsExit()) return;
3834
3835 DCHECK(!lowering.Changed());
3836 FeedbackSource feedback = CreateFeedbackSource(slot);
3837 Node* node =
3838 NewNode(javascript()->ForInNext(GetForInMode(slot), feedback), receiver,
3839 cache_array, cache_type, index, feedback_vector_node());
3840 environment()->BindAccumulator(node, Environment::kAttachFrameState);
3841}
3842
3843void BytecodeGraphBuilder::VisitForInStep() {
3844 PrepareEagerCheckpoint();
3845 interpreter::Register index_reg = bytecode_iterator().GetRegisterOperand(0);
3846 Node* index = environment()->LookupRegister(index_reg);
3847 index = NewNode(simplified()->SpeculativeSmallIntegerAdd(
3848 NumberOperationHint::kSignedSmall),
3849 index, jsgraph()->OneConstant());
3850 environment()->BindRegister(index_reg, index, Environment::kAttachFrameState);
3851}
3852
3853void BytecodeGraphBuilder::VisitGetIterator() {
3854 PrepareEagerCheckpoint();
3855 Node* receiver =
3856 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
3857 FeedbackSource load_feedback =
3858 CreateFeedbackSource(bytecode_iterator().GetIndexOperand(1));
3859 FeedbackSource call_feedback =
3860 CreateFeedbackSource(bytecode_iterator().GetIndexOperand(2));
3861 const Operator* op = javascript()->GetIterator(load_feedback, call_feedback);
3862
3863 JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedGetIterator(
3864 op, receiver, load_feedback.slot, call_feedback.slot);
3865 if (lowering.IsExit()) return;
3866
3867 DCHECK(!lowering.Changed());
3868 static_assert(JSGetIteratorNode::ReceiverIndex() == 0);
3869 static_assert(JSGetIteratorNode::FeedbackVectorIndex() == 1);
3870 DCHECK(IrOpcode::IsFeedbackCollectingOpcode(op->opcode()));
3871 Node* iterator = NewNode(op, receiver, feedback_vector_node());
3872 environment()->BindAccumulator(iterator, Environment::kAttachFrameState);
3873}
3874
3875void BytecodeGraphBuilder::VisitSuspendGenerator() {
3876 Node* generator = environment()->LookupRegister(
3877 bytecode_iterator().GetRegisterOperand(0));
3878 interpreter::Register first_reg = bytecode_iterator().GetRegisterOperand(1);
3879 // We assume we are storing a range starting from index 0.
3880 CHECK_EQ(0, first_reg.index());
3881 int register_count =
3882 static_cast<int>(bytecode_iterator().GetRegisterCountOperand(2));
3883 int parameter_count_without_receiver = bytecode_array().parameter_count() - 1;
3884
3885 Node* suspend_id = jsgraph()->SmiConstant(
3886 bytecode_iterator().GetUnsignedImmediateOperand(3));
3887
3888 // The offsets used by the bytecode iterator are relative to a different base
3889 // than what is used in the interpreter, hence the addition.
3890 Node* offset =
3891 jsgraph()->ConstantNoHole(bytecode_iterator().current_offset() +
3893
3894 const BytecodeLivenessState* liveness = bytecode_analysis().GetInLivenessFor(
3895 bytecode_iterator().current_offset());
3896
3897 // Maybe overallocate the value list since we don't know how many registers
3898 // are live.
3899 // TODO(leszeks): We could get this count from liveness rather than the
3900 // register list.
3901 int value_input_count = 3 + parameter_count_without_receiver + register_count;
3902
3903 Node** value_inputs = local_zone()->AllocateArray<Node*>(value_input_count);
3904 value_inputs[0] = generator;
3905 value_inputs[1] = suspend_id;
3906 value_inputs[2] = offset;
3907
3908 int count_written = 0;
3909 // Store the parameters.
3910 for (int i = 0; i < parameter_count_without_receiver; i++) {
3911 value_inputs[3 + count_written++] =
3912 environment()->LookupRegister(bytecode_iterator().GetParameter(i));
3913 }
3914
3915 // Store the registers.
3916 for (int i = 0; i < register_count; ++i) {
3917 if (liveness == nullptr || liveness->RegisterIsLive(i)) {
3918 int index_in_parameters_and_registers =
3919 parameter_count_without_receiver + i;
3920 while (count_written < index_in_parameters_and_registers) {
3921 value_inputs[3 + count_written++] = jsgraph()->OptimizedOutConstant();
3922 }
3923 value_inputs[3 + count_written++] =
3924 environment()->LookupRegister(interpreter::Register(i));
3925 DCHECK_EQ(count_written, index_in_parameters_and_registers + 1);
3926 }
3927 }
3928
3929 // Use the actual written count rather than the register count to create the
3930 // node.
3931 MakeNode(javascript()->GeneratorStore(count_written), 3 + count_written,
3932 value_inputs, false);
3933
3934 // TODO(leszeks): This over-approximates the liveness at exit, only the
3935 // accumulator should be live by this point.
3936 BuildReturn(bytecode_analysis().GetInLivenessFor(
3937 bytecode_iterator().current_offset()));
3938}
3939
3940void BytecodeGraphBuilder::BuildSwitchOnGeneratorState(
3941 const ZoneVector<ResumeJumpTarget>& resume_jump_targets,
3942 bool allow_fallthrough_on_executing) {
3943 Node* generator_state = environment()->LookupGeneratorState();
3944
3945 int extra_cases = allow_fallthrough_on_executing ? 2 : 1;
3946 NewSwitch(generator_state,
3947 static_cast<int>(resume_jump_targets.size() + extra_cases));
3948 for (const ResumeJumpTarget& target : resume_jump_targets) {
3949 SubEnvironment sub_environment(this);
3950 NewIfValue(target.suspend_id());
3951 if (target.is_leaf()) {
3952 // Mark that we are resuming executing.
3953 environment()->BindGeneratorState(
3955 }
3956 // Jump to the target offset, whether it's a loop header or the resume.
3957 MergeIntoSuccessorEnvironment(target.target_offset());
3958 }
3959
3960 {
3961 SubEnvironment sub_environment(this);
3962 // We should never hit the default case (assuming generator state cannot be
3963 // corrupted), so abort if we do.
3964 // TODO(leszeks): Maybe only check this in debug mode, and otherwise use
3965 // the default to represent one of the cases above/fallthrough below?
3966 NewIfDefault();
3967 NewNode(simplified()->RuntimeAbort(AbortReason::kInvalidJumpTableIndex));
3968 // TODO(7099): Investigate if we need LoopExit here.
3969 Node* control = NewNode(common()->Throw());
3970 MergeControlToLeaveFunction(control);
3971 }
3972
3973 if (allow_fallthrough_on_executing) {
3974 // If we are executing (rather than resuming), and we allow it, just fall
3975 // through to the actual loop body.
3977 } else {
3978 // Otherwise, this environment is dead.
3979 set_environment(nullptr);
3980 }
3981}
3982
3983void BytecodeGraphBuilder::VisitSwitchOnGeneratorState() {
3984 Node* generator =
3985 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
3986
3987 Node* generator_is_undefined =
3988 NewNode(simplified()->ReferenceEqual(), generator,
3989 jsgraph()->UndefinedConstant());
3990
3991 NewBranch(generator_is_undefined);
3992 {
3993 SubEnvironment resume_env(this);
3994 NewIfFalse();
3995
3996 Node* generator_state =
3997 NewNode(javascript()->GeneratorRestoreContinuation(), generator);
3998 environment()->BindGeneratorState(generator_state);
3999
4000 Node* generator_context =
4001 NewNode(javascript()->GeneratorRestoreContext(), generator);
4002 environment()->SetContext(generator_context);
4003
4004 BuildSwitchOnGeneratorState(bytecode_analysis().resume_jump_targets(),
4005 false);
4006 }
4007
4008 // Fallthrough for the first-call case.
4009 NewIfTrue();
4010}
4011
4012void BytecodeGraphBuilder::VisitResumeGenerator() {
4013 Node* generator =
4014 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
4015 interpreter::Register first_reg = bytecode_iterator().GetRegisterOperand(1);
4016 // We assume we are restoring registers starting from index 0.
4017 CHECK_EQ(0, first_reg.index());
4018
4019 const BytecodeLivenessState* liveness = bytecode_analysis().GetOutLivenessFor(
4020 bytecode_iterator().current_offset());
4021
4022 int parameter_count_without_receiver = bytecode_array().parameter_count() - 1;
4023
4024 // Mapping between registers and array indices must match that used in
4025 // InterpreterAssembler::ExportParametersAndRegisterFile.
4026 for (int i = 0; i < environment()->register_count(); ++i) {
4027 if (liveness == nullptr || liveness->RegisterIsLive(i)) {
4028 Node* value = NewNode(javascript()->GeneratorRestoreRegister(
4029 parameter_count_without_receiver + i),
4030 generator);
4031 environment()->BindRegister(interpreter::Register(i), value);
4032 }
4033 }
4034
4035 // Update the accumulator with the generator's input_or_debug_pos.
4036 Node* input_or_debug_pos =
4037 NewNode(javascript()->GeneratorRestoreInputOrDebugPos(), generator);
4038 environment()->BindAccumulator(input_or_debug_pos);
4039}
4040
4041void BytecodeGraphBuilder::VisitWide() {
4042 // Consumed by the BytecodeArrayIterator.
4043 UNREACHABLE();
4044}
4045
4046void BytecodeGraphBuilder::VisitExtraWide() {
4047 // Consumed by the BytecodeArrayIterator.
4048 UNREACHABLE();
4049}
4050
4051void BytecodeGraphBuilder::VisitIllegal() {
4052 // Not emitted in valid bytecode.
4053 UNREACHABLE();
4054}
4055
4056void BytecodeGraphBuilder::SwitchToMergeEnvironment(int current_offset) {
4057 auto it = merge_environments_.find(current_offset);
4058 if (it != merge_environments_.end()) {
4059 mark_as_needing_eager_checkpoint(true);
4060 if (environment() != nullptr) {
4061 it->second->Merge(environment(),
4062 bytecode_analysis().GetInLivenessFor(current_offset));
4063 }
4064 set_environment(it->second);
4065 }
4066}
4067
4068void BytecodeGraphBuilder::BuildLoopHeaderEnvironment(int current_offset) {
4069 if (bytecode_analysis().IsLoopHeader(current_offset)) {
4070 mark_as_needing_eager_checkpoint(true);
4071 const LoopInfo& loop_info =
4072 bytecode_analysis().GetLoopInfoFor(current_offset);
4073 const BytecodeLivenessState* liveness =
4074 bytecode_analysis().GetInLivenessFor(current_offset);
4075
4076 const auto& resume_jump_targets = loop_info.resume_jump_targets();
4077 bool generate_suspend_switch = !resume_jump_targets.empty();
4078
4079 // Add loop header.
4080 environment()->PrepareForLoop(loop_info.assignments(), liveness);
4081
4082 // Store a copy of the environment so we can connect merged back edge inputs
4083 // to the loop header.
4084 merge_environments_[current_offset] = environment()->Copy();
4085
4086 // If this loop contains resumes, create a new switch just after the loop
4087 // for those resumes.
4088 if (generate_suspend_switch) {
4089 BuildSwitchOnGeneratorState(loop_info.resume_jump_targets(), true);
4090
4091 // TODO(leszeks): At this point we know we are executing rather than
4092 // resuming, so we should be able to prune off the phis in the environment
4093 // related to the resume path.
4094
4095 // Set the generator state to a known constant.
4096 environment()->BindGeneratorState(
4098 }
4099 }
4100}
4101
4102void BytecodeGraphBuilder::MergeIntoSuccessorEnvironment(int target_offset) {
4103 BuildLoopExitsForBranch(target_offset);
4104 Environment*& merge_environment = merge_environments_[target_offset];
4105
4106 if (merge_environment == nullptr) {
4107 // Append merge nodes to the environment. We may merge here with another
4108 // environment. So add a place holder for merge nodes. We may add redundant
4109 // but will be eliminated in a later pass.
4110 NewMerge();
4111 merge_environment = environment();
4112 } else {
4113 // Merge any values which are live coming into the successor.
4114 merge_environment->Merge(
4115 environment(), bytecode_analysis().GetInLivenessFor(target_offset));
4116 }
4117 set_environment(nullptr);
4118}
4119
4120void BytecodeGraphBuilder::MergeControlToLeaveFunction(Node* exit) {
4121 exit_controls_.push_back(exit);
4122 set_environment(nullptr);
4123}
4124
4125void BytecodeGraphBuilder::BuildLoopExitsForBranch(int target_offset) {
4126 int origin_offset = bytecode_iterator().current_offset();
4127 // Only build loop exits for forward edges.
4128 if (target_offset > origin_offset) {
4129 BuildLoopExitsUntilLoop(
4130 bytecode_analysis().GetLoopOffsetFor(target_offset),
4131 bytecode_analysis().GetInLivenessFor(target_offset));
4132 }
4133}
4134
4135void BytecodeGraphBuilder::BuildLoopExitsUntilLoop(
4136 int loop_offset, const BytecodeLivenessState* liveness) {
4137 int origin_offset = bytecode_iterator().current_offset();
4138 int current_loop = bytecode_analysis().GetLoopOffsetFor(origin_offset);
4139 // The limit_offset is the stop offset for building loop exists, used for OSR.
4140 // It prevents the creations of loopexits for loops which do not exist.
4141 loop_offset = std::max(loop_offset, currently_peeled_loop_offset_);
4142
4143 while (loop_offset < current_loop) {
4144 Node* loop_node = merge_environments_[current_loop]->GetControlDependency();
4145 const LoopInfo& loop_info =
4146 bytecode_analysis().GetLoopInfoFor(current_loop);
4147 environment()->PrepareForLoopExit(loop_node, loop_info.assignments(),
4148 liveness);
4149 current_loop = loop_info.parent_offset();
4150 }
4151}
4152
4153void BytecodeGraphBuilder::BuildLoopExitsForFunctionExit(
4154 const BytecodeLivenessState* liveness) {
4155 BuildLoopExitsUntilLoop(-1, liveness);
4156}
4157
4158void BytecodeGraphBuilder::BuildJump() {
4159 MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
4160}
4161
4162void BytecodeGraphBuilder::BuildJumpIf(Node* condition) {
4163 NewBranch(condition, BranchHint::kNone);
4164 {
4165 SubEnvironment sub_environment(this);
4166 NewIfTrue();
4167 MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
4168 }
4169 NewIfFalse();
4170}
4171
4172void BytecodeGraphBuilder::BuildJumpIfNot(Node* condition) {
4173 NewBranch(condition, BranchHint::kNone);
4174 {
4175 SubEnvironment sub_environment(this);
4176 NewIfFalse();
4177 MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
4178 }
4179 NewIfTrue();
4180}
4181
4182void BytecodeGraphBuilder::BuildJumpIfEqual(Node* comperand) {
4183 Node* accumulator = environment()->LookupAccumulator();
4184 Node* condition =
4185 NewNode(simplified()->ReferenceEqual(), accumulator, comperand);
4186 BuildJumpIf(condition);
4187}
4188
4189void BytecodeGraphBuilder::BuildJumpIfNotEqual(Node* comperand) {
4190 Node* accumulator = environment()->LookupAccumulator();
4191 Node* condition =
4192 NewNode(simplified()->ReferenceEqual(), accumulator, comperand);
4193 BuildJumpIfNot(condition);
4194}
4195
4196void BytecodeGraphBuilder::BuildJumpIfFalse() {
4197 NewBranch(environment()->LookupAccumulator(), BranchHint::kNone);
4198 {
4199 SubEnvironment sub_environment(this);
4200 NewIfFalse();
4201 environment()->BindAccumulator(jsgraph()->FalseConstant());
4202 MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
4203 }
4204 NewIfTrue();
4205 environment()->BindAccumulator(jsgraph()->TrueConstant());
4206}
4207
4208void BytecodeGraphBuilder::BuildJumpIfTrue() {
4209 NewBranch(environment()->LookupAccumulator(), BranchHint::kNone);
4210 {
4211 SubEnvironment sub_environment(this);
4212 NewIfTrue();
4213 environment()->BindAccumulator(jsgraph()->TrueConstant());
4214 MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
4215 }
4216 NewIfFalse();
4217 environment()->BindAccumulator(jsgraph()->FalseConstant());
4218}
4219
4220void BytecodeGraphBuilder::BuildJumpIfToBooleanTrue() {
4221 Node* accumulator = environment()->LookupAccumulator();
4222 Node* condition = NewNode(simplified()->ToBoolean(), accumulator);
4223 BuildJumpIf(condition);
4224}
4225
4226void BytecodeGraphBuilder::BuildJumpIfToBooleanFalse() {
4227 Node* accumulator = environment()->LookupAccumulator();
4228 Node* condition = NewNode(simplified()->ToBoolean(), accumulator);
4229 BuildJumpIfNot(condition);
4230}
4231
4232void BytecodeGraphBuilder::BuildJumpIfNotHole() {
4233 Node* accumulator = environment()->LookupAccumulator();
4234 Node* condition = NewNode(simplified()->ReferenceEqual(), accumulator,
4235 jsgraph()->TheHoleConstant());
4236 BuildJumpIfNot(condition);
4237}
4238
4239void BytecodeGraphBuilder::BuildJumpIfJSReceiver() {
4240 Node* accumulator = environment()->LookupAccumulator();
4241 Node* condition = NewNode(simplified()->ObjectIsReceiver(), accumulator);
4242 BuildJumpIf(condition);
4243}
4244
4245void BytecodeGraphBuilder::BuildJumpIfForInDone() {
4246 // There's an eager checkpoint here for the speculative comparison, but it can
4247 // never actually deopt because these are known to be Smi.
4248 PrepareEagerCheckpoint();
4249 Node* index =
4250 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
4251 Node* cache_length =
4252 environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(2));
4253 Node* condition = NewNode(
4254 simplified()->SpeculativeNumberEqual(NumberOperationHint::kSignedSmall),
4255 index, cache_length);
4256 BuildJumpIf(condition);
4257}
4258
4260BytecodeGraphBuilder::TryBuildSimplifiedUnaryOp(const Operator* op,
4261 Node* operand,
4262 FeedbackSlot slot) {
4263 Node* effect = environment()->GetEffectDependency();
4264 Node* control = environment()->GetControlDependency();
4266 type_hint_lowering().ReduceUnaryOperation(op, operand, effect, control,
4267 slot);
4268 ApplyEarlyReduction(result);
4269 return result;
4270}
4271
4273BytecodeGraphBuilder::TryBuildSimplifiedBinaryOp(const Operator* op, Node* left,
4274 Node* right,
4275 FeedbackSlot slot) {
4276 Node* effect = environment()->GetEffectDependency();
4277 Node* control = environment()->GetControlDependency();
4279 type_hint_lowering().ReduceBinaryOperation(op, left, right, effect,
4280 control, slot);
4281 ApplyEarlyReduction(result);
4282 return result;
4283}
4284
4286BytecodeGraphBuilder::TryBuildSimplifiedForInNext(Node* receiver,
4287 Node* cache_array,
4288 Node* cache_type, Node* index,
4289 FeedbackSlot slot) {
4290 Node* effect = environment()->GetEffectDependency();
4291 Node* control = environment()->GetControlDependency();
4293 type_hint_lowering().ReduceForInNextOperation(
4294 receiver, cache_array, cache_type, index, effect, control, slot);
4295 ApplyEarlyReduction(result);
4296 return result;
4297}
4298
4300BytecodeGraphBuilder::TryBuildSimplifiedForInPrepare(Node* enumerator,
4301 FeedbackSlot slot) {
4302 Node* effect = environment()->GetEffectDependency();
4303 Node* control = environment()->GetControlDependency();
4305 type_hint_lowering().ReduceForInPrepareOperation(enumerator, effect,
4306 control, slot);
4307 ApplyEarlyReduction(result);
4308 return result;
4309}
4310
4312BytecodeGraphBuilder::TryBuildSimplifiedToNumber(Node* value,
4313 FeedbackSlot slot) {
4314 Node* effect = environment()->GetEffectDependency();
4315 Node* control = environment()->GetControlDependency();
4317 type_hint_lowering().ReduceToNumberOperation(value, effect, control,
4318 slot);
4319 ApplyEarlyReduction(result);
4320 return result;
4321}
4322
4323JSTypeHintLowering::LoweringResult BytecodeGraphBuilder::TryBuildSimplifiedCall(
4324 const Operator* op, Node* const* args, int arg_count, FeedbackSlot slot) {
4325 Node* effect = environment()->GetEffectDependency();
4326 Node* control = environment()->GetControlDependency();
4328 type_hint_lowering().ReduceCallOperation(op, args, arg_count, effect,
4329 control, slot);
4330 ApplyEarlyReduction(result);
4331 return result;
4332}
4333
4335BytecodeGraphBuilder::TryBuildSimplifiedConstruct(const Operator* op,
4336 Node* const* args,
4337 int arg_count,
4338 FeedbackSlot slot) {
4339 Node* effect = environment()->GetEffectDependency();
4340 Node* control = environment()->GetControlDependency();
4342 type_hint_lowering().ReduceConstructOperation(op, args, arg_count, effect,
4343 control, slot);
4344 ApplyEarlyReduction(result);
4345 return result;
4346}
4347
4349BytecodeGraphBuilder::TryBuildSimplifiedGetIterator(const Operator* op,
4350 Node* receiver,
4351 FeedbackSlot load_slot,
4352 FeedbackSlot call_slot) {
4353 Node* effect = environment()->GetEffectDependency();
4354 Node* control = environment()->GetControlDependency();
4355 JSTypeHintLowering::LoweringResult early_reduction =
4356 type_hint_lowering().ReduceGetIteratorOperation(
4357 op, receiver, effect, control, load_slot, call_slot);
4358 ApplyEarlyReduction(early_reduction);
4359 return early_reduction;
4360}
4361
4363BytecodeGraphBuilder::TryBuildSimplifiedLoadNamed(const Operator* op,
4364 FeedbackSlot slot) {
4365 Node* effect = environment()->GetEffectDependency();
4366 Node* control = environment()->GetControlDependency();
4367 JSTypeHintLowering::LoweringResult early_reduction =
4368 type_hint_lowering().ReduceLoadNamedOperation(op, effect, control, slot);
4369 ApplyEarlyReduction(early_reduction);
4370 return early_reduction;
4371}
4372
4374BytecodeGraphBuilder::TryBuildSimplifiedLoadKeyed(const Operator* op,
4375 Node* receiver, Node* key,
4376 FeedbackSlot slot) {
4377 Node* effect = environment()->GetEffectDependency();
4378 Node* control = environment()->GetControlDependency();
4380 type_hint_lowering().ReduceLoadKeyedOperation(op, receiver, key, effect,
4381 control, slot);
4382 ApplyEarlyReduction(result);
4383 return result;
4384}
4385
4387BytecodeGraphBuilder::TryBuildSimplifiedStoreNamed(const Operator* op,
4388 Node* receiver, Node* value,
4389 FeedbackSlot slot) {
4390 Node* effect = environment()->GetEffectDependency();
4391 Node* control = environment()->GetControlDependency();
4393 type_hint_lowering().ReduceStoreNamedOperation(op, receiver, value,
4394 effect, control, slot);
4395 ApplyEarlyReduction(result);
4396 return result;
4397}
4398
4400BytecodeGraphBuilder::TryBuildSimplifiedStoreKeyed(const Operator* op,
4401 Node* receiver, Node* key,
4402 Node* value,
4403 FeedbackSlot slot) {
4404 Node* effect = environment()->GetEffectDependency();
4405 Node* control = environment()->GetControlDependency();
4407 type_hint_lowering().ReduceStoreKeyedOperation(op, receiver, key, value,
4408 effect, control, slot);
4409 ApplyEarlyReduction(result);
4410 return result;
4411}
4412
4413void BytecodeGraphBuilder::ApplyEarlyReduction(
4415 if (reduction.IsExit()) {
4416 MergeControlToLeaveFunction(reduction.control());
4417 } else if (reduction.IsSideEffectFree()) {
4418 environment()->UpdateEffectDependency(reduction.effect());
4419 environment()->UpdateControlDependency(reduction.control());
4420 } else {
4421 DCHECK(!reduction.Changed());
4422 // At the moment, we assume side-effect free reduction. To support
4423 // side-effects, we would have to invalidate the eager checkpoint,
4424 // so that deoptimization does not repeat the side effect.
4425 }
4426}
4427
4428Node** BytecodeGraphBuilder::EnsureInputBufferSize(int size) {
4429 if (size > input_buffer_size_) {
4430 size = size + kInputBufferSizeIncrement + input_buffer_size_;
4431 input_buffer_ = local_zone()->AllocateArray<Node*>(size);
4432 input_buffer_size_ = size;
4433 }
4434 return input_buffer_;
4435}
4436
4437void BytecodeGraphBuilder::ExitThenEnterExceptionHandlers(int current_offset) {
4439 HandlerTable table(bytecode_array().handler_table_address(),
4440 bytecode_array().handler_table_size(),
4442
4443 // Potentially exit exception handlers.
4444 while (!exception_handlers_.empty()) {
4445 int current_end = exception_handlers_.top().end_offset_;
4446 if (current_offset < current_end) break; // Still covered by range.
4447 exception_handlers_.pop();
4448 }
4449
4450 // Potentially enter exception handlers.
4451 int num_entries = table.NumberOfRangeEntries();
4452 while (current_exception_handler_ < num_entries) {
4453 int next_start = table.GetRangeStart(current_exception_handler_);
4454 if (current_offset < next_start) break; // Not yet covered by range.
4455 int next_end = table.GetRangeEnd(current_exception_handler_);
4456 int next_handler = table.GetRangeHandler(current_exception_handler_);
4457 int context_register = table.GetRangeData(current_exception_handler_);
4458 exception_handlers_.push(
4459 {next_start, next_end, next_handler, context_register});
4460 current_exception_handler_++;
4461 }
4462}
4463
4464Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
4465 Node* const* value_inputs,
4466 bool incomplete) {
4467 DCHECK_EQ(op->ValueInputCount(), value_input_count);
4468 // Parameter nodes must be created through GetParameter.
4470 op->opcode() == IrOpcode::kParameter,
4471 (nullptr == cached_parameters_[static_cast<std::size_t>(
4472 ParameterIndexOf(op) - ParameterInfo::kMinIndex)]));
4473
4474 bool has_context = OperatorProperties::HasContextInput(op);
4475 bool has_frame_state = OperatorProperties::HasFrameStateInput(op);
4476 bool has_control = op->ControlInputCount() == 1;
4477 bool has_effect = op->EffectInputCount() == 1;
4478
4479 DCHECK_LT(op->ControlInputCount(), 2);
4480 DCHECK_LT(op->EffectInputCount(), 2);
4481
4482 Node* result = nullptr;
4483 if (!has_context && !has_frame_state && !has_control && !has_effect) {
4484 result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
4485 } else {
4486 bool inside_handler = !exception_handlers_.empty();
4487 int input_count_with_deps = value_input_count;
4488 if (has_context) ++input_count_with_deps;
4489 if (has_frame_state) ++input_count_with_deps;
4490 if (has_control) ++input_count_with_deps;
4491 if (has_effect) ++input_count_with_deps;
4492 Node** buffer = EnsureInputBufferSize(input_count_with_deps);
4493 if (value_input_count > 0) {
4494 memcpy(buffer, value_inputs, kSystemPointerSize * value_input_count);
4495 }
4496 Node** current_input = buffer + value_input_count;
4497 if (has_context) {
4498 *current_input++ = OperatorProperties::NeedsExactContext(op)
4499 ? environment()->Context()
4500 : native_context_node();
4501 }
4502 if (has_frame_state) {
4503 // The frame state will be inserted later. Here we misuse the {Dead} node
4504 // as a sentinel to be later overwritten with the real frame state by the
4505 // calls to {PrepareFrameState} within individual visitor methods.
4506 *current_input++ = jsgraph()->Dead();
4507 }
4508 if (has_effect) {
4509 *current_input++ = environment()->GetEffectDependency();
4510 }
4511 if (has_control) {
4512 *current_input++ = environment()->GetControlDependency();
4513 }
4514 result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
4515 // Update the current control dependency for control-producing nodes.
4516 if (result->op()->ControlOutputCount() > 0) {
4517 environment()->UpdateControlDependency(result);
4518 }
4519 // Update the current effect dependency for effect-producing nodes.
4520 if (result->op()->EffectOutputCount() > 0) {
4521 environment()->UpdateEffectDependency(result);
4522 }
4523 // Add implicit exception continuation for throwing nodes.
4524 if (!result->op()->HasProperty(Operator::kNoThrow) && inside_handler) {
4525 int handler_offset = exception_handlers_.top().handler_offset_;
4526 int context_index = exception_handlers_.top().context_register_;
4527 interpreter::Register context_register(context_index);
4528 Environment* success_env = environment()->Copy();
4529 const Operator* if_exception = common()->IfException();
4530 Node* effect = environment()->GetEffectDependency();
4531 Node* on_exception = graph()->NewNode(if_exception, effect, result);
4532 Node* context = environment()->LookupRegister(context_register);
4533 environment()->UpdateControlDependency(on_exception);
4534 environment()->UpdateEffectDependency(on_exception);
4535 environment()->BindAccumulator(on_exception);
4536 environment()->SetContext(context);
4537 MergeIntoSuccessorEnvironment(handler_offset);
4538 set_environment(success_env);
4539 }
4540 // Add implicit success continuation for throwing nodes.
4541 if (!result->op()->HasProperty(Operator::kNoThrow) && inside_handler) {
4542 const Operator* if_success = common()->IfSuccess();
4543 Node* on_success = graph()->NewNode(if_success, result);
4544 environment()->UpdateControlDependency(on_success);
4545 }
4546 // Ensure checkpoints are created after operations with side-effects.
4547 if (has_effect && !result->op()->HasProperty(Operator::kNoWrite)) {
4548 mark_as_needing_eager_checkpoint(true);
4549 }
4550 }
4551
4552 return result;
4553}
4554
4555
4556Node* BytecodeGraphBuilder::NewPhi(int count, Node* input, Node* control) {
4557 const Operator* phi_op = common()->Phi(MachineRepresentation::kTagged, count);
4558 Node** buffer = EnsureInputBufferSize(count + 1);
4559 MemsetPointer(buffer, input, count);
4560 buffer[count] = control;
4561 return graph()->NewNode(phi_op, count + 1, buffer, true);
4562}
4563
4564Node* BytecodeGraphBuilder::NewEffectPhi(int count, Node* input,
4565 Node* control) {
4566 const Operator* phi_op = common()->EffectPhi(count);
4567 Node** buffer = EnsureInputBufferSize(count + 1);
4568 MemsetPointer(buffer, input, count);
4569 buffer[count] = control;
4570 return graph()->NewNode(phi_op, count + 1, buffer, true);
4571}
4572
4573
4574Node* BytecodeGraphBuilder::MergeControl(Node* control, Node* other) {
4575 int inputs = control->op()->ControlInputCount() + 1;
4576 if (control->opcode() == IrOpcode::kLoop) {
4577 // Control node for loop exists, add input.
4578 const Operator* op = common()->Loop(inputs);
4579 control->AppendInput(graph_zone(), other);
4580 NodeProperties::ChangeOp(control, op);
4581 } else if (control->opcode() == IrOpcode::kMerge) {
4582 // Control node for merge exists, add input.
4583 const Operator* op = common()->Merge(inputs);
4584 control->AppendInput(graph_zone(), other);
4585 NodeProperties::ChangeOp(control, op);
4586 } else {
4587 // Control node is a singleton, introduce a merge.
4588 const Operator* op = common()->Merge(inputs);
4589 Node* merge_inputs[] = {control, other};
4590 control = graph()->NewNode(op, arraysize(merge_inputs), merge_inputs, true);
4591 }
4592 return control;
4593}
4594
4595Node* BytecodeGraphBuilder::MergeEffect(Node* value, Node* other,
4596 Node* control) {
4597 int inputs = control->op()->ControlInputCount();
4598 if (value->opcode() == IrOpcode::kEffectPhi &&
4599 NodeProperties::GetControlInput(value) == control) {
4600 // Phi already exists, add input.
4601 value->InsertInput(graph_zone(), inputs - 1, other);
4602 NodeProperties::ChangeOp(value, common()->EffectPhi(inputs));
4603 } else if (value != other) {
4604 // Phi does not exist yet, introduce one.
4605 value = NewEffectPhi(inputs, value, control);
4606 value->ReplaceInput(inputs - 1, other);
4607 }
4608 return value;
4609}
4610
4611Node* BytecodeGraphBuilder::MergeValue(Node* value, Node* other,
4612 Node* control) {
4613 int inputs = control->op()->ControlInputCount();
4614 if (value->opcode() == IrOpcode::kPhi &&
4615 NodeProperties::GetControlInput(value) == control) {
4616 // Phi already exists, add input.
4617 value->InsertInput(graph_zone(), inputs - 1, other);
4618 NodeProperties::ChangeOp(
4619 value, common()->Phi(MachineRepresentation::kTagged, inputs));
4620 } else if (value != other) {
4621 // Phi does not exist yet, introduce one.
4622 value = NewPhi(inputs, value, control);
4623 value->ReplaceInput(inputs - 1, other);
4624 }
4625 return value;
4626}
4627
4628void BytecodeGraphBuilder::UpdateSourceAndBytecodePosition(int offset) {
4629 if (node_origins_) {
4630 node_origins_->SetCurrentBytecodePosition(offset);
4631 }
4632 if (source_position_iterator().done()) return;
4633 if (source_position_iterator().code_offset() == offset) {
4634 source_positions_->SetCurrentPosition(SourcePosition(
4635 source_position_iterator().source_position().ScriptOffset(),
4636 start_position_.InliningId()));
4637 source_position_iterator().Advance();
4638 } else {
4639 DCHECK_GT(source_position_iterator().code_offset(), offset);
4640 }
4641}
4642
4644 JSHeapBroker* broker, Zone* local_zone, SharedFunctionInfoRef shared_info,
4645 BytecodeArrayRef bytecode, FeedbackCellRef feedback_cell,
4646 BytecodeOffset osr_offset, JSGraph* jsgraph,
4647 CallFrequency const& invocation_frequency,
4649 int inlining_id, CodeKind code_kind, BytecodeGraphBuilderFlags flags,
4650 TickCounter* tick_counter, ObserveNodeInfo const& observe_node_info) {
4651 BytecodeGraphBuilder builder(
4652 broker, local_zone, broker->target_native_context(), shared_info,
4653 bytecode, feedback_cell, osr_offset, jsgraph, invocation_frequency,
4654 source_positions, node_origins, inlining_id, code_kind, flags,
4655 tick_counter, observe_node_info);
4656 builder.CreateGraph();
4657}
4658
4659} // namespace compiler
4660} // namespace internal
4661} // namespace v8
TFGraph * graph
JSGraph * jsgraph
SimplifiedOperatorBuilder * simplified
#define SHORT_STAR_VISITOR(Name,...)
#define BYTECODE_CASE(name,...)
#define DEBUG_BREAK(Name,...)
int16_t parameter_count
Definition builtins.cc:67
#define BUILTIN_CODE(isolate, name)
Definition builtins.h:45
#define DECLARE_VISIT_BYTECODE(name,...)
#define SHORT_STAR_BYTECODE_LIST(V)
Definition bytecodes.h:24
#define DEBUG_BREAK_BYTECODE_LIST(V)
Definition bytecodes.h:502
#define BYTECODE_LIST(V, V_TSA)
Definition bytecodes.h:479
static constexpr T decode(U value)
Definition bit-field.h:66
constexpr int ToInt() const
Definition utils.h:673
static FeedbackSlot ToSlot(intptr_t index)
static constexpr int kHeaderSize
static const int kGeneratorExecuting
static bool IsNonReturning(FunctionId id)
Definition runtime.cc:146
std::reverse_iterator< const T * > const_reverse_iterator
void resize(size_t new_size)
const_reverse_iterator crbegin() const V8_NOEXCEPT
const_reverse_iterator crend() const V8_NOEXCEPT
void push_back(const T &value)
T * New(Args &&... args)
Definition zone.h:114
const BytecodeLivenessState * GetInLivenessFor(int offset) const
void BindRegister(interpreter::Register the_register, Node *node, FrameStateAttachmentMode mode=kDontAttachFrameState)
void RecordAfterState(Node *node, FrameStateAttachmentMode mode=kDontAttachFrameState)
bool StateValuesRequireUpdate(Node **state_values, Node **values, int count)
void PrepareForLoop(const BytecodeLoopAssignments &assignments, const BytecodeLivenessState *liveness)
void BindAccumulator(Node *node, FrameStateAttachmentMode mode=kDontAttachFrameState)
void BindRegistersToProjections(interpreter::Register first_reg, Node *node, FrameStateAttachmentMode mode=kDontAttachFrameState)
int RegisterToValuesIndex(interpreter::Register the_register) const
void UpdateStateValues(Node **state_values, Node **values, int count)
void Merge(Environment *other, const BytecodeLivenessState *liveness)
void PrepareForLoopExit(Node *loop, const BytecodeLoopAssignments &assignments, const BytecodeLivenessState *liveness)
Node * GetStateValuesFromCache(Node **values, int count, const BytecodeLivenessState *liveness)
Environment(BytecodeGraphBuilder *builder, int register_count, int parameter_count, interpreter::Register incoming_new_target_or_generator, Node *control_dependency)
Node * LookupRegister(interpreter::Register the_register) const
Node * Checkpoint(BytecodeOffset bytecode_offset, OutputFrameStateCombine combine, const BytecodeLivenessState *liveness)
interpreter::BytecodeArrayIterator const & bytecode_iterator() const
void BuildLdaLookupContextSlot(ContextKind context_kind, TypeofMode typeof_mode)
void BuildLoopExitsUntilLoop(int loop_offset, const BytecodeLivenessState *liveness)
Node * NewPhi(int count, Node *input, Node *control)
JSTypeHintLowering::LoweringResult TryBuildSimplifiedStoreKeyed(const Operator *op, Node *receiver, Node *key, Node *value, FeedbackSlot slot)
void BuildLoopExitsForFunctionExit(const BytecodeLivenessState *liveness)
BytecodeGraphBuilder(JSHeapBroker *broker, Zone *local_zone, NativeContextRef native_context, SharedFunctionInfoRef shared_info, BytecodeArrayRef bytecode, FeedbackCellRef feedback_cell, BytecodeOffset osr_offset, JSGraph *jsgraph, CallFrequency const &invocation_frequency, SourcePositionTable *source_positions, NodeOriginTable *node_origins, int inlining_id, CodeKind code_kind, BytecodeGraphBuilderFlags flags, TickCounter *tick_counter, ObserveNodeInfo const &observe_node_info)
Node * MergeEffect(Node *effect, Node *other_effect, Node *control)
void PrepareFrameState(Node *node, OutputFrameStateCombine combine)
void BuildSwitchOnGeneratorState(const ZoneVector< ResumeJumpTarget > &resume_jump_targets, bool allow_fallthrough_on_executing)
JSTypeHintLowering::LoweringResult TryBuildSimplifiedToNumber(Node *input, FeedbackSlot slot)
JSTypeHintLowering::LoweringResult TryBuildSimplifiedStoreNamed(const Operator *op, Node *receiver, Node *value, FeedbackSlot slot)
void BuildHoleCheckAndThrow(Node *condition, Runtime::FunctionId runtime_id, Node *name=nullptr)
Node *const * GetCallArgumentsFromRegisters(Node *callee, Node *receiver, interpreter::Register first_arg, int arg_count)
Node * MakeNode(const Operator *op, int value_input_count, Node *const *value_inputs, bool incomplete=false)
void BuildCall(ConvertReceiverMode receiver_mode, std::initializer_list< Node * > args, int slot_id)
JSTypeHintLowering::LoweringResult TryBuildSimplifiedConstruct(const Operator *op, Node *const *args, int arg_count, FeedbackSlot slot)
JSTypeHintLowering::LoweringResult TryBuildSimplifiedUnaryOp(const Operator *op, Node *operand, FeedbackSlot slot)
SpeculationMode GetSpeculationMode(int slot_id) const
Node * NewBranch(Node *condition, BranchHint hint=BranchHint::kNone)
void BuildCall(ConvertReceiverMode receiver_mode, Node *const *args, size_t arg_count, int slot_id)
BytecodeGraphBuilder(const BytecodeGraphBuilder &)=delete
ZoneMap< int, Environment * > generator_merge_environments_
Node * NewSwitch(Node *condition, int control_output_count)
JSTypeHintLowering::LoweringResult TryBuildSimplifiedForInNext(Node *receiver, Node *cache_array, Node *cache_type, Node *index, FeedbackSlot slot)
const FrameStateFunctionInfo * frame_state_function_info() const
JSTypeHintLowering::LoweringResult TryBuildSimplifiedForInPrepare(Node *receiver, FeedbackSlot slot)
const JSTypeHintLowering & type_hint_lowering() const
SimplifiedOperatorBuilder * simplified() const
interpreter::BytecodeArrayIterator bytecode_iterator_
JSTypeHintLowering::LoweringResult TryBuildSimplifiedLoadNamed(const Operator *op, FeedbackSlot slot)
BytecodeGraphBuilder & operator=(const BytecodeGraphBuilder &)=delete
SourcePositionTableIterator & source_position_iterator()
void PrepareFrameState(Node *node, OutputFrameStateCombine combine, BytecodeOffset bailout_id, const BytecodeLivenessState *liveness)
Node * NewNode(const Operator *op, Node *n0, Args... nodes)
Node * NewNode(const Operator *op, bool incomplete=false)
void BuildReturn(const BytecodeLivenessState *liveness)
JSTypeHintLowering::LoweringResult TryBuildSimplifiedCall(const Operator *op, Node *const *args, int arg_count, FeedbackSlot slot)
Node * MergeValue(Node *value, Node *other_value, Node *control)
void ApplyEarlyReduction(JSTypeHintLowering::LoweringResult reduction)
Node * GetParameter(int index, const char *debug_name_hint=nullptr)
Environment * CheckContextExtensionsSlowPath(uint32_t depth)
JSTypeHintLowering::LoweringResult TryBuildSimplifiedBinaryOp(const Operator *op, Node *left, Node *right, FeedbackSlot slot)
ref_traits< T >::ref_type MakeRefForConstantForIndexOperand(int operand_index)
CallFeedbackRelation ComputeCallFeedbackRelation(int slot_id) const
void BuildCallVarArgs(ConvertReceiverMode receiver_mode)
Node * BuildLoadGlobal(NameRef name, uint32_t feedback_slot_index, TypeofMode typeof_mode)
CallFrequency ComputeCallFrequency(int slot_id) const
Node * ProcessCallRuntimeArguments(const Operator *call_runtime_op, interpreter::Register receiver, size_t reg_count)
interpreter::BytecodeArrayIterator & bytecode_iterator()
const FrameStateFunctionInfo *const frame_state_function_info_
Node *const * ProcessCallVarArgs(ConvertReceiverMode receiver_mode, Node *callee, interpreter::Register first_reg, int arg_count)
Node * NewEffectPhi(int count, Node *input, Node *control)
JSTypeHintLowering::LoweringResult TryBuildSimplifiedGetIterator(const Operator *op, Node *receiver, FeedbackSlot load_slot, FeedbackSlot call_slot)
Node *const * GetConstructArgumentsFromRegister(Node *target, Node *new_target, interpreter::Register first_arg, int arg_count)
JSTypeHintLowering::LoweringResult TryBuildSimplifiedLoadKeyed(const Operator *op, Node *receiver, Node *key, FeedbackSlot slot)
Environment * CheckContextExtensionAtDepth(Environment *slow_environment, uint32_t depth)
CallFeedbackContent call_feedback_content() const
const Operator * StateValues(int arguments, SparseInputMask bitmask)
const Operator * FrameState(BytecodeOffset bailout_id, OutputFrameStateCombine state_combine, const FrameStateFunctionInfo *function_info)
JSOperatorBuilder * javascript() const
Definition js-graph.h:104
SimplifiedOperatorBuilder * simplified() const
Definition js-graph.h:105
Isolate * isolate() const
Definition js-graph.h:106
Node * ConstantNoHole(ObjectRef ref, JSHeapBroker *broker)
Definition js-graph.cc:51
static constexpr int GetJSCallNewTargetParamIndex(int parameter_count)
Definition linkage.h:477
static constexpr int GetJSCallContextParamIndex(int parameter_count)
Definition linkage.h:495
static constexpr int kJSCallClosureParamIndex
Definition linkage.h:504
static const int kOsrContextSpillSlotIndex
Definition linkage.h:508
static const int kOsrAccumulatorRegisterIndex
Definition linkage.h:511
CommonOperatorBuilder * common() const
static Node * GetEffectInput(Node *node, int index=0)
static void ReplaceContextInput(Node *node, Node *context)
static Node * GetFrameStateInput(Node *node)
static void ReplaceFrameStateInput(Node *node, Node *frame_state)
constexpr IrOpcode::Value opcode() const
Definition node.h:52
const Operator * op() const
Definition node.h:50
void AppendInput(Zone *zone, Node *new_to)
Definition node.cc:154
static bool HasFrameStateInput(const Operator *op)
static int GetFrameStateInputCount(const Operator *op)
constexpr Opcode opcode() const
Definition operator.h:75
static OutputFrameStateCombine PokeAt(size_t index)
static OutputFrameStateCombine Ignore()
ScopeInfoRef OuterScopeInfo(JSHeapBroker *broker) const
static constexpr int OutputArityForFormalParameterCount(int argc)
Node * NewNode(const Operator *op, int input_count, Node *const *inputs, bool incomplete=false)
static ConvertReceiverMode GetReceiverMode(Bytecode bytecode)
Definition bytecodes.h:980
constexpr bool is_current_context() const
constexpr bool is_function_closure() const
static LiteralFlag Decode(uint8_t raw_flag)
CppGraphBuilderImpl & graph_builder_
int start
uint32_t count
int end
Handle< Context > context_
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
DirectHandle< Object > new_target
Definition execution.cc:75
Isolate * isolate
Zone * graph_zone
SourcePositionTable * source_positions
JSHeapBroker * broker
int32_t offset
TNode< Object > target
TNode< Object > receiver
Node * node
ZoneVector< RpoNumber > & result
LiftoffRegister reg
ArgType first_arg
FunctionLiteral * literal
Definition liveedit.cc:294
InstructionOperand source
int int32_t
Definition unicode.cc:40
T Divide(T x, T y)
void Add(RWDigits Z, Digits X, Digits Y)
bool GreaterThanOrEqual(Digits A, Digits B)
void Subtract(RWDigits Z, Digits X, Digits Y)
std::function< Node *(int, GraphAssemblerLabel< 0 > *)> GetParameter
TNode< Oddball > UndefinedConstant(JSGraph *jsgraph)
int ParameterIndexOf(const Operator *const op)
FloatMatcher< double, IrOpcode::kNumberConstant > NumberMatcher
ScopeInfoRef ScopeInfoOf(const Operator *op)
ref_traits< T >::ref_type MakeRefAssumeMemoryFence(JSHeapBroker *broker, Tagged< T > object)
CreateFunctionContextParameters const & CreateFunctionContextParametersOf(Operator const *op)
void BuildGraphFromBytecode(JSHeapBroker *broker, Zone *local_zone, SharedFunctionInfoRef shared_info, BytecodeArrayRef bytecode, FeedbackCellRef feedback_cell, BytecodeOffset osr_offset, JSGraph *jsgraph, CallFrequency const &invocation_frequency, SourcePositionTable *source_positions, NodeOriginTable *node_origins, int inlining_id, CodeKind code_kind, BytecodeGraphBuilderFlags flags, TickCounter *tick_counter, ObserveNodeInfo const &observe_node_info)
ref_traits< T >::ref_type MakeRef(JSHeapBroker *broker, Tagged< T > object)
T * MakeNode(Args... args)
Definition ast.h:1286
constexpr int kFunctionEntryBytecodeOffset
Definition globals.h:854
constexpr const char * ToString(DeoptimizeKind kind)
Definition globals.h:880
bool IsNone(Tagged< FieldType > obj)
Definition field-type.h:50
bool is_sloppy(LanguageMode language_mode)
Definition globals.h:773
bool Is(IndirectHandle< U > value)
Definition handles-inl.h:51
LanguageMode GetLanguageModeFromSlotKind(FeedbackSlotKind kind)
int ToNumber(Register reg)
constexpr int kSystemPointerSize
Definition globals.h:410
void Terminate(Isolate *isolate)
Definition bigint.cc:1187
bool is_strict(LanguageMode language_mode)
Definition globals.h:777
const int kHeapObjectTag
Definition v8-internal.h:72
V8_EXPORT_PRIVATE FlagValues v8_flags
return value
Definition map-inl.h:893
bool IsLoadGlobalICKind(FeedbackSlotKind kind)
void MemsetPointer(FullObjectSlot start, Tagged< Object > value, size_t counter)
Definition slots-inl.h:507
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
RegExpBuilder builder_
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_NULL(val)
Definition logging.h:491
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define arraysize(array)
Definition macros.h:67
IteratorsStates(int exception_handler_index, SourcePositionTableIterator::IndexAndPositionState source_iterator_state)
const ZoneVector< ResumeJumpTarget > & resume_jump_targets() const
BytecodeLoopAssignments & assignments()