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