Partial fix for V8 issue 1079.
authorkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 2 Feb 2011 13:55:29 +0000 (13:55 +0000)
committerkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 2 Feb 2011 13:55:29 +0000 (13:55 +0000)
Record a safepoint with a deoptimization id for throw in optimized code.  We
don't seem to much care what the AST ID is because we will not be using it
for lazy deoptimization (throw doesn't return to the point of throw).  For
hygiene we use the actual ID of the throw expression.  Throw is no longer a
control-flow instruction, but it's followed by an unconditional abnormal
exit.  This is required to insert a simulate between the throw and the exit.

Make our optimized treatment of Function.prototype.apply act like a call and
have side effects.  This ensures that it will get a lazy deoptimization
environment.  Use that deoptimization ID in the safepoint for the call.

Deleting a property was also missing a deoptimization ID, though there was a
deoptimization environment assigned to the instruction.  Record the
environment and use the deoptimization ID at the safepoint.

Review URL: http://codereview.chromium.org/6250105

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

19 files changed:
src/arm/deoptimizer-arm.cc
src/arm/lithium-arm.cc
src/arm/lithium-arm.h
src/arm/lithium-codegen-arm.cc
src/deoptimizer.h
src/hydrogen-instructions.h
src/hydrogen.cc
src/ia32/deoptimizer-ia32.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h
src/safepoint-table.cc
src/safepoint-table.h
src/x64/deoptimizer-x64.cc
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc
src/x64/lithium-x64.h
test/cctest/cctest.status
test/mjsunit/regress/regress-1079.js [new file with mode: 0644]

index 4fa09c31484ac0a2e42691d44b6226e86a92c964..75399c69db36fa1e37d6d9d229db97ac08149001 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// 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:
@@ -37,6 +37,14 @@ namespace internal {
 
 int Deoptimizer::table_entry_size_ = 16;
 
+
+int Deoptimizer::patch_size() {
+  const int kCallInstructionSizeInWords = 3;
+  return kCallInstructionSizeInWords * Assembler::kInstrSize;
+}
+
+
+
 void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
   AssertNoAllocation no_allocation;
 
@@ -51,6 +59,8 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
 
   // For each return after a safepoint insert an absolute call to the
   // corresponding deoptimization entry.
+  ASSERT(patch_size() % Assembler::kInstrSize == 0);
+  int call_size_in_words = patch_size() / Assembler::kInstrSize;
   unsigned last_pc_offset = 0;
   SafepointTable table(function->code());
   for (unsigned i = 0; i < table.length(); i++) {
@@ -73,14 +83,13 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
 #endif
     last_pc_offset = pc_offset;
     if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
-      const int kCallInstructionSizeInWords = 3;
-      CodePatcher patcher(code->instruction_start() + pc_offset + gap_code_size,
-                          kCallInstructionSizeInWords);
+      last_pc_offset += gap_code_size;
+      CodePatcher patcher(code->instruction_start() + last_pc_offset,
+                          call_size_in_words);
       Address deoptimization_entry = Deoptimizer::GetDeoptimizationEntry(
           deoptimization_index, Deoptimizer::LAZY);
       patcher.masm()->Call(deoptimization_entry, RelocInfo::NONE);
-      last_pc_offset +=
-          gap_code_size + kCallInstructionSizeInWords * Assembler::kInstrSize;
+      last_pc_offset += patch_size();
     }
   }
 
index c458138380bd29602d23280e58156ae8a92b8568..b7c1b78d1ba2075ec31e017c97f2268d2653dcb1 100644 (file)
@@ -655,16 +655,16 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
 
 LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
     LInstruction* instr, int ast_id) {
-  ASSERT(instructions_pending_deoptimization_environment_ == NULL);
+  ASSERT(instruction_pending_deoptimization_environment_ == NULL);
   ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
-  instructions_pending_deoptimization_environment_ = instr;
+  instruction_pending_deoptimization_environment_ = instr;
   pending_deoptimization_ast_id_ = ast_id;
   return instr;
 }
 
 
 void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
