static const int kNullValueRootIndex = 7;
static const int kTrueValueRootIndex = 8;
static const int kFalseValueRootIndex = 9;
- static const int kEmptySymbolRootIndex = 112;
+ static const int kEmptySymbolRootIndex = 113;
static const int kJSObjectType = 0xaa;
static const int kFirstNonstringType = 0x80;
}
+void Deoptimizer::DoComputeSetterStubFrame(TranslationIterator* iterator,
+ int frame_index) {
+ JSFunction* setter = JSFunction::cast(ComputeLiteral(iterator->Next()));
+ // The receiver and the implicit return value are expected in registers by the
+ // StoreIC, so they don't belong to the output stack frame. This means that we
+ // have to use a height of 0.
+ unsigned height = 0;
+ unsigned height_in_bytes = height * kPointerSize;
+ if (FLAG_trace_deopt) {
+ PrintF(" translating setter stub => height=%u\n", height_in_bytes);
+ }
+
+ // We need 5 stack entries from StackFrame::INTERNAL (lr, fp, cp, frame type,
+ // code object, see MacroAssembler::EnterFrame) + 1 stack entry from setter
+ // stub (implicit return value, see StoreStubCompiler::CompileStoreViaSetter).
+ unsigned fixed_frame_size = (5 + 1) * kPointerSize;
+ unsigned output_frame_size = height_in_bytes + fixed_frame_size;
+
+ // Allocate and store the output frame description.
+ FrameDescription* output_frame =
+ new(output_frame_size) FrameDescription(output_frame_size, setter);
+ output_frame->SetFrameType(StackFrame::INTERNAL);
+
+ // A frame for a setter stub can not be the topmost or bottommost one.
+ ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
+ ASSERT(output_[frame_index] == NULL);
+ output_[frame_index] = output_frame;
+
+ // The top address of the frame is computed from the previous frame's top and
+ // this frame's size.
+ uint32_t top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
+ output_frame->SetTop(top_address);
+
+ unsigned output_offset = output_frame_size;
+
+ // Read caller's PC from the previous frame.
+ output_offset -= kPointerSize;
+ intptr_t callers_pc = output_[frame_index - 1]->GetPc();
+ output_frame->SetFrameSlot(output_offset, callers_pc);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; caller's pc\n",
+ top_address + output_offset, output_offset, callers_pc);
+ }
+
+ // Read caller's FP from the previous frame, and set this frame's FP.
+ output_offset -= kPointerSize;
+ intptr_t value = output_[frame_index - 1]->GetFp();
+ output_frame->SetFrameSlot(output_offset, value);
+ intptr_t fp_value = top_address + output_offset;
+ output_frame->SetFp(fp_value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; caller's fp\n",
+ fp_value, output_offset, value);
+ }
+
+ // The context can be gotten from the previous frame.
+ output_offset -= kPointerSize;
+ value = output_[frame_index - 1]->GetContext();
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; context\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // A marker value is used in place of the function.
+ output_offset -= kPointerSize;
+ value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL));
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; function (setter sentinel)\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // Get Code object from setter stub.
+ output_offset -= kPointerSize;
+ Code* setter_stub =
+ isolate_->builtins()->builtin(Builtins::kStoreIC_Setter_ForDeopt);
+ value = reinterpret_cast<intptr_t>(setter_stub);
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; code object\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // Skip receiver.
+ Translation::Opcode opcode =
+ static_cast<Translation::Opcode>(iterator->Next());
+ iterator->Skip(Translation::NumberOfOperandsFor(opcode));
+
+ // The implicit return value was part of the artificial setter stub
+ // environment.
+ output_offset -= kPointerSize;
+ DoTranslateCommand(iterator, frame_index, output_offset);
+
+ ASSERT(0 == output_offset);
+
+ intptr_t pc = reinterpret_cast<intptr_t>(
+ setter_stub->instruction_start() +
+ isolate_->heap()->setter_stub_deopt_pc_offset()->value());
+ output_frame->SetPc(pc);
+}
+
+
// This code is very similar to ia32 code, but relies on register names (fp, sp)
// and how the frame is laid out.
void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
translation->BeginConstructStubFrame(closure_id, translation_size);
break;
case JS_SETTER:
- // TODO(svenpanne) Implement me!
+ ASSERT(translation_size == 2);
+ ASSERT(height == 0);
+ translation->BeginSetterStubFrame(closure_id);
break;
case ARGUMENTS_ADAPTOR:
translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
}
-Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
- Handle<String> name,
- Handle<JSObject> receiver,
- Handle<JSObject> holder,
+#undef __
+#define __ ACCESS_MASM(masm)
+
+
+void StoreStubCompiler::GenerateStoreViaSetter(
+ MacroAssembler* masm,
Handle<JSFunction> setter) {
// ----------- S t a t e -------------
// -- r0 : value
// -- r2 : name
// -- lr : return address
// -----------------------------------
- Label miss;
-
- // Check that the maps haven't changed.
- __ JumpIfSmi(r1, &miss);
- CheckPrototypes(receiver, r1, holder, r3, r4, r5, name, &miss);
-
{
- FrameScope scope(masm(), StackFrame::INTERNAL);
+ FrameScope scope(masm, StackFrame::INTERNAL);
// Save value register, so we can restore it later.
__ push(r0);
- // Call the JavaScript setter with the receiver and the value on the stack.
- __ Push(r1, r0);
- ParameterCount actual(1);
- __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
- CALL_AS_METHOD);
+ if (!setter.is_null()) {
+ // Call the JavaScript setter with receiver and value on the stack.
+ __ Push(r1, r0);
+ ParameterCount actual(1);
+ __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
+ CALL_AS_METHOD);
+ } else {
+ // If we generate a global code snippet for deoptimization only, remember
+ // the place to continue after deoptimization.
+ masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
+ }
// We have to return the passed value, not the return value of the setter.
__ pop(r0);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
__ Ret();
+}
+
+
+#undef __
+#define __ ACCESS_MASM(masm())
+
+
+Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
+ Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ Handle<JSFunction> setter) {
+ // ----------- S t a t e -------------
+ // -- r0 : value
+ // -- r1 : receiver
+ // -- r2 : name
+ // -- lr : return address
+ // -----------------------------------
+ Label miss;
+
+ // Check that the maps haven't changed.
+ __ JumpIfSmi(r1, &miss);
+ CheckPrototypes(receiver, r1, holder, r3, r4, r5, name, &miss);
+
+ GenerateStoreViaSetter(masm(), setter);
__ bind(&miss);
Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
#include "ic-inl.h"
#include "heap-profiler.h"
#include "mark-compact.h"
+#include "stub-cache.h"
#include "vm-state-inl.h"
namespace v8 {
}
+static void Generate_StoreIC_Setter_ForDeopt(MacroAssembler* masm) {
+ StoreStubCompiler::GenerateStoreViaSetter(masm, Handle<JSFunction>());
+}
+
+
static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
KeyedStoreIC::GenerateGeneric(masm, kNonStrictMode);
}
kStrictMode) \
V(StoreIC_GlobalProxy_Strict, STORE_IC, MEGAMORPHIC, \
kStrictMode) \
+ V(StoreIC_Setter_ForDeopt, STORE_IC, MONOMORPHIC, \
+ kStrictMode) \
\
V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED, \
Code::kNoExtraICState) \
case Translation::CONSTRUCT_STUB_FRAME:
DoComputeConstructStubFrame(&iterator, i);
break;
- default:
+ case Translation::SETTER_STUB_FRAME:
+ DoComputeSetterStubFrame(&iterator, i);
+ break;
+ case Translation::BEGIN:
+ case Translation::REGISTER:
+ case Translation::INT32_REGISTER:
+ case Translation::DOUBLE_REGISTER:
+ case Translation::STACK_SLOT:
+ case Translation::INT32_STACK_SLOT:
+ case Translation::DOUBLE_STACK_SLOT:
+ case Translation::LITERAL:
+ case Translation::ARGUMENTS_OBJECT:
+ case Translation::DUPLICATE:
UNREACHABLE();
break;
}
case Translation::JS_FRAME:
case Translation::ARGUMENTS_ADAPTOR_FRAME:
case Translation::CONSTRUCT_STUB_FRAME:
+ case Translation::SETTER_STUB_FRAME:
case Translation::DUPLICATE:
UNREACHABLE();
return;
case Translation::JS_FRAME:
case Translation::ARGUMENTS_ADAPTOR_FRAME:
case Translation::CONSTRUCT_STUB_FRAME:
+ case Translation::SETTER_STUB_FRAME:
case Translation::DUPLICATE:
UNREACHABLE(); // Malformed input.
return false;
}
+void Translation::BeginSetterStubFrame(int literal_id) {
+ buffer_->Add(SETTER_STUB_FRAME, zone());
+ buffer_->Add(literal_id, zone());
+}
+
+
void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) {
buffer_->Add(ARGUMENTS_ADAPTOR_FRAME, zone());
buffer_->Add(literal_id, zone());
case ARGUMENTS_OBJECT:
case DUPLICATE:
return 0;
+ case SETTER_STUB_FRAME:
case REGISTER:
case INT32_REGISTER:
case DOUBLE_REGISTER:
return "ARGUMENTS_ADAPTOR_FRAME";
case CONSTRUCT_STUB_FRAME:
return "CONSTRUCT_STUB_FRAME";
+ case SETTER_STUB_FRAME:
+ return "SETTER_STUB_FRAME";
case REGISTER:
return "REGISTER";
case INT32_REGISTER:
case Translation::JS_FRAME:
case Translation::ARGUMENTS_ADAPTOR_FRAME:
case Translation::CONSTRUCT_STUB_FRAME:
+ case Translation::SETTER_STUB_FRAME:
// Peeled off before getting here.
break;
int frame_index);
void DoComputeConstructStubFrame(TranslationIterator* iterator,
int frame_index);
+ void DoComputeSetterStubFrame(TranslationIterator* iterator,
+ int frame_index);
void DoTranslateCommand(TranslationIterator* iterator,
int frame_index,
unsigned output_offset);
BEGIN,
JS_FRAME,
CONSTRUCT_STUB_FRAME,
+ SETTER_STUB_FRAME,
ARGUMENTS_ADAPTOR_FRAME,
REGISTER,
INT32_REGISTER,
void BeginJSFrame(BailoutId node_id, int literal_id, unsigned height);
void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
void BeginConstructStubFrame(int literal_id, unsigned height);
+ void BeginSetterStubFrame(int literal_id);
void StoreRegister(Register reg);
void StoreInt32Register(Register reg);
void StoreDoubleRegister(DoubleRegister reg);
"cache optimized code for closures")
DEFINE_bool(inline_construct, true, "inline constructor calls")
DEFINE_bool(inline_arguments, true, "inline functions with arguments object")
-DEFINE_bool(inline_accessors, false, "inline JavaScript accessors")
+DEFINE_bool(inline_accessors, true, "inline JavaScript accessors")
DEFINE_int(loop_weight, 1, "loop weight for representation inference")
DEFINE_bool(optimize_for_in, true,
V(Smi, real_stack_limit, RealStackLimit) \
V(StringDictionary, intrinsic_function_names, IntrinsicFunctionNames) \
V(Smi, arguments_adaptor_deopt_pc_offset, ArgumentsAdaptorDeoptPCOffset) \
- V(Smi, construct_stub_deopt_pc_offset, ConstructStubDeoptPCOffset)
+ V(Smi, construct_stub_deopt_pc_offset, ConstructStubDeoptPCOffset) \
+ V(Smi, setter_stub_deopt_pc_offset, SetterStubDeoptPCOffset)
#define ROOT_LIST(V) \
STRONG_ROOT_LIST(V) \
set_construct_stub_deopt_pc_offset(Smi::FromInt(pc_offset));
}
+ void SetSetterStubDeoptPCOffset(int pc_offset) {
+ ASSERT(setter_stub_deopt_pc_offset() == Smi::FromInt(0));
+ set_setter_stub_deopt_pc_offset(Smi::FromInt(pc_offset));
+ }
+
// For post mortem debugging.
void RememberUnmappedPage(Address page, bool compacted);
}
+void Deoptimizer::DoComputeSetterStubFrame(TranslationIterator* iterator,
+ int frame_index) {
+ JSFunction* setter = JSFunction::cast(ComputeLiteral(iterator->Next()));
+ // The receiver and the implicit return value are expected in registers by the
+ // StoreIC, so they don't belong to the output stack frame. This means that we
+ // have to use a height of 0.
+ unsigned height = 0;
+ unsigned height_in_bytes = height * kPointerSize;
+ if (FLAG_trace_deopt) {
+ PrintF(" translating setter stub => height=%u\n", height_in_bytes);
+ }
+
+ // We need 1 stack entry for the return address + 4 stack entries from
+ // StackFrame::INTERNAL (FP, context, frame type, code object, see
+ // MacroAssembler::EnterFrame) + 1 stack entry from setter stub (implicit
+ // return value, see StoreStubCompiler::CompileStoreViaSetter).
+ unsigned fixed_frame_size = (1 + 4 + 1) * kPointerSize;
+ unsigned output_frame_size = height_in_bytes + fixed_frame_size;
+
+ // Allocate and store the output frame description.
+ FrameDescription* output_frame =
+ new(output_frame_size) FrameDescription(output_frame_size, setter);
+ output_frame->SetFrameType(StackFrame::INTERNAL);
+
+ // A frame for a setter stub can not be the topmost or bottommost one.
+ ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
+ ASSERT(output_[frame_index] == NULL);
+ output_[frame_index] = output_frame;
+
+ // The top address of the frame is computed from the previous frame's top and
+ // this frame's size.
+ intptr_t top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
+ output_frame->SetTop(top_address);
+
+ unsigned output_offset = output_frame_size;
+
+ // Read caller's PC from the previous frame.
+ output_offset -= kPointerSize;
+ intptr_t callers_pc = output_[frame_index - 1]->GetPc();
+ output_frame->SetFrameSlot(output_offset, callers_pc);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; caller's pc\n",
+ top_address + output_offset, output_offset, callers_pc);
+ }
+
+ // Read caller's FP from the previous frame, and set this frame's FP.
+ output_offset -= kPointerSize;
+ intptr_t value = output_[frame_index - 1]->GetFp();
+ output_frame->SetFrameSlot(output_offset, value);
+ intptr_t fp_value = top_address + output_offset;
+ output_frame->SetFp(fp_value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; caller's fp\n",
+ fp_value, output_offset, value);
+ }
+
+ // The context can be gotten from the previous frame.
+ output_offset -= kPointerSize;
+ value = output_[frame_index - 1]->GetContext();
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; context\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // A marker value is used in place of the function.
+ output_offset -= kPointerSize;
+ value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL));
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; function (setter sentinel)\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // Get Code object from setter stub.
+ output_offset -= kPointerSize;
+ Code* setter_stub =
+ isolate_->builtins()->builtin(Builtins::kStoreIC_Setter_ForDeopt);
+ value = reinterpret_cast<intptr_t>(setter_stub);
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; code object\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // Skip receiver.
+ Translation::Opcode opcode =
+ static_cast<Translation::Opcode>(iterator->Next());
+ iterator->Skip(Translation::NumberOfOperandsFor(opcode));
+
+ // The implicit return value was part of the artificial setter stub
+ // environment.
+ output_offset -= kPointerSize;
+ DoTranslateCommand(iterator, frame_index, output_offset);
+
+ ASSERT(0 == output_offset);
+
+ intptr_t pc = reinterpret_cast<intptr_t>(
+ setter_stub->instruction_start() +
+ isolate_->heap()->setter_stub_deopt_pc_offset()->value());
+ output_frame->SetPc(pc);
+}
+
+
void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
int frame_index) {
BailoutId node_id = BailoutId(iterator->Next());
translation->BeginConstructStubFrame(closure_id, translation_size);
break;
case JS_SETTER:
- // TODO(svenpanne) Implement me!
+ ASSERT(translation_size == 2);
+ ASSERT(height == 0);
+ translation->BeginSetterStubFrame(closure_id);
break;
case ARGUMENTS_ADAPTOR:
translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
}
-Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
- Handle<String> name,
- Handle<JSObject> receiver,
- Handle<JSObject> holder,
+#undef __
+#define __ ACCESS_MASM(masm)
+
+
+void StoreStubCompiler::GenerateStoreViaSetter(
+ MacroAssembler* masm,
Handle<JSFunction> setter) {
// ----------- S t a t e -------------
// -- eax : value
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
- Label miss;
-
- // Check that the maps haven't changed, preserving the name register.
- __ push(ecx);
- __ JumpIfSmi(edx, &miss);
- CheckPrototypes(receiver, edx, holder, ebx, ecx, edi, name, &miss);
- __ pop(ecx);
-
{
- FrameScope scope(masm(), StackFrame::INTERNAL);
+ FrameScope scope(masm, StackFrame::INTERNAL);
// Save value register, so we can restore it later.
__ push(eax);
- // Call the JavaScript setter with the receiver and the value on the stack.
- __ push(edx);
- __ push(eax);
- ParameterCount actual(1);
- __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
- CALL_AS_METHOD);
+ if (!setter.is_null()) {
+ // Call the JavaScript setter with receiver and value on the stack.
+ __ push(edx);
+ __ push(eax);
+ ParameterCount actual(1);
+ __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
+ CALL_AS_METHOD);
+ } else {
+ // If we generate a global code snippet for deoptimization only, remember
+ // the place to continue after deoptimization.
+ masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
+ }
// We have to return the passed value, not the return value of the setter.
__ pop(eax);
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
}
__ ret(0);
+}
+
+
+#undef __
+#define __ ACCESS_MASM(masm())
+
+
+Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
+ Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ Handle<JSFunction> setter) {
+ // ----------- S t a t e -------------
+ // -- eax : value
+ // -- ecx : name
+ // -- edx : receiver
+ // -- esp[0] : return address
+ // -----------------------------------
+ Label miss;
+
+ // Check that the maps haven't changed, preserving the name register.
+ __ push(ecx);
+ __ JumpIfSmi(edx, &miss);
+ CheckPrototypes(receiver, edx, holder, ebx, ecx, edi, name, &miss);
+ __ pop(ecx);
+
+ GenerateStoreViaSetter(masm(), setter);
__ bind(&miss);
__ pop(ecx);
}
+void Deoptimizer::DoComputeSetterStubFrame(TranslationIterator* iterator,
+ int frame_index) {
+ JSFunction* setter = JSFunction::cast(ComputeLiteral(iterator->Next()));
+ // The receiver and the implicit return value are expected in registers by the
+ // StoreIC, so they don't belong to the output stack frame. This means that we
+ // have to use a height of 0.
+ unsigned height = 0;
+ unsigned height_in_bytes = height * kPointerSize;
+ if (FLAG_trace_deopt) {
+ PrintF(" translating setter stub => height=%u\n", height_in_bytes);
+ }
+
+ // We need 5 stack entries from StackFrame::INTERNAL (ra, fp, cp, frame type,
+ // code object, see MacroAssembler::EnterFrame) + 1 stack entry from setter
+ // stub (implicit return value, see StoreStubCompiler::CompileStoreViaSetter).
+ unsigned fixed_frame_size = (5 + 1) * kPointerSize;
+ unsigned output_frame_size = height_in_bytes + fixed_frame_size;
+
+ // Allocate and store the output frame description.
+ FrameDescription* output_frame =
+ new(output_frame_size) FrameDescription(output_frame_size, setter);
+ output_frame->SetFrameType(StackFrame::INTERNAL);
+
+ // A frame for a setter stub can not be the topmost or bottommost one.
+ ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
+ ASSERT(output_[frame_index] == NULL);
+ output_[frame_index] = output_frame;
+
+ // The top address of the frame is computed from the previous frame's top and
+ // this frame's size.
+ uint32_t top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
+ output_frame->SetTop(top_address);
+
+ unsigned output_offset = output_frame_size;
+
+ // Read caller's PC from the previous frame.
+ output_offset -= kPointerSize;
+ intptr_t value = output_[frame_index - 1]->GetPc();
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; caller's pc\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // Read caller's FP from the previous frame, and set this frame's FP.
+ output_offset -= kPointerSize;
+ value = output_[frame_index - 1]->GetFp();
+ output_frame->SetFrameSlot(output_offset, value);
+ intptr_t fp_value = top_address + output_offset;
+ output_frame->SetFp(fp_value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; caller's fp\n",
+ fp_value, output_offset, value);
+ }
+
+ // The context can be gotten from the previous frame.
+ output_offset -= kPointerSize;
+ value = output_[frame_index - 1]->GetContext();
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; context\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // A marker value is used in place of the function.
+ output_offset -= kPointerSize;
+ value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL));
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; function (setter sentinel)\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // Get Code object from setter stub.
+ output_offset -= kPointerSize;
+ Code* setter_stub =
+ isolate_->builtins()->builtin(Builtins::kStoreIC_Setter_ForDeopt);
+ value = reinterpret_cast<intptr_t>(setter_stub);
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; code object\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // Skip receiver.
+ Translation::Opcode opcode =
+ static_cast<Translation::Opcode>(iterator->Next());
+ iterator->Skip(Translation::NumberOfOperandsFor(opcode));
+
+ // The implicit return value was part of the artificial setter stub
+ // environment.
+ output_offset -= kPointerSize;
+ DoTranslateCommand(iterator, frame_index, output_offset);
+
+ ASSERT(0 == output_offset);
+
+ intptr_t pc = reinterpret_cast<intptr_t>(
+ setter_stub->instruction_start() +
+ isolate_->heap()->setter_stub_deopt_pc_offset()->value());
+ output_frame->SetPc(pc);
+}
+
+
// This code is very similar to ia32/arm code, but relies on register names
// (fp, sp) and how the frame is laid out.
void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
translation->BeginConstructStubFrame(closure_id, translation_size);
break;
case JS_SETTER:
- // TODO(svenpanne) Implement me!
+ ASSERT(translation_size == 2);
+ ASSERT(height == 0);
+ translation->BeginSetterStubFrame(closure_id);
break;
case ARGUMENTS_ADAPTOR:
translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
}
-Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
- Handle<String> name,
- Handle<JSObject> receiver,
- Handle<JSObject> holder,
+#undef __
+#define __ ACCESS_MASM(masm)
+
+
+void StoreStubCompiler::GenerateStoreViaSetter(
+ MacroAssembler* masm,
Handle<JSFunction> setter) {
// ----------- S t a t e -------------
// -- a0 : value
// -- a2 : name
// -- ra : return address
// -----------------------------------
- Label miss;
-
- // Check that the maps haven't changed.
- __ JumpIfSmi(a1, &miss);
- CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
-
{
- FrameScope scope(masm(), StackFrame::INTERNAL);
+ FrameScope scope(masm, StackFrame::INTERNAL);
// Save value register, so we can restore it later.
__ push(a0);
- // Call the JavaScript setter with the receiver and the value on the stack.
- __ push(a1);
- __ push(a0);
- ParameterCount actual(1);
- __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
- CALL_AS_METHOD);
+ if (!setter.is_null()) {
+ // Call the JavaScript setter with receiver and value on the stack.
+ __ push(a1);
+ __ push(a0);
+ ParameterCount actual(1);
+ __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
+ CALL_AS_METHOD);
+ } else {
+ // If we generate a global code snippet for deoptimization only, remember
+ // the place to continue after deoptimization.
+ masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
+ }
// We have to return the passed value, not the return value of the setter.
__ pop(v0);
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
__ Ret();
+}
+
+
+#undef __
+#define __ ACCESS_MASM(masm())
+
+
+Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
+ Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ Handle<JSFunction> setter) {
+ // ----------- S t a t e -------------
+ // -- a0 : value
+ // -- a1 : receiver
+ // -- a2 : name
+ // -- ra : return address
+ // -----------------------------------
+ Label miss;
+
+ // Check that the maps haven't changed.
+ __ JumpIfSmi(a1, &miss);
+ CheckPrototypes(receiver, a1, holder, a3, t0, t1, name, &miss);
+
+ GenerateStoreViaSetter(masm(), setter);
__ bind(&miss);
Handle<Code> ic = masm()->isolate()->builtins()->StoreIC_Miss();
break;
}
+ case Translation::SETTER_STUB_FRAME: {
+ int function_id = iterator.Next();
+ JSFunction* function =
+ JSFunction::cast(LiteralArray()->get(function_id));
+ PrintF(out, "{function=");
+ function->PrintName(out);
+ PrintF(out, "}");
+ break;
+ }
+
case Translation::DUPLICATE:
break;
Handle<AccessorInfo> callback,
Handle<String> name);
+ static void GenerateStoreViaSetter(MacroAssembler* masm,
+ Handle<JSFunction> setter);
+
Handle<Code> CompileStoreViaSetter(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
}
+void Deoptimizer::DoComputeSetterStubFrame(TranslationIterator* iterator,
+ int frame_index) {
+ JSFunction* setter = JSFunction::cast(ComputeLiteral(iterator->Next()));
+ // The receiver and the implicit return value are expected in registers by the
+ // StoreIC, so they don't belong to the output stack frame. This means that we
+ // have to use a height of 0.
+ unsigned height = 0;
+ unsigned height_in_bytes = height * kPointerSize;
+ if (FLAG_trace_deopt) {
+ PrintF(" translating setter stub => height=%u\n", height_in_bytes);
+ }
+
+ // We need 1 stack entry for the return address + 4 stack entries from
+ // StackFrame::INTERNAL (FP, context, frame type, code object, see
+ // MacroAssembler::EnterFrame) + 1 stack entry from setter stub (implicit
+ // return value, see StoreStubCompiler::CompileStoreViaSetter).
+ unsigned fixed_frame_size = (1 + 4 + 1) * kPointerSize;
+ unsigned output_frame_size = height_in_bytes + fixed_frame_size;
+
+ // Allocate and store the output frame description.
+ FrameDescription* output_frame =
+ new(output_frame_size) FrameDescription(output_frame_size, setter);
+ output_frame->SetFrameType(StackFrame::INTERNAL);
+
+ // A frame for a setter stub can not be the topmost or bottommost one.
+ ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
+ ASSERT(output_[frame_index] == NULL);
+ output_[frame_index] = output_frame;
+
+ // The top address of the frame is computed from the previous frame's top and
+ // this frame's size.
+ intptr_t top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
+ output_frame->SetTop(top_address);
+
+ unsigned output_offset = output_frame_size;
+
+ // Read caller's PC from the previous frame.
+ output_offset -= kPointerSize;
+ intptr_t callers_pc = output_[frame_index - 1]->GetPc();
+ output_frame->SetFrameSlot(output_offset, callers_pc);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; caller's pc\n",
+ top_address + output_offset, output_offset, callers_pc);
+ }
+
+ // Read caller's FP from the previous frame, and set this frame's FP.
+ output_offset -= kPointerSize;
+ intptr_t value = output_[frame_index - 1]->GetFp();
+ output_frame->SetFrameSlot(output_offset, value);
+ intptr_t fp_value = top_address + output_offset;
+ output_frame->SetFp(fp_value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; caller's fp\n",
+ fp_value, output_offset, value);
+ }
+
+ // The context can be gotten from the previous frame.
+ output_offset -= kPointerSize;
+ value = output_[frame_index - 1]->GetContext();
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; context\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // A marker value is used in place of the function.
+ output_offset -= kPointerSize;
+ value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL));
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; function (setter sentinel)\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // Get Code object from setter stub.
+ output_offset -= kPointerSize;
+ Code* setter_stub =
+ isolate_->builtins()->builtin(Builtins::kStoreIC_Setter_ForDeopt);
+ value = reinterpret_cast<intptr_t>(setter_stub);
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; code object\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // Skip receiver.
+ Translation::Opcode opcode =
+ static_cast<Translation::Opcode>(iterator->Next());
+ iterator->Skip(Translation::NumberOfOperandsFor(opcode));
+
+ // The implicit return value was part of the artificial setter stub
+ // environment.
+ output_offset -= kPointerSize;
+ DoTranslateCommand(iterator, frame_index, output_offset);
+
+ ASSERT(0 == output_offset);
+
+ intptr_t pc = reinterpret_cast<intptr_t>(
+ setter_stub->instruction_start() +
+ isolate_->heap()->setter_stub_deopt_pc_offset()->value());
+ output_frame->SetPc(pc);
+}
+
+
void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
int frame_index) {
BailoutId node_id = BailoutId(iterator->Next());
translation->BeginConstructStubFrame(closure_id, translation_size);
break;
case JS_SETTER:
- // TODO(svenpanne) Implement me!
+ ASSERT(translation_size == 2);
+ ASSERT(height == 0);
+ translation->BeginSetterStubFrame(closure_id);
break;
case ARGUMENTS_ADAPTOR:
translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
}
-Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
- Handle<String> name,
- Handle<JSObject> receiver,
- Handle<JSObject> holder,
+#undef __
+#define __ ACCESS_MASM(masm)
+
+
+void StoreStubCompiler::GenerateStoreViaSetter(
+ MacroAssembler* masm,
Handle<JSFunction> setter) {
// ----------- S t a t e -------------
// -- rax : value
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
- Label miss;
-
- // Check that the maps haven't changed.
- __ JumpIfSmi(rdx, &miss);
- CheckPrototypes(receiver, rdx, holder, rbx, r8, rdi, name, &miss);
-
{
- FrameScope scope(masm(), StackFrame::INTERNAL);
+ FrameScope scope(masm, StackFrame::INTERNAL);
// Save value register, so we can restore it later.
__ push(rax);
- // Call the JavaScript setter with the receiver and the value on the stack.
- __ push(rdx);
- __ push(rax);
- ParameterCount actual(1);
- __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
- CALL_AS_METHOD);
+ if (!setter.is_null()) {
+ // Call the JavaScript setter with receiver and value on the stack.
+ __ push(rdx);
+ __ push(rax);
+ ParameterCount actual(1);
+ __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
+ CALL_AS_METHOD);
+ } else {
+ // If we generate a global code snippet for deoptimization only, remember
+ // the place to continue after deoptimization.
+ masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
+ }
// We have to return the passed value, not the return value of the setter.
__ pop(rax);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
}
__ ret(0);
+}
+
+
+#undef __
+#define __ ACCESS_MASM(masm())
+
+
+Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
+ Handle<String> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> holder,
+ Handle<JSFunction> setter) {
+ // ----------- S t a t e -------------
+ // -- rax : value
+ // -- rcx : name
+ // -- rdx : receiver
+ // -- rsp[0] : return address
+ // -----------------------------------
+ Label miss;
+
+ // Check that the maps haven't changed.
+ __ JumpIfSmi(rdx, &miss);
+ CheckPrototypes(receiver, rdx, holder, rbx, r8, rdi, name, &miss);
+
+ GenerateStoreViaSetter(masm(), setter);
__ bind(&miss);
Handle<Code> ic = isolate()->builtins()->StoreIC_Miss();
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --allow-natives-syntax --inline-accessors
+// Flags: --allow-natives-syntax --inline-accessors --max-opt-count=100
var accessorCallCount, setterArgument, setterValue, obj, forceDeopt;
// -----------------------------------------------------------------------------
// Helpers for testing inlining of getters.
-function TestInlinedGetter(context, expected) {
- forceDeopt = 0;
+function TestInlinedGetter(context, obj, expected) {
+ forceDeopt = { deopt: 0 };
accessorCallCount = 0;
- assertEquals(expected, context());
+ assertEquals(expected, context(obj));
assertEquals(1, accessorCallCount);
- assertEquals(expected, context());
+ assertEquals(expected, context(obj));
assertEquals(2, accessorCallCount);
%OptimizeFunctionOnNextCall(context);
- assertEquals(expected, context());
+ assertEquals(expected, context(obj));
assertEquals(3, accessorCallCount);
- %DeoptimizeFunction(context);
- %ClearFunctionTypeFeedback(context);
+ forceDeopt = { /* empty*/ };
+ assertEquals(expected, context(obj));
+ assertEquals(4, accessorCallCount);
}
-function TestGetterInAllContexts(obj, expected) {
- function value_context() {
- return obj.getterProperty;
- }
- TestInlinedGetter(value_context, expected);
-
- function test_context() {
- if (obj.getterProperty) {
- return 111;
- } else {
- return 222;
- }
+function value_context_for_getter(obj) {
+ return obj.getterProperty;
+}
+
+function test_context_for_getter(obj) {
+ if (obj.getterProperty) {
+ return 111;
+ } else {
+ return 222;
}
- TestInlinedGetter(test_context, expected ? 111 : 222);
+}
- function effect_context() {
- obj.getterProperty;
- return 5678;
+function effect_context_for_getter(obj) {
+ obj.getterProperty;
+ return 5678;
+}
+
+function TryGetter(context, getter, obj, expected, expectException) {
+ try {
+ TestInlinedGetter(context, obj, expected);
+ assertFalse(expectException);
+ } catch (exception) {
+ assertTrue(expectException);
+ assertEquals(7, exception.stack.split('\n').length);
}
- TestInlinedGetter(effect_context, 5678);
+ %DeoptimizeFunction(context);
+ %ClearFunctionTypeFeedback(context);
+ %ClearFunctionTypeFeedback(getter);
+}
+
+function TestGetterInAllContexts(getter, obj, expected, expectException) {
+ TryGetter(value_context_for_getter, getter, obj, expected, expectException);
+ TryGetter(test_context_for_getter, getter, obj, expected ? 111 : 222,
+ expectException);
+ TryGetter(effect_context_for_getter, getter, obj, 5678, expectException);
}
// -----------------------------------------------------------------------------
function getter1() {
assertSame(obj, this);
accessorCallCount++;
- forceDeopt + 1;
+ forceDeopt.deopt;
return 1234;
}
function ConstrG1() { }
obj = Object.defineProperty(new ConstrG1(), "getterProperty", { get: getter1 });
-TestGetterInAllContexts(obj, 1234);
+TestGetterInAllContexts(getter1, obj, 1234, false);
obj = Object.create(obj);
-TestGetterInAllContexts(obj, 1234);
+TestGetterInAllContexts(getter1, obj, 1234, false);
// -----------------------------------------------------------------------------
// Test getter returning false in all contexts.
function getter2() {
assertSame(obj, this);
accessorCallCount++;
- forceDeopt + 1;
+ forceDeopt.deopt;
return false;
}
function ConstrG2() { }
obj = Object.defineProperty(new ConstrG2(), "getterProperty", { get: getter2 });
-TestGetterInAllContexts(obj, false);
+TestGetterInAllContexts(getter2, obj, false, false);
obj = Object.create(obj);
-TestGetterInAllContexts(obj, false);
+TestGetterInAllContexts(getter2, obj, false, false);
// -----------------------------------------------------------------------------
// Test getter without a return in all contexts.
function getter3() {
assertSame(obj, this);
accessorCallCount++;
- forceDeopt + 1;
+ forceDeopt.deopt;
}
function ConstrG3() { }
obj = Object.defineProperty(new ConstrG3(), "getterProperty", { get: getter3 });
-TestGetterInAllContexts(obj, undefined);
+TestGetterInAllContexts(getter3, obj, undefined, false);
obj = Object.create(obj);
-TestGetterInAllContexts(obj, undefined);
+TestGetterInAllContexts(getter3, obj, undefined, false);
// -----------------------------------------------------------------------------
// Test getter with too many arguments without a return in all contexts.
assertSame(obj, this);
assertEquals(undefined, a);
accessorCallCount++;
- forceDeopt + 1;
+ forceDeopt.deopt;
}
function ConstrG4() { }
obj = Object.defineProperty(new ConstrG4(), "getterProperty", { get: getter4 });
-TestGetterInAllContexts(obj, undefined);
+TestGetterInAllContexts(getter4, obj, undefined, false);
obj = Object.create(obj);
-TestGetterInAllContexts(obj, undefined);
+TestGetterInAllContexts(getter4, obj, undefined, false);
// -----------------------------------------------------------------------------
// Test getter with too many arguments with a return in all contexts.
assertSame(obj, this);
assertEquals(undefined, a);
accessorCallCount++;
- forceDeopt + 1;
+ forceDeopt.deopt;
return 9876;
}
function ConstrG5() { }
obj = Object.defineProperty(new ConstrG5(), "getterProperty", { get: getter5 });
-TestGetterInAllContexts(obj, 9876);
+TestGetterInAllContexts(getter5, obj, 9876, false);
+obj = Object.create(obj);
+TestGetterInAllContexts(getter5, obj, 9876, false);
+
+// -----------------------------------------------------------------------------
+// Test getter which throws from optimized code.
+
+function getter6() {
+ assertSame(obj, this);
+ accessorCallCount++;
+ forceDeopt.deopt;
+ if (accessorCallCount == 4) { 123 in null; }
+ return 13579;
+}
+
+function ConstrG6() { }
+obj = Object.defineProperty(new ConstrG6(), "getterProperty", { get: getter6 });
+TestGetterInAllContexts(getter6, obj, 13579, true);
obj = Object.create(obj);
-TestGetterInAllContexts(obj, 9876);
+TestGetterInAllContexts(getter6, obj, 13579, true);
// -----------------------------------------------------------------------------
// Helpers for testing inlining of setters.
-function TestInlinedSetter(context, value, expected) {
- forceDeopt = 0;
+function TestInlinedSetter(context, obj, value, expected) {
+ forceDeopt = { deopt: 0 };
accessorCallCount = 0;
setterArgument = value;
- assertEquals(expected, context(value));
+ assertEquals(expected, context(obj, value));
assertEquals(value, setterValue);
assertEquals(1, accessorCallCount);
- assertEquals(expected, context(value));
+ assertEquals(expected, context(obj, value));
assertEquals(value, setterValue);
assertEquals(2, accessorCallCount);
%OptimizeFunctionOnNextCall(context);
- assertEquals(expected, context(value));
+ assertEquals(expected, context(obj, value));
assertEquals(value, setterValue);
assertEquals(3, accessorCallCount);
- %DeoptimizeFunction(context);
- %ClearFunctionTypeFeedback(context);
+ forceDeopt = { /* empty*/ };
+ assertEquals(expected, context(obj, value));
+ assertEquals(value, setterValue);
+ assertEquals(4, accessorCallCount);
}
-function TestSetterInAllContexts(obj) {
- function value_context(value) {
- return obj.setterProperty = value;
- }
- TestInlinedSetter(value_context, 111, 111);
-
- function test_context(value) {
- if (obj.setterProperty = value) {
- return 333;
- } else {
- return 444;
- }
+function value_context_for_setter(obj, value) {
+ return obj.setterProperty = value;
+}
+
+function test_context_for_setter(obj, value) {
+ if (obj.setterProperty = value) {
+ return 333;
+ } else {
+ return 444;
}
- TestInlinedSetter(test_context, true, 333);
- TestInlinedSetter(test_context, false, 444);
+}
+
+function effect_context_for_setter(obj, value) {
+ obj.setterProperty = value;
+ return 666;
+}
- function effect_context(value) {
- obj.setterProperty = value;
- return 666;
+function TrySetter(context, setter, obj, expectException, value, expected) {
+ try {
+ TestInlinedSetter(context, obj, value, expected);
+ assertFalse(expectException);
+ } catch (exception) {
+ assertTrue(expectException);
+ assertEquals(7, exception.stack.split('\n').length);
}
- TestInlinedSetter(effect_context, 555, 666);
+ %DeoptimizeFunction(context);
+ %ClearFunctionTypeFeedback(context);
+ %ClearFunctionTypeFeedback(setter);
+}
+
+function TestSetterInAllContexts(setter, obj, expectException) {
+ TrySetter(value_context_for_setter, setter, obj, expectException, 111, 111);
+ TrySetter(test_context_for_setter, setter, obj, expectException, true, 333);
+ TrySetter(test_context_for_setter, setter, obj, expectException, false, 444);
+ TrySetter(effect_context_for_setter, setter, obj, expectException, 555, 666);
}
// -----------------------------------------------------------------------------
function setter1(value) {
assertSame(obj, this);
accessorCallCount++;
- forceDeopt + 1;
+ forceDeopt.deopt;
setterValue = value;
}
function ConstrS1() { }
obj = Object.defineProperty(new ConstrS1(), "setterProperty", { set: setter1 });
-TestSetterInAllContexts(obj);
+TestSetterInAllContexts(setter1, obj, false);
obj = Object.create(obj);
-TestSetterInAllContexts(obj);
+TestSetterInAllContexts(setter1, obj, false);
// -----------------------------------------------------------------------------
// Test setter returning something different than the RHS in all contexts.
function setter2(value) {
assertSame(obj, this);
accessorCallCount++;
- forceDeopt + 1;
+ forceDeopt.deopt;
setterValue = value;
return 1000000;
}
function ConstrS2() { }
obj = Object.defineProperty(new ConstrS2(), "setterProperty", { set: setter2 });
-TestSetterInAllContexts(obj);
+TestSetterInAllContexts(setter2, obj, false);
obj = Object.create(obj);
-TestSetterInAllContexts(obj);
+TestSetterInAllContexts(setter2, obj, false);
// -----------------------------------------------------------------------------
// Test setter with too few arguments without a return in all contexts.
function setter3() {
assertSame(obj, this);
accessorCallCount++;
- forceDeopt + 1;
+ forceDeopt.deopt;
setterValue = setterArgument;
}
function ConstrS3() { }
obj = Object.defineProperty(new ConstrS3(), "setterProperty", { set: setter3 });
-TestSetterInAllContexts(obj);
+TestSetterInAllContexts(setter3, obj, false);
obj = Object.create(obj);
-TestSetterInAllContexts(obj);
+TestSetterInAllContexts(setter3, obj, false);
// -----------------------------------------------------------------------------
// Test setter with too few arguments with a return in all contexts.
function setter4() {
assertSame(obj, this);
accessorCallCount++;
- forceDeopt + 1;
+ forceDeopt.deopt;
setterValue = setterArgument;
return 2000000;
}
function ConstrS4() { }
obj = Object.defineProperty(new ConstrS4(), "setterProperty", { set: setter4 });
-TestSetterInAllContexts(obj);
+TestSetterInAllContexts(setter4, obj, false);
obj = Object.create(obj);
-TestSetterInAllContexts(obj);
+TestSetterInAllContexts(setter4, obj, false);
// -----------------------------------------------------------------------------
// Test setter with too many arguments without a return in all contexts.
assertSame(obj, this);
assertEquals(undefined, foo);
accessorCallCount++;
- forceDeopt + 1;
+ forceDeopt.deopt;
setterValue = value;
}
function ConstrS5() { }
obj = Object.defineProperty(new ConstrS5(), "setterProperty", { set: setter5 });
-TestSetterInAllContexts(obj);
+TestSetterInAllContexts(setter5, obj, false);
obj = Object.create(obj);
-TestSetterInAllContexts(obj);
+TestSetterInAllContexts(setter5, obj, false);
// -----------------------------------------------------------------------------
// Test setter with too many arguments with a return in all contexts.
assertSame(obj, this);
assertEquals(undefined, foo);
accessorCallCount++;
- forceDeopt + 1;
+ forceDeopt.deopt;
setterValue = value;
return 3000000;
}
function ConstrS6() { }
obj = Object.defineProperty(new ConstrS6(), "setterProperty", { set: setter6 });
-TestSetterInAllContexts(obj);
+TestSetterInAllContexts(setter6, obj, false);
+obj = Object.create(obj);
+TestSetterInAllContexts(setter6, obj, false);
+
+// -----------------------------------------------------------------------------
+// Test setter which throws from optimized code.
+
+function setter7(value) {
+ accessorCallCount++;
+ forceDeopt.deopt;
+ if (accessorCallCount == 4) { 123 in null; }
+ setterValue = value;
+}
+
+function ConstrS7() { }
+obj = Object.defineProperty(new ConstrS7(), "setterProperty", { set: setter7 });
+TestSetterInAllContexts(setter7, obj, true);
obj = Object.create(obj);
-TestSetterInAllContexts(obj);
+TestSetterInAllContexts(setter7, obj, true);