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