| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 namespace v8 { | 36 namespace v8 { |
| 37 namespace internal { | 37 namespace internal { |
| 38 | 38 |
| 39 | 39 |
| 40 // When invoking builtins, we need to record the safepoint in the middle of | 40 // When invoking builtins, we need to record the safepoint in the middle of |
| 41 // the invoke instruction sequence generated by the macro assembler. | 41 // the invoke instruction sequence generated by the macro assembler. |
| 42 class SafepointGenerator : public CallWrapper { | 42 class SafepointGenerator : public CallWrapper { |
| 43 public: | 43 public: |
| 44 SafepointGenerator(LCodeGen* codegen, | 44 SafepointGenerator(LCodeGen* codegen, |
| 45 LPointerMap* pointers, | 45 LPointerMap* pointers, |
| 46 int deoptimization_index) | 46 Safepoint::DeoptMode mode) |
| 47 : codegen_(codegen), | 47 : codegen_(codegen), |
| 48 pointers_(pointers), | 48 pointers_(pointers), |
| 49 deoptimization_index_(deoptimization_index) { } | 49 deopt_mode_(mode) { } |
| 50 virtual ~SafepointGenerator() { } | 50 virtual ~SafepointGenerator() { } |
| 51 | 51 |
| 52 virtual void BeforeCall(int call_size) const { | 52 virtual void BeforeCall(int call_size) const { |
| 53 ASSERT(call_size >= 0); | 53 codegen_->EnsureSpaceForLazyDeopt(Deoptimizer::patch_size() - call_size); |
| 54 // Ensure that we have enough space after the previous safepoint position | |
| 55 // for the jump generated there. | |
| 56 int call_end = codegen_->masm()->pc_offset() + call_size; | |
| 57 int prev_jump_end = codegen_->LastSafepointEnd() + kMinSafepointSize; | |
| 58 if (call_end < prev_jump_end) { | |
| 59 int padding_size = prev_jump_end - call_end; | |
| 60 STATIC_ASSERT(kMinSafepointSize <= 9); // One multibyte nop is enough. | |
| 61 codegen_->masm()->nop(padding_size); | |
| 62 } | |
| 63 } | 54 } |
| 64 | 55 |
| 65 virtual void AfterCall() const { | 56 virtual void AfterCall() const { |
| 66 codegen_->RecordSafepoint(pointers_, deoptimization_index_); | 57 codegen_->RecordSafepoint(pointers_, deopt_mode_); |
| 67 } | 58 } |
| 68 | 59 |
| 69 private: | 60 private: |
| 70 static const int kMinSafepointSize = | |
| 71 MacroAssembler::kShortCallInstructionLength; | |
| 72 LCodeGen* codegen_; | 61 LCodeGen* codegen_; |
| 73 LPointerMap* pointers_; | 62 LPointerMap* pointers_; |
| 74 int deoptimization_index_; | 63 Safepoint::DeoptMode deopt_mode_; |
| 75 }; | 64 }; |
| 76 | 65 |
| 77 | 66 |
| 78 #define __ masm()-> | 67 #define __ masm()-> |
| 79 | 68 |
| 80 bool LCodeGen::GenerateCode() { | 69 bool LCodeGen::GenerateCode() { |
| 81 HPhase phase("Code generation", chunk()); | 70 HPhase phase("Code generation", chunk()); |
| 82 ASSERT(is_unused()); | 71 ASSERT(is_unused()); |
| 83 status_ = GENERATING; | 72 status_ = GENERATING; |
| 84 return GeneratePrologue() && | 73 return GeneratePrologue() && |
| 85 GenerateBody() && | 74 GenerateBody() && |
| 86 GenerateDeferredCode() && | 75 GenerateDeferredCode() && |
| 87 GenerateJumpTable() && | 76 GenerateJumpTable() && |
| 88 GenerateSafepointTable(); | 77 GenerateSafepointTable(); |
| 89 } | 78 } |
| 90 | 79 |
| 91 | 80 |
| 92 void LCodeGen::FinishCode(Handle<Code> code) { | 81 void LCodeGen::FinishCode(Handle<Code> code) { |
| 93 ASSERT(is_done()); | 82 ASSERT(is_done()); |
| 94 code->set_stack_slots(GetStackSlotCount()); | 83 code->set_stack_slots(GetStackSlotCount()); |
| 95 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); | 84 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); |
| 96 PopulateDeoptimizationData(code); | 85 PopulateDeoptimizationData(code); |
| 97 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code); | |
| 98 } | 86 } |
| 99 | 87 |
| 100 | 88 |
| 101 void LCodeGen::Abort(const char* format, ...) { | 89 void LCodeGen::Abort(const char* format, ...) { |
| 102 if (FLAG_trace_bailout) { | 90 if (FLAG_trace_bailout) { |
| 103 SmartArrayPointer<char> name( | 91 SmartArrayPointer<char> name( |
| 104 info()->shared_info()->DebugName()->ToCString()); | 92 info()->shared_info()->DebugName()->ToCString()); |
| 105 PrintF("Aborting LCodeGen in @\"%s\": ", *name); | 93 PrintF("Aborting LCodeGen in @\"%s\": ", *name); |
| 106 va_list arguments; | 94 va_list arguments; |
| 107 va_start(arguments, format); | 95 va_start(arguments, format); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 if (heap_slots > 0) { | 181 if (heap_slots > 0) { |
| 194 Comment(";;; Allocate local context"); | 182 Comment(";;; Allocate local context"); |
| 195 // Argument to NewContext is the function, which is still in rdi. | 183 // Argument to NewContext is the function, which is still in rdi. |
| 196 __ push(rdi); | 184 __ push(rdi); |
| 197 if (heap_slots <= FastNewContextStub::kMaximumSlots) { | 185 if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
| 198 FastNewContextStub stub(heap_slots); | 186 FastNewContextStub stub(heap_slots); |
| 199 __ CallStub(&stub); | 187 __ CallStub(&stub); |
| 200 } else { | 188 } else { |
| 201 __ CallRuntime(Runtime::kNewFunctionContext, 1); | 189 __ CallRuntime(Runtime::kNewFunctionContext, 1); |
| 202 } | 190 } |
| 203 RecordSafepoint(Safepoint::kNoDeoptimizationIndex); | 191 RecordSafepoint(Safepoint::kNoLazyDeopt); |
| 204 // Context is returned in both rax and rsi. It replaces the context | 192 // Context is returned in both rax and rsi. It replaces the context |
| 205 // passed to us. It's saved in the stack and kept live in rsi. | 193 // passed to us. It's saved in the stack and kept live in rsi. |
| 206 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); | 194 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); |
| 207 | 195 |
| 208 // Copy any necessary parameters into the context. | 196 // Copy any necessary parameters into the context. |
| 209 int num_parameters = scope()->num_parameters(); | 197 int num_parameters = scope()->num_parameters(); |
| 210 for (int i = 0; i < num_parameters; i++) { | 198 for (int i = 0; i < num_parameters; i++) { |
| 211 Variable* var = scope()->parameter(i); | 199 Variable* var = scope()->parameter(i); |
| 212 if (var->IsContextSlot()) { | 200 if (var->IsContextSlot()) { |
| 213 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 201 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 if (instr->IsLabel()) { | 233 if (instr->IsLabel()) { |
| 246 LLabel* label = LLabel::cast(instr); | 234 LLabel* label = LLabel::cast(instr); |
| 247 emit_instructions = !label->HasReplacement(); | 235 emit_instructions = !label->HasReplacement(); |
| 248 } | 236 } |
| 249 | 237 |
| 250 if (emit_instructions) { | 238 if (emit_instructions) { |
| 251 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic()); | 239 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic()); |
| 252 instr->CompileToNative(this); | 240 instr->CompileToNative(this); |
| 253 } | 241 } |
| 254 } | 242 } |
| 243 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); |
| 255 return !is_aborted(); | 244 return !is_aborted(); |
| 256 } | 245 } |
| 257 | 246 |
| 258 | 247 |
| 259 LInstruction* LCodeGen::GetNextInstruction() { | |
| 260 if (current_instruction_ < instructions_->length() - 1) { | |
| 261 return instructions_->at(current_instruction_ + 1); | |
| 262 } else { | |
| 263 return NULL; | |
| 264 } | |
| 265 } | |
| 266 | |
| 267 | |
| 268 bool LCodeGen::GenerateJumpTable() { | 248 bool LCodeGen::GenerateJumpTable() { |
| 269 for (int i = 0; i < jump_table_.length(); i++) { | 249 for (int i = 0; i < jump_table_.length(); i++) { |
| 270 __ bind(&jump_table_[i].label); | 250 __ bind(&jump_table_[i].label); |
| 271 __ Jump(jump_table_[i].address, RelocInfo::RUNTIME_ENTRY); | 251 __ Jump(jump_table_[i].address, RelocInfo::RUNTIME_ENTRY); |
| 272 } | 252 } |
| 273 return !is_aborted(); | 253 return !is_aborted(); |
| 274 } | 254 } |
| 275 | 255 |
| 276 | 256 |
| 277 bool LCodeGen::GenerateDeferredCode() { | 257 bool LCodeGen::GenerateDeferredCode() { |
| 278 ASSERT(is_generating()); | 258 ASSERT(is_generating()); |
| 279 if (deferred_.length() > 0) { | 259 if (deferred_.length() > 0) { |
| 280 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { | 260 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { |
| 281 LDeferredCode* code = deferred_[i]; | 261 LDeferredCode* code = deferred_[i]; |
| 282 __ bind(code->entry()); | 262 __ bind(code->entry()); |
| 283 code->Generate(); | 263 code->Generate(); |
| 284 __ jmp(code->exit()); | 264 __ jmp(code->exit()); |
| 285 } | 265 } |
| 286 | |
| 287 // Pad code to ensure that the last piece of deferred code have | |
| 288 // room for lazy bailout. | |
| 289 while ((masm()->pc_offset() - LastSafepointEnd()) | |
| 290 < Deoptimizer::patch_size()) { | |
| 291 int padding = masm()->pc_offset() - LastSafepointEnd(); | |
| 292 if (padding > 9) { | |
| 293 __ nop(9); | |
| 294 } else { | |
| 295 __ nop(padding); | |
| 296 } | |
| 297 } | |
| 298 } | 266 } |
| 299 | 267 |
| 300 // Deferred code is the last part of the instruction sequence. Mark | 268 // Deferred code is the last part of the instruction sequence. Mark |
| 301 // the generated code as done unless we bailed out. | 269 // the generated code as done unless we bailed out. |
| 302 if (!is_aborted()) status_ = DONE; | 270 if (!is_aborted()) status_ = DONE; |
| 303 return !is_aborted(); | 271 return !is_aborted(); |
| 304 } | 272 } |
| 305 | 273 |
| 306 | 274 |
| 307 bool LCodeGen::GenerateSafepointTable() { | 275 bool LCodeGen::GenerateSafepointTable() { |
| 308 ASSERT(is_done()); | 276 ASSERT(is_done()); |
| 309 // Ensure that there is space at the end of the code to write a number | |
| 310 // of jump instructions, as well as to afford writing a call near the end | |
| 311 // of the code. | |
| 312 // The jumps are used when there isn't room in the code stream to write | |
| 313 // a long call instruction. Instead it writes a shorter call to a | |
| 314 // jump instruction in the same code object. | |
| 315 // The calls are used when lazy deoptimizing a function and calls to a | |
| 316 // deoptimization function. | |
| 317 int short_deopts = safepoints_.CountShortDeoptimizationIntervals( | |
| 318 static_cast<unsigned>(MacroAssembler::kJumpInstructionLength)); | |
| 319 int byte_count = (short_deopts) * MacroAssembler::kJumpInstructionLength; | |
| 320 while (byte_count-- > 0) { | |
| 321 __ int3(); | |
| 322 } | |
| 323 safepoints_.Emit(masm(), GetStackSlotCount()); | 277 safepoints_.Emit(masm(), GetStackSlotCount()); |
| 324 return !is_aborted(); | 278 return !is_aborted(); |
| 325 } | 279 } |
| 326 | 280 |
| 327 | 281 |
| 328 Register LCodeGen::ToRegister(int index) const { | 282 Register LCodeGen::ToRegister(int index) const { |
| 329 return Register::FromAllocationIndex(index); | 283 return Register::FromAllocationIndex(index); |
| 330 } | 284 } |
| 331 | 285 |
| 332 | 286 |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 468 UNREACHABLE(); | 422 UNREACHABLE(); |
| 469 } | 423 } |
| 470 } | 424 } |
| 471 | 425 |
| 472 | 426 |
| 473 void LCodeGen::CallCodeGeneric(Handle<Code> code, | 427 void LCodeGen::CallCodeGeneric(Handle<Code> code, |
| 474 RelocInfo::Mode mode, | 428 RelocInfo::Mode mode, |
| 475 LInstruction* instr, | 429 LInstruction* instr, |
| 476 SafepointMode safepoint_mode, | 430 SafepointMode safepoint_mode, |
| 477 int argc) { | 431 int argc) { |
| 432 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size() - masm()->CallSize(code)); |
| 478 ASSERT(instr != NULL); | 433 ASSERT(instr != NULL); |
| 479 LPointerMap* pointers = instr->pointer_map(); | 434 LPointerMap* pointers = instr->pointer_map(); |
| 480 RecordPosition(pointers->position()); | 435 RecordPosition(pointers->position()); |
| 481 __ call(code, mode); | 436 __ call(code, mode); |
| 482 RegisterLazyDeoptimization(instr, safepoint_mode, argc); | 437 RecordSafepointWithLazyDeopt(instr, safepoint_mode, argc); |
| 483 | 438 |
| 484 // Signal that we don't inline smi code before these stubs in the | 439 // Signal that we don't inline smi code before these stubs in the |
| 485 // optimizing code generator. | 440 // optimizing code generator. |
| 486 if (code->kind() == Code::BINARY_OP_IC || | 441 if (code->kind() == Code::BINARY_OP_IC || |
| 487 code->kind() == Code::COMPARE_IC) { | 442 code->kind() == Code::COMPARE_IC) { |
| 488 __ nop(); | 443 __ nop(); |
| 489 } | 444 } |
| 490 } | 445 } |
| 491 | 446 |
| 492 | 447 |
| 493 void LCodeGen::CallCode(Handle<Code> code, | 448 void LCodeGen::CallCode(Handle<Code> code, |
| 494 RelocInfo::Mode mode, | 449 RelocInfo::Mode mode, |
| 495 LInstruction* instr) { | 450 LInstruction* instr) { |
| 496 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT, 0); | 451 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT, 0); |
| 497 } | 452 } |
| 498 | 453 |
| 499 | 454 |
| 500 void LCodeGen::CallRuntime(const Runtime::Function* function, | 455 void LCodeGen::CallRuntime(const Runtime::Function* function, |
| 501 int num_arguments, | 456 int num_arguments, |
| 502 LInstruction* instr) { | 457 LInstruction* instr) { |
| 503 ASSERT(instr != NULL); | 458 ASSERT(instr != NULL); |
| 504 ASSERT(instr->HasPointerMap()); | 459 ASSERT(instr->HasPointerMap()); |
| 505 LPointerMap* pointers = instr->pointer_map(); | 460 LPointerMap* pointers = instr->pointer_map(); |
| 506 RecordPosition(pointers->position()); | 461 RecordPosition(pointers->position()); |
| 507 | 462 |
| 508 __ CallRuntime(function, num_arguments); | 463 __ CallRuntime(function, num_arguments); |
| 509 RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT, 0); | 464 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0); |
| 510 } | 465 } |
| 511 | 466 |
| 512 | 467 |
| 513 void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, | 468 void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, |
| 514 int argc, | 469 int argc, |
| 515 LInstruction* instr) { | 470 LInstruction* instr) { |
| 516 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 471 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 517 __ CallRuntimeSaveDoubles(id); | 472 __ CallRuntimeSaveDoubles(id); |
| 518 RecordSafepointWithRegisters( | 473 RecordSafepointWithRegisters( |
| 519 instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex); | 474 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt); |
| 520 } | 475 } |
| 521 | 476 |
| 522 | 477 |
| 523 void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr, | 478 void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment, |
| 524 SafepointMode safepoint_mode, | 479 Safepoint::DeoptMode mode) { |
| 525 int argc) { | |
| 526 // Create the environment to bailout to. If the call has side effects | |
| 527 // execution has to continue after the call otherwise execution can continue | |
| 528 // from a previous bailout point repeating the call. | |
| 529 LEnvironment* deoptimization_environment; | |
| 530 if (instr->HasDeoptimizationEnvironment()) { | |
| 531 deoptimization_environment = instr->deoptimization_environment(); | |
| 532 } else { | |
| 533 deoptimization_environment = instr->environment(); | |
| 534 } | |
| 535 | |
| 536 RegisterEnvironmentForDeoptimization(deoptimization_environment); | |
| 537 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) { | |
| 538 ASSERT(argc == 0); | |
| 539 RecordSafepoint(instr->pointer_map(), | |
| 540 deoptimization_environment->deoptimization_index()); | |
| 541 } else { | |
| 542 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS); | |
| 543 RecordSafepointWithRegisters( | |
| 544 instr->pointer_map(), | |
| 545 argc, | |
| 546 deoptimization_environment->deoptimization_index()); | |
| 547 } | |
| 548 } | |
| 549 | |
| 550 | |
| 551 void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) { | |
| 552 if (!environment->HasBeenRegistered()) { | 480 if (!environment->HasBeenRegistered()) { |
| 553 // Physical stack frame layout: | 481 // Physical stack frame layout: |
| 554 // -x ............. -4 0 ..................................... y | 482 // -x ............. -4 0 ..................................... y |
| 555 // [incoming arguments] [spill slots] [pushed outgoing arguments] | 483 // [incoming arguments] [spill slots] [pushed outgoing arguments] |
| 556 | 484 |
| 557 // Layout of the environment: | 485 // Layout of the environment: |
| 558 // 0 ..................................................... size-1 | 486 // 0 ..................................................... size-1 |
| 559 // [parameters] [locals] [expression stack including arguments] | 487 // [parameters] [locals] [expression stack including arguments] |
| 560 | 488 |
| 561 // Layout of the translation: | 489 // Layout of the translation: |
| 562 // 0 ........................................................ size - 1 + 4 | 490 // 0 ........................................................ size - 1 + 4 |
| 563 // [expression stack including arguments] [locals] [4 words] [parameters] | 491 // [expression stack including arguments] [locals] [4 words] [parameters] |
| 564 // |>------------ translation_size ------------<| | 492 // |>------------ translation_size ------------<| |
| 565 | 493 |
| 566 int frame_count = 0; | 494 int frame_count = 0; |
| 567 for (LEnvironment* e = environment; e != NULL; e = e->outer()) { | 495 for (LEnvironment* e = environment; e != NULL; e = e->outer()) { |
| 568 ++frame_count; | 496 ++frame_count; |
| 569 } | 497 } |
| 570 Translation translation(&translations_, frame_count); | 498 Translation translation(&translations_, frame_count); |
| 571 WriteTranslation(environment, &translation); | 499 WriteTranslation(environment, &translation); |
| 572 int deoptimization_index = deoptimizations_.length(); | 500 int deoptimization_index = deoptimizations_.length(); |
| 573 environment->Register(deoptimization_index, translation.index()); | 501 int pc_offset = masm()->pc_offset(); |
| 502 environment->Register(deoptimization_index, |
| 503 translation.index(), |
| 504 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1); |
| 574 deoptimizations_.Add(environment); | 505 deoptimizations_.Add(environment); |
| 575 } | 506 } |
| 576 } | 507 } |
| 577 | 508 |
| 578 | 509 |
| 579 void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { | 510 void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { |
| 580 RegisterEnvironmentForDeoptimization(environment); | 511 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); |
| 581 ASSERT(environment->HasBeenRegistered()); | 512 ASSERT(environment->HasBeenRegistered()); |
| 582 int id = environment->deoptimization_index(); | 513 int id = environment->deoptimization_index(); |
| 583 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); | 514 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); |
| 584 ASSERT(entry != NULL); | 515 ASSERT(entry != NULL); |
| 585 if (entry == NULL) { | 516 if (entry == NULL) { |
| 586 Abort("bailout was not prepared"); | 517 Abort("bailout was not prepared"); |
| 587 return; | 518 return; |
| 588 } | 519 } |
| 589 | 520 |
| 590 if (cc == no_condition) { | 521 if (cc == no_condition) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 622 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id())); | 553 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id())); |
| 623 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_)); | 554 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_)); |
| 624 | 555 |
| 625 // Populate the deoptimization entries. | 556 // Populate the deoptimization entries. |
| 626 for (int i = 0; i < length; i++) { | 557 for (int i = 0; i < length; i++) { |
| 627 LEnvironment* env = deoptimizations_[i]; | 558 LEnvironment* env = deoptimizations_[i]; |
| 628 data->SetAstId(i, Smi::FromInt(env->ast_id())); | 559 data->SetAstId(i, Smi::FromInt(env->ast_id())); |
| 629 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index())); | 560 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index())); |
| 630 data->SetArgumentsStackHeight(i, | 561 data->SetArgumentsStackHeight(i, |
| 631 Smi::FromInt(env->arguments_stack_height())); | 562 Smi::FromInt(env->arguments_stack_height())); |
| 563 data->SetPc(i, Smi::FromInt(env->pc_offset())); |
| 632 } | 564 } |
| 633 code->set_deoptimization_data(*data); | 565 code->set_deoptimization_data(*data); |
| 634 } | 566 } |
| 635 | 567 |
| 636 | 568 |
| 637 int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) { | 569 int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) { |
| 638 int result = deoptimization_literals_.length(); | 570 int result = deoptimization_literals_.length(); |
| 639 for (int i = 0; i < deoptimization_literals_.length(); ++i) { | 571 for (int i = 0; i < deoptimization_literals_.length(); ++i) { |
| 640 if (deoptimization_literals_[i].is_identical_to(literal)) return i; | 572 if (deoptimization_literals_[i].is_identical_to(literal)) return i; |
| 641 } | 573 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 653 for (int i = 0, length = inlined_closures->length(); | 585 for (int i = 0, length = inlined_closures->length(); |
| 654 i < length; | 586 i < length; |
| 655 i++) { | 587 i++) { |
| 656 DefineDeoptimizationLiteral(inlined_closures->at(i)); | 588 DefineDeoptimizationLiteral(inlined_closures->at(i)); |
| 657 } | 589 } |
| 658 | 590 |
| 659 inlined_function_count_ = deoptimization_literals_.length(); | 591 inlined_function_count_ = deoptimization_literals_.length(); |
| 660 } | 592 } |
| 661 | 593 |
| 662 | 594 |
| 595 void LCodeGen::RecordSafepointWithLazyDeopt( |
| 596 LInstruction* instr, SafepointMode safepoint_mode, int argc) { |
| 597 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) { |
| 598 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt); |
| 599 } else { |
| 600 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS); |
| 601 RecordSafepointWithRegisters( |
| 602 instr->pointer_map(), argc, Safepoint::kLazyDeopt); |
| 603 } |
| 604 } |
| 605 |
| 606 |
| 663 void LCodeGen::RecordSafepoint( | 607 void LCodeGen::RecordSafepoint( |
| 664 LPointerMap* pointers, | 608 LPointerMap* pointers, |
| 665 Safepoint::Kind kind, | 609 Safepoint::Kind kind, |
| 666 int arguments, | 610 int arguments, |
| 667 int deoptimization_index) { | 611 Safepoint::DeoptMode deopt_mode) { |
| 668 ASSERT(kind == expected_safepoint_kind_); | 612 ASSERT(kind == expected_safepoint_kind_); |
| 669 | 613 |
| 670 const ZoneList<LOperand*>* operands = pointers->operands(); | 614 const ZoneList<LOperand*>* operands = pointers->operands(); |
| 671 | 615 |
| 672 Safepoint safepoint = safepoints_.DefineSafepoint(masm(), | 616 Safepoint safepoint = safepoints_.DefineSafepoint(masm(), |
| 673 kind, arguments, deoptimization_index); | 617 kind, arguments, deopt_mode); |
| 674 for (int i = 0; i < operands->length(); i++) { | 618 for (int i = 0; i < operands->length(); i++) { |
| 675 LOperand* pointer = operands->at(i); | 619 LOperand* pointer = operands->at(i); |
| 676 if (pointer->IsStackSlot()) { | 620 if (pointer->IsStackSlot()) { |
| 677 safepoint.DefinePointerSlot(pointer->index()); | 621 safepoint.DefinePointerSlot(pointer->index()); |
| 678 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { | 622 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { |
| 679 safepoint.DefinePointerRegister(ToRegister(pointer)); | 623 safepoint.DefinePointerRegister(ToRegister(pointer)); |
| 680 } | 624 } |
| 681 } | 625 } |
| 682 if (kind & Safepoint::kWithRegisters) { | 626 if (kind & Safepoint::kWithRegisters) { |
| 683 // Register rsi always contains a pointer to the context. | 627 // Register rsi always contains a pointer to the context. |
| 684 safepoint.DefinePointerRegister(rsi); | 628 safepoint.DefinePointerRegister(rsi); |
| 685 } | 629 } |
| 686 } | 630 } |
| 687 | 631 |
| 688 | 632 |
| 689 void LCodeGen::RecordSafepoint(LPointerMap* pointers, | 633 void LCodeGen::RecordSafepoint(LPointerMap* pointers, |
| 690 int deoptimization_index) { | 634 Safepoint::DeoptMode deopt_mode) { |
| 691 RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); | 635 RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode); |
| 692 } | 636 } |
| 693 | 637 |
| 694 | 638 |
| 695 void LCodeGen::RecordSafepoint(int deoptimization_index) { | 639 void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) { |
| 696 LPointerMap empty_pointers(RelocInfo::kNoPosition); | 640 LPointerMap empty_pointers(RelocInfo::kNoPosition); |
| 697 RecordSafepoint(&empty_pointers, deoptimization_index); | 641 RecordSafepoint(&empty_pointers, deopt_mode); |
| 698 } | 642 } |
| 699 | 643 |
| 700 | 644 |
| 701 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, | 645 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, |
| 702 int arguments, | 646 int arguments, |
| 703 int deoptimization_index) { | 647 Safepoint::DeoptMode deopt_mode) { |
| 704 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, | 648 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, deopt_mode); |
| 705 deoptimization_index); | |
| 706 } | 649 } |
| 707 | 650 |
| 708 | 651 |
| 709 void LCodeGen::RecordPosition(int position) { | 652 void LCodeGen::RecordPosition(int position) { |
| 710 if (position == RelocInfo::kNoPosition) return; | 653 if (position == RelocInfo::kNoPosition) return; |
| 711 masm()->positions_recorder()->RecordPosition(position); | 654 masm()->positions_recorder()->RecordPosition(position); |
| 712 } | 655 } |
| 713 | 656 |
| 714 | 657 |
| 715 void LCodeGen::DoLabel(LLabel* label) { | 658 void LCodeGen::DoLabel(LLabel* label) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 730 | 673 |
| 731 | 674 |
| 732 void LCodeGen::DoGap(LGap* gap) { | 675 void LCodeGen::DoGap(LGap* gap) { |
| 733 for (int i = LGap::FIRST_INNER_POSITION; | 676 for (int i = LGap::FIRST_INNER_POSITION; |
| 734 i <= LGap::LAST_INNER_POSITION; | 677 i <= LGap::LAST_INNER_POSITION; |
| 735 i++) { | 678 i++) { |
| 736 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i); | 679 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i); |
| 737 LParallelMove* move = gap->GetParallelMove(inner_pos); | 680 LParallelMove* move = gap->GetParallelMove(inner_pos); |
| 738 if (move != NULL) DoParallelMove(move); | 681 if (move != NULL) DoParallelMove(move); |
| 739 } | 682 } |
| 740 | |
| 741 LInstruction* next = GetNextInstruction(); | |
| 742 if (next != NULL && next->IsLazyBailout()) { | |
| 743 int pc = masm()->pc_offset(); | |
| 744 safepoints_.SetPcAfterGap(pc); | |
| 745 } | |
| 746 } | 683 } |
| 747 | 684 |
| 748 | 685 |
| 749 void LCodeGen::DoInstructionGap(LInstructionGap* instr) { | 686 void LCodeGen::DoInstructionGap(LInstructionGap* instr) { |
| 750 DoGap(instr); | 687 DoGap(instr); |
| 751 } | 688 } |
| 752 | 689 |
| 753 | 690 |
| 754 void LCodeGen::DoParameter(LParameter* instr) { | 691 void LCodeGen::DoParameter(LParameter* instr) { |
| 755 // Nothing to do. | 692 // Nothing to do. |
| (...skipping 1088 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1844 } | 1781 } |
| 1845 | 1782 |
| 1846 | 1783 |
| 1847 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { | 1784 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { |
| 1848 class DeferredInstanceOfKnownGlobal: public LDeferredCode { | 1785 class DeferredInstanceOfKnownGlobal: public LDeferredCode { |
| 1849 public: | 1786 public: |
| 1850 DeferredInstanceOfKnownGlobal(LCodeGen* codegen, | 1787 DeferredInstanceOfKnownGlobal(LCodeGen* codegen, |
| 1851 LInstanceOfKnownGlobal* instr) | 1788 LInstanceOfKnownGlobal* instr) |
| 1852 : LDeferredCode(codegen), instr_(instr) { } | 1789 : LDeferredCode(codegen), instr_(instr) { } |
| 1853 virtual void Generate() { | 1790 virtual void Generate() { |
| 1854 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); | 1791 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_); |
| 1855 } | 1792 } |
| 1856 | 1793 |
| 1857 Label* map_check() { return &map_check_; } | 1794 Label* map_check() { return &map_check_; } |
| 1858 | 1795 |
| 1859 private: | 1796 private: |
| 1860 LInstanceOfKnownGlobal* instr_; | 1797 LInstanceOfKnownGlobal* instr_; |
| 1861 Label map_check_; | 1798 Label map_check_; |
| 1862 }; | 1799 }; |
| 1863 | 1800 |
| 1864 | 1801 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1903 __ JumpIfNotString(object, kScratchRegister, deferred->entry()); | 1840 __ JumpIfNotString(object, kScratchRegister, deferred->entry()); |
| 1904 | 1841 |
| 1905 __ bind(&false_result); | 1842 __ bind(&false_result); |
| 1906 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); | 1843 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); |
| 1907 | 1844 |
| 1908 __ bind(deferred->exit()); | 1845 __ bind(deferred->exit()); |
| 1909 __ bind(&done); | 1846 __ bind(&done); |
| 1910 } | 1847 } |
| 1911 | 1848 |
| 1912 | 1849 |
| 1913 void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, | 1850 void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, |
| 1914 Label* map_check) { | 1851 Label* map_check) { |
| 1915 { | 1852 { |
| 1916 PushSafepointRegistersScope scope(this); | 1853 PushSafepointRegistersScope scope(this); |
| 1917 InstanceofStub::Flags flags = static_cast<InstanceofStub::Flags>( | 1854 InstanceofStub::Flags flags = static_cast<InstanceofStub::Flags>( |
| 1918 InstanceofStub::kNoFlags | InstanceofStub::kCallSiteInlineCheck); | 1855 InstanceofStub::kNoFlags | InstanceofStub::kCallSiteInlineCheck); |
| 1919 InstanceofStub stub(flags); | 1856 InstanceofStub stub(flags); |
| 1920 | 1857 |
| 1921 __ push(ToRegister(instr->InputAt(0))); | 1858 __ push(ToRegister(instr->InputAt(0))); |
| 1922 __ Push(instr->function()); | 1859 __ Push(instr->function()); |
| 1923 | 1860 |
| 1924 static const int kAdditionalDelta = 10; | 1861 static const int kAdditionalDelta = 10; |
| 1925 int delta = | 1862 int delta = |
| 1926 masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta; | 1863 masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta; |
| 1927 ASSERT(delta >= 0); | 1864 ASSERT(delta >= 0); |
| 1928 __ push_imm32(delta); | 1865 __ push_imm32(delta); |
| 1929 | 1866 |
| 1930 // We are pushing three values on the stack but recording a | 1867 // We are pushing three values on the stack but recording a |
| 1931 // safepoint with two arguments because stub is going to | 1868 // safepoint with two arguments because stub is going to |
| 1932 // remove the third argument from the stack before jumping | 1869 // remove the third argument from the stack before jumping |
| 1933 // to instanceof builtin on the slow path. | 1870 // to instanceof builtin on the slow path. |
| 1934 CallCodeGeneric(stub.GetCode(), | 1871 CallCodeGeneric(stub.GetCode(), |
| 1935 RelocInfo::CODE_TARGET, | 1872 RelocInfo::CODE_TARGET, |
| 1936 instr, | 1873 instr, |
| 1937 RECORD_SAFEPOINT_WITH_REGISTERS, | 1874 RECORD_SAFEPOINT_WITH_REGISTERS, |
| 1938 2); | 1875 2); |
| 1939 ASSERT(delta == masm_->SizeOfCodeGeneratedSince(map_check)); | 1876 ASSERT(delta == masm_->SizeOfCodeGeneratedSince(map_check)); |
| 1877 ASSERT(instr->HasDeoptimizationEnvironment()); |
| 1878 LEnvironment* env = instr->deoptimization_environment(); |
| 1879 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); |
| 1940 // Move result to a register that survives the end of the | 1880 // Move result to a register that survives the end of the |
| 1941 // PushSafepointRegisterScope. | 1881 // PushSafepointRegisterScope. |
| 1942 __ movq(kScratchRegister, rax); | 1882 __ movq(kScratchRegister, rax); |
| 1943 } | 1883 } |
| 1944 __ testq(kScratchRegister, kScratchRegister); | 1884 __ testq(kScratchRegister, kScratchRegister); |
| 1945 Label load_false; | 1885 Label load_false; |
| 1946 Label done; | 1886 Label done; |
| 1947 __ j(not_zero, &load_false); | 1887 __ j(not_zero, &load_false); |
| 1948 __ LoadRoot(rax, Heap::kTrueValueRootIndex); | 1888 __ LoadRoot(rax, Heap::kTrueValueRootIndex); |
| 1949 __ jmp(&done); | 1889 __ jmp(&done); |
| (...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2501 __ j(zero, &invoke, Label::kNear); | 2441 __ j(zero, &invoke, Label::kNear); |
| 2502 __ bind(&loop); | 2442 __ bind(&loop); |
| 2503 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize)); | 2443 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize)); |
| 2504 __ decl(length); | 2444 __ decl(length); |
| 2505 __ j(not_zero, &loop); | 2445 __ j(not_zero, &loop); |
| 2506 | 2446 |
| 2507 // Invoke the function. | 2447 // Invoke the function. |
| 2508 __ bind(&invoke); | 2448 __ bind(&invoke); |
| 2509 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); | 2449 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); |
| 2510 LPointerMap* pointers = instr->pointer_map(); | 2450 LPointerMap* pointers = instr->pointer_map(); |
| 2511 LEnvironment* env = instr->deoptimization_environment(); | |
| 2512 RecordPosition(pointers->position()); | 2451 RecordPosition(pointers->position()); |
| 2513 RegisterEnvironmentForDeoptimization(env); | 2452 SafepointGenerator safepoint_generator( |
| 2514 SafepointGenerator safepoint_generator(this, | 2453 this, pointers, Safepoint::kLazyDeopt); |
| 2515 pointers, | |
| 2516 env->deoptimization_index()); | |
| 2517 v8::internal::ParameterCount actual(rax); | 2454 v8::internal::ParameterCount actual(rax); |
| 2518 __ InvokeFunction(function, actual, CALL_FUNCTION, | 2455 __ InvokeFunction(function, actual, CALL_FUNCTION, |
| 2519 safepoint_generator, CALL_AS_METHOD); | 2456 safepoint_generator, CALL_AS_METHOD); |
| 2520 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2457 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2521 } | 2458 } |
| 2522 | 2459 |
| 2523 | 2460 |
| 2524 void LCodeGen::DoPushArgument(LPushArgument* instr) { | 2461 void LCodeGen::DoPushArgument(LPushArgument* instr) { |
| 2525 LOperand* argument = instr->InputAt(0); | 2462 LOperand* argument = instr->InputAt(0); |
| 2526 EmitPushTaggedOperand(argument); | 2463 EmitPushTaggedOperand(argument); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2584 | 2521 |
| 2585 // Invoke function. | 2522 // Invoke function. |
| 2586 __ SetCallKind(rcx, call_kind); | 2523 __ SetCallKind(rcx, call_kind); |
| 2587 if (*function == *info()->closure()) { | 2524 if (*function == *info()->closure()) { |
| 2588 __ CallSelf(); | 2525 __ CallSelf(); |
| 2589 } else { | 2526 } else { |
| 2590 __ call(FieldOperand(rdi, JSFunction::kCodeEntryOffset)); | 2527 __ call(FieldOperand(rdi, JSFunction::kCodeEntryOffset)); |
| 2591 } | 2528 } |
| 2592 | 2529 |
| 2593 // Setup deoptimization. | 2530 // Setup deoptimization. |
| 2594 RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT, 0); | 2531 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0); |
| 2595 | 2532 |
| 2596 // Restore context. | 2533 // Restore context. |
| 2597 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2534 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2598 } | 2535 } |
| 2599 | 2536 |
| 2600 | 2537 |
| 2601 void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { | 2538 void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { |
| 2602 ASSERT(ToRegister(instr->result()).is(rax)); | 2539 ASSERT(ToRegister(instr->result()).is(rax)); |
| 2603 __ Move(rdi, instr->function()); | 2540 __ Move(rdi, instr->function()); |
| 2604 CallKnownFunction(instr->function(), | 2541 CallKnownFunction(instr->function(), |
| (...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2931 UNREACHABLE(); | 2868 UNREACHABLE(); |
| 2932 } | 2869 } |
| 2933 } | 2870 } |
| 2934 | 2871 |
| 2935 | 2872 |
| 2936 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { | 2873 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { |
| 2937 ASSERT(ToRegister(instr->function()).is(rdi)); | 2874 ASSERT(ToRegister(instr->function()).is(rdi)); |
| 2938 ASSERT(instr->HasPointerMap()); | 2875 ASSERT(instr->HasPointerMap()); |
| 2939 ASSERT(instr->HasDeoptimizationEnvironment()); | 2876 ASSERT(instr->HasDeoptimizationEnvironment()); |
| 2940 LPointerMap* pointers = instr->pointer_map(); | 2877 LPointerMap* pointers = instr->pointer_map(); |
| 2941 LEnvironment* env = instr->deoptimization_environment(); | |
| 2942 RecordPosition(pointers->position()); | 2878 RecordPosition(pointers->position()); |
| 2943 RegisterEnvironmentForDeoptimization(env); | 2879 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); |
| 2944 SafepointGenerator generator(this, pointers, env->deoptimization_index()); | |
| 2945 ParameterCount count(instr->arity()); | 2880 ParameterCount count(instr->arity()); |
| 2946 __ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD); | 2881 __ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD); |
| 2947 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2882 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2948 } | 2883 } |
| 2949 | 2884 |
| 2950 | 2885 |
| 2951 void LCodeGen::DoCallKeyed(LCallKeyed* instr) { | 2886 void LCodeGen::DoCallKeyed(LCallKeyed* instr) { |
| 2952 ASSERT(ToRegister(instr->key()).is(rcx)); | 2887 ASSERT(ToRegister(instr->key()).is(rcx)); |
| 2953 ASSERT(ToRegister(instr->result()).is(rax)); | 2888 ASSERT(ToRegister(instr->result()).is(rax)); |
| 2954 | 2889 |
| (...skipping 1075 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4030 __ j(not_equal, &check_frame_marker, Label::kNear); | 3965 __ j(not_equal, &check_frame_marker, Label::kNear); |
| 4031 __ movq(temp, Operand(rax, StandardFrameConstants::kCallerFPOffset)); | 3966 __ movq(temp, Operand(rax, StandardFrameConstants::kCallerFPOffset)); |
| 4032 | 3967 |
| 4033 // Check the marker in the calling frame. | 3968 // Check the marker in the calling frame. |
| 4034 __ bind(&check_frame_marker); | 3969 __ bind(&check_frame_marker); |
| 4035 __ Cmp(Operand(temp, StandardFrameConstants::kMarkerOffset), | 3970 __ Cmp(Operand(temp, StandardFrameConstants::kMarkerOffset), |
| 4036 Smi::FromInt(StackFrame::CONSTRUCT)); | 3971 Smi::FromInt(StackFrame::CONSTRUCT)); |
| 4037 } | 3972 } |
| 4038 | 3973 |
| 4039 | 3974 |
| 3975 void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) { |
| 3976 // Ensure that we have enough space after the previous lazy-bailout |
| 3977 // instruction for patching the code here. |
| 3978 int current_pc = masm()->pc_offset(); |
| 3979 if (current_pc < last_lazy_deopt_pc_ + space_needed) { |
| 3980 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc; |
| 3981 while (padding_size > 0) { |
| 3982 int nop_size = padding_size > 9 ? 9 : padding_size; |
| 3983 __ nop(nop_size); |
| 3984 padding_size -= nop_size; |
| 3985 } |
| 3986 } |
| 3987 } |
| 3988 |
| 3989 |
| 4040 void LCodeGen::DoLazyBailout(LLazyBailout* instr) { | 3990 void LCodeGen::DoLazyBailout(LLazyBailout* instr) { |
| 4041 // No code for lazy bailout instruction. Used to capture environment after a | 3991 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); |
| 4042 // call for populating the safepoint data with deoptimization data. | 3992 last_lazy_deopt_pc_ = masm()->pc_offset(); |
| 3993 ASSERT(instr->HasEnvironment()); |
| 3994 LEnvironment* env = instr->environment(); |
| 3995 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); |
| 3996 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); |
| 4043 } | 3997 } |
| 4044 | 3998 |
| 4045 | 3999 |
| 4046 void LCodeGen::DoDeoptimize(LDeoptimize* instr) { | 4000 void LCodeGen::DoDeoptimize(LDeoptimize* instr) { |
| 4047 DeoptimizeIf(no_condition, instr->environment()); | 4001 DeoptimizeIf(no_condition, instr->environment()); |
| 4048 } | 4002 } |
| 4049 | 4003 |
| 4050 | 4004 |
| 4051 void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { | 4005 void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { |
| 4052 LOperand* obj = instr->object(); | 4006 LOperand* obj = instr->object(); |
| 4053 LOperand* key = instr->key(); | 4007 LOperand* key = instr->key(); |
| 4054 EmitPushTaggedOperand(obj); | 4008 EmitPushTaggedOperand(obj); |
| 4055 EmitPushTaggedOperand(key); | 4009 EmitPushTaggedOperand(key); |
| 4056 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); | 4010 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); |
| 4057 LPointerMap* pointers = instr->pointer_map(); | 4011 LPointerMap* pointers = instr->pointer_map(); |
| 4058 LEnvironment* env = instr->deoptimization_environment(); | |
| 4059 RecordPosition(pointers->position()); | 4012 RecordPosition(pointers->position()); |
| 4060 RegisterEnvironmentForDeoptimization(env); | |
| 4061 // Create safepoint generator that will also ensure enough space in the | 4013 // Create safepoint generator that will also ensure enough space in the |
| 4062 // reloc info for patching in deoptimization (since this is invoking a | 4014 // reloc info for patching in deoptimization (since this is invoking a |
| 4063 // builtin) | 4015 // builtin) |
| 4064 SafepointGenerator safepoint_generator(this, | 4016 SafepointGenerator safepoint_generator( |
| 4065 pointers, | 4017 this, pointers, Safepoint::kLazyDeopt); |
| 4066 env->deoptimization_index()); | |
| 4067 __ Push(Smi::FromInt(strict_mode_flag())); | 4018 __ Push(Smi::FromInt(strict_mode_flag())); |
| 4068 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator); | 4019 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator); |
| 4069 } | 4020 } |
| 4070 | 4021 |
| 4071 | 4022 |
| 4072 void LCodeGen::DoIn(LIn* instr) { | 4023 void LCodeGen::DoIn(LIn* instr) { |
| 4073 LOperand* obj = instr->object(); | 4024 LOperand* obj = instr->object(); |
| 4074 LOperand* key = instr->key(); | 4025 LOperand* key = instr->key(); |
| 4075 EmitPushTaggedOperand(key); | 4026 EmitPushTaggedOperand(key); |
| 4076 EmitPushTaggedOperand(obj); | 4027 EmitPushTaggedOperand(obj); |
| 4077 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); | 4028 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); |
| 4078 LPointerMap* pointers = instr->pointer_map(); | 4029 LPointerMap* pointers = instr->pointer_map(); |
| 4079 LEnvironment* env = instr->deoptimization_environment(); | |
| 4080 RecordPosition(pointers->position()); | 4030 RecordPosition(pointers->position()); |
| 4081 RegisterEnvironmentForDeoptimization(env); | 4031 SafepointGenerator safepoint_generator( |
| 4082 // Create safepoint generator that will also ensure enough space in the | 4032 this, pointers, Safepoint::kLazyDeopt); |
| 4083 // reloc info for patching in deoptimization (since this is invoking a | |
| 4084 // builtin) | |
| 4085 SafepointGenerator safepoint_generator(this, | |
| 4086 pointers, | |
| 4087 env->deoptimization_index()); | |
| 4088 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); | 4033 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); |
| 4089 } | 4034 } |
| 4090 | 4035 |
| 4091 | 4036 |
| 4092 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { | 4037 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { |
| 4093 { | 4038 PushSafepointRegistersScope scope(this); |
| 4094 PushSafepointRegistersScope scope(this); | 4039 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 4095 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 4040 __ CallRuntimeSaveDoubles(Runtime::kStackGuard); |
| 4096 __ CallRuntimeSaveDoubles(Runtime::kStackGuard); | 4041 RecordSafepointWithLazyDeopt(instr, RECORD_SAFEPOINT_WITH_REGISTERS, 0); |
| 4097 RegisterLazyDeoptimization(instr, RECORD_SAFEPOINT_WITH_REGISTERS, 0); | 4042 ASSERT(instr->HasEnvironment()); |
| 4098 } | 4043 LEnvironment* env = instr->environment(); |
| 4099 | 4044 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); |
| 4100 // The gap code includes the restoring of the safepoint registers. | |
| 4101 int pc = masm()->pc_offset(); | |
| 4102 safepoints_.SetPcAfterGap(pc); | |
| 4103 } | 4045 } |
| 4104 | 4046 |
| 4105 | 4047 |
| 4106 void LCodeGen::DoStackCheck(LStackCheck* instr) { | 4048 void LCodeGen::DoStackCheck(LStackCheck* instr) { |
| 4107 class DeferredStackCheck: public LDeferredCode { | 4049 class DeferredStackCheck: public LDeferredCode { |
| 4108 public: | 4050 public: |
| 4109 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr) | 4051 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr) |
| 4110 : LDeferredCode(codegen), instr_(instr) { } | 4052 : LDeferredCode(codegen), instr_(instr) { } |
| 4111 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); } | 4053 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); } |
| 4112 private: | 4054 private: |
| 4113 LStackCheck* instr_; | 4055 LStackCheck* instr_; |
| 4114 }; | 4056 }; |
| 4115 | 4057 |
| 4058 ASSERT(instr->HasEnvironment()); |
| 4059 LEnvironment* env = instr->environment(); |
| 4060 // There is no LLazyBailout instruction for stack-checks. We have to |
| 4061 // prepare for lazy deoptimization explicitly here. |
| 4116 if (instr->hydrogen()->is_function_entry()) { | 4062 if (instr->hydrogen()->is_function_entry()) { |
| 4117 // Perform stack overflow check. | 4063 // Perform stack overflow check. |
| 4118 Label done; | 4064 Label done; |
| 4119 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 4065 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
| 4120 __ j(above_equal, &done, Label::kNear); | 4066 __ j(above_equal, &done, Label::kNear); |
| 4121 StackCheckStub stub; | 4067 StackCheckStub stub; |
| 4122 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 4068 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 4069 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); |
| 4070 last_lazy_deopt_pc_ = masm()->pc_offset(); |
| 4123 __ bind(&done); | 4071 __ bind(&done); |
| 4072 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); |
| 4073 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); |
| 4124 } else { | 4074 } else { |
| 4125 ASSERT(instr->hydrogen()->is_backwards_branch()); | 4075 ASSERT(instr->hydrogen()->is_backwards_branch()); |
| 4126 // Perform stack overflow check if this goto needs it before jumping. | 4076 // Perform stack overflow check if this goto needs it before jumping. |
| 4127 DeferredStackCheck* deferred_stack_check = | 4077 DeferredStackCheck* deferred_stack_check = |
| 4128 new DeferredStackCheck(this, instr); | 4078 new DeferredStackCheck(this, instr); |
| 4129 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 4079 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
| 4130 __ j(below, deferred_stack_check->entry()); | 4080 __ j(below, deferred_stack_check->entry()); |
| 4081 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); |
| 4082 last_lazy_deopt_pc_ = masm()->pc_offset(); |
| 4131 __ bind(instr->done_label()); | 4083 __ bind(instr->done_label()); |
| 4132 deferred_stack_check->SetExit(instr->done_label()); | 4084 deferred_stack_check->SetExit(instr->done_label()); |
| 4085 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); |
| 4086 // Don't record a deoptimization index for the safepoint here. |
| 4087 // This will be done explicitly when emitting call and the safepoint in |
| 4088 // the deferred code. |
| 4133 } | 4089 } |
| 4134 } | 4090 } |
| 4135 | 4091 |
| 4136 | 4092 |
| 4137 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { | 4093 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { |
| 4138 // This is a pseudo-instruction that ensures that the environment here is | 4094 // This is a pseudo-instruction that ensures that the environment here is |
| 4139 // properly registered for deoptimization and records the assembler's PC | 4095 // properly registered for deoptimization and records the assembler's PC |
| 4140 // offset. | 4096 // offset. |
| 4141 LEnvironment* environment = instr->environment(); | 4097 LEnvironment* environment = instr->environment(); |
| 4142 environment->SetSpilledRegisters(instr->SpilledRegisterArray(), | 4098 environment->SetSpilledRegisters(instr->SpilledRegisterArray(), |
| 4143 instr->SpilledDoubleRegisterArray()); | 4099 instr->SpilledDoubleRegisterArray()); |
| 4144 | 4100 |
| 4145 // If the environment were already registered, we would have no way of | 4101 // If the environment were already registered, we would have no way of |
| 4146 // backpatching it with the spill slot operands. | 4102 // backpatching it with the spill slot operands. |
| 4147 ASSERT(!environment->HasBeenRegistered()); | 4103 ASSERT(!environment->HasBeenRegistered()); |
| 4148 RegisterEnvironmentForDeoptimization(environment); | 4104 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); |
| 4149 ASSERT(osr_pc_offset_ == -1); | 4105 ASSERT(osr_pc_offset_ == -1); |
| 4150 osr_pc_offset_ = masm()->pc_offset(); | 4106 osr_pc_offset_ = masm()->pc_offset(); |
| 4151 } | 4107 } |
| 4152 | 4108 |
| 4153 #undef __ | 4109 #undef __ |
| 4154 | 4110 |
| 4155 } } // namespace v8::internal | 4111 } } // namespace v8::internal |
| 4156 | 4112 |
| 4157 #endif // V8_TARGET_ARCH_X64 | 4113 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |