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