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