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 #include "src/compiler.h" 8 #include "src/interpreter/bytecode-array-writer.h" 9 #include "src/interpreter/bytecode-dead-code-optimizer.h" 10 #include "src/interpreter/bytecode-label.h" 11 #include "src/interpreter/bytecode-peephole-optimizer.h" 12 #include "src/interpreter/bytecode-register-optimizer.h" 13 #include "src/interpreter/interpreter-intrinsics.h" 14 15 namespace v8 { 16 namespace internal { 17 namespace interpreter { 18 19 BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone, 20 int parameter_count, 21 int context_count, int locals_count, 22 FunctionLiteral* literal) 23 : isolate_(isolate), 24 zone_(zone), 25 bytecode_generated_(false), 26 constant_array_builder_(isolate, zone), 27 handler_table_builder_(isolate, zone), 28 return_seen_in_block_(false), 29 parameter_count_(parameter_count), 30 local_register_count_(locals_count), 31 context_register_count_(context_count), 32 temporary_allocator_(zone, fixed_register_count()), 33 bytecode_array_writer_(isolate, zone, &constant_array_builder_), 34 pipeline_(&bytecode_array_writer_) { 35 DCHECK_GE(parameter_count_, 0); 36 DCHECK_GE(context_register_count_, 0); 37 DCHECK_GE(local_register_count_, 0); 38 39 if (FLAG_ignition_deadcode) { 40 pipeline_ = new (zone) BytecodeDeadCodeOptimizer(pipeline_); 41 } 42 43 if (FLAG_ignition_peephole) { 44 pipeline_ = new (zone) 45 BytecodePeepholeOptimizer(&constant_array_builder_, pipeline_); 46 } 47 48 if (FLAG_ignition_reo) { 49 pipeline_ = new (zone) BytecodeRegisterOptimizer( 50 zone, &temporary_allocator_, parameter_count, pipeline_); 51 } 52 53 return_position_ = 54 literal ? std::max(literal->start_position(), literal->end_position() - 1) 55 : RelocInfo::kNoPosition; 56 } 57 58 Register BytecodeArrayBuilder::first_context_register() const { 59 DCHECK_GT(context_register_count_, 0); 60 return Register(local_register_count_); 61 } 62 63 Register BytecodeArrayBuilder::last_context_register() const { 64 DCHECK_GT(context_register_count_, 0); 65 return Register(local_register_count_ + context_register_count_ - 1); 66 } 67 68 Register BytecodeArrayBuilder::Parameter(int parameter_index) const { 69 DCHECK_GE(parameter_index, 0); 70 return Register::FromParameterIndex(parameter_index, parameter_count()); 71 } 72 73 bool BytecodeArrayBuilder::RegisterIsParameterOrLocal(Register reg) const { 74 return reg.is_parameter() || reg.index() < locals_count(); 75 } 76 77 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { 78 DCHECK(return_seen_in_block_); 79 DCHECK(!bytecode_generated_); 80 bytecode_generated_ = true; 81 82 Handle<FixedArray> handler_table = handler_table_builder()->ToHandlerTable(); 83 return pipeline_->ToBytecodeArray(fixed_register_count(), parameter_count(), 84 handler_table); 85 } 86 87 namespace { 88 89 static bool ExpressionPositionIsNeeded(Bytecode bytecode) { 90 // An expression position is always needed if filtering is turned 91 // off. Otherwise an expression is only needed if the bytecode has 92 // external side effects. 93 return !FLAG_ignition_filter_expression_positions || 94 !Bytecodes::IsWithoutExternalSideEffects(bytecode); 95 } 96 97 } // namespace 98 99 void BytecodeArrayBuilder::AttachSourceInfo(BytecodeNode* node) { 100 if (latest_source_info_.is_valid()) { 101 // Statement positions need to be emitted immediately. Expression 102 // positions can be pushed back until a bytecode is found that can 103 // throw. Hence we only invalidate the existing source position 104 // information if it is used. 105 if (latest_source_info_.is_statement() || 106 ExpressionPositionIsNeeded(node->bytecode())) { 107 node->source_info().Clone(latest_source_info_); 108 latest_source_info_.set_invalid(); 109 } 110 } 111 } 112 113 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0, 114 uint32_t operand1, uint32_t operand2, 115 uint32_t operand3) { 116 DCHECK(OperandsAreValid(bytecode, 4, operand0, operand1, operand2, operand3)); 117 BytecodeNode node(bytecode, operand0, operand1, operand2, operand3); 118 AttachSourceInfo(&node); 119 pipeline()->Write(&node); 120 } 121 122 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0, 123 uint32_t operand1, uint32_t operand2) { 124 DCHECK(OperandsAreValid(bytecode, 3, operand0, operand1, operand2)); 125 BytecodeNode node(bytecode, operand0, operand1, operand2); 126 AttachSourceInfo(&node); 127 pipeline()->Write(&node); 128 } 129 130 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0, 131 uint32_t operand1) { 132 DCHECK(OperandsAreValid(bytecode, 2, operand0, operand1)); 133 BytecodeNode node(bytecode, operand0, operand1); 134 AttachSourceInfo(&node); 135 pipeline()->Write(&node); 136 } 137 138 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0) { 139 DCHECK(OperandsAreValid(bytecode, 1, operand0)); 140 BytecodeNode node(bytecode, operand0); 141 AttachSourceInfo(&node); 142 pipeline()->Write(&node); 143 } 144 145 void BytecodeArrayBuilder::Output(Bytecode bytecode) { 146 DCHECK(OperandsAreValid(bytecode, 0)); 147 BytecodeNode node(bytecode); 148 AttachSourceInfo(&node); 149 pipeline()->Write(&node); 150 } 151 152 BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op, 153 Register reg) { 154 Output(BytecodeForBinaryOperation(op), RegisterOperand(reg)); 155 return *this; 156 } 157 158 BytecodeArrayBuilder& BytecodeArrayBuilder::CountOperation(Token::Value op) { 159 Output(BytecodeForCountOperation(op)); 160 return *this; 161 } 162 163 BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot() { 164 Output(Bytecode::kToBooleanLogicalNot); 165 return *this; 166 } 167 168 169 BytecodeArrayBuilder& BytecodeArrayBuilder::TypeOf() { 170 Output(Bytecode::kTypeOf); 171 return *this; 172 } 173 174 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(Token::Value op, 175 Register reg) { 176 Output(BytecodeForCompareOperation(op), RegisterOperand(reg)); 177 return *this; 178 } 179 180 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral( 181 v8::internal::Smi* smi) { 182 int32_t raw_smi = smi->value(); 183 if (raw_smi == 0) { 184 Output(Bytecode::kLdaZero); 185 } else { 186 Output(Bytecode::kLdaSmi, SignedOperand(raw_smi)); 187 } 188 return *this; 189 } 190 191 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) { 192 size_t entry = GetConstantPoolEntry(object); 193 Output(Bytecode::kLdaConstant, UnsignedOperand(entry)); 194 return *this; 195 } 196 197 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() { 198 Output(Bytecode::kLdaUndefined); 199 return *this; 200 } 201 202 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNull() { 203 Output(Bytecode::kLdaNull); 204 return *this; 205 } 206 207 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTheHole() { 208 Output(Bytecode::kLdaTheHole); 209 return *this; 210 } 211 212 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTrue() { 213 Output(Bytecode::kLdaTrue); 214 return *this; 215 } 216 217 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() { 218 Output(Bytecode::kLdaFalse); 219 return *this; 220 } 221 222 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister( 223 Register reg) { 224 Output(Bytecode::kLdar, RegisterOperand(reg)); 225 return *this; 226 } 227 228 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister( 229 Register reg) { 230 Output(Bytecode::kStar, RegisterOperand(reg)); 231 return *this; 232 } 233 234 BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from, 235 Register to) { 236 DCHECK(from != to); 237 Output(Bytecode::kMov, RegisterOperand(from), RegisterOperand(to)); 238 return *this; 239 } 240 241 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(int feedback_slot, 242 TypeofMode typeof_mode) { 243 // TODO(rmcilroy): Potentially store typeof information in an 244 // operand rather than having extra bytecodes. 245 Bytecode bytecode = BytecodeForLoadGlobal(typeof_mode); 246 Output(bytecode, UnsignedOperand(feedback_slot)); 247 return *this; 248 } 249 250 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreGlobal( 251 const Handle<String> name, int feedback_slot, LanguageMode language_mode) { 252 Bytecode bytecode = BytecodeForStoreGlobal(language_mode); 253 size_t name_index = GetConstantPoolEntry(name); 254 Output(bytecode, UnsignedOperand(name_index), UnsignedOperand(feedback_slot)); 255 return *this; 256 } 257 258 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context, 259 int slot_index) { 260 Output(Bytecode::kLdaContextSlot, RegisterOperand(context), 261 UnsignedOperand(slot_index)); 262 return *this; 263 } 264 265 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context, 266 int slot_index) { 267 Output(Bytecode::kStaContextSlot, RegisterOperand(context), 268 UnsignedOperand(slot_index)); 269 return *this; 270 } 271 272 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupSlot( 273 const Handle<String> name, TypeofMode typeof_mode) { 274 Bytecode bytecode = (typeof_mode == INSIDE_TYPEOF) 275 ? Bytecode::kLdaLookupSlotInsideTypeof 276 : Bytecode::kLdaLookupSlot; 277 size_t name_index = GetConstantPoolEntry(name); 278 Output(bytecode, UnsignedOperand(name_index)); 279 return *this; 280 } 281 282 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot( 283 const Handle<String> name, LanguageMode language_mode) { 284 Bytecode bytecode = BytecodeForStoreLookupSlot(language_mode); 285 size_t name_index = GetConstantPoolEntry(name); 286 Output(bytecode, UnsignedOperand(name_index)); 287 return *this; 288 } 289 290 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty( 291 Register object, const Handle<Name> name, int feedback_slot) { 292 size_t name_index = GetConstantPoolEntry(name); 293 Output(Bytecode::kLdaNamedProperty, RegisterOperand(object), 294 UnsignedOperand(name_index), UnsignedOperand(feedback_slot)); 295 return *this; 296 } 297 298 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty( 299 Register object, int feedback_slot) { 300 Output(Bytecode::kLdaKeyedProperty, RegisterOperand(object), 301 UnsignedOperand(feedback_slot)); 302 return *this; 303 } 304 305 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty( 306 Register object, const Handle<Name> name, int feedback_slot, 307 LanguageMode language_mode) { 308 Bytecode bytecode = BytecodeForStoreNamedProperty(language_mode); 309 size_t name_index = GetConstantPoolEntry(name); 310 Output(bytecode, RegisterOperand(object), UnsignedOperand(name_index), 311 UnsignedOperand(feedback_slot)); 312 return *this; 313 } 314 315 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty( 316 Register object, Register key, int feedback_slot, 317 LanguageMode language_mode) { 318 Bytecode bytecode = BytecodeForStoreKeyedProperty(language_mode); 319 Output(bytecode, RegisterOperand(object), RegisterOperand(key), 320 UnsignedOperand(feedback_slot)); 321 return *this; 322 } 323 324 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure( 325 Handle<SharedFunctionInfo> shared_info, PretenureFlag tenured) { 326 size_t entry = GetConstantPoolEntry(shared_info); 327 Output(Bytecode::kCreateClosure, UnsignedOperand(entry), 328 UnsignedOperand(static_cast<size_t>(tenured))); 329 return *this; 330 } 331 332 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments( 333 CreateArgumentsType type) { 334 // TODO(rmcilroy): Consider passing the type as a bytecode operand rather 335 // than having two different bytecodes once we have better support for 336 // branches in the InterpreterAssembler. 337 Bytecode bytecode = BytecodeForCreateArguments(type); 338 Output(bytecode); 339 return *this; 340 } 341 342 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral( 343 Handle<String> pattern, int literal_index, int flags) { 344 size_t pattern_entry = GetConstantPoolEntry(pattern); 345 Output(Bytecode::kCreateRegExpLiteral, UnsignedOperand(pattern_entry), 346 UnsignedOperand(literal_index), UnsignedOperand(flags)); 347 return *this; 348 } 349 350 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral( 351 Handle<FixedArray> constant_elements, int literal_index, int flags) { 352 size_t constant_elements_entry = GetConstantPoolEntry(constant_elements); 353 Output(Bytecode::kCreateArrayLiteral, 354 UnsignedOperand(constant_elements_entry), 355 UnsignedOperand(literal_index), UnsignedOperand(flags)); 356 return *this; 357 } 358 359 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral( 360 Handle<FixedArray> constant_properties, int literal_index, int flags) { 361 size_t constant_properties_entry = GetConstantPoolEntry(constant_properties); 362 Output(Bytecode::kCreateObjectLiteral, 363 UnsignedOperand(constant_properties_entry), 364 UnsignedOperand(literal_index), UnsignedOperand(flags)); 365 return *this; 366 } 367 368 BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) { 369 Output(Bytecode::kPushContext, RegisterOperand(context)); 370 return *this; 371 } 372 373 BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) { 374 Output(Bytecode::kPopContext, RegisterOperand(context)); 375 return *this; 376 } 377 378 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToJSObject() { 379 Output(Bytecode::kToObject); 380 return *this; 381 } 382 383 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() { 384 Output(Bytecode::kToName); 385 return *this; 386 } 387 388 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToNumber() { 389 Output(Bytecode::kToNumber); 390 return *this; 391 } 392 393 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) { 394 pipeline_->BindLabel(label); 395 LeaveBasicBlock(); 396 return *this; 397 } 398 399 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(const BytecodeLabel& target, 400 BytecodeLabel* label) { 401 pipeline_->BindLabel(target, label); 402 LeaveBasicBlock(); 403 return *this; 404 } 405 406 BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode, 407 BytecodeLabel* label) { 408 BytecodeNode node(jump_bytecode, 0); 409 AttachSourceInfo(&node); 410 pipeline_->WriteJump(&node, label); 411 LeaveBasicBlock(); 412 return *this; 413 } 414 415 BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) { 416 return OutputJump(Bytecode::kJump, label); 417 } 418 419 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfTrue(BytecodeLabel* label) { 420 // The peephole optimizer attempts to simplify JumpIfToBooleanTrue 421 // to JumpIfTrue. 422 return OutputJump(Bytecode::kJumpIfToBooleanTrue, label); 423 } 424 425 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(BytecodeLabel* label) { 426 // The peephole optimizer attempts to simplify JumpIfToBooleanFalse 427 // to JumpIfFalse. 428 return OutputJump(Bytecode::kJumpIfToBooleanFalse, label); 429 } 430 431 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNull(BytecodeLabel* label) { 432 return OutputJump(Bytecode::kJumpIfNull, label); 433 } 434 435 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined( 436 BytecodeLabel* label) { 437 return OutputJump(Bytecode::kJumpIfUndefined, label); 438 } 439 440 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotHole( 441 BytecodeLabel* label) { 442 return OutputJump(Bytecode::kJumpIfNotHole, label); 443 } 444 445 BytecodeArrayBuilder& BytecodeArrayBuilder::StackCheck(int position) { 446 if (position != RelocInfo::kNoPosition) { 447 // We need to attach a non-breakable source position to a stack 448 // check, so we simply add it as expression position. There can be 449 // a prior statement position from constructs like: 450 // 451 // do var x; while (false); 452 // 453 // A Nop could be inserted for empty statements, but since no code 454 // is associated with these positions, instead we force the stack 455 // check's expression position which eliminates the empty 456 // statement's position. 457 latest_source_info_.ForceExpressionPosition(position); 458 } 459 Output(Bytecode::kStackCheck); 460 return *this; 461 } 462 463 BytecodeArrayBuilder& BytecodeArrayBuilder::Throw() { 464 Output(Bytecode::kThrow); 465 return *this; 466 } 467 468 BytecodeArrayBuilder& BytecodeArrayBuilder::ReThrow() { 469 Output(Bytecode::kReThrow); 470 return *this; 471 } 472 473 BytecodeArrayBuilder& BytecodeArrayBuilder::Return() { 474 SetReturnPosition(); 475 Output(Bytecode::kReturn); 476 return_seen_in_block_ = true; 477 return *this; 478 } 479 480 BytecodeArrayBuilder& BytecodeArrayBuilder::Debugger() { 481 Output(Bytecode::kDebugger); 482 return *this; 483 } 484 485 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInPrepare( 486 Register cache_info_triple) { 487 Output(Bytecode::kForInPrepare, RegisterOperand(cache_info_triple)); 488 return *this; 489 } 490 491 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInDone(Register index, 492 Register cache_length) { 493 Output(Bytecode::kForInDone, RegisterOperand(index), 494 RegisterOperand(cache_length)); 495 return *this; 496 } 497 498 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext( 499 Register receiver, Register index, Register cache_type_array_pair, 500 int feedback_slot) { 501 Output(Bytecode::kForInNext, RegisterOperand(receiver), 502 RegisterOperand(index), RegisterOperand(cache_type_array_pair), 503 UnsignedOperand(feedback_slot)); 504 return *this; 505 } 506 507 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) { 508 Output(Bytecode::kForInStep, RegisterOperand(index)); 509 return *this; 510 } 511 512 BytecodeArrayBuilder& BytecodeArrayBuilder::SuspendGenerator( 513 Register generator) { 514 Output(Bytecode::kSuspendGenerator, RegisterOperand(generator)); 515 return *this; 516 } 517 518 BytecodeArrayBuilder& BytecodeArrayBuilder::ResumeGenerator( 519 Register generator) { 520 Output(Bytecode::kResumeGenerator, RegisterOperand(generator)); 521 return *this; 522 } 523 524 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkHandler(int handler_id, 525 bool will_catch) { 526 BytecodeLabel handler; 527 Bind(&handler); 528 handler_table_builder()->SetHandlerTarget(handler_id, handler.offset()); 529 handler_table_builder()->SetPrediction(handler_id, will_catch); 530 return *this; 531 } 532 533 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryBegin(int handler_id, 534 Register context) { 535 BytecodeLabel try_begin; 536 Bind(&try_begin); 537 handler_table_builder()->SetTryRegionStart(handler_id, try_begin.offset()); 538 handler_table_builder()->SetContextRegister(handler_id, context); 539 return *this; 540 } 541 542 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryEnd(int handler_id) { 543 BytecodeLabel try_end; 544 Bind(&try_end); 545 handler_table_builder()->SetTryRegionEnd(handler_id, try_end.offset()); 546 return *this; 547 } 548 549 void BytecodeArrayBuilder::EnsureReturn() { 550 if (!return_seen_in_block_) { 551 LoadUndefined(); 552 Return(); 553 } 554 DCHECK(return_seen_in_block_); 555 } 556 557 BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, 558 Register receiver_args, 559 size_t receiver_args_count, 560 int feedback_slot, 561 TailCallMode tail_call_mode) { 562 Bytecode bytecode = BytecodeForCall(tail_call_mode); 563 Output(bytecode, RegisterOperand(callable), RegisterOperand(receiver_args), 564 UnsignedOperand(receiver_args_count), UnsignedOperand(feedback_slot)); 565 return *this; 566 } 567 568 BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor, 569 Register first_arg, 570 size_t arg_count) { 571 if (!first_arg.is_valid()) { 572 DCHECK_EQ(0u, arg_count); 573 first_arg = Register(0); 574 } 575 Output(Bytecode::kNew, RegisterOperand(constructor), 576 RegisterOperand(first_arg), UnsignedOperand(arg_count)); 577 return *this; 578 } 579 580 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( 581 Runtime::FunctionId function_id, Register first_arg, size_t arg_count) { 582 DCHECK_EQ(1, Runtime::FunctionForId(function_id)->result_size); 583 DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort); 584 if (!first_arg.is_valid()) { 585 DCHECK_EQ(0u, arg_count); 586 first_arg = Register(0); 587 } 588 Bytecode bytecode; 589 uint32_t id; 590 if (IntrinsicsHelper::IsSupported(function_id)) { 591 bytecode = Bytecode::kInvokeIntrinsic; 592 id = static_cast<uint32_t>(IntrinsicsHelper::FromRuntimeId(function_id)); 593 } else { 594 bytecode = Bytecode::kCallRuntime; 595 id = static_cast<uint32_t>(function_id); 596 } 597 Output(bytecode, id, RegisterOperand(first_arg), UnsignedOperand(arg_count)); 598 return *this; 599 } 600 601 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair( 602 Runtime::FunctionId function_id, Register first_arg, size_t arg_count, 603 Register first_return) { 604 DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size); 605 DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort); 606 if (!first_arg.is_valid()) { 607 DCHECK_EQ(0u, arg_count); 608 first_arg = Register(0); 609 } 610 Output(Bytecode::kCallRuntimeForPair, static_cast<uint16_t>(function_id), 611 RegisterOperand(first_arg), UnsignedOperand(arg_count), 612 RegisterOperand(first_return)); 613 return *this; 614 } 615 616 BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime( 617 int context_index, Register receiver_args, size_t receiver_args_count) { 618 Output(Bytecode::kCallJSRuntime, UnsignedOperand(context_index), 619 RegisterOperand(receiver_args), UnsignedOperand(receiver_args_count)); 620 return *this; 621 } 622 623 BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object, 624 LanguageMode language_mode) { 625 Output(BytecodeForDelete(language_mode), RegisterOperand(object)); 626 return *this; 627 } 628 629 size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) { 630 return constant_array_builder()->Insert(object); 631 } 632 633 void BytecodeArrayBuilder::SetReturnPosition() { 634 if (return_position_ == RelocInfo::kNoPosition) return; 635 latest_source_info_.MakeStatementPosition(return_position_); 636 } 637 638 void BytecodeArrayBuilder::SetStatementPosition(Statement* stmt) { 639 if (stmt->position() == RelocInfo::kNoPosition) return; 640 latest_source_info_.MakeStatementPosition(stmt->position()); 641 } 642 643 void BytecodeArrayBuilder::SetExpressionPosition(Expression* expr) { 644 if (expr->position() == RelocInfo::kNoPosition) return; 645 if (!latest_source_info_.is_statement()) { 646 // Ensure the current expression position is overwritten with the 647 // latest value. 648 latest_source_info_.MakeExpressionPosition(expr->position()); 649 } 650 } 651 652 void BytecodeArrayBuilder::SetExpressionAsStatementPosition(Expression* expr) { 653 if (expr->position() == RelocInfo::kNoPosition) return; 654 latest_source_info_.MakeStatementPosition(expr->position()); 655 } 656 657 bool BytecodeArrayBuilder::TemporaryRegisterIsLive(Register reg) const { 658 return temporary_register_allocator()->RegisterIsLive(reg); 659 } 660 661 bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const { 662 if (!reg.is_valid()) { 663 return false; 664 } 665 666 if (reg.is_current_context() || reg.is_function_closure() || 667 reg.is_new_target()) { 668 return true; 669 } else if (reg.is_parameter()) { 670 int parameter_index = reg.ToParameterIndex(parameter_count()); 671 return parameter_index >= 0 && parameter_index < parameter_count(); 672 } else if (reg.index() < fixed_register_count()) { 673 return true; 674 } else { 675 return TemporaryRegisterIsLive(reg); 676 } 677 } 678 679 bool BytecodeArrayBuilder::OperandsAreValid( 680 Bytecode bytecode, int operand_count, uint32_t operand0, uint32_t operand1, 681 uint32_t operand2, uint32_t operand3) const { 682 if (Bytecodes::NumberOfOperands(bytecode) != operand_count) { 683 return false; 684 } 685 686 uint32_t operands[] = {operand0, operand1, operand2, operand3}; 687 const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode); 688 for (int i = 0; i < operand_count; ++i) { 689 switch (operand_types[i]) { 690 case OperandType::kNone: 691 return false; 692 case OperandType::kRegCount: { 693 CHECK_NE(i, 0); 694 CHECK(operand_types[i - 1] == OperandType::kMaybeReg || 695 operand_types[i - 1] == OperandType::kReg); 696 if (i > 0 && operands[i] > 0) { 697 Register start = Register::FromOperand(operands[i - 1]); 698 Register end(start.index() + static_cast<int>(operands[i]) - 1); 699 if (!RegisterIsValid(start) || !RegisterIsValid(end) || start > end) { 700 return false; 701 } 702 } 703 break; 704 } 705 case OperandType::kFlag8: 706 case OperandType::kIntrinsicId: 707 if (Bytecodes::SizeForUnsignedOperand(operands[i]) > 708 OperandSize::kByte) { 709 return false; 710 } 711 break; 712 case OperandType::kRuntimeId: 713 if (Bytecodes::SizeForUnsignedOperand(operands[i]) > 714 OperandSize::kShort) { 715 return false; 716 } 717 break; 718 case OperandType::kIdx: 719 // TODO(oth): Consider splitting OperandType::kIdx into two 720 // operand types. One which is a constant pool index that can 721 // be checked, and the other is an unsigned value. 722 break; 723 case OperandType::kImm: 724 break; 725 case OperandType::kMaybeReg: 726 if (Register::FromOperand(operands[i]) == Register(0)) { 727 break; 728 } 729 // Fall-through to kReg case. 730 case OperandType::kReg: 731 case OperandType::kRegOut: { 732 Register reg = Register::FromOperand(operands[i]); 733 if (!RegisterIsValid(reg)) { 734 return false; 735 } 736 break; 737 } 738 case OperandType::kRegOutPair: 739 case OperandType::kRegPair: { 740 Register reg0 = Register::FromOperand(operands[i]); 741 Register reg1 = Register(reg0.index() + 1); 742 if (!RegisterIsValid(reg0) || !RegisterIsValid(reg1)) { 743 return false; 744 } 745 break; 746 } 747 case OperandType::kRegOutTriple: { 748 Register reg0 = Register::FromOperand(operands[i]); 749 Register reg1 = Register(reg0.index() + 1); 750 Register reg2 = Register(reg0.index() + 2); 751 if (!RegisterIsValid(reg0) || !RegisterIsValid(reg1) || 752 !RegisterIsValid(reg2)) { 753 return false; 754 } 755 break; 756 } 757 } 758 } 759 760 return true; 761 } 762 763 // static 764 Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) { 765 switch (op) { 766 case Token::Value::ADD: 767 return Bytecode::kAdd; 768 case Token::Value::SUB: 769 return Bytecode::kSub; 770 case Token::Value::MUL: 771 return Bytecode::kMul; 772 case Token::Value::DIV: 773 return Bytecode::kDiv; 774 case Token::Value::MOD: 775 return Bytecode::kMod; 776 case Token::Value::BIT_OR: 777 return Bytecode::kBitwiseOr; 778 case Token::Value::BIT_XOR: 779 return Bytecode::kBitwiseXor; 780 case Token::Value::BIT_AND: 781 return Bytecode::kBitwiseAnd; 782 case Token::Value::SHL: 783 return Bytecode::kShiftLeft; 784 case Token::Value::SAR: 785 return Bytecode::kShiftRight; 786 case Token::Value::SHR: 787 return Bytecode::kShiftRightLogical; 788 default: 789 UNREACHABLE(); 790 return Bytecode::kIllegal; 791 } 792 } 793 794 // static 795 Bytecode BytecodeArrayBuilder::BytecodeForCountOperation(Token::Value op) { 796 switch (op) { 797 case Token::Value::ADD: 798 return Bytecode::kInc; 799 case Token::Value::SUB: 800 return Bytecode::kDec; 801 default: 802 UNREACHABLE(); 803 return Bytecode::kIllegal; 804 } 805 } 806 807 // static 808 Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) { 809 switch (op) { 810 case Token::Value::EQ: 811 return Bytecode::kTestEqual; 812 case Token::Value::NE: 813 return Bytecode::kTestNotEqual; 814 case Token::Value::EQ_STRICT: 815 return Bytecode::kTestEqualStrict; 816 case Token::Value::LT: 817 return Bytecode::kTestLessThan; 818 case Token::Value::GT: 819 return Bytecode::kTestGreaterThan; 820 case Token::Value::LTE: 821 return Bytecode::kTestLessThanOrEqual; 822 case Token::Value::GTE: 823 return Bytecode::kTestGreaterThanOrEqual; 824 case Token::Value::INSTANCEOF: 825 return Bytecode::kTestInstanceOf; 826 case Token::Value::IN: 827 return Bytecode::kTestIn; 828 default: 829 UNREACHABLE(); 830 return Bytecode::kIllegal; 831 } 832 } 833 834 // static 835 Bytecode BytecodeArrayBuilder::BytecodeForStoreNamedProperty( 836 LanguageMode language_mode) { 837 switch (language_mode) { 838 case SLOPPY: 839 return Bytecode::kStaNamedPropertySloppy; 840 case STRICT: 841 return Bytecode::kStaNamedPropertyStrict; 842 default: 843 UNREACHABLE(); 844 } 845 return Bytecode::kIllegal; 846 } 847 848 // static 849 Bytecode BytecodeArrayBuilder::BytecodeForStoreKeyedProperty( 850 LanguageMode language_mode) { 851 switch (language_mode) { 852 case SLOPPY: 853 return Bytecode::kStaKeyedPropertySloppy; 854 case STRICT: 855 return Bytecode::kStaKeyedPropertyStrict; 856 default: 857 UNREACHABLE(); 858 } 859 return Bytecode::kIllegal; 860 } 861 862 // static 863 Bytecode BytecodeArrayBuilder::BytecodeForLoadGlobal(TypeofMode typeof_mode) { 864 return typeof_mode == INSIDE_TYPEOF ? Bytecode::kLdaGlobalInsideTypeof 865 : Bytecode::kLdaGlobal; 866 } 867 868 // static 869 Bytecode BytecodeArrayBuilder::BytecodeForStoreGlobal( 870 LanguageMode language_mode) { 871 switch (language_mode) { 872 case SLOPPY: 873 return Bytecode::kStaGlobalSloppy; 874 case STRICT: 875 return Bytecode::kStaGlobalStrict; 876 default: 877 UNREACHABLE(); 878 } 879 return Bytecode::kIllegal; 880 } 881 882 // static 883 Bytecode BytecodeArrayBuilder::BytecodeForStoreLookupSlot( 884 LanguageMode language_mode) { 885 switch (language_mode) { 886 case SLOPPY: 887 return Bytecode::kStaLookupSlotSloppy; 888 case STRICT: 889 return Bytecode::kStaLookupSlotStrict; 890 default: 891 UNREACHABLE(); 892 } 893 return Bytecode::kIllegal; 894 } 895 896 // static 897 Bytecode BytecodeArrayBuilder::BytecodeForCreateArguments( 898 CreateArgumentsType type) { 899 switch (type) { 900 case CreateArgumentsType::kMappedArguments: 901 return Bytecode::kCreateMappedArguments; 902 case CreateArgumentsType::kUnmappedArguments: 903 return Bytecode::kCreateUnmappedArguments; 904 case CreateArgumentsType::kRestParameter: 905 return Bytecode::kCreateRestParameter; 906 } 907 UNREACHABLE(); 908 return Bytecode::kIllegal; 909 } 910 911 // static 912 Bytecode BytecodeArrayBuilder::BytecodeForDelete(LanguageMode language_mode) { 913 switch (language_mode) { 914 case SLOPPY: 915 return Bytecode::kDeletePropertySloppy; 916 case STRICT: 917 return Bytecode::kDeletePropertyStrict; 918 default: 919 UNREACHABLE(); 920 } 921 return Bytecode::kIllegal; 922 } 923 924 // static 925 Bytecode BytecodeArrayBuilder::BytecodeForCall(TailCallMode tail_call_mode) { 926 switch (tail_call_mode) { 927 case TailCallMode::kDisallow: 928 return Bytecode::kCall; 929 case TailCallMode::kAllow: 930 return Bytecode::kTailCall; 931 default: 932 UNREACHABLE(); 933 } 934 return Bytecode::kIllegal; 935 } 936 937 } // namespace interpreter 938 } // namespace internal 939 } // namespace v8 940