Partial fix for V8 issue 1079.

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
parent 09b3041a
// 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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
...@@ -37,6 +37,14 @@ namespace internal { ...@@ -37,6 +37,14 @@ namespace internal {
int Deoptimizer::table_entry_size_ = 16; int Deoptimizer::table_entry_size_ = 16;
int Deoptimizer::patch_size() {
const int kCallInstructionSizeInWords = 3;
return kCallInstructionSizeInWords * Assembler::kInstrSize;
}
void Deoptimizer::DeoptimizeFunction(JSFunction* function) { void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
AssertNoAllocation no_allocation; AssertNoAllocation no_allocation;
...@@ -51,6 +59,8 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { ...@@ -51,6 +59,8 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
// For each return after a safepoint insert an absolute call to the // For each return after a safepoint insert an absolute call to the
// corresponding deoptimization entry. // corresponding deoptimization entry.
ASSERT(patch_size() % Assembler::kInstrSize == 0);
int call_size_in_words = patch_size() / Assembler::kInstrSize;
unsigned last_pc_offset = 0; unsigned last_pc_offset = 0;
SafepointTable table(function->code()); SafepointTable table(function->code());
for (unsigned i = 0; i < table.length(); i++) { for (unsigned i = 0; i < table.length(); i++) {
...@@ -73,14 +83,13 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { ...@@ -73,14 +83,13 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
#endif #endif
last_pc_offset = pc_offset; last_pc_offset = pc_offset;
if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
const int kCallInstructionSizeInWords = 3; last_pc_offset += gap_code_size;
CodePatcher patcher(code->instruction_start() + pc_offset + gap_code_size, CodePatcher patcher(code->instruction_start() + last_pc_offset,
kCallInstructionSizeInWords); call_size_in_words);
Address deoptimization_entry = Deoptimizer::GetDeoptimizationEntry( Address deoptimization_entry = Deoptimizer::GetDeoptimizationEntry(
deoptimization_index, Deoptimizer::LAZY); deoptimization_index, Deoptimizer::LAZY);
patcher.masm()->Call(deoptimization_entry, RelocInfo::NONE); patcher.masm()->Call(deoptimization_entry, RelocInfo::NONE);
last_pc_offset += last_pc_offset += patch_size();
gap_code_size + kCallInstructionSizeInWords * Assembler::kInstrSize;
} }
} }
......
...@@ -655,16 +655,16 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) { ...@@ -655,16 +655,16 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment( LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
LInstruction* instr, int ast_id) { LInstruction* instr, int ast_id) {
ASSERT(instructions_pending_deoptimization_environment_ == NULL); ASSERT(instruction_pending_deoptimization_environment_ == NULL);
ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber); ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
instructions_pending_deoptimization_environment_ = instr; instruction_pending_deoptimization_environment_ = instr;
pending_deoptimization_ast_id_ = ast_id; pending_deoptimization_ast_id_ = ast_id;
return instr; return instr;
} }
void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() { void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
instructions_pending_deoptimization_environment_ = NULL; instruction_pending_deoptimization_environment_ = NULL;
pending_deoptimization_ast_id_ = AstNode::kNoNumber; pending_deoptimization_ast_id_ = AstNode::kNoNumber;
} }
...@@ -1463,6 +1463,13 @@ LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { ...@@ -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) { LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
LOperand* value = UseFixed(instr->value(), r0); LOperand* value = UseFixed(instr->value(), r0);
return MarkAsCall(new LThrow(value), instr); return MarkAsCall(new LThrow(value), instr);
...@@ -1837,7 +1844,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { ...@@ -1837,7 +1844,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
if (pending_deoptimization_ast_id_ == instr->ast_id()) { if (pending_deoptimization_ast_id_ == instr->ast_id()) {
LInstruction* result = new LLazyBailout; LInstruction* result = new LLazyBailout;
result = AssignEnvironment(result); result = AssignEnvironment(result);
instructions_pending_deoptimization_environment_-> instruction_pending_deoptimization_environment_->
set_deoptimization_environment(result->environment()); set_deoptimization_environment(result->environment());
ClearInstructionPendingDeoptimizationEnvironment(); ClearInstructionPendingDeoptimizationEnvironment();
return result; return result;
......
...@@ -1855,7 +1855,7 @@ class LChunkBuilder BASE_EMBEDDED { ...@@ -1855,7 +1855,7 @@ class LChunkBuilder BASE_EMBEDDED {
argument_count_(0), argument_count_(0),
allocator_(allocator), allocator_(allocator),
position_(RelocInfo::kNoPosition), position_(RelocInfo::kNoPosition),
instructions_pending_deoptimization_environment_(NULL), instruction_pending_deoptimization_environment_(NULL),
pending_deoptimization_ast_id_(AstNode::kNoNumber) { } pending_deoptimization_ast_id_(AstNode::kNoNumber) { }
// Build the sequence for the graph. // Build the sequence for the graph.
...@@ -1989,7 +1989,7 @@ class LChunkBuilder BASE_EMBEDDED { ...@@ -1989,7 +1989,7 @@ class LChunkBuilder BASE_EMBEDDED {
int argument_count_; int argument_count_;
LAllocator* allocator_; LAllocator* allocator_;
int position_; int position_;
LInstruction* instructions_pending_deoptimization_environment_; LInstruction* instruction_pending_deoptimization_environment_;
int pending_deoptimization_ast_id_; int pending_deoptimization_ast_id_;
DISALLOW_COPY_AND_ASSIGN(LChunkBuilder); DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
......
...@@ -562,17 +562,11 @@ void LCodeGen::AddToTranslation(Translation* translation, ...@@ -562,17 +562,11 @@ void LCodeGen::AddToTranslation(Translation* translation,
void LCodeGen::CallCode(Handle<Code> code, void LCodeGen::CallCode(Handle<Code> code,
RelocInfo::Mode mode, RelocInfo::Mode mode,
LInstruction* instr) { LInstruction* instr) {
if (instr != NULL) { ASSERT(instr != NULL);
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
__ Call(code, mode); __ Call(code, mode);
RegisterLazyDeoptimization(instr); RegisterLazyDeoptimization(instr);
} else {
LPointerMap no_pointers(0);
RecordPosition(no_pointers.position());
__ Call(code, mode);
RecordSafepoint(&no_pointers, Safepoint::kNoDeoptimizationIndex);
}
} }
...@@ -585,15 +579,7 @@ void LCodeGen::CallRuntime(Runtime::Function* function, ...@@ -585,15 +579,7 @@ void LCodeGen::CallRuntime(Runtime::Function* function,
RecordPosition(pointers->position()); RecordPosition(pointers->position());
__ CallRuntime(function, num_arguments); __ CallRuntime(function, num_arguments);
// Runtime calls to Throw are not supposed to ever return at the RegisterLazyDeoptimization(instr);
// 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);
}
} }
...@@ -2446,12 +2432,17 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { ...@@ -2446,12 +2432,17 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
__ b(ne, &loop); __ b(ne, &loop);
__ bind(&invoke); __ bind(&invoke);
// Invoke the function. The number of arguments is stored in receiver ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
// which is r0, as expected by InvokeFunction. LPointerMap* pointers = instr->pointer_map();
v8::internal::ParameterCount actual(receiver); LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env);
SafepointGenerator safepoint_generator(this, SafepointGenerator safepoint_generator(this,
instr->pointer_map(), pointers,
Safepoint::kNoDeoptimizationIndex); 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); __ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator);
} }
...@@ -3666,10 +3657,14 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { ...@@ -3666,10 +3657,14 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
Register object = ToRegister(instr->object()); Register object = ToRegister(instr->object());
Register key = ToRegister(instr->key()); Register key = ToRegister(instr->key());
__ Push(object, 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, SafepointGenerator safepoint_generator(this,
instr->pointer_map(), pointers,
Safepoint::kNoDeoptimizationIndex); env->deoptimization_index());
__ InvokeBuiltin(Builtins::DELETE, CALL_JS, &safepoint_generator); __ InvokeBuiltin(Builtins::DELETE, CALL_JS, &safepoint_generator);
} }
......
// 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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
...@@ -128,6 +128,9 @@ class Deoptimizer : public Malloced { ...@@ -128,6 +128,9 @@ class Deoptimizer : public Malloced {
static void VisitAllOptimizedFunctions(OptimizedFunctionVisitor* visitor); 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 // Patch all stack guard checks in the unoptimized code to
// unconditionally call replacement_code. // unconditionally call replacement_code.
static void PatchStackCheckCode(Code* unoptimized_code, static void PatchStackCheckCode(Code* unoptimized_code,
......
...@@ -64,6 +64,7 @@ class LChunkBuilder; ...@@ -64,6 +64,7 @@ class LChunkBuilder;
#define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \ #define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \
V(AbnormalExit) \
V(AccessArgumentsAt) \ V(AccessArgumentsAt) \
V(Add) \ V(Add) \
V(ApplyArguments) \ V(ApplyArguments) \
...@@ -834,12 +835,11 @@ class HReturn: public HUnaryControlInstruction { ...@@ -834,12 +835,11 @@ class HReturn: public HUnaryControlInstruction {
}; };
class HThrow: public HUnaryControlInstruction { class HAbnormalExit: public HControlInstruction {
public: public:
explicit HThrow(HValue* value) HAbnormalExit() : HControlInstruction(NULL, NULL) { }
: HUnaryControlInstruction(value, NULL, NULL) { }
DECLARE_CONCRETE_INSTRUCTION(Throw, "throw") DECLARE_CONCRETE_INSTRUCTION(AbnormalExit, "abnormal_exit")
}; };
...@@ -866,6 +866,20 @@ class HUnaryOperation: public HInstruction { ...@@ -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 { class HChange: public HUnaryOperation {
public: public:
HChange(HValue* value, HChange(HValue* value,
...@@ -989,7 +1003,7 @@ class HStackCheck: public HInstruction { ...@@ -989,7 +1003,7 @@ class HStackCheck: public HInstruction {
public: public:
HStackCheck() { } HStackCheck() { }
DECLARE_CONCRETE_INSTRUCTION(Throw, "stack_check") DECLARE_CONCRETE_INSTRUCTION(StackCheck, "stack_check")
}; };
...@@ -1831,6 +1845,7 @@ class HApplyArguments: public HInstruction { ...@@ -1831,6 +1845,7 @@ class HApplyArguments: public HInstruction {
SetOperandAt(1, receiver); SetOperandAt(1, receiver);
SetOperandAt(2, length); SetOperandAt(2, length);
SetOperandAt(3, elements); SetOperandAt(3, elements);
SetAllSideEffects();
} }
virtual Representation RequiredInputRepresentation(int index) const { virtual Representation RequiredInputRepresentation(int index) const {
...@@ -1850,8 +1865,6 @@ class HApplyArguments: public HInstruction { ...@@ -1850,8 +1865,6 @@ class HApplyArguments: public HInstruction {
DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply_arguments") DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply_arguments")
protected: protected:
virtual void InternalSetOperandAt(int index, HValue* value) { virtual void InternalSetOperandAt(int index, HValue* value) {
operands_[index] = value; operands_[index] = value;
......
...@@ -3556,9 +3556,11 @@ void HGraphBuilder::VisitThrow(Throw* expr) { ...@@ -3556,9 +3556,11 @@ void HGraphBuilder::VisitThrow(Throw* expr) {
VISIT_FOR_VALUE(expr->exception()); VISIT_FOR_VALUE(expr->exception());
HValue* value = environment()->Pop(); HValue* value = environment()->Pop();
HControlInstruction* instr = new HThrow(value); HThrow* instr = new HThrow(value);
instr->set_position(expr->position()); instr->set_position(expr->position());
current_subgraph_->FinishExit(instr); AddInstruction(instr);
AddSimulate(expr->id());
current_subgraph_->FinishExit(new HAbnormalExit);
} }
......
...@@ -37,9 +37,14 @@ ...@@ -37,9 +37,14 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
int Deoptimizer::table_entry_size_ = 10; int Deoptimizer::table_entry_size_ = 10;
int Deoptimizer::patch_size() {
return Assembler::kCallInstructionLength;
}
void Deoptimizer::DeoptimizeFunction(JSFunction* function) { void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
AssertNoAllocation no_allocation; AssertNoAllocation no_allocation;
...@@ -77,11 +82,12 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { ...@@ -77,11 +82,12 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
#endif #endif
last_pc_offset = pc_offset; last_pc_offset = pc_offset;
if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
Address call_pc = code->instruction_start() + pc_offset + gap_code_size; last_pc_offset += gap_code_size;
CodePatcher patcher(call_pc, Assembler::kCallInstructionLength); Address call_pc = code->instruction_start() + last_pc_offset;
CodePatcher patcher(call_pc, patch_size());
Address entry = GetDeoptimizationEntry(deoptimization_index, LAZY); Address entry = GetDeoptimizationEntry(deoptimization_index, LAZY);
patcher.masm()->call(entry, RelocInfo::NONE); 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, RelocInfo rinfo(call_pc + 1, RelocInfo::RUNTIME_ENTRY,
reinterpret_cast<intptr_t>(entry)); reinterpret_cast<intptr_t>(entry));
reloc_info_writer.Write(&rinfo); reloc_info_writer.Write(&rinfo);
......
...@@ -37,6 +37,8 @@ namespace v8 { ...@@ -37,6 +37,8 @@ namespace v8 {
namespace internal { 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 { class SafepointGenerator : public PostCallGenerator {
public: public:
SafepointGenerator(LCodeGen* codegen, SafepointGenerator(LCodeGen* codegen,
...@@ -366,17 +368,11 @@ void LCodeGen::AddToTranslation(Translation* translation, ...@@ -366,17 +368,11 @@ void LCodeGen::AddToTranslation(Translation* translation,
void LCodeGen::CallCode(Handle<Code> code, void LCodeGen::CallCode(Handle<Code> code,
RelocInfo::Mode mode, RelocInfo::Mode mode,
LInstruction* instr) { LInstruction* instr) {
if (instr != NULL) { ASSERT(instr != NULL);
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
__ call(code, mode); __ call(code, mode);
RegisterLazyDeoptimization(instr); RegisterLazyDeoptimization(instr);
} else {
LPointerMap no_pointers(0);
RecordPosition(no_pointers.position());
__ call(code, mode);
RecordSafepoint(&no_pointers, Safepoint::kNoDeoptimizationIndex);
}
// Signal that we don't inline smi code before these stubs in the // Signal that we don't inline smi code before these stubs in the
// optimizing code generator. // optimizing code generator.
...@@ -391,22 +387,12 @@ void LCodeGen::CallRuntime(Runtime::Function* function, ...@@ -391,22 +387,12 @@ void LCodeGen::CallRuntime(Runtime::Function* function,
int num_arguments, int num_arguments,
LInstruction* instr) { LInstruction* instr) {
ASSERT(instr != NULL); ASSERT(instr != NULL);
ASSERT(instr->HasPointerMap());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
ASSERT(pointers != NULL);
RecordPosition(pointers->position()); RecordPosition(pointers->position());
__ CallRuntime(function, num_arguments); __ CallRuntime(function, num_arguments);
// Runtime calls to Throw are not supposed to ever return at the RegisterLazyDeoptimization(instr);
// 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);
}
} }
...@@ -2145,11 +2131,16 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { ...@@ -2145,11 +2131,16 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
// Invoke the function. // Invoke the function.
__ bind(&invoke); __ 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)); ASSERT(receiver.is(eax));
v8::internal::ParameterCount actual(eax); v8::internal::ParameterCount actual(eax);
SafepointGenerator safepoint_generator(this,
instr->pointer_map(),
Safepoint::kNoDeoptimizationIndex);
__ InvokeFunction(edi, actual, CALL_FUNCTION, &safepoint_generator); __ InvokeFunction(edi, actual, CALL_FUNCTION, &safepoint_generator);
} }
...@@ -3577,10 +3568,14 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { ...@@ -3577,10 +3568,14 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
} else { } else {
__ push(ToOperand(key)); __ 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, SafepointGenerator safepoint_generator(this,
instr->pointer_map(), pointers,
Safepoint::kNoDeoptimizationIndex); env->deoptimization_index());
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, &safepoint_generator); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, &safepoint_generator);
} }
......
...@@ -658,16 +658,16 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) { ...@@ -658,16 +658,16 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment( LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
LInstruction* instr, int ast_id) { LInstruction* instr, int ast_id) {
ASSERT(instructions_pending_deoptimization_environment_ == NULL); ASSERT(instruction_pending_deoptimization_environment_ == NULL);
ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber); ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
instructions_pending_deoptimization_environment_ = instr; instruction_pending_deoptimization_environment_ = instr;
pending_deoptimization_ast_id_ = ast_id; pending_deoptimization_ast_id_ = ast_id;
return instr; return instr;
} }
void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() { void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
instructions_pending_deoptimization_environment_ = NULL; instruction_pending_deoptimization_environment_ = NULL;
pending_deoptimization_ast_id_ = AstNode::kNoNumber; pending_deoptimization_ast_id_ = AstNode::kNoNumber;
} }
...@@ -1507,6 +1507,13 @@ LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { ...@@ -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) { LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
LOperand* value = UseFixed(instr->value(), eax); LOperand* value = UseFixed(instr->value(), eax);
return MarkAsCall(new LThrow(value), instr); return MarkAsCall(new LThrow(value), instr);
...@@ -1875,10 +1882,11 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { ...@@ -1875,10 +1882,11 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
// If there is an instruction pending deoptimization environment create a // If there is an instruction pending deoptimization environment create a
// lazy bailout instruction to capture the environment. // 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; LLazyBailout* lazy_bailout = new LLazyBailout;
LInstruction* result = AssignEnvironment(lazy_bailout); LInstruction* result = AssignEnvironment(lazy_bailout);
instructions_pending_deoptimization_environment_-> instruction_pending_deoptimization_environment_->
set_deoptimization_environment(result->environment()); set_deoptimization_environment(result->environment());
ClearInstructionPendingDeoptimizationEnvironment(); ClearInstructionPendingDeoptimizationEnvironment();
return result; return result;
......
...@@ -1881,7 +1881,7 @@ class LChunkBuilder BASE_EMBEDDED { ...@@ -1881,7 +1881,7 @@ class LChunkBuilder BASE_EMBEDDED {
argument_count_(0), argument_count_(0),
allocator_(allocator), allocator_(allocator),
position_(RelocInfo::kNoPosition), position_(RelocInfo::kNoPosition),
instructions_pending_deoptimization_environment_(NULL), instruction_pending_deoptimization_environment_(NULL),
pending_deoptimization_ast_id_(AstNode::kNoNumber) { } pending_deoptimization_ast_id_(AstNode::kNoNumber) { }
// Build the sequence for the graph. // Build the sequence for the graph.
...@@ -2015,7 +2015,7 @@ class LChunkBuilder BASE_EMBEDDED { ...@@ -2015,7 +2015,7 @@ class LChunkBuilder BASE_EMBEDDED {
int argument_count_; int argument_count_;
LAllocator* allocator_; LAllocator* allocator_;
int position_; int position_;
LInstruction* instructions_pending_deoptimization_environment_; LInstruction* instruction_pending_deoptimization_environment_;
int pending_deoptimization_ast_id_; int pending_deoptimization_ast_id_;
DISALLOW_COPY_AND_ASSIGN(LChunkBuilder); DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
......
// 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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "safepoint-table.h" #include "safepoint-table.h"
#include "deoptimizer.h"
#include "disasm.h" #include "disasm.h"
#include "macro-assembler.h" #include "macro-assembler.h"
...@@ -144,6 +145,14 @@ unsigned SafepointTableBuilder::GetCodeOffset() const { ...@@ -144,6 +145,14 @@ unsigned SafepointTableBuilder::GetCodeOffset() const {
void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) { 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. // Make sure the safepoint table is properly aligned. Pad with nops.
assembler->Align(kIntSize); assembler->Align(kIntSize);
assembler->RecordComment(";;; Safepoint table."); assembler->RecordComment(";;; Safepoint table.");
......
// 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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
...@@ -215,11 +215,10 @@ class SafepointTableBuilder BASE_EMBEDDED { ...@@ -215,11 +215,10 @@ class SafepointTableBuilder BASE_EMBEDDED {
unsigned GetCodeOffset() const; unsigned GetCodeOffset() const;
// Define a new safepoint for the current position in the body. // Define a new safepoint for the current position in the body.
Safepoint DefineSafepoint( Safepoint DefineSafepoint(Assembler* assembler,
Assembler* assembler, Safepoint::Kind kind,
Safepoint::Kind kind, int arguments,
int arguments, int deoptimization_index);
int deoptimization_index = Safepoint::kNoDeoptimizationIndex);
// Update the last safepoint with the size of the code generated for the gap // Update the last safepoint with the size of the code generated for the gap
// following it. // following it.
......
// 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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
...@@ -40,6 +40,12 @@ namespace internal { ...@@ -40,6 +40,12 @@ namespace internal {
int Deoptimizer::table_entry_size_ = 10; int Deoptimizer::table_entry_size_ = 10;
int Deoptimizer::patch_size() {
return Assembler::kCallInstructionLength;
}
void Deoptimizer::DeoptimizeFunction(JSFunction* function) { void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
AssertNoAllocation no_allocation; AssertNoAllocation no_allocation;
...@@ -72,12 +78,12 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { ...@@ -72,12 +78,12 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
#endif #endif
last_pc_offset = pc_offset; last_pc_offset = pc_offset;
if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
CodePatcher patcher( last_pc_offset += gap_code_size;
code->instruction_start() + pc_offset + gap_code_size, CodePatcher patcher(code->instruction_start() + last_pc_offset,
Assembler::kCallInstructionLength); patch_size());
patcher.masm()->Call(GetDeoptimizationEntry(deoptimization_index, LAZY), patcher.masm()->Call(GetDeoptimizationEntry(deoptimization_index, LAZY),
RelocInfo::NONE); RelocInfo::NONE);
last_pc_offset += gap_code_size + Assembler::kCallInstructionLength; last_pc_offset += patch_size();
} }
} }
#ifdef DEBUG #ifdef DEBUG
......
...@@ -346,17 +346,11 @@ void LCodeGen::AddToTranslation(Translation* translation, ...@@ -346,17 +346,11 @@ void LCodeGen::AddToTranslation(Translation* translation,
void LCodeGen::CallCode(Handle<Code> code, void LCodeGen::CallCode(Handle<Code> code,
RelocInfo::Mode mode, RelocInfo::Mode mode,
LInstruction* instr) { LInstruction* instr) {
if (instr != NULL) { ASSERT(instr != NULL);
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
__ call(code, mode); __ call(code, mode);
RegisterLazyDeoptimization(instr); RegisterLazyDeoptimization(instr);
} else {
LPointerMap no_pointers(0);
RecordPosition(no_pointers.position());
__ call(code, mode);
RecordSafepoint(&no_pointers, Safepoint::kNoDeoptimizationIndex);
}
// Signal that we don't inline smi code before these stubs in the // Signal that we don't inline smi code before these stubs in the
// optimizing code generator. // optimizing code generator.
......
...@@ -655,14 +655,14 @@ LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment( ...@@ -655,14 +655,14 @@ LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
LInstruction* instr, int ast_id) { LInstruction* instr, int ast_id) {
ASSERT(instructions_pending_deoptimization_environment_ == NULL); ASSERT(instructions_pending_deoptimization_environment_ == NULL);
ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber); ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
instructions_pending_deoptimization_environment_ = instr; instruction_pending_deoptimization_environment_ = instr;
pending_deoptimization_ast_id_ = ast_id; pending_deoptimization_ast_id_ = ast_id;
return instr; return instr;
} }
void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() { void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
instructions_pending_deoptimization_environment_ = NULL; instruction_pending_deoptimization_environment_ = NULL;
pending_deoptimization_ast_id_ = AstNode::kNoNumber; pending_deoptimization_ast_id_ = AstNode::kNoNumber;
} }
...@@ -1328,6 +1328,13 @@ LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { ...@@ -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) { LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
Abort("Unimplemented: %s", "DoThrow"); Abort("Unimplemented: %s", "DoThrow");
return NULL; return NULL;
...@@ -1663,7 +1670,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { ...@@ -1663,7 +1670,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
if (pending_deoptimization_ast_id_ == instr->ast_id()) { if (pending_deoptimization_ast_id_ == instr->ast_id()) {
LLazyBailout* lazy_bailout = new LLazyBailout; LLazyBailout* lazy_bailout = new LLazyBailout;
LInstruction* result = AssignEnvironment(lazy_bailout); LInstruction* result = AssignEnvironment(lazy_bailout);
instructions_pending_deoptimization_environment_-> instruction_pending_deoptimization_environment_->
set_deoptimization_environment(result->environment()); set_deoptimization_environment(result->environment());
ClearInstructionPendingDeoptimizationEnvironment(); ClearInstructionPendingDeoptimizationEnvironment();
return result; return result;
......
...@@ -1847,7 +1847,7 @@ class LChunkBuilder BASE_EMBEDDED { ...@@ -1847,7 +1847,7 @@ class LChunkBuilder BASE_EMBEDDED {
argument_count_(0), argument_count_(0),
allocator_(allocator), allocator_(allocator),
position_(RelocInfo::kNoPosition), position_(RelocInfo::kNoPosition),
instructions_pending_deoptimization_environment_(NULL), instruction_pending_deoptimization_environment_(NULL),
pending_deoptimization_ast_id_(AstNode::kNoNumber) { } pending_deoptimization_ast_id_(AstNode::kNoNumber) { }
// Build the sequence for the graph. // Build the sequence for the graph.
...@@ -1981,7 +1981,7 @@ class LChunkBuilder BASE_EMBEDDED { ...@@ -1981,7 +1981,7 @@ class LChunkBuilder BASE_EMBEDDED {
int argument_count_; int argument_count_;
LAllocator* allocator_; LAllocator* allocator_;
int position_; int position_;
LInstruction* instructions_pending_deoptimization_environment_; LInstruction* instruction_pending_deoptimization_environment_;
int pending_deoptimization_ast_id_; int pending_deoptimization_ast_id_;
DISALLOW_COPY_AND_ASSIGN(LChunkBuilder); DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
......
...@@ -46,9 +46,6 @@ test-heap-profiler/HeapSnapshotsDiff: PASS || FAIL ...@@ -46,9 +46,6 @@ test-heap-profiler/HeapSnapshotsDiff: PASS || FAIL
test-serialize/TestThatAlwaysFails: FAIL test-serialize/TestThatAlwaysFails: FAIL
test-serialize/DependentTestThatAlwaysFails: FAIL test-serialize/DependentTestThatAlwaysFails: FAIL
# BUG(1079)
test-api/CaptureStackTraceForUncaughtException: PASS || FAIL
############################################################################## ##############################################################################
[ $arch == x64 ] [ $arch == x64 ]
......
// 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)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment