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 #include "src/interpreter/bytecode-array-builder.h" 6 7 namespace v8 { 8 namespace internal { 9 namespace interpreter { 10 11 class BytecodeArrayBuilder::PreviousBytecodeHelper { 12 public: 13 explicit PreviousBytecodeHelper(const BytecodeArrayBuilder& array_builder) 14 : array_builder_(array_builder), 15 previous_bytecode_start_(array_builder_.last_bytecode_start_) { 16 // This helper is expected to be instantiated only when the last bytecode is 17 // in the same basic block. 18 DCHECK(array_builder_.LastBytecodeInSameBlock()); 19 } 20 21 // Returns the previous bytecode in the same basic block. 22 MUST_USE_RESULT Bytecode GetBytecode() const { 23 DCHECK_EQ(array_builder_.last_bytecode_start_, previous_bytecode_start_); 24 return Bytecodes::FromByte( 25 array_builder_.bytecodes()->at(previous_bytecode_start_)); 26 } 27 28 // Returns the operand at operand_index for the previous bytecode in the 29 // same basic block. 30 MUST_USE_RESULT uint32_t GetOperand(int operand_index) const { 31 DCHECK_EQ(array_builder_.last_bytecode_start_, previous_bytecode_start_); 32 Bytecode bytecode = GetBytecode(); 33 DCHECK_GE(operand_index, 0); 34 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode)); 35 size_t operand_offset = 36 previous_bytecode_start_ + 37 Bytecodes::GetOperandOffset(bytecode, operand_index); 38 OperandSize size = Bytecodes::GetOperandSize(bytecode, operand_index); 39 switch (size) { 40 default: 41 case OperandSize::kNone: 42 UNREACHABLE(); 43 case OperandSize::kByte: 44 return static_cast<uint32_t>( 45 array_builder_.bytecodes()->at(operand_offset)); 46 case OperandSize::kShort: 47 uint16_t operand = 48 (array_builder_.bytecodes()->at(operand_offset) << 8) + 49 array_builder_.bytecodes()->at(operand_offset + 1); 50 return static_cast<uint32_t>(operand); 51 } 52 } 53 54 Handle<Object> GetConstantForIndexOperand(int operand_index) const { 55 return array_builder_.constant_array_builder()->At( 56 GetOperand(operand_index)); 57 } 58 59 private: 60 const BytecodeArrayBuilder& array_builder_; 61 size_t previous_bytecode_start_; 62 63 DISALLOW_COPY_AND_ASSIGN(PreviousBytecodeHelper); 64 }; 65 66 67 BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone) 68 : isolate_(isolate), 69 zone_(zone), 70 bytecodes_(zone), 71 bytecode_generated_(false), 72 constant_array_builder_(isolate, zone), 73 last_block_end_(0), 74 last_bytecode_start_(~0), 75 exit_seen_in_block_(false), 76 unbound_jumps_(0), 77 parameter_count_(-1), 78 local_register_count_(-1), 79 context_register_count_(-1), 80 temporary_register_count_(0), 81 free_temporaries_(zone) {} 82 83 84 BytecodeArrayBuilder::~BytecodeArrayBuilder() { DCHECK_EQ(0, unbound_jumps_); } 85 86 87 void BytecodeArrayBuilder::set_locals_count(int number_of_locals) { 88 local_register_count_ = number_of_locals; 89 DCHECK_LE(context_register_count_, 0); 90 } 91 92 93 void BytecodeArrayBuilder::set_parameter_count(int number_of_parameters) { 94 parameter_count_ = number_of_parameters; 95 } 96 97 98 void BytecodeArrayBuilder::set_context_count(int number_of_contexts) { 99 context_register_count_ = number_of_contexts; 100 DCHECK_GE(local_register_count_, 0); 101 } 102 103 104 Register BytecodeArrayBuilder::first_context_register() const { 105 DCHECK_GT(context_register_count_, 0); 106 return Register(local_register_count_); 107 } 108 109 110 Register BytecodeArrayBuilder::last_context_register() const { 111 DCHECK_GT(context_register_count_, 0); 112 return Register(local_register_count_ + context_register_count_ - 1); 113 } 114 115 116 Register BytecodeArrayBuilder::first_temporary_register() const { 117 DCHECK_GT(temporary_register_count_, 0); 118 return Register(fixed_register_count()); 119 } 120 121 122 Register BytecodeArrayBuilder::last_temporary_register() const { 123 DCHECK_GT(temporary_register_count_, 0); 124 return Register(fixed_register_count() + temporary_register_count_ - 1); 125 } 126 127 128 Register BytecodeArrayBuilder::Parameter(int parameter_index) const { 129 DCHECK_GE(parameter_index, 0); 130 return Register::FromParameterIndex(parameter_index, parameter_count()); 131 } 132 133 134 bool BytecodeArrayBuilder::RegisterIsParameterOrLocal(Register reg) const { 135 return reg.is_parameter() || reg.index() < locals_count(); 136 } 137 138 139 bool BytecodeArrayBuilder::RegisterIsTemporary(Register reg) const { 140 return temporary_register_count_ > 0 && first_temporary_register() <= reg && 141 reg <= last_temporary_register(); 142 } 143 144 145 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { 146 DCHECK_EQ(bytecode_generated_, false); 147 EnsureReturn(); 148 149 int bytecode_size = static_cast<int>(bytecodes_.size()); 150 int register_count = fixed_register_count() + temporary_register_count_; 151 int frame_size = register_count * kPointerSize; 152 Factory* factory = isolate_->factory(); 153 Handle<FixedArray> constant_pool = 154 constant_array_builder()->ToFixedArray(factory); 155 Handle<BytecodeArray> output = 156 factory->NewBytecodeArray(bytecode_size, &bytecodes_.front(), frame_size, 157 parameter_count(), constant_pool); 158 bytecode_generated_ = true; 159 return output; 160 } 161 162 163 template <size_t N> 164 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t(&operands)[N]) { 165 // Don't output dead code. 166 if (exit_seen_in_block_) return; 167 168 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), static_cast<int>(N)); 169 last_bytecode_start_ = bytecodes()->size(); 170 bytecodes()->push_back(Bytecodes::ToByte(bytecode)); 171 for (int i = 0; i < static_cast<int>(N); i++) { 172 DCHECK(OperandIsValid(bytecode, i, operands[i])); 173 switch (Bytecodes::GetOperandSize(bytecode, i)) { 174 case OperandSize::kNone: 175 UNREACHABLE(); 176 case OperandSize::kByte: 177 bytecodes()->push_back(static_cast<uint8_t>(operands[i])); 178 break; 179 case OperandSize::kShort: { 180 uint8_t operand_bytes[2]; 181 WriteUnalignedUInt16(operand_bytes, operands[i]); 182 bytecodes()->insert(bytecodes()->end(), operand_bytes, 183 operand_bytes + 2); 184 break; 185 } 186 } 187 } 188 } 189 190 191 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0, 192 uint32_t operand1, uint32_t operand2, 193 uint32_t operand3) { 194 uint32_t operands[] = {operand0, operand1, operand2, operand3}; 195 Output(bytecode, operands); 196 } 197 198 199 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0, 200 uint32_t operand1, uint32_t operand2) { 201 uint32_t operands[] = {operand0, operand1, operand2}; 202 Output(bytecode, operands); 203 } 204 205 206 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0, 207 uint32_t operand1) { 208 uint32_t operands[] = {operand0, operand1}; 209 Output(bytecode, operands); 210 } 211 212 213 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0) { 214 uint32_t operands[] = {operand0}; 215 Output(bytecode, operands); 216 } 217 218 219 void BytecodeArrayBuilder::Output(Bytecode bytecode) { 220 // Don't output dead code. 221 if (exit_seen_in_block_) return; 222 223 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), 0); 224 last_bytecode_start_ = bytecodes()->size(); 225 bytecodes()->push_back(Bytecodes::ToByte(bytecode)); 226 } 227 228 229 BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op, 230 Register reg, 231 Strength strength) { 232 if (is_strong(strength)) { 233 UNIMPLEMENTED(); 234 } 235 236 Output(BytecodeForBinaryOperation(op), reg.ToOperand()); 237 return *this; 238 } 239 240 241 BytecodeArrayBuilder& BytecodeArrayBuilder::CountOperation(Token::Value op, 242 Strength strength) { 243 if (is_strong(strength)) { 244 UNIMPLEMENTED(); 245 } 246 247 Output(BytecodeForCountOperation(op)); 248 return *this; 249 } 250 251 252 BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot() { 253 Output(Bytecode::kLogicalNot); 254 return *this; 255 } 256 257 258 BytecodeArrayBuilder& BytecodeArrayBuilder::TypeOf() { 259 Output(Bytecode::kTypeOf); 260 return *this; 261 } 262 263 264 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation( 265 Token::Value op, Register reg, Strength strength) { 266 if (is_strong(strength)) { 267 UNIMPLEMENTED(); 268 } 269 270 Output(BytecodeForCompareOperation(op), reg.ToOperand()); 271 return *this; 272 } 273 274 275 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral( 276 v8::internal::Smi* smi) { 277 int32_t raw_smi = smi->value(); 278 if (raw_smi == 0) { 279 Output(Bytecode::kLdaZero); 280 } else if (raw_smi >= -128 && raw_smi <= 127) { 281 Output(Bytecode::kLdaSmi8, static_cast<uint8_t>(raw_smi)); 282 } else { 283 LoadLiteral(Handle<Object>(smi, isolate_)); 284 } 285 return *this; 286 } 287 288 289 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) { 290 size_t entry = GetConstantPoolEntry(object); 291 if (FitsInIdx8Operand(entry)) { 292 Output(Bytecode::kLdaConstant, static_cast<uint8_t>(entry)); 293 } else if (FitsInIdx16Operand(entry)) { 294 Output(Bytecode::kLdaConstantWide, static_cast<uint16_t>(entry)); 295 } else { 296 UNIMPLEMENTED(); 297 } 298 return *this; 299 } 300 301 302 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() { 303 Output(Bytecode::kLdaUndefined); 304 return *this; 305 } 306 307 308 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNull() { 309 Output(Bytecode::kLdaNull); 310 return *this; 311 } 312 313 314 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTheHole() { 315 Output(Bytecode::kLdaTheHole); 316 return *this; 317 } 318 319 320 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTrue() { 321 Output(Bytecode::kLdaTrue); 322 return *this; 323 } 324 325 326 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() { 327 Output(Bytecode::kLdaFalse); 328 return *this; 329 } 330 331 332 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadBooleanConstant(bool value) { 333 if (value) { 334 LoadTrue(); 335 } else { 336 LoadFalse(); 337 } 338 return *this; 339 } 340 341 342 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister( 343 Register reg) { 344 if (!IsRegisterInAccumulator(reg)) { 345 Output(Bytecode::kLdar, reg.ToOperand()); 346 } 347 return *this; 348 } 349 350 351 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister( 352 Register reg) { 353 // TODO(oth): Avoid storing the accumulator in the register if the 354 // previous bytecode loaded the accumulator with the same register. 355 // 356 // TODO(oth): If the previous bytecode is a MOV into this register, 357 // the previous instruction can be removed. The logic for determining 358 // these redundant MOVs appears complex. 359 Output(Bytecode::kStar, reg.ToOperand()); 360 if (!IsRegisterInAccumulator(reg)) { 361 Output(Bytecode::kStar, reg.ToOperand()); 362 } 363 return *this; 364 } 365 366 367 BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from, 368 Register to) { 369 DCHECK(from != to); 370 Output(Bytecode::kMov, from.ToOperand(), to.ToOperand()); 371 return *this; 372 } 373 374 375 BytecodeArrayBuilder& BytecodeArrayBuilder::ExchangeRegisters(Register reg0, 376 Register reg1) { 377 DCHECK(reg0 != reg1); 378 if (FitsInReg8Operand(reg0)) { 379 Output(Bytecode::kExchange, reg0.ToOperand(), reg1.ToWideOperand()); 380 } else if (FitsInReg8Operand(reg1)) { 381 Output(Bytecode::kExchange, reg1.ToOperand(), reg0.ToWideOperand()); 382 } else { 383 Output(Bytecode::kExchangeWide, reg0.ToWideOperand(), reg1.ToWideOperand()); 384 } 385 return *this; 386 } 387 388 389 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal( 390 const Handle<String> name, int feedback_slot, LanguageMode language_mode, 391 TypeofMode typeof_mode) { 392 // TODO(rmcilroy): Potentially store language and typeof information in an 393 // operand rather than having extra bytecodes. 394 Bytecode bytecode = BytecodeForLoadGlobal(language_mode, typeof_mode); 395 size_t name_index = GetConstantPoolEntry(name); 396 if (FitsInIdx8Operand(name_index) && FitsInIdx8Operand(feedback_slot)) { 397 Output(bytecode, static_cast<uint8_t>(name_index), 398 static_cast<uint8_t>(feedback_slot)); 399 } else if (FitsInIdx16Operand(name_index) && 400 FitsInIdx16Operand(feedback_slot)) { 401 Output(BytecodeForWideOperands(bytecode), static_cast<uint16_t>(name_index), 402 static_cast<uint16_t>(feedback_slot)); 403 } else { 404 UNIMPLEMENTED(); 405 } 406 return *this; 407 } 408 409 410 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreGlobal( 411 const Handle<String> name, int feedback_slot, LanguageMode language_mode) { 412 Bytecode bytecode = BytecodeForStoreGlobal(language_mode); 413 size_t name_index = GetConstantPoolEntry(name); 414 if (FitsInIdx8Operand(name_index) && FitsInIdx8Operand(feedback_slot)) { 415 Output(bytecode, static_cast<uint8_t>(name_index), 416 static_cast<uint8_t>(feedback_slot)); 417 } else if (FitsInIdx16Operand(name_index) && 418 FitsInIdx16Operand(feedback_slot)) { 419 Output(BytecodeForWideOperands(bytecode), static_cast<uint16_t>(name_index), 420 static_cast<uint16_t>(feedback_slot)); 421 } else { 422 UNIMPLEMENTED(); 423 } 424 return *this; 425 } 426 427 428 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context, 429 int slot_index) { 430 DCHECK(slot_index >= 0); 431 if (FitsInIdx8Operand(slot_index)) { 432 Output(Bytecode::kLdaContextSlot, context.ToOperand(), 433 static_cast<uint8_t>(slot_index)); 434 } else if (FitsInIdx16Operand(slot_index)) { 435 Output(Bytecode::kLdaContextSlotWide, context.ToOperand(), 436 static_cast<uint16_t>(slot_index)); 437 } else { 438 UNIMPLEMENTED(); 439 } 440 return *this; 441 } 442 443 444 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context, 445 int slot_index) { 446 DCHECK(slot_index >= 0); 447 if (FitsInIdx8Operand(slot_index)) { 448 Output(Bytecode::kStaContextSlot, context.ToOperand(), 449 static_cast<uint8_t>(slot_index)); 450 } else if (FitsInIdx16Operand(slot_index)) { 451 Output(Bytecode::kStaContextSlotWide, context.ToOperand(), 452 static_cast<uint16_t>(slot_index)); 453 } else { 454 UNIMPLEMENTED(); 455 } 456 return *this; 457 } 458 459 460 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupSlot( 461 const Handle<String> name, TypeofMode typeof_mode) { 462 Bytecode bytecode = (typeof_mode == INSIDE_TYPEOF) 463 ? Bytecode::kLdaLookupSlotInsideTypeof 464 : Bytecode::kLdaLookupSlot; 465 size_t name_index = GetConstantPoolEntry(name); 466 if (FitsInIdx8Operand(name_index)) { 467 Output(bytecode, static_cast<uint8_t>(name_index)); 468 } else if (FitsInIdx16Operand(name_index)) { 469 Output(BytecodeForWideOperands(bytecode), 470 static_cast<uint16_t>(name_index)); 471 } else { 472 UNIMPLEMENTED(); 473 } 474 return *this; 475 } 476 477 478 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot( 479 const Handle<String> name, LanguageMode language_mode) { 480 Bytecode bytecode = BytecodeForStoreLookupSlot(language_mode); 481 size_t name_index = GetConstantPoolEntry(name); 482 if (FitsInIdx8Operand(name_index)) { 483 Output(bytecode, static_cast<uint8_t>(name_index)); 484 } else if (FitsInIdx16Operand(name_index)) { 485 Output(BytecodeForWideOperands(bytecode), 486 static_cast<uint16_t>(name_index)); 487 } else { 488 UNIMPLEMENTED(); 489 } 490 return *this; 491 } 492 493 494 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty( 495 Register object, const Handle<String> name, int feedback_slot, 496 LanguageMode language_mode) { 497 Bytecode bytecode = BytecodeForLoadIC(language_mode); 498 size_t name_index = GetConstantPoolEntry(name); 499 if (FitsInIdx8Operand(name_index) && FitsInIdx8Operand(feedback_slot)) { 500 Output(bytecode, object.ToOperand(), static_cast<uint8_t>(name_index), 501 static_cast<uint8_t>(feedback_slot)); 502 } else if (FitsInIdx16Operand(name_index) && 503 FitsInIdx16Operand(feedback_slot)) { 504 Output(BytecodeForWideOperands(bytecode), object.ToOperand(), 505 static_cast<uint16_t>(name_index), 506 static_cast<uint16_t>(feedback_slot)); 507 } else { 508 UNIMPLEMENTED(); 509 } 510 return *this; 511 } 512 513 514 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty( 515 Register object, int feedback_slot, LanguageMode language_mode) { 516 Bytecode bytecode = BytecodeForKeyedLoadIC(language_mode); 517 if (FitsInIdx8Operand(feedback_slot)) { 518 Output(bytecode, object.ToOperand(), static_cast<uint8_t>(feedback_slot)); 519 } else if (FitsInIdx16Operand(feedback_slot)) { 520 Output(BytecodeForWideOperands(bytecode), object.ToOperand(), 521 static_cast<uint16_t>(feedback_slot)); 522 } else { 523 UNIMPLEMENTED(); 524 } 525 return *this; 526 } 527 528 529 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty( 530 Register object, const Handle<String> name, int feedback_slot, 531 LanguageMode language_mode) { 532 Bytecode bytecode = BytecodeForStoreIC(language_mode); 533 size_t name_index = GetConstantPoolEntry(name); 534 if (FitsInIdx8Operand(name_index) && FitsInIdx8Operand(feedback_slot)) { 535 Output(bytecode, object.ToOperand(), static_cast<uint8_t>(name_index), 536 static_cast<uint8_t>(feedback_slot)); 537 } else if (FitsInIdx16Operand(name_index) && 538 FitsInIdx16Operand(feedback_slot)) { 539 Output(BytecodeForWideOperands(bytecode), object.ToOperand(), 540 static_cast<uint16_t>(name_index), 541 static_cast<uint16_t>(feedback_slot)); 542 } else { 543 UNIMPLEMENTED(); 544 } 545 return *this; 546 } 547 548 549 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty( 550 Register object, Register key, int feedback_slot, 551 LanguageMode language_mode) { 552 Bytecode bytecode = BytecodeForKeyedStoreIC(language_mode); 553 if (FitsInIdx8Operand(feedback_slot)) { 554 Output(bytecode, object.ToOperand(), key.ToOperand(), 555 static_cast<uint8_t>(feedback_slot)); 556 } else if (FitsInIdx16Operand(feedback_slot)) { 557 Output(BytecodeForWideOperands(bytecode), object.ToOperand(), 558 key.ToOperand(), static_cast<uint16_t>(feedback_slot)); 559 } else { 560 UNIMPLEMENTED(); 561 } 562 return *this; 563 } 564 565 566 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure( 567 Handle<SharedFunctionInfo> shared_info, PretenureFlag tenured) { 568 size_t entry = GetConstantPoolEntry(shared_info); 569 DCHECK(FitsInImm8Operand(tenured)); 570 if (FitsInIdx8Operand(entry)) { 571 Output(Bytecode::kCreateClosure, static_cast<uint8_t>(entry), 572 static_cast<uint8_t>(tenured)); 573 } else if (FitsInIdx16Operand(entry)) { 574 Output(Bytecode::kCreateClosureWide, static_cast<uint16_t>(entry), 575 static_cast<uint8_t>(tenured)); 576 } else { 577 UNIMPLEMENTED(); 578 } 579 return *this; 580 } 581 582 583 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments( 584 CreateArgumentsType type) { 585 // TODO(rmcilroy): Consider passing the type as a bytecode operand rather 586 // than having two different bytecodes once we have better support for 587 // branches in the InterpreterAssembler. 588 Bytecode bytecode = BytecodeForCreateArguments(type); 589 Output(bytecode); 590 return *this; 591 } 592 593 594 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral( 595 Handle<String> pattern, int literal_index, int flags) { 596 DCHECK(FitsInImm8Operand(flags)); // Flags should fit in 8 bits. 597 size_t pattern_entry = GetConstantPoolEntry(pattern); 598 if (FitsInIdx8Operand(literal_index) && FitsInIdx8Operand(pattern_entry)) { 599 Output(Bytecode::kCreateRegExpLiteral, static_cast<uint8_t>(pattern_entry), 600 static_cast<uint8_t>(literal_index), static_cast<uint8_t>(flags)); 601 } else if (FitsInIdx16Operand(literal_index) && 602 FitsInIdx16Operand(pattern_entry)) { 603 Output(Bytecode::kCreateRegExpLiteralWide, 604 static_cast<uint16_t>(pattern_entry), 605 static_cast<uint16_t>(literal_index), static_cast<uint8_t>(flags)); 606 } else { 607 UNIMPLEMENTED(); 608 } 609 return *this; 610 } 611 612 613 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral( 614 Handle<FixedArray> constant_elements, int literal_index, int flags) { 615 DCHECK(FitsInImm8Operand(flags)); // Flags should fit in 8 bits. 616 size_t constant_elements_entry = GetConstantPoolEntry(constant_elements); 617 if (FitsInIdx8Operand(literal_index) && 618 FitsInIdx8Operand(constant_elements_entry)) { 619 Output(Bytecode::kCreateArrayLiteral, 620 static_cast<uint8_t>(constant_elements_entry), 621 static_cast<uint8_t>(literal_index), static_cast<uint8_t>(flags)); 622 } else if (FitsInIdx16Operand(literal_index) && 623 FitsInIdx16Operand(constant_elements_entry)) { 624 Output(Bytecode::kCreateArrayLiteralWide, 625 static_cast<uint16_t>(constant_elements_entry), 626 static_cast<uint16_t>(literal_index), static_cast<uint8_t>(flags)); 627 } else { 628 UNIMPLEMENTED(); 629 } 630 return *this; 631 } 632 633 634 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral( 635 Handle<FixedArray> constant_properties, int literal_index, int flags) { 636 DCHECK(FitsInImm8Operand(flags)); // Flags should fit in 8 bits. 637 size_t constant_properties_entry = GetConstantPoolEntry(constant_properties); 638 if (FitsInIdx8Operand(literal_index) && 639 FitsInIdx8Operand(constant_properties_entry)) { 640 Output(Bytecode::kCreateObjectLiteral, 641 static_cast<uint8_t>(constant_properties_entry), 642 static_cast<uint8_t>(literal_index), static_cast<uint8_t>(flags)); 643 } else if (FitsInIdx16Operand(literal_index) && 644 FitsInIdx16Operand(constant_properties_entry)) { 645 Output(Bytecode::kCreateObjectLiteralWide, 646 static_cast<uint16_t>(constant_properties_entry), 647 static_cast<uint16_t>(literal_index), static_cast<uint8_t>(flags)); 648 } else { 649 UNIMPLEMENTED(); 650 } 651 return *this; 652 } 653 654 655 BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) { 656 Output(Bytecode::kPushContext, context.ToOperand()); 657 return *this; 658 } 659 660 661 BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) { 662 Output(Bytecode::kPopContext, context.ToOperand()); 663 return *this; 664 } 665 666 667 bool BytecodeArrayBuilder::NeedToBooleanCast() { 668 if (!LastBytecodeInSameBlock()) { 669 return true; 670 } 671 PreviousBytecodeHelper previous_bytecode(*this); 672 switch (previous_bytecode.GetBytecode()) { 673 // If the previous bytecode puts a boolean in the accumulator return true. 674 case Bytecode::kLdaTrue: 675 case Bytecode::kLdaFalse: 676 case Bytecode::kLogicalNot: 677 case Bytecode::kTestEqual: 678 case Bytecode::kTestNotEqual: 679 case Bytecode::kTestEqualStrict: 680 case Bytecode::kTestNotEqualStrict: 681 case Bytecode::kTestLessThan: 682 case Bytecode::kTestLessThanOrEqual: 683 case Bytecode::kTestGreaterThan: 684 case Bytecode::kTestGreaterThanOrEqual: 685 case Bytecode::kTestInstanceOf: 686 case Bytecode::kTestIn: 687 case Bytecode::kForInDone: 688 return false; 689 default: 690 return true; 691 } 692 } 693 694 695 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToJSObject() { 696 Output(Bytecode::kToObject); 697 return *this; 698 } 699 700 701 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() { 702 if (LastBytecodeInSameBlock()) { 703 PreviousBytecodeHelper previous_bytecode(*this); 704 switch (previous_bytecode.GetBytecode()) { 705 case Bytecode::kToName: 706 case Bytecode::kTypeOf: 707 return *this; 708 case Bytecode::kLdaConstantWide: 709 case Bytecode::kLdaConstant: { 710 Handle<Object> object = previous_bytecode.GetConstantForIndexOperand(0); 711 if (object->IsName()) return *this; 712 break; 713 } 714 default: 715 break; 716 } 717 } 718 Output(Bytecode::kToName); 719 return *this; 720 } 721 722 723 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToNumber() { 724 // TODO(rmcilroy): consider omitting if the preceeding bytecode always returns 725 // a number. 726 Output(Bytecode::kToNumber); 727 return *this; 728 } 729 730 731 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) { 732 if (label->is_forward_target()) { 733 // An earlier jump instruction refers to this label. Update it's location. 734 PatchJump(bytecodes()->end(), bytecodes()->begin() + label->offset()); 735 // Now treat as if the label will only be back referred to. 736 } 737 label->bind_to(bytecodes()->size()); 738 LeaveBasicBlock(); 739 return *this; 740 } 741 742 743 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(const BytecodeLabel& target, 744 BytecodeLabel* label) { 745 DCHECK(!label->is_bound()); 746 DCHECK(target.is_bound()); 747 PatchJump(bytecodes()->begin() + target.offset(), 748 bytecodes()->begin() + label->offset()); 749 label->bind_to(target.offset()); 750 LeaveBasicBlock(); 751 return *this; 752 } 753 754 755 // static 756 Bytecode BytecodeArrayBuilder::GetJumpWithConstantOperand( 757 Bytecode jump_bytecode) { 758 switch (jump_bytecode) { 759 case Bytecode::kJump: 760 return Bytecode::kJumpConstant; 761 case Bytecode::kJumpIfTrue: 762 return Bytecode::kJumpIfTrueConstant; 763 case Bytecode::kJumpIfFalse: 764 return Bytecode::kJumpIfFalseConstant; 765 case Bytecode::kJumpIfToBooleanTrue: 766 return Bytecode::kJumpIfToBooleanTrueConstant; 767 case Bytecode::kJumpIfToBooleanFalse: 768 return Bytecode::kJumpIfToBooleanFalseConstant; 769 case Bytecode::kJumpIfNull: 770 return Bytecode::kJumpIfNullConstant; 771 case Bytecode::kJumpIfUndefined: 772 return Bytecode::kJumpIfUndefinedConstant; 773 default: 774 UNREACHABLE(); 775 return static_cast<Bytecode>(-1); 776 } 777 } 778 779 780 // static 781 Bytecode BytecodeArrayBuilder::GetJumpWithConstantWideOperand( 782 Bytecode jump_bytecode) { 783 switch (jump_bytecode) { 784 case Bytecode::kJump: 785 return Bytecode::kJumpConstantWide; 786 case Bytecode::kJumpIfTrue: 787 return Bytecode::kJumpIfTrueConstantWide; 788 case Bytecode::kJumpIfFalse: 789 return Bytecode::kJumpIfFalseConstantWide; 790 case Bytecode::kJumpIfToBooleanTrue: 791 return Bytecode::kJumpIfToBooleanTrueConstantWide; 792 case Bytecode::kJumpIfToBooleanFalse: 793 return Bytecode::kJumpIfToBooleanFalseConstantWide; 794 case Bytecode::kJumpIfNull: 795 return Bytecode::kJumpIfNullConstantWide; 796 case Bytecode::kJumpIfUndefined: 797 return Bytecode::kJumpIfUndefinedConstantWide; 798 default: 799 UNREACHABLE(); 800 return static_cast<Bytecode>(-1); 801 } 802 } 803 804 805 // static 806 Bytecode BytecodeArrayBuilder::GetJumpWithToBoolean(Bytecode jump_bytecode) { 807 switch (jump_bytecode) { 808 case Bytecode::kJump: 809 case Bytecode::kJumpIfNull: 810 case Bytecode::kJumpIfUndefined: 811 return jump_bytecode; 812 case Bytecode::kJumpIfTrue: 813 return Bytecode::kJumpIfToBooleanTrue; 814 case Bytecode::kJumpIfFalse: 815 return Bytecode::kJumpIfToBooleanFalse; 816 default: 817 UNREACHABLE(); 818 } 819 return static_cast<Bytecode>(-1); 820 } 821 822 823 void BytecodeArrayBuilder::PatchIndirectJumpWith8BitOperand( 824 const ZoneVector<uint8_t>::iterator& jump_location, int delta) { 825 Bytecode jump_bytecode = Bytecodes::FromByte(*jump_location); 826 DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode)); 827 ZoneVector<uint8_t>::iterator operand_location = jump_location + 1; 828 DCHECK_EQ(*operand_location, 0); 829 if (FitsInImm8Operand(delta)) { 830 // The jump fits within the range of an Imm8 operand, so cancel 831 // the reservation and jump directly. 832 constant_array_builder()->DiscardReservedEntry(OperandSize::kByte); 833 *operand_location = static_cast<uint8_t>(delta); 834 } else { 835 // The jump does not fit within the range of an Imm8 operand, so 836 // commit reservation putting the offset into the constant pool, 837 // and update the jump instruction and operand. 838 size_t entry = constant_array_builder()->CommitReservedEntry( 839 OperandSize::kByte, handle(Smi::FromInt(delta), isolate())); 840 DCHECK(FitsInIdx8Operand(entry)); 841 jump_bytecode = GetJumpWithConstantOperand(jump_bytecode); 842 *jump_location = Bytecodes::ToByte(jump_bytecode); 843 *operand_location = static_cast<uint8_t>(entry); 844 } 845 } 846 847 848 void BytecodeArrayBuilder::PatchIndirectJumpWith16BitOperand( 849 const ZoneVector<uint8_t>::iterator& jump_location, int delta) { 850 DCHECK(Bytecodes::IsJumpConstantWide(Bytecodes::FromByte(*jump_location))); 851 ZoneVector<uint8_t>::iterator operand_location = jump_location + 1; 852 size_t entry = constant_array_builder()->CommitReservedEntry( 853 OperandSize::kShort, handle(Smi::FromInt(delta), isolate())); 854 DCHECK(FitsInIdx16Operand(entry)); 855 uint8_t operand_bytes[2]; 856 WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(entry)); 857 DCHECK(*operand_location == 0 && *(operand_location + 1) == 0); 858 *operand_location++ = operand_bytes[0]; 859 *operand_location = operand_bytes[1]; 860 } 861 862 863 void BytecodeArrayBuilder::PatchJump( 864 const ZoneVector<uint8_t>::iterator& jump_target, 865 const ZoneVector<uint8_t>::iterator& jump_location) { 866 Bytecode jump_bytecode = Bytecodes::FromByte(*jump_location); 867 int delta = static_cast<int>(jump_target - jump_location); 868 DCHECK(Bytecodes::IsJump(jump_bytecode)); 869 switch (Bytecodes::GetOperandSize(jump_bytecode, 0)) { 870 case OperandSize::kByte: 871 PatchIndirectJumpWith8BitOperand(jump_location, delta); 872 break; 873 case OperandSize::kShort: 874 PatchIndirectJumpWith16BitOperand(jump_location, delta); 875 break; 876 case OperandSize::kNone: 877 UNREACHABLE(); 878 } 879 unbound_jumps_--; 880 } 881 882 883 BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode, 884 BytecodeLabel* label) { 885 // Don't emit dead code. 886 if (exit_seen_in_block_) return *this; 887 888 // Check if the value in accumulator is boolean, if not choose an 889 // appropriate JumpIfToBoolean bytecode. 890 if (NeedToBooleanCast()) { 891 jump_bytecode = GetJumpWithToBoolean(jump_bytecode); 892 } 893 894 if (label->is_bound()) { 895 // Label has been bound already so this is a backwards jump. 896 CHECK_GE(bytecodes()->size(), label->offset()); 897 CHECK_LE(bytecodes()->size(), static_cast<size_t>(kMaxInt)); 898 size_t abs_delta = bytecodes()->size() - label->offset(); 899 int delta = -static_cast<int>(abs_delta); 900 901 if (FitsInImm8Operand(delta)) { 902 Output(jump_bytecode, static_cast<uint8_t>(delta)); 903 } else { 904 size_t entry = 905 GetConstantPoolEntry(handle(Smi::FromInt(delta), isolate())); 906 if (FitsInIdx8Operand(entry)) { 907 Output(GetJumpWithConstantOperand(jump_bytecode), 908 static_cast<uint8_t>(entry)); 909 } else if (FitsInIdx16Operand(entry)) { 910 Output(GetJumpWithConstantWideOperand(jump_bytecode), 911 static_cast<uint16_t>(entry)); 912 } else { 913 UNREACHABLE(); 914 } 915 } 916 } else { 917 // The label has not yet been bound so this is a forward reference 918 // that will be patched when the label is bound. We create a 919 // reservation in the constant pool so the jump can be patched 920 // when the label is bound. The reservation means the maximum size 921 // of the operand for the constant is known and the jump can 922 // be emitted into the bytecode stream with space for the operand. 923 label->set_referrer(bytecodes()->size()); 924 unbound_jumps_++; 925 OperandSize reserved_operand_size = 926 constant_array_builder()->CreateReservedEntry(); 927 switch (reserved_operand_size) { 928 case OperandSize::kByte: 929 Output(jump_bytecode, 0); 930 break; 931 case OperandSize::kShort: 932 Output(GetJumpWithConstantWideOperand(jump_bytecode), 0); 933 break; 934 case OperandSize::kNone: 935 UNREACHABLE(); 936 } 937 } 938 LeaveBasicBlock(); 939 return *this; 940 } 941 942 943 BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) { 944 return OutputJump(Bytecode::kJump, label); 945 } 946 947 948 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfTrue(BytecodeLabel* label) { 949 return OutputJump(Bytecode::kJumpIfTrue, label); 950 } 951 952 953 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(BytecodeLabel* label) { 954 return OutputJump(Bytecode::kJumpIfFalse, label); 955 } 956 957 958 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNull(BytecodeLabel* label) { 959 return OutputJump(Bytecode::kJumpIfNull, label); 960 } 961 962 963 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined( 964 BytecodeLabel* label) { 965 return OutputJump(Bytecode::kJumpIfUndefined, label); 966 } 967 968 969 BytecodeArrayBuilder& BytecodeArrayBuilder::Throw() { 970 Output(Bytecode::kThrow); 971 exit_seen_in_block_ = true; 972 return *this; 973 } 974 975 976 BytecodeArrayBuilder& BytecodeArrayBuilder::Return() { 977 Output(Bytecode::kReturn); 978 exit_seen_in_block_ = true; 979 return *this; 980 } 981 982 983 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInPrepare( 984 Register cache_type, Register cache_array, Register cache_length) { 985 Output(Bytecode::kForInPrepare, cache_type.ToOperand(), 986 cache_array.ToOperand(), cache_length.ToOperand()); 987 return *this; 988 } 989 990 991 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInDone(Register index, 992 Register cache_length) { 993 Output(Bytecode::kForInDone, index.ToOperand(), cache_length.ToOperand()); 994 return *this; 995 } 996 997 998 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext(Register receiver, 999 Register cache_type, 1000 Register cache_array, 1001 Register index) { 1002 Output(Bytecode::kForInNext, receiver.ToOperand(), cache_type.ToOperand(), 1003 cache_array.ToOperand(), index.ToOperand()); 1004 return *this; 1005 } 1006 1007 1008 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) { 1009 Output(Bytecode::kForInStep, index.ToOperand()); 1010 return *this; 1011 } 1012 1013 1014 void BytecodeArrayBuilder::LeaveBasicBlock() { 1015 last_block_end_ = bytecodes()->size(); 1016 exit_seen_in_block_ = false; 1017 } 1018 1019 1020 void BytecodeArrayBuilder::EnsureReturn() { 1021 if (!exit_seen_in_block_) { 1022 LoadUndefined(); 1023 Return(); 1024 } 1025 } 1026 1027 1028 BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, 1029 Register receiver, 1030 size_t arg_count, 1031 int feedback_slot) { 1032 if (FitsInIdx8Operand(arg_count) && FitsInIdx8Operand(feedback_slot)) { 1033 Output(Bytecode::kCall, callable.ToOperand(), receiver.ToOperand(), 1034 static_cast<uint8_t>(arg_count), 1035 static_cast<uint8_t>(feedback_slot)); 1036 } else if (FitsInIdx16Operand(arg_count) && 1037 FitsInIdx16Operand(feedback_slot)) { 1038 Output(Bytecode::kCallWide, callable.ToOperand(), receiver.ToOperand(), 1039 static_cast<uint16_t>(arg_count), 1040 static_cast<uint16_t>(feedback_slot)); 1041 } else { 1042 UNIMPLEMENTED(); 1043 } 1044 return *this; 1045 } 1046 1047 1048 BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor, 1049 Register first_arg, 1050 size_t arg_count) { 1051 if (!first_arg.is_valid()) { 1052 DCHECK_EQ(0u, arg_count); 1053 first_arg = Register(0); 1054 } 1055 DCHECK(FitsInIdx8Operand(arg_count)); 1056 Output(Bytecode::kNew, constructor.ToOperand(), first_arg.ToOperand(), 1057 static_cast<uint8_t>(arg_count)); 1058 return *this; 1059 } 1060 1061 1062 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( 1063 Runtime::FunctionId function_id, Register first_arg, size_t arg_count) { 1064 DCHECK_EQ(1, Runtime::FunctionForId(function_id)->result_size); 1065 DCHECK(FitsInIdx16Operand(function_id)); 1066 DCHECK(FitsInIdx8Operand(arg_count)); 1067 if (!first_arg.is_valid()) { 1068 DCHECK_EQ(0u, arg_count); 1069 first_arg = Register(0); 1070 } 1071 Output(Bytecode::kCallRuntime, static_cast<uint16_t>(function_id), 1072 first_arg.ToOperand(), static_cast<uint8_t>(arg_count)); 1073 return *this; 1074 } 1075 1076 1077 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair( 1078 Runtime::FunctionId function_id, Register first_arg, size_t arg_count, 1079 Register first_return) { 1080 DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size); 1081 DCHECK(FitsInIdx16Operand(function_id)); 1082 DCHECK(FitsInIdx8Operand(arg_count)); 1083 if (!first_arg.is_valid()) { 1084 DCHECK_EQ(0u, arg_count); 1085 first_arg = Register(0); 1086 } 1087 Output(Bytecode::kCallRuntimeForPair, static_cast<uint16_t>(function_id), 1088 first_arg.ToOperand(), static_cast<uint8_t>(arg_count), 1089 first_return.ToOperand()); 1090 return *this; 1091 } 1092 1093 1094 BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime(int context_index, 1095 Register receiver, 1096 size_t arg_count) { 1097 DCHECK(FitsInIdx16Operand(context_index)); 1098 DCHECK(FitsInIdx8Operand(arg_count)); 1099 Output(Bytecode::kCallJSRuntime, static_cast<uint16_t>(context_index), 1100 receiver.ToOperand(), static_cast<uint8_t>(arg_count)); 1101 return *this; 1102 } 1103 1104 1105 BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object, 1106 LanguageMode language_mode) { 1107 Output(BytecodeForDelete(language_mode), object.ToOperand()); 1108 return *this; 1109 } 1110 1111 1112 BytecodeArrayBuilder& BytecodeArrayBuilder::DeleteLookupSlot() { 1113 Output(Bytecode::kDeleteLookupSlot); 1114 return *this; 1115 } 1116 1117 1118 size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) { 1119 return constant_array_builder()->Insert(object); 1120 } 1121 1122 1123 int BytecodeArrayBuilder::BorrowTemporaryRegister() { 1124 if (free_temporaries_.empty()) { 1125 temporary_register_count_ += 1; 1126 return last_temporary_register().index(); 1127 } else { 1128 auto pos = free_temporaries_.begin(); 1129 int retval = *pos; 1130 free_temporaries_.erase(pos); 1131 return retval; 1132 } 1133 } 1134 1135 1136 int BytecodeArrayBuilder::BorrowTemporaryRegisterNotInRange(int start_index, 1137 int end_index) { 1138 auto index = free_temporaries_.lower_bound(start_index); 1139 if (index == free_temporaries_.begin()) { 1140 // If start_index is the first free register, check for a register 1141 // greater than end_index. 1142 index = free_temporaries_.upper_bound(end_index); 1143 if (index == free_temporaries_.end()) { 1144 temporary_register_count_ += 1; 1145 return last_temporary_register().index(); 1146 } 1147 } else { 1148 // If there is a free register < start_index 1149 index--; 1150 } 1151 1152 int retval = *index; 1153 free_temporaries_.erase(index); 1154 return retval; 1155 } 1156 1157 1158 void BytecodeArrayBuilder::BorrowConsecutiveTemporaryRegister(int reg_index) { 1159 DCHECK(free_temporaries_.find(reg_index) != free_temporaries_.end()); 1160 free_temporaries_.erase(reg_index); 1161 } 1162 1163 1164 void BytecodeArrayBuilder::ReturnTemporaryRegister(int reg_index) { 1165 DCHECK(free_temporaries_.find(reg_index) == free_temporaries_.end()); 1166 free_temporaries_.insert(reg_index); 1167 } 1168 1169 1170 int BytecodeArrayBuilder::PrepareForConsecutiveTemporaryRegisters( 1171 size_t count) { 1172 if (count == 0) { 1173 return -1; 1174 } 1175 1176 // Search within existing temporaries for a run. 1177 auto start = free_temporaries_.begin(); 1178 size_t run_length = 0; 1179 for (auto run_end = start; run_end != free_temporaries_.end(); run_end++) { 1180 if (*run_end != *start + static_cast<int>(run_length)) { 1181 start = run_end; 1182 run_length = 0; 1183 } 1184 if (++run_length == count) { 1185 return *start; 1186 } 1187 } 1188 1189 // Continue run if possible across existing last temporary. 1190 if (temporary_register_count_ > 0 && 1191 (start == free_temporaries_.end() || 1192 *start + static_cast<int>(run_length) != 1193 last_temporary_register().index() + 1)) { 1194 run_length = 0; 1195 } 1196 1197 // Ensure enough registers for run. 1198 while (run_length++ < count) { 1199 temporary_register_count_++; 1200 free_temporaries_.insert(last_temporary_register().index()); 1201 } 1202 return last_temporary_register().index() - static_cast<int>(count) + 1; 1203 } 1204 1205 1206 bool BytecodeArrayBuilder::TemporaryRegisterIsLive(Register reg) const { 1207 if (temporary_register_count_ > 0) { 1208 DCHECK(reg.index() >= first_temporary_register().index() && 1209 reg.index() <= last_temporary_register().index()); 1210 return free_temporaries_.find(reg.index()) == free_temporaries_.end(); 1211 } else { 1212 return false; 1213 } 1214 } 1215 1216 1217 bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const { 1218 if (reg.is_function_context() || reg.is_function_closure() || 1219 reg.is_new_target()) { 1220 return true; 1221 } else if (reg.is_parameter()) { 1222 int parameter_index = reg.ToParameterIndex(parameter_count_); 1223 return parameter_index >= 0 && parameter_index < parameter_count_; 1224 } else if (reg.index() < fixed_register_count()) { 1225 return true; 1226 } else { 1227 return TemporaryRegisterIsLive(reg); 1228 } 1229 } 1230 1231 1232 bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, 1233 uint32_t operand_value) const { 1234 OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index); 1235 switch (operand_type) { 1236 case OperandType::kNone: 1237 return false; 1238 case OperandType::kCount16: 1239 case OperandType::kIdx16: 1240 return static_cast<uint16_t>(operand_value) == operand_value; 1241 case OperandType::kCount8: 1242 case OperandType::kImm8: 1243 case OperandType::kIdx8: 1244 return static_cast<uint8_t>(operand_value) == operand_value; 1245 case OperandType::kMaybeReg8: 1246 if (operand_value == 0) { 1247 return true; 1248 } 1249 // Fall-through to kReg8 case. 1250 case OperandType::kReg8: 1251 return RegisterIsValid( 1252 Register::FromOperand(static_cast<uint8_t>(operand_value))); 1253 case OperandType::kRegPair8: { 1254 Register reg0 = 1255 Register::FromOperand(static_cast<uint8_t>(operand_value)); 1256 Register reg1 = Register(reg0.index() + 1); 1257 return RegisterIsValid(reg0) && RegisterIsValid(reg1); 1258 } 1259 case OperandType::kReg16: 1260 if (bytecode != Bytecode::kExchange && 1261 bytecode != Bytecode::kExchangeWide) { 1262 return false; 1263 } 1264 return RegisterIsValid( 1265 Register::FromWideOperand(static_cast<uint16_t>(operand_value))); 1266 } 1267 UNREACHABLE(); 1268 return false; 1269 } 1270 1271 1272 bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const { 1273 return last_bytecode_start_ < bytecodes()->size() && 1274 last_bytecode_start_ >= last_block_end_; 1275 } 1276 1277 1278 bool BytecodeArrayBuilder::IsRegisterInAccumulator(Register reg) { 1279 if (LastBytecodeInSameBlock()) { 1280 PreviousBytecodeHelper previous_bytecode(*this); 1281 Bytecode bytecode = previous_bytecode.GetBytecode(); 1282 if ((bytecode == Bytecode::kLdar || bytecode == Bytecode::kStar) && 1283 (reg == Register::FromOperand(previous_bytecode.GetOperand(0)))) { 1284 return true; 1285 } 1286 } 1287 return false; 1288 } 1289 1290 1291 // static 1292 Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) { 1293 switch (op) { 1294 case Token::Value::ADD: 1295 return Bytecode::kAdd; 1296 case Token::Value::SUB: 1297 return Bytecode::kSub; 1298 case Token::Value::MUL: 1299 return Bytecode::kMul; 1300 case Token::Value::DIV: 1301 return Bytecode::kDiv; 1302 case Token::Value::MOD: 1303 return Bytecode::kMod; 1304 case Token::Value::BIT_OR: 1305 return Bytecode::kBitwiseOr; 1306 case Token::Value::BIT_XOR: 1307 return Bytecode::kBitwiseXor; 1308 case Token::Value::BIT_AND: 1309 return Bytecode::kBitwiseAnd; 1310 case Token::Value::SHL: 1311 return Bytecode::kShiftLeft; 1312 case Token::Value::SAR: 1313 return Bytecode::kShiftRight; 1314 case Token::Value::SHR: 1315 return Bytecode::kShiftRightLogical; 1316 default: 1317 UNREACHABLE(); 1318 return static_cast<Bytecode>(-1); 1319 } 1320 } 1321 1322 1323 // static 1324 Bytecode BytecodeArrayBuilder::BytecodeForCountOperation(Token::Value op) { 1325 switch (op) { 1326 case Token::Value::ADD: 1327 return Bytecode::kInc; 1328 case Token::Value::SUB: 1329 return Bytecode::kDec; 1330 default: 1331 UNREACHABLE(); 1332 return static_cast<Bytecode>(-1); 1333 } 1334 } 1335 1336 1337 // static 1338 Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) { 1339 switch (op) { 1340 case Token::Value::EQ: 1341 return Bytecode::kTestEqual; 1342 case Token::Value::NE: 1343 return Bytecode::kTestNotEqual; 1344 case Token::Value::EQ_STRICT: 1345 return Bytecode::kTestEqualStrict; 1346 case Token::Value::NE_STRICT: 1347 return Bytecode::kTestNotEqualStrict; 1348 case Token::Value::LT: 1349 return Bytecode::kTestLessThan; 1350 case Token::Value::GT: 1351 return Bytecode::kTestGreaterThan; 1352 case Token::Value::LTE: 1353 return Bytecode::kTestLessThanOrEqual; 1354 case Token::Value::GTE: 1355 return Bytecode::kTestGreaterThanOrEqual; 1356 case Token::Value::INSTANCEOF: 1357 return Bytecode::kTestInstanceOf; 1358 case Token::Value::IN: 1359 return Bytecode::kTestIn; 1360 default: 1361 UNREACHABLE(); 1362 return static_cast<Bytecode>(-1); 1363 } 1364 } 1365 1366 1367 // static 1368 Bytecode BytecodeArrayBuilder::BytecodeForWideOperands(Bytecode bytecode) { 1369 switch (bytecode) { 1370 case Bytecode::kLoadICSloppy: 1371 return Bytecode::kLoadICSloppyWide; 1372 case Bytecode::kLoadICStrict: 1373 return Bytecode::kLoadICStrictWide; 1374 case Bytecode::kKeyedLoadICSloppy: 1375 return Bytecode::kKeyedLoadICSloppyWide; 1376 case Bytecode::kKeyedLoadICStrict: 1377 return Bytecode::kKeyedLoadICStrictWide; 1378 case Bytecode::kStoreICSloppy: 1379 return Bytecode::kStoreICSloppyWide; 1380 case Bytecode::kStoreICStrict: 1381 return Bytecode::kStoreICStrictWide; 1382 case Bytecode::kKeyedStoreICSloppy: 1383 return Bytecode::kKeyedStoreICSloppyWide; 1384 case Bytecode::kKeyedStoreICStrict: 1385 return Bytecode::kKeyedStoreICStrictWide; 1386 case Bytecode::kLdaGlobalSloppy: 1387 return Bytecode::kLdaGlobalSloppyWide; 1388 case Bytecode::kLdaGlobalStrict: 1389 return Bytecode::kLdaGlobalStrictWide; 1390 case Bytecode::kLdaGlobalInsideTypeofSloppy: 1391 return Bytecode::kLdaGlobalInsideTypeofSloppyWide; 1392 case Bytecode::kLdaGlobalInsideTypeofStrict: 1393 return Bytecode::kLdaGlobalInsideTypeofStrictWide; 1394 case Bytecode::kStaGlobalSloppy: 1395 return Bytecode::kStaGlobalSloppyWide; 1396 case Bytecode::kStaGlobalStrict: 1397 return Bytecode::kStaGlobalStrictWide; 1398 case Bytecode::kLdaLookupSlot: 1399 return Bytecode::kLdaLookupSlotWide; 1400 case Bytecode::kLdaLookupSlotInsideTypeof: 1401 return Bytecode::kLdaLookupSlotInsideTypeofWide; 1402 case Bytecode::kStaLookupSlotStrict: 1403 return Bytecode::kStaLookupSlotStrictWide; 1404 case Bytecode::kStaLookupSlotSloppy: 1405 return Bytecode::kStaLookupSlotSloppyWide; 1406 default: 1407 UNREACHABLE(); 1408 return static_cast<Bytecode>(-1); 1409 } 1410 } 1411 1412 1413 // static 1414 Bytecode BytecodeArrayBuilder::BytecodeForLoadIC(LanguageMode language_mode) { 1415 switch (language_mode) { 1416 case SLOPPY: 1417 return Bytecode::kLoadICSloppy; 1418 case STRICT: 1419 return Bytecode::kLoadICStrict; 1420 case STRONG: 1421 UNIMPLEMENTED(); 1422 default: 1423 UNREACHABLE(); 1424 } 1425 return static_cast<Bytecode>(-1); 1426 } 1427 1428 1429 // static 1430 Bytecode BytecodeArrayBuilder::BytecodeForKeyedLoadIC( 1431 LanguageMode language_mode) { 1432 switch (language_mode) { 1433 case SLOPPY: 1434 return Bytecode::kKeyedLoadICSloppy; 1435 case STRICT: 1436 return Bytecode::kKeyedLoadICStrict; 1437 case STRONG: 1438 UNIMPLEMENTED(); 1439 default: 1440 UNREACHABLE(); 1441 } 1442 return static_cast<Bytecode>(-1); 1443 } 1444 1445 1446 // static 1447 Bytecode BytecodeArrayBuilder::BytecodeForStoreIC(LanguageMode language_mode) { 1448 switch (language_mode) { 1449 case SLOPPY: 1450 return Bytecode::kStoreICSloppy; 1451 case STRICT: 1452 return Bytecode::kStoreICStrict; 1453 case STRONG: 1454 UNIMPLEMENTED(); 1455 default: 1456 UNREACHABLE(); 1457 } 1458 return static_cast<Bytecode>(-1); 1459 } 1460 1461 1462 // static 1463 Bytecode BytecodeArrayBuilder::BytecodeForKeyedStoreIC( 1464 LanguageMode language_mode) { 1465 switch (language_mode) { 1466 case SLOPPY: 1467 return Bytecode::kKeyedStoreICSloppy; 1468 case STRICT: 1469 return Bytecode::kKeyedStoreICStrict; 1470 case STRONG: 1471 UNIMPLEMENTED(); 1472 default: 1473 UNREACHABLE(); 1474 } 1475 return static_cast<Bytecode>(-1); 1476 } 1477 1478 1479 // static 1480 Bytecode BytecodeArrayBuilder::BytecodeForLoadGlobal(LanguageMode language_mode, 1481 TypeofMode typeof_mode) { 1482 switch (language_mode) { 1483 case SLOPPY: 1484 return typeof_mode == INSIDE_TYPEOF 1485 ? Bytecode::kLdaGlobalInsideTypeofSloppy 1486 : Bytecode::kLdaGlobalSloppy; 1487 case STRICT: 1488 return typeof_mode == INSIDE_TYPEOF 1489 ? Bytecode::kLdaGlobalInsideTypeofStrict 1490 : Bytecode::kLdaGlobalStrict; 1491 case STRONG: 1492 UNIMPLEMENTED(); 1493 default: 1494 UNREACHABLE(); 1495 } 1496 return static_cast<Bytecode>(-1); 1497 } 1498 1499 1500 // static 1501 Bytecode BytecodeArrayBuilder::BytecodeForStoreGlobal( 1502 LanguageMode language_mode) { 1503 switch (language_mode) { 1504 case SLOPPY: 1505 return Bytecode::kStaGlobalSloppy; 1506 case STRICT: 1507 return Bytecode::kStaGlobalStrict; 1508 case STRONG: 1509 UNIMPLEMENTED(); 1510 default: 1511 UNREACHABLE(); 1512 } 1513 return static_cast<Bytecode>(-1); 1514 } 1515 1516 1517 // static 1518 Bytecode BytecodeArrayBuilder::BytecodeForStoreLookupSlot( 1519 LanguageMode language_mode) { 1520 switch (language_mode) { 1521 case SLOPPY: 1522 return Bytecode::kStaLookupSlotSloppy; 1523 case STRICT: 1524 return Bytecode::kStaLookupSlotStrict; 1525 case STRONG: 1526 UNIMPLEMENTED(); 1527 default: 1528 UNREACHABLE(); 1529 } 1530 return static_cast<Bytecode>(-1); 1531 } 1532 1533 1534 // static 1535 Bytecode BytecodeArrayBuilder::BytecodeForCreateArguments( 1536 CreateArgumentsType type) { 1537 switch (type) { 1538 case CreateArgumentsType::kMappedArguments: 1539 return Bytecode::kCreateMappedArguments; 1540 case CreateArgumentsType::kUnmappedArguments: 1541 return Bytecode::kCreateUnmappedArguments; 1542 default: 1543 UNREACHABLE(); 1544 } 1545 return static_cast<Bytecode>(-1); 1546 } 1547 1548 1549 // static 1550 Bytecode BytecodeArrayBuilder::BytecodeForDelete(LanguageMode language_mode) { 1551 switch (language_mode) { 1552 case SLOPPY: 1553 return Bytecode::kDeletePropertySloppy; 1554 case STRICT: 1555 return Bytecode::kDeletePropertyStrict; 1556 case STRONG: 1557 UNIMPLEMENTED(); 1558 default: 1559 UNREACHABLE(); 1560 } 1561 return static_cast<Bytecode>(-1); 1562 } 1563 1564 1565 // static 1566 bool BytecodeArrayBuilder::FitsInIdx8Operand(int value) { 1567 return kMinUInt8 <= value && value <= kMaxUInt8; 1568 } 1569 1570 1571 // static 1572 bool BytecodeArrayBuilder::FitsInIdx8Operand(size_t value) { 1573 return value <= static_cast<size_t>(kMaxUInt8); 1574 } 1575 1576 1577 // static 1578 bool BytecodeArrayBuilder::FitsInImm8Operand(int value) { 1579 return kMinInt8 <= value && value <= kMaxInt8; 1580 } 1581 1582 1583 // static 1584 bool BytecodeArrayBuilder::FitsInIdx16Operand(int value) { 1585 return kMinUInt16 <= value && value <= kMaxUInt16; 1586 } 1587 1588 1589 // static 1590 bool BytecodeArrayBuilder::FitsInIdx16Operand(size_t value) { 1591 return value <= static_cast<size_t>(kMaxUInt16); 1592 } 1593 1594 1595 // static 1596 bool BytecodeArrayBuilder::FitsInReg8Operand(Register value) { 1597 return kMinInt8 <= value.index() && value.index() <= kMaxInt8; 1598 } 1599 1600 1601 // static 1602 bool BytecodeArrayBuilder::FitsInReg16Operand(Register value) { 1603 return kMinInt16 <= value.index() && value.index() <= kMaxInt16; 1604 } 1605 1606 } // namespace interpreter 1607 } // namespace internal 1608 } // namespace v8 1609