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