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 BuildVariableLoad(Variable* variable, HoleCheckMode hole_check_mode,
124                          TypeofMode typeof_mode = NOT_INSIDE_TYPEOF);
125   void BuildVariableLoadForAccumulatorValue(
126       Variable* variable, HoleCheckMode hole_check_mode,
127       TypeofMode typeof_mode = NOT_INSIDE_TYPEOF);
128   void BuildVariableAssignment(
129       Variable* variable, Token::Value op, HoleCheckMode hole_check_mode,
130       LookupHoistingMode lookup_hoisting_mode = LookupHoistingMode::kNormal);
131   void BuildLiteralCompareNil(Token::Value compare_op,
132                               BytecodeArrayBuilder::NilValue nil);
133   void BuildReturn(int source_position = kNoSourcePosition);
134   void BuildAsyncReturn(int source_position = kNoSourcePosition);
135   void BuildAsyncGeneratorReturn();
136   void BuildReThrow();
137   void BuildHoleCheckForVariableAssignment(Variable* variable, Token::Value op);
138   void BuildThrowIfHole(Variable* variable);
139 
140   // Build jump to targets[value], where
141   // start_index <= value < start_index + size.
142   void BuildIndexedJump(Register value, size_t start_index, size_t size,
143                         ZoneVector<BytecodeLabel>& targets);
144 
145   void BuildNewLocalActivationContext();
146   void BuildLocalActivationContextInitialization();
147   void BuildNewLocalBlockContext(Scope* scope);
148   void BuildNewLocalCatchContext(Scope* scope);
149   void BuildNewLocalWithContext(Scope* scope);
150 
151   void BuildGeneratorPrologue();
152   void BuildSuspendPoint(Expression* suspend_expr);
153 
154   void BuildAwait(Expression* await_expr);
155 
156   void BuildGetIterator(Expression* iterable, IteratorType hint);
157 
158   // Create an IteratorRecord with pre-allocated registers holding the next
159   // method and iterator object.
160   IteratorRecord BuildGetIteratorRecord(Expression* iterable,
161                                         Register iterator_next,
162                                         Register iterator_object,
163                                         IteratorType hint);
164 
165   // Create an IteratorRecord allocating new registers to hold the next method
166   // and iterator object.
167   IteratorRecord BuildGetIteratorRecord(Expression* iterable,
168                                         IteratorType hint);
169   void BuildIteratorNext(const IteratorRecord& iterator, Register next_result);
170   void BuildIteratorClose(const IteratorRecord& iterator,
171                           Expression* expr = nullptr);
172   void BuildCallIteratorMethod(Register iterator, const AstRawString* method,
173                                RegisterList receiver_and_args,
174                                BytecodeLabel* if_called,
175                                BytecodeLabels* if_notcalled);
176 
177   void BuildArrayLiteralSpread(Spread* spread, Register array, Register index,
178                                FeedbackSlot index_slot,
179                                FeedbackSlot element_slot);
180   void BuildArrayLiteralElementsInsertion(Register array,
181                                           int first_spread_index,
182                                           ZonePtrList<Expression>* elements,
183                                           bool skip_constants);
184 
185   void AllocateTopLevelRegisters();
186   void VisitArgumentsObject(Variable* variable);
187   void VisitRestArgumentsArray(Variable* rest);
188   void VisitCallSuper(Call* call);
189   void BuildClassLiteral(ClassLiteral* expr);
190   void VisitNewTargetVariable(Variable* variable);
191   void VisitThisFunctionVariable(Variable* variable);
192   void BuildInstanceFieldInitialization(Register constructor,
193                                         Register instance);
194   void BuildGeneratorObjectVariableInitialization();
195   void VisitBlockDeclarationsAndStatements(Block* stmt);
196   void VisitSetHomeObject(Register value, Register home_object,
197                           LiteralProperty* property);
198   void VisitObjectLiteralAccessor(Register home_object,
199                                   ObjectLiteralProperty* property,
200                                   Register value_out);
201   void VisitForInAssignment(Expression* expr);
202   void VisitModuleNamespaceImports();
203 
204   // Visit a logical OR/AND within a test context, rewiring the jumps based
205   // on the expression values.
206   void VisitLogicalTest(Token::Value token, Expression* left, Expression* right,
207                         int right_coverage_slot);
208   void VisitNaryLogicalTest(Token::Value token, NaryOperation* expr,
209                             const NaryCodeCoverageSlots* coverage_slots);
210   // Visit a (non-RHS) test for a logical op, which falls through if the test
211   // fails or jumps to the appropriate labels if it succeeds.
212   void VisitLogicalTestSubExpression(Token::Value token, Expression* expr,
213                                      BytecodeLabels* then_labels,
214                                      BytecodeLabels* else_labels,
215                                      int coverage_slot);
216 
217   // Helpers for binary and nary logical op value expressions.
218   bool VisitLogicalOrSubExpression(Expression* expr, BytecodeLabels* end_labels,
219                                    int coverage_slot);
220   bool VisitLogicalAndSubExpression(Expression* expr,
221                                     BytecodeLabels* end_labels,
222                                     int coverage_slot);
223 
224   // Visit the body of a loop iteration.
225   void VisitIterationBody(IterationStatement* stmt, LoopBuilder* loop_builder);
226 
227   // Visit a statement and switch scopes, the context is in the accumulator.
228   void VisitInScope(Statement* stmt, Scope* scope);
229 
230   void BuildPushUndefinedIntoRegisterList(RegisterList* reg_list);
231 
232   void BuildLoadPropertyKey(LiteralProperty* property, Register out_reg);
233 
234   int AllocateBlockCoverageSlotIfEnabled(AstNode* node, SourceRangeKind kind);
235   int AllocateNaryBlockCoverageSlotIfEnabled(NaryOperation* node, size_t index);
236 
237   void BuildIncrementBlockCoverageCounterIfEnabled(AstNode* node,
238                                                    SourceRangeKind kind);
239   void BuildIncrementBlockCoverageCounterIfEnabled(int coverage_array_slot);
240 
241   void BuildTest(ToBooleanMode mode, BytecodeLabels* then_labels,
242                  BytecodeLabels* else_labels, TestFallthrough fallthrough);
243 
244   // Visitors for obtaining expression result in the accumulator, in a
245   // register, or just getting the effect. Some visitors return a TypeHint which
246   // specifies the type of the result of the visited expression.
247   TypeHint VisitForAccumulatorValue(Expression* expr);
248   void VisitForAccumulatorValueOrTheHole(Expression* expr);
249   V8_WARN_UNUSED_RESULT Register VisitForRegisterValue(Expression* expr);
250   INLINE(void VisitForRegisterValue(Expression* expr, Register destination));
251   void VisitAndPushIntoRegisterList(Expression* expr, RegisterList* reg_list);
252   void VisitForEffect(Expression* expr);
253   void VisitForTest(Expression* expr, BytecodeLabels* then_labels,
254                     BytecodeLabels* else_labels, TestFallthrough fallthrough);
255 
256   void VisitInSameTestExecutionScope(Expression* expr);
257 
258   Register GetRegisterForLocalVariable(Variable* variable);
259 
260   // Returns the runtime function id for a store to super for the function's
261   // language mode.
262   inline Runtime::FunctionId StoreToSuperRuntimeId();
263   inline Runtime::FunctionId StoreKeyedToSuperRuntimeId();
264 
265   // Returns a cached slot, or create and cache a new slot if one doesn't
266   // already exists.
267   FeedbackSlot GetCachedLoadGlobalICSlot(TypeofMode typeof_mode,
268                                          Variable* variable);
269   FeedbackSlot GetCachedStoreGlobalICSlot(LanguageMode language_mode,
270                                           Variable* variable);
271   FeedbackSlot GetCachedCreateClosureSlot(FunctionLiteral* literal);
272   FeedbackSlot GetCachedLoadICSlot(const Expression* expr,
273                                    const AstRawString* name);
274   FeedbackSlot GetCachedStoreICSlot(const Expression* expr,
275                                     const AstRawString* name);
276   FeedbackSlot GetDummyCompareICSlot();
277 
278   void AddToEagerLiteralsIfEager(FunctionLiteral* literal);
279 
ToBooleanModeFromTypeHint(TypeHint type_hint)280   static constexpr ToBooleanMode ToBooleanModeFromTypeHint(TypeHint type_hint) {
281     return type_hint == TypeHint::kBoolean ? ToBooleanMode::kAlreadyBoolean
282                                            : ToBooleanMode::kConvertToBoolean;
283   }
284 
285   inline Register generator_object() const;
286 
builder()287   inline BytecodeArrayBuilder* builder() { return &builder_; }
zone()288   inline Zone* zone() const { return zone_; }
closure_scope()289   inline DeclarationScope* closure_scope() const { return closure_scope_; }
info()290   inline UnoptimizedCompilationInfo* info() const { return info_; }
ast_string_constants()291   inline const AstStringConstants* ast_string_constants() const {
292     return ast_string_constants_;
293   }
294 
current_scope()295   inline Scope* current_scope() const { return current_scope_; }
set_current_scope(Scope * scope)296   inline void set_current_scope(Scope* scope) { current_scope_ = scope; }
297 
execution_control()298   inline ControlScope* execution_control() const { return execution_control_; }
set_execution_control(ControlScope * scope)299   inline void set_execution_control(ControlScope* scope) {
300     execution_control_ = scope;
301   }
execution_context()302   inline ContextScope* execution_context() const { return execution_context_; }
set_execution_context(ContextScope * context)303   inline void set_execution_context(ContextScope* context) {
304     execution_context_ = context;
305   }
set_execution_result(ExpressionResultScope * execution_result)306   inline void set_execution_result(ExpressionResultScope* execution_result) {
307     execution_result_ = execution_result;
308   }
execution_result()309   ExpressionResultScope* execution_result() const { return execution_result_; }
register_allocator()310   BytecodeRegisterAllocator* register_allocator() {
311     return builder()->register_allocator();
312   }
313 
globals_builder()314   GlobalDeclarationsBuilder* globals_builder() {
315     DCHECK_NOT_NULL(globals_builder_);
316     return globals_builder_;
317   }
318   inline LanguageMode language_mode() const;
319   inline FunctionKind function_kind() const;
320   inline FeedbackVectorSpec* feedback_spec();
321   inline int feedback_index(FeedbackSlot slot) const;
322 
feedback_slot_cache()323   inline FeedbackSlotCache* feedback_slot_cache() {
324     return feedback_slot_cache_;
325   }
326 
catch_prediction()327   inline HandlerTable::CatchPrediction catch_prediction() const {
328     return catch_prediction_;
329   }
set_catch_prediction(HandlerTable::CatchPrediction value)330   inline void set_catch_prediction(HandlerTable::CatchPrediction value) {
331     catch_prediction_ = value;
332   }
333 
334   Zone* zone_;
335   BytecodeArrayBuilder builder_;
336   UnoptimizedCompilationInfo* info_;
337   const AstStringConstants* ast_string_constants_;
338   DeclarationScope* closure_scope_;
339   Scope* current_scope_;
340 
341   // External vector of literals to be eagerly compiled.
342   ZoneVector<FunctionLiteral*>* eager_inner_literals_;
343 
344   FeedbackSlotCache* feedback_slot_cache_;
345 
346   GlobalDeclarationsBuilder* globals_builder_;
347   BlockCoverageBuilder* block_coverage_builder_;
348   ZoneVector<GlobalDeclarationsBuilder*> global_declarations_;
349   ZoneVector<std::pair<FunctionLiteral*, size_t>> function_literals_;
350   ZoneVector<std::pair<NativeFunctionLiteral*, size_t>>
351       native_function_literals_;
352   ZoneVector<std::pair<ObjectLiteral*, size_t>> object_literals_;
353   ZoneVector<std::pair<ArrayLiteral*, size_t>> array_literals_;
354   ZoneVector<std::pair<ClassLiteral*, size_t>> class_literals_;
355   ZoneVector<std::pair<GetTemplateObject*, size_t>> template_objects_;
356 
357   ControlScope* execution_control_;
358   ContextScope* execution_context_;
359   ExpressionResultScope* execution_result_;
360 
361   Register incoming_new_target_or_generator_;
362 
363   // Dummy feedback slot for compare operations, where we don't care about
364   // feedback
365   FeedbackSlot dummy_feedback_slot_;
366 
367   BytecodeJumpTable* generator_jump_table_;
368   int suspend_count_;
369   int loop_depth_;
370 
371   HandlerTable::CatchPrediction catch_prediction_;
372 };
373 
374 }  // namespace interpreter
375 }  // namespace internal
376 }  // namespace v8
377 
378 #endif  // V8_INTERPRETER_BYTECODE_GENERATOR_H_
379