Fix lazy deoptimization at HInvokeFunction and enable target-recording call-function...
authorfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 16 Nov 2011 08:44:30 +0000 (08:44 +0000)
committerfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 16 Nov 2011 08:44:30 +0000 (08:44 +0000)
Changes the way we do lazy deoptimization:

1. For side-effect instructions, we insert the lazy-deopt call at
the following LLazyBailout instruction.

     CALL
     GAP
     LAZY-BAILOUT ==> lazy-deopt-call

2. For other instructions (StackCheck) we insert it right after the
instruction since the deopt targets an earlier deoptimization environment.

   STACK-CHECK
   GAP ==> lazy-deopt-call

The pc of the lazy-deopt call that will be patched in is recorded in the
deoptimization input data. Each Lithium instruction can have 0..n safepoints.
All safepoints get the deoptimization index of the associated LAZY-BAILOUT
instruction. On lazy deoptimization we use the return-pc to find the safepoint.
The safepoint tells us the deoptimization index, which in turn finds us the
PC where to insert the lazy-deopt-call.

Additional changes:
 * RegExpLiteral marked it as having side-effects so that it
   gets an explicitlazy-bailout instruction (instead of
   treating it specially like stack-checks)
 * Enable target recording CallFunctionStub to achieve
   more inlining on optimized code.

BUG=v8:1789
TEST=jslint and uglify run without crashing, mjsunit/compiler/regress-lazy-deopt.js
Review URL: http://codereview.chromium.org/8492004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10006 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

20 files changed:
src/arm/deoptimizer-arm.cc
src/arm/lithium-codegen-arm.cc
src/arm/lithium-codegen-arm.h
src/deoptimizer.cc
src/hydrogen-instructions.h
src/ia32/deoptimizer-ia32.cc
src/ia32/full-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.h
src/ia32/lithium-ia32.h
src/lithium.h
src/objects.cc
src/objects.h
src/safepoint-table.cc
src/safepoint-table.h
src/x64/deoptimizer-x64.cc
src/x64/lithium-codegen-x64.cc
src/x64/lithium-codegen-x64.h
test/mjsunit/compiler/regress-funcaller.js
test/mjsunit/compiler/regress-lazy-deopt.js [new file with mode: 0644]

index 8505c7dfc1cf7ad3397ac043e48f589ab4dc1df8..4b54b6dbc2889e17970c53b2cf1823d4d0ce5a35 100644 (file)
@@ -44,12 +44,6 @@ int Deoptimizer::patch_size() {
 }
 
 
-void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
-  // Nothing to do. No new relocation information is written for lazy
-  // deoptimization on ARM.
-}
-
-
 void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
   HandleScope scope;
   AssertNoAllocation no_allocation;
@@ -58,58 +52,37 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
 
   // Get the optimized code.
   Code* code = function->code();
+  Address code_start_address = code->instruction_start();
 
   // Invalidate the relocation information, as it will become invalid by the
   // code patching below, and is not needed any more.
   code->InvalidateRelocation();
 
-  // For each return after a safepoint insert an absolute call to the
-  // corresponding deoptimization entry.
-  unsigned last_pc_offset = 0;
-  SafepointTable table(function->code());
-  for (unsigned i = 0; i < table.length(); i++) {
-    unsigned pc_offset = table.GetPcOffset(i);
-    SafepointEntry safepoint_entry = table.GetEntry(i);
-    int deoptimization_index = safepoint_entry.deoptimization_index();
-    int gap_code_size = safepoint_entry.gap_code_size();
-    // Check that we did not shoot past next safepoint.
-    CHECK(pc_offset >= last_pc_offset);
+  // For each LLazyBailout instruction insert a call to the corresponding
+  // deoptimization entry.
+  DeoptimizationInputData* deopt_data =
+      DeoptimizationInputData::cast(code->deoptimization_data());
 #ifdef DEBUG
-    // Destroy the code which is not supposed to be run again.
-    int instructions = (pc_offset - last_pc_offset) / Assembler::kInstrSize;
-    CodePatcher destroyer(code->instruction_start() + last_pc_offset,
-                          instructions);
-    for (int x = 0; x < instructions; x++) {
-      destroyer.masm()->bkpt(0);
-    }
+  Address prev_call_address = NULL;
 #endif
-    last_pc_offset = pc_offset;
-    if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
-      Address deoptimization_entry = Deoptimizer::GetDeoptimizationEntry(
-          deoptimization_index, Deoptimizer::LAZY);
-      last_pc_offset += gap_code_size;
-      int call_size_in_bytes = MacroAssembler::CallSize(deoptimization_entry,
-                                                        RelocInfo::NONE);
-      int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize;
-      ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0);
-      ASSERT(call_size_in_bytes <= patch_size());
-      CodePatcher patcher(code->instruction_start() + last_pc_offset,
-                          call_size_in_words);
-      patcher.masm()->Call(deoptimization_entry, RelocInfo::NONE);
-      last_pc_offset += call_size_in_bytes;
-    }
-  }
-
+  for (int i = 0; i < deopt_data->DeoptCount(); i++) {
+    if (deopt_data->Pc(i)->value() == -1) continue;
+    Address call_address = code_start_address + deopt_data->Pc(i)->value();
+    Address deopt_entry = GetDeoptimizationEntry(i, LAZY);
+    int call_size_in_bytes = MacroAssembler::CallSize(deopt_entry,
+                                                      RelocInfo::NONE);
+    int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize;
+    ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0);
+    ASSERT(call_size_in_bytes <= patch_size());
+    CodePatcher patcher(call_address, call_size_in_words);
+    patcher.masm()->Call(deopt_entry, RelocInfo::NONE);
+    ASSERT(prev_call_address == NULL ||
+           call_address >= prev_call_address + patch_size());
+    ASSERT(call_address + patch_size() <= code->instruction_end());
 #ifdef DEBUG
-  // Destroy the code which is not supposed to be run again.
-  int instructions =
-      (code->safepoint_table_offset() - last_pc_offset) / Assembler::kInstrSize;
-  CodePatcher destroyer(code->instruction_start() + last_pc_offset,
-                        instructions);
-  for (int x = 0; x < instructions; x++) {
-    destroyer.masm()->bkpt(0);
-  }
+    prev_call_address = call_address;
 #endif
+  }
 
   Isolate* isolate = code->GetIsolate();
 
@@ -131,11 +104,6 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
     PrintF("[forced deoptimization: ");
     function->PrintName();
     PrintF(" / %x]\n", reinterpret_cast<uint32_t>(function));
-#ifdef DEBUG
-    if (FLAG_print_code) {
-      code->PrintLn();
-    }
-#endif
   }
 }
 
index 54526ed01bf32cfb849b65ffdf1cd52a89005a0d..db1a365b948156b17ce25c3233d4ccece1aba1c0 100644 (file)
@@ -40,37 +40,22 @@ class SafepointGenerator : public CallWrapper {
  public:
   SafepointGenerator(LCodeGen* codegen,
                      LPointerMap* pointers,
-                     int deoptimization_index)
+                     Safepoint::DeoptMode mode)
       : codegen_(codegen),
         pointers_(pointers),
-        deoptimization_index_(deoptimization_index) { }
+        deopt_mode_(mode) { }
   virtual ~SafepointGenerator() { }
 
-  virtual void BeforeCall(int call_size) const {
-    ASSERT(call_size >= 0);
-    // Ensure that we have enough space after the previous safepoint position
-    // for the generated code there.
-    int call_end = codegen_->masm()->pc_offset() + call_size;
-    int prev_jump_end =
-        codegen_->LastSafepointEnd() + Deoptimizer::patch_size();
-    if (call_end < prev_jump_end) {
-      int padding_size = prev_jump_end - call_end;
-      ASSERT_EQ(0, padding_size % Assembler::kInstrSize);
-      while (padding_size > 0) {
-        codegen_->masm()->nop();
-        padding_size -= Assembler::kInstrSize;
-      }
-    }
-  }
+  virtual void BeforeCall(int call_size) const { }
 
   virtual void AfterCall() const {
-    codegen_->RecordSafepoint(pointers_, deoptimization_index_);
+    codegen_->RecordSafepoint(pointers_, deopt_mode_);
   }
 
  private:
   LCodeGen* codegen_;
   LPointerMap* pointers_;
-  int deoptimization_index_;
+  Safepoint::DeoptMode deopt_mode_;
 };
 
 
@@ -103,7 +88,6 @@ void LCodeGen::FinishCode(Handle<Code> code) {
   code->set_stack_slots(GetStackSlotCount());
   code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
   PopulateDeoptimizationData(code);
-  Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
 }
 
 
@@ -200,7 +184,7 @@ bool LCodeGen::GeneratePrologue() {
     } else {
       __ CallRuntime(Runtime::kNewFunctionContext, 1);
     }
-    RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
+    RecordSafepoint(Safepoint::kNoLazyDeopt);
     // Context is returned in both r0 and cp.  It replaces the context
     // passed to us.  It's saved in the stack and kept live in cp.
     __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -249,19 +233,11 @@ bool LCodeGen::GenerateBody() {
       instr->CompileToNative(this);
     }
   }
+  EnsureSpaceForLazyDeopt();
   return !is_aborted();
 }
 
 
-LInstruction* LCodeGen::GetNextInstruction() {
-  if (current_instruction_ < instructions_->length() - 1) {
-    return instructions_->at(current_instruction_ + 1);
-  } else {
-    return NULL;
-  }
-}
-
-
 bool LCodeGen::GenerateDeferredCode() {
   ASSERT(is_generating());
   if (deferred_.length() > 0) {
@@ -274,13 +250,6 @@ bool LCodeGen::GenerateDeferredCode() {
       code->Generate();
       __ jmp(code->exit());
     }
-
-    // Pad code to ensure that the last piece of deferred code have
-    // room for lazy bailout.
-    while ((masm()->pc_offset() - LastSafepointEnd())
-           < Deoptimizer::patch_size()) {
-      __ nop();
-    }
   }
 
   // Force constant pool emission at the end of the deferred code to make
@@ -566,7 +535,7 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code,
   LPointerMap* pointers = instr->pointer_map();
   RecordPosition(pointers->position());
   __ Call(code, mode);
-  RegisterLazyDeoptimization(instr, safepoint_mode);
+  RecordSafepointWithLazyDeopt(instr, safepoint_mode);
 
   // Signal that we don't inline smi code before these stubs in the
   // optimizing code generator.
@@ -586,7 +555,7 @@ void LCodeGen::CallRuntime(const Runtime::Function* function,
   RecordPosition(pointers->position());
 
   __ CallRuntime(function, num_arguments);
-  RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT);
+  RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
 }
 
 
@@ -595,37 +564,12 @@ void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
                                        LInstruction* instr) {
   __ CallRuntimeSaveDoubles(id);
   RecordSafepointWithRegisters(
-      instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex);
+      instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
 }
 
 
-void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr,
-                                          SafepointMode safepoint_mode) {
-  // Create the environment to bailout to. If the call has side effects
-  // execution has to continue after the call otherwise execution can continue
-  // from a previous bailout point repeating the call.
-  LEnvironment* deoptimization_environment;
-  if (instr->HasDeoptimizationEnvironment()) {
-    deoptimization_environment = instr->deoptimization_environment();
-  } else {
-    deoptimization_environment = instr->environment();
-  }
-
-  RegisterEnvironmentForDeoptimization(deoptimization_environment);
-  if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
-    RecordSafepoint(instr->pointer_map(),
-                    deoptimization_environment->deoptimization_index());
-  } else {
-    ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
-    RecordSafepointWithRegisters(
-        instr->pointer_map(),
-        0,
-        deoptimization_environment->deoptimization_index());
-  }
-}
-
-
-void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
+void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
+                                                    Safepoint::DeoptMode mode) {
   if (!environment->HasBeenRegistered()) {
     // Physical stack frame layout:
     // -x ............. -4  0 ..................................... y
@@ -647,14 +591,17 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
     Translation translation(&translations_, frame_count);
     WriteTranslation(environment, &translation);
     int deoptimization_index = deoptimizations_.length();
-    environment->Register(deoptimization_index, translation.index());
+    int pc_offset = masm()->pc_offset();
+    environment->Register(deoptimization_index,
+                          translation.index(),
+                          (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
     deoptimizations_.Add(environment);
   }
 }
 
 
 void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
-  RegisterEnvironmentForDeoptimization(environment);
+  RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
   ASSERT(environment->HasBeenRegistered());
   int id = environment->deoptimization_index();
   Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
@@ -716,6 +663,7 @@ void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
     data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
     data->SetArgumentsStackHeight(i,
                                   Smi::FromInt(env->arguments_stack_height()));
+    data->SetPc(i, Smi::FromInt(env->pc_offset()));
   }
   code->set_deoptimization_data(*data);
 }
@@ -747,16 +695,28 @@ void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
 }
 
 
+void LCodeGen::RecordSafepointWithLazyDeopt(
+    LInstruction* instr, SafepointMode safepoint_mode) {
+  if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
+    RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
+  } else {
+    ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
+    RecordSafepointWithRegisters(
+        instr->pointer_map(), 0, Safepoint::kLazyDeopt);
+  }
+}
+
+
 void LCodeGen::RecordSafepoint(
     LPointerMap* pointers,
     Safepoint::Kind kind,
     int arguments,
-    int deoptimization_index) {
+    Safepoint::DeoptMode deopt_mode) {
   ASSERT(expected_safepoint_kind_ == kind);
 
   const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
   Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
-      kind, arguments, deoptimization_index);
+      kind, arguments, deopt_mode);
   for (int i = 0; i < operands->length(); i++) {
     LOperand* pointer = operands->at(i);
     if (pointer->IsStackSlot()) {
@@ -773,31 +733,31 @@ void LCodeGen::RecordSafepoint(
 
 
 void LCodeGen::RecordSafepoint(LPointerMap* pointers,
-                               int deoptimization_index) {
-  RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index);
+                               Safepoint::DeoptMode deopt_mode) {
+  RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode);
 }
 
 
-void LCodeGen::RecordSafepoint(int deoptimization_index) {
+void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
   LPointerMap empty_pointers(RelocInfo::kNoPosition);
-  RecordSafepoint(&empty_pointers, deoptimization_index);
+  RecordSafepoint(&empty_pointers, deopt_mode);
 }
 
 
 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
                                             int arguments,
-                                            int deoptimization_index) {
-  RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments,
-      deoptimization_index);
+                                            Safepoint::DeoptMode deopt_mode) {
+  RecordSafepoint(
+      pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
 }
 
 
 void LCodeGen::RecordSafepointWithRegistersAndDoubles(
     LPointerMap* pointers,
     int arguments,
-    int deoptimization_index) {
-  RecordSafepoint(pointers, Safepoint::kWithRegistersAndDoubles, arguments,
-      deoptimization_index);
+    Safepoint::DeoptMode deopt_mode) {
+  RecordSafepoint(
+      pointers, Safepoint::kWithRegistersAndDoubles, arguments, deopt_mode);
 }
 
 
@@ -832,12 +792,6 @@ void LCodeGen::DoGap(LGap* gap) {
     LParallelMove* move = gap->GetParallelMove(inner_pos);
     if (move != NULL) DoParallelMove(move);
   }
-
-  LInstruction* next = GetNextInstruction();
-  if (next != NULL && next->IsLazyBailout()) {
-    int pc = masm()->pc_offset();
-    safepoints_.SetPcAfterGap(pc);
-  }
 }
 
 
@@ -1145,7 +1099,7 @@ void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr,
   __ CallStub(&stub);
   RecordSafepointWithRegistersAndDoubles(instr->pointer_map(),
                                          0,
-                                         Safepoint::kNoDeoptimizationIndex);
+                                         Safepoint::kNoLazyDeopt);
   // Overwrite the stored value of r0 with the result of the stub.
   __ StoreToSafepointRegistersAndDoublesSlot(r0, r0);
 }
@@ -2062,7 +2016,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
                                   LInstanceOfKnownGlobal* instr)
         : LDeferredCode(codegen), instr_(instr) { }
     virtual void Generate() {
-      codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_);
+      codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
     }
     virtual LInstruction* instr() { return instr_; }
     Label* map_check() { return &map_check_; }
@@ -2129,8 +2083,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
 }
 
 
-void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
-                                                Label* map_check) {
+void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
+                                               Label* map_check) {
   Register result = ToRegister(instr->result());
   ASSERT(result.is(r0));
 
@@ -2162,6 +2116,9 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
                   RelocInfo::CODE_TARGET,
                   instr,
                   RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
+  ASSERT(instr->HasDeoptimizationEnvironment());
+  LEnvironment* env = instr->deoptimization_environment();
+  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
   // Put the result value into the result register slot and
   // restore all registers.
   __ StoreToSafepointRegisterSlot(result, result);
@@ -2778,12 +2735,9 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
   __ bind(&invoke);
   ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
   LPointerMap* pointers = instr->pointer_map();
-  LEnvironment* env = instr->deoptimization_environment();
   RecordPosition(pointers->position());
-  RegisterEnvironmentForDeoptimization(env);
-  SafepointGenerator safepoint_generator(this,
-                                         pointers,
-                                         env->deoptimization_index());
+  SafepointGenerator safepoint_generator(
+      this, pointers, Safepoint::kLazyDeopt);
   // The number of arguments is stored in receiver which is r0, as expected
   // by InvokeFunction.
   v8::internal::ParameterCount actual(receiver);
@@ -2865,7 +2819,7 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
   __ Call(ip);
 
   // Setup deoptimization.
-  RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT);
+  RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
 
   // Restore context.
   __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -3230,10 +3184,8 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
   ASSERT(instr->HasPointerMap());
   ASSERT(instr->HasDeoptimizationEnvironment());
   LPointerMap* pointers = instr->pointer_map();
-  LEnvironment* env = instr->deoptimization_environment();
   RecordPosition(pointers->position());
-  RegisterEnvironmentForDeoptimization(env);
-  SafepointGenerator generator(this, pointers, env->deoptimization_index());
+  SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
   ParameterCount count(instr->arity());
   __ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
   __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -4560,9 +4512,29 @@ void LCodeGen::EmitIsConstructCall(Register temp1, Register temp2) {
 }
 
 
+void LCodeGen::EnsureSpaceForLazyDeopt() {
+  // Ensure that we have enough space after the previous lazy-bailout
+  // instruction for patching the code here.
+  int current_pc = masm()->pc_offset();
+  int patch_size = Deoptimizer::patch_size();
+  if (current_pc < last_lazy_deopt_pc_ + patch_size) {
+    int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc;
+    ASSERT_EQ(0, padding_size % Assembler::kInstrSize);
+    while (padding_size > 0) {
+      __ nop();
+      padding_size -= Assembler::kInstrSize;
+    }
+  }
+  last_lazy_deopt_pc_ = current_pc;
+}
+
+
 void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
-  // No code for lazy bailout instruction. Used to capture environment after a
-  // call for populating the safepoint data with deoptimization data.
+  EnsureSpaceForLazyDeopt();
+  ASSERT(instr->HasEnvironment());
+  LEnvironment* env = instr->environment();
+  RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
+  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
 }
 
 
@@ -4579,12 +4551,9 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
   __ Push(object, key, strict);
   ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
   LPointerMap* pointers = instr->pointer_map();
-  LEnvironment* env = instr->deoptimization_environment();
   RecordPosition(pointers->position());
-  RegisterEnvironmentForDeoptimization(env);
-  SafepointGenerator safepoint_generator(this,
-                                         pointers,
-                                         env->deoptimization_index());
+  SafepointGenerator safepoint_generator(
+      this, pointers, Safepoint::kLazyDeopt);
   __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
 }
 
@@ -4595,27 +4564,20 @@ void LCodeGen::DoIn(LIn* instr) {
   __ Push(key, obj);
   ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
   LPointerMap* pointers = instr->pointer_map();
-  LEnvironment* env = instr->deoptimization_environment();
   RecordPosition(pointers->position());
-  RegisterEnvironmentForDeoptimization(env);
-  SafepointGenerator safepoint_generator(this,
-                                         pointers,
-                                         env->deoptimization_index());
+  SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt);
   __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
 }
 
 
 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
-  {
-    PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
-    __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
-    RegisterLazyDeoptimization(
-        instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
-  }
-
-  // The gap code includes the restoring of the safepoint registers.
-  int pc = masm()->pc_offset();
-  safepoints_.SetPcAfterGap(pc);
+  PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
+  __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
+  RecordSafepointWithLazyDeopt(
+      instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
+  ASSERT(instr->HasEnvironment());
+  LEnvironment* env = instr->environment();
+  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
 }
 
 
@@ -4630,6 +4592,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
     LStackCheck* instr_;
   };
 
+  ASSERT(instr->HasEnvironment());
+  LEnvironment* env = instr->environment();
+  // There is no LLazyBailout instruction for stack-checks. We have to
+  // prepare for lazy deoptimization explicitly here.
   if (instr->hydrogen()->is_function_entry()) {
     // Perform stack overflow check.
     Label done;
@@ -4638,7 +4604,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
     __ b(hs, &done);
     StackCheckStub stub;
     CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+    EnsureSpaceForLazyDeopt();
     __ bind(&done);
+    RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
+    safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
   } else {
     ASSERT(instr->hydrogen()->is_backwards_branch());
     // Perform stack overflow check if this goto needs it before jumping.
@@ -4647,8 +4616,13 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
     __ LoadRoot(ip, Heap::kStackLimitRootIndex);
     __ cmp(sp, Operand(ip));
     __ b(lo, deferred_stack_check->entry());
+    EnsureSpaceForLazyDeopt();
     __ bind(instr->done_label());
     deferred_stack_check->SetExit(instr->done_label());
+    RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
+    // Don't record a deoptimization index for the safepoint here.
+    // This will be done explicitly when emitting call and the safepoint in
+    // the deferred code.
   }
 }
 
@@ -4664,7 +4638,7 @@ void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
   // If the environment were already registered, we would have no way of
   // backpatching it with the spill slot operands.
   ASSERT(!environment->HasBeenRegistered());
-  RegisterEnvironmentForDeoptimization(environment);
+  RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
   ASSERT(osr_pc_offset_ == -1);
   osr_pc_offset_ = masm()->pc_offset();
 }
index b01e4967d77a62f7baf45d7905abfe1ddfd815d3..2b49e19fda143810305cd94a349329f50b20b38f 100644 (file)
@@ -58,6 +58,7 @@ class LCodeGen BASE_EMBEDDED {
         status_(UNUSED),
         deferred_(8),
         osr_pc_offset_(-1),
+        last_lazy_deopt_pc_(0),
         resolver_(this),
         expected_safepoint_kind_(Safepoint::kSimple) {
     PopulateDeoptimizationLiteralsWithInlinedFunctions();
@@ -112,8 +113,8 @@ class LCodeGen BASE_EMBEDDED {
   void DoDeferredStackCheck(LStackCheck* instr);
   void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
   void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
-  void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
-                                        Label* map_check);
+  void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
+                                       Label* map_check);
 
   // Parallel move support.
   void DoParallelMove(LParallelMove* move);
@@ -215,10 +216,11 @@ class LCodeGen BASE_EMBEDDED {
 
   void LoadHeapObject(Register result, Handle<HeapObject> object);
 
-  void RegisterLazyDeoptimization(LInstruction* instr,
-                                  SafepointMode safepoint_mode);
+  void RecordSafepointWithLazyDeopt(LInstruction* instr,
+                                    SafepointMode safepoint_mode);
 
-  void RegisterEnvironmentForDeoptimization(LEnvironment* environment);
+  void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
+                                            Safepoint::DeoptMode mode);
   void DeoptimizeIf(Condition cc, LEnvironment* environment);
 
   void AddToTranslation(Translation* translation,
@@ -247,19 +249,16 @@ class LCodeGen BASE_EMBEDDED {
   void RecordSafepoint(LPointerMap* pointers,
                        Safepoint::Kind kind,
                        int arguments,
-                       int deoptimization_index);
-  void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
-  void RecordSafepoint(int deoptimization_index);
+                       Safepoint::DeoptMode mode);
+  void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
+  void RecordSafepoint(Safepoint::DeoptMode mode);
   void RecordSafepointWithRegisters(LPointerMap* pointers,
                                     int arguments,
-                                    int deoptimization_index);
+                                    Safepoint::DeoptMode mode);
   void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
                                               int arguments,
-                                              int deoptimization_index);
+                                              Safepoint::DeoptMode mode);
   void RecordPosition(int position);
-  int LastSafepointEnd() {
-    return static_cast<int>(safepoints_.GetPcAfterGap());
-  }
 
   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
   void EmitGoto(int block);
@@ -302,6 +301,8 @@ class LCodeGen BASE_EMBEDDED {
     Address address;
   };
 
+  void EnsureSpaceForLazyDeopt();
+
   LChunk* const chunk_;
   MacroAssembler* const masm_;
   CompilationInfo* const info_;
@@ -318,6 +319,7 @@ class LCodeGen BASE_EMBEDDED {
   TranslationBuffer translations_;
   ZoneList<LDeferredCode*> deferred_;
   int osr_pc_offset_;
+  int last_lazy_deopt_pc_;
 
   // Builder that keeps track of safepoints in the code. The table
   // itself is emitted at the end of the generated code.
index a83493db48a811e54c8bfb040b5b6e41819f6d6f..108e547f2b95e6197a6d282bb432f7d06dde5ca2 100644 (file)
@@ -116,25 +116,11 @@ DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
   // Get the function and code from the frame.
   JSFunction* function = JSFunction::cast(frame->function());
   Code* code = frame->LookupCode();
-  Address code_start_address = code->instruction_start();
 
   // Locate the deoptimization point in the code. As we are at a call the
   // return address must be at a place in the code with deoptimization support.
-  int deoptimization_index = Safepoint::kNoDeoptimizationIndex;
-  // Scope this as the safe point constructor will disallow allocation.
-  {
-    SafepointTable table(code);
-    for (unsigned i = 0; i < table.length(); ++i) {
-      Address address = code_start_address + table.GetPcOffset(i);
-      if (address == frame->pc()) {
-        SafepointEntry safepoint_entry = table.GetEntry(i);
-        ASSERT(safepoint_entry.deoptimization_index() !=
-               Safepoint::kNoDeoptimizationIndex);
-        deoptimization_index = safepoint_entry.deoptimization_index();
-        break;
-      }
-    }
-  }
+  SafepointEntry safepoint_entry = code->GetSafepointEntry(frame->pc());
+  int deoptimization_index = safepoint_entry.deoptimization_index();
   ASSERT(deoptimization_index != Safepoint::kNoDeoptimizationIndex);
 
   // Always use the actual stack slots when calculating the fp to sp
index 64a40b9a478685c90e9e5e85acf3bc16132e5d8b..fce0e30238609f38dacd3f4baa5a32076e782aa4 100644 (file)
@@ -4138,6 +4138,7 @@ class HRegExpLiteral: public HMaterializedLiteral<1> {
         pattern_(pattern),
         flags_(flags) {
     SetOperandAt(0, context);
+    SetAllSideEffects();
   }
 
   HValue* context() { return OperandAt(0); }
index db6c16b2df4e7986ff795d0097f14772f7fe9a3b..eeee4f2b791c93f0c856e07a3c92881a6e78a96b 100644 (file)
@@ -45,16 +45,6 @@ int Deoptimizer::patch_size() {
 }
 
 
-static void ZapCodeRange(Address start, Address end) {
-#ifdef DEBUG
-  ASSERT(start <= end);
-  int size = end - start;
-  CodePatcher destroyer(start, size);
-  while (size-- > 0) destroyer.masm()->int3();
-#endif
-}
-
-
 void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
   Isolate* isolate = code->GetIsolate();
   HandleScope scope(isolate);
@@ -62,30 +52,23 @@ void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
   // Compute the size of relocation information needed for the code
   // patching in Deoptimizer::DeoptimizeFunction.
   int min_reloc_size = 0;
-  Address prev_reloc_address = code->instruction_start();
-  Address code_start_address = code->instruction_start();
-  SafepointTable table(*code);
-  for (unsigned i = 0; i < table.length(); ++i) {
-    Address curr_reloc_address = code_start_address + table.GetPcOffset(i);
-    ASSERT_GE(curr_reloc_address, prev_reloc_address);
-    SafepointEntry safepoint_entry = table.GetEntry(i);
-    int deoptimization_index = safepoint_entry.deoptimization_index();
-    if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
-      // The gap code is needed to get to the state expected at the
-      // bailout and we need to skip the call opcode to get to the
-      // address that needs reloc.
-      curr_reloc_address += safepoint_entry.gap_code_size() + 1;
-      int pc_delta = curr_reloc_address - prev_reloc_address;
-      // We use RUNTIME_ENTRY reloc info which has a size of 2 bytes
-      // if encodable with small pc delta encoding and up to 6 bytes
-      // otherwise.
-      if (pc_delta <= RelocInfo::kMaxSmallPCDelta) {
-        min_reloc_size += 2;
-      } else {
-        min_reloc_size += 6;
-      }
-      prev_reloc_address = curr_reloc_address;
+  int prev_pc_offset = 0;
+  DeoptimizationInputData* deopt_data =
+      DeoptimizationInputData::cast(code->deoptimization_data());
+  for (int i = 0; i < deopt_data->DeoptCount(); i++) {
+    int pc_offset = deopt_data->Pc(i)->value();
+    if (pc_offset == -1) continue;
+    ASSERT_GE(pc_offset, prev_pc_offset);
+    int pc_delta = pc_offset - prev_pc_offset;
+    // We use RUNTIME_ENTRY reloc info which has a size of 2 bytes
+    // if encodable with small pc delta encoding and up to 6 bytes
+    // otherwise.
+    if (pc_delta <= RelocInfo::kMaxSmallPCDelta) {
+      min_reloc_size += 2;
+    } else {
+      min_reloc_size += 6;
     }
+    prev_pc_offset = pc_offset;
   }
 
   // If the relocation information is not big enough we create a new
@@ -150,41 +133,41 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
   Address reloc_end_address = reloc_info->address() + reloc_info->Size();
   RelocInfoWriter reloc_info_writer(reloc_end_address, code_start_address);
 
-  // For each return after a safepoint insert a call to the corresponding
-  // deoptimization entry.  Since the call is a relative encoding, write new
+  // For each LLazyBailout instruction insert a call to the corresponding
+  // deoptimization entry.
+
+  // Since the call is a relative encoding, write new
   // reloc info.  We do not need any of the existing reloc info because the
   // existing code will not be used again (we zap it in debug builds).
-  SafepointTable table(code);
-  Address prev_address = code_start_address;
-  for (unsigned i = 0; i < table.length(); ++i) {
-    Address curr_address = code_start_address + table.GetPcOffset(i);
-    ASSERT_GE(curr_address, prev_address);
-    ZapCodeRange(prev_address, curr_address);
-
-    SafepointEntry safepoint_entry = table.GetEntry(i);
-    int deoptimization_index = safepoint_entry.deoptimization_index();
-    if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
-      // The gap code is needed to get to the state expected at the bailout.
-      curr_address += safepoint_entry.gap_code_size();
-
-      CodePatcher patcher(curr_address, patch_size());
-      Address deopt_entry = GetDeoptimizationEntry(deoptimization_index, LAZY);
-      patcher.masm()->call(deopt_entry, RelocInfo::NONE);
-
-      // We use RUNTIME_ENTRY for deoptimization bailouts.
-      RelocInfo rinfo(curr_address + 1,  // 1 after the call opcode.
-                      RelocInfo::RUNTIME_ENTRY,
-                      reinterpret_cast<intptr_t>(deopt_entry),
-                      NULL);
-      reloc_info_writer.Write(&rinfo);
-      ASSERT_GE(reloc_info_writer.pos(),
-                reloc_info->address() + ByteArray::kHeaderSize);
-      curr_address += patch_size();
-    }
-    prev_address = curr_address;
+  //
+  // Emit call to lazy deoptimization at all lazy deopt points.
+  DeoptimizationInputData* deopt_data =
+      DeoptimizationInputData::cast(code->deoptimization_data());
+#ifdef DEBUG
+  Address prev_call_address = NULL;
+#endif
+  for (int i = 0; i < deopt_data->DeoptCount(); i++) {
+    if (deopt_data->Pc(i)->value() == -1) continue;
+    // Patch lazy deoptimization entry.
+    Address call_address = code_start_address + deopt_data->Pc(i)->value();
+    CodePatcher patcher(call_address, patch_size());
+    Address deopt_entry = GetDeoptimizationEntry(i, LAZY);
+    patcher.masm()->call(deopt_entry, RelocInfo::NONE);
+    // We use RUNTIME_ENTRY for deoptimization bailouts.
+    RelocInfo rinfo(call_address + 1,  // 1 after the call opcode.
+                    RelocInfo::RUNTIME_ENTRY,
+                    reinterpret_cast<intptr_t>(deopt_entry),
+                    NULL);
+    reloc_info_writer.Write(&rinfo);
+    ASSERT_GE(reloc_info_writer.pos(),
+              reloc_info->address() + ByteArray::kHeaderSize);
+    ASSERT(prev_call_address == NULL ||
+           call_address >= prev_call_address + patch_size());
+    ASSERT(call_address + patch_size() <= code->instruction_end());
+#ifdef DEBUG
+    prev_call_address = call_address;
+#endif
   }
-  ZapCodeRange(prev_address,
-               code_start_address + code->safepoint_table_offset());
 
   // Move the relocation info to the beginning of the byte array.
   int new_reloc_size = reloc_end_address - reloc_info_writer.pos();
@@ -218,11 +201,6 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
     PrintF("[forced deoptimization: ");
     function->PrintName();
     PrintF(" / %x]\n", reinterpret_cast<uint32_t>(function));
-#ifdef DEBUG
-    if (FLAG_print_code) {
-      code->PrintLn();
-    }
-#endif
   }
 }
 
index 28e544377241b25df2835587741ebe40967a469e..74616d0756cb9321adf6b7c420f053108250f71c 100644 (file)
@@ -2104,9 +2104,7 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
   SetSourcePosition(expr->position());
 
   // Record call targets in unoptimized code, but not in the snapshot.
-  // TODO(1789): Reenable temporarily disabled recording CallFunctionStub
-  // when the issue is fixed.
-  bool record_call_target = false && !Serializer::enabled();
+  bool record_call_target = !Serializer::enabled();
   if (record_call_target) {
     flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET);
   }
index 0ec80e27ec8b1c39cec72fbb5721fedbebba2ab2..7f78d03da0db85dcb3ece1c63ba77e38791d418a 100644 (file)
@@ -44,22 +44,22 @@ class SafepointGenerator : public CallWrapper {
  public:
   SafepointGenerator(LCodeGen* codegen,
                      LPointerMap* pointers,
-                     int deoptimization_index)
+                     Safepoint::DeoptMode mode)
       : codegen_(codegen),
         pointers_(pointers),
-        deoptimization_index_(deoptimization_index) {}
+        deopt_mode_(mode) {}
   virtual ~SafepointGenerator() { }
 
   virtual void BeforeCall(int call_size) const {}
 
   virtual void AfterCall() const {
-    codegen_->RecordSafepoint(pointers_, deoptimization_index_);
+    codegen_->RecordSafepoint(pointers_, deopt_mode_);
   }
 
  private:
   LCodeGen* codegen_;
   LPointerMap* pointers_;
-  int deoptimization_index_;
+  Safepoint::DeoptMode deopt_mode_;
 };
 
 
@@ -221,7 +221,7 @@ bool LCodeGen::GeneratePrologue() {
     } else {
       __ CallRuntime(Runtime::kNewFunctionContext, 1);
     }
-    RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
+    RecordSafepoint(Safepoint::kNoLazyDeopt);
     // Context is returned in both eax and esi.  It replaces the context
     // passed to us.  It's saved in the stack and kept live in esi.
     __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
@@ -276,19 +276,11 @@ bool LCodeGen::GenerateBody() {
       instr->CompileToNative(this);
     }
   }
+  EnsureSpaceForLazyDeopt();
   return !is_aborted();
 }
 
 
-LInstruction* LCodeGen::GetNextInstruction() {
-  if (current_instruction_ < instructions_->length() - 1) {
-    return instructions_->at(current_instruction_ + 1);
-  } else {
-    return NULL;
-  }
-}
-
-
 bool LCodeGen::GenerateDeferredCode() {
   ASSERT(is_generating());
   if (deferred_.length() > 0) {
@@ -301,13 +293,6 @@ bool LCodeGen::GenerateDeferredCode() {
       code->Generate();
       __ jmp(code->exit());
     }
-
-    // Pad code to ensure that the last piece of deferred code have
-    // room for lazy bailout.
-    while ((masm()->pc_offset() - LastSafepointEnd())
-           < Deoptimizer::patch_size()) {
-      __ nop();
-    }
   }
 
   // Deferred code is the last part of the instruction sequence. Mark
@@ -486,10 +471,8 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code,
   ASSERT(instr != NULL);
   LPointerMap* pointers = instr->pointer_map();
   RecordPosition(pointers->position());
-
   __ call(code, mode);
-
-  RegisterLazyDeoptimization(instr, safepoint_mode);
+  RecordSafepointWithLazyDeopt(instr, safepoint_mode);
 
   // Signal that we don't inline smi code before these stubs in the
   // optimizing code generator.
@@ -517,7 +500,7 @@ void LCodeGen::CallRuntime(const Runtime::Function* fun,
 
   __ CallRuntime(fun, argc);
 
-  RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT);
+  RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
 }
 
 
@@ -541,37 +524,12 @@ void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
 
   __ CallRuntimeSaveDoubles(id);
   RecordSafepointWithRegisters(
-      instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex);
+      instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
 }
 
 
-void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr,
-                                          SafepointMode safepoint_mode) {
-  // Create the environment to bailout to. If the call has side effects
-  // execution has to continue after the call otherwise execution can continue
-  // from a previous bailout point repeating the call.
-  LEnvironment* deoptimization_environment;
-  if (instr->HasDeoptimizationEnvironment()) {
-    deoptimization_environment = instr->deoptimization_environment();
-  } else {
-    deoptimization_environment = instr->environment();
-  }
-
-  RegisterEnvironmentForDeoptimization(deoptimization_environment);
-  if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
-    RecordSafepoint(instr->pointer_map(),
-                    deoptimization_environment->deoptimization_index());
-  } else {
-    ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
-    RecordSafepointWithRegisters(
-        instr->pointer_map(),
-        0,
-        deoptimization_environment->deoptimization_index());
-  }
-}
-
-
-void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
+void LCodeGen::RegisterEnvironmentForDeoptimization(
+    LEnvironment* environment, Safepoint::DeoptMode mode) {
   if (!environment->HasBeenRegistered()) {
     // Physical stack frame layout:
     // -x ............. -4  0 ..................................... y
@@ -593,14 +551,17 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
     Translation translation(&translations_, frame_count);
     WriteTranslation(environment, &translation);
     int deoptimization_index = deoptimizations_.length();
-    environment->Register(deoptimization_index, translation.index());
+    int pc_offset = masm()->pc_offset();
+    environment->Register(deoptimization_index,
+                          translation.index(),
+                          (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
     deoptimizations_.Add(environment);
   }
 }
 
 
 void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
-  RegisterEnvironmentForDeoptimization(environment);
+  RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
   ASSERT(environment->HasBeenRegistered());
   int id = environment->deoptimization_index();
   Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
@@ -680,6 +641,7 @@ void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
     data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
     data->SetArgumentsStackHeight(i,
                                   Smi::FromInt(env->arguments_stack_height()));
+    data->SetPc(i, Smi::FromInt(env->pc_offset()));
   }
   code->set_deoptimization_data(*data);
 }
@@ -711,15 +673,27 @@ void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
 }
 
 
+void LCodeGen::RecordSafepointWithLazyDeopt(
+    LInstruction* instr, SafepointMode safepoint_mode) {
+  if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
+    RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
+  } else {
+    ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
+    RecordSafepointWithRegisters(
+        instr->pointer_map(), 0, Safepoint::kLazyDeopt);
+  }
+}
+
+
 void LCodeGen::RecordSafepoint(
     LPointerMap* pointers,
     Safepoint::Kind kind,
     int arguments,
-    int deoptimization_index) {
+    Safepoint::DeoptMode deopt_mode) {
   ASSERT(kind == expected_safepoint_kind_);
   const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
-  Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
-      kind, arguments, deoptimization_index);
+  Safepoint safepoint =
+      safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode);
   for (int i = 0; i < operands->length(); i++) {
     LOperand* pointer = operands->at(i);
     if (pointer->IsStackSlot()) {
@@ -732,22 +706,21 @@ void LCodeGen::RecordSafepoint(
 
 
 void LCodeGen::RecordSafepoint(LPointerMap* pointers,
-                               int deoptimization_index) {
-  RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index);
+                               Safepoint::DeoptMode mode) {
+  RecordSafepoint(pointers, Safepoint::kSimple, 0, mode);
 }
 
 
-void LCodeGen::RecordSafepoint(int deoptimization_index) {
+void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) {
   LPointerMap empty_pointers(RelocInfo::kNoPosition);
-  RecordSafepoint(&empty_pointers, deoptimization_index);
+  RecordSafepoint(&empty_pointers, mode);
 }
 
 
 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
                                             int arguments,
-                                            int deoptimization_index) {
-  RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments,
-      deoptimization_index);
+                                            Safepoint::DeoptMode mode) {
+  RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, mode);
 }
 
 
@@ -782,12 +755,6 @@ void LCodeGen::DoGap(LGap* gap) {
     LParallelMove* move = gap->GetParallelMove(inner_pos);
     if (move != NULL) DoParallelMove(move);
   }
-
-  LInstruction* next = GetNextInstruction();
-  if (next != NULL && next->IsLazyBailout()) {
-    int pc = masm()->pc_offset();
-    safepoints_.SetPcAfterGap(pc);
-  }
 }
 
 
@@ -1928,7 +1895,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
                                   LInstanceOfKnownGlobal* instr)
         : LDeferredCode(codegen), instr_(instr) { }
     virtual void Generate() {
-      codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_);
+      codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
     }
     virtual LInstruction* instr() { return instr_; }
     Label* map_check() { return &map_check_; }
@@ -1983,8 +1950,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
 }
 
 
-void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
-                                                Label* map_check) {
+void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
+                                               Label* map_check) {
   PushSafepointRegistersScope scope(this);
 
   InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
@@ -2011,6 +1978,10 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
                   RelocInfo::CODE_TARGET,
                   instr,
                   RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
+  ASSERT(instr->HasDeoptimizationEnvironment());
+  LEnvironment* env = instr->deoptimization_environment();
+  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
+
   // Put the result value into the eax slot and restore all registers.
   __ StoreToSafepointRegisterSlot(eax, eax);
 }
@@ -2616,12 +2587,9 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
   __ bind(&invoke);
   ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
   LPointerMap* pointers = instr->pointer_map();
-  LEnvironment* env = instr->deoptimization_environment();
   RecordPosition(pointers->position());
-  RegisterEnvironmentForDeoptimization(env);
-  SafepointGenerator safepoint_generator(this,
-                                         pointers,
-                                         env->deoptimization_index());
+  SafepointGenerator safepoint_generator(
+      this, pointers, Safepoint::kLazyDeopt);
   ParameterCount actual(eax);
   __ InvokeFunction(function, actual, CALL_FUNCTION,
                     safepoint_generator, CALL_AS_METHOD);
@@ -2704,8 +2672,7 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
     __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
   }
 
-  // Setup deoptimization.
-  RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT);
+  RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
 }
 
 
@@ -3081,10 +3048,9 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
   ASSERT(instr->HasPointerMap());
   ASSERT(instr->HasDeoptimizationEnvironment());
   LPointerMap* pointers = instr->pointer_map();
-  LEnvironment* env = instr->deoptimization_environment();
   RecordPosition(pointers->position());
-  RegisterEnvironmentForDeoptimization(env);
-  SafepointGenerator generator(this, pointers, env->deoptimization_index());
+  SafepointGenerator generator(
+      this, pointers, Safepoint::kLazyDeopt);
   ParameterCount count(instr->arity());
   __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
 }
@@ -3657,7 +3623,7 @@ void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
   __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
   RecordSafepointWithRegisters(
-      instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
+      instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
   if (!reg.is(eax)) __ mov(reg, eax);
 
   // Done. Put the value in xmm0 into the value of the allocated heap
@@ -3709,8 +3675,8 @@ void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
   // not have easy access to the local context.
   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
   __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
-  RecordSafepointWithRegisters(instr->pointer_map(), 0,
-                               Safepoint::kNoDeoptimizationIndex);
+  RecordSafepointWithRegisters(
+      instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
   __ StoreToSafepointRegisterSlot(reg, eax);
 }
 
@@ -4453,9 +4419,27 @@ void LCodeGen::EmitIsConstructCall(Register temp) {
 }
 
 
+void LCodeGen::EnsureSpaceForLazyDeopt() {
+  // Ensure that we have enough space after the previous lazy-bailout
+  // instruction for patching the code here.
+  int current_pc = masm()->pc_offset();
+  int patch_size = Deoptimizer::patch_size();
+  if (current_pc < last_lazy_deopt_pc_ + patch_size) {
+    int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc;
+    while (padding_size-- > 0) {
+      __ nop();
+    }
+  }
+  last_lazy_deopt_pc_ = current_pc;
+}
+
+
 void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
-  // No code for lazy bailout instruction. Used to capture environment after a
-  // call for populating the safepoint data with deoptimization data.
+  EnsureSpaceForLazyDeopt();
+  ASSERT(instr->HasEnvironment());
+  LEnvironment* env = instr->environment();
+  RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
+  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
 }
 
 
@@ -4475,32 +4459,26 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
   }
   ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
   LPointerMap* pointers = instr->pointer_map();
-  LEnvironment* env = instr->deoptimization_environment();
   RecordPosition(pointers->position());
-  RegisterEnvironmentForDeoptimization(env);
   // Create safepoint generator that will also ensure enough space in the
   // reloc info for patching in deoptimization (since this is invoking a
   // builtin)
-  SafepointGenerator safepoint_generator(this,
-                                         pointers,
-                                         env->deoptimization_index());
+  SafepointGenerator safepoint_generator(
+      this, pointers, Safepoint::kLazyDeopt);
   __ push(Immediate(Smi::FromInt(strict_mode_flag())));
   __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
 }
 
 
 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
-  {
-    PushSafepointRegistersScope scope(this);
-    __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
-    __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
-    RegisterLazyDeoptimization(
-        instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
-  }
-
-  // The gap code includes the restoring of the safepoint registers.
-  int pc = masm()->pc_offset();
-  safepoints_.SetPcAfterGap(pc);
+  PushSafepointRegistersScope scope(this);
+  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+  __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
+  RecordSafepointWithLazyDeopt(
+      instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
+  ASSERT(instr->HasEnvironment());
+  LEnvironment* env = instr->environment();
+  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
 }
 
 
@@ -4515,6 +4493,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
     LStackCheck* instr_;
   };
 
+  ASSERT(instr->HasEnvironment());
+  LEnvironment* env = instr->environment();
+  // There is no LLazyBailout instruction for stack-checks. We have to
+  // prepare for lazy deoptimization explicitly here.
   if (instr->hydrogen()->is_function_entry()) {
     // Perform stack overflow check.
     Label done;
@@ -4527,7 +4509,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
     ASSERT(ToRegister(instr->context()).is(esi));
     StackCheckStub stub;
     CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+    EnsureSpaceForLazyDeopt();
     __ bind(&done);
+    RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
+    safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
   } else {
     ASSERT(instr->hydrogen()->is_backwards_branch());
     // Perform stack overflow check if this goto needs it before jumping.
@@ -4537,8 +4522,13 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
         ExternalReference::address_of_stack_limit(isolate());
     __ cmp(esp, Operand::StaticVariable(stack_limit));
     __ j(below, deferred_stack_check->entry());
+    EnsureSpaceForLazyDeopt();
     __ bind(instr->done_label());
     deferred_stack_check->SetExit(instr->done_label());
+    RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
+    // Don't record a deoptimization index for the safepoint here.
+    // This will be done explicitly when emitting call and the safepoint in
+    // the deferred code.
   }
 }
 
@@ -4554,7 +4544,7 @@ void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
   // If the environment were already registered, we would have no way of
   // backpatching it with the spill slot operands.
   ASSERT(!environment->HasBeenRegistered());
-  RegisterEnvironmentForDeoptimization(environment);
+  RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
   ASSERT(osr_pc_offset_ == -1);
   osr_pc_offset_ = masm()->pc_offset();
 }
@@ -4575,15 +4565,9 @@ void LCodeGen::DoIn(LIn* instr) {
   }
   ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
   LPointerMap* pointers = instr->pointer_map();
-  LEnvironment* env = instr->deoptimization_environment();
   RecordPosition(pointers->position());
-  RegisterEnvironmentForDeoptimization(env);
-  // Create safepoint generator that will also ensure enough space in the
-  // reloc info for patching in deoptimization (since this is invoking a
-  // builtin)
-  SafepointGenerator safepoint_generator(this,
-                                         pointers,
-                                         env->deoptimization_index());
+  SafepointGenerator safepoint_generator(
+      this, pointers, Safepoint::kLazyDeopt);
   __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
 }
 
index 412e418f217ef3744072401a5aa467646e96902f..1354e1d173e042eabfe3a0571f57d592303d72f7 100644 (file)
@@ -61,7 +61,7 @@ class LCodeGen BASE_EMBEDDED {
         dynamic_frame_alignment_(false),
         deferred_(8),
         osr_pc_offset_(-1),
-        deoptimization_reloc_size(),
+        last_lazy_deopt_pc_(0),
         resolver_(this),
         expected_safepoint_kind_(Safepoint::kSimple) {
     PopulateDeoptimizationLiteralsWithInlinedFunctions();
@@ -101,8 +101,8 @@ class LCodeGen BASE_EMBEDDED {
   void DoDeferredStackCheck(LStackCheck* instr);
   void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
   void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
-  void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
-                                        Label* map_check);
+  void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
+                                       Label* map_check);
 
   // Parallel move support.
   void DoParallelMove(LParallelMove* move);
@@ -144,7 +144,6 @@ class LCodeGen BASE_EMBEDDED {
   HGraph* graph() const { return chunk_->graph(); }
 
   int GetNextEmittedBlock(int block);
-  LInstruction* GetNextInstruction();
 
   void EmitClassOfTest(Label* if_true,
                        Label* if_false,
@@ -210,10 +209,11 @@ class LCodeGen BASE_EMBEDDED {
 
   void LoadHeapObject(Register result, Handle<HeapObject> object);
 
-  void RegisterLazyDeoptimization(LInstruction* instr,
-                                  SafepointMode safepoint_mode);
+  void RecordSafepointWithLazyDeopt(LInstruction* instr,
+                                    SafepointMode safepoint_mode);
 
-  void RegisterEnvironmentForDeoptimization(LEnvironment* environment);
+  void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
+                                            Safepoint::DeoptMode mode);
   void DeoptimizeIf(Condition cc, LEnvironment* environment);
 
   void AddToTranslation(Translation* translation,
@@ -248,16 +248,13 @@ class LCodeGen BASE_EMBEDDED {
   void RecordSafepoint(LPointerMap* pointers,
                        Safepoint::Kind kind,
                        int arguments,
-                       int deoptimization_index);
-  void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
-  void RecordSafepoint(int deoptimization_index);
+                       Safepoint::DeoptMode mode);
+  void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
+  void RecordSafepoint(Safepoint::DeoptMode mode);
   void RecordSafepointWithRegisters(LPointerMap* pointers,
                                     int arguments,
-                                    int deoptimization_index);
+                                    Safepoint::DeoptMode mode);
   void RecordPosition(int position);
-  int LastSafepointEnd() {
-    return static_cast<int>(safepoints_.GetPcAfterGap());
-  }
 
   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
   void EmitGoto(int block);
@@ -291,6 +288,7 @@ class LCodeGen BASE_EMBEDDED {
                                        Register object,
                                        Handle<Map> type,
                                        Handle<String> name);
+  void EnsureSpaceForLazyDeopt();
 
   LChunk* const chunk_;
   MacroAssembler* const masm_;
@@ -308,13 +306,7 @@ class LCodeGen BASE_EMBEDDED {
   TranslationBuffer translations_;
   ZoneList<LDeferredCode*> deferred_;
   int osr_pc_offset_;
-
-  struct DeoptimizationRelocSize {
-    int min_size;
-    int last_pc_offset;
-  };
-
-  DeoptimizationRelocSize deoptimization_reloc_size;
+  int last_lazy_deopt_pc_;
 
   // Builder that keeps track of safepoints in the code. The table
   // itself is emitted at the end of the generated code.
index cb8b3dc66428017827a06644e78cf764ad938448..2fe55fd1efd2c21aada46d94648cf73d05b214db 100644 (file)
@@ -366,17 +366,7 @@ class LGoto: public LTemplateInstruction<0, 0, 0> {
 
 class LLazyBailout: public LTemplateInstruction<0, 0, 0> {
  public:
-  LLazyBailout() : gap_instructions_size_(0) { }
-
   DECLARE_CONCRETE_INSTRUCTION(LazyBailout, "lazy-bailout")
-
-  void set_gap_instructions_size(int gap_instructions_size) {
-    gap_instructions_size_ = gap_instructions_size;
-  }
-  int gap_instructions_size() { return gap_instructions_size_; }
-
- private:
-  int gap_instructions_size_;
 };
 
 
index 1e90804c30cbb485e287893c42474a4f66573732..b605eb97bd3a81565d4f084c74acb99c6573641b 100644 (file)
@@ -454,6 +454,7 @@ class LEnvironment: public ZoneObject {
         translation_index_(-1),
         ast_id_(ast_id),
         parameter_count_(parameter_count),
+        pc_offset_(-1),
         values_(value_count),
         representations_(value_count),
         spilled_registers_(NULL),
@@ -467,6 +468,7 @@ class LEnvironment: public ZoneObject {
   int translation_index() const { return translation_index_; }
   int ast_id() const { return ast_id_; }
   int parameter_count() const { return parameter_count_; }
+  int pc_offset() const { return pc_offset_; }
   LOperand** spilled_registers() const { return spilled_registers_; }
   LOperand** spilled_double_registers() const {
     return spilled_double_registers_;
@@ -483,10 +485,13 @@ class LEnvironment: public ZoneObject {
     return representations_[index].IsTagged();
   }
 
-  void Register(int deoptimization_index, int translation_index) {
+  void Register(int deoptimization_index,
+                int translation_index,
+                int pc_offset) {
     ASSERT(!HasBeenRegistered());
     deoptimization_index_ = deoptimization_index;
     translation_index_ = translation_index;
+    pc_offset_ = pc_offset;
   }
   bool HasBeenRegistered() const {
     return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex;
@@ -507,6 +512,7 @@ class LEnvironment: public ZoneObject {
   int translation_index_;
   int ast_id_;
   int parameter_count_;
+  int pc_offset_;
   ZoneList<LOperand*> values_;
   ZoneList<Representation> representations_;
 
index 0a3508dcccabf243d24dd5789a784cf73abeb544..854ce6812deb98609e7633f4f98c5df4b2f8784b 100644 (file)
@@ -7866,11 +7866,14 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
   PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
   if (0 == deopt_count) return;
 
-  PrintF(out, "%6s  %6s  %6s  %12s\n", "index", "ast id", "argc",
+  PrintF(out, "%6s  %6s  %6s %6s %12s\n", "index", "ast id", "argc", "pc",
          FLAG_print_code_verbose ? "commands" : "");
   for (int i = 0; i < deopt_count; i++) {
-    PrintF(out, "%6d  %6d  %6d",
-           i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
+    PrintF(out, "%6d  %6d  %6d %6d",
+           i,
+           AstId(i)->value(),
+           ArgumentsStackHeight(i)->value(),
+           Pc(i)->value());
 
     if (!FLAG_print_code_verbose) {
       PrintF(out, "\n");
index 59d735d80260006b45bdb9977903924b51c1a0f5..6e672e734aa008662cebe039d63c0c2da355f3c6 100644 (file)
@@ -3675,7 +3675,8 @@ class DeoptimizationInputData: public FixedArray {
   static const int kAstIdOffset = 0;
   static const int kTranslationIndexOffset = 1;
   static const int kArgumentsStackHeightOffset = 2;
-  static const int kDeoptEntrySize = 3;
+  static const int kPcOffset = 3;
+  static const int kDeoptEntrySize = 4;
 
   // Simple element accessors.
 #define DEFINE_ELEMENT_ACCESSORS(name, type)      \
@@ -3711,6 +3712,7 @@ class DeoptimizationInputData: public FixedArray {
   DEFINE_ENTRY_ACCESSORS(AstId, Smi)
   DEFINE_ENTRY_ACCESSORS(TranslationIndex, Smi)
   DEFINE_ENTRY_ACCESSORS(ArgumentsStackHeight, Smi)
+  DEFINE_ENTRY_ACCESSORS(Pc, Smi)
 
 #undef DEFINE_ENTRY_ACCESSORS
 
index bcd0a1d63d9d5891945f49ab67b2f55fa3737cea..89ad8afabec2a96bb4b60101a9945bd3bb2d86b2 100644 (file)
@@ -122,17 +122,20 @@ void Safepoint::DefinePointerRegister(Register reg) {
 
 
 Safepoint SafepointTableBuilder::DefineSafepoint(
-    Assembler* assembler, Safepoint::Kind kind, int arguments,
-    int deoptimization_index) {
-  ASSERT(deoptimization_index != -1);
+    Assembler* assembler,
+    Safepoint::Kind kind,
+    int arguments,
+    Safepoint::DeoptMode deopt_mode) {
   ASSERT(arguments >= 0);
-  DeoptimizationInfo pc_and_deoptimization_index;
-  pc_and_deoptimization_index.pc = assembler->pc_offset();
-  pc_and_deoptimization_index.deoptimization_index = deoptimization_index;
-  pc_and_deoptimization_index.pc_after_gap = assembler->pc_offset();
-  pc_and_deoptimization_index.arguments = arguments;
-  pc_and_deoptimization_index.has_doubles = (kind & Safepoint::kWithDoubles);
-  deoptimization_info_.Add(pc_and_deoptimization_index);
+  DeoptimizationInfo info;
+  info.pc = assembler->pc_offset();
+  info.arguments = arguments;
+  info.has_doubles = (kind & Safepoint::kWithDoubles);
+  deoptimization_info_.Add(info);
+  deopt_index_list_.Add(Safepoint::kNoDeoptimizationIndex);
+  if (deopt_mode == Safepoint::kNoLazyDeopt) {
+    last_lazy_safepoint_ = deopt_index_list_.length();
+  }
   indexes_.Add(new ZoneList<int>(8));
   registers_.Add((kind & Safepoint::kWithRegisters)
       ? new ZoneList<int>(4)
@@ -141,6 +144,12 @@ Safepoint SafepointTableBuilder::DefineSafepoint(
 }
 
 
+void SafepointTableBuilder::RecordLazyDeoptimizationIndex(int index) {
+  while (last_lazy_safepoint_ < deopt_index_list_.length()) {
+    deopt_index_list_[last_lazy_safepoint_++] = index;
+  }
+}
+
 unsigned SafepointTableBuilder::GetCodeOffset() const {
   ASSERT(emitted_);
   return offset_;
@@ -173,11 +182,11 @@ void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) {
   assembler->dd(length);
   assembler->dd(bytes_per_entry);
 
-  // Emit sorted table of pc offsets together with deoptimization indexes and
-  // pc after gap information.
+  // Emit sorted table of pc offsets together with deoptimization indexes.
   for (int i = 0; i < length; i++) {
     assembler->dd(deoptimization_info_[i].pc);
-    assembler->dd(EncodeExceptPC(deoptimization_info_[i]));
+    assembler->dd(EncodeExceptPC(deoptimization_info_[i],
+                                 deopt_index_list_[i]));
   }
 
   // Emit table of bitmaps.
@@ -222,35 +231,14 @@ void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) {
 }
 
 
-uint32_t SafepointTableBuilder::EncodeExceptPC(const DeoptimizationInfo& info) {
-  unsigned index = info.deoptimization_index;
-  unsigned gap_size = info.pc_after_gap - info.pc;
+uint32_t SafepointTableBuilder::EncodeExceptPC(const DeoptimizationInfo& info,
+                                               unsigned index) {
   uint32_t encoding = SafepointEntry::DeoptimizationIndexField::encode(index);
-  encoding |= SafepointEntry::GapCodeSizeField::encode(gap_size);
   encoding |= SafepointEntry::ArgumentsField::encode(info.arguments);
   encoding |= SafepointEntry::SaveDoublesField::encode(info.has_doubles);
   return encoding;
 }
 
 
-int SafepointTableBuilder::CountShortDeoptimizationIntervals(unsigned limit) {
-  int result = 0;
-  if (!deoptimization_info_.is_empty()) {
-    unsigned previous_gap_end = deoptimization_info_[0].pc_after_gap;
-    for (int i = 1, n = deoptimization_info_.length(); i < n; i++) {
-      DeoptimizationInfo info = deoptimization_info_[i];
-      if (static_cast<int>(info.deoptimization_index) !=
-          Safepoint::kNoDeoptimizationIndex) {
-        if (previous_gap_end + limit > info.pc) {
-          result++;
-        }
-        previous_gap_end = info.pc_after_gap;
-      }
-    }
-  }
-  return result;
-}
-
-
 
 } }  // namespace v8::internal
index de537f98284c73fd5faf502859e9ae8b3c495d6a..57fceecd92e9ad105aa9b1fa35a216f88460d9cb 100644 (file)
@@ -62,10 +62,20 @@ class SafepointEntry BASE_EMBEDDED {
     return DeoptimizationIndexField::decode(info_);
   }
 
-  int gap_code_size() const {
-    ASSERT(is_valid());
-    return GapCodeSizeField::decode(info_);
-  }
+  static const int kArgumentsFieldBits = 3;
+  static const int kSaveDoublesFieldBits = 1;
+  static const int kDeoptIndexBits =
+      32 - kArgumentsFieldBits - kSaveDoublesFieldBits;
+  class DeoptimizationIndexField:
+    public BitField<int, 0, kDeoptIndexBits> {};  // NOLINT
+  class ArgumentsField:
+    public BitField<unsigned,
+                    kDeoptIndexBits,
+                    kArgumentsFieldBits> {};  // NOLINT
+  class SaveDoublesField:
+    public BitField<bool,
+                    kDeoptIndexBits + kArgumentsFieldBits,
+                    kSaveDoublesFieldBits> { }; // NOLINT
 
   int argument_count() const {
     ASSERT(is_valid());
@@ -85,27 +95,6 @@ class SafepointEntry BASE_EMBEDDED {
   bool HasRegisters() const;
   bool HasRegisterAt(int reg_index) const;
 
-  // Reserve 13 bits for the gap code size. On ARM a constant pool can be
-  // emitted when generating the gap code. The size of the const pool is less
-  // than what can be represented in 12 bits, so 13 bits gives room for having
-  // instructions before potentially emitting a constant pool.
-  static const int kGapCodeSizeBits = 13;
-  static const int kArgumentsFieldBits = 3;
-  static const int kSaveDoublesFieldBits = 1;
-  static const int kDeoptIndexBits =
-      32 - kGapCodeSizeBits - kArgumentsFieldBits - kSaveDoublesFieldBits;
-  class GapCodeSizeField: public BitField<unsigned, 0, kGapCodeSizeBits> {};
-  class DeoptimizationIndexField: public BitField<int,
-                                                  kGapCodeSizeBits,
-                                                  kDeoptIndexBits> {};  // NOLINT
-  class ArgumentsField: public BitField<unsigned,
-                                        kGapCodeSizeBits + kDeoptIndexBits,
-                                        kArgumentsFieldBits> {};  // NOLINT
-  class SaveDoublesField: public BitField<bool,
-                                          kGapCodeSizeBits + kDeoptIndexBits +
-                                          kArgumentsFieldBits,
-                                          kSaveDoublesFieldBits> { }; // NOLINT
-
  private:
   unsigned info_;
   uint8_t* bits_;
@@ -186,6 +175,11 @@ class Safepoint BASE_EMBEDDED {
     kWithRegistersAndDoubles = kWithRegisters | kWithDoubles
   } Kind;
 
+  enum DeoptMode {
+    kNoLazyDeopt,
+    kLazyDeopt
+  };
+
   static const int kNoDeoptimizationIndex =
       (1 << (SafepointEntry::kDeoptIndexBits)) - 1;
 
@@ -206,9 +200,11 @@ class SafepointTableBuilder BASE_EMBEDDED {
  public:
   SafepointTableBuilder()
       : deoptimization_info_(32),
+        deopt_index_list_(32),
         indexes_(32),
         registers_(32),
-        emitted_(false) { }
+        emitted_(false),
+        last_lazy_safepoint_(0) { }
 
   // Get the offset of the emitted safepoint table in the code.
   unsigned GetCodeOffset() const;
@@ -217,50 +213,34 @@ class SafepointTableBuilder BASE_EMBEDDED {
   Safepoint DefineSafepoint(Assembler* assembler,
                             Safepoint::Kind kind,
                             int arguments,
-                            int deoptimization_index);
-
-  // Update the last safepoint with the size of the code generated until the
-  // end of the gap following it.
-  void SetPcAfterGap(int pc) {
-    ASSERT(!deoptimization_info_.is_empty());
-    int index = deoptimization_info_.length() - 1;
-    deoptimization_info_[index].pc_after_gap = pc;
-  }
+                            Safepoint::DeoptMode mode);
 
-  // Get the end pc offset of the last safepoint, including the code generated
-  // until the end of the gap following it.
-  unsigned GetPcAfterGap() {
-    int index = deoptimization_info_.length();
-    if (index == 0) return 0;
-    return deoptimization_info_[index - 1].pc_after_gap;
-  }
+  // Record deoptimization index for lazy deoptimization for the last
+  // outstanding safepoints.
+  void RecordLazyDeoptimizationIndex(int index);
 
   // Emit the safepoint table after the body. The number of bits per
   // entry must be enough to hold all the pointer indexes.
   void Emit(Assembler* assembler, int bits_per_entry);
 
-  // Count the number of deoptimization points where the next
-  // following deoptimization point comes less than limit bytes
-  // after the end of this point's gap.
-  int CountShortDeoptimizationIntervals(unsigned limit);
 
  private:
   struct DeoptimizationInfo {
     unsigned pc;
-    unsigned deoptimization_index;
-    unsigned pc_after_gap;
     unsigned arguments;
     bool has_doubles;
   };
 
-  uint32_t EncodeExceptPC(const DeoptimizationInfo& info);
+  uint32_t EncodeExceptPC(const DeoptimizationInfo& info, unsigned index);
 
   ZoneList<DeoptimizationInfo> deoptimization_info_;
+  ZoneList<unsigned> deopt_index_list_;
   ZoneList<ZoneList<int>*> indexes_;
   ZoneList<ZoneList<int>*> registers_;
 
   unsigned offset_;
   bool emitted_;
+  int last_lazy_safepoint_;
 
   DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder);
 };
index d0a052b42dd16af030d20fda1e92e9f7cedd6d0d..1fd78fc5789531709c898a672d8d5bfbbc704756 100644 (file)
@@ -42,67 +42,7 @@ const int Deoptimizer::table_entry_size_ = 10;
 
 
 int Deoptimizer::patch_size() {
-  return MacroAssembler::kCallInstructionLength;
-}
-
-
-#ifdef DEBUG
-// Overwrites code with int3 instructions.
-static void ZapCodeRange(Address from, Address to) {
-  CHECK(from <= to);
-  int length = static_cast<int>(to - from);
-  CodePatcher destroyer(from, length);
-  while (length-- > 0) {
-    destroyer.masm()->int3();
-  }
-}
-#endif
-
-
-// Iterate through the entries of a SafepointTable that corresponds to
-// deoptimization points.
-class SafepointTableDeoptimiztionEntryIterator {
- public:
-  explicit SafepointTableDeoptimiztionEntryIterator(Code* code)
-      : code_(code), table_(code), index_(-1), limit_(table_.length()) {
-    FindNextIndex();
-  }
-
-  SafepointEntry Next(Address* pc) {
-    if (index_ >= limit_) {
-      *pc = NULL;
-      return SafepointEntry();  // Invalid entry.
-    }
-    *pc = code_->instruction_start() + table_.GetPcOffset(index_);
-    SafepointEntry entry = table_.GetEntry(index_);
-    FindNextIndex();
-    return entry;
-  }
-
- private:
-  void FindNextIndex() {
-    ASSERT(index_ < limit_);
-    while (++index_ < limit_) {
-      if (table_.GetEntry(index_).deoptimization_index() !=
-          Safepoint::kNoDeoptimizationIndex) {
-        return;
-      }
-    }
-  }
-
-  Code* code_;
-  SafepointTable table_;
-  // Index of next deoptimization entry. If negative after calling
-  // FindNextIndex, there are no more, and Next will return an invalid
-  // SafepointEntry.
-  int index_;
-  // Table length.
-  int limit_;
-};
-
-
-void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
-  // TODO(1276): Implement.
+  return Assembler::kCallInstructionLength;
 }
 
 
@@ -119,84 +59,34 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
   // code patching below, and is not needed any more.
   code->InvalidateRelocation();
 
-  // For each return after a safepoint insert a absolute call to the
+  // For each LLazyBailout instruction insert a absolute call to the
   // corresponding deoptimization entry, or a short call to an absolute
   // jump if space is short. The absolute jumps are put in a table just
   // before the safepoint table (space was allocated there when the Code
   // object was created, if necessary).
 
   Address instruction_start = function->code()->instruction_start();
-  Address jump_table_address =
-      instruction_start + function->code()->safepoint_table_offset();
 #ifdef DEBUG
-  Address previous_pc = instruction_start;
-#endif
-
-  SafepointTableDeoptimiztionEntryIterator deoptimizations(function->code());
-  Address entry_pc = NULL;
-
-  SafepointEntry current_entry = deoptimizations.Next(&entry_pc);
-  while (current_entry.is_valid()) {
-    int gap_code_size = current_entry.gap_code_size();
-    unsigned deoptimization_index = current_entry.deoptimization_index();
-
-#ifdef DEBUG
-    // Destroy the code which is not supposed to run again.
-    ZapCodeRange(previous_pc, entry_pc);
+  Address prev_call_address = NULL;
 #endif
+  DeoptimizationInputData* deopt_data =
+      DeoptimizationInputData::cast(code->deoptimization_data());
+  for (int i = 0; i < deopt_data->DeoptCount(); i++) {
+    if (deopt_data->Pc(i)->value() == -1) continue;
     // Position where Call will be patched in.
-    Address call_address = entry_pc + gap_code_size;
-    // End of call instruction, if using a direct call to a 64-bit address.
-    Address call_end_address =
-        call_address + MacroAssembler::kCallInstructionLength;
-
-    // Find next deoptimization entry, if any.
-    Address next_pc = NULL;
-    SafepointEntry next_entry = deoptimizations.Next(&next_pc);
-
-    if (!next_entry.is_valid() || next_pc >= call_end_address) {
-      // Room enough to write a long call instruction.
-      CodePatcher patcher(call_address, Assembler::kCallInstructionLength);
-      patcher.masm()->Call(GetDeoptimizationEntry(deoptimization_index, LAZY),
-                           RelocInfo::NONE);
-#ifdef DEBUG
-      previous_pc = call_end_address;
-#endif
-    } else {
-      // Not room enough for a long Call instruction. Write a short call
-      // instruction to a long jump placed elsewhere in the code.
+    Address call_address = instruction_start + deopt_data->Pc(i)->value();
+    // There is room enough to write a long call instruction because we pad
+    // LLazyBailout instructions with nops if necessary.
+    CodePatcher patcher(call_address, Assembler::kCallInstructionLength);
+    patcher.masm()->Call(GetDeoptimizationEntry(i, LAZY), RelocInfo::NONE);
+    ASSERT(prev_call_address == NULL ||
+           call_address >= prev_call_address + patch_size());
+    ASSERT(call_address + patch_size() <= code->instruction_end());
 #ifdef DEBUG
-      Address short_call_end_address =
-          call_address + MacroAssembler::kShortCallInstructionLength;
+    prev_call_address = call_address;
 #endif
-      ASSERT(next_pc >= short_call_end_address);
-
-      // Write jump in jump-table.
-      jump_table_address -= MacroAssembler::kJumpInstructionLength;
-      CodePatcher jump_patcher(jump_table_address,
-                               MacroAssembler::kJumpInstructionLength);
-      jump_patcher.masm()->Jump(
-          GetDeoptimizationEntry(deoptimization_index, LAZY),
-          RelocInfo::NONE);
-
-      // Write call to jump at call_offset.
-      CodePatcher call_patcher(call_address,
-                               MacroAssembler::kShortCallInstructionLength);
-      call_patcher.masm()->call(jump_table_address);
-#ifdef DEBUG
-      previous_pc = short_call_end_address;
-#endif
-    }
-
-    // Continue with next deoptimization entry.
-    current_entry = next_entry;
-    entry_pc = next_pc;
   }
 
-#ifdef DEBUG
-  // Destroy the code which is not supposed to run again.
-  ZapCodeRange(previous_pc, jump_table_address);
-#endif
   Isolate* isolate = code->GetIsolate();
 
   // Add the deoptimizing code to the list.
@@ -217,11 +107,6 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
     PrintF("[forced deoptimization: ");
     function->PrintName();
     PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
-#ifdef DEBUG
-    if (FLAG_print_code) {
-      code->PrintLn();
-    }
-#endif
   }
 }
 
index 22d4c3d5d5ca88c1af938196a9e34c6fef8878f1..36edfb7dcb066cba82fcb702cea58fbba405057c 100644 (file)
@@ -43,35 +43,22 @@ class SafepointGenerator : public CallWrapper {
  public:
   SafepointGenerator(LCodeGen* codegen,
                      LPointerMap* pointers,
-                     int deoptimization_index)
+                     Safepoint::DeoptMode mode)
       : codegen_(codegen),
         pointers_(pointers),
-        deoptimization_index_(deoptimization_index) { }
+        deopt_mode_(mode) { }
   virtual ~SafepointGenerator() { }
 
-  virtual void BeforeCall(int call_size) const {
-    ASSERT(call_size >= 0);
-    // Ensure that we have enough space after the previous safepoint position
-    // for the jump generated there.
-    int call_end = codegen_->masm()->pc_offset() + call_size;
-    int prev_jump_end = codegen_->LastSafepointEnd() + kMinSafepointSize;
-    if (call_end < prev_jump_end) {
-      int padding_size = prev_jump_end - call_end;
-      STATIC_ASSERT(kMinSafepointSize <= 9);  // One multibyte nop is enough.
-      codegen_->masm()->nop(padding_size);
-    }
-  }
+  virtual void BeforeCall(int call_size) const { }
 
   virtual void AfterCall() const {
-    codegen_->RecordSafepoint(pointers_, deoptimization_index_);
+    codegen_->RecordSafepoint(pointers_, deopt_mode_);
   }
 
  private:
-  static const int kMinSafepointSize =
-      MacroAssembler::kShortCallInstructionLength;
   LCodeGen* codegen_;
   LPointerMap* pointers_;
-  int deoptimization_index_;
+  Safepoint::DeoptMode deopt_mode_;
 };
 
 
@@ -100,7 +87,6 @@ void LCodeGen::FinishCode(Handle<Code> code) {
   code->set_stack_slots(GetStackSlotCount());
   code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
   PopulateDeoptimizationData(code);
-  Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
 }
 
 
@@ -206,7 +192,7 @@ bool LCodeGen::GeneratePrologue() {
     } else {
       __ CallRuntime(Runtime::kNewFunctionContext, 1);
     }
-    RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
+    RecordSafepoint(Safepoint::kNoLazyDeopt);
     // Context is returned in both rax and rsi.  It replaces the context
     // passed to us.  It's saved in the stack and kept live in rsi.
     __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
@@ -255,19 +241,11 @@ bool LCodeGen::GenerateBody() {
       instr->CompileToNative(this);
     }
   }
+  EnsureSpaceForLazyDeopt();
   return !is_aborted();
 }
 
 
-LInstruction* LCodeGen::GetNextInstruction() {
-  if (current_instruction_ < instructions_->length() - 1) {
-    return instructions_->at(current_instruction_ + 1);
-  } else {
-    return NULL;
-  }
-}
-
-
 bool LCodeGen::GenerateJumpTable() {
   for (int i = 0; i < jump_table_.length(); i++) {
     __ bind(&jump_table_[i].label);
@@ -289,18 +267,6 @@ bool LCodeGen::GenerateDeferredCode() {
       code->Generate();
       __ jmp(code->exit());
     }
-
-    // Pad code to ensure that the last piece of deferred code have
-    // room for lazy bailout.
-    while ((masm()->pc_offset() - LastSafepointEnd())
-           < Deoptimizer::patch_size()) {
-      int padding = masm()->pc_offset() - LastSafepointEnd();
-      if (padding > 9) {
-        __ nop(9);
-      } else {
-        __ nop(padding);
-      }
-    }
   }
 
   // Deferred code is the last part of the instruction sequence. Mark
@@ -312,20 +278,6 @@ bool LCodeGen::GenerateDeferredCode() {
 
 bool LCodeGen::GenerateSafepointTable() {
   ASSERT(is_done());
-  // Ensure that there is space at the end of the code to write a number
-  // of jump instructions, as well as to afford writing a call near the end
-  // of the code.
-  // The jumps are used when there isn't room in the code stream to write
-  // a long call instruction. Instead it writes a shorter call to a
-  // jump instruction in the same code object.
-  // The calls are used when lazy deoptimizing a function and calls to a
-  // deoptimization function.
-  int short_deopts = safepoints_.CountShortDeoptimizationIntervals(
-      static_cast<unsigned>(MacroAssembler::kJumpInstructionLength));
-  int byte_count = (short_deopts) * MacroAssembler::kJumpInstructionLength;
-  while (byte_count-- > 0) {
-    __ int3();
-  }
   safepoints_.Emit(masm(), GetStackSlotCount());
   return !is_aborted();
 }
@@ -491,7 +443,7 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code,
   LPointerMap* pointers = instr->pointer_map();
   RecordPosition(pointers->position());
   __ call(code, mode);
-  RegisterLazyDeoptimization(instr, safepoint_mode, argc);
+  RecordSafepointWithLazyDeopt(instr, safepoint_mode, argc);
 
   // Signal that we don't inline smi code before these stubs in the
   // optimizing code generator.
@@ -518,7 +470,7 @@ void LCodeGen::CallRuntime(const Runtime::Function* function,
   RecordPosition(pointers->position());
 
   __ CallRuntime(function, num_arguments);
-  RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT, 0);
+  RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0);
 }
 
 
@@ -528,39 +480,12 @@ void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
   __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
   __ CallRuntimeSaveDoubles(id);
   RecordSafepointWithRegisters(
-      instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex);
-}
-
-
-void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr,
-                                          SafepointMode safepoint_mode,
-                                          int argc) {
-  // Create the environment to bailout to. If the call has side effects
-  // execution has to continue after the call otherwise execution can continue
-  // from a previous bailout point repeating the call.
-  LEnvironment* deoptimization_environment;
-  if (instr->HasDeoptimizationEnvironment()) {
-    deoptimization_environment = instr->deoptimization_environment();
-  } else {
-    deoptimization_environment = instr->environment();
-  }
-
-  RegisterEnvironmentForDeoptimization(deoptimization_environment);
-  if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
-    ASSERT(argc == 0);
-    RecordSafepoint(instr->pointer_map(),
-                    deoptimization_environment->deoptimization_index());
-  } else {
-    ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS);
-    RecordSafepointWithRegisters(
-        instr->pointer_map(),
-        argc,
-        deoptimization_environment->deoptimization_index());
-  }
+      instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
 }
 
 
-void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
+void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
+                                                    Safepoint::DeoptMode mode) {
   if (!environment->HasBeenRegistered()) {
     // Physical stack frame layout:
     // -x ............. -4  0 ..................................... y
@@ -582,14 +507,17 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
     Translation translation(&translations_, frame_count);
     WriteTranslation(environment, &translation);
     int deoptimization_index = deoptimizations_.length();
-    environment->Register(deoptimization_index, translation.index());
+    int pc_offset = masm()->pc_offset();
+    environment->Register(deoptimization_index,
+                          translation.index(),
+                          (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
     deoptimizations_.Add(environment);
   }
 }
 
 
 void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
-  RegisterEnvironmentForDeoptimization(environment);
+  RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
   ASSERT(environment->HasBeenRegistered());
   int id = environment->deoptimization_index();
   Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
@@ -641,6 +569,7 @@ void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
     data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
     data->SetArgumentsStackHeight(i,
                                   Smi::FromInt(env->arguments_stack_height()));
+    data->SetPc(i, Smi::FromInt(env->pc_offset()));
   }
   code->set_deoptimization_data(*data);
 }
@@ -672,17 +601,29 @@ void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
 }
 
 
+void LCodeGen::RecordSafepointWithLazyDeopt(
+    LInstruction* instr, SafepointMode safepoint_mode, int argc) {
+  if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
+    RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
+  } else {
+    ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS);
+    RecordSafepointWithRegisters(
+        instr->pointer_map(), argc, Safepoint::kLazyDeopt);
+  }
+}
+
+
 void LCodeGen::RecordSafepoint(
     LPointerMap* pointers,
     Safepoint::Kind kind,
     int arguments,
-    int deoptimization_index) {
+    Safepoint::DeoptMode deopt_mode) {
   ASSERT(kind == expected_safepoint_kind_);
 
   const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
 
   Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
-      kind, arguments, deoptimization_index);
+      kind, arguments, deopt_mode);
   for (int i = 0; i < operands->length(); i++) {
     LOperand* pointer = operands->at(i);
     if (pointer->IsStackSlot()) {
@@ -699,22 +640,21 @@ void LCodeGen::RecordSafepoint(
 
 
 void LCodeGen::RecordSafepoint(LPointerMap* pointers,
-                               int deoptimization_index) {
-  RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index);
+                               Safepoint::DeoptMode deopt_mode) {
+  RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode);
 }
 
 
-void LCodeGen::RecordSafepoint(int deoptimization_index) {
+void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
   LPointerMap empty_pointers(RelocInfo::kNoPosition);
-  RecordSafepoint(&empty_pointers, deoptimization_index);
+  RecordSafepoint(&empty_pointers, deopt_mode);
 }
 
 
 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
                                             int arguments,
-                                            int deoptimization_index) {
-  RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments,
-      deoptimization_index);
+                                            Safepoint::DeoptMode deopt_mode) {
+  RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
 }
 
 
@@ -749,12 +689,6 @@ void LCodeGen::DoGap(LGap* gap) {
     LParallelMove* move = gap->GetParallelMove(inner_pos);
     if (move != NULL) DoParallelMove(move);
   }
-
-  LInstruction* next = GetNextInstruction();
-  if (next != NULL && next->IsLazyBailout()) {
-    int pc = masm()->pc_offset();
-    safepoints_.SetPcAfterGap(pc);
-  }
 }
 
 
@@ -1889,7 +1823,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
                                   LInstanceOfKnownGlobal* instr)
         : LDeferredCode(codegen), instr_(instr) { }
     virtual void Generate() {
-      codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_);
+      codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
     }
     virtual LInstruction* instr() { return instr_; }
     Label* map_check() { return &map_check_; }
@@ -1947,8 +1881,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
 }
 
 
-void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
-                                                Label* map_check) {
+void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
+                                               Label* map_check) {
   {
     PushSafepointRegistersScope scope(this);
     InstanceofStub::Flags flags = static_cast<InstanceofStub::Flags>(
@@ -1974,6 +1908,9 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
                     RECORD_SAFEPOINT_WITH_REGISTERS,
                     2);
     ASSERT(delta == masm_->SizeOfCodeGeneratedSince(map_check));
+    ASSERT(instr->HasDeoptimizationEnvironment());
+    LEnvironment* env = instr->deoptimization_environment();
+    safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
     // Move result to a register that survives the end of the
     // PushSafepointRegisterScope.
     __ movq(kScratchRegister, rax);
@@ -2569,12 +2506,9 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
   __ bind(&invoke);
   ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
   LPointerMap* pointers = instr->pointer_map();
-  LEnvironment* env = instr->deoptimization_environment();
   RecordPosition(pointers->position());
-  RegisterEnvironmentForDeoptimization(env);
-  SafepointGenerator safepoint_generator(this,
-                                         pointers,
-                                         env->deoptimization_index());
+  SafepointGenerator safepoint_generator(
+      this, pointers, Safepoint::kLazyDeopt);
   v8::internal::ParameterCount actual(rax);
   __ InvokeFunction(function, actual, CALL_FUNCTION,
                     safepoint_generator, CALL_AS_METHOD);
@@ -2652,7 +2586,7 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
   }
 
   // Setup deoptimization.
-  RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT, 0);
+  RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0);
 
   // Restore context.
   __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@@ -3000,10 +2934,8 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
   ASSERT(instr->HasPointerMap());
   ASSERT(instr->HasDeoptimizationEnvironment());
   LPointerMap* pointers = instr->pointer_map();
-  LEnvironment* env = instr->deoptimization_environment();
   RecordPosition(pointers->position());
-  RegisterEnvironmentForDeoptimization(env);
-  SafepointGenerator generator(this, pointers, env->deoptimization_index());
+  SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
   ParameterCount count(instr->arity());
   __ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
   __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@@ -4184,9 +4116,29 @@ void LCodeGen::EmitIsConstructCall(Register temp) {
 }
 
 
+void LCodeGen::EnsureSpaceForLazyDeopt() {
+  // Ensure that we have enough space after the previous lazy-bailout
+  // instruction for patching the code here.
+  int current_pc = masm()->pc_offset();
+  int patch_size = Deoptimizer::patch_size();
+  if (current_pc < last_lazy_deopt_pc_ + patch_size) {
+    int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc;
+    while (padding_size > 0) {
+      int nop_size = padding_size > 9 ? 9 : padding_size;
+      __ nop(nop_size);
+      padding_size -= nop_size;
+    }
+  }
+  last_lazy_deopt_pc_ = current_pc;
+}
+
+
 void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
-  // No code for lazy bailout instruction. Used to capture environment after a
-  // call for populating the safepoint data with deoptimization data.
+  EnsureSpaceForLazyDeopt();
+  ASSERT(instr->HasEnvironment());
+  LEnvironment* env = instr->environment();
+  RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
+  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
 }
 
 