-  instructions_pending_deoptimization_environment_ = NULL;
+  instruction_pending_deoptimization_environment_ = NULL;
   pending_deoptimization_ast_id_ = AstNode::kNoNumber;
 }
 
@@ -1463,6 +1463,13 @@ LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
 }
 
 
+LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
+  // The control instruction marking the end of a block that completed
+  // abruptly (e.g., threw an exception).  There is nothing specific to do.
+  return NULL;
+}
+
+
 LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
   LOperand* value = UseFixed(instr->value(), r0);
   return MarkAsCall(new LThrow(value), instr);
@@ -1837,7 +1844,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
   if (pending_deoptimization_ast_id_ == instr->ast_id()) {
     LInstruction* result = new LLazyBailout;
     result = AssignEnvironment(result);
-    instructions_pending_deoptimization_environment_->
+    instruction_pending_deoptimization_environment_->
         set_deoptimization_environment(result->environment());
     ClearInstructionPendingDeoptimizationEnvironment();
     return result;
index 3de58329819f65f4d0976b76c78ed8747cab7680..7f89ee2922dd8ba1bd064cb1911f7aa189ab964a 100644 (file)
@@ -1855,7 +1855,7 @@ class LChunkBuilder BASE_EMBEDDED {
         argument_count_(0),
         allocator_(allocator),
         position_(RelocInfo::kNoPosition),
-        instructions_pending_deoptimization_environment_(NULL),
+        instruction_pending_deoptimization_environment_(NULL),
         pending_deoptimization_ast_id_(AstNode::kNoNumber) { }
 
   // Build the sequence for the graph.
@@ -1989,7 +1989,7 @@ class LChunkBuilder BASE_EMBEDDED {
   int argument_count_;
   LAllocator* allocator_;
   int position_;
-  LInstruction* instructions_pending_deoptimization_environment_;
+  LInstruction* instruction_pending_deoptimization_environment_;
   int pending_deoptimization_ast_id_;
 
   DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
index 46a19134e08bbfc1551858d3e9e0ec6ef6890d94..a1adae389d89625b36ff26dbe96df02a44de4f2f 100644 (file)
@@ -562,17 +562,11 @@ void LCodeGen::AddToTranslation(Translation* translation,
 void LCodeGen::CallCode(Handle<Code> code,
                         RelocInfo::Mode mode,
                         LInstruction* instr) {
-  if (instr != NULL) {
-    LPointerMap* pointers = instr->pointer_map();
-    RecordPosition(pointers->position());
-    __ Call(code, mode);
-    RegisterLazyDeoptimization(instr);
-  } else {
-    LPointerMap no_pointers(0);
-    RecordPosition(no_pointers.position());
-    __ Call(code, mode);
-    RecordSafepoint(&no_pointers, Safepoint::kNoDeoptimizationIndex);
-  }
+  ASSERT(instr != NULL);
+  LPointerMap* pointers = instr->pointer_map();
+  RecordPosition(pointers->position());
+  __ Call(code, mode);
+  RegisterLazyDeoptimization(instr);
 }
 
 
@@ -585,15 +579,7 @@ void LCodeGen::CallRuntime(Runtime::Function* function,
   RecordPosition(pointers->position());
 
   __ CallRuntime(function, num_arguments);
-  // Runtime calls to Throw are not supposed to ever return at the
-  // call site, so don't register lazy deoptimization for these. We do
-  // however have to record a safepoint since throwing exceptions can
-  // cause garbage collections.
-  if (!instr->IsThrow()) {
-    RegisterLazyDeoptimization(instr);
-  } else {
-    RecordSafepoint(instr->pointer_map(), Safepoint::kNoDeoptimizationIndex);
-  }
+  RegisterLazyDeoptimization(instr);
 }
 
 
@@ -2446,12 +2432,17 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
   __ b(ne, &loop);
 
   __ bind(&invoke);
-  // Invoke the function. The number of arguments is stored in receiver
-  // which is r0, as expected by InvokeFunction.
-  v8::internal::ParameterCount actual(receiver);
+  ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+  LPointerMap* pointers = instr->pointer_map();
+  LEnvironment* env = instr->deoptimization_environment();
+  RecordPosition(pointers->position());
+  RegisterEnvironmentForDeoptimization(env);
   SafepointGenerator safepoint_generator(this,
-                                         instr->pointer_map(),
-                                         Safepoint::kNoDeoptimizationIndex);
+                                         pointers,
+                                         env->deoptimization_index());
+  // The number of arguments is stored in receiver which is r0, as expected
+  // by InvokeFunction.
+  v8::internal::ParameterCount actual(receiver);
   __ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator);
 }
 
@@ -3666,10 +3657,14 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
   Register object = ToRegister(instr->object());
   Register key = ToRegister(instr->key());
   __ Push(object, key);
-  RecordPosition(instr->pointer_map()->position());
+  ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+  LPointerMap* pointers = instr->pointer_map();
+  LEnvironment* env = instr->deoptimization_environment();
+  RecordPosition(pointers->position());
+  RegisterEnvironmentForDeoptimization(env);
   SafepointGenerator safepoint_generator(this,
-                                         instr->pointer_map(),
-                                         Safepoint::kNoDeoptimizationIndex);
+                                         pointers,
+                                         env->deoptimization_index());
   __ InvokeBuiltin(Builtins::DELETE, CALL_JS, &safepoint_generator);
 }
 
index de5e57f8eb21e1814a7af2b141ea97d12a2374bf..1d4f4770f9762465b49c95f4e35dcddd969b6d31 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// 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:
@@ -128,6 +128,9 @@ class Deoptimizer : public Malloced {
 
   static void VisitAllOptimizedFunctions(OptimizedFunctionVisitor* visitor);
 
+  // The size in bytes of the code required at a lazy deopt patch site.
+  static int patch_size();
+
   // Patch all stack guard checks in the unoptimized code to
   // unconditionally call replacement_code.
   static void PatchStackCheckCode(Code* unoptimized_code,
index cdd141714a91bed43a72fcae465df270676a6980..eaab8adef2b0eec3406abff64bac5f8333d76ea9 100644 (file)
@@ -64,6 +64,7 @@ class LChunkBuilder;
 
 
 #define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V)  \
+  V(AbnormalExit)                              \
   V(AccessArgumentsAt)                         \
   V(Add)                                       \
   V(ApplyArguments)                            \
@@ -834,12 +835,11 @@ class HReturn: public HUnaryControlInstruction {
 };
 
 
-class HThrow: public HUnaryControlInstruction {
+class HAbnormalExit: public HControlInstruction {
  public:
-  explicit HThrow(HValue* value)
-      : HUnaryControlInstruction(value, NULL, NULL) { }
+  HAbnormalExit() : HControlInstruction(NULL, NULL) { }
 
-  DECLARE_CONCRETE_INSTRUCTION(Throw, "throw")
+  DECLARE_CONCRETE_INSTRUCTION(AbnormalExit, "abnormal_exit")
 };
 
 
@@ -866,6 +866,20 @@ class HUnaryOperation: public HInstruction {
 };
 
 
+class HThrow: public HUnaryOperation {
+ public:
+  explicit HThrow(HValue* value) : HUnaryOperation(value) {
+    SetAllSideEffects();
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(Throw, "throw")
+};
+
+
 class HChange: public HUnaryOperation {
  public:
   HChange(HValue* value,
@@ -989,7 +1003,7 @@ class HStackCheck: public HInstruction {
  public:
   HStackCheck() { }
 
-  DECLARE_CONCRETE_INSTRUCTION(Throw, "stack_check")
+  DECLARE_CONCRETE_INSTRUCTION(StackCheck, "stack_check")
 };
 
 
@@ -1831,6 +1845,7 @@ class HApplyArguments: public HInstruction {
     SetOperandAt(1, receiver);
     SetOperandAt(2, length);
     SetOperandAt(3, elements);
+    SetAllSideEffects();
   }
 
   virtual Representation RequiredInputRepresentation(int index) const {
@@ -1850,8 +1865,6 @@ class HApplyArguments: public HInstruction {
 
   DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply_arguments")
 
-
-
  protected:
   virtual void InternalSetOperandAt(int index, HValue* value) {
     operands_[index] = value;
index ca14f96a87e644a7b3eef2204193a994a1d1b77e..9d5aa2be31fa7206456e93d1257eb4320e0abf30 100644 (file)
@@ -3556,9 +3556,11 @@ void HGraphBuilder::VisitThrow(Throw* expr) {
   VISIT_FOR_VALUE(expr->exception());
 
   HValue* value = environment()->Pop();
-  HControlInstruction* instr = new HThrow(value);
+  HThrow* instr = new HThrow(value);
   instr->set_position(expr->position());
-  current_subgraph_->FinishExit(instr);
+  AddInstruction(instr);
+  AddSimulate(expr->id());
+  current_subgraph_->FinishExit(new HAbnormalExit);
 }
 
 
index 4e0bf471125b202771a1f8ecfdfcf80d1bec76f8..35c671365ddb39d613010fc7977b8531e15d926b 100644 (file)
 namespace v8 {
 namespace internal {
 
-
 int Deoptimizer::table_entry_size_ = 10;
 
+
+int Deoptimizer::patch_size() {
+  return Assembler::kCallInstructionLength;
+}
+
+
 void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
   AssertNoAllocation no_allocation;
 
@@ -77,11 +82,12 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
 #endif
     last_pc_offset = pc_offset;
     if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
-      Address call_pc = code->instruction_start() + pc_offset + gap_code_size;
-      CodePatcher patcher(call_pc, Assembler::kCallInstructionLength);
+      last_pc_offset += gap_code_size;
+      Address call_pc = code->instruction_start() + last_pc_offset;
+      CodePatcher patcher(call_pc, patch_size());
       Address entry = GetDeoptimizationEntry(deoptimization_index, LAZY);
       patcher.masm()->call(entry, RelocInfo::NONE);
-      last_pc_offset += gap_code_size + Assembler::kCallInstructionLength;
+      last_pc_offset += patch_size();
       RelocInfo rinfo(call_pc + 1, RelocInfo::RUNTIME_ENTRY,
                       reinterpret_cast<intptr_t>(entry));
       reloc_info_writer.Write(&rinfo);
index 1922697c7bf8fc1e3b6956eeefbb7a974d3c4fcd..ae8fe8d65a1ab30cc64b080f875915dc8a251b8b 100644 (file)
@@ -37,6 +37,8 @@ namespace v8 {
 namespace internal {
 
 
+// When invoking builtins, we need to record the safepoint in the middle of
+// the invoke instruction sequence generated by the macro assembler.
 class SafepointGenerator : public PostCallGenerator {
  public:
   SafepointGenerator(LCodeGen* codegen,
@@ -366,17 +368,11 @@ void LCodeGen::AddToTranslation(Translation* translation,
 void LCodeGen::CallCode(Handle<Code> code,
                         RelocInfo::Mode mode,
                         LInstruction* instr) {
-  if (instr != NULL) {
-    LPointerMap* pointers = instr->pointer_map();
-    RecordPosition(pointers->position());
-    __ call(code, mode);
-    RegisterLazyDeoptimization(instr);
-  } else {
-    LPointerMap no_pointers(0);
-    RecordPosition(no_pointers.position());
-    __ call(code, mode);
-    RecordSafepoint(&no_pointers, Safepoint::kNoDeoptimizationIndex);
-  }
+  ASSERT(instr != NULL);
+  LPointerMap* pointers = instr->pointer_map();
+  RecordPosition(pointers->position());
+  __ call(code, mode);
+  RegisterLazyDeoptimization(instr);
 
   // Signal that we don't inline smi code before these stubs in the
   // optimizing code generator.
@@ -391,22 +387,12 @@ void LCodeGen::CallRuntime(Runtime::Function* function,
                            int num_arguments,
                            LInstruction* instr) {
   ASSERT(instr != NULL);
+  ASSERT(instr->HasPointerMap());
   LPointerMap* pointers = instr->pointer_map();
-  ASSERT(pointers != NULL);
   RecordPosition(pointers->position());
 
   __ CallRuntime(function, num_arguments);
-  // Runtime calls to Throw are not supposed to ever return at the
-  // call site, so don't register lazy deoptimization for these. We do
-  // however have to record a safepoint since throwing exceptions can
-  // cause garbage collections.
-  // BUG(3243555): register a lazy deoptimization point at throw. We need
-  // it to be able to inline functions containing a throw statement.
-  if (!instr->IsThrow()) {
-    RegisterLazyDeoptimization(instr);
-  } else {
-    RecordSafepoint(instr->pointer_map(), Safepoint::kNoDeoptimizationIndex);
-  }
+  RegisterLazyDeoptimization(instr);
 }
 
 
@@ -2145,11 +2131,16 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
 
   // Invoke the function.
   __ 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());
   ASSERT(receiver.is(eax));
   v8::internal::ParameterCount actual(eax);
-  SafepointGenerator safepoint_generator(this,
-                                         instr->pointer_map(),
-                                         Safepoint::kNoDeoptimizationIndex);
   __ InvokeFunction(edi, actual, CALL_FUNCTION, &safepoint_generator);
 }
 
@@ -3577,10 +3568,14 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
   } else {
     __ push(ToOperand(key));
   }
-  RecordPosition(instr->pointer_map()->position());
+  ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
+  LPointerMap* pointers = instr->pointer_map();
+  LEnvironment* env = instr->deoptimization_environment();
+  RecordPosition(pointers->position());
+  RegisterEnvironmentForDeoptimization(env);
   SafepointGenerator safepoint_generator(this,
-                                         instr->pointer_map(),
-                                         Safepoint::kNoDeoptimizationIndex);
+                                         pointers,
+                                         env->deoptimization_index());
   __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, &safepoint_generator);
 }
 
index 100a2d44fac07075fccb776cac2e511c5e1b4a12..20703673202d4b5cfbe17f5fc15cf47b287b796b 100644 (file)
@@ -658,16 +658,16 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
 
 LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
     LInstruction* instr, int ast_id) {
-  ASSERT(instructions_pending_deoptimization_environment_ == NULL);
+  ASSERT(instruction_pending_deoptimization_environment_ == NULL);
   ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
-  instructions_pending_deoptimization_environment_ = instr;
+  instruction_pending_deoptimization_environment_ = instr;
   pending_deoptimization_ast_id_ = ast_id;
   return instr;
 }
 
 
 void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
-  instructions_pending_deoptimization_environment_ = NULL;
+  instruction_pending_deoptimization_environment_ = NULL;
   pending_deoptimization_ast_id_ = AstNode::kNoNumber;
 }
 
@@ -1507,6 +1507,13 @@ LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
 }
 
 
+LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
+  // The control instruction marking the end of a block that completed
+  // abruptly (e.g., threw an exception).  There is nothing specific to do.
+  return NULL;
+}
+
+
 LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
   LOperand* value = UseFixed(instr->value(), eax);
   return MarkAsCall(new LThrow(value), instr);
@@ -1875,10 +1882,11 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
 
   // If there is an instruction pending deoptimization environment create a
   // lazy bailout instruction to capture the environment.
-  if (pending_deoptimization_ast_id_ == instr->ast_id()) {
+  if (pending_deoptimization_ast_id_ != AstNode::kNoNumber) {
+    ASSERT(pending_deoptimization_ast_id_ == instr->ast_id());
     LLazyBailout* lazy_bailout = new LLazyBailout;
     LInstruction* result = AssignEnvironment(lazy_bailout);
-    instructions_pending_deoptimization_environment_->
+    instruction_pending_deoptimization_environment_->
         set_deoptimization_environment(result->environment());
     ClearInstructionPendingDeoptimizationEnvironment();
     return result;
index 1cdd31ede883dcf08c4ab8a3327c3ba2a05cbd96..1adc13e4d4a6614968cdfe386f1b19a240e89ddf 100644 (file)
@@ -1881,7 +1881,7 @@ class LChunkBuilder BASE_EMBEDDED {
         argument_count_(0),
         allocator_(allocator),
         position_(RelocInfo::kNoPosition),
-        instructions_pending_deoptimization_environment_(NULL),
+        instruction_pending_deoptimization_environment_(NULL),
         pending_deoptimization_ast_id_(AstNode::kNoNumber) { }
 
   // Build the sequence for the graph.
@@ -2015,7 +2015,7 @@ class LChunkBuilder BASE_EMBEDDED {
   int argument_count_;
   LAllocator* allocator_;
   int position_;
-  LInstruction* instructions_pending_deoptimization_environment_;
+  LInstruction* instruction_pending_deoptimization_environment_;
   int pending_deoptimization_ast_id_;
 
   DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
index 153bf4327f672dd998190cef077f46ace7d1aad5..34e9cf4aba04d602743c619395f3a88644d7653f 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// 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:
@@ -27,6 +27,7 @@
 
 #include "safepoint-table.h"
 
+#include "deoptimizer.h"
 #include "disasm.h"
 #include "macro-assembler.h"
 
@@ -144,6 +145,14 @@ unsigned SafepointTableBuilder::GetCodeOffset() const {
 
 
 void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) {
+  // For lazy deoptimization we need space to patch a call after every call.
+  // Ensure there is always space for such patching, even if the code ends
+  // in a call.
+  int target_offset = assembler->pc_offset() + Deoptimizer::patch_size();
+  while (assembler->pc_offset() < target_offset) {
+    assembler->nop();
+  }
+
   // Make sure the safepoint table is properly aligned. Pad with nops.
   assembler->Align(kIntSize);
   assembler->RecordComment(";;; Safepoint table.");
index fa3590511e97af8ffbcdb8436520814ed53e0f4e..eeeae37fbe14e9f18f0fa9e6ca09f282cfa886aa 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// 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:
@@ -215,11 +215,10 @@ class SafepointTableBuilder BASE_EMBEDDED {
   unsigned GetCodeOffset() const;
 
   // Define a new safepoint for the current position in the body.
-  Safepoint DefineSafepoint(
-      Assembler* assembler,
-      Safepoint::Kind kind,
-      int arguments,
-      int deoptimization_index = Safepoint::kNoDeoptimizationIndex);
+  Safepoint DefineSafepoint(Assembler* assembler,
+                            Safepoint::Kind kind,
+                            int arguments,
+                            int deoptimization_index);
 
   // Update the last safepoint with the size of the code generated for the gap
   // following it.
index 708be862ac3732d87a9231d657e1617bf7b720d8..29b9023d42a7aad0ab19fd246b8c5f9a21523445 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// 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:
@@ -40,6 +40,12 @@ namespace internal {
 
 int Deoptimizer::table_entry_size_ = 10;
 
+
+int Deoptimizer::patch_size() {
+  return Assembler::kCallInstructionLength;
+}
+
+
 void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
   AssertNoAllocation no_allocation;
 
@@ -72,12 +78,12 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
 #endif
     last_pc_offset = pc_offset;
     if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
-      CodePatcher patcher(
-          code->instruction_start() + pc_offset + gap_code_size,
-          Assembler::kCallInstructionLength);
+      last_pc_offset += gap_code_size;
+      CodePatcher patcher(code->instruction_start() + last_pc_offset,
+                          patch_size());
       patcher.masm()->Call(GetDeoptimizationEntry(deoptimization_index, LAZY),
                            RelocInfo::NONE);
-      last_pc_offset += gap_code_size + Assembler::kCallInstructionLength;
+      last_pc_offset += patch_size();
     }
   }
 #ifdef DEBUG
index 513c98407c16300d2094a4341c5e61a68ee9a1a1..4f1efc480b1f1115e2d875f801bc1034a3823a78 100644 (file)
@@ -346,17 +346,11 @@ void LCodeGen::AddToTranslation(Translation* translation,
 void LCodeGen::CallCode(Handle<Code> code,
                         RelocInfo::Mode mode,
                         LInstruction* instr) {
-  if (instr != NULL) {
-    LPointerMap* pointers = instr->pointer_map();
-    RecordPosition(pointers->position());
-    __ call(code, mode);
-    RegisterLazyDeoptimization(instr);
-  } else {
-    LPointerMap no_pointers(0);
-    RecordPosition(no_pointers.position());
-    __ call(code, mode);
-    RecordSafepoint(&no_pointers, Safepoint::kNoDeoptimizationIndex);
-  }
+  ASSERT(instr != NULL);
+  LPointerMap* pointers = instr->pointer_map();
+  RecordPosition(pointers->position());
+  __ call(code, mode);
+  RegisterLazyDeoptimization(instr);
 
   // Signal that we don't inline smi code before these stubs in the
   // optimizing code generator.
index 2dd5cf7337c1b7486540a044ee93d3708270d191..3617e0dc8e83e150918d9f21cca310f244515b58 100644 (file)
@@ -655,14 +655,14 @@ LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
     LInstruction* instr, int ast_id) {
   ASSERT(instructions_pending_deoptimization_environment_ == NULL);
   ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
-  instructions_pending_deoptimization_environment_ = instr;
+  instruction_pending_deoptimization_environment_ = instr;
   pending_deoptimization_ast_id_ = ast_id;
   return instr;
 }
 
 
 void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
-  instructions_pending_deoptimization_environment_ = NULL;
+  instruction_pending_deoptimization_environment_ = NULL;
   pending_deoptimization_ast_id_ = AstNode::kNoNumber;
 }
 
@@ -1328,6 +1328,13 @@ LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
 }
 
 
+LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
+  // The control instruction marking the end of a block that completed
+  // abruptly (e.g., threw an exception).  There is nothing specific to do.
+  return NULL;
+}
+
+
 LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
   Abort("Unimplemented: %s", "DoThrow");
   return NULL;
@@ -1663,7 +1670,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
   if (pending_deoptimization_ast_id_ == instr->ast_id()) {
     LLazyBailout* lazy_bailout = new LLazyBailout;
     LInstruction* result = AssignEnvironment(lazy_bailout);
-    instructions_pending_deoptimization_environment_->
+    instruction_pending_deoptimization_environment_->
         set_deoptimization_environment(result->environment());
     ClearInstructionPendingDeoptimizationEnvironment();
     return result;
index 319579165410dcd5c2e6f8379a26f4e0a30e1de1..abeb2a360d2bbcf7899257a04e7666c52f23f96a 100644 (file)
@@ -1847,7 +1847,7 @@ class LChunkBuilder BASE_EMBEDDED {
         argument_count_(0),
         allocator_(allocator),
         position_(RelocInfo::kNoPosition),
-        instructions_pending_deoptimization_environment_(NULL),
+        instruction_pending_deoptimization_environment_(NULL),
         pending_deoptimization_ast_id_(AstNode::kNoNumber) { }
 
   // Build the sequence for the graph.
@@ -1981,7 +1981,7 @@ class LChunkBuilder BASE_EMBEDDED {
   int argument_count_;
   LAllocator* allocator_;
   int position_;
-  LInstruction* instructions_pending_deoptimization_environment_;
+  LInstruction* instruction_pending_deoptimization_environment_;
   int pending_deoptimization_ast_id_;
 
   DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
index 40ab26ca44d84523a72b900726b3d055e00981ac..d7e446d1c39201d5de0b64e6d414c839198552da 100644 (file)
@@ -46,9 +46,6 @@ test-heap-profiler/HeapSnapshotsDiff: PASS || FAIL
 test-serialize/TestThatAlwaysFails: FAIL
 test-serialize/DependentTestThatAlwaysFails: FAIL
 
-# BUG(1079)
-test-api/CaptureStackTraceForUncaughtException: PASS || FAIL
-
 ##############################################################################
 [ $arch == x64 ]
 
diff --git a/test/mjsunit/regress/regress-1079.js b/test/mjsunit/regress/regress-1079.js
new file mode 100644 (file)
index 0000000..6863eb1
--- /dev/null
@@ -0,0 +1,45 @@
+// 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.
+
+// Getting the arguments property of an optimized function should not crash,
+// even if called through our optimized version of Function.prototype.apply.
+
+function optimized() {
+  return unoptimized.apply(null, arguments);
+}
+
+// It's not crucial that this is unoptimized.
+function unoptimized() {
+  with ({}) {
+    return optimized.arguments;
+  }
+}
+
+for (var i = 0; i < 100000; ++i) {
+  optimized(1, 2, 3)
+}
+