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