@@ -4202,15 +4154,12 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
   EmitPushTaggedOperand(key);
   ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
   LPointerMap* pointers = instr->pointer_map();
-  LEnvironment* env = instr->deoptimization_environment();
   RecordPosition(pointers->position());
-  RegisterEnvironmentForDeoptimization(env);
   // Create safepoint generator that will also ensure enough space in the
   // reloc info for patching in deoptimization (since this is invoking a
   // builtin)
-  SafepointGenerator safepoint_generator(this,
-                                         pointers,
-                                         env->deoptimization_index());
+  SafepointGenerator safepoint_generator(
+      this, pointers, Safepoint::kLazyDeopt);
   __ Push(Smi::FromInt(strict_mode_flag()));
   __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
 }
@@ -4223,30 +4172,21 @@ void LCodeGen::DoIn(LIn* instr) {
   EmitPushTaggedOperand(obj);
   ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
   LPointerMap* pointers = instr->pointer_map();
-  LEnvironment* env = instr->deoptimization_environment();
   RecordPosition(pointers->position());
-  RegisterEnvironmentForDeoptimization(env);
-  // Create safepoint generator that will also ensure enough space in the
-  // reloc info for patching in deoptimization (since this is invoking a
-  // builtin)
-  SafepointGenerator safepoint_generator(this,
-                                         pointers,
-                                         env->deoptimization_index());
+  SafepointGenerator safepoint_generator(
+      this, pointers, Safepoint::kLazyDeopt);
   __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
 }
 
 
 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
-  {
-    PushSafepointRegistersScope scope(this);
-    __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
-    __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
-    RegisterLazyDeoptimization(instr, RECORD_SAFEPOINT_WITH_REGISTERS, 0);
-  }
-
-  // The gap code includes the restoring of the safepoint registers.
-  int pc = masm()->pc_offset();
-  safepoints_.SetPcAfterGap(pc);
+  PushSafepointRegistersScope scope(this);
+  __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+  __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
+  RecordSafepointWithLazyDeopt(instr, RECORD_SAFEPOINT_WITH_REGISTERS, 0);
+  ASSERT(instr->HasEnvironment());
+  LEnvironment* env = instr->environment();
+  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
 }
 
 
@@ -4261,6 +4201,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
     LStackCheck* instr_;
   };
 
+  ASSERT(instr->HasEnvironment());
+  LEnvironment* env = instr->environment();
+  // There is no LLazyBailout instruction for stack-checks. We have to
+  // prepare for lazy deoptimization explicitly here.
   if (instr->hydrogen()->is_function_entry()) {
     // Perform stack overflow check.
     Label done;
@@ -4268,7 +4212,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
     __ j(above_equal, &done, Label::kNear);
     StackCheckStub stub;
     CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+    EnsureSpaceForLazyDeopt();
     __ bind(&done);
+    RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
+    safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
   } else {
     ASSERT(instr->hydrogen()->is_backwards_branch());
     // Perform stack overflow check if this goto needs it before jumping.
@@ -4276,8 +4223,13 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
         new DeferredStackCheck(this, instr);
     __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
     __ j(below, deferred_stack_check->entry());
+    EnsureSpaceForLazyDeopt();
     __ bind(instr->done_label());
     deferred_stack_check->SetExit(instr->done_label());
+    RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
+    // Don't record a deoptimization index for the safepoint here.
+    // This will be done explicitly when emitting call and the safepoint in
+    // the deferred code.
   }
 }
 
@@ -4293,7 +4245,7 @@ void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
   // If the environment were already registered, we would have no way of
   // backpatching it with the spill slot operands.
   ASSERT(!environment->HasBeenRegistered());
-  RegisterEnvironmentForDeoptimization(environment);
+  RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
   ASSERT(osr_pc_offset_ == -1);
   osr_pc_offset_ = masm()->pc_offset();
 }
index f3cb667973ce58c486e85c1ff752f09f34e666a8..37e426e2b7321b15c2912624bbdef4755de29d4b 100644 (file)
@@ -60,6 +60,7 @@ class LCodeGen BASE_EMBEDDED {
         status_(UNUSED),
         deferred_(8),
         osr_pc_offset_(-1),
+        last_lazy_deopt_pc_(0),
         resolver_(this),
         expected_safepoint_kind_(Safepoint::kSimple) {
     PopulateDeoptimizationLiteralsWithInlinedFunctions();
@@ -98,8 +99,8 @@ class LCodeGen BASE_EMBEDDED {
   void DoDeferredStackCheck(LStackCheck* instr);
   void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
   void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
-  void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
-                                        Label* map_check);
+  void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
+                                       Label* map_check);
 
   // Parallel move support.
   void DoParallelMove(LParallelMove* move);
@@ -135,7 +136,6 @@ class LCodeGen BASE_EMBEDDED {
   HGraph* graph() const { return chunk_->graph(); }
 
   int GetNextEmittedBlock(int block);
-  LInstruction* GetNextInstruction();
 
   void EmitClassOfTest(Label* if_true,
                        Label* if_false,
@@ -200,10 +200,11 @@ class LCodeGen BASE_EMBEDDED {
 
   void LoadHeapObject(Register result, Handle<HeapObject> object);
 
-  void RegisterLazyDeoptimization(LInstruction* instr,
-                                  SafepointMode safepoint_mode,
-                                  int argc);
-  void RegisterEnvironmentForDeoptimization(LEnvironment* environment);
+  void RecordSafepointWithLazyDeopt(LInstruction* instr,
+                                    SafepointMode safepoint_mode,
+                                    int argc);
+  void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
+                                            Safepoint::DeoptMode mode);
   void DeoptimizeIf(Condition cc, LEnvironment* environment);
 
   void AddToTranslation(Translation* translation,
@@ -237,16 +238,13 @@ class LCodeGen BASE_EMBEDDED {
   void RecordSafepoint(LPointerMap* pointers,
                        Safepoint::Kind kind,
                        int arguments,
-                       int deoptimization_index);
-  void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
-  void RecordSafepoint(int deoptimization_index);
+                       Safepoint::DeoptMode mode);
+  void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
+  void RecordSafepoint(Safepoint::DeoptMode mode);
   void RecordSafepointWithRegisters(LPointerMap* pointers,
                                     int arguments,
-                                    int deoptimization_index);
+                                    Safepoint::DeoptMode mode);
   void RecordPosition(int position);
-  int LastSafepointEnd() {
-    return static_cast<int>(safepoints_.GetPcAfterGap());
-  }
 
   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
   void EmitGoto(int block);
@@ -292,6 +290,8 @@ class LCodeGen BASE_EMBEDDED {
     Address address;
   };
 
+  void EnsureSpaceForLazyDeopt();
+
   LChunk* const chunk_;
   MacroAssembler* const masm_;
   CompilationInfo* const info_;
@@ -308,6 +308,7 @@ class LCodeGen BASE_EMBEDDED {
   TranslationBuffer translations_;
   ZoneList<LDeferredCode*> deferred_;
   int osr_pc_offset_;
+  int last_lazy_deopt_pc_;
 
   // Builder that keeps track of safepoints in the code. The table
   // itself is emitted at the end of the generated code.
index 88db147a8f0180ba731279b9968e079906b0bfbc..5c2a59720be356475c1c2647d52b1a6f16c53ae6 100644 (file)
@@ -25,6 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// Flags: --allow-natives-syntax
+
 // Test function.caller.
 function A() {}
 
@@ -40,9 +42,10 @@ A.prototype.g = gee;
 
 var o = new A();
 
-for (var i=0; i<5000000; i++) {
+for (var i=0; i<5; i++) {
   o.g(i);
 }
+%OptimizeFunctionOnNextCall(o.g);
 assertEquals(gee, o.g(0));
 assertEquals(null, o.g(1));
 
@@ -53,9 +56,10 @@ function hej(x) {
   return o.g(x);
 }
 
-for (var j=0; j<5000000; j++) {
+for (var j=0; j<5; j++) {
   hej(j);
 }
+%OptimizeFunctionOnNextCall(hej);
 assertEquals(gee, hej(0));
 assertEquals(hej, hej(1));
 
@@ -66,8 +70,9 @@ function from_eval(x) {
   return o.g(x);
 }
 
-for (var j=0; j<5000000; j++) {
+for (var j=0; j<5; j++) {
   from_eval(j);
 }
+%OptimizeFunctionOnNextCall(from_eval);
 assertEquals(gee, from_eval(0));
 assertEquals(from_eval, from_eval(1));
diff --git a/test/mjsunit/compiler/regress-lazy-deopt.js b/test/mjsunit/compiler/regress-lazy-deopt.js
new file mode 100644 (file)
index 0000000..d1c3d01
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+// Test lazy deoptimization after CallFunctionStub.
+
+function foo() { return 1; }
+
+function f(x, y) {
+  var a = [0];
+  if (x == 0) {
+    %DeoptimizeFunction(f);
+    return 1;
+  }
+  a[0] = %_CallFunction(null, x - 1, f);
+  return x >> a[0];
+}
+
+f(42);
+f(42);
+assertEquals(42, f(42));
+%OptimizeFunctionOnNextCall(f);
+assertEquals(42, f(42));