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/interpreter/bytecode-array-writer.h" 10 #include "src/interpreter/bytecode-register-allocator.h" 11 #include "src/interpreter/bytecodes.h" 12 #include "src/interpreter/constant-array-builder.h" 13 #include "src/interpreter/handler-table-builder.h" 14 #include "src/zone-containers.h" 15 16 namespace v8 { 17 namespace internal { 18 19 class Isolate; 20 21 namespace interpreter { 22 23 class BytecodeLabel; 24 class BytecodeNode; 25 class BytecodePipelineStage; 26 class Register; 27 28 class BytecodeArrayBuilder final : public ZoneObject { 29 public: 30 BytecodeArrayBuilder(Isolate* isolate, Zone* zone, int parameter_count, 31 int context_count, int locals_count, 32 FunctionLiteral* literal = nullptr); 33 34 Handle<BytecodeArray> ToBytecodeArray(); 35 36 // Get the number of parameters expected by function. parameter_count()37 int parameter_count() const { 38 DCHECK_GE(parameter_count_, 0); 39 return parameter_count_; 40 } 41 42 // Get the number of locals required for bytecode array. locals_count()43 int locals_count() const { 44 DCHECK_GE(local_register_count_, 0); 45 return local_register_count_; 46 } 47 48 // Get number of contexts required for bytecode array. context_count()49 int context_count() const { 50 DCHECK_GE(context_register_count_, 0); 51 return context_register_count_; 52 } 53 54 Register first_context_register() const; 55 Register last_context_register() const; 56 57 // Returns the number of fixed (non-temporary) registers. fixed_register_count()58 int fixed_register_count() const { return context_count() + locals_count(); } 59 60 // Returns the number of fixed and temporary registers. fixed_and_temporary_register_count()61 int fixed_and_temporary_register_count() const { 62 return fixed_register_count() + temporary_register_count(); 63 } 64 temporary_register_count()65 int temporary_register_count() const { 66 return temporary_register_allocator()->allocation_count(); 67 } 68 69 Register Parameter(int parameter_index) const; 70 71 // Return true if the register |reg| represents a parameter or a 72 // local. 73 bool RegisterIsParameterOrLocal(Register reg) const; 74 75 // Returns true if the register |reg| is a live temporary register. 76 bool TemporaryRegisterIsLive(Register reg) const; 77 78 // Constant loads to accumulator. 79 BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value); 80 BytecodeArrayBuilder& LoadLiteral(Handle<Object> object); 81 BytecodeArrayBuilder& LoadUndefined(); 82 BytecodeArrayBuilder& LoadNull(); 83 BytecodeArrayBuilder& LoadTheHole(); 84 BytecodeArrayBuilder& LoadTrue(); 85 BytecodeArrayBuilder& LoadFalse(); 86 87 // Global loads to the accumulator and stores from the accumulator. 88 BytecodeArrayBuilder& LoadGlobal(int feedback_slot, TypeofMode typeof_mode); 89 BytecodeArrayBuilder& StoreGlobal(const Handle<String> name, 90 int feedback_slot, 91 LanguageMode language_mode); 92 93 // Load the object at |slot_index| in |context| into the accumulator. 94 BytecodeArrayBuilder& LoadContextSlot(Register context, int slot_index); 95 96 // Stores the object in the accumulator into |slot_index| of |context|. 97 BytecodeArrayBuilder& StoreContextSlot(Register context, int slot_index); 98 99 // Register-accumulator transfers. 100 BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg); 101 BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg); 102 103 // Register-register transfer. 104 BytecodeArrayBuilder& MoveRegister(Register from, Register to); 105 106 // Named load property. 107 BytecodeArrayBuilder& LoadNamedProperty(Register object, 108 const Handle<Name> name, 109 int feedback_slot); 110 // Keyed load property. The key should be in the accumulator. 111 BytecodeArrayBuilder& LoadKeyedProperty(Register object, int feedback_slot); 112 113 // Store properties. The value to be stored should be in the accumulator. 114 BytecodeArrayBuilder& StoreNamedProperty(Register object, 115 const Handle<Name> name, 116 int feedback_slot, 117 LanguageMode language_mode); 118 BytecodeArrayBuilder& StoreKeyedProperty(Register object, Register key, 119 int feedback_slot, 120 LanguageMode language_mode); 121 122 // Lookup the variable with |name|. 123 BytecodeArrayBuilder& LoadLookupSlot(const Handle<String> name, 124 TypeofMode typeof_mode); 125 126 // Store value in the accumulator into the variable with |name|. 127 BytecodeArrayBuilder& StoreLookupSlot(const Handle<String> name, 128 LanguageMode language_mode); 129 130 // Create a new closure for the SharedFunctionInfo. 131 BytecodeArrayBuilder& CreateClosure(Handle<SharedFunctionInfo> shared_info, 132 PretenureFlag tenured); 133 134 // Create a new arguments object in the accumulator. 135 BytecodeArrayBuilder& CreateArguments(CreateArgumentsType type); 136 137 // Literals creation. Constant elements should be in the accumulator. 138 BytecodeArrayBuilder& CreateRegExpLiteral(Handle<String> pattern, 139 int literal_index, int flags); 140 BytecodeArrayBuilder& CreateArrayLiteral(Handle<FixedArray> constant_elements, 141 int literal_index, int flags); 142 BytecodeArrayBuilder& CreateObjectLiteral( 143 Handle<FixedArray> constant_properties, int literal_index, int flags); 144 145 // Push the context in accumulator as the new context, and store in register 146 // |context|. 147 BytecodeArrayBuilder& PushContext(Register context); 148 149 // Pop the current context and replace with |context|. 150 BytecodeArrayBuilder& PopContext(Register context); 151 152 // Call a JS function. The JSFunction or Callable to be called should be in 153 // |callable|, the receiver should be in |receiver_args| and all subsequent 154 // arguments should be in registers <receiver_args + 1> to 155 // <receiver_args + receiver_arg_count - 1>. 156 BytecodeArrayBuilder& Call( 157 Register callable, Register receiver_args, size_t receiver_arg_count, 158 int feedback_slot, TailCallMode tail_call_mode = TailCallMode::kDisallow); 159 TailCall(Register callable,Register receiver_args,size_t receiver_arg_count,int feedback_slot)160 BytecodeArrayBuilder& TailCall(Register callable, Register receiver_args, 161 size_t receiver_arg_count, int feedback_slot) { 162 return Call(callable, receiver_args, receiver_arg_count, feedback_slot, 163 TailCallMode::kAllow); 164 } 165 166 // Call the new operator. The accumulator holds the |new_target|. 167 // The |constructor| is in a register followed by |arg_count| 168 // consecutive arguments starting at |first_arg| for the constuctor 169 // invocation. 170 BytecodeArrayBuilder& New(Register constructor, Register first_arg, 171 size_t arg_count); 172 173 // Call the runtime function with |function_id|. The first argument should be 174 // in |first_arg| and all subsequent arguments should be in registers 175 // <first_arg + 1> to <first_arg + arg_count - 1>. 176 BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id, 177 Register first_arg, size_t arg_count); 178 179 // Call the runtime function with |function_id| that returns a pair of values. 180 // The first argument should be in |first_arg| and all subsequent arguments 181 // should be in registers <first_arg + 1> to <first_arg + arg_count - 1>. The 182 // return values will be returned in <first_return> and <first_return + 1>. 183 BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id, 184 Register first_arg, size_t arg_count, 185 Register first_return); 186 187 // Call the JS runtime function with |context_index|. The the receiver should 188 // be in |receiver_args| and all subsequent arguments should be in registers 189 // <receiver + 1> to <receiver + receiver_args_count - 1>. 190 BytecodeArrayBuilder& CallJSRuntime(int context_index, Register receiver_args, 191 size_t receiver_args_count); 192 193 // Operators (register holds the lhs value, accumulator holds the rhs value). 194 BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg); 195 196 // Count Operators (value stored in accumulator). 197 BytecodeArrayBuilder& CountOperation(Token::Value op); 198 199 // Unary Operators. 200 BytecodeArrayBuilder& LogicalNot(); 201 BytecodeArrayBuilder& TypeOf(); 202 203 // Deletes property from an object. This expects that accumulator contains 204 // the key to be deleted and the register contains a reference to the object. 205 BytecodeArrayBuilder& Delete(Register object, LanguageMode language_mode); 206 207 // Tests. 208 BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg); 209 210 // Casts. 211 BytecodeArrayBuilder& CastAccumulatorToBoolean(); 212 BytecodeArrayBuilder& CastAccumulatorToJSObject(); 213 BytecodeArrayBuilder& CastAccumulatorToName(); 214 BytecodeArrayBuilder& CastAccumulatorToNumber(); 215 216 // Flow Control. 217 BytecodeArrayBuilder& Bind(BytecodeLabel* label); 218 BytecodeArrayBuilder& Bind(const BytecodeLabel& target, BytecodeLabel* label); 219 220 BytecodeArrayBuilder& Jump(BytecodeLabel* label); 221 BytecodeArrayBuilder& JumpIfTrue(BytecodeLabel* label); 222 BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label); 223 BytecodeArrayBuilder& JumpIfNotHole(BytecodeLabel* label); 224 BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label); 225 BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label); 226 227 BytecodeArrayBuilder& StackCheck(int position); 228 229 BytecodeArrayBuilder& Throw(); 230 BytecodeArrayBuilder& ReThrow(); 231 BytecodeArrayBuilder& Return(); 232 233 // Debugger. 234 BytecodeArrayBuilder& Debugger(); 235 236 // Complex flow control. 237 BytecodeArrayBuilder& ForInPrepare(Register cache_info_triple); 238 BytecodeArrayBuilder& ForInDone(Register index, Register cache_length); 239 BytecodeArrayBuilder& ForInNext(Register receiver, Register index, 240 Register cache_type_array_pair, 241 int feedback_slot); 242 BytecodeArrayBuilder& ForInStep(Register index); 243 244 // Generators. 245 BytecodeArrayBuilder& SuspendGenerator(Register generator); 246 BytecodeArrayBuilder& ResumeGenerator(Register generator); 247 248 // Exception handling. 249 BytecodeArrayBuilder& MarkHandler(int handler_id, bool will_catch); 250 BytecodeArrayBuilder& MarkTryBegin(int handler_id, Register context); 251 BytecodeArrayBuilder& MarkTryEnd(int handler_id); 252 253 // Creates a new handler table entry and returns a {hander_id} identifying the 254 // entry, so that it can be referenced by above exception handling support. NewHandlerEntry()255 int NewHandlerEntry() { return handler_table_builder()->NewHandlerEntry(); } 256 257 void InitializeReturnPosition(FunctionLiteral* literal); 258 259 void SetStatementPosition(Statement* stmt); 260 void SetExpressionPosition(Expression* expr); 261 void SetExpressionAsStatementPosition(Expression* expr); 262 263 // Accessors temporary_register_allocator()264 TemporaryRegisterAllocator* temporary_register_allocator() { 265 return &temporary_allocator_; 266 } temporary_register_allocator()267 const TemporaryRegisterAllocator* temporary_register_allocator() const { 268 return &temporary_allocator_; 269 } zone()270 Zone* zone() const { return zone_; } 271 272 void EnsureReturn(); 273 RegisterOperand(Register reg)274 static uint32_t RegisterOperand(Register reg) { 275 return static_cast<uint32_t>(reg.ToOperand()); 276 } 277 SignedOperand(int value)278 static uint32_t SignedOperand(int value) { 279 return static_cast<uint32_t>(value); 280 } 281 UnsignedOperand(int value)282 static uint32_t UnsignedOperand(int value) { 283 DCHECK_GE(value, 0); 284 return static_cast<uint32_t>(value); 285 } 286 UnsignedOperand(size_t value)287 static uint32_t UnsignedOperand(size_t value) { 288 DCHECK_LE(value, kMaxUInt32); 289 return static_cast<uint32_t>(value); 290 } 291 292 private: 293 friend class BytecodeRegisterAllocator; 294 295 static Bytecode BytecodeForBinaryOperation(Token::Value op); 296 static Bytecode BytecodeForCountOperation(Token::Value op); 297 static Bytecode BytecodeForCompareOperation(Token::Value op); 298 static Bytecode BytecodeForStoreNamedProperty(LanguageMode language_mode); 299 static Bytecode BytecodeForStoreKeyedProperty(LanguageMode language_mode); 300 static Bytecode BytecodeForLoadGlobal(TypeofMode typeof_mode); 301 static Bytecode BytecodeForStoreGlobal(LanguageMode language_mode); 302 static Bytecode BytecodeForStoreLookupSlot(LanguageMode language_mode); 303 static Bytecode BytecodeForCreateArguments(CreateArgumentsType type); 304 static Bytecode BytecodeForDelete(LanguageMode language_mode); 305 static Bytecode BytecodeForCall(TailCallMode tail_call_mode); 306 307 void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1, 308 uint32_t operand2, uint32_t operand3); 309 void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1, 310 uint32_t operand2); 311 void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1); 312 void Output(Bytecode bytecode, uint32_t operand0); 313 void Output(Bytecode bytecode); 314 315 BytecodeArrayBuilder& OutputJump(Bytecode jump_bytecode, 316 BytecodeLabel* label); 317 318 bool RegisterIsValid(Register reg) const; 319 bool OperandsAreValid(Bytecode bytecode, int operand_count, 320 uint32_t operand0 = 0, uint32_t operand1 = 0, 321 uint32_t operand2 = 0, uint32_t operand3 = 0) const; 322 323 // Attach latest source position to |node|. 324 void AttachSourceInfo(BytecodeNode* node); 325 326 // Set position for return. 327 void SetReturnPosition(); 328 329 // Gets a constant pool entry for the |object|. 330 size_t GetConstantPoolEntry(Handle<Object> object); 331 332 // Not implemented as the illegal bytecode is used inside internally 333 // to indicate a bytecode field is not valid or an error has occured 334 // during bytecode generation. 335 BytecodeArrayBuilder& Illegal(); 336 LeaveBasicBlock()337 void LeaveBasicBlock() { return_seen_in_block_ = false; } 338 isolate()339 Isolate* isolate() const { return isolate_; } bytecode_array_writer()340 BytecodeArrayWriter* bytecode_array_writer() { 341 return &bytecode_array_writer_; 342 } pipeline()343 BytecodePipelineStage* pipeline() { return pipeline_; } constant_array_builder()344 ConstantArrayBuilder* constant_array_builder() { 345 return &constant_array_builder_; 346 } constant_array_builder()347 const ConstantArrayBuilder* constant_array_builder() const { 348 return &constant_array_builder_; 349 } handler_table_builder()350 HandlerTableBuilder* handler_table_builder() { 351 return &handler_table_builder_; 352 } 353 354 Isolate* isolate_; 355 Zone* zone_; 356 bool bytecode_generated_; 357 ConstantArrayBuilder constant_array_builder_; 358 HandlerTableBuilder handler_table_builder_; 359 bool return_seen_in_block_; 360 int parameter_count_; 361 int local_register_count_; 362 int context_register_count_; 363 int return_position_; 364 TemporaryRegisterAllocator temporary_allocator_; 365 BytecodeArrayWriter bytecode_array_writer_; 366 BytecodePipelineStage* pipeline_; 367 BytecodeSourceInfo latest_source_info_; 368 369 DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder); 370 }; 371 372 } // namespace interpreter 373 } // namespace internal 374 } // namespace v8 375 376 #endif // V8_INTERPRETER_BYTECODE_ARRAY_BUILDER_H_ 377