OLD | NEW |
(Empty) | |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are |
| 4 // met: |
| 5 // |
| 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. |
| 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 |
| 28 #include "v8.h" |
| 29 |
| 30 #include "lithium-allocator-inl.h" |
| 31 #include "mips/lithium-mips.h" |
| 32 #include "mips/lithium-codegen-mips.h" |
| 33 |
| 34 namespace v8 { |
| 35 namespace internal { |
| 36 |
| 37 #define DEFINE_COMPILE(type) \ |
| 38 void L##type::CompileToNative(LCodeGen* generator) { \ |
| 39 generator->Do##type(this); \ |
| 40 } |
| 41 LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE) |
| 42 #undef DEFINE_COMPILE |
| 43 |
| 44 LOsrEntry::LOsrEntry() { |
| 45 for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) { |
| 46 register_spills_[i] = NULL; |
| 47 } |
| 48 for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; ++i) { |
| 49 double_register_spills_[i] = NULL; |
| 50 } |
| 51 } |
| 52 |
| 53 |
| 54 void LOsrEntry::MarkSpilledRegister(int allocation_index, |
| 55 LOperand* spill_operand) { |
| 56 ASSERT(spill_operand->IsStackSlot()); |
| 57 ASSERT(register_spills_[allocation_index] == NULL); |
| 58 register_spills_[allocation_index] = spill_operand; |
| 59 } |
| 60 |
| 61 |
| 62 #ifdef DEBUG |
| 63 void LInstruction::VerifyCall() { |
| 64 // Call instructions can use only fixed registers as temporaries and |
| 65 // outputs because all registers are blocked by the calling convention. |
| 66 // Inputs operands must use a fixed register or use-at-start policy or |
| 67 // a non-register policy. |
| 68 ASSERT(Output() == NULL || |
| 69 LUnallocated::cast(Output())->HasFixedPolicy() || |
| 70 !LUnallocated::cast(Output())->HasRegisterPolicy()); |
| 71 for (UseIterator it(this); !it.Done(); it.Advance()) { |
| 72 LUnallocated* operand = LUnallocated::cast(it.Current()); |
| 73 ASSERT(operand->HasFixedPolicy() || |
| 74 operand->IsUsedAtStart()); |
| 75 } |
| 76 for (TempIterator it(this); !it.Done(); it.Advance()) { |
| 77 LUnallocated* operand = LUnallocated::cast(it.Current()); |
| 78 ASSERT(operand->HasFixedPolicy() ||!operand->HasRegisterPolicy()); |
| 79 } |
| 80 } |
| 81 #endif |
| 82 |
| 83 |
| 84 void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index, |
| 85 LOperand* spill_operand) { |
| 86 ASSERT(spill_operand->IsDoubleStackSlot()); |
| 87 ASSERT(double_register_spills_[allocation_index] == NULL); |
| 88 double_register_spills_[allocation_index] = spill_operand; |
| 89 } |
| 90 |
| 91 |
| 92 void LInstruction::PrintTo(StringStream* stream) { |
| 93 stream->Add("%s ", this->Mnemonic()); |
| 94 |
| 95 PrintOutputOperandTo(stream); |
| 96 |
| 97 PrintDataTo(stream); |
| 98 |
| 99 if (HasEnvironment()) { |
| 100 stream->Add(" "); |
| 101 environment()->PrintTo(stream); |
| 102 } |
| 103 |
| 104 if (HasPointerMap()) { |
| 105 stream->Add(" "); |
| 106 pointer_map()->PrintTo(stream); |
| 107 } |
| 108 } |
| 109 |
| 110 |
| 111 template<int R, int I, int T> |
| 112 void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) { |
| 113 stream->Add("= "); |
| 114 for (int i = 0; i < inputs_.length(); i++) { |
| 115 if (i > 0) stream->Add(" "); |
| 116 inputs_[i]->PrintTo(stream); |
| 117 } |
| 118 } |
| 119 |
| 120 |
| 121 template<int R, int I, int T> |
| 122 void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) { |
| 123 for (int i = 0; i < results_.length(); i++) { |
| 124 if (i > 0) stream->Add(" "); |
| 125 results_[i]->PrintTo(stream); |
| 126 } |
| 127 } |
| 128 |
| 129 |
| 130 void LLabel::PrintDataTo(StringStream* stream) { |
| 131 LGap::PrintDataTo(stream); |
| 132 LLabel* rep = replacement(); |
| 133 if (rep != NULL) { |
| 134 stream->Add(" Dead block replaced with B%d", rep->block_id()); |
| 135 } |
| 136 } |
| 137 |
| 138 |
| 139 bool LGap::IsRedundant() const { |
| 140 for (int i = 0; i < 4; i++) { |
| 141 if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) { |
| 142 return false; |
| 143 } |
| 144 } |
| 145 |
| 146 return true; |
| 147 } |
| 148 |
| 149 |
| 150 void LGap::PrintDataTo(StringStream* stream) { |
| 151 for (int i = 0; i < 4; i++) { |
| 152 stream->Add("("); |
| 153 if (parallel_moves_[i] != NULL) { |
| 154 parallel_moves_[i]->PrintDataTo(stream); |
| 155 } |
| 156 stream->Add(") "); |
| 157 } |
| 158 } |
| 159 |
| 160 |
| 161 const char* LArithmeticD::Mnemonic() const { |
| 162 switch (op()) { |
| 163 case Token::ADD: return "add-d"; |
| 164 case Token::SUB: return "sub-d"; |
| 165 case Token::MUL: return "mul-d"; |
| 166 case Token::DIV: return "div-d"; |
| 167 case Token::MOD: return "mod-d"; |
| 168 default: |
| 169 UNREACHABLE(); |
| 170 return NULL; |
| 171 } |
| 172 } |
| 173 |
| 174 |
| 175 const char* LArithmeticT::Mnemonic() const { |
| 176 switch (op()) { |
| 177 case Token::ADD: return "add-t"; |
| 178 case Token::SUB: return "sub-t"; |
| 179 case Token::MUL: return "mul-t"; |
| 180 case Token::MOD: return "mod-t"; |
| 181 case Token::DIV: return "div-t"; |
| 182 case Token::BIT_AND: return "bit-and-t"; |
| 183 case Token::BIT_OR: return "bit-or-t"; |
| 184 case Token::BIT_XOR: return "bit-xor-t"; |
| 185 case Token::SHL: return "sll-t"; |
| 186 case Token::SAR: return "sra-t"; |
| 187 case Token::SHR: return "srl-t"; |
| 188 default: |
| 189 UNREACHABLE(); |
| 190 return NULL; |
| 191 } |
| 192 } |
| 193 |
| 194 |
| 195 void LGoto::PrintDataTo(StringStream* stream) { |
| 196 stream->Add("B%d", block_id()); |
| 197 } |
| 198 |
| 199 |
| 200 void LBranch::PrintDataTo(StringStream* stream) { |
| 201 stream->Add("B%d | B%d on ", true_block_id(), false_block_id()); |
| 202 InputAt(0)->PrintTo(stream); |
| 203 } |
| 204 |
| 205 |
| 206 void LCmpIDAndBranch::PrintDataTo(StringStream* stream) { |
| 207 stream->Add("if "); |
| 208 InputAt(0)->PrintTo(stream); |
| 209 stream->Add(" %s ", Token::String(op())); |
| 210 InputAt(1)->PrintTo(stream); |
| 211 stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); |
| 212 } |
| 213 |
| 214 |
| 215 void LIsNilAndBranch::PrintDataTo(StringStream* stream) { |
| 216 stream->Add("if "); |
| 217 InputAt(0)->PrintTo(stream); |
| 218 stream->Add(kind() == kStrictEquality ? " === " : " == "); |
| 219 stream->Add(nil() == kNullValue ? "null" : "undefined"); |
| 220 stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); |
| 221 } |
| 222 |
| 223 |
| 224 void LIsObjectAndBranch::PrintDataTo(StringStream* stream) { |
| 225 stream->Add("if is_object("); |
| 226 InputAt(0)->PrintTo(stream); |
| 227 stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); |
| 228 } |
| 229 |
| 230 |
| 231 void LIsSmiAndBranch::PrintDataTo(StringStream* stream) { |
| 232 stream->Add("if is_smi("); |
| 233 InputAt(0)->PrintTo(stream); |
| 234 stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); |
| 235 } |
| 236 |
| 237 |
| 238 void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) { |
| 239 stream->Add("if is_undetectable("); |
| 240 InputAt(0)->PrintTo(stream); |
| 241 stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); |
| 242 } |
| 243 |
| 244 |
| 245 void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { |
| 246 stream->Add("if has_instance_type("); |
| 247 InputAt(0)->PrintTo(stream); |
| 248 stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); |
| 249 } |
| 250 |
| 251 |
| 252 void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) { |
| 253 stream->Add("if has_cached_array_index("); |
| 254 InputAt(0)->PrintTo(stream); |
| 255 stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); |
| 256 } |
| 257 |
| 258 |
| 259 void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { |
| 260 stream->Add("if class_of_test("); |
| 261 InputAt(0)->PrintTo(stream); |
| 262 stream->Add(", \"%o\") then B%d else B%d", |
| 263 *hydrogen()->class_name(), |
| 264 true_block_id(), |
| 265 false_block_id()); |
| 266 } |
| 267 |
| 268 |
| 269 void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { |
| 270 stream->Add("if typeof "); |
| 271 InputAt(0)->PrintTo(stream); |
| 272 stream->Add(" == \"%s\" then B%d else B%d", |
| 273 *hydrogen()->type_literal()->ToCString(), |
| 274 true_block_id(), false_block_id()); |
| 275 } |
| 276 |
| 277 |
| 278 void LCallConstantFunction::PrintDataTo(StringStream* stream) { |
| 279 stream->Add("#%d / ", arity()); |
| 280 } |
| 281 |
| 282 |
| 283 void LUnaryMathOperation::PrintDataTo(StringStream* stream) { |
| 284 stream->Add("/%s ", hydrogen()->OpName()); |
| 285 InputAt(0)->PrintTo(stream); |
| 286 } |
| 287 |
| 288 |
| 289 void LLoadContextSlot::PrintDataTo(StringStream* stream) { |
| 290 InputAt(0)->PrintTo(stream); |
| 291 stream->Add("[%d]", slot_index()); |
| 292 } |
| 293 |
| 294 |
| 295 void LStoreContextSlot::PrintDataTo(StringStream* stream) { |
| 296 InputAt(0)->PrintTo(stream); |
| 297 stream->Add("[%d] <- ", slot_index()); |
| 298 InputAt(1)->PrintTo(stream); |
| 299 } |
| 300 |
| 301 |
| 302 void LInvokeFunction::PrintDataTo(StringStream* stream) { |
| 303 stream->Add("= "); |
| 304 InputAt(0)->PrintTo(stream); |
| 305 stream->Add(" #%d / ", arity()); |
| 306 } |
| 307 |
| 308 |
| 309 void LCallKeyed::PrintDataTo(StringStream* stream) { |
| 310 stream->Add("[a2] #%d / ", arity()); |
| 311 } |
| 312 |
| 313 |
| 314 void LCallNamed::PrintDataTo(StringStream* stream) { |
| 315 SmartArrayPointer<char> name_string = name()->ToCString(); |
| 316 stream->Add("%s #%d / ", *name_string, arity()); |
| 317 } |
| 318 |
| 319 |
| 320 void LCallGlobal::PrintDataTo(StringStream* stream) { |
| 321 SmartArrayPointer<char> name_string = name()->ToCString(); |
| 322 stream->Add("%s #%d / ", *name_string, arity()); |
| 323 } |
| 324 |
| 325 |
| 326 void LCallKnownGlobal::PrintDataTo(StringStream* stream) { |
| 327 stream->Add("#%d / ", arity()); |
| 328 } |
| 329 |
| 330 |
| 331 void LCallNew::PrintDataTo(StringStream* stream) { |
| 332 stream->Add("= "); |
| 333 InputAt(0)->PrintTo(stream); |
| 334 stream->Add(" #%d / ", arity()); |
| 335 } |
| 336 |
| 337 |
| 338 void LAccessArgumentsAt::PrintDataTo(StringStream* stream) { |
| 339 arguments()->PrintTo(stream); |
| 340 |
| 341 stream->Add(" length "); |
| 342 length()->PrintTo(stream); |
| 343 |
| 344 stream->Add(" index "); |
| 345 index()->PrintTo(stream); |
| 346 } |
| 347 |
| 348 |
| 349 void LStoreNamedField::PrintDataTo(StringStream* stream) { |
| 350 object()->PrintTo(stream); |
| 351 stream->Add("."); |
| 352 stream->Add(*String::cast(*name())->ToCString()); |
| 353 stream->Add(" <- "); |
| 354 value()->PrintTo(stream); |
| 355 } |
| 356 |
| 357 |
| 358 void LStoreNamedGeneric::PrintDataTo(StringStream* stream) { |
| 359 object()->PrintTo(stream); |
| 360 stream->Add("."); |
| 361 stream->Add(*String::cast(*name())->ToCString()); |
| 362 stream->Add(" <- "); |
| 363 value()->PrintTo(stream); |
| 364 } |
| 365 |
| 366 |
| 367 void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) { |
| 368 object()->PrintTo(stream); |
| 369 stream->Add("["); |
| 370 key()->PrintTo(stream); |
| 371 stream->Add("] <- "); |
| 372 value()->PrintTo(stream); |
| 373 } |
| 374 |
| 375 |
| 376 void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) { |
| 377 elements()->PrintTo(stream); |
| 378 stream->Add("["); |
| 379 key()->PrintTo(stream); |
| 380 stream->Add("] <- "); |
| 381 value()->PrintTo(stream); |
| 382 } |
| 383 |
| 384 |
| 385 void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) { |
| 386 object()->PrintTo(stream); |
| 387 stream->Add("["); |
| 388 key()->PrintTo(stream); |
| 389 stream->Add("] <- "); |
| 390 value()->PrintTo(stream); |
| 391 } |
| 392 |
| 393 |
| 394 LChunk::LChunk(CompilationInfo* info, HGraph* graph) |
| 395 : spill_slot_count_(0), |
| 396 info_(info), |
| 397 graph_(graph), |
| 398 instructions_(32), |
| 399 pointer_maps_(8), |
| 400 inlined_closures_(1) { |
| 401 } |
| 402 |
| 403 |
| 404 int LChunk::GetNextSpillIndex(bool is_double) { |
| 405 // Skip a slot if for a double-width slot. |
| 406 if (is_double) spill_slot_count_++; |
| 407 return spill_slot_count_++; |
| 408 } |
| 409 |
| 410 |
| 411 LOperand* LChunk::GetNextSpillSlot(bool is_double) { |
| 412 int index = GetNextSpillIndex(is_double); |
| 413 if (is_double) { |
| 414 return LDoubleStackSlot::Create(index); |
| 415 } else { |
| 416 return LStackSlot::Create(index); |
| 417 } |
| 418 } |
| 419 |
| 420 |
| 421 void LChunk::MarkEmptyBlocks() { |
| 422 HPhase phase("Mark empty blocks", this); |
| 423 for (int i = 0; i < graph()->blocks()->length(); ++i) { |
| 424 HBasicBlock* block = graph()->blocks()->at(i); |
| 425 int first = block->first_instruction_index(); |
| 426 int last = block->last_instruction_index(); |
| 427 LInstruction* first_instr = instructions()->at(first); |
| 428 LInstruction* last_instr = instructions()->at(last); |
| 429 |
| 430 LLabel* label = LLabel::cast(first_instr); |
| 431 if (last_instr->IsGoto()) { |
| 432 LGoto* goto_instr = LGoto::cast(last_instr); |
| 433 if (label->IsRedundant() && |
| 434 !label->is_loop_header()) { |
| 435 bool can_eliminate = true; |
| 436 for (int i = first + 1; i < last && can_eliminate; ++i) { |
| 437 LInstruction* cur = instructions()->at(i); |
| 438 if (cur->IsGap()) { |
| 439 LGap* gap = LGap::cast(cur); |
| 440 if (!gap->IsRedundant()) { |
| 441 can_eliminate = false; |
| 442 } |
| 443 } else { |
| 444 can_eliminate = false; |
| 445 } |
| 446 } |
| 447 |
| 448 if (can_eliminate) { |
| 449 label->set_replacement(GetLabel(goto_instr->block_id())); |
| 450 } |
| 451 } |
| 452 } |
| 453 } |
| 454 } |
| 455 |
| 456 |
| 457 void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) { |
| 458 LInstructionGap* gap = new LInstructionGap(block); |
| 459 int index = -1; |
| 460 if (instr->IsControl()) { |
| 461 instructions_.Add(gap); |
| 462 index = instructions_.length(); |
| 463 instructions_.Add(instr); |
| 464 } else { |
| 465 index = instructions_.length(); |
| 466 instructions_.Add(instr); |
| 467 instructions_.Add(gap); |
| 468 } |
| 469 if (instr->HasPointerMap()) { |
| 470 pointer_maps_.Add(instr->pointer_map()); |
| 471 instr->pointer_map()->set_lithium_position(index); |
| 472 } |
| 473 } |
| 474 |
| 475 |
| 476 LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) { |
| 477 return LConstantOperand::Create(constant->id()); |
| 478 } |
| 479 |
| 480 |
| 481 int LChunk::GetParameterStackSlot(int index) const { |
| 482 // The receiver is at index 0, the first parameter at index 1, so we |
| 483 // shift all parameter indexes down by the number of parameters, and |
| 484 // make sure they end up negative so they are distinguishable from |
| 485 // spill slots. |
| 486 int result = index - info()->scope()->num_parameters() - 1; |
| 487 ASSERT(result < 0); |
| 488 return result; |
| 489 } |
| 490 |
| 491 // A parameter relative to ebp in the arguments stub. |
| 492 int LChunk::ParameterAt(int index) { |
| 493 ASSERT(-1 <= index); // -1 is the receiver. |
| 494 return (1 + info()->scope()->num_parameters() - index) * |
| 495 kPointerSize; |
| 496 } |
| 497 |
| 498 |
| 499 LGap* LChunk::GetGapAt(int index) const { |
| 500 return LGap::cast(instructions_[index]); |
| 501 } |
| 502 |
| 503 |
| 504 bool LChunk::IsGapAt(int index) const { |
| 505 return instructions_[index]->IsGap(); |
| 506 } |
| 507 |
| 508 |
| 509 int LChunk::NearestGapPos(int index) const { |
| 510 while (!IsGapAt(index)) index--; |
| 511 return index; |
| 512 } |
| 513 |
| 514 |
| 515 void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) { |
| 516 GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to); |
| 517 } |
| 518 |
| 519 |
| 520 Handle<Object> LChunk::LookupLiteral(LConstantOperand* operand) const { |
| 521 return HConstant::cast(graph_->LookupValue(operand->index()))->handle(); |
| 522 } |
| 523 |
| 524 |
| 525 Representation LChunk::LookupLiteralRepresentation( |
| 526 LConstantOperand* operand) const { |
| 527 return graph_->LookupValue(operand->index())->representation(); |
| 528 } |
| 529 |
| 530 |
| 531 LChunk* LChunkBuilder::Build() { |
| 532 ASSERT(is_unused()); |
| 533 chunk_ = new LChunk(info(), graph()); |
| 534 HPhase phase("Building chunk", chunk_); |
| 535 status_ = BUILDING; |
| 536 const ZoneList<HBasicBlock*>* blocks = graph()->blocks(); |
| 537 for (int i = 0; i < blocks->length(); i++) { |
| 538 HBasicBlock* next = NULL; |
| 539 if (i < blocks->length() - 1) next = blocks->at(i + 1); |
| 540 DoBasicBlock(blocks->at(i), next); |
| 541 if (is_aborted()) return NULL; |
| 542 } |
| 543 status_ = DONE; |
| 544 return chunk_; |
| 545 } |
| 546 |
| 547 |
| 548 void LChunkBuilder::Abort(const char* format, ...) { |
| 549 if (FLAG_trace_bailout) { |
| 550 SmartArrayPointer<char> name( |
| 551 info()->shared_info()->DebugName()->ToCString()); |
| 552 PrintF("Aborting LChunk building in @\"%s\": ", *name); |
| 553 va_list arguments; |
| 554 va_start(arguments, format); |
| 555 OS::VPrint(format, arguments); |
| 556 va_end(arguments); |
| 557 PrintF("\n"); |
| 558 } |
| 559 status_ = ABORTED; |
| 560 } |
| 561 |
| 562 |
| 563 LRegister* LChunkBuilder::ToOperand(Register reg) { |
| 564 return LRegister::Create(Register::ToAllocationIndex(reg)); |
| 565 } |
| 566 |
| 567 |
| 568 LUnallocated* LChunkBuilder::ToUnallocated(Register reg) { |
| 569 return new LUnallocated(LUnallocated::FIXED_REGISTER, |
| 570 Register::ToAllocationIndex(reg)); |
| 571 } |
| 572 |
| 573 |
| 574 LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) { |
| 575 return new LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, |
| 576 DoubleRegister::ToAllocationIndex(reg)); |
| 577 } |
| 578 |
| 579 |
| 580 LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) { |
| 581 return Use(value, ToUnallocated(fixed_register)); |
| 582 } |
| 583 |
| 584 |
| 585 LOperand* LChunkBuilder::UseFixedDouble(HValue* value, DoubleRegister reg) { |
| 586 return Use(value, ToUnallocated(reg)); |
| 587 } |
| 588 |
| 589 |
| 590 LOperand* LChunkBuilder::UseRegister(HValue* value) { |
| 591 return Use(value, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER)); |
| 592 } |
| 593 |
| 594 |
| 595 LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) { |
| 596 return Use(value, |
| 597 new LUnallocated(LUnallocated::MUST_HAVE_REGISTER, |
| 598 LUnallocated::USED_AT_START)); |
| 599 } |
| 600 |
| 601 |
| 602 LOperand* LChunkBuilder::UseTempRegister(HValue* value) { |
| 603 return Use(value, new LUnallocated(LUnallocated::WRITABLE_REGISTER)); |
| 604 } |
| 605 |
| 606 |
| 607 LOperand* LChunkBuilder::Use(HValue* value) { |
| 608 return Use(value, new LUnallocated(LUnallocated::NONE)); |
| 609 } |
| 610 |
| 611 |
| 612 LOperand* LChunkBuilder::UseAtStart(HValue* value) { |
| 613 return Use(value, new LUnallocated(LUnallocated::NONE, |
| 614 LUnallocated::USED_AT_START)); |
| 615 } |
| 616 |
| 617 |
| 618 LOperand* LChunkBuilder::UseOrConstant(HValue* value) { |
| 619 return value->IsConstant() |
| 620 ? chunk_->DefineConstantOperand(HConstant::cast(value)) |
| 621 : Use(value); |
| 622 } |
| 623 |
| 624 |
| 625 LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) { |
| 626 return value->IsConstant() |
| 627 ? chunk_->DefineConstantOperand(HConstant::cast(value)) |
| 628 : UseAtStart(value); |
| 629 } |
| 630 |
| 631 |
| 632 LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) { |
| 633 return value->IsConstant() |
| 634 ? chunk_->DefineConstantOperand(HConstant::cast(value)) |
| 635 : UseRegister(value); |
| 636 } |
| 637 |
| 638 |
| 639 LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) { |
| 640 return value->IsConstant() |
| 641 ? chunk_->DefineConstantOperand(HConstant::cast(value)) |
| 642 : UseRegisterAtStart(value); |
| 643 } |
| 644 |
| 645 |
| 646 LOperand* LChunkBuilder::UseAny(HValue* value) { |
| 647 return value->IsConstant() |
| 648 ? chunk_->DefineConstantOperand(HConstant::cast(value)) |
| 649 : Use(value, new LUnallocated(LUnallocated::ANY)); |
| 650 } |
| 651 |
| 652 |
| 653 LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) { |
| 654 if (value->EmitAtUses()) { |
| 655 HInstruction* instr = HInstruction::cast(value); |
| 656 VisitInstruction(instr); |
| 657 } |
| 658 allocator_->RecordUse(value, operand); |
| 659 return operand; |
| 660 } |
| 661 |
| 662 |
| 663 template<int I, int T> |
| 664 LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr, |
| 665 LUnallocated* result) { |
| 666 allocator_->RecordDefinition(current_instruction_, result); |
| 667 instr->set_result(result); |
| 668 return instr; |
| 669 } |
| 670 |
| 671 |
| 672 template<int I, int T> |
| 673 LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr) { |
| 674 return Define(instr, new LUnallocated(LUnallocated::NONE)); |
| 675 } |
| 676 |
| 677 |
| 678 template<int I, int T> |
| 679 LInstruction* LChunkBuilder::DefineAsRegister( |
| 680 LTemplateInstruction<1, I, T>* instr) { |
| 681 return Define(instr, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER)); |
| 682 } |
| 683 |
| 684 |
| 685 template<int I, int T> |
| 686 LInstruction* LChunkBuilder::DefineAsSpilled( |
| 687 LTemplateInstruction<1, I, T>* instr, int index) { |
| 688 return Define(instr, new LUnallocated(LUnallocated::FIXED_SLOT, index)); |
| 689 } |
| 690 |
| 691 |
| 692 template<int I, int T> |
| 693 LInstruction* LChunkBuilder::DefineSameAsFirst( |
| 694 LTemplateInstruction<1, I, T>* instr) { |
| 695 return Define(instr, new LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT)); |
| 696 } |
| 697 |
| 698 |
| 699 template<int I, int T> |
| 700 LInstruction* LChunkBuilder::DefineFixed( |
| 701 LTemplateInstruction<1, I, T>* instr, Register reg) { |
| 702 return Define(instr, ToUnallocated(reg)); |
| 703 } |
| 704 |
| 705 |
| 706 template<int I, int T> |
| 707 LInstruction* LChunkBuilder::DefineFixedDouble( |
| 708 LTemplateInstruction<1, I, T>* instr, DoubleRegister reg) { |
| 709 return Define(instr, ToUnallocated(reg)); |
| 710 } |
| 711 |
| 712 |
| 713 LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) { |
| 714 HEnvironment* hydrogen_env = current_block_->last_environment(); |
| 715 int argument_index_accumulator = 0; |
| 716 instr->set_environment(CreateEnvironment(hydrogen_env, |
| 717 &argument_index_accumulator)); |
| 718 return instr; |
| 719 } |
| 720 |
| 721 |
| 722 LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment( |
| 723 LInstruction* instr, int ast_id) { |
| 724 ASSERT(instruction_pending_deoptimization_environment_ == NULL); |
| 725 ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber); |
| 726 instruction_pending_deoptimization_environment_ = instr; |
| 727 pending_deoptimization_ast_id_ = ast_id; |
| 728 return instr; |
| 729 } |
| 730 |
| 731 |
| 732 void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() { |
| 733 instruction_pending_deoptimization_environment_ = NULL; |
| 734 pending_deoptimization_ast_id_ = AstNode::kNoNumber; |
| 735 } |
| 736 |
| 737 |
| 738 LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr, |
| 739 HInstruction* hinstr, |
| 740 CanDeoptimize can_deoptimize) { |
| 741 #ifdef DEBUG |
| 742 instr->VerifyCall(); |
| 743 #endif |
| 744 instr->MarkAsCall(); |
| 745 instr = AssignPointerMap(instr); |
| 746 |
| 747 if (hinstr->HasSideEffects()) { |
| 748 ASSERT(hinstr->next()->IsSimulate()); |
| 749 HSimulate* sim = HSimulate::cast(hinstr->next()); |
| 750 instr = SetInstructionPendingDeoptimizationEnvironment( |
| 751 instr, sim->ast_id()); |
| 752 } |
| 753 |
| 754 // If instruction does not have side-effects lazy deoptimization |
| 755 // after the call will try to deoptimize to the point before the call. |
| 756 // Thus we still need to attach environment to this call even if |
| 757 // call sequence can not deoptimize eagerly. |
| 758 bool needs_environment = |
| 759 (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) || !hinstr->HasSideEffects(); |
| 760 if (needs_environment && !instr->HasEnvironment()) { |
| 761 instr = AssignEnvironment(instr); |
| 762 } |
| 763 |
| 764 return instr; |
| 765 } |
| 766 |
| 767 |
| 768 LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) { |
| 769 instr->MarkAsSaveDoubles(); |
| 770 return instr; |
| 771 } |
| 772 |
| 773 |
| 774 LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) { |
| 775 ASSERT(!instr->HasPointerMap()); |
| 776 instr->set_pointer_map(new LPointerMap(position_)); |
| 777 return instr; |
| 778 } |
| 779 |
| 780 |
| 781 LUnallocated* LChunkBuilder::TempRegister() { |
| 782 LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER); |
| 783 allocator_->RecordTemporary(operand); |
| 784 return operand; |
| 785 } |
| 786 |
| 787 |
| 788 LOperand* LChunkBuilder::FixedTemp(Register reg) { |
| 789 LUnallocated* operand = ToUnallocated(reg); |
| 790 allocator_->RecordTemporary(operand); |
| 791 return operand; |
| 792 } |
| 793 |
| 794 |
| 795 LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) { |
| 796 LUnallocated* operand = ToUnallocated(reg); |
| 797 allocator_->RecordTemporary(operand); |
| 798 return operand; |
| 799 } |
| 800 |
| 801 |
| 802 LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) { |
| 803 return new LLabel(instr->block()); |
| 804 } |
| 805 |
| 806 |
| 807 LInstruction* LChunkBuilder::DoSoftDeoptimize(HSoftDeoptimize* instr) { |
| 808 return AssignEnvironment(new LDeoptimize); |
| 809 } |
| 810 |
| 811 |
| 812 LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) { |
| 813 return AssignEnvironment(new LDeoptimize); |
| 814 } |
| 815 |
| 816 |
| 817 LInstruction* LChunkBuilder::DoBit(Token::Value op, |
| 818 HBitwiseBinaryOperation* instr) { |
| 819 if (instr->representation().IsInteger32()) { |
| 820 ASSERT(instr->left()->representation().IsInteger32()); |
| 821 ASSERT(instr->right()->representation().IsInteger32()); |
| 822 |
| 823 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand()); |
| 824 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand()); |
| 825 return DefineAsRegister(new LBitI(op, left, right)); |
| 826 } else { |
| 827 ASSERT(instr->representation().IsTagged()); |
| 828 ASSERT(instr->left()->representation().IsTagged()); |
| 829 ASSERT(instr->right()->representation().IsTagged()); |
| 830 |
| 831 LOperand* left = UseFixed(instr->left(), a1); |
| 832 LOperand* right = UseFixed(instr->right(), a0); |
| 833 LArithmeticT* result = new LArithmeticT(op, left, right); |
| 834 return MarkAsCall(DefineFixed(result, v0), instr); |
| 835 } |
| 836 } |
| 837 |
| 838 |
| 839 LInstruction* LChunkBuilder::DoShift(Token::Value op, |
| 840 HBitwiseBinaryOperation* instr) { |
| 841 if (instr->representation().IsTagged()) { |
| 842 ASSERT(instr->left()->representation().IsTagged()); |
| 843 ASSERT(instr->right()->representation().IsTagged()); |
| 844 |
| 845 LOperand* left = UseFixed(instr->left(), a1); |
| 846 LOperand* right = UseFixed(instr->right(), a0); |
| 847 LArithmeticT* result = new LArithmeticT(op, left, right); |
| 848 return MarkAsCall(DefineFixed(result, v0), instr); |
| 849 } |
| 850 |
| 851 ASSERT(instr->representation().IsInteger32()); |
| 852 ASSERT(instr->left()->representation().IsInteger32()); |
| 853 ASSERT(instr->right()->representation().IsInteger32()); |
| 854 LOperand* left = UseRegisterAtStart(instr->left()); |
| 855 |
| 856 HValue* right_value = instr->right(); |
| 857 LOperand* right = NULL; |
| 858 int constant_value = 0; |
| 859 if (right_value->IsConstant()) { |
| 860 HConstant* constant = HConstant::cast(right_value); |
| 861 right = chunk_->DefineConstantOperand(constant); |
| 862 constant_value = constant->Integer32Value() & 0x1f; |
| 863 } else { |
| 864 right = UseRegisterAtStart(right_value); |
| 865 } |
| 866 |
| 867 // Shift operations can only deoptimize if we do a logical shift |
| 868 // by 0 and the result cannot be truncated to int32. |
| 869 bool may_deopt = (op == Token::SHR && constant_value == 0); |
| 870 bool does_deopt = false; |
| 871 if (may_deopt) { |
| 872 for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) { |
| 873 if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) { |
| 874 does_deopt = true; |
| 875 break; |
| 876 } |
| 877 } |
| 878 } |
| 879 |
| 880 LInstruction* result = |
| 881 DefineAsRegister(new LShiftI(op, left, right, does_deopt)); |
| 882 return does_deopt ? AssignEnvironment(result) : result; |
| 883 } |
| 884 |
| 885 |
| 886 LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op, |
| 887 HArithmeticBinaryOperation* instr) { |
| 888 ASSERT(instr->representation().IsDouble()); |
| 889 ASSERT(instr->left()->representation().IsDouble()); |
| 890 ASSERT(instr->right()->representation().IsDouble()); |
| 891 ASSERT(op != Token::MOD); |
| 892 LOperand* left = UseRegisterAtStart(instr->left()); |
| 893 LOperand* right = UseRegisterAtStart(instr->right()); |
| 894 LArithmeticD* result = new LArithmeticD(op, left, right); |
| 895 return DefineAsRegister(result); |
| 896 } |
| 897 |
| 898 |
| 899 LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op, |
| 900 HArithmeticBinaryOperation* instr) { |
| 901 ASSERT(op == Token::ADD || |
| 902 op == Token::DIV || |
| 903 op == Token::MOD || |
| 904 op == Token::MUL || |
| 905 op == Token::SUB); |
| 906 HValue* left = instr->left(); |
| 907 HValue* right = instr->right(); |
| 908 ASSERT(left->representation().IsTagged()); |
| 909 ASSERT(right->representation().IsTagged()); |
| 910 LOperand* left_operand = UseFixed(left, a1); |
| 911 LOperand* right_operand = UseFixed(right, a0); |
| 912 LArithmeticT* result = new LArithmeticT(op, left_operand, right_operand); |
| 913 return MarkAsCall(DefineFixed(result, v0), instr); |
| 914 } |
| 915 |
| 916 |
| 917 void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) { |
| 918 ASSERT(is_building()); |
| 919 current_block_ = block; |
| 920 next_block_ = next_block; |
| 921 if (block->IsStartBlock()) { |
| 922 block->UpdateEnvironment(graph_->start_environment()); |
| 923 argument_count_ = 0; |
| 924 } else if (block->predecessors()->length() == 1) { |
| 925 // We have a single predecessor => copy environment and outgoing |
| 926 // argument count from the predecessor. |
| 927 ASSERT(block->phis()->length() == 0); |
| 928 HBasicBlock* pred = block->predecessors()->at(0); |
| 929 HEnvironment* last_environment = pred->last_environment(); |
| 930 ASSERT(last_environment != NULL); |
| 931 // Only copy the environment, if it is later used again. |
| 932 if (pred->end()->SecondSuccessor() == NULL) { |
| 933 ASSERT(pred->end()->FirstSuccessor() == block); |
| 934 } else { |
| 935 if (pred->end()->FirstSuccessor()->block_id() > block->block_id() || |
| 936 pred->end()->SecondSuccessor()->block_id() > block->block_id()) { |
| 937 last_environment = last_environment->Copy(); |
| 938 } |
| 939 } |
| 940 block->UpdateEnvironment(last_environment); |
| 941 ASSERT(pred->argument_count() >= 0); |
| 942 argument_count_ = pred->argument_count(); |
| 943 } else { |
| 944 // We are at a state join => process phis. |
| 945 HBasicBlock* pred = block->predecessors()->at(0); |
| 946 // No need to copy the environment, it cannot be used later. |
| 947 HEnvironment* last_environment = pred->last_environment(); |
| 948 for (int i = 0; i < block->phis()->length(); ++i) { |
| 949 HPhi* phi = block->phis()->at(i); |
| 950 last_environment->SetValueAt(phi->merged_index(), phi); |
| 951 } |
| 952 for (int i = 0; i < block->deleted_phis()->length(); ++i) { |
| 953 last_environment->SetValueAt(block->deleted_phis()->at(i), |
| 954 graph_->GetConstantUndefined()); |
| 955 } |
| 956 block->UpdateEnvironment(last_environment); |
| 957 // Pick up the outgoing argument count of one of the predecessors. |
| 958 argument_count_ = pred->argument_count(); |
| 959 } |
| 960 HInstruction* current = block->first(); |
| 961 int start = chunk_->instructions()->length(); |
| 962 while (current != NULL && !is_aborted()) { |
| 963 // Code for constants in registers is generated lazily. |
| 964 if (!current->EmitAtUses()) { |
| 965 VisitInstruction(current); |
| 966 } |
| 967 current = current->next(); |
| 968 } |
| 969 int end = chunk_->instructions()->length() - 1; |
| 970 if (end >= start) { |
| 971 block->set_first_instruction_index(start); |
| 972 block->set_last_instruction_index(end); |
| 973 } |
| 974 block->set_argument_count(argument_count_); |
| 975 next_block_ = NULL; |
| 976 current_block_ = NULL; |
| 977 } |
| 978 |
| 979 |
| 980 void LChunkBuilder::VisitInstruction(HInstruction* current) { |
| 981 HInstruction* old_current = current_instruction_; |
| 982 current_instruction_ = current; |
| 983 if (current->has_position()) position_ = current->position(); |
| 984 LInstruction* instr = current->CompileToLithium(this); |
| 985 |
| 986 if (instr != NULL) { |
| 987 if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) { |
| 988 instr = AssignPointerMap(instr); |
| 989 } |
| 990 if (FLAG_stress_environments && !instr->HasEnvironment()) { |
| 991 instr = AssignEnvironment(instr); |
| 992 } |
| 993 instr->set_hydrogen_value(current); |
| 994 chunk_->AddInstruction(instr, current_block_); |
| 995 } |
| 996 current_instruction_ = old_current; |
| 997 } |
| 998 |
| 999 |
| 1000 LEnvironment* LChunkBuilder::CreateEnvironment( |
| 1001 HEnvironment* hydrogen_env, |
| 1002 int* argument_index_accumulator) { |
| 1003 if (hydrogen_env == NULL) return NULL; |
| 1004 |
| 1005 LEnvironment* outer = |
| 1006 CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator); |
| 1007 int ast_id = hydrogen_env->ast_id(); |
| 1008 ASSERT(ast_id != AstNode::kNoNumber); |
| 1009 int value_count = hydrogen_env->length(); |
| 1010 LEnvironment* result = new LEnvironment(hydrogen_env->closure(), |
| 1011 ast_id, |
| 1012 hydrogen_env->parameter_count(), |
| 1013 argument_count_, |
| 1014 value_count, |
| 1015 outer); |
| 1016 for (int i = 0; i < value_count; ++i) { |
| 1017 if (hydrogen_env->is_special_index(i)) continue; |
| 1018 |
| 1019 HValue* value = hydrogen_env->values()->at(i); |
| 1020 LOperand* op = NULL; |
| 1021 if (value->IsArgumentsObject()) { |
| 1022 op = NULL; |
| 1023 } else if (value->IsPushArgument()) { |
| 1024 op = new LArgument((*argument_index_accumulator)++); |
| 1025 } else { |
| 1026 op = UseAny(value); |
| 1027 } |
| 1028 result->AddValue(op, value->representation()); |
| 1029 } |
| 1030 |
| 1031 return result; |
| 1032 } |
| 1033 |
| 1034 |
| 1035 LInstruction* LChunkBuilder::DoGoto(HGoto* instr) { |
| 1036 return new LGoto(instr->FirstSuccessor()->block_id()); |
| 1037 } |
| 1038 |
| 1039 |
| 1040 LInstruction* LChunkBuilder::DoBranch(HBranch* instr) { |
| 1041 HValue* v = instr->value(); |
| 1042 if (v->EmitAtUses()) { |
| 1043 HBasicBlock* successor = HConstant::cast(v)->ToBoolean() |
| 1044 ? instr->FirstSuccessor() |
| 1045 : instr->SecondSuccessor(); |
| 1046 return new LGoto(successor->block_id()); |
| 1047 } |
| 1048 return AssignEnvironment(new LBranch(UseRegister(v))); |
| 1049 } |
| 1050 |
| 1051 |
| 1052 LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) { |
| 1053 ASSERT(instr->value()->representation().IsTagged()); |
| 1054 LOperand* value = UseRegisterAtStart(instr->value()); |
| 1055 LOperand* temp = TempRegister(); |
| 1056 return new LCmpMapAndBranch(value, temp); |
| 1057 } |
| 1058 |
| 1059 |
| 1060 LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) { |
| 1061 return DefineAsRegister(new LArgumentsLength(UseRegister(length->value()))); |
| 1062 } |
| 1063 |
| 1064 |
| 1065 LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) { |
| 1066 return DefineAsRegister(new LArgumentsElements); |
| 1067 } |
| 1068 |
| 1069 |
| 1070 LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) { |
| 1071 LInstanceOf* result = |
| 1072 new LInstanceOf(UseFixed(instr->left(), a0), |
| 1073 UseFixed(instr->right(), a1)); |
| 1074 return MarkAsCall(DefineFixed(result, v0), instr); |
| 1075 } |
| 1076 |
| 1077 |
| 1078 LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal( |
| 1079 HInstanceOfKnownGlobal* instr) { |
| 1080 LInstanceOfKnownGlobal* result = |
| 1081 new LInstanceOfKnownGlobal(UseFixed(instr->left(), a0), FixedTemp(t0)); |
| 1082 return MarkAsCall(DefineFixed(result, v0), instr); |
| 1083 } |
| 1084 |
| 1085 |
| 1086 LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) { |
| 1087 LOperand* function = UseFixed(instr->function(), a1); |
| 1088 LOperand* receiver = UseFixed(instr->receiver(), a0); |
| 1089 LOperand* length = UseFixed(instr->length(), a2); |
| 1090 LOperand* elements = UseFixed(instr->elements(), a3); |
| 1091 LApplyArguments* result = new LApplyArguments(function, |
| 1092 receiver, |
| 1093 length, |
| 1094 elements); |
| 1095 return MarkAsCall(DefineFixed(result, v0), instr, CAN_DEOPTIMIZE_EAGERLY); |
| 1096 } |
| 1097 |
| 1098 |
| 1099 LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) { |
| 1100 ++argument_count_; |
| 1101 LOperand* argument = Use(instr->argument()); |
| 1102 return new LPushArgument(argument); |
| 1103 } |
| 1104 |
| 1105 |
| 1106 LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) { |
| 1107 return instr->HasNoUses() ? NULL : DefineAsRegister(new LThisFunction); |
| 1108 } |
| 1109 |
| 1110 |
| 1111 LInstruction* LChunkBuilder::DoContext(HContext* instr) { |
| 1112 return instr->HasNoUses() ? NULL : DefineAsRegister(new LContext); |
| 1113 } |
| 1114 |
| 1115 |
| 1116 LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) { |
| 1117 LOperand* context = UseRegisterAtStart(instr->value()); |
| 1118 return DefineAsRegister(new LOuterContext(context)); |
| 1119 } |
| 1120 |
| 1121 |
| 1122 LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) { |
| 1123 LOperand* context = UseRegisterAtStart(instr->value()); |
| 1124 return DefineAsRegister(new LGlobalObject(context)); |
| 1125 } |
| 1126 |
| 1127 |
| 1128 LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) { |
| 1129 LOperand* global_object = UseRegisterAtStart(instr->value()); |
| 1130 return DefineAsRegister(new LGlobalReceiver(global_object)); |
| 1131 } |
| 1132 |
| 1133 |
| 1134 LInstruction* LChunkBuilder::DoCallConstantFunction( |
| 1135 HCallConstantFunction* instr) { |
| 1136 argument_count_ -= instr->argument_count(); |
| 1137 return MarkAsCall(DefineFixed(new LCallConstantFunction, v0), instr); |
| 1138 } |
| 1139 |
| 1140 |
| 1141 LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) { |
| 1142 LOperand* function = UseFixed(instr->function(), a1); |
| 1143 argument_count_ -= instr->argument_count(); |
| 1144 LInvokeFunction* result = new LInvokeFunction(function); |
| 1145 return MarkAsCall(DefineFixed(result, v0), instr, CANNOT_DEOPTIMIZE_EAGERLY); |
| 1146 } |
| 1147 |
| 1148 |
| 1149 LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { |
| 1150 BuiltinFunctionId op = instr->op(); |
| 1151 if (op == kMathLog || op == kMathSin || op == kMathCos) { |
| 1152 LOperand* input = UseFixedDouble(instr->value(), f4); |
| 1153 LUnaryMathOperation* result = new LUnaryMathOperation(input, NULL); |
| 1154 return MarkAsCall(DefineFixedDouble(result, f4), instr); |
| 1155 } else { |
| 1156 LOperand* input = UseRegisterAtStart(instr->value()); |
| 1157 LOperand* temp = (op == kMathFloor) ? TempRegister() : NULL; |
| 1158 LUnaryMathOperation* result = new LUnaryMathOperation(input, temp); |
| 1159 switch (op) { |
| 1160 case kMathAbs: |
| 1161 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result))); |
| 1162 case kMathFloor: |
| 1163 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result))); |
| 1164 case kMathSqrt: |
| 1165 return DefineAsRegister(result); |
| 1166 case kMathRound: |
| 1167 return AssignEnvironment(DefineAsRegister(result)); |
| 1168 case kMathPowHalf: |
| 1169 return DefineAsRegister(result); |
| 1170 default: |
| 1171 UNREACHABLE(); |
| 1172 return NULL; |
| 1173 } |
| 1174 } |
| 1175 } |
| 1176 |
| 1177 |
| 1178 LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) { |
| 1179 ASSERT(instr->key()->representation().IsTagged()); |
| 1180 argument_count_ -= instr->argument_count(); |
| 1181 LOperand* key = UseFixed(instr->key(), a2); |
| 1182 return MarkAsCall(DefineFixed(new LCallKeyed(key), v0), instr); |
| 1183 } |
| 1184 |
| 1185 |
| 1186 LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) { |
| 1187 argument_count_ -= instr->argument_count(); |
| 1188 return MarkAsCall(DefineFixed(new LCallNamed, v0), instr); |
| 1189 } |
| 1190 |
| 1191 |
| 1192 LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) { |
| 1193 argument_count_ -= instr->argument_count(); |
| 1194 return MarkAsCall(DefineFixed(new LCallGlobal, v0), instr); |
| 1195 } |
| 1196 |
| 1197 |
| 1198 LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) { |
| 1199 argument_count_ -= instr->argument_count(); |
| 1200 return MarkAsCall(DefineFixed(new LCallKnownGlobal, v0), instr); |
| 1201 } |
| 1202 |
| 1203 |
| 1204 LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) { |
| 1205 LOperand* constructor = UseFixed(instr->constructor(), a1); |
| 1206 argument_count_ -= instr->argument_count(); |
| 1207 LCallNew* result = new LCallNew(constructor); |
| 1208 return MarkAsCall(DefineFixed(result, v0), instr); |
| 1209 } |
| 1210 |
| 1211 |
| 1212 LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) { |
| 1213 argument_count_ -= instr->argument_count(); |
| 1214 return MarkAsCall(DefineFixed(new LCallFunction, v0), instr); |
| 1215 } |
| 1216 |
| 1217 |
| 1218 LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) { |
| 1219 argument_count_ -= instr->argument_count(); |
| 1220 return MarkAsCall(DefineFixed(new LCallRuntime, v0), instr); |
| 1221 } |
| 1222 |
| 1223 |
| 1224 LInstruction* LChunkBuilder::DoShr(HShr* instr) { |
| 1225 return DoShift(Token::SHR, instr); |
| 1226 } |
| 1227 |
| 1228 |
| 1229 LInstruction* LChunkBuilder::DoSar(HSar* instr) { |
| 1230 return DoShift(Token::SAR, instr); |
| 1231 } |
| 1232 |
| 1233 |
| 1234 LInstruction* LChunkBuilder::DoShl(HShl* instr) { |
| 1235 return DoShift(Token::SHL, instr); |
| 1236 } |
| 1237 |
| 1238 |
| 1239 LInstruction* LChunkBuilder::DoBitAnd(HBitAnd* instr) { |
| 1240 return DoBit(Token::BIT_AND, instr); |
| 1241 } |
| 1242 |
| 1243 |
| 1244 LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) { |
| 1245 ASSERT(instr->value()->representation().IsInteger32()); |
| 1246 ASSERT(instr->representation().IsInteger32()); |
| 1247 return DefineAsRegister(new LBitNotI(UseRegisterAtStart(instr->value()))); |
| 1248 } |
| 1249 |
| 1250 |
| 1251 LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) { |
| 1252 return DoBit(Token::BIT_OR, instr); |
| 1253 } |
| 1254 |
| 1255 |
| 1256 LInstruction* LChunkBuilder::DoBitXor(HBitXor* instr) { |
| 1257 return DoBit(Token::BIT_XOR, instr); |
| 1258 } |
| 1259 |
| 1260 |
| 1261 LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { |
| 1262 if (instr->representation().IsDouble()) { |
| 1263 return DoArithmeticD(Token::DIV, instr); |
| 1264 } else if (instr->representation().IsInteger32()) { |
| 1265 // TODO(1042) The fixed register allocation |
| 1266 // is needed because we call TypeRecordingBinaryOpStub from |
| 1267 // the generated code, which requires registers a0 |
| 1268 // and a1 to be used. We should remove that |
| 1269 // when we provide a native implementation. |
| 1270 LOperand* dividend = UseFixed(instr->left(), a0); |
| 1271 LOperand* divisor = UseFixed(instr->right(), a1); |
| 1272 return AssignEnvironment(AssignPointerMap( |
| 1273 DefineFixed(new LDivI(dividend, divisor), v0))); |
| 1274 } else { |
| 1275 return DoArithmeticT(Token::DIV, instr); |
| 1276 } |
| 1277 } |
| 1278 |
| 1279 |
| 1280 LInstruction* LChunkBuilder::DoMod(HMod* instr) { |
| 1281 if (instr->representation().IsInteger32()) { |
| 1282 ASSERT(instr->left()->representation().IsInteger32()); |
| 1283 ASSERT(instr->right()->representation().IsInteger32()); |
| 1284 |
| 1285 LModI* mod; |
| 1286 if (instr->HasPowerOf2Divisor()) { |
| 1287 ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero)); |
| 1288 LOperand* value = UseRegisterAtStart(instr->left()); |
| 1289 mod = new LModI(value, UseOrConstant(instr->right())); |
| 1290 } else { |
| 1291 LOperand* dividend = UseRegister(instr->left()); |
| 1292 LOperand* divisor = UseRegister(instr->right()); |
| 1293 mod = new LModI(dividend, |
| 1294 divisor, |
| 1295 TempRegister(), |
| 1296 FixedTemp(f20), |
| 1297 FixedTemp(f22)); |
| 1298 } |
| 1299 |
| 1300 if (instr->CheckFlag(HValue::kBailoutOnMinusZero) || |
| 1301 instr->CheckFlag(HValue::kCanBeDivByZero)) { |
| 1302 return AssignEnvironment(DefineAsRegister(mod)); |
| 1303 } else { |
| 1304 return DefineAsRegister(mod); |
| 1305 } |
| 1306 } else if (instr->representation().IsTagged()) { |
| 1307 return DoArithmeticT(Token::MOD, instr); |
| 1308 } else { |
| 1309 ASSERT(instr->representation().IsDouble()); |
| 1310 // We call a C function for double modulo. It can't trigger a GC. |
| 1311 // We need to use fixed result register for the call. |
| 1312 // TODO(fschneider): Allow any register as input registers. |
| 1313 LOperand* left = UseFixedDouble(instr->left(), f2); |
| 1314 LOperand* right = UseFixedDouble(instr->right(), f4); |
| 1315 LArithmeticD* result = new LArithmeticD(Token::MOD, left, right); |
| 1316 return MarkAsCall(DefineFixedDouble(result, f2), instr); |
| 1317 } |
| 1318 } |
| 1319 |
| 1320 |
| 1321 LInstruction* LChunkBuilder::DoMul(HMul* instr) { |
| 1322 if (instr->representation().IsInteger32()) { |
| 1323 ASSERT(instr->left()->representation().IsInteger32()); |
| 1324 ASSERT(instr->right()->representation().IsInteger32()); |
| 1325 LOperand* left; |
| 1326 LOperand* right = UseOrConstant(instr->MostConstantOperand()); |
| 1327 LOperand* temp = NULL; |
| 1328 if (instr->CheckFlag(HValue::kBailoutOnMinusZero) && |
| 1329 (instr->CheckFlag(HValue::kCanOverflow) || |
| 1330 !right->IsConstantOperand())) { |
| 1331 left = UseRegister(instr->LeastConstantOperand()); |
| 1332 temp = TempRegister(); |
| 1333 } else { |
| 1334 left = UseRegisterAtStart(instr->LeastConstantOperand()); |
| 1335 } |
| 1336 return AssignEnvironment(DefineAsRegister(new LMulI(left, right, temp))); |
| 1337 |
| 1338 } else if (instr->representation().IsDouble()) { |
| 1339 return DoArithmeticD(Token::MUL, instr); |
| 1340 |
| 1341 } else { |
| 1342 return DoArithmeticT(Token::MUL, instr); |
| 1343 } |
| 1344 } |
| 1345 |
| 1346 |
| 1347 LInstruction* LChunkBuilder::DoSub(HSub* instr) { |
| 1348 if (instr->representation().IsInteger32()) { |
| 1349 ASSERT(instr->left()->representation().IsInteger32()); |
| 1350 ASSERT(instr->right()->representation().IsInteger32()); |
| 1351 LOperand* left = UseRegisterAtStart(instr->left()); |
| 1352 LOperand* right = UseOrConstantAtStart(instr->right()); |
| 1353 LSubI* sub = new LSubI(left, right); |
| 1354 LInstruction* result = DefineAsRegister(sub); |
| 1355 if (instr->CheckFlag(HValue::kCanOverflow)) { |
| 1356 result = AssignEnvironment(result); |
| 1357 } |
| 1358 return result; |
| 1359 } else if (instr->representation().IsDouble()) { |
| 1360 return DoArithmeticD(Token::SUB, instr); |
| 1361 } else { |
| 1362 return DoArithmeticT(Token::SUB, instr); |
| 1363 } |
| 1364 } |
| 1365 |
| 1366 |
| 1367 LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { |
| 1368 if (instr->representation().IsInteger32()) { |
| 1369 ASSERT(instr->left()->representation().IsInteger32()); |
| 1370 ASSERT(instr->right()->representation().IsInteger32()); |
| 1371 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand()); |
| 1372 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand()); |
| 1373 LAddI* add = new LAddI(left, right); |
| 1374 LInstruction* result = DefineAsRegister(add); |
| 1375 if (instr->CheckFlag(HValue::kCanOverflow)) { |
| 1376 result = AssignEnvironment(result); |
| 1377 } |
| 1378 return result; |
| 1379 } else if (instr->representation().IsDouble()) { |
| 1380 return DoArithmeticD(Token::ADD, instr); |
| 1381 } else { |
| 1382 ASSERT(instr->representation().IsTagged()); |
| 1383 return DoArithmeticT(Token::ADD, instr); |
| 1384 } |
| 1385 } |
| 1386 |
| 1387 |
| 1388 LInstruction* LChunkBuilder::DoPower(HPower* instr) { |
| 1389 ASSERT(instr->representation().IsDouble()); |
| 1390 // We call a C function for double power. It can't trigger a GC. |
| 1391 // We need to use fixed result register for the call. |
| 1392 Representation exponent_type = instr->right()->representation(); |
| 1393 ASSERT(instr->left()->representation().IsDouble()); |
| 1394 LOperand* left = UseFixedDouble(instr->left(), f2); |
| 1395 LOperand* right = exponent_type.IsDouble() ? |
| 1396 UseFixedDouble(instr->right(), f4) : |
| 1397 UseFixed(instr->right(), a0); |
| 1398 LPower* result = new LPower(left, right); |
| 1399 return MarkAsCall(DefineFixedDouble(result, f6), |
| 1400 instr, |
| 1401 CAN_DEOPTIMIZE_EAGERLY); |
| 1402 } |
| 1403 |
| 1404 |
| 1405 LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) { |
| 1406 Token::Value op = instr->token(); |
| 1407 Representation r = instr->GetInputRepresentation(); |
| 1408 ASSERT(instr->left()->representation().IsTagged()); |
| 1409 ASSERT(instr->right()->representation().IsTagged()); |
| 1410 bool reversed = (op == Token::GT || op == Token::LTE); |
| 1411 LOperand* left = UseFixed(instr->left(), reversed ? a0 : a1); |
| 1412 LOperand* right = UseFixed(instr->right(), reversed ? a1 : a0); |
| 1413 LCmpT* result = new LCmpT(left, right); |
| 1414 return MarkAsCall(DefineFixed(result, v0), instr); |
| 1415 } |
| 1416 |
| 1417 |
| 1418 LInstruction* LChunkBuilder::DoCompareIDAndBranch( |
| 1419 HCompareIDAndBranch* instr) { |
| 1420 Representation r = instr->GetInputRepresentation(); |
| 1421 if (r.IsInteger32()) { |
| 1422 ASSERT(instr->left()->representation().IsInteger32()); |
| 1423 ASSERT(instr->right()->representation().IsInteger32()); |
| 1424 LOperand* left = UseRegisterAtStart(instr->left()); |
| 1425 LOperand* right = UseRegisterAtStart(instr->right()); |
| 1426 return new LCmpIDAndBranch(left, right); |
| 1427 } else { |
| 1428 ASSERT(r.IsDouble()); |
| 1429 ASSERT(instr->left()->representation().IsDouble()); |
| 1430 ASSERT(instr->right()->representation().IsDouble()); |
| 1431 LOperand* left = UseRegisterAtStart(instr->left()); |
| 1432 LOperand* right = UseRegisterAtStart(instr->right()); |
| 1433 return new LCmpIDAndBranch(left, right); |
| 1434 } |
| 1435 } |
| 1436 |
| 1437 |
| 1438 LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch( |
| 1439 HCompareObjectEqAndBranch* instr) { |
| 1440 LOperand* left = UseRegisterAtStart(instr->left()); |
| 1441 LOperand* right = UseRegisterAtStart(instr->right()); |
| 1442 return new LCmpObjectEqAndBranch(left, right); |
| 1443 } |
| 1444 |
| 1445 |
| 1446 LInstruction* LChunkBuilder::DoCompareConstantEqAndBranch( |
| 1447 HCompareConstantEqAndBranch* instr) { |
| 1448 return new LCmpConstantEqAndBranch(UseRegisterAtStart(instr->value())); |
| 1449 } |
| 1450 |
| 1451 |
| 1452 LInstruction* LChunkBuilder::DoIsNilAndBranch(HIsNilAndBranch* instr) { |
| 1453 ASSERT(instr->value()->representation().IsTagged()); |
| 1454 return new LIsNilAndBranch(UseRegisterAtStart(instr->value())); |
| 1455 } |
| 1456 |
| 1457 |
| 1458 LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) { |
| 1459 ASSERT(instr->value()->representation().IsTagged()); |
| 1460 LOperand* temp = TempRegister(); |
| 1461 return new LIsObjectAndBranch(UseRegisterAtStart(instr->value()), temp); |
| 1462 } |
| 1463 |
| 1464 |
| 1465 LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) { |
| 1466 ASSERT(instr->value()->representation().IsTagged()); |
| 1467 return new LIsSmiAndBranch(Use(instr->value())); |
| 1468 } |
| 1469 |
| 1470 |
| 1471 LInstruction* LChunkBuilder::DoIsUndetectableAndBranch( |
| 1472 HIsUndetectableAndBranch* instr) { |
| 1473 ASSERT(instr->value()->representation().IsTagged()); |
| 1474 return new LIsUndetectableAndBranch(UseRegisterAtStart(instr->value()), |
| 1475 TempRegister()); |
| 1476 } |
| 1477 |
| 1478 |
| 1479 LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch( |
| 1480 HHasInstanceTypeAndBranch* instr) { |
| 1481 ASSERT(instr->value()->representation().IsTagged()); |
| 1482 return new LHasInstanceTypeAndBranch(UseRegisterAtStart(instr->value())); |
| 1483 } |
| 1484 |
| 1485 |
| 1486 LInstruction* LChunkBuilder::DoGetCachedArrayIndex( |
| 1487 HGetCachedArrayIndex* instr) { |
| 1488 ASSERT(instr->value()->representation().IsTagged()); |
| 1489 LOperand* value = UseRegisterAtStart(instr->value()); |
| 1490 |
| 1491 return DefineAsRegister(new LGetCachedArrayIndex(value)); |
| 1492 } |
| 1493 |
| 1494 |
| 1495 LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch( |
| 1496 HHasCachedArrayIndexAndBranch* instr) { |
| 1497 ASSERT(instr->value()->representation().IsTagged()); |
| 1498 return new LHasCachedArrayIndexAndBranch( |
| 1499 UseRegisterAtStart(instr->value())); |
| 1500 } |
| 1501 |
| 1502 |
| 1503 LInstruction* LChunkBuilder::DoClassOfTestAndBranch( |
| 1504 HClassOfTestAndBranch* instr) { |
| 1505 ASSERT(instr->value()->representation().IsTagged()); |
| 1506 return new LClassOfTestAndBranch(UseTempRegister(instr->value()), |
| 1507 TempRegister()); |
| 1508 } |
| 1509 |
| 1510 |
| 1511 LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) { |
| 1512 LOperand* array = UseRegisterAtStart(instr->value()); |
| 1513 return DefineAsRegister(new LJSArrayLength(array)); |
| 1514 } |
| 1515 |
| 1516 |
| 1517 LInstruction* LChunkBuilder::DoFixedArrayBaseLength( |
| 1518 HFixedArrayBaseLength* instr) { |
| 1519 LOperand* array = UseRegisterAtStart(instr->value()); |
| 1520 return DefineAsRegister(new LFixedArrayBaseLength(array)); |
| 1521 } |
| 1522 |
| 1523 |
| 1524 LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) { |
| 1525 LOperand* object = UseRegisterAtStart(instr->value()); |
| 1526 return DefineAsRegister(new LElementsKind(object)); |
| 1527 } |
| 1528 |
| 1529 |
| 1530 LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) { |
| 1531 LOperand* object = UseRegister(instr->value()); |
| 1532 LValueOf* result = new LValueOf(object, TempRegister()); |
| 1533 return AssignEnvironment(DefineAsRegister(result)); |
| 1534 } |
| 1535 |
| 1536 |
| 1537 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { |
| 1538 return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()), |
| 1539 UseRegister(instr->length()))); |
| 1540 } |
| 1541 |
| 1542 |
| 1543 LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) { |
| 1544 // The control instruction marking the end of a block that completed |
| 1545 // abruptly (e.g., threw an exception). There is nothing specific to do. |
| 1546 return NULL; |
| 1547 } |
| 1548 |
| 1549 |
| 1550 LInstruction* LChunkBuilder::DoThrow(HThrow* instr) { |
| 1551 LOperand* value = UseFixed(instr->value(), a0); |
| 1552 return MarkAsCall(new LThrow(value), instr); |
| 1553 } |
| 1554 |
| 1555 |
| 1556 LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) { |
| 1557 return NULL; |
| 1558 } |
| 1559 |
| 1560 |
| 1561 LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) { |
| 1562 // All HForceRepresentation instructions should be eliminated in the |
| 1563 // representation change phase of Hydrogen. |
| 1564 UNREACHABLE(); |
| 1565 return NULL; |
| 1566 } |
| 1567 |
| 1568 |
| 1569 LInstruction* LChunkBuilder::DoChange(HChange* instr) { |
| 1570 Representation from = instr->from(); |
| 1571 Representation to = instr->to(); |
| 1572 if (from.IsTagged()) { |
| 1573 if (to.IsDouble()) { |
| 1574 LOperand* value = UseRegister(instr->value()); |
| 1575 LNumberUntagD* res = new LNumberUntagD(value); |
| 1576 return AssignEnvironment(DefineAsRegister(res)); |
| 1577 } else { |
| 1578 ASSERT(to.IsInteger32()); |
| 1579 LOperand* value = UseRegister(instr->value()); |
| 1580 bool needs_check = !instr->value()->type().IsSmi(); |
| 1581 LInstruction* res = NULL; |
| 1582 if (!needs_check) { |
| 1583 res = DefineSameAsFirst(new LSmiUntag(value, needs_check)); |
| 1584 } else { |
| 1585 LOperand* temp1 = TempRegister(); |
| 1586 LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister() |
| 1587 : NULL; |
| 1588 LOperand* temp3 = instr->CanTruncateToInt32() ? FixedTemp(f22) |
| 1589 : NULL; |
| 1590 res = DefineSameAsFirst(new LTaggedToI(value, temp1, temp2, temp3)); |
| 1591 res = AssignEnvironment(res); |
| 1592 } |
| 1593 return res; |
| 1594 } |
| 1595 } else if (from.IsDouble()) { |
| 1596 if (to.IsTagged()) { |
| 1597 LOperand* value = UseRegister(instr->value()); |
| 1598 LOperand* temp1 = TempRegister(); |
| 1599 LOperand* temp2 = TempRegister(); |
| 1600 |
| 1601 // Make sure that the temp and result_temp registers are |
| 1602 // different. |
| 1603 LUnallocated* result_temp = TempRegister(); |
| 1604 LNumberTagD* result = new LNumberTagD(value, temp1, temp2); |
| 1605 Define(result, result_temp); |
| 1606 return AssignPointerMap(result); |
| 1607 } else { |
| 1608 ASSERT(to.IsInteger32()); |
| 1609 LOperand* value = UseRegister(instr->value()); |
| 1610 LDoubleToI* res = |
| 1611 new LDoubleToI(value, |
| 1612 TempRegister(), |
| 1613 instr->CanTruncateToInt32() ? TempRegister() : NULL); |
| 1614 return AssignEnvironment(DefineAsRegister(res)); |
| 1615 } |
| 1616 } else if (from.IsInteger32()) { |
| 1617 if (to.IsTagged()) { |
| 1618 HValue* val = instr->value(); |
| 1619 LOperand* value = UseRegister(val); |
| 1620 if (val->HasRange() && val->range()->IsInSmiRange()) { |
| 1621 return DefineSameAsFirst(new LSmiTag(value)); |
| 1622 } else { |
| 1623 LNumberTagI* result = new LNumberTagI(value); |
| 1624 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result))); |
| 1625 } |
| 1626 } else { |
| 1627 ASSERT(to.IsDouble()); |
| 1628 LOperand* value = Use(instr->value()); |
| 1629 return DefineAsRegister(new LInteger32ToDouble(value)); |
| 1630 } |
| 1631 } |
| 1632 UNREACHABLE(); |
| 1633 return NULL; |
| 1634 } |
| 1635 |
| 1636 |
| 1637 LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) { |
| 1638 LOperand* value = UseRegisterAtStart(instr->value()); |
| 1639 return AssignEnvironment(new LCheckNonSmi(value)); |
| 1640 } |
| 1641 |
| 1642 |
| 1643 LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { |
| 1644 LOperand* value = UseRegisterAtStart(instr->value()); |
| 1645 LInstruction* result = new LCheckInstanceType(value); |
| 1646 return AssignEnvironment(result); |
| 1647 } |
| 1648 |
| 1649 |
| 1650 LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) { |
| 1651 LOperand* temp1 = TempRegister(); |
| 1652 LOperand* temp2 = TempRegister(); |
| 1653 LInstruction* result = new LCheckPrototypeMaps(temp1, temp2); |
| 1654 return AssignEnvironment(result); |
| 1655 } |
| 1656 |
| 1657 |
| 1658 LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) { |
| 1659 LOperand* value = UseRegisterAtStart(instr->value()); |
| 1660 return AssignEnvironment(new LCheckSmi(value)); |
| 1661 } |
| 1662 |
| 1663 |
| 1664 LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { |
| 1665 LOperand* value = UseRegisterAtStart(instr->value()); |
| 1666 return AssignEnvironment(new LCheckFunction(value)); |
| 1667 } |
| 1668 |
| 1669 |
| 1670 LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) { |
| 1671 LOperand* value = UseRegisterAtStart(instr->value()); |
| 1672 LInstruction* result = new LCheckMap(value); |
| 1673 return AssignEnvironment(result); |
| 1674 } |
| 1675 |
| 1676 |
| 1677 LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) { |
| 1678 HValue* value = instr->value(); |
| 1679 Representation input_rep = value->representation(); |
| 1680 LOperand* reg = UseRegister(value); |
| 1681 if (input_rep.IsDouble()) { |
| 1682 // Revisit this decision, here and 8 lines below. |
| 1683 return DefineAsRegister(new LClampDToUint8(reg, FixedTemp(f22))); |
| 1684 } else if (input_rep.IsInteger32()) { |
| 1685 return DefineAsRegister(new LClampIToUint8(reg)); |
| 1686 } else { |
| 1687 ASSERT(input_rep.IsTagged()); |
| 1688 // Register allocator doesn't (yet) support allocation of double |
| 1689 // temps. Reserve f22 explicitly. |
| 1690 LClampTToUint8* result = new LClampTToUint8(reg, FixedTemp(f22)); |
| 1691 return AssignEnvironment(DefineAsRegister(result)); |
| 1692 } |
| 1693 } |
| 1694 |
| 1695 |
| 1696 LInstruction* LChunkBuilder::DoToInt32(HToInt32* instr) { |
| 1697 HValue* value = instr->value(); |
| 1698 Representation input_rep = value->representation(); |
| 1699 LOperand* reg = UseRegister(value); |
| 1700 if (input_rep.IsDouble()) { |
| 1701 LOperand* temp1 = TempRegister(); |
| 1702 LOperand* temp2 = TempRegister(); |
| 1703 LDoubleToI* res = new LDoubleToI(reg, temp1, temp2); |
| 1704 return AssignEnvironment(DefineAsRegister(res)); |
| 1705 } else if (input_rep.IsInteger32()) { |
| 1706 // Canonicalization should already have removed the hydrogen instruction in |
| 1707 // this case, since it is a noop. |
| 1708 UNREACHABLE(); |
| 1709 return NULL; |
| 1710 } else { |
| 1711 ASSERT(input_rep.IsTagged()); |
| 1712 LOperand* temp1 = TempRegister(); |
| 1713 LOperand* temp2 = TempRegister(); |
| 1714 LOperand* temp3 = FixedTemp(f22); |
| 1715 LTaggedToI* res = new LTaggedToI(reg, temp1, temp2, temp3); |
| 1716 return AssignEnvironment(DefineSameAsFirst(res)); |
| 1717 } |
| 1718 } |
| 1719 |
| 1720 |
| 1721 LInstruction* LChunkBuilder::DoReturn(HReturn* instr) { |
| 1722 return new LReturn(UseFixed(instr->value(), v0)); |
| 1723 } |
| 1724 |
| 1725 |
| 1726 LInstruction* LChunkBuilder::DoConstant(HConstant* instr) { |
| 1727 Representation r = instr->representation(); |
| 1728 if (r.IsInteger32()) { |
| 1729 return DefineAsRegister(new LConstantI); |
| 1730 } else if (r.IsDouble()) { |
| 1731 return DefineAsRegister(new LConstantD); |
| 1732 } else if (r.IsTagged()) { |
| 1733 return DefineAsRegister(new LConstantT); |
| 1734 } else { |
| 1735 UNREACHABLE(); |
| 1736 return NULL; |
| 1737 } |
| 1738 } |
| 1739 |
| 1740 |
| 1741 LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) { |
| 1742 LLoadGlobalCell* result = new LLoadGlobalCell; |
| 1743 return instr->RequiresHoleCheck() |
| 1744 ? AssignEnvironment(DefineAsRegister(result)) |
| 1745 : DefineAsRegister(result); |
| 1746 } |
| 1747 |
| 1748 |
| 1749 LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) { |
| 1750 LOperand* global_object = UseFixed(instr->global_object(), a0); |
| 1751 LLoadGlobalGeneric* result = new LLoadGlobalGeneric(global_object); |
| 1752 return MarkAsCall(DefineFixed(result, v0), instr); |
| 1753 } |
| 1754 |
| 1755 |
| 1756 LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) { |
| 1757 LOperand* temp = TempRegister(); |
| 1758 LOperand* value = UseTempRegister(instr->value()); |
| 1759 LInstruction* result = new LStoreGlobalCell(value, temp); |
| 1760 if (instr->RequiresHoleCheck()) result = AssignEnvironment(result); |
| 1761 return result; |
| 1762 } |
| 1763 |
| 1764 |
| 1765 LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) { |
| 1766 LOperand* global_object = UseFixed(instr->global_object(), a1); |
| 1767 LOperand* value = UseFixed(instr->value(), a0); |
| 1768 LStoreGlobalGeneric* result = |
| 1769 new LStoreGlobalGeneric(global_object, value); |
| 1770 return MarkAsCall(result, instr); |
| 1771 } |
| 1772 |
| 1773 |
| 1774 LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) { |
| 1775 LOperand* context = UseRegisterAtStart(instr->value()); |
| 1776 return DefineAsRegister(new LLoadContextSlot(context)); |
| 1777 } |
| 1778 |
| 1779 |
| 1780 LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) { |
| 1781 LOperand* context; |
| 1782 LOperand* value; |
| 1783 if (instr->NeedsWriteBarrier()) { |
| 1784 context = UseTempRegister(instr->context()); |
| 1785 value = UseTempRegister(instr->value()); |
| 1786 } else { |
| 1787 context = UseRegister(instr->context()); |
| 1788 value = UseRegister(instr->value()); |
| 1789 } |
| 1790 return new LStoreContextSlot(context, value); |
| 1791 } |
| 1792 |
| 1793 |
| 1794 LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) { |
| 1795 return DefineAsRegister( |
| 1796 new LLoadNamedField(UseRegisterAtStart(instr->object()))); |
| 1797 } |
| 1798 |
| 1799 |
| 1800 LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic( |
| 1801 HLoadNamedFieldPolymorphic* instr) { |
| 1802 ASSERT(instr->representation().IsTagged()); |
| 1803 if (instr->need_generic()) { |
| 1804 LOperand* obj = UseFixed(instr->object(), a0); |
| 1805 LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj); |
| 1806 return MarkAsCall(DefineFixed(result, v0), instr); |
| 1807 } else { |
| 1808 LOperand* obj = UseRegisterAtStart(instr->object()); |
| 1809 LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj); |
| 1810 return AssignEnvironment(DefineAsRegister(result)); |
| 1811 } |
| 1812 } |
| 1813 |
| 1814 |
| 1815 LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { |
| 1816 LOperand* object = UseFixed(instr->object(), a0); |
| 1817 LInstruction* result = DefineFixed(new LLoadNamedGeneric(object), v0); |
| 1818 return MarkAsCall(result, instr); |
| 1819 } |
| 1820 |
| 1821 |
| 1822 LInstruction* LChunkBuilder::DoLoadFunctionPrototype( |
| 1823 HLoadFunctionPrototype* instr) { |
| 1824 return AssignEnvironment(DefineAsRegister( |
| 1825 new LLoadFunctionPrototype(UseRegister(instr->function())))); |
| 1826 } |
| 1827 |
| 1828 |
| 1829 LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) { |
| 1830 LOperand* input = UseRegisterAtStart(instr->value()); |
| 1831 return DefineAsRegister(new LLoadElements(input)); |
| 1832 } |
| 1833 |
| 1834 |
| 1835 LInstruction* LChunkBuilder::DoLoadExternalArrayPointer( |
| 1836 HLoadExternalArrayPointer* instr) { |
| 1837 LOperand* input = UseRegisterAtStart(instr->value()); |
| 1838 return DefineAsRegister(new LLoadExternalArrayPointer(input)); |
| 1839 } |
| 1840 |
| 1841 |
| 1842 LInstruction* LChunkBuilder::DoLoadKeyedFastElement( |
| 1843 HLoadKeyedFastElement* instr) { |
| 1844 ASSERT(instr->representation().IsTagged()); |
| 1845 ASSERT(instr->key()->representation().IsInteger32()); |
| 1846 LOperand* obj = UseRegisterAtStart(instr->object()); |
| 1847 LOperand* key = UseRegisterAtStart(instr->key()); |
| 1848 LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key); |
| 1849 return AssignEnvironment(DefineAsRegister(result)); |
| 1850 } |
| 1851 |
| 1852 |
| 1853 LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement( |
| 1854 HLoadKeyedFastDoubleElement* instr) { |
| 1855 ASSERT(instr->representation().IsDouble()); |
| 1856 ASSERT(instr->key()->representation().IsInteger32()); |
| 1857 LOperand* elements = UseTempRegister(instr->elements()); |
| 1858 LOperand* key = UseRegisterOrConstantAtStart(instr->key()); |
| 1859 LLoadKeyedFastDoubleElement* result = |
| 1860 new LLoadKeyedFastDoubleElement(elements, key); |
| 1861 return AssignEnvironment(DefineAsRegister(result)); |
| 1862 } |
| 1863 |
| 1864 |
| 1865 LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement( |
| 1866 HLoadKeyedSpecializedArrayElement* instr) { |
| 1867 ElementsKind elements_kind = instr->elements_kind(); |
| 1868 Representation representation(instr->representation()); |
| 1869 ASSERT( |
| 1870 (representation.IsInteger32() && |
| 1871 (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && |
| 1872 (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || |
| 1873 (representation.IsDouble() && |
| 1874 ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || |
| 1875 (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); |
| 1876 ASSERT(instr->key()->representation().IsInteger32()); |
| 1877 LOperand* external_pointer = UseRegister(instr->external_pointer()); |
| 1878 LOperand* key = UseRegisterOrConstant(instr->key()); |
| 1879 LLoadKeyedSpecializedArrayElement* result = |
| 1880 new LLoadKeyedSpecializedArrayElement(external_pointer, key); |
| 1881 LInstruction* load_instr = DefineAsRegister(result); |
| 1882 // An unsigned int array load might overflow and cause a deopt, make sure it |
| 1883 // has an environment. |
| 1884 return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) ? |
| 1885 AssignEnvironment(load_instr) : load_instr; |
| 1886 } |
| 1887 |
| 1888 |
| 1889 LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { |
| 1890 LOperand* object = UseFixed(instr->object(), a1); |
| 1891 LOperand* key = UseFixed(instr->key(), a0); |
| 1892 |
| 1893 LInstruction* result = |
| 1894 DefineFixed(new LLoadKeyedGeneric(object, key), v0); |
| 1895 return MarkAsCall(result, instr); |
| 1896 } |
| 1897 |
| 1898 |
| 1899 LInstruction* LChunkBuilder::DoStoreKeyedFastElement( |
| 1900 HStoreKeyedFastElement* instr) { |
| 1901 bool needs_write_barrier = instr->NeedsWriteBarrier(); |
| 1902 ASSERT(instr->value()->representation().IsTagged()); |
| 1903 ASSERT(instr->object()->representation().IsTagged()); |
| 1904 ASSERT(instr->key()->representation().IsInteger32()); |
| 1905 |
| 1906 LOperand* obj = UseTempRegister(instr->object()); |
| 1907 LOperand* val = needs_write_barrier |
| 1908 ? UseTempRegister(instr->value()) |
| 1909 : UseRegisterAtStart(instr->value()); |
| 1910 LOperand* key = needs_write_barrier |
| 1911 ? UseTempRegister(instr->key()) |
| 1912 : UseRegisterOrConstantAtStart(instr->key()); |
| 1913 |
| 1914 return AssignEnvironment(new LStoreKeyedFastElement(obj, key, val)); |
| 1915 } |
| 1916 |
| 1917 |
| 1918 LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement( |
| 1919 HStoreKeyedFastDoubleElement* instr) { |
| 1920 ASSERT(instr->value()->representation().IsDouble()); |
| 1921 ASSERT(instr->elements()->representation().IsTagged()); |
| 1922 ASSERT(instr->key()->representation().IsInteger32()); |
| 1923 |
| 1924 LOperand* elements = UseRegisterAtStart(instr->elements()); |
| 1925 LOperand* val = UseTempRegister(instr->value()); |
| 1926 LOperand* key = UseRegisterOrConstantAtStart(instr->key()); |
| 1927 |
| 1928 return new LStoreKeyedFastDoubleElement(elements, key, val); |
| 1929 } |
| 1930 |
| 1931 |
| 1932 LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement( |
| 1933 HStoreKeyedSpecializedArrayElement* instr) { |
| 1934 Representation representation(instr->value()->representation()); |
| 1935 ElementsKind elements_kind = instr->elements_kind(); |
| 1936 ASSERT( |
| 1937 (representation.IsInteger32() && |
| 1938 (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && |
| 1939 (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || |
| 1940 (representation.IsDouble() && |
| 1941 ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || |
| 1942 (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); |
| 1943 ASSERT(instr->external_pointer()->representation().IsExternal()); |
| 1944 ASSERT(instr->key()->representation().IsInteger32()); |
| 1945 |
| 1946 LOperand* external_pointer = UseRegister(instr->external_pointer()); |
| 1947 bool val_is_temp_register = |
| 1948 elements_kind == EXTERNAL_PIXEL_ELEMENTS || |
| 1949 elements_kind == EXTERNAL_FLOAT_ELEMENTS; |
| 1950 LOperand* val = val_is_temp_register |
| 1951 ? UseTempRegister(instr->value()) |
| 1952 : UseRegister(instr->value()); |
| 1953 LOperand* key = UseRegisterOrConstant(instr->key()); |
| 1954 |
| 1955 return new LStoreKeyedSpecializedArrayElement(external_pointer, |
| 1956 key, |
| 1957 val); |
| 1958 } |
| 1959 |
| 1960 |
| 1961 LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) { |
| 1962 LOperand* obj = UseFixed(instr->object(), a2); |
| 1963 LOperand* key = UseFixed(instr->key(), a1); |
| 1964 LOperand* val = UseFixed(instr->value(), a0); |
| 1965 |
| 1966 ASSERT(instr->object()->representation().IsTagged()); |
| 1967 ASSERT(instr->key()->representation().IsTagged()); |
| 1968 ASSERT(instr->value()->representation().IsTagged()); |
| 1969 |
| 1970 return MarkAsCall(new LStoreKeyedGeneric(obj, key, val), instr); |
| 1971 } |
| 1972 |
| 1973 |
| 1974 LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) { |
| 1975 bool needs_write_barrier = instr->NeedsWriteBarrier(); |
| 1976 |
| 1977 LOperand* obj = needs_write_barrier |
| 1978 ? UseTempRegister(instr->object()) |
| 1979 : UseRegisterAtStart(instr->object()); |
| 1980 |
| 1981 LOperand* val = needs_write_barrier |
| 1982 ? UseTempRegister(instr->value()) |
| 1983 : UseRegister(instr->value()); |
| 1984 |
| 1985 return new LStoreNamedField(obj, val); |
| 1986 } |
| 1987 |
| 1988 |
| 1989 LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) { |
| 1990 LOperand* obj = UseFixed(instr->object(), a1); |
| 1991 LOperand* val = UseFixed(instr->value(), a0); |
| 1992 |
| 1993 LInstruction* result = new LStoreNamedGeneric(obj, val); |
| 1994 return MarkAsCall(result, instr); |
| 1995 } |
| 1996 |
| 1997 |
| 1998 LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) { |
| 1999 LOperand* left = UseRegisterAtStart(instr->left()); |
| 2000 LOperand* right = UseRegisterAtStart(instr->right()); |
| 2001 return MarkAsCall(DefineFixed(new LStringAdd(left, right), v0), instr); |
| 2002 } |
| 2003 |
| 2004 |
| 2005 LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) { |
| 2006 LOperand* string = UseTempRegister(instr->string()); |
| 2007 LOperand* index = UseTempRegister(instr->index()); |
| 2008 LStringCharCodeAt* result = new LStringCharCodeAt(string, index); |
| 2009 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result))); |
| 2010 } |
| 2011 |
| 2012 |
| 2013 LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) { |
| 2014 LOperand* char_code = UseRegister(instr->value()); |
| 2015 LStringCharFromCode* result = new LStringCharFromCode(char_code); |
| 2016 return AssignPointerMap(DefineAsRegister(result)); |
| 2017 } |
| 2018 |
| 2019 |
| 2020 LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) { |
| 2021 LOperand* string = UseRegisterAtStart(instr->value()); |
| 2022 return DefineAsRegister(new LStringLength(string)); |
| 2023 } |
| 2024 |
| 2025 |
| 2026 LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) { |
| 2027 return MarkAsCall(DefineFixed(new LArrayLiteral, v0), instr); |
| 2028 } |
| 2029 |
| 2030 |
| 2031 LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) { |
| 2032 return MarkAsCall(DefineFixed(new LObjectLiteral, v0), instr); |
| 2033 } |
| 2034 |
| 2035 |
| 2036 LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) { |
| 2037 return MarkAsCall(DefineFixed(new LRegExpLiteral, v0), instr); |
| 2038 } |
| 2039 |
| 2040 |
| 2041 LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) { |
| 2042 return MarkAsCall(DefineFixed(new LFunctionLiteral, v0), instr); |
| 2043 } |
| 2044 |
| 2045 |
| 2046 LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) { |
| 2047 LOperand* object = UseFixed(instr->object(), a0); |
| 2048 LOperand* key = UseFixed(instr->key(), a1); |
| 2049 LDeleteProperty* result = new LDeleteProperty(object, key); |
| 2050 return MarkAsCall(DefineFixed(result, v0), instr); |
| 2051 } |
| 2052 |
| 2053 |
| 2054 LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) { |
| 2055 allocator_->MarkAsOsrEntry(); |
| 2056 current_block_->last_environment()->set_ast_id(instr->ast_id()); |
| 2057 return AssignEnvironment(new LOsrEntry); |
| 2058 } |
| 2059 |
| 2060 |
| 2061 LInstruction* LChunkBuilder::DoParameter(HParameter* instr) { |
| 2062 int spill_index = chunk()->GetParameterStackSlot(instr->index()); |
| 2063 return DefineAsSpilled(new LParameter, spill_index); |
| 2064 } |
| 2065 |
| 2066 |
| 2067 LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) { |
| 2068 int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width. |
| 2069 if (spill_index > LUnallocated::kMaxFixedIndex) { |
| 2070 Abort("Too many spill slots needed for OSR"); |
| 2071 spill_index = 0; |
| 2072 } |
| 2073 return DefineAsSpilled(new LUnknownOSRValue, spill_index); |
| 2074 } |
| 2075 |
| 2076 |
| 2077 LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) { |
| 2078 argument_count_ -= instr->argument_count(); |
| 2079 return MarkAsCall(DefineFixed(new LCallStub, v0), instr); |
| 2080 } |
| 2081 |
| 2082 |
| 2083 LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) { |
| 2084 // There are no real uses of the arguments object. |
| 2085 // arguments.length and element access are supported directly on |
| 2086 // stack arguments, and any real arguments object use causes a bailout. |
| 2087 // So this value is never used. |
| 2088 return NULL; |
| 2089 } |
| 2090 |
| 2091 |
| 2092 LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) { |
| 2093 LOperand* arguments = UseRegister(instr->arguments()); |
| 2094 LOperand* length = UseTempRegister(instr->length()); |
| 2095 LOperand* index = UseRegister(instr->index()); |
| 2096 LAccessArgumentsAt* result = new LAccessArgumentsAt(arguments, length, index); |
| 2097 return AssignEnvironment(DefineAsRegister(result)); |
| 2098 } |
| 2099 |
| 2100 |
| 2101 LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) { |
| 2102 LOperand* object = UseFixed(instr->value(), a0); |
| 2103 LToFastProperties* result = new LToFastProperties(object); |
| 2104 return MarkAsCall(DefineFixed(result, v0), instr); |
| 2105 } |
| 2106 |
| 2107 |
| 2108 LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) { |
| 2109 LTypeof* result = new LTypeof(UseFixed(instr->value(), a0)); |
| 2110 return MarkAsCall(DefineFixed(result, v0), instr); |
| 2111 } |
| 2112 |
| 2113 |
| 2114 LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) { |
| 2115 return new LTypeofIsAndBranch(UseTempRegister(instr->value())); |
| 2116 } |
| 2117 |
| 2118 |
| 2119 LInstruction* LChunkBuilder::DoIsConstructCallAndBranch( |
| 2120 HIsConstructCallAndBranch* instr) { |
| 2121 return new LIsConstructCallAndBranch(TempRegister()); |
| 2122 } |
| 2123 |
| 2124 |
| 2125 LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { |
| 2126 HEnvironment* env = current_block_->last_environment(); |
| 2127 ASSERT(env != NULL); |
| 2128 |
| 2129 env->set_ast_id(instr->ast_id()); |
| 2130 |
| 2131 env->Drop(instr->pop_count()); |
| 2132 for (int i = 0; i < instr->values()->length(); ++i) { |
| 2133 HValue* value = instr->values()->at(i); |
| 2134 if (instr->HasAssignedIndexAt(i)) { |
| 2135 env->Bind(instr->GetAssignedIndexAt(i), value); |
| 2136 } else { |
| 2137 env->Push(value); |
| 2138 } |
| 2139 } |
| 2140 |
| 2141 // If there is an instruction pending deoptimization environment create a |
| 2142 // lazy bailout instruction to capture the environment. |
| 2143 if (pending_deoptimization_ast_id_ == instr->ast_id()) { |
| 2144 LInstruction* result = new LLazyBailout; |
| 2145 result = AssignEnvironment(result); |
| 2146 instruction_pending_deoptimization_environment_-> |
| 2147 set_deoptimization_environment(result->environment()); |
| 2148 ClearInstructionPendingDeoptimizationEnvironment(); |
| 2149 return result; |
| 2150 } |
| 2151 |
| 2152 return NULL; |
| 2153 } |
| 2154 |
| 2155 |
| 2156 LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) { |
| 2157 if (instr->is_function_entry()) { |
| 2158 return MarkAsCall(new LStackCheck, instr); |
| 2159 } else { |
| 2160 ASSERT(instr->is_backwards_branch()); |
| 2161 return AssignEnvironment(AssignPointerMap(new LStackCheck)); |
| 2162 } |
| 2163 } |
| 2164 |
| 2165 |
| 2166 LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { |
| 2167 HEnvironment* outer = current_block_->last_environment(); |
| 2168 HConstant* undefined = graph()->GetConstantUndefined(); |
| 2169 HEnvironment* inner = outer->CopyForInlining(instr->closure(), |
| 2170 instr->function(), |
| 2171 undefined, |
| 2172 instr->call_kind()); |
| 2173 current_block_->UpdateEnvironment(inner); |
| 2174 chunk_->AddInlinedClosure(instr->closure()); |
| 2175 return NULL; |
| 2176 } |
| 2177 |
| 2178 |
| 2179 LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) { |
| 2180 HEnvironment* outer = current_block_->last_environment()->outer(); |
| 2181 current_block_->UpdateEnvironment(outer); |
| 2182 return NULL; |
| 2183 } |
| 2184 |
| 2185 |
| 2186 LInstruction* LChunkBuilder::DoIn(HIn* instr) { |
| 2187 LOperand* key = UseRegisterAtStart(instr->key()); |
| 2188 LOperand* object = UseRegisterAtStart(instr->object()); |
| 2189 LIn* result = new LIn(key, object); |
| 2190 return MarkAsCall(DefineFixed(result, v0), instr); |
| 2191 } |
| 2192 |
| 2193 |
| 2194 } } // namespace v8::internal |
OLD | NEW |