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/bytecodes.h" 10 #include "src/interpreter/constant-array-builder.h" 11 #include "src/zone-containers.h" 12 13 namespace v8 { 14 namespace internal { 15 16 class Isolate; 17 18 namespace interpreter { 19 20 class BytecodeLabel; 21 class ConstantArrayBuilder; 22 class Register; 23 24 // TODO(rmcilroy): Unify this with CreateArgumentsParameters::Type in Turbofan 25 // when rest parameters implementation has settled down. 26 enum class CreateArgumentsType { kMappedArguments, kUnmappedArguments }; 27 28 class BytecodeArrayBuilder final { 29 public: 30 BytecodeArrayBuilder(Isolate* isolate, Zone* zone); 31 ~BytecodeArrayBuilder(); 32 33 Handle<BytecodeArray> ToBytecodeArray(); 34 35 // Set the number of parameters expected by function. 36 void set_parameter_count(int number_of_params); 37 int parameter_count() const { 38 DCHECK_GE(parameter_count_, 0); 39 return parameter_count_; 40 } 41 42 // Set the number of locals required for bytecode array. 43 void set_locals_count(int number_of_locals); 44 int locals_count() const { 45 DCHECK_GE(local_register_count_, 0); 46 return local_register_count_; 47 } 48 49 // Set number of contexts required for bytecode array. 50 void set_context_count(int number_of_contexts); 51 int context_count() const { 52 DCHECK_GE(context_register_count_, 0); 53 return context_register_count_; 54 } 55 56 Register first_context_register() const; 57 Register last_context_register() const; 58 59 // Returns the number of fixed (non-temporary) registers. 60 int fixed_register_count() const { return context_count() + locals_count(); } 61 62 Register Parameter(int parameter_index) const; 63 64 // Return true if the register |reg| represents a parameter or a 65 // local. 66 bool RegisterIsParameterOrLocal(Register reg) const; 67 68 // Return true if the register |reg| represents a temporary register. 69 bool RegisterIsTemporary(Register reg) const; 70 71 // Constant loads to accumulator. 72 BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value); 73 BytecodeArrayBuilder& LoadLiteral(Handle<Object> object); 74 BytecodeArrayBuilder& LoadUndefined(); 75 BytecodeArrayBuilder& LoadNull(); 76 BytecodeArrayBuilder& LoadTheHole(); 77 BytecodeArrayBuilder& LoadTrue(); 78 BytecodeArrayBuilder& LoadFalse(); 79 BytecodeArrayBuilder& LoadBooleanConstant(bool value); 80 81 // Global loads to the accumulator and stores from the accumulator. 82 BytecodeArrayBuilder& LoadGlobal(const Handle<String> name, int feedback_slot, 83 LanguageMode language_mode, 84 TypeofMode typeof_mode); 85 BytecodeArrayBuilder& StoreGlobal(const Handle<String> name, 86 int feedback_slot, 87 LanguageMode language_mode); 88 89 // Load the object at |slot_index| in |context| into the accumulator. 90 BytecodeArrayBuilder& LoadContextSlot(Register context, int slot_index); 91 92 // Stores the object in the accumulator into |slot_index| of |context|. 93 BytecodeArrayBuilder& StoreContextSlot(Register context, int slot_index); 94 95 // Register-accumulator transfers. 96 BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg); 97 BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg); 98 99 // Register-register transfer. 100 BytecodeArrayBuilder& MoveRegister(Register from, Register to); 101 BytecodeArrayBuilder& ExchangeRegisters(Register reg0, Register reg1); 102 103 // Named load property. 104 BytecodeArrayBuilder& LoadNamedProperty(Register object, 105 const Handle<String> name, 106 int feedback_slot, 107 LanguageMode language_mode); 108 // Keyed load property. The key should be in the accumulator. 109 BytecodeArrayBuilder& LoadKeyedProperty(Register object, int feedback_slot, 110 LanguageMode language_mode); 111 112 // Store properties. The value to be stored should be in the accumulator. 113 BytecodeArrayBuilder& StoreNamedProperty(Register object, 114 const Handle<String> name, 115 int feedback_slot, 116 LanguageMode language_mode); 117 BytecodeArrayBuilder& StoreKeyedProperty(Register object, Register key, 118 int feedback_slot, 119 LanguageMode language_mode); 120 121 // Lookup the variable with |name|. 122 BytecodeArrayBuilder& LoadLookupSlot(const Handle<String> name, 123 TypeofMode typeof_mode); 124 125 // Store value in the accumulator into the variable with |name|. 126 BytecodeArrayBuilder& StoreLookupSlot(const Handle<String> name, 127 LanguageMode language_mode); 128 129 // Create a new closure for the SharedFunctionInfo. 130 BytecodeArrayBuilder& CreateClosure(Handle<SharedFunctionInfo> shared_info, 131 PretenureFlag tenured); 132 133 // Create a new arguments object in the accumulator. 134 BytecodeArrayBuilder& CreateArguments(CreateArgumentsType type); 135 136 // Literals creation. Constant elements should be in the accumulator. 137 BytecodeArrayBuilder& CreateRegExpLiteral(Handle<String> pattern, 138 int literal_index, int flags); 139 BytecodeArrayBuilder& CreateArrayLiteral(Handle<FixedArray> constant_elements, 140 int literal_index, int flags); 141 BytecodeArrayBuilder& CreateObjectLiteral( 142 Handle<FixedArray> constant_properties, int literal_index, int flags); 143 144 // Push the context in accumulator as the new context, and store in register 145 // |context|. 146 BytecodeArrayBuilder& PushContext(Register context); 147 148 // Pop the current context and replace with |context|. 149 BytecodeArrayBuilder& PopContext(Register context); 150 151 // Call a JS function. The JSFunction or Callable to be called should be in 152 // |callable|, the receiver should be in |receiver| and all subsequent 153 // arguments should be in registers <receiver + 1> to 154 // <receiver + 1 + arg_count>. 155 BytecodeArrayBuilder& Call(Register callable, Register receiver, 156 size_t arg_count, int feedback_slot); 157 158 // Call the new operator. The |constructor| register is followed by 159 // |arg_count| consecutive registers containing arguments to be 160 // applied to the constructor. 161 BytecodeArrayBuilder& New(Register constructor, Register first_arg, 162 size_t arg_count); 163 164 // Call the runtime function with |function_id|. The first argument should be 165 // in |first_arg| and all subsequent arguments should be in registers 166 // <first_arg + 1> to <first_arg + 1 + arg_count>. 167 BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id, 168 Register first_arg, size_t arg_count); 169 170 // Call the runtime function with |function_id| that returns a pair of values. 171 // The first argument should be in |first_arg| and all subsequent arguments 172 // should be in registers <first_arg + 1> to <first_arg + 1 + arg_count>. The 173 // return values will be returned in <first_return> and <first_return + 1>. 174 BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id, 175 Register first_arg, size_t arg_count, 176 Register first_return); 177 178 // Call the JS runtime function with |context_index|. The the receiver should 179 // be in |receiver| and all subsequent arguments should be in registers 180 // <receiver + 1> to <receiver + 1 + arg_count>. 181 BytecodeArrayBuilder& CallJSRuntime(int context_index, Register receiver, 182 size_t arg_count); 183 184 // Operators (register holds the lhs value, accumulator holds the rhs value). 185 BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg, 186 Strength strength); 187 188 // Count Operators (value stored in accumulator). 189 BytecodeArrayBuilder& CountOperation(Token::Value op, Strength strength); 190 191 // Unary Operators. 192 BytecodeArrayBuilder& LogicalNot(); 193 BytecodeArrayBuilder& TypeOf(); 194 195 // Deletes property from an object. This expects that accumulator contains 196 // the key to be deleted and the register contains a reference to the object. 197 BytecodeArrayBuilder& Delete(Register object, LanguageMode language_mode); 198 BytecodeArrayBuilder& DeleteLookupSlot(); 199 200 // Tests. 201 BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg, 202 Strength strength); 203 204 // Casts. 205 BytecodeArrayBuilder& CastAccumulatorToBoolean(); 206 BytecodeArrayBuilder& CastAccumulatorToJSObject(); 207 BytecodeArrayBuilder& CastAccumulatorToName(); 208 BytecodeArrayBuilder& CastAccumulatorToNumber(); 209 210 // Flow Control. 211 BytecodeArrayBuilder& Bind(BytecodeLabel* label); 212 BytecodeArrayBuilder& Bind(const BytecodeLabel& target, BytecodeLabel* label); 213 214 BytecodeArrayBuilder& Jump(BytecodeLabel* label); 215 BytecodeArrayBuilder& JumpIfTrue(BytecodeLabel* label); 216 BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label); 217 BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label); 218 BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label); 219 220 BytecodeArrayBuilder& Throw(); 221 BytecodeArrayBuilder& Return(); 222 223 // Complex flow control. 224 BytecodeArrayBuilder& ForInPrepare(Register cache_type, Register cache_array, 225 Register cache_length); 226 BytecodeArrayBuilder& ForInDone(Register index, Register cache_length); 227 BytecodeArrayBuilder& ForInNext(Register receiver, Register cache_type, 228 Register cache_array, Register index); 229 BytecodeArrayBuilder& ForInStep(Register index); 230 231 // Accessors 232 Zone* zone() const { return zone_; } 233 234 private: 235 ZoneVector<uint8_t>* bytecodes() { return &bytecodes_; } 236 const ZoneVector<uint8_t>* bytecodes() const { return &bytecodes_; } 237 Isolate* isolate() const { return isolate_; } 238 ConstantArrayBuilder* constant_array_builder() { 239 return &constant_array_builder_; 240 } 241 const ConstantArrayBuilder* constant_array_builder() const { 242 return &constant_array_builder_; 243 } 244 245 static Bytecode BytecodeForBinaryOperation(Token::Value op); 246 static Bytecode BytecodeForCountOperation(Token::Value op); 247 static Bytecode BytecodeForCompareOperation(Token::Value op); 248 static Bytecode BytecodeForWideOperands(Bytecode bytecode); 249 static Bytecode BytecodeForLoadIC(LanguageMode language_mode); 250 static Bytecode BytecodeForKeyedLoadIC(LanguageMode language_mode); 251 static Bytecode BytecodeForStoreIC(LanguageMode language_mode); 252 static Bytecode BytecodeForKeyedStoreIC(LanguageMode language_mode); 253 static Bytecode BytecodeForLoadGlobal(LanguageMode language_mode, 254 TypeofMode typeof_mode); 255 static Bytecode BytecodeForStoreGlobal(LanguageMode language_mode); 256 static Bytecode BytecodeForStoreLookupSlot(LanguageMode language_mode); 257 static Bytecode BytecodeForCreateArguments(CreateArgumentsType type); 258 static Bytecode BytecodeForDelete(LanguageMode language_mode); 259 260 static bool FitsInIdx8Operand(int value); 261 static bool FitsInIdx8Operand(size_t value); 262 static bool FitsInImm8Operand(int value); 263 static bool FitsInIdx16Operand(int value); 264 static bool FitsInIdx16Operand(size_t value); 265 static bool FitsInReg8Operand(Register value); 266 static bool FitsInReg16Operand(Register value); 267 268 static Bytecode GetJumpWithConstantOperand(Bytecode jump_smi8_operand); 269 static Bytecode GetJumpWithConstantWideOperand(Bytecode jump_smi8_operand); 270 static Bytecode GetJumpWithToBoolean(Bytecode jump_smi8_operand); 271 272 Register MapRegister(Register reg); 273 Register MapRegisters(Register reg, Register args_base, int args_length = 1); 274 275 template <size_t N> 276 INLINE(void Output(Bytecode bytecode, uint32_t(&operands)[N])); 277 void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1, 278 uint32_t operand2, uint32_t operand3); 279 void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1, 280 uint32_t operand2); 281 void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1); 282 void Output(Bytecode bytecode, uint32_t operand0); 283 void Output(Bytecode bytecode); 284 285 BytecodeArrayBuilder& OutputJump(Bytecode jump_bytecode, 286 BytecodeLabel* label); 287 void PatchJump(const ZoneVector<uint8_t>::iterator& jump_target, 288 const ZoneVector<uint8_t>::iterator& jump_location); 289 void PatchIndirectJumpWith8BitOperand( 290 const ZoneVector<uint8_t>::iterator& jump_location, int delta); 291 void PatchIndirectJumpWith16BitOperand( 292 const ZoneVector<uint8_t>::iterator& jump_location, int delta); 293 294 void LeaveBasicBlock(); 295 void EnsureReturn(); 296 297 bool OperandIsValid(Bytecode bytecode, int operand_index, 298 uint32_t operand_value) const; 299 bool LastBytecodeInSameBlock() const; 300 301 bool NeedToBooleanCast(); 302 bool IsRegisterInAccumulator(Register reg); 303 304 bool RegisterIsValid(Register reg) const; 305 306 // Temporary register management. 307 int BorrowTemporaryRegister(); 308 int BorrowTemporaryRegisterNotInRange(int start_index, int end_index); 309 void ReturnTemporaryRegister(int reg_index); 310 int PrepareForConsecutiveTemporaryRegisters(size_t count); 311 void BorrowConsecutiveTemporaryRegister(int reg_index); 312 bool TemporaryRegisterIsLive(Register reg) const; 313 314 Register first_temporary_register() const; 315 Register last_temporary_register() const; 316 317 // Gets a constant pool entry for the |object|. 318 size_t GetConstantPoolEntry(Handle<Object> object); 319 320 Isolate* isolate_; 321 Zone* zone_; 322 ZoneVector<uint8_t> bytecodes_; 323 bool bytecode_generated_; 324 ConstantArrayBuilder constant_array_builder_; 325 size_t last_block_end_; 326 size_t last_bytecode_start_; 327 bool exit_seen_in_block_; 328 int unbound_jumps_; 329 330 int parameter_count_; 331 int local_register_count_; 332 int context_register_count_; 333 int temporary_register_count_; 334 ZoneSet<int> free_temporaries_; 335 336 class PreviousBytecodeHelper; 337 friend class BytecodeRegisterAllocator; 338 339 DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder); 340 }; 341 342 343 // A label representing a branch target in a bytecode array. When a 344 // label is bound, it represents a known position in the bytecode 345 // array. For labels that are forward references there can be at most 346 // one reference whilst it is unbound. 347 class BytecodeLabel final { 348 public: 349 BytecodeLabel() : bound_(false), offset_(kInvalidOffset) {} 350 351 bool is_bound() const { return bound_; } 352 size_t offset() const { return offset_; } 353 354 private: 355 static const size_t kInvalidOffset = static_cast<size_t>(-1); 356 357 void bind_to(size_t offset) { 358 DCHECK(!bound_ && offset != kInvalidOffset); 359 offset_ = offset; 360 bound_ = true; 361 } 362 363 void set_referrer(size_t offset) { 364 DCHECK(!bound_ && offset != kInvalidOffset && offset_ == kInvalidOffset); 365 offset_ = offset; 366 } 367 368 bool is_forward_target() const { 369 return offset() != kInvalidOffset && !is_bound(); 370 } 371 372 // There are three states for a label: 373 // bound_ offset_ 374 // UNSET false kInvalidOffset 375 // FORWARD_TARGET false Offset of referring jump 376 // BACKWARD_TARGET true Offset of label in bytecode array when bound 377 bool bound_; 378 size_t offset_; 379 380 friend class BytecodeArrayBuilder; 381 }; 382 383 } // namespace interpreter 384 } // namespace internal 385 } // namespace v8 386 387 #endif // V8_INTERPRETER_BYTECODE_ARRAY_BUILDER_H_ 388