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
// 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();
}
}
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
}
......
// 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,
......
......@@ -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;
......
......@@ -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);
}
......
......@@ -37,9 +37,14 @@
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);
......
......@@ -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);
}
......
......@@ -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;
......
......@@ -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);
......
// 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.");
......
// 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.
......
// 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
......
......@@ -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.
......
......@@ -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;
......
......@@ -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);
......
......@@ -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 ]
......
// 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