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_ARRAY_BUILDER_H_ 6 #define V8_INTERPRETER_BYTECODE_ARRAY_BUILDER_H_ 7 8 #include "src/ast/ast.h" 9 #include "src/base/compiler-specific.h" 10 #include "src/globals.h" 11 #include "src/interpreter/bytecode-array-writer.h" 12 #include "src/interpreter/bytecode-register-allocator.h" 13 #include "src/interpreter/bytecode-register.h" 14 #include "src/interpreter/bytecodes.h" 15 #include "src/interpreter/constant-array-builder.h" 16 #include "src/interpreter/handler-table-builder.h" 17 #include "src/zone/zone-containers.h" 18 19 namespace v8 { 20 namespace internal { 21 22 class Isolate; 23 24 namespace interpreter { 25 26 class BytecodeLabel; 27 class BytecodeNode; 28 class BytecodePipelineStage; 29 class BytecodeRegisterOptimizer; 30 class Register; 31 32 class V8_EXPORT_PRIVATE BytecodeArrayBuilder final NON_EXPORTED_BASE(ZoneObject)33 : public NON_EXPORTED_BASE(ZoneObject) { 34 public: 35 BytecodeArrayBuilder( 36 Isolate* isolate, Zone* zone, int parameter_count, int context_count, 37 int locals_count, FunctionLiteral* literal = nullptr, 38 SourcePositionTableBuilder::RecordingMode source_position_mode = 39 SourcePositionTableBuilder::RECORD_SOURCE_POSITIONS); 40 41 Handle<BytecodeArray> ToBytecodeArray(Isolate* isolate); 42 43 // Get the number of parameters expected by function. 44 int parameter_count() const { 45 DCHECK_GE(parameter_count_, 0); 46 return parameter_count_; 47 } 48 49 // Get the number of locals required for bytecode array. 50 int locals_count() const { 51 DCHECK_GE(local_register_count_, 0); 52 return local_register_count_; 53 } 54 55 // Get number of contexts required for bytecode array. 56 int context_count() const { 57 DCHECK_GE(context_register_count_, 0); 58 return context_register_count_; 59 } 60 61 Register first_context_register() const; 62 Register last_context_register() const; 63 64 // Returns the number of fixed (non-temporary) registers. 65 int fixed_register_count() const { return context_count() + locals_count(); } 66 67 // Returns the number of fixed and temporary registers. 68 int total_register_count() const { 69 DCHECK_LE(fixed_register_count(), 70 register_allocator()->maximum_register_count()); 71 return register_allocator()->maximum_register_count(); 72 } 73 74 Register Local(int index) const; 75 Register Parameter(int parameter_index) const; 76 77 // Constant loads to accumulator. 78 BytecodeArrayBuilder& LoadConstantPoolEntry(size_t entry); 79 BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value); 80 BytecodeArrayBuilder& LoadLiteral(const AstRawString* raw_string); 81 BytecodeArrayBuilder& LoadLiteral(const Scope* scope); 82 BytecodeArrayBuilder& LoadLiteral(const AstValue* ast_value); 83 BytecodeArrayBuilder& LoadUndefined(); 84 BytecodeArrayBuilder& LoadNull(); 85 BytecodeArrayBuilder& LoadTheHole(); 86 BytecodeArrayBuilder& LoadTrue(); 87 BytecodeArrayBuilder& LoadFalse(); 88 89 // Global loads to the accumulator and stores from the accumulator. 90 BytecodeArrayBuilder& LoadGlobal(const AstRawString* name, int feedback_slot, 91 TypeofMode typeof_mode); 92 BytecodeArrayBuilder& StoreGlobal(const AstRawString* name, int feedback_slot, 93 LanguageMode language_mode); 94 95 // Load the object at |slot_index| at |depth| in the context chain starting 96 // with |context| into the accumulator. 97 enum ContextSlotMutability { kImmutableSlot, kMutableSlot }; 98 BytecodeArrayBuilder& LoadContextSlot(Register context, int slot_index, 99 int depth, 100 ContextSlotMutability immutable); 101 102 // Stores the object in the accumulator into |slot_index| at |depth| in the 103 // context chain starting with |context|. 104 BytecodeArrayBuilder& StoreContextSlot(Register context, int slot_index, 105 int depth); 106 107 // Load from a module variable into the accumulator. |depth| is the depth of 108 // the current context relative to the module context. 109 BytecodeArrayBuilder& LoadModuleVariable(int cell_index, int depth); 110 111 // Store from the accumulator into a module variable. |depth| is the depth of 112 // the current context relative to the module context. 113 BytecodeArrayBuilder& StoreModuleVariable(int cell_index, int depth); 114 115 // Register-accumulator transfers. 116 BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg); 117 BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg); 118 119 // Register-register transfer. 120 BytecodeArrayBuilder& MoveRegister(Register from, Register to); 121 122 // Named load property. 123 BytecodeArrayBuilder& LoadNamedProperty(Register object, 124 const AstRawString* name, 125 int feedback_slot); 126 // Keyed load property. The key should be in the accumulator. 127 BytecodeArrayBuilder& LoadKeyedProperty(Register object, int feedback_slot); 128 // Named load property of the @@iterator symbol. 129 BytecodeArrayBuilder& LoadIteratorProperty(Register object, 130 int feedback_slot); 131 // Named load property of the @@asyncIterator symbol. 132 BytecodeArrayBuilder& LoadAsyncIteratorProperty(Register object, 133 int feedback_slot); 134 135 // Store properties. Flag for NeedsSetFunctionName() should 136 // be in the accumulator. 137 BytecodeArrayBuilder& StoreDataPropertyInLiteral( 138 Register object, Register name, DataPropertyInLiteralFlags flags, 139 int feedback_slot); 140 141 // Store a property named by a property name. The value to be stored should be 142 // in the accumulator. 143 BytecodeArrayBuilder& StoreNamedProperty(Register object, 144 const AstRawString* name, 145 int feedback_slot, 146 LanguageMode language_mode); 147 // Store a property named by a constant from the constant pool. The value to 148 // be stored should be in the accumulator. 149 BytecodeArrayBuilder& StoreNamedProperty(Register object, 150 size_t constant_pool_entry, 151 int feedback_slot, 152 LanguageMode language_mode); 153 // Store an own property named by a constant from the constant pool. The 154 // value to be stored should be in the accumulator. 155 BytecodeArrayBuilder& StoreNamedOwnProperty(Register object, 156 const AstRawString* name, 157 int feedback_slot); 158 // Store a property keyed by a value in a register. The value to be stored 159 // should be in the accumulator. 160 BytecodeArrayBuilder& StoreKeyedProperty(Register object, Register key, 161 int feedback_slot, 162 LanguageMode language_mode); 163 // Store the home object property. The value to be stored should be in the 164 // accumulator. 165 BytecodeArrayBuilder& StoreHomeObjectProperty(Register object, 166 int feedback_slot, 167 LanguageMode language_mode); 168 169 // Lookup the variable with |name|. 170 BytecodeArrayBuilder& LoadLookupSlot(const AstRawString* name, 171 TypeofMode typeof_mode); 172 173 // Lookup the variable with |name|, which is known to be at |slot_index| at 174 // |depth| in the context chain if not shadowed by a context extension 175 // somewhere in that context chain. 176 BytecodeArrayBuilder& LoadLookupContextSlot(const AstRawString* name, 177 TypeofMode typeof_mode, 178 int slot_index, int depth); 179 180 // Lookup the variable with |name|, which has its feedback in |feedback_slot| 181 // and is known to be global if not shadowed by a context extension somewhere 182 // up to |depth| in that context chain. 183 BytecodeArrayBuilder& LoadLookupGlobalSlot(const AstRawString* name, 184 TypeofMode typeof_mode, 185 int feedback_slot, int depth); 186 187 // Store value in the accumulator into the variable with |name|. 188 BytecodeArrayBuilder& StoreLookupSlot(const AstRawString* name, 189 LanguageMode language_mode); 190 191 // Create a new closure for a SharedFunctionInfo which will be inserted at 192 // constant pool index |shared_function_info_entry|. 193 BytecodeArrayBuilder& CreateClosure(size_t shared_function_info_entry, 194 int slot, int flags); 195 196 // Create a new local context for a |scope| and a closure which should be 197 // in the accumulator. 198 BytecodeArrayBuilder& CreateBlockContext(const Scope* scope); 199 200 // Create a new context for a catch block with |exception|, |name|, 201 // |scope|, and the closure in the accumulator. 202 BytecodeArrayBuilder& CreateCatchContext(Register exception, 203 const AstRawString* name, 204 const Scope* scope); 205 206 // Create a new context with size |slots|. 207 BytecodeArrayBuilder& CreateFunctionContext(int slots); 208 209 // Create a new eval context with size |slots|. 210 BytecodeArrayBuilder& CreateEvalContext(int slots); 211 212 // Creates a new context with the given |scope| for a with-statement 213 // with the |object| in a register and the closure in the accumulator. 214 BytecodeArrayBuilder& CreateWithContext(Register object, const Scope* scope); 215 216 // Create a new arguments object in the accumulator. 217 BytecodeArrayBuilder& CreateArguments(CreateArgumentsType type); 218 219 // Literals creation. Constant elements should be in the accumulator. 220 BytecodeArrayBuilder& CreateRegExpLiteral(const AstRawString* pattern, 221 int literal_index, int flags); 222 BytecodeArrayBuilder& CreateArrayLiteral(size_t constant_elements_entry, 223 int literal_index, int flags); 224 BytecodeArrayBuilder& CreateObjectLiteral(size_t constant_properties_entry, 225 int literal_index, int flags, 226 Register output); 227 228 // Push the context in accumulator as the new context, and store in register 229 // |context|. 230 BytecodeArrayBuilder& PushContext(Register context); 231 232 // Pop the current context and replace with |context|. 233 BytecodeArrayBuilder& PopContext(Register context); 234 235 // Call a JS function. The JSFunction or Callable to be called should be in 236 // |callable|. The arguments should be in |args|, with the receiver in 237 // |args[0]|. The call type of the expression is in |call_type|. Type feedback 238 // is recorded in the |feedback_slot| in the type feedback vector. 239 BytecodeArrayBuilder& Call( 240 Register callable, RegisterList args, int feedback_slot, 241 Call::CallType call_type, 242 TailCallMode tail_call_mode = TailCallMode::kDisallow); 243 244 // Call a JS function. The JSFunction or Callable to be called should be in 245 // |callable|, the receiver in |args[0]| and the arguments in |args[1]| 246 // onwards. The final argument must be a spread. 247 BytecodeArrayBuilder& CallWithSpread(Register callable, RegisterList args); 248 249 // Call the Construct operator. The accumulator holds the |new_target|. 250 // The |constructor| is in a register and arguments are in |args|. 251 BytecodeArrayBuilder& Construct(Register constructor, RegisterList args, 252 int feedback_slot); 253 254 // Call the Construct operator for use with a spread. The accumulator holds 255 // the |new_target|. The |constructor| is in a register and arguments are in 256 // |args|. The final argument must be a spread. 257 BytecodeArrayBuilder& ConstructWithSpread(Register constructor, 258 RegisterList args); 259 260 // Call the runtime function with |function_id| and arguments |args|. 261 BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id, 262 RegisterList args); 263 // Call the runtime function with |function_id| with single argument |arg|. 264 BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id, 265 Register arg); 266 // Call the runtime function with |function_id| with no arguments. 267 BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id); 268 269 // Call the runtime function with |function_id| and arguments |args|, that 270 // returns a pair of values. The return values will be returned in 271 // |return_pair|. 272 BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id, 273 RegisterList args, 274 RegisterList return_pair); 275 // Call the runtime function with |function_id| with single argument |arg| 276 // that returns a pair of values. The return values will be returned in 277 // |return_pair|. 278 BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id, 279 Register arg, 280 RegisterList return_pair); 281 282 // Call the JS runtime function with |context_index| and arguments |args|. 283 BytecodeArrayBuilder& CallJSRuntime(int context_index, RegisterList args); 284 285 // Operators (register holds the lhs value, accumulator holds the rhs value). 286 // Type feedback will be recorded in the |feedback_slot| 287 BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg, 288 int feedback_slot); 289 290 // Count Operators (value stored in accumulator). 291 // Type feedback will be recorded in the |feedback_slot| 292 BytecodeArrayBuilder& CountOperation(Token::Value op, int feedback_slot); 293 294 // Unary Operators. 295 BytecodeArrayBuilder& LogicalNot(); 296 BytecodeArrayBuilder& TypeOf(); 297 298 // Expects a heap object in the accumulator. Returns its super constructor in 299 // the register |out| if it passes the IsConstructor test. Otherwise, it 300 // throws a TypeError exception. 301 BytecodeArrayBuilder& GetSuperConstructor(Register out); 302 303 // Deletes property from an object. This expects that accumulator contains 304 // the key to be deleted and the register contains a reference to the object. 305 BytecodeArrayBuilder& Delete(Register object, LanguageMode language_mode); 306 307 // Tests. 308 BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg, 309 int feedback_slot = kNoFeedbackSlot); 310 311 // Converts accumulator and stores result in register |out|. 312 BytecodeArrayBuilder& ConvertAccumulatorToObject(Register out); 313 BytecodeArrayBuilder& ConvertAccumulatorToName(Register out); 314 BytecodeArrayBuilder& ConvertAccumulatorToNumber(Register out); 315 316 // Flow Control. 317 BytecodeArrayBuilder& Bind(BytecodeLabel* label); 318 BytecodeArrayBuilder& Bind(const BytecodeLabel& target, BytecodeLabel* label); 319 320 BytecodeArrayBuilder& Jump(BytecodeLabel* label); 321 BytecodeArrayBuilder& JumpIfTrue(BytecodeLabel* label); 322 BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label); 323 BytecodeArrayBuilder& JumpIfNotHole(BytecodeLabel* label); 324 BytecodeArrayBuilder& JumpIfJSReceiver(BytecodeLabel* label); 325 BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label); 326 BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label); 327 BytecodeArrayBuilder& JumpLoop(BytecodeLabel* label, int loop_depth); 328 329 BytecodeArrayBuilder& StackCheck(int position); 330 331 // Sets the pending message to the value in the accumulator, and returns the 332 // previous pending message in the accumulator. 333 BytecodeArrayBuilder& SetPendingMessage(); 334 335 BytecodeArrayBuilder& Throw(); 336 BytecodeArrayBuilder& ReThrow(); 337 BytecodeArrayBuilder& Return(); 338 339 // Debugger. 340 BytecodeArrayBuilder& Debugger(); 341 342 // Complex flow control. 343 BytecodeArrayBuilder& ForInPrepare(Register receiver, 344 RegisterList cache_info_triple); 345 BytecodeArrayBuilder& ForInContinue(Register index, Register cache_length); 346 BytecodeArrayBuilder& ForInNext(Register receiver, Register index, 347 RegisterList cache_type_array_pair, 348 int feedback_slot); 349 BytecodeArrayBuilder& ForInStep(Register index); 350 351 // Generators. 352 BytecodeArrayBuilder& SuspendGenerator(Register generator); 353 BytecodeArrayBuilder& ResumeGenerator(Register generator); 354 355 // Exception handling. 356 BytecodeArrayBuilder& MarkHandler(int handler_id, 357 HandlerTable::CatchPrediction will_catch); 358 BytecodeArrayBuilder& MarkTryBegin(int handler_id, Register context); 359 BytecodeArrayBuilder& MarkTryEnd(int handler_id); 360 361 // Creates a new handler table entry and returns a {hander_id} identifying the 362 // entry, so that it can be referenced by above exception handling support. 363 int NewHandlerEntry() { return handler_table_builder()->NewHandlerEntry(); } 364 365 // Gets a constant pool entry. 366 size_t GetConstantPoolEntry(const AstRawString* raw_string); 367 size_t GetConstantPoolEntry(const AstValue* heap_number); 368 size_t GetConstantPoolEntry(const Scope* scope); 369 #define ENTRY_GETTER(NAME, ...) size_t NAME##ConstantPoolEntry(); 370 SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_GETTER) 371 #undef ENTRY_GETTER 372 373 // Allocates a slot in the constant pool which can later be set. 374 size_t AllocateDeferredConstantPoolEntry(); 375 // Sets the deferred value into an allocated constant pool entry. 376 void SetDeferredConstantPoolEntry(size_t entry, Handle<Object> object); 377 378 void InitializeReturnPosition(FunctionLiteral* literal); 379 380 void SetStatementPosition(Statement* stmt) { 381 if (stmt->position() == kNoSourcePosition) return; 382 latest_source_info_.MakeStatementPosition(stmt->position()); 383 } 384 385 void SetExpressionPosition(Expression* expr) { 386 if (expr->position() == kNoSourcePosition) return; 387 if (!latest_source_info_.is_statement()) { 388 // Ensure the current expression position is overwritten with the 389 // latest value. 390 latest_source_info_.MakeExpressionPosition(expr->position()); 391 } 392 } 393 394 void SetExpressionAsStatementPosition(Expression* expr) { 395 if (expr->position() == kNoSourcePosition) return; 396 latest_source_info_.MakeStatementPosition(expr->position()); 397 } 398 399 bool RequiresImplicitReturn() const { return !return_seen_in_block_; } 400 401 // Returns the raw operand value for the given register or register list. 402 uint32_t GetInputRegisterOperand(Register reg); 403 uint32_t GetOutputRegisterOperand(Register reg); 404 uint32_t GetInputRegisterListOperand(RegisterList reg_list); 405 uint32_t GetOutputRegisterListOperand(RegisterList reg_list); 406 407 // Accessors 408 BytecodeRegisterAllocator* register_allocator() { 409 return ®ister_allocator_; 410 } 411 const BytecodeRegisterAllocator* register_allocator() const { 412 return ®ister_allocator_; 413 } 414 Zone* zone() const { return zone_; } 415 416 private: 417 friend class BytecodeRegisterAllocator; 418 template <Bytecode bytecode, AccumulatorUse accumulator_use, 419 OperandType... operand_types> 420 friend class BytecodeNodeBuilder; 421 422 const FeedbackVectorSpec* feedback_vector_spec() const { 423 return literal_->feedback_vector_spec(); 424 } 425 426 // Returns the current source position for the given |bytecode|. 427 INLINE(BytecodeSourceInfo CurrentSourcePosition(Bytecode bytecode)); 428 429 #define DECLARE_BYTECODE_OUTPUT(Name, ...) \ 430 template <typename... Operands> \ 431 INLINE(void Output##Name(Operands... operands)); \ 432 template <typename... Operands> \ 433 INLINE(void Output##Name(BytecodeLabel* label, Operands... operands)); 434 BYTECODE_LIST(DECLARE_BYTECODE_OUTPUT) 435 #undef DECLARE_OPERAND_TYPE_INFO 436 437 bool RegisterIsValid(Register reg) const; 438 bool RegisterListIsValid(RegisterList reg_list) const; 439 440 // Set position for return. 441 void SetReturnPosition(); 442 443 // Not implemented as the illegal bytecode is used inside internally 444 // to indicate a bytecode field is not valid or an error has occured 445 // during bytecode generation. 446 BytecodeArrayBuilder& Illegal(); 447 448 template <Bytecode bytecode, AccumulatorUse accumulator_use> 449 void PrepareToOutputBytecode(); 450 451 void LeaveBasicBlock() { return_seen_in_block_ = false; } 452 453 BytecodeArrayWriter* bytecode_array_writer() { 454 return &bytecode_array_writer_; 455 } 456 BytecodePipelineStage* pipeline() { return pipeline_; } 457 ConstantArrayBuilder* constant_array_builder() { 458 return &constant_array_builder_; 459 } 460 const ConstantArrayBuilder* constant_array_builder() const { 461 return &constant_array_builder_; 462 } 463 HandlerTableBuilder* handler_table_builder() { 464 return &handler_table_builder_; 465 } 466 467 Zone* zone_; 468 FunctionLiteral* literal_; 469 bool bytecode_generated_; 470 ConstantArrayBuilder constant_array_builder_; 471 HandlerTableBuilder handler_table_builder_; 472 bool return_seen_in_block_; 473 int parameter_count_; 474 int local_register_count_; 475 int context_register_count_; 476 int return_position_; 477 BytecodeRegisterAllocator register_allocator_; 478 BytecodeArrayWriter bytecode_array_writer_; 479 BytecodePipelineStage* pipeline_; 480 BytecodeRegisterOptimizer* register_optimizer_; 481 BytecodeSourceInfo latest_source_info_; 482 483 static int const kNoFeedbackSlot = 0; 484 485 DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder); 486 }; 487 488 } // namespace interpreter 489 } // namespace internal 490 } // namespace v8 491 492 #endif // V8_INTERPRETER_BYTECODE_ARRAY_BUILDER_H_ 493