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 Parameter(int parameter_index) const; 75 76 // Constant loads to accumulator. 77 BytecodeArrayBuilder& LoadConstantPoolEntry(size_t entry); 78 BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value); 79 BytecodeArrayBuilder& LoadLiteral(Handle<Object> object); 80 BytecodeArrayBuilder& LoadUndefined(); 81 BytecodeArrayBuilder& LoadNull(); 82 BytecodeArrayBuilder& LoadTheHole(); 83 BytecodeArrayBuilder& LoadTrue(); 84 BytecodeArrayBuilder& LoadFalse(); 85 86 // Global loads to the accumulator and stores from the accumulator. 87 BytecodeArrayBuilder& LoadGlobal(int feedback_slot, TypeofMode typeof_mode); 88 BytecodeArrayBuilder& StoreGlobal(const Handle<String> name, 89 int feedback_slot, 90 LanguageMode language_mode); 91 92 // Load the object at |slot_index| at |depth| in the context chain starting 93 // with |context| into the accumulator. 94 BytecodeArrayBuilder& LoadContextSlot(Register context, int slot_index, 95 int depth); 96 97 // Stores the object in the accumulator into |slot_index| at |depth| in the 98 // context chain starting with |context|. 99 BytecodeArrayBuilder& StoreContextSlot(Register context, int slot_index, 100 int depth); 101 102 // Load from a module variable into the accumulator. |depth| is the depth of 103 // the current context relative to the module context. 104 BytecodeArrayBuilder& LoadModuleVariable(int cell_index, int depth); 105 106 // Store from the accumulator into a module variable. |depth| is the depth of 107 // the current context relative to the module context. 108 BytecodeArrayBuilder& StoreModuleVariable(int cell_index, int depth); 109 110 // Register-accumulator transfers. 111 BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg); 112 BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg); 113 114 // Register-register transfer. 115 BytecodeArrayBuilder& MoveRegister(Register from, Register to); 116 117 // Named load property. 118 BytecodeArrayBuilder& LoadNamedProperty(Register object, 119 const Handle<Name> name, 120 int feedback_slot); 121 // Keyed load property. The key should be in the accumulator. 122 BytecodeArrayBuilder& LoadKeyedProperty(Register object, int feedback_slot); 123 124 // Store properties. The value to be stored should be in the accumulator. 125 BytecodeArrayBuilder& StoreNamedProperty(Register object, 126 const Handle<Name> name, 127 int feedback_slot, 128 LanguageMode language_mode); 129 BytecodeArrayBuilder& StoreKeyedProperty(Register object, Register key, 130 int feedback_slot, 131 LanguageMode language_mode); 132 133 // Lookup the variable with |name|. 134 BytecodeArrayBuilder& LoadLookupSlot(const Handle<String> name, 135 TypeofMode typeof_mode); 136 137 // Lookup the variable with |name|, which is known to be at |slot_index| at 138 // |depth| in the context chain if not shadowed by a context extension 139 // somewhere in that context chain. 140 BytecodeArrayBuilder& LoadLookupContextSlot(const Handle<String> name, 141 TypeofMode typeof_mode, 142 int slot_index, int depth); 143 144 // Lookup the variable with |name|, which has its feedback in |feedback_slot| 145 // and is known to be global if not shadowed by a context extension somewhere 146 // up to |depth| in that context chain. 147 BytecodeArrayBuilder& LoadLookupGlobalSlot(const Handle<String> name, 148 TypeofMode typeof_mode, 149 int feedback_slot, int depth); 150 151 // Store value in the accumulator into the variable with |name|. 152 BytecodeArrayBuilder& StoreLookupSlot(const Handle<String> name, 153 LanguageMode language_mode); 154 155 // Create a new closure for a SharedFunctionInfo which will be inserted at 156 // constant pool index |entry|. 157 BytecodeArrayBuilder& CreateClosure(size_t entry, int flags); 158 159 // Create a new local context for a |scope_info| and a closure which should be 160 // in the accumulator. 161 BytecodeArrayBuilder& CreateBlockContext(Handle<ScopeInfo> scope_info); 162 163 // Create a new context for a catch block with |exception|, |name|, 164 // |scope_info|, and the closure in the accumulator. 165 BytecodeArrayBuilder& CreateCatchContext(Register exception, 166 Handle<String> name, 167 Handle<ScopeInfo> scope_info); 168 169 // Create a new context with size |slots|. 170 BytecodeArrayBuilder& CreateFunctionContext(int slots); 171 172 // Creates a new context with the given |scope_info| for a with-statement 173 // with the |object| in a register and the closure in the accumulator. 174 BytecodeArrayBuilder& CreateWithContext(Register object, 175 Handle<ScopeInfo> scope_info); 176 177 // Create a new arguments object in the accumulator. 178 BytecodeArrayBuilder& CreateArguments(CreateArgumentsType type); 179 180 // Literals creation. Constant elements should be in the accumulator. 181 BytecodeArrayBuilder& CreateRegExpLiteral(Handle<String> pattern, 182 int literal_index, int flags); 183 BytecodeArrayBuilder& CreateArrayLiteral(Handle<FixedArray> constant_elements, 184 int literal_index, int flags); 185 BytecodeArrayBuilder& CreateObjectLiteral( 186 Handle<FixedArray> constant_properties, int literal_index, int flags, 187 Register output); 188 189 // Push the context in accumulator as the new context, and store in register 190 // |context|. 191 BytecodeArrayBuilder& PushContext(Register context); 192 193 // Pop the current context and replace with |context|. 194 BytecodeArrayBuilder& PopContext(Register context); 195 196 // Call a JS function. The JSFunction or Callable to be called should be in 197 // |callable|. The arguments should be in |args|, with the receiver in 198 // |args[0]|. The call type of the expression is in |call_type|. Type feedback 199 // is recorded in the |feedback_slot| in the type feedback vector. 200 BytecodeArrayBuilder& Call( 201 Register callable, RegisterList args, int feedback_slot, 202 Call::CallType call_type, 203 TailCallMode tail_call_mode = TailCallMode::kDisallow); 204 205 // Call the new operator. The accumulator holds the |new_target|. 206 // The |constructor| is in a register and arguments are in |args|. 207 BytecodeArrayBuilder& New(Register constructor, RegisterList args, 208 int feedback_slot); 209 210 // Call the runtime function with |function_id| and arguments |args|. 211 BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id, 212 RegisterList args); 213 // Call the runtime function with |function_id| with single argument |arg|. 214 BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id, 215 Register arg); 216 // Call the runtime function with |function_id| with no arguments. 217 BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id); 218 219 // Call the runtime function with |function_id| and arguments |args|, that 220 // returns a pair of values. The return values will be returned in 221 // |return_pair|. 222 BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id, 223 RegisterList args, 224 RegisterList return_pair); 225 // Call the runtime function with |function_id| with single argument |arg| 226 // that returns a pair of values. The return values will be returned in 227 // |return_pair|. 228 BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id, 229 Register arg, 230 RegisterList return_pair); 231 232 // Call the JS runtime function with |context_index| and arguments |args|. 233 BytecodeArrayBuilder& CallJSRuntime(int context_index, RegisterList args); 234 235 // Operators (register holds the lhs value, accumulator holds the rhs value). 236 // Type feedback will be recorded in the |feedback_slot| 237 BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg, 238 int feedback_slot); 239 240 // Count Operators (value stored in accumulator). 241 // Type feedback will be recorded in the |feedback_slot| 242 BytecodeArrayBuilder& CountOperation(Token::Value op, int feedback_slot); 243 244 // Unary Operators. 245 BytecodeArrayBuilder& LogicalNot(); 246 BytecodeArrayBuilder& TypeOf(); 247 248 // Deletes property from an object. This expects that accumulator contains 249 // the key to be deleted and the register contains a reference to the object. 250 BytecodeArrayBuilder& Delete(Register object, LanguageMode language_mode); 251 252 // Tests. 253 BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg, 254 int feedback_slot = kNoFeedbackSlot); 255 256 // Converts accumulator and stores result in register |out|. 257 BytecodeArrayBuilder& ConvertAccumulatorToObject(Register out); 258 BytecodeArrayBuilder& ConvertAccumulatorToName(Register out); 259 BytecodeArrayBuilder& ConvertAccumulatorToNumber(Register out); 260 261 // Flow Control. 262 BytecodeArrayBuilder& Bind(BytecodeLabel* label); 263 BytecodeArrayBuilder& Bind(const BytecodeLabel& target, BytecodeLabel* label); 264 265 BytecodeArrayBuilder& Jump(BytecodeLabel* label); 266 BytecodeArrayBuilder& JumpIfTrue(BytecodeLabel* label); 267 BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label); 268 BytecodeArrayBuilder& JumpIfNotHole(BytecodeLabel* label); 269 BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label); 270 BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label); 271 BytecodeArrayBuilder& JumpLoop(BytecodeLabel* label, int loop_depth); 272 273 BytecodeArrayBuilder& StackCheck(int position); 274 275 BytecodeArrayBuilder& Throw(); 276 BytecodeArrayBuilder& ReThrow(); 277 BytecodeArrayBuilder& Return(); 278 279 // Debugger. 280 BytecodeArrayBuilder& Debugger(); 281 282 // Complex flow control. 283 BytecodeArrayBuilder& ForInPrepare(Register receiver, 284 RegisterList cache_info_triple); 285 BytecodeArrayBuilder& ForInContinue(Register index, Register cache_length); 286 BytecodeArrayBuilder& ForInNext(Register receiver, Register index, 287 RegisterList cache_type_array_pair, 288 int feedback_slot); 289 BytecodeArrayBuilder& ForInStep(Register index); 290 291 // Generators. 292 BytecodeArrayBuilder& SuspendGenerator(Register generator); 293 BytecodeArrayBuilder& ResumeGenerator(Register generator); 294 295 // Exception handling. 296 BytecodeArrayBuilder& MarkHandler(int handler_id, 297 HandlerTable::CatchPrediction will_catch); 298 BytecodeArrayBuilder& MarkTryBegin(int handler_id, Register context); 299 BytecodeArrayBuilder& MarkTryEnd(int handler_id); 300 301 // Creates a new handler table entry and returns a {hander_id} identifying the 302 // entry, so that it can be referenced by above exception handling support. 303 int NewHandlerEntry() { return handler_table_builder()->NewHandlerEntry(); } 304 305 // Allocates a slot in the constant pool which can later be inserted. 306 size_t AllocateConstantPoolEntry(); 307 // Inserts a entry into an allocated constant pool entry. 308 void InsertConstantPoolEntryAt(size_t entry, Handle<Object> object); 309 310 void InitializeReturnPosition(FunctionLiteral* literal); 311 312 void SetStatementPosition(Statement* stmt) { 313 if (stmt->position() == kNoSourcePosition) return; 314 latest_source_info_.MakeStatementPosition(stmt->position()); 315 } 316 317 void SetExpressionPosition(Expression* expr) { 318 if (expr->position() == kNoSourcePosition) return; 319 if (!latest_source_info_.is_statement()) { 320 // Ensure the current expression position is overwritten with the 321 // latest value. 322 latest_source_info_.MakeExpressionPosition(expr->position()); 323 } 324 } 325 326 void SetExpressionAsStatementPosition(Expression* expr) { 327 if (expr->position() == kNoSourcePosition) return; 328 latest_source_info_.MakeStatementPosition(expr->position()); 329 } 330 331 bool RequiresImplicitReturn() const { return !return_seen_in_block_; } 332 333 // Returns the raw operand value for the given register or register list. 334 uint32_t GetInputRegisterOperand(Register reg); 335 uint32_t GetOutputRegisterOperand(Register reg); 336 uint32_t GetInputRegisterListOperand(RegisterList reg_list); 337 uint32_t GetOutputRegisterListOperand(RegisterList reg_list); 338 339 // Accessors 340 BytecodeRegisterAllocator* register_allocator() { 341 return ®ister_allocator_; 342 } 343 const BytecodeRegisterAllocator* register_allocator() const { 344 return ®ister_allocator_; 345 } 346 Zone* zone() const { return zone_; } 347 348 private: 349 friend class BytecodeRegisterAllocator; 350 template <OperandType... operand_types> 351 friend class BytecodeNodeBuilder; 352 353 // Returns the current source position for the given |bytecode|. 354 INLINE(BytecodeSourceInfo CurrentSourcePosition(Bytecode bytecode)); 355 356 #define DECLARE_BYTECODE_OUTPUT(Name, ...) \ 357 template <typename... Operands> \ 358 INLINE(void Output##Name(Operands... operands)); \ 359 template <typename... Operands> \ 360 INLINE(void Output##Name(BytecodeLabel* label, Operands... operands)); 361 BYTECODE_LIST(DECLARE_BYTECODE_OUTPUT) 362 #undef DECLARE_OPERAND_TYPE_INFO 363 364 bool RegisterIsValid(Register reg) const; 365 bool RegisterListIsValid(RegisterList reg_list) const; 366 367 // Set position for return. 368 void SetReturnPosition(); 369 370 // Gets a constant pool entry for the |object|. 371 size_t GetConstantPoolEntry(Handle<Object> object); 372 373 // Not implemented as the illegal bytecode is used inside internally 374 // to indicate a bytecode field is not valid or an error has occured 375 // during bytecode generation. 376 BytecodeArrayBuilder& Illegal(); 377 378 void PrepareToOutputBytecode(Bytecode bytecode); 379 380 void LeaveBasicBlock() { return_seen_in_block_ = false; } 381 382 BytecodeArrayWriter* bytecode_array_writer() { 383 return &bytecode_array_writer_; 384 } 385 BytecodePipelineStage* pipeline() { return pipeline_; } 386 ConstantArrayBuilder* constant_array_builder() { 387 return &constant_array_builder_; 388 } 389 const ConstantArrayBuilder* constant_array_builder() const { 390 return &constant_array_builder_; 391 } 392 HandlerTableBuilder* handler_table_builder() { 393 return &handler_table_builder_; 394 } 395 396 Zone* zone_; 397 bool bytecode_generated_; 398 ConstantArrayBuilder constant_array_builder_; 399 HandlerTableBuilder handler_table_builder_; 400 bool return_seen_in_block_; 401 int parameter_count_; 402 int local_register_count_; 403 int context_register_count_; 404 int return_position_; 405 BytecodeRegisterAllocator register_allocator_; 406 BytecodeArrayWriter bytecode_array_writer_; 407 BytecodePipelineStage* pipeline_; 408 BytecodeRegisterOptimizer* register_optimizer_; 409 BytecodeSourceInfo latest_source_info_; 410 411 static int const kNoFeedbackSlot = 0; 412 413 DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder); 414 }; 415 416 } // namespace interpreter 417 } // namespace internal 418 } // namespace v8 419 420 #endif // V8_INTERPRETER_BYTECODE_ARRAY_BUILDER_H_ 421