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 #include "src/objects/feedback-vector.h" 14 #include "src/objects/function-kind.h" 15 16 namespace v8 { 17 namespace internal { 18 19 class AstNodeSourceRanges; 20 class AstStringConstants; 21 class BytecodeArray; 22 class UnoptimizedCompilationInfo; 23 enum class SourceRangeKind; 24 25 namespace interpreter { 26 27 class TopLevelDeclarationsBuilder; 28 class LoopBuilder; 29 class BlockCoverageBuilder; 30 class BytecodeJumpTable; 31 32 class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { 33 public: 34 explicit BytecodeGenerator( 35 Zone* zone, UnoptimizedCompilationInfo* info, 36 const AstStringConstants* ast_string_constants, 37 std::vector<FunctionLiteral*>* eager_inner_literals); 38 39 void GenerateBytecode(uintptr_t stack_limit); 40 template <typename LocalIsolate> 41 Handle<BytecodeArray> FinalizeBytecode(LocalIsolate* isolate, 42 Handle<Script> script); 43 template <typename LocalIsolate> 44 Handle<ByteArray> FinalizeSourcePositionTable(LocalIsolate* isolate); 45 46 #ifdef DEBUG 47 int CheckBytecodeMatches(BytecodeArray bytecode); 48 #endif 49 50 #define DECLARE_VISIT(type) void Visit##type(type* node); 51 AST_NODE_LIST(DECLARE_VISIT) 52 #undef DECLARE_VISIT 53 54 // Visiting function for declarations list and statements are overridden. 55 void VisitModuleDeclarations(Declaration::List* declarations); 56 void VisitGlobalDeclarations(Declaration::List* declarations); 57 void VisitDeclarations(Declaration::List* declarations); 58 void VisitStatements(const ZonePtrList<Statement>* statments); 59 60 private: 61 class AccumulatorPreservingScope; 62 class ContextScope; 63 class ControlScope; 64 class ControlScopeForBreakable; 65 class ControlScopeForIteration; 66 class ControlScopeForTopLevel; 67 class ControlScopeForTryCatch; 68 class ControlScopeForTryFinally; 69 class CurrentScope; 70 class EffectResultScope; 71 class ExpressionResultScope; 72 class FeedbackSlotCache; 73 class IteratorRecord; 74 class LoopScope; 75 class NaryCodeCoverageSlots; 76 class OptionalChainNullLabelScope; 77 class RegisterAllocationScope; 78 class TestResultScope; 79 class TopLevelDeclarationsBuilder; 80 class ValueResultScope; 81 82 using ToBooleanMode = BytecodeArrayBuilder::ToBooleanMode; 83 84 enum class TestFallthrough { kThen, kElse, kNone }; 85 enum class TypeHint { kAny, kBoolean, kString }; 86 enum class AccumulatorPreservingMode { kNone, kPreserve }; 87 88 // An assignment has to evaluate its LHS before its RHS, but has to assign to 89 // the LHS after both evaluations are done. This class stores the data 90 // computed in the LHS evaulation that has to live across the RHS evaluation, 91 // and is used in the actual LHS assignment. 92 class AssignmentLhsData { 93 public: 94 static AssignmentLhsData NonProperty(Expression* expr); 95 static AssignmentLhsData NamedProperty(Expression* object_expr, 96 Register object, 97 const AstRawString* name); 98 static AssignmentLhsData KeyedProperty(Register object, Register key); 99 static AssignmentLhsData PrivateMethodOrAccessor(AssignType type, 100 Property* property); 101 static AssignmentLhsData NamedSuperProperty( 102 RegisterList super_property_args); 103 static AssignmentLhsData KeyedSuperProperty( 104 RegisterList super_property_args); 105 assign_type()106 AssignType assign_type() const { return assign_type_; } expr()107 Expression* expr() const { 108 DCHECK(assign_type_ == NON_PROPERTY || assign_type_ == PRIVATE_METHOD || 109 assign_type_ == PRIVATE_GETTER_ONLY || 110 assign_type_ == PRIVATE_SETTER_ONLY || 111 assign_type_ == PRIVATE_GETTER_AND_SETTER); 112 return expr_; 113 } object_expr()114 Expression* object_expr() const { 115 DCHECK_EQ(assign_type_, NAMED_PROPERTY); 116 return object_expr_; 117 } object()118 Register object() const { 119 DCHECK(assign_type_ == NAMED_PROPERTY || assign_type_ == KEYED_PROPERTY); 120 return object_; 121 } key()122 Register key() const { 123 DCHECK(assign_type_ == KEYED_PROPERTY); 124 return key_; 125 } name()126 const AstRawString* name() const { 127 DCHECK(assign_type_ == NAMED_PROPERTY); 128 return name_; 129 } super_property_args()130 RegisterList super_property_args() const { 131 DCHECK(assign_type_ == NAMED_SUPER_PROPERTY || 132 assign_type_ == KEYED_SUPER_PROPERTY); 133 return super_property_args_; 134 } 135 136 private: AssignmentLhsData(AssignType assign_type,Expression * expr,RegisterList super_property_args,Register object,Register key,Expression * object_expr,const AstRawString * name)137 AssignmentLhsData(AssignType assign_type, Expression* expr, 138 RegisterList super_property_args, Register object, 139 Register key, Expression* object_expr, 140 const AstRawString* name) 141 : assign_type_(assign_type), 142 expr_(expr), 143 super_property_args_(super_property_args), 144 object_(object), 145 key_(key), 146 object_expr_(object_expr), 147 name_(name) {} 148 149 AssignType assign_type_; 150 151 // Different assignment types use different fields: 152 // 153 // NON_PROPERTY: expr 154 // NAMED_PROPERTY: object_expr, object, name 155 // KEYED_PROPERTY, PRIVATE_METHOD: object, key 156 // NAMED_SUPER_PROPERTY: super_property_args 157 // KEYED_SUPER_PROPERT: super_property_args 158 Expression* expr_; 159 RegisterList super_property_args_; 160 Register object_; 161 Register key_; 162 Expression* object_expr_; 163 const AstRawString* name_; 164 }; 165 166 void GenerateBytecodeBody(); 167 template <typename LocalIsolate> 168 void AllocateDeferredConstants(LocalIsolate* isolate, Handle<Script> script); 169 170 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); 171 172 // Dispatched from VisitBinaryOperation. 173 void VisitArithmeticExpression(BinaryOperation* binop); 174 void VisitCommaExpression(BinaryOperation* binop); 175 void VisitLogicalOrExpression(BinaryOperation* binop); 176 void VisitLogicalAndExpression(BinaryOperation* binop); 177 void VisitNullishExpression(BinaryOperation* binop); 178 179 // Dispatched from VisitNaryOperation. 180 void VisitNaryArithmeticExpression(NaryOperation* expr); 181 void VisitNaryCommaExpression(NaryOperation* expr); 182 void VisitNaryLogicalOrExpression(NaryOperation* expr); 183 void VisitNaryLogicalAndExpression(NaryOperation* expr); 184 void VisitNaryNullishExpression(NaryOperation* expr); 185 186 // Dispatched from VisitUnaryOperation. 187 void VisitVoid(UnaryOperation* expr); 188 void VisitTypeOf(UnaryOperation* expr); 189 void VisitNot(UnaryOperation* expr); 190 void VisitDelete(UnaryOperation* expr); 191 192 // Visits a typeof expression for the value on which to perform the typeof. 193 void VisitForTypeOfValue(Expression* expr); 194 195 // Used by flow control routines to evaluate loop condition. 196 void VisitCondition(Expression* expr); 197 198 // Visit the arguments expressions in |args| and store them in |args_regs|, 199 // growing |args_regs| for each argument visited. 200 void VisitArguments(const ZonePtrList<Expression>* args, 201 RegisterList* arg_regs); 202 203 // Visit a keyed super property load. The optional 204 // |opt_receiver_out| register will have the receiver stored to it 205 // if it's a valid register. The loaded value is placed in the 206 // accumulator. 207 void VisitKeyedSuperPropertyLoad(Property* property, 208 Register opt_receiver_out); 209 210 // Visit a named super property load. The optional 211 // |opt_receiver_out| register will have the receiver stored to it 212 // if it's a valid register. The loaded value is placed in the 213 // accumulator. 214 void VisitNamedSuperPropertyLoad(Property* property, 215 Register opt_receiver_out); 216 217 void VisitPropertyLoad(Register obj, Property* expr); 218 void VisitPropertyLoadForRegister(Register obj, Property* expr, 219 Register destination); 220 221 AssignmentLhsData PrepareAssignmentLhs( 222 Expression* lhs, AccumulatorPreservingMode accumulator_preserving_mode = 223 AccumulatorPreservingMode::kNone); 224 void BuildAssignment(const AssignmentLhsData& data, Token::Value op, 225 LookupHoistingMode lookup_hoisting_mode); 226 227 void BuildThisVariableLoad(); 228 229 void BuildDeclareCall(Runtime::FunctionId id); 230 231 Expression* GetDestructuringDefaultValue(Expression** target); 232 void BuildDestructuringArrayAssignment( 233 ArrayLiteral* pattern, Token::Value op, 234 LookupHoistingMode lookup_hoisting_mode); 235 void BuildDestructuringObjectAssignment( 236 ObjectLiteral* pattern, Token::Value op, 237 LookupHoistingMode lookup_hoisting_mode); 238 239 void BuildLoadNamedProperty(const Expression* object_expr, Register object, 240 const AstRawString* name); 241 void BuildStoreNamedProperty(const Expression* object_expr, Register object, 242 const AstRawString* name); 243 244 void BuildVariableLoad(Variable* variable, HoleCheckMode hole_check_mode, 245 TypeofMode typeof_mode = NOT_INSIDE_TYPEOF); 246 void BuildVariableLoadForAccumulatorValue( 247 Variable* variable, HoleCheckMode hole_check_mode, 248 TypeofMode typeof_mode = NOT_INSIDE_TYPEOF); 249 void BuildVariableAssignment( 250 Variable* variable, Token::Value op, HoleCheckMode hole_check_mode, 251 LookupHoistingMode lookup_hoisting_mode = LookupHoistingMode::kNormal); 252 void BuildLiteralCompareNil(Token::Value compare_op, 253 BytecodeArrayBuilder::NilValue nil); 254 void BuildReturn(int source_position = kNoSourcePosition); 255 void BuildAsyncReturn(int source_position = kNoSourcePosition); 256 void BuildAsyncGeneratorReturn(); 257 void BuildReThrow(); 258 void BuildHoleCheckForVariableAssignment(Variable* variable, Token::Value op); 259 void BuildThrowIfHole(Variable* variable); 260 261 void BuildNewLocalActivationContext(); 262 void BuildLocalActivationContextInitialization(); 263 void BuildNewLocalBlockContext(Scope* scope); 264 void BuildNewLocalCatchContext(Scope* scope); 265 void BuildNewLocalWithContext(Scope* scope); 266 267 void BuildGeneratorPrologue(); 268 void BuildSuspendPoint(int position); 269 270 void BuildAwait(int position = kNoSourcePosition); 271 void BuildAwait(Expression* await_expr); 272 273 void BuildFinalizeIteration(IteratorRecord iterator, Register done, 274 Register iteration_continuation_token); 275 276 void BuildGetIterator(IteratorType hint); 277 278 // Create an IteratorRecord with pre-allocated registers holding the next 279 // method and iterator object. 280 IteratorRecord BuildGetIteratorRecord(Register iterator_next, 281 Register iterator_object, 282 IteratorType hint); 283 284 // Create an IteratorRecord allocating new registers to hold the next method 285 // and iterator object. 286 IteratorRecord BuildGetIteratorRecord(IteratorType hint); 287 void BuildIteratorNext(const IteratorRecord& iterator, Register next_result); 288 void BuildIteratorClose(const IteratorRecord& iterator, 289 Expression* expr = nullptr); 290 void BuildCallIteratorMethod(Register iterator, const AstRawString* method, 291 RegisterList receiver_and_args, 292 BytecodeLabel* if_called, 293 BytecodeLabels* if_notcalled); 294 295 void BuildFillArrayWithIterator(IteratorRecord iterator, Register array, 296 Register index, Register value, 297 FeedbackSlot next_value_slot, 298 FeedbackSlot next_done_slot, 299 FeedbackSlot index_slot, 300 FeedbackSlot element_slot); 301 // Create Array literals. |expr| can be nullptr, but if provided, 302 // a boilerplate will be used to create an initial array for elements 303 // before the first spread. 304 void BuildCreateArrayLiteral(const ZonePtrList<Expression>* elements, 305 ArrayLiteral* expr); 306 void BuildCreateObjectLiteral(Register literal, uint8_t flags, size_t entry); 307 void AllocateTopLevelRegisters(); 308 void VisitArgumentsObject(Variable* variable); 309 void VisitRestArgumentsArray(Variable* rest); 310 void VisitCallSuper(Call* call); 311 void BuildInvalidPropertyAccess(MessageTemplate tmpl, Property* property); 312 void BuildPrivateBrandCheck(Property* property, Register object, 313 MessageTemplate tmpl); 314 void BuildPrivateGetterAccess(Register obj, Register access_pair); 315 void BuildPrivateSetterAccess(Register obj, Register access_pair, 316 Register value); 317 void BuildPrivateMethods(ClassLiteral* expr, bool is_static, 318 Register home_object); 319 void BuildClassLiteral(ClassLiteral* expr, Register name); 320 void VisitClassLiteral(ClassLiteral* expr, Register name); 321 void VisitNewTargetVariable(Variable* variable); 322 void VisitThisFunctionVariable(Variable* variable); 323 void BuildPrivateBrandInitialization(Register receiver); 324 void BuildInstanceMemberInitialization(Register constructor, 325 Register instance); 326 void BuildGeneratorObjectVariableInitialization(); 327 void VisitBlockDeclarationsAndStatements(Block* stmt); 328 void VisitSetHomeObject(Register value, Register home_object, 329 LiteralProperty* property); 330 void VisitLiteralAccessor(Register home_object, LiteralProperty* property, 331 Register value_out); 332 void VisitForInAssignment(Expression* expr); 333 void VisitModuleNamespaceImports(); 334 335 // Visit a logical OR/AND within a test context, rewiring the jumps based 336 // on the expression values. 337 void VisitLogicalTest(Token::Value token, Expression* left, Expression* right, 338 int right_coverage_slot); 339 void VisitNaryLogicalTest(Token::Value token, NaryOperation* expr, 340 const NaryCodeCoverageSlots* coverage_slots); 341 342 // Visit a (non-RHS) test for a logical op, which falls through if the test 343 // fails or jumps to the appropriate labels if it succeeds. 344 void VisitLogicalTestSubExpression(Token::Value token, Expression* expr, 345 BytecodeLabels* then_labels, 346 BytecodeLabels* else_labels, 347 int coverage_slot); 348 349 // Helpers for binary and nary logical op value expressions. 350 bool VisitLogicalOrSubExpression(Expression* expr, BytecodeLabels* end_labels, 351 int coverage_slot); 352 bool VisitLogicalAndSubExpression(Expression* expr, 353 BytecodeLabels* end_labels, 354 int coverage_slot); 355 356 // Helper for binary and nary nullish op value expressions. 357 bool VisitNullishSubExpression(Expression* expr, BytecodeLabels* end_labels, 358 int coverage_slot); 359 360 // Visit the body of a loop iteration. 361 void VisitIterationBody(IterationStatement* stmt, LoopBuilder* loop_builder); 362 363 // Visit a statement and switch scopes, the context is in the accumulator. 364 void VisitInScope(Statement* stmt, Scope* scope); 365 366 void BuildPushUndefinedIntoRegisterList(RegisterList* reg_list); 367 368 void BuildLoadPropertyKey(LiteralProperty* property, Register out_reg); 369 370 int AllocateBlockCoverageSlotIfEnabled(AstNode* node, SourceRangeKind kind); 371 int AllocateNaryBlockCoverageSlotIfEnabled(NaryOperation* node, size_t index); 372 373 void BuildIncrementBlockCoverageCounterIfEnabled(AstNode* node, 374 SourceRangeKind kind); 375 void BuildIncrementBlockCoverageCounterIfEnabled(int coverage_array_slot); 376 377 void BuildTest(ToBooleanMode mode, BytecodeLabels* then_labels, 378 BytecodeLabels* else_labels, TestFallthrough fallthrough); 379 380 template <typename TryBodyFunc, typename CatchBodyFunc> 381 void BuildTryCatch(TryBodyFunc try_body_func, CatchBodyFunc catch_body_func, 382 HandlerTable::CatchPrediction catch_prediction, 383 TryCatchStatement* stmt_for_coverage = nullptr); 384 template <typename TryBodyFunc, typename FinallyBodyFunc> 385 void BuildTryFinally(TryBodyFunc try_body_func, 386 FinallyBodyFunc finally_body_func, 387 HandlerTable::CatchPrediction catch_prediction, 388 TryFinallyStatement* stmt_for_coverage = nullptr); 389 390 template <typename ExpressionFunc> 391 void BuildOptionalChain(ExpressionFunc expression_func); 392 393 // Visitors for obtaining expression result in the accumulator, in a 394 // register, or just getting the effect. Some visitors return a TypeHint which 395 // specifies the type of the result of the visited expression. 396 TypeHint VisitForAccumulatorValue(Expression* expr); 397 void VisitForAccumulatorValueOrTheHole(Expression* expr); 398 V8_WARN_UNUSED_RESULT Register VisitForRegisterValue(Expression* expr); 399 V8_INLINE void VisitForRegisterValue(Expression* expr, Register destination); 400 void VisitAndPushIntoRegisterList(Expression* expr, RegisterList* reg_list); 401 void VisitForEffect(Expression* expr); 402 void VisitForTest(Expression* expr, BytecodeLabels* then_labels, 403 BytecodeLabels* else_labels, TestFallthrough fallthrough); 404 void VisitForNullishTest(Expression* expr, BytecodeLabels* then_labels, 405 BytecodeLabels* test_next_labels, 406 BytecodeLabels* else_labels); 407 408 void VisitInSameTestExecutionScope(Expression* expr); 409 410 Register GetRegisterForLocalVariable(Variable* variable); 411 412 // Returns the runtime function id for a store to super for the function's 413 // language mode. 414 inline Runtime::FunctionId StoreToSuperRuntimeId(); 415 inline Runtime::FunctionId StoreKeyedToSuperRuntimeId(); 416 417 // Returns a cached slot, or create and cache a new slot if one doesn't 418 // already exists. 419 FeedbackSlot GetCachedLoadGlobalICSlot(TypeofMode typeof_mode, 420 Variable* variable); 421 FeedbackSlot GetCachedStoreGlobalICSlot(LanguageMode language_mode, 422 Variable* variable); 423 FeedbackSlot GetCachedLoadICSlot(const Expression* expr, 424 const AstRawString* name); 425 FeedbackSlot GetCachedLoadSuperICSlot(const AstRawString* name); 426 FeedbackSlot GetCachedStoreICSlot(const Expression* expr, 427 const AstRawString* name); 428 FeedbackSlot GetDummyCompareICSlot(); 429 430 int GetCachedCreateClosureSlot(FunctionLiteral* literal); 431 432 void AddToEagerLiteralsIfEager(FunctionLiteral* literal); 433 434 // Checks if the visited expression is one shot, i.e executed only once. Any 435 // expression either in a top level code or an IIFE that is not within a loop 436 // is eligible for one shot optimizations. 437 inline bool ShouldOptimizeAsOneShot() const; 438 ToBooleanModeFromTypeHint(TypeHint type_hint)439 static constexpr ToBooleanMode ToBooleanModeFromTypeHint(TypeHint type_hint) { 440 return type_hint == TypeHint::kBoolean ? ToBooleanMode::kAlreadyBoolean 441 : ToBooleanMode::kConvertToBoolean; 442 } 443 444 inline Register generator_object() const; 445 builder()446 inline BytecodeArrayBuilder* builder() { return &builder_; } zone()447 inline Zone* zone() const { return zone_; } closure_scope()448 inline DeclarationScope* closure_scope() const { return closure_scope_; } info()449 inline UnoptimizedCompilationInfo* info() const { return info_; } ast_string_constants()450 inline const AstStringConstants* ast_string_constants() const { 451 return ast_string_constants_; 452 } 453 current_scope()454 inline Scope* current_scope() const { return current_scope_; } set_current_scope(Scope * scope)455 inline void set_current_scope(Scope* scope) { current_scope_ = scope; } 456 execution_control()457 inline ControlScope* execution_control() const { return execution_control_; } set_execution_control(ControlScope * scope)458 inline void set_execution_control(ControlScope* scope) { 459 execution_control_ = scope; 460 } execution_context()461 inline ContextScope* execution_context() const { return execution_context_; } set_execution_context(ContextScope * context)462 inline void set_execution_context(ContextScope* context) { 463 execution_context_ = context; 464 } set_execution_result(ExpressionResultScope * execution_result)465 inline void set_execution_result(ExpressionResultScope* execution_result) { 466 execution_result_ = execution_result; 467 } execution_result()468 ExpressionResultScope* execution_result() const { return execution_result_; } register_allocator()469 BytecodeRegisterAllocator* register_allocator() { 470 return builder()->register_allocator(); 471 } 472 top_level_builder()473 TopLevelDeclarationsBuilder* top_level_builder() { 474 DCHECK_NOT_NULL(top_level_builder_); 475 return top_level_builder_; 476 } 477 inline LanguageMode language_mode() const; 478 inline FunctionKind function_kind() const; 479 inline FeedbackVectorSpec* feedback_spec(); 480 inline int feedback_index(FeedbackSlot slot) const; 481 feedback_slot_cache()482 inline FeedbackSlotCache* feedback_slot_cache() { 483 return feedback_slot_cache_; 484 } 485 catch_prediction()486 inline HandlerTable::CatchPrediction catch_prediction() const { 487 return catch_prediction_; 488 } set_catch_prediction(HandlerTable::CatchPrediction value)489 inline void set_catch_prediction(HandlerTable::CatchPrediction value) { 490 catch_prediction_ = value; 491 } 492 current_loop_scope()493 LoopScope* current_loop_scope() const { return current_loop_scope_; } set_current_loop_scope(LoopScope * loop_scope)494 void set_current_loop_scope(LoopScope* loop_scope) { 495 current_loop_scope_ = loop_scope; 496 } 497 498 Zone* zone_; 499 BytecodeArrayBuilder builder_; 500 UnoptimizedCompilationInfo* info_; 501 const AstStringConstants* ast_string_constants_; 502 DeclarationScope* closure_scope_; 503 Scope* current_scope_; 504 505 // External vector of literals to be eagerly compiled. 506 std::vector<FunctionLiteral*>* eager_inner_literals_; 507 508 FeedbackSlotCache* feedback_slot_cache_; 509 510 TopLevelDeclarationsBuilder* top_level_builder_; 511 BlockCoverageBuilder* block_coverage_builder_; 512 ZoneVector<std::pair<FunctionLiteral*, size_t>> function_literals_; 513 ZoneVector<std::pair<NativeFunctionLiteral*, size_t>> 514 native_function_literals_; 515 ZoneVector<std::pair<ObjectLiteral*, size_t>> object_literals_; 516 ZoneVector<std::pair<ArrayLiteral*, size_t>> array_literals_; 517 ZoneVector<std::pair<ClassLiteral*, size_t>> class_literals_; 518 ZoneVector<std::pair<GetTemplateObject*, size_t>> template_objects_; 519 520 ControlScope* execution_control_; 521 ContextScope* execution_context_; 522 ExpressionResultScope* execution_result_; 523 524 Register incoming_new_target_or_generator_; 525 526 BytecodeLabels* optional_chaining_null_labels_; 527 528 // Dummy feedback slot for compare operations, where we don't care about 529 // feedback 530 SharedFeedbackSlot dummy_feedback_slot_; 531 532 BytecodeJumpTable* generator_jump_table_; 533 int suspend_count_; 534 // TODO(solanes): assess if we can move loop_depth_ into LoopScope. 535 int loop_depth_; 536 537 LoopScope* current_loop_scope_; 538 539 HandlerTable::CatchPrediction catch_prediction_; 540 }; 541 542 } // namespace interpreter 543 } // namespace internal 544 } // namespace v8 545 546 #endif // V8_INTERPRETER_BYTECODE_GENERATOR_H_ 547