V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
bytecode-generator.h
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 #ifndef V8_INTERPRETER_BYTECODE_GENERATOR_H_
6 #define V8_INTERPRETER_BYTECODE_GENERATOR_H_
7 
8 #include "src/ast/ast.h"
9 #include "src/feedback-vector.h"
10 #include "src/interpreter/bytecode-array-builder.h"
11 #include "src/interpreter/bytecode-label.h"
12 #include "src/interpreter/bytecode-register.h"
13 #include "src/interpreter/bytecodes.h"
14 
15 namespace v8 {
16 namespace internal {
17 
18 class AstNodeSourceRanges;
19 class AstStringConstants;
20 class UnoptimizedCompilationInfo;
21 enum class SourceRangeKind;
22 
23 namespace interpreter {
24 
25 class GlobalDeclarationsBuilder;
26 class LoopBuilder;
27 class BlockCoverageBuilder;
28 class BytecodeJumpTable;
29 
30 class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
31  public:
32  explicit BytecodeGenerator(
34  const AstStringConstants* ast_string_constants,
35  std::vector<FunctionLiteral*>* eager_inner_literals);
36 
37  void GenerateBytecode(uintptr_t stack_limit);
38  Handle<BytecodeArray> FinalizeBytecode(Isolate* isolate,
39  Handle<Script> script);
40 
41 #define DECLARE_VISIT(type) void Visit##type(type* node);
42  AST_NODE_LIST(DECLARE_VISIT)
43 #undef DECLARE_VISIT
44 
45  // Visiting function for declarations list and statements are overridden.
46  void VisitDeclarations(Declaration::List* declarations);
47  void VisitStatements(const ZonePtrList<Statement>* statments);
48 
49  private:
50  class ContextScope;
51  class ControlScope;
57  class CurrentScope;
59  class EffectResultScope;
60  class FeedbackSlotCache;
62  class IteratorRecord;
65  class TestResultScope;
66  class ValueResultScope;
67 
68  using ToBooleanMode = BytecodeArrayBuilder::ToBooleanMode;
69 
70  enum class TestFallthrough { kThen, kElse, kNone };
71  enum class TypeHint { kAny, kBoolean, kString };
72 
73  void GenerateBytecodeBody();
74  void AllocateDeferredConstants(Isolate* isolate, Handle<Script> script);
75 
76  DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
77 
78  // Dispatched from VisitBinaryOperation.
79  void VisitArithmeticExpression(BinaryOperation* binop);
80  void VisitCommaExpression(BinaryOperation* binop);
81  void VisitLogicalOrExpression(BinaryOperation* binop);
82  void VisitLogicalAndExpression(BinaryOperation* binop);
83 
84  // Dispatched from VisitNaryOperation.
85  void VisitNaryArithmeticExpression(NaryOperation* expr);
86  void VisitNaryCommaExpression(NaryOperation* expr);
87  void VisitNaryLogicalOrExpression(NaryOperation* expr);
88  void VisitNaryLogicalAndExpression(NaryOperation* expr);
89 
90  // Dispatched from VisitUnaryOperation.
91  void VisitVoid(UnaryOperation* expr);
92  void VisitTypeOf(UnaryOperation* expr);
93  void VisitNot(UnaryOperation* expr);
94  void VisitDelete(UnaryOperation* expr);
95 
96  // Visits a typeof expression for the value on which to perform the typeof.
97  void VisitForTypeOfValue(Expression* expr);
98 
99  // Used by flow control routines to evaluate loop condition.
100  void VisitCondition(Expression* expr);
101 
102  // Visit the arguments expressions in |args| and store them in |args_regs|,
103  // growing |args_regs| for each argument visited.
104  void VisitArguments(const ZonePtrList<Expression>* args,
105  RegisterList* arg_regs);
106 
107  // Visit a keyed super property load. The optional
108  // |opt_receiver_out| register will have the receiver stored to it
109  // if it's a valid register. The loaded value is placed in the
110  // accumulator.
111  void VisitKeyedSuperPropertyLoad(Property* property,
112  Register opt_receiver_out);
113 
114  // Visit a named super property load. The optional
115  // |opt_receiver_out| register will have the receiver stored to it
116  // if it's a valid register. The loaded value is placed in the
117  // accumulator.
118  void VisitNamedSuperPropertyLoad(Property* property,
119  Register opt_receiver_out);
120 
121  void VisitPropertyLoad(Register obj, Property* expr);
122  void VisitPropertyLoadForRegister(Register obj, Property* expr,
123  Register destination);
124 
125  void BuildLoadNamedProperty(Property* property, Register object,
126  const AstRawString* name);
127  void BuildStoreNamedProperty(Property* property, Register object,
128  const AstRawString* name);
129 
130  void BuildVariableLoad(Variable* variable, HoleCheckMode hole_check_mode,
131  TypeofMode typeof_mode = NOT_INSIDE_TYPEOF);
132  void BuildVariableLoadForAccumulatorValue(
133  Variable* variable, HoleCheckMode hole_check_mode,
134  TypeofMode typeof_mode = NOT_INSIDE_TYPEOF);
135  void BuildVariableAssignment(
136  Variable* variable, Token::Value op, HoleCheckMode hole_check_mode,
137  LookupHoistingMode lookup_hoisting_mode = LookupHoistingMode::kNormal);
138  void BuildLiteralCompareNil(Token::Value compare_op,
139  BytecodeArrayBuilder::NilValue nil);
140  void BuildReturn(int source_position = kNoSourcePosition);
141  void BuildAsyncReturn(int source_position = kNoSourcePosition);
142  void BuildAsyncGeneratorReturn();
143  void BuildReThrow();
144  void BuildHoleCheckForVariableAssignment(Variable* variable, Token::Value op);
145  void BuildThrowIfHole(Variable* variable);
146 
147  // Build jump to targets[value], where
148  // start_index <= value < start_index + size.
149  void BuildIndexedJump(Register value, size_t start_index, size_t size,
150  ZoneVector<BytecodeLabel>& targets);
151 
152  void BuildNewLocalActivationContext();
153  void BuildLocalActivationContextInitialization();
154  void BuildNewLocalBlockContext(Scope* scope);
155  void BuildNewLocalCatchContext(Scope* scope);
156  void BuildNewLocalWithContext(Scope* scope);
157 
158  void BuildGeneratorPrologue();
159  void BuildSuspendPoint(Expression* suspend_expr);
160 
161  void BuildAwait(Expression* await_expr);
162 
163  void BuildGetIterator(Expression* iterable, IteratorType hint);
164 
165  // Create an IteratorRecord with pre-allocated registers holding the next
166  // method and iterator object.
167  IteratorRecord BuildGetIteratorRecord(Expression* iterable,
168  Register iterator_next,
169  Register iterator_object,
170  IteratorType hint);
171 
172  // Create an IteratorRecord allocating new registers to hold the next method
173  // and iterator object.
174  IteratorRecord BuildGetIteratorRecord(Expression* iterable,
175  IteratorType hint);
176  void BuildIteratorNext(const IteratorRecord& iterator, Register next_result);
177  void BuildIteratorClose(const IteratorRecord& iterator,
178  Expression* expr = nullptr);
179  void BuildCallIteratorMethod(Register iterator, const AstRawString* method,
180  RegisterList receiver_and_args,
181  BytecodeLabel* if_called,
182  BytecodeLabels* if_notcalled);
183 
184  void BuildArrayLiteralSpread(Spread* spread, Register array, Register index,
185  FeedbackSlot index_slot,
186  FeedbackSlot element_slot);
187  // Create Array literals. |expr| can be nullptr, but if provided,
188  // a boilerplate will be used to create an initial array for elements
189  // before the first spread.
190  void BuildCreateArrayLiteral(const ZonePtrList<Expression>* elements,
191  ArrayLiteral* expr);
192  void BuildCreateObjectLiteral(Register literal, uint8_t flags, size_t entry);
193  void AllocateTopLevelRegisters();
194  void VisitArgumentsObject(Variable* variable);
195  void VisitRestArgumentsArray(Variable* rest);
196  void VisitCallSuper(Call* call);
197  void BuildClassLiteral(ClassLiteral* expr, Register name);
198  void VisitClassLiteral(ClassLiteral* expr, Register name);
199  void VisitNewTargetVariable(Variable* variable);
200  void VisitThisFunctionVariable(Variable* variable);
201  void BuildInstanceMemberInitialization(Register constructor,
202  Register instance);
203  void BuildGeneratorObjectVariableInitialization();
204  void VisitBlockDeclarationsAndStatements(Block* stmt);
205  void VisitSetHomeObject(Register value, Register home_object,
206  LiteralProperty* property);
207  void VisitObjectLiteralAccessor(Register home_object,
208  ObjectLiteralProperty* property,
209  Register value_out);
210  void VisitForInAssignment(Expression* expr);
211  void VisitModuleNamespaceImports();
212 
213  // Visit a logical OR/AND within a test context, rewiring the jumps based
214  // on the expression values.
215  void VisitLogicalTest(Token::Value token, Expression* left, Expression* right,
216  int right_coverage_slot);
217  void VisitNaryLogicalTest(Token::Value token, NaryOperation* expr,
218  const NaryCodeCoverageSlots* coverage_slots);
219  // Visit a (non-RHS) test for a logical op, which falls through if the test
220  // fails or jumps to the appropriate labels if it succeeds.
221  void VisitLogicalTestSubExpression(Token::Value token, Expression* expr,
222  BytecodeLabels* then_labels,
223  BytecodeLabels* else_labels,
224  int coverage_slot);
225 
226  // Helpers for binary and nary logical op value expressions.
227  bool VisitLogicalOrSubExpression(Expression* expr, BytecodeLabels* end_labels,
228  int coverage_slot);
229  bool VisitLogicalAndSubExpression(Expression* expr,
230  BytecodeLabels* end_labels,
231  int coverage_slot);
232 
233  // Visit the body of a loop iteration.
234  void VisitIterationBody(IterationStatement* stmt, LoopBuilder* loop_builder);
235 
236  // Visit a statement and switch scopes, the context is in the accumulator.
237  void VisitInScope(Statement* stmt, Scope* scope);
238 
239  void BuildPushUndefinedIntoRegisterList(RegisterList* reg_list);
240 
241  void BuildLoadPropertyKey(LiteralProperty* property, Register out_reg);
242 
243  int AllocateBlockCoverageSlotIfEnabled(AstNode* node, SourceRangeKind kind);
244  int AllocateNaryBlockCoverageSlotIfEnabled(NaryOperation* node, size_t index);
245 
246  void BuildIncrementBlockCoverageCounterIfEnabled(AstNode* node,
247  SourceRangeKind kind);
248  void BuildIncrementBlockCoverageCounterIfEnabled(int coverage_array_slot);
249 
250  void BuildTest(ToBooleanMode mode, BytecodeLabels* then_labels,
251  BytecodeLabels* else_labels, TestFallthrough fallthrough);
252 
253  // Visitors for obtaining expression result in the accumulator, in a
254  // register, or just getting the effect. Some visitors return a TypeHint which
255  // specifies the type of the result of the visited expression.
256  TypeHint VisitForAccumulatorValue(Expression* expr);
257  void VisitForAccumulatorValueOrTheHole(Expression* expr);
258  V8_WARN_UNUSED_RESULT Register VisitForRegisterValue(Expression* expr);
259  V8_INLINE void VisitForRegisterValue(Expression* expr, Register destination);
260  void VisitAndPushIntoRegisterList(Expression* expr, RegisterList* reg_list);
261  void VisitForEffect(Expression* expr);
262  void VisitForTest(Expression* expr, BytecodeLabels* then_labels,
263  BytecodeLabels* else_labels, TestFallthrough fallthrough);
264 
265  void VisitInSameTestExecutionScope(Expression* expr);
266 
267  Register GetRegisterForLocalVariable(Variable* variable);
268 
269  // Returns the runtime function id for a store to super for the function's
270  // language mode.
271  inline Runtime::FunctionId StoreToSuperRuntimeId();
272  inline Runtime::FunctionId StoreKeyedToSuperRuntimeId();
273 
274  // Returns a cached slot, or create and cache a new slot if one doesn't
275  // already exists.
276  FeedbackSlot GetCachedLoadGlobalICSlot(TypeofMode typeof_mode,
277  Variable* variable);
278  FeedbackSlot GetCachedStoreGlobalICSlot(LanguageMode language_mode,
279  Variable* variable);
280  FeedbackSlot GetCachedCreateClosureSlot(FunctionLiteral* literal);
281  FeedbackSlot GetCachedLoadICSlot(const Expression* expr,
282  const AstRawString* name);
283  FeedbackSlot GetCachedStoreICSlot(const Expression* expr,
284  const AstRawString* name);
285  FeedbackSlot GetDummyCompareICSlot();
286 
287  void AddToEagerLiteralsIfEager(FunctionLiteral* literal);
288 
289  // Checks if the visited expression is one shot, i.e executed only once. Any
290  // expression either in a top level code or an IIFE that is not within a loop
291  // is eligible for one shot optimizations.
292  inline bool ShouldOptimizeAsOneShot() const;
293 
294  static constexpr ToBooleanMode ToBooleanModeFromTypeHint(TypeHint type_hint) {
295  return type_hint == TypeHint::kBoolean ? ToBooleanMode::kAlreadyBoolean
296  : ToBooleanMode::kConvertToBoolean;
297  }
298 
299  inline Register generator_object() const;
300 
301  inline BytecodeArrayBuilder* builder() { return &builder_; }
302  inline Zone* zone() const { return zone_; }
303  inline DeclarationScope* closure_scope() const { return closure_scope_; }
304  inline UnoptimizedCompilationInfo* info() const { return info_; }
305  inline const AstStringConstants* ast_string_constants() const {
306  return ast_string_constants_;
307  }
308 
309  inline Scope* current_scope() const { return current_scope_; }
310  inline void set_current_scope(Scope* scope) { current_scope_ = scope; }
311 
312  inline ControlScope* execution_control() const { return execution_control_; }
313  inline void set_execution_control(ControlScope* scope) {
314  execution_control_ = scope;
315  }
316  inline ContextScope* execution_context() const { return execution_context_; }
317  inline void set_execution_context(ContextScope* context) {
318  execution_context_ = context;
319  }
320  inline void set_execution_result(ExpressionResultScope* execution_result) {
321  execution_result_ = execution_result;
322  }
323  ExpressionResultScope* execution_result() const { return execution_result_; }
324  BytecodeRegisterAllocator* register_allocator() {
325  return builder()->register_allocator();
326  }
327 
328  GlobalDeclarationsBuilder* globals_builder() {
329  DCHECK_NOT_NULL(globals_builder_);
330  return globals_builder_;
331  }
332  inline LanguageMode language_mode() const;
333  inline FunctionKind function_kind() const;
334  inline FeedbackVectorSpec* feedback_spec();
335  inline int feedback_index(FeedbackSlot slot) const;
336 
337  inline FeedbackSlotCache* feedback_slot_cache() {
338  return feedback_slot_cache_;
339  }
340 
341  inline HandlerTable::CatchPrediction catch_prediction() const {
342  return catch_prediction_;
343  }
344  inline void set_catch_prediction(HandlerTable::CatchPrediction value) {
345  catch_prediction_ = value;
346  }
347 
348  Zone* zone_;
349  BytecodeArrayBuilder builder_;
351  const AstStringConstants* ast_string_constants_;
352  DeclarationScope* closure_scope_;
353  Scope* current_scope_;
354 
355  // External vector of literals to be eagerly compiled.
356  std::vector<FunctionLiteral*>* eager_inner_literals_;
357 
358  FeedbackSlotCache* feedback_slot_cache_;
359 
360  GlobalDeclarationsBuilder* globals_builder_;
361  BlockCoverageBuilder* block_coverage_builder_;
362  ZoneVector<GlobalDeclarationsBuilder*> global_declarations_;
365  native_function_literals_;
370 
371  ControlScope* execution_control_;
372  ContextScope* execution_context_;
373  ExpressionResultScope* execution_result_;
374 
375  Register incoming_new_target_or_generator_;
376 
377  // Dummy feedback slot for compare operations, where we don't care about
378  // feedback
379  SharedFeedbackSlot dummy_feedback_slot_;
380 
381  BytecodeJumpTable* generator_jump_table_;
382  int suspend_count_;
383  int loop_depth_;
384 
385  HandlerTable::CatchPrediction catch_prediction_;
386 };
387 
388 } // namespace interpreter
389 } // namespace internal
390 } // namespace v8
391 
392 #endif // V8_INTERPRETER_BYTECODE_GENERATOR_H_
Definition: libplatform.h:13