From: mmaly@chromium.org Date: Tue, 1 Mar 2011 01:42:37 +0000 (+0000) Subject: Assignment to read only properties throws in strict mode. X-Git-Tag: upstream/4.7.83~20068 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=98aea3c3532646e20fb70eef1f308de65dba247d;p=platform%2Fupstream%2Fv8.git Assignment to read only properties throws in strict mode. Review URL: http://codereview.chromium.org/6594037/ git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6976 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/api.cc b/src/api.cc index d718c88..b77e450 100644 --- a/src/api.cc +++ b/src/api.cc @@ -2286,7 +2286,8 @@ bool v8::Object::Set(v8::Handle key, v8::Handle value, self, key_obj, value_obj, - static_cast(attribs)); + static_cast(attribs), + i::kNonStrictMode); has_pending_exception = obj.is_null(); EXCEPTION_BAILOUT_CHECK(false); return true; @@ -2711,7 +2712,8 @@ bool v8::Object::SetHiddenValue(v8::Handle key, hidden_props, key_obj, value_obj, - static_cast(None)); + static_cast(None), + i::kNonStrictMode); has_pending_exception = obj.is_null(); EXCEPTION_BAILOUT_CHECK(false); return true; diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index 3e125a3..f03504e 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -1938,8 +1938,9 @@ void CodeGenerator::DeclareGlobals(Handle pairs) { frame_->EmitPush(cp); frame_->EmitPush(Operand(pairs)); frame_->EmitPush(Operand(Smi::FromInt(is_eval() ? 1 : 0))); + frame_->EmitPush(Operand(Smi::FromInt(strict_mode_flag()))); - frame_->CallRuntime(Runtime::kDeclareGlobals, 3); + frame_->CallRuntime(Runtime::kDeclareGlobals, 4); // The result is discarded. } @@ -3287,7 +3288,8 @@ void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { // context slot followed by initialization. frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); } else { - frame_->CallRuntime(Runtime::kStoreContextSlot, 3); + frame_->EmitPush(Operand(Smi::FromInt(strict_mode_flag()))); + frame_->CallRuntime(Runtime::kStoreContextSlot, 4); } // Storing a variable must keep the (new) value on the expression // stack. This is necessary for compiling assignment expressions. @@ -3637,7 +3639,8 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { Load(key); Load(value); if (property->emit_store()) { - frame_->CallRuntime(Runtime::kSetProperty, 3); + frame_->EmitPush(Operand(Smi::FromInt(NONE))); // PropertyAttributes + frame_->CallRuntime(Runtime::kSetProperty, 4); } else { frame_->Drop(3); } @@ -6674,8 +6677,12 @@ class DeferredReferenceSetKeyedValue: public DeferredCode { public: DeferredReferenceSetKeyedValue(Register value, Register key, - Register receiver) - : value_(value), key_(key), receiver_(receiver) { + Register receiver, + StrictModeFlag strict_mode) + : value_(value), + key_(key), + receiver_(receiver), + strict_mode_(strict_mode) { set_comment("[ DeferredReferenceSetKeyedValue"); } @@ -6685,6 +6692,7 @@ class DeferredReferenceSetKeyedValue: public DeferredCode { Register value_; Register key_; Register receiver_; + StrictModeFlag strict_mode_; }; @@ -6706,7 +6714,9 @@ void DeferredReferenceSetKeyedValue::Generate() { { Assembler::BlockConstPoolScope block_const_pool(masm_); // Call keyed store IC. It has the arguments value, key and receiver in r0, // r1 and r2. - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + (strict_mode_ == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); __ Call(ic, RelocInfo::CODE_TARGET); // The call must be followed by a nop instruction to indicate that the // keyed store has been inlined. @@ -6724,8 +6734,12 @@ class DeferredReferenceSetNamedValue: public DeferredCode { public: DeferredReferenceSetNamedValue(Register value, Register receiver, - Handle name) - : value_(value), receiver_(receiver), name_(name) { + Handle name, + StrictModeFlag strict_mode) + : value_(value), + receiver_(receiver), + name_(name), + strict_mode_(strict_mode) { set_comment("[ DeferredReferenceSetNamedValue"); } @@ -6735,6 +6749,7 @@ class DeferredReferenceSetNamedValue: public DeferredCode { Register value_; Register receiver_; Handle name_; + StrictModeFlag strict_mode_; }; @@ -6754,7 +6769,9 @@ void DeferredReferenceSetNamedValue::Generate() { { Assembler::BlockConstPoolScope block_const_pool(masm_); // Call keyed store IC. It has the arguments value, key and receiver in r0, // r1 and r2. - Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + (strict_mode_ == kStrictMode) ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); __ Call(ic, RelocInfo::CODE_TARGET); // The call must be followed by a nop instruction to indicate that the // named store has been inlined. @@ -6943,7 +6960,8 @@ void CodeGenerator::EmitNamedStore(Handle name, bool is_contextual) { Register receiver = r1; DeferredReferenceSetNamedValue* deferred = - new DeferredReferenceSetNamedValue(value, receiver, name); + new DeferredReferenceSetNamedValue( + value, receiver, name, strict_mode_flag()); // Check that the receiver is a heap object. __ tst(receiver, Operand(kSmiTagMask)); @@ -7129,7 +7147,8 @@ void CodeGenerator::EmitKeyedStore(StaticType* key_type, // The deferred code expects value, key and receiver in registers. DeferredReferenceSetKeyedValue* deferred = - new DeferredReferenceSetKeyedValue(value, key, receiver); + new DeferredReferenceSetKeyedValue( + value, key, receiver, strict_mode_flag()); // Check that the value is a smi. As this inlined code does not set the // write barrier it is only possible to store smi values. @@ -7214,7 +7233,7 @@ void CodeGenerator::EmitKeyedStore(StaticType* key_type, deferred->BindExit(); } else { - frame()->CallKeyedStoreIC(); + frame()->CallKeyedStoreIC(strict_mode_flag()); } } diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 9f521fb..a242870 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -793,7 +793,9 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, prop->key()->AsLiteral()->handle()->IsSmi()); __ mov(r1, Operand(prop->key()->AsLiteral()->handle())); - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin(is_strict() + ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); // Value in r0 is ignored (declarations are statements). } @@ -809,10 +811,11 @@ void FullCodeGenerator::VisitDeclaration(Declaration* decl) { void FullCodeGenerator::DeclareGlobals(Handle pairs) { // Call the runtime to declare the globals. // The context is the first argument. - __ mov(r1, Operand(pairs)); - __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); - __ Push(cp, r1, r0); - __ CallRuntime(Runtime::kDeclareGlobals, 3); + __ mov(r2, Operand(pairs)); + __ mov(r1, Operand(Smi::FromInt(is_eval() ? 1 : 0))); + __ mov(r0, Operand(Smi::FromInt(strict_mode_flag()))); + __ Push(cp, r2, r1, r0); + __ CallRuntime(Runtime::kDeclareGlobals, 4); // Return value is ignored. } @@ -1456,7 +1459,9 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForStackValue(key); VisitForStackValue(value); if (property->emit_store()) { - __ CallRuntime(Runtime::kSetProperty, 3); + __ mov(r0, Operand(Smi::FromInt(NONE))); // PropertyAttributes + __ push(r0); + __ CallRuntime(Runtime::kSetProperty, 4); } else { __ Drop(3); } @@ -2050,7 +2055,9 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { __ mov(r1, r0); __ pop(r0); // Restore value. __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); - Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); break; } @@ -2071,7 +2078,9 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { __ pop(r2); } __ pop(r0); // Restore value. - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); break; } @@ -2095,9 +2104,9 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, // r2, and the global object in r1. __ mov(r2, Operand(var->name())); __ ldr(r1, GlobalObjectOperand()); - Handle ic(Builtins::builtin(is_strict() - ? Builtins::StoreIC_Initialize_Strict - : Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); } else if (op == Token::INIT_CONST) { @@ -2166,9 +2175,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, case Slot::LOOKUP: // Call the runtime for the assignment. __ push(r0); // Value. - __ mov(r0, Operand(slot->var()->name())); - __ Push(cp, r0); // Context and name. - __ CallRuntime(Runtime::kStoreContextSlot, 3); + __ mov(r1, Operand(slot->var()->name())); + __ mov(r0, Operand(Smi::FromInt(strict_mode_flag()))); + __ Push(cp, r1, r0); // Context, name, strict mode. + __ CallRuntime(Runtime::kStoreContextSlot, 4); break; } } @@ -2203,7 +2213,9 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { __ pop(r1); } - Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); // If the assignment ends an initialization block, revert to fast case. @@ -2247,7 +2259,9 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { __ pop(r2); } - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); // If the assignment ends an initialization block, revert to fast case. @@ -3767,7 +3781,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { case NAMED_PROPERTY: { __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); __ pop(r1); - Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { @@ -3782,7 +3798,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { case KEYED_PROPERTY: { __ pop(r1); // Key. __ pop(r2); // Receiver. - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc index 6c7aa06..0fc6818 100644 --- a/src/arm/ic-arm.cc +++ b/src/arm/ic-arm.cc @@ -1400,7 +1400,8 @@ void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { } -void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) { +void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, + StrictModeFlag strict_mode) { // ---------- S t a t e -------------- // -- r0 : value // -- r1 : key @@ -1411,11 +1412,16 @@ void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) { // Push receiver, key and value for runtime call. __ Push(r2, r1, r0); - __ TailCallRuntime(Runtime::kSetProperty, 3, 1); + __ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes + __ mov(r0, Operand(Smi::FromInt(strict_mode))); // Strict mode. + __ Push(r1, r0); + + __ TailCallRuntime(Runtime::kSetProperty, 5, 1); } -void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { +void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, + StrictModeFlag strict_mode) { // ---------- S t a t e -------------- // -- r0 : value // -- r1 : key @@ -1470,7 +1476,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { // r0: value. // r1: key. // r2: receiver. - GenerateRuntimeSetProperty(masm); + GenerateRuntimeSetProperty(masm, strict_mode); // Check whether the elements is a pixel array. // r4: elements map. @@ -1540,7 +1546,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { void StoreIC::GenerateMegamorphic(MacroAssembler* masm, - Code::ExtraICState extra_ic_state) { + StrictModeFlag strict_mode) { // ----------- S t a t e ------------- // -- r0 : value // -- r1 : receiver @@ -1552,7 +1558,7 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm, Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, NOT_IN_LOOP, MONOMORPHIC, - extra_ic_state); + strict_mode); StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5); // Cache miss: Jump to runtime. @@ -1646,7 +1652,8 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) { } -void StoreIC::GenerateGlobalProxy(MacroAssembler* masm) { +void StoreIC::GenerateGlobalProxy(MacroAssembler* masm, + StrictModeFlag strict_mode) { // ----------- S t a t e ------------- // -- r0 : value // -- r1 : receiver @@ -1656,8 +1663,12 @@ void StoreIC::GenerateGlobalProxy(MacroAssembler* masm) { __ Push(r1, r2, r0); + __ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes + __ mov(r0, Operand(Smi::FromInt(strict_mode))); + __ Push(r1, r0); + // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kSetProperty, 3, 1); + __ TailCallRuntime(Runtime::kSetProperty, 5, 1); } diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index d375617..56debac 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -2863,9 +2863,9 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { // Name is always in r2. __ mov(r2, Operand(instr->name())); - Handle ic(Builtins::builtin(info_->is_strict() - ? Builtins::StoreIC_Initialize_Strict - : Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + info_->is_strict() ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -2907,7 +2907,9 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { ASSERT(ToRegister(instr->key()).is(r1)); ASSERT(ToRegister(instr->value()).is(r0)); - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + info_->is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); CallCode(ic, RelocInfo::CODE_TARGET, instr); } diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index e250112..60a11f3 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -2671,10 +2671,13 @@ MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, __ Push(r1, r2, r0); // Receiver, name, value. + __ mov(r0, Operand(Smi::FromInt(strict_mode_))); + __ push(r0); // strict mode + // Do tail-call to the runtime system. ExternalReference store_ic_property = ExternalReference(IC_Utility(IC::kStoreInterceptorProperty)); - __ TailCallExternalReference(store_ic_property, 3, 1); + __ TailCallExternalReference(store_ic_property, 4, 1); // Handle store cache miss. __ bind(&miss); @@ -4056,7 +4059,12 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( // Push receiver, key and value for runtime call. __ Push(r2, r1, r0); - __ TailCallRuntime(Runtime::kSetProperty, 3, 1); + __ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes + __ mov(r0, Operand(Smi::FromInt( + Code::ExtractExtraICStateFromFlags(flags) & kStrictMode))); + __ Push(r1, r0); + + __ TailCallRuntime(Runtime::kSetProperty, 5, 1); return GetCode(flags); } diff --git a/src/arm/virtual-frame-arm.cc b/src/arm/virtual-frame-arm.cc index b4b518c..544e405 100644 --- a/src/arm/virtual-frame-arm.cc +++ b/src/arm/virtual-frame-arm.cc @@ -332,9 +332,9 @@ void VirtualFrame::CallLoadIC(Handle name, RelocInfo::Mode mode) { void VirtualFrame::CallStoreIC(Handle name, bool is_contextual, StrictModeFlag strict_mode) { - Handle ic(Builtins::builtin(strict_mode == kStrictMode - ? Builtins::StoreIC_Initialize_Strict - : Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + (strict_mode == kStrictMode) ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); PopToR0(); RelocInfo::Mode mode; if (is_contextual) { @@ -359,8 +359,10 @@ void VirtualFrame::CallKeyedLoadIC() { } -void VirtualFrame::CallKeyedStoreIC() { - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); +void VirtualFrame::CallKeyedStoreIC(StrictModeFlag strict_mode) { + Handle ic(Builtins::builtin( + (strict_mode == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); PopToR1R0(); SpillAll(); EmitPop(r2); diff --git a/src/arm/virtual-frame-arm.h b/src/arm/virtual-frame-arm.h index b6e794a..76470bd 100644 --- a/src/arm/virtual-frame-arm.h +++ b/src/arm/virtual-frame-arm.h @@ -303,7 +303,7 @@ class VirtualFrame : public ZoneObject { // Call keyed store IC. Value, key and receiver are on the stack. All three // are consumed. Result is returned in r0. - void CallKeyedStoreIC(); + void CallKeyedStoreIC(StrictModeFlag strict_mode); // Call into an IC stub given the number of arguments it removes // from the stack. Register arguments to the IC stub are implicit, diff --git a/src/builtins.cc b/src/builtins.cc index 8fdc1b1..01e8deb 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -1328,12 +1328,12 @@ static void Generate_StoreIC_Normal_Strict(MacroAssembler* masm) { static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) { - StoreIC::GenerateMegamorphic(masm, StoreIC::kStoreICNonStrict); + StoreIC::GenerateMegamorphic(masm, kNonStrictMode); } static void Generate_StoreIC_Megamorphic_Strict(MacroAssembler* masm) { - StoreIC::GenerateMegamorphic(masm, StoreIC::kStoreICStrict); + StoreIC::GenerateMegamorphic(masm, kStrictMode); } @@ -1348,17 +1348,22 @@ static void Generate_StoreIC_ArrayLength_Strict(MacroAssembler* masm) { static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) { - StoreIC::GenerateGlobalProxy(masm); + StoreIC::GenerateGlobalProxy(masm, kNonStrictMode); } static void Generate_StoreIC_GlobalProxy_Strict(MacroAssembler* masm) { - StoreIC::GenerateGlobalProxy(masm); + StoreIC::GenerateGlobalProxy(masm, kStrictMode); } static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) { - KeyedStoreIC::GenerateGeneric(masm); + KeyedStoreIC::GenerateGeneric(masm, kNonStrictMode); +} + + +static void Generate_KeyedStoreIC_Generic_Strict(MacroAssembler* masm) { + KeyedStoreIC::GenerateGeneric(masm, kStrictMode); } @@ -1372,6 +1377,11 @@ static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) { } +static void Generate_KeyedStoreIC_Initialize_Strict(MacroAssembler* masm) { + KeyedStoreIC::GenerateInitialize(masm); +} + + #ifdef ENABLE_DEBUGGER_SUPPORT static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) { Debug::GenerateLoadICDebugBreak(masm); diff --git a/src/builtins.h b/src/builtins.h index 2733410..5ea4665 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -62,111 +62,116 @@ enum BuiltinExtraArguments { // Define list of builtins implemented in assembly. -#define BUILTIN_LIST_A(V) \ - V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(JSConstructCall, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(JSConstructStubCountdown, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(JSConstructStubApi, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(JSEntryTrampoline, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(LazyCompile, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(LazyRecompile, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(NotifyDeoptimized, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(NotifyLazyDeoptimized, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(NotifyOSR, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - \ - V(LoadIC_Miss, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(StoreIC_Miss, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - \ - V(LoadIC_Initialize, LOAD_IC, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC, \ - Code::kNoExtraICState) \ - V(LoadIC_Normal, LOAD_IC, MONOMORPHIC, \ - Code::kNoExtraICState) \ - V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC, \ - Code::kNoExtraICState) \ - V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC, \ - Code::kNoExtraICState) \ - V(LoadIC_StringWrapperLength, LOAD_IC, MONOMORPHIC, \ - Code::kNoExtraICState) \ - V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC, \ - Code::kNoExtraICState) \ - V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC, \ - Code::kNoExtraICState) \ - \ - V(KeyedLoadIC_Initialize, KEYED_LOAD_IC, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC, \ - Code::kNoExtraICState) \ - V(KeyedLoadIC_Generic, KEYED_LOAD_IC, MEGAMORPHIC, \ - Code::kNoExtraICState) \ - V(KeyedLoadIC_String, KEYED_LOAD_IC, MEGAMORPHIC, \ - Code::kNoExtraICState) \ - V(KeyedLoadIC_IndexedInterceptor, KEYED_LOAD_IC, MEGAMORPHIC, \ - Code::kNoExtraICState) \ - \ - V(StoreIC_Initialize, STORE_IC, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(StoreIC_ArrayLength, STORE_IC, MONOMORPHIC, \ - Code::kNoExtraICState) \ - V(StoreIC_Normal, STORE_IC, MONOMORPHIC, \ - Code::kNoExtraICState) \ - V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC, \ - Code::kNoExtraICState) \ - V(StoreIC_GlobalProxy, STORE_IC, MEGAMORPHIC, \ - Code::kNoExtraICState) \ - V(StoreIC_Initialize_Strict, STORE_IC, UNINITIALIZED, \ - StoreIC::kStoreICStrict) \ - V(StoreIC_ArrayLength_Strict, STORE_IC, MONOMORPHIC, \ - StoreIC::kStoreICStrict) \ - V(StoreIC_Normal_Strict, STORE_IC, MONOMORPHIC, \ - StoreIC::kStoreICStrict) \ - V(StoreIC_Megamorphic_Strict, STORE_IC, MEGAMORPHIC, \ - StoreIC::kStoreICStrict) \ - V(StoreIC_GlobalProxy_Strict, STORE_IC, MEGAMORPHIC, \ - StoreIC::kStoreICStrict) \ - \ - V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(KeyedStoreIC_Generic, KEYED_STORE_IC, MEGAMORPHIC, \ - Code::kNoExtraICState) \ - \ - /* Uses KeyedLoadIC_Initialize; must be after in list. */ \ - V(FunctionCall, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(FunctionApply, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - \ - V(ArrayCode, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - V(ArrayConstructCode, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - \ - V(StringConstructCode, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) \ - \ - V(OnStackReplacement, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) +#define BUILTIN_LIST_A(V) \ + V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(JSConstructCall, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(JSConstructStubCountdown, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(JSConstructStubApi, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(JSEntryTrampoline, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(LazyCompile, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(LazyRecompile, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(NotifyDeoptimized, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(NotifyLazyDeoptimized, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(NotifyOSR, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + \ + V(LoadIC_Miss, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(StoreIC_Miss, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + \ + V(LoadIC_Initialize, LOAD_IC, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC, \ + Code::kNoExtraICState) \ + V(LoadIC_Normal, LOAD_IC, MONOMORPHIC, \ + Code::kNoExtraICState) \ + V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC, \ + Code::kNoExtraICState) \ + V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC, \ + Code::kNoExtraICState) \ + V(LoadIC_StringWrapperLength, LOAD_IC, MONOMORPHIC, \ + Code::kNoExtraICState) \ + V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC, \ + Code::kNoExtraICState) \ + V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC, \ + Code::kNoExtraICState) \ + \ + V(KeyedLoadIC_Initialize, KEYED_LOAD_IC, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC, \ + Code::kNoExtraICState) \ + V(KeyedLoadIC_Generic, KEYED_LOAD_IC, MEGAMORPHIC, \ + Code::kNoExtraICState) \ + V(KeyedLoadIC_String, KEYED_LOAD_IC, MEGAMORPHIC, \ + Code::kNoExtraICState) \ + V(KeyedLoadIC_IndexedInterceptor, KEYED_LOAD_IC, MEGAMORPHIC, \ + Code::kNoExtraICState) \ + \ + V(StoreIC_Initialize, STORE_IC, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(StoreIC_ArrayLength, STORE_IC, MONOMORPHIC, \ + Code::kNoExtraICState) \ + V(StoreIC_Normal, STORE_IC, MONOMORPHIC, \ + Code::kNoExtraICState) \ + V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC, \ + Code::kNoExtraICState) \ + V(StoreIC_GlobalProxy, STORE_IC, MEGAMORPHIC, \ + Code::kNoExtraICState) \ + V(StoreIC_Initialize_Strict, STORE_IC, UNINITIALIZED, \ + kStrictMode) \ + V(StoreIC_ArrayLength_Strict, STORE_IC, MONOMORPHIC, \ + kStrictMode) \ + V(StoreIC_Normal_Strict, STORE_IC, MONOMORPHIC, \ + kStrictMode) \ + V(StoreIC_Megamorphic_Strict, STORE_IC, MEGAMORPHIC, \ + kStrictMode) \ + V(StoreIC_GlobalProxy_Strict, STORE_IC, MEGAMORPHIC, \ + kStrictMode) \ + \ + V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(KeyedStoreIC_Generic, KEYED_STORE_IC, MEGAMORPHIC, \ + Code::kNoExtraICState) \ + \ + V(KeyedStoreIC_Initialize_Strict, KEYED_STORE_IC, UNINITIALIZED, \ + kStrictMode) \ + V(KeyedStoreIC_Generic_Strict, KEYED_STORE_IC, MEGAMORPHIC, \ + kStrictMode) \ + \ + /* Uses KeyedLoadIC_Initialize; must be after in list. */ \ + V(FunctionCall, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(FunctionApply, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + \ + V(ArrayCode, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + V(ArrayConstructCode, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + \ + V(StringConstructCode, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) \ + \ + V(OnStackReplacement, BUILTIN, UNINITIALIZED, \ + Code::kNoExtraICState) #ifdef ENABLE_DEBUGGER_SUPPORT diff --git a/src/debug.cc b/src/debug.cc index d8201a1..c473941 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -836,7 +836,8 @@ bool Debug::Load() { Handle key = Factory::LookupAsciiSymbol("builtins"); Handle global = Handle(context->global()); RETURN_IF_EMPTY_HANDLE_VALUE( - SetProperty(global, key, Handle(global->builtins()), NONE), + SetProperty(global, key, Handle(global->builtins()), + NONE, kNonStrictMode), false); // Compile the JavaScript for the debugger in the debugger context. diff --git a/src/handles.cc b/src/handles.cc index 8b2f95b..05c81bb 100644 --- a/src/handles.cc +++ b/src/handles.cc @@ -242,17 +242,21 @@ Handle SetPrototype(Handle function, Handle SetProperty(Handle object, Handle key, Handle value, - PropertyAttributes attributes) { - CALL_HEAP_FUNCTION(object->SetProperty(*key, *value, attributes), Object); + PropertyAttributes attributes, + StrictModeFlag strict) { + CALL_HEAP_FUNCTION(object->SetProperty(*key, *value, attributes, strict), + Object); } Handle SetProperty(Handle object, Handle key, Handle value, - PropertyAttributes attributes) { + PropertyAttributes attributes, + StrictModeFlag strict) { CALL_HEAP_FUNCTION( - Runtime::SetObjectProperty(object, key, value, attributes), Object); + Runtime::SetObjectProperty(object, key, value, attributes, strict), + Object); } @@ -304,10 +308,12 @@ void SetLocalPropertyNoThrow(Handle object, Handle SetPropertyWithInterceptor(Handle object, Handle key, Handle value, - PropertyAttributes attributes) { + PropertyAttributes attributes, + StrictModeFlag strict) { CALL_HEAP_FUNCTION(object->SetPropertyWithInterceptor(*key, *value, - attributes), + attributes, + strict), Object); } diff --git a/src/handles.h b/src/handles.h index 8f1664b..c4e9925 100644 --- a/src/handles.h +++ b/src/handles.h @@ -246,12 +246,14 @@ Handle FlattenGetString(Handle str); Handle SetProperty(Handle object, Handle key, Handle value, - PropertyAttributes attributes); + PropertyAttributes attributes, + StrictModeFlag strict); Handle SetProperty(Handle object, Handle key, Handle value, - PropertyAttributes attributes); + PropertyAttributes attributes, + StrictModeFlag strict); Handle ForceSetProperty(Handle object, Handle key, @@ -282,7 +284,8 @@ void SetLocalPropertyNoThrow(Handle object, Handle SetPropertyWithInterceptor(Handle object, Handle key, Handle value, - PropertyAttributes attributes); + PropertyAttributes attributes, + StrictModeFlag strict); Handle SetElement(Handle object, uint32_t index, diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index 770ec0b..1318622 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -3526,7 +3526,8 @@ void CodeGenerator::DeclareGlobals(Handle pairs) { frame_->EmitPush(esi); // The context is the first argument. frame_->EmitPush(Immediate(pairs)); frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); - Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); + frame_->EmitPush(Immediate(Smi::FromInt(strict_mode_flag()))); + Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 4); // Return value is ignored. } @@ -5259,7 +5260,8 @@ void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { // by initialization. value = frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); } else { - value = frame_->CallRuntime(Runtime::kStoreContextSlot, 3); + frame_->Push(Smi::FromInt(strict_mode_flag())); + value = frame_->CallRuntime(Runtime::kStoreContextSlot, 4); } // Storing a variable must keep the (new) value on the expression // stack. This is necessary for compiling chained assignment @@ -5618,8 +5620,9 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { Load(property->key()); Load(property->value()); if (property->emit_store()) { + frame_->Push(Smi::FromInt(NONE)); // PropertyAttributes // Ignore the result. - Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3); + Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 4); } else { frame_->Drop(3); } @@ -9468,11 +9471,13 @@ class DeferredReferenceSetKeyedValue: public DeferredCode { DeferredReferenceSetKeyedValue(Register value, Register key, Register receiver, - Register scratch) + Register scratch, + StrictModeFlag strict_mode) : value_(value), key_(key), receiver_(receiver), - scratch_(scratch) { + scratch_(scratch), + strict_mode_(strict_mode) { set_comment("[ DeferredReferenceSetKeyedValue"); } @@ -9486,6 +9491,7 @@ class DeferredReferenceSetKeyedValue: public DeferredCode { Register receiver_; Register scratch_; Label patch_site_; + StrictModeFlag strict_mode_; }; @@ -9544,7 +9550,9 @@ void DeferredReferenceSetKeyedValue::Generate() { } // Call the IC stub. - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + (strict_mode_ == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); __ call(ic, RelocInfo::CODE_TARGET); // The delta from the start of the map-compare instruction to the // test instruction. We use masm_-> directly here instead of the @@ -9906,7 +9914,8 @@ Result CodeGenerator::EmitKeyedStore(StaticType* key_type) { new DeferredReferenceSetKeyedValue(result.reg(), key.reg(), receiver.reg(), - tmp.reg()); + tmp.reg(), + strict_mode_flag()); // Check that the receiver is not a smi. __ test(receiver.reg(), Immediate(kSmiTagMask)); @@ -9961,7 +9970,7 @@ Result CodeGenerator::EmitKeyedStore(StaticType* key_type) { deferred->BindExit(); } else { - result = frame()->CallKeyedStoreIC(); + result = frame()->CallKeyedStoreIC(strict_mode_flag()); // Make sure that we do not have a test instruction after the // call. A test instruction after the call is used to // indicate that we have generated an inline version of the diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 4255347..566b9a7 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -741,7 +741,9 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, prop->key()->AsLiteral()->handle()->IsSmi()); __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin(is_strict() + ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); } } @@ -758,7 +760,8 @@ void FullCodeGenerator::DeclareGlobals(Handle pairs) { __ push(esi); // The context is the first argument. __ push(Immediate(pairs)); __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); - __ CallRuntime(Runtime::kDeclareGlobals, 3); + __ push(Immediate(Smi::FromInt(strict_mode_flag()))); + __ CallRuntime(Runtime::kDeclareGlobals, 4); // Return value is ignored. } @@ -1380,7 +1383,9 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForAccumulatorValue(value); __ mov(ecx, Immediate(key->handle())); __ mov(edx, Operand(esp, 0)); - Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); PrepareForBailoutForId(key->id(), NO_REGISTERS); } else { @@ -1394,7 +1399,8 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForStackValue(key); VisitForStackValue(value); if (property->emit_store()) { - __ CallRuntime(Runtime::kSetProperty, 3); + __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes + __ CallRuntime(Runtime::kSetProperty, 4); } else { __ Drop(3); } @@ -1985,7 +1991,9 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { __ mov(edx, eax); __ pop(eax); // Restore value. __ mov(ecx, prop->key()->AsLiteral()->handle()); - Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); break; } @@ -2006,7 +2014,9 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { __ pop(edx); } __ pop(eax); // Restore value. - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); break; } @@ -2101,7 +2111,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, __ push(eax); // Value. __ push(esi); // Context. __ push(Immediate(var->name())); - __ CallRuntime(Runtime::kStoreContextSlot, 3); + __ push(Immediate(Smi::FromInt(strict_mode_flag()))); + __ CallRuntime(Runtime::kStoreContextSlot, 4); break; } } @@ -2132,7 +2143,9 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { } else { __ pop(edx); } - Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); // If the assignment ends an initialization block, revert to fast case. @@ -2170,7 +2183,9 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { } // Record source code position before IC call. SetSourcePosition(expr->position()); - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); // If the assignment ends an initialization block, revert to fast case. @@ -4025,7 +4040,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { case NAMED_PROPERTY: { __ mov(ecx, prop->key()->AsLiteral()->handle()); __ pop(edx); - Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { @@ -4040,7 +4057,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { case KEYED_PROPERTY: { __ pop(ecx); __ pop(edx); - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc index 73cd60d..6b9e749 100644 --- a/src/ia32/ic-ia32.cc +++ b/src/ia32/ic-ia32.cc @@ -761,7 +761,8 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { } -void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { +void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, + StrictModeFlag strict_mode) { // ----------- S t a t e ------------- // -- eax : value // -- ecx : key @@ -801,7 +802,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { // Slow case: call runtime. __ bind(&slow); - GenerateRuntimeSetProperty(masm); + GenerateRuntimeSetProperty(masm, strict_mode); // Check whether the elements is a pixel array. __ bind(&check_pixel_array); @@ -1488,7 +1489,7 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { void StoreIC::GenerateMegamorphic(MacroAssembler* masm, - Code::ExtraICState extra_ic_state) { + StrictModeFlag strict_mode) { // ----------- S t a t e ------------- // -- eax : value // -- ecx : name @@ -1499,7 +1500,7 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm, Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, NOT_IN_LOOP, MONOMORPHIC, - extra_ic_state); + strict_mode); StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg); // Cache miss: Jump to runtime. @@ -1617,7 +1618,8 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) { } -void StoreIC::GenerateGlobalProxy(MacroAssembler* masm) { +void StoreIC::GenerateGlobalProxy(MacroAssembler* masm, + StrictModeFlag strict_mode) { // ----------- S t a t e ------------- // -- eax : value // -- ecx : name @@ -1628,14 +1630,17 @@ void StoreIC::GenerateGlobalProxy(MacroAssembler* masm) { __ push(edx); __ push(ecx); __ push(eax); - __ push(ebx); + __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes + __ push(Immediate(Smi::FromInt(strict_mode))); + __ push(ebx); // return address // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kSetProperty, 3, 1); + __ TailCallRuntime(Runtime::kSetProperty, 5, 1); } -void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) { +void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, + StrictModeFlag strict_mode) { // ----------- S t a t e ------------- // -- eax : value // -- ecx : key @@ -1647,10 +1652,12 @@ void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) { __ push(edx); __ push(ecx); __ push(eax); - __ push(ebx); + __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes + __ push(Immediate(Smi::FromInt(strict_mode))); // Strict mode. + __ push(ebx); // return address // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kSetProperty, 3, 1); + __ TailCallRuntime(Runtime::kSetProperty, 5, 1); } diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index c7424a5..8fab7ce 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -2786,7 +2786,9 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { ASSERT(ToRegister(instr->value()).is(eax)); __ mov(ecx, instr->name()); - Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + info_->is_strict() ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -2854,7 +2856,9 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { ASSERT(ToRegister(instr->key()).is(ecx)); ASSERT(ToRegister(instr->value()).is(eax)); - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + info_->is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); CallCode(ic, RelocInfo::CODE_TARGET, instr); } diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index 51cc46a..633097a 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -2552,12 +2552,13 @@ MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, __ push(edx); // receiver __ push(ecx); // name __ push(eax); // value + __ push(Immediate(Smi::FromInt(strict_mode_))); __ push(ebx); // restore return address // Do tail-call to the runtime system. ExternalReference store_ic_property = ExternalReference(IC_Utility(IC::kStoreInterceptorProperty)); - __ TailCallExternalReference(store_ic_property, 3, 1); + __ TailCallExternalReference(store_ic_property, 4, 1); // Handle store cache miss. __ bind(&miss); @@ -3712,10 +3713,13 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( __ push(edx); __ push(ecx); __ push(eax); - __ push(ebx); + __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes + __ push(Immediate(Smi::FromInt( + Code::ExtractExtraICStateFromFlags(flags) & kStrictMode))); + __ push(ebx); // return address // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kSetProperty, 3, 1); + __ TailCallRuntime(Runtime::kSetProperty, 5, 1); return GetCode(flags); } diff --git a/src/ia32/virtual-frame-ia32.cc b/src/ia32/virtual-frame-ia32.cc index 515a9fe..5e2cbee 100644 --- a/src/ia32/virtual-frame-ia32.cc +++ b/src/ia32/virtual-frame-ia32.cc @@ -1038,9 +1038,9 @@ Result VirtualFrame::CallStoreIC(Handle name, StrictModeFlag strict_mode) { // Value and (if not contextual) receiver are on top of the frame. // The IC expects name in ecx, value in eax, and receiver in edx. - Handle ic(Builtins::builtin(strict_mode == kStrictMode - ? Builtins::StoreIC_Initialize_Strict - : Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + (strict_mode == kStrictMode) ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); Result value = Pop(); RelocInfo::Mode mode; @@ -1061,7 +1061,7 @@ Result VirtualFrame::CallStoreIC(Handle name, } -Result VirtualFrame::CallKeyedStoreIC() { +Result VirtualFrame::CallKeyedStoreIC(StrictModeFlag strict_mode) { // Value, key, and receiver are on the top of the frame. The IC // expects value in eax, key in ecx, and receiver in edx. Result value = Pop(); @@ -1105,7 +1105,9 @@ Result VirtualFrame::CallKeyedStoreIC() { receiver.Unuse(); } - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + (strict_mode == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); return RawCallCodeObject(ic, RelocInfo::CODE_TARGET); } diff --git a/src/ia32/virtual-frame-ia32.h b/src/ia32/virtual-frame-ia32.h index 93362b4..f5d0e8d 100644 --- a/src/ia32/virtual-frame-ia32.h +++ b/src/ia32/virtual-frame-ia32.h @@ -370,7 +370,7 @@ class VirtualFrame: public ZoneObject { // Call keyed store IC. Value, key, and receiver are found on top // of the frame. All three are dropped. - Result CallKeyedStoreIC(); + Result CallKeyedStoreIC(StrictModeFlag strict_mode); // Call call IC. Function name, arguments, and receiver are found on top // of the frame and dropped by the call. The argument count does not diff --git a/src/ic-inl.h b/src/ic-inl.h index 8fbc184..9d358ed 100644 --- a/src/ic-inl.h +++ b/src/ic-inl.h @@ -76,6 +76,15 @@ Code* IC::GetTargetAtAddress(Address address) { void IC::SetTargetAtAddress(Address address, Code* target) { ASSERT(target->is_inline_cache_stub() || target->is_compare_ic_stub()); +#ifdef DEBUG + // STORE_IC and KEYED_STORE_IC use Code::extra_ic_state() to mark + // ICs as strict mode. The strict-ness of the IC must be preserved. + Code* old_target = GetTargetAtAddress(address); + if (old_target->kind() == Code::STORE_IC || + old_target->kind() == Code::KEYED_STORE_IC) { + ASSERT(old_target->extra_ic_state() == target->extra_ic_state()); + } +#endif Assembler::set_target_address_at(address, target->instruction_start()); } diff --git a/src/ic.cc b/src/ic.cc index 4f75ade..2d666d6 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -343,7 +343,7 @@ void StoreIC::Clear(Address address, Code* target) { if (target->ic_state() == UNINITIALIZED) return; ClearInlinedVersion(address); SetTargetAtAddress(address, - target->extra_ic_state() == kStoreICStrict + (target->extra_ic_state() == kStrictMode) ? initialize_stub_strict() : initialize_stub()); } @@ -366,7 +366,10 @@ void KeyedStoreIC::RestoreInlinedVersion(Address address) { void KeyedStoreIC::Clear(Address address, Code* target) { if (target->ic_state() == UNINITIALIZED) return; - SetTargetAtAddress(address, initialize_stub()); + SetTargetAtAddress(address, + (target->extra_ic_state() == kStrictMode) + ? initialize_stub_strict() + : initialize_stub()); } @@ -1227,7 +1230,8 @@ MaybeObject* KeyedLoadIC::Load(State state, if (receiver->HasExternalArrayElements()) { MaybeObject* probe = StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver, - false); + false, + kNonStrictMode); stub = probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); } else if (receiver->HasIndexedInterceptor()) { @@ -1383,7 +1387,7 @@ static bool LookupForWrite(JSObject* object, MaybeObject* StoreIC::Store(State state, - Code::ExtraICState extra_ic_state, + StrictModeFlag strict_mode, Handle object, Handle name, Handle value) { @@ -1413,11 +1417,11 @@ MaybeObject* StoreIC::Store(State state, #ifdef DEBUG if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); #endif - Builtins::Name target = (extra_ic_state == kStoreICStrict) + Builtins::Name target = (strict_mode == kStrictMode) ? Builtins::StoreIC_ArrayLength_Strict : Builtins::StoreIC_ArrayLength; set_target(Builtins::builtin(target)); - return receiver->SetProperty(*name, *value, NONE); + return receiver->SetProperty(*name, *value, NONE, strict_mode); } // Lookup the property locally in the receiver. @@ -1441,13 +1445,15 @@ MaybeObject* StoreIC::Store(State state, // Index is an offset from the end of the object. int offset = map->instance_size() + (index * kPointerSize); if (PatchInlinedStore(address(), map, offset)) { - set_target(megamorphic_stub()); + set_target((strict_mode == kStrictMode) + ? megamorphic_stub_strict() + : megamorphic_stub()); #ifdef DEBUG if (FLAG_trace_ic) { PrintF("[StoreIC : inline patch %s]\n", *name->ToCString()); } #endif - return receiver->SetProperty(*name, *value, NONE); + return receiver->SetProperty(*name, *value, NONE, strict_mode); #ifdef DEBUG } else { @@ -1474,11 +1480,16 @@ MaybeObject* StoreIC::Store(State state, // If no inlined store ic was patched, generate a stub for this // store. - UpdateCaches(&lookup, state, extra_ic_state, receiver, name, value); + UpdateCaches(&lookup, state, strict_mode, receiver, name, value); } else { - // Strict mode doesn't allow setting non-existent global property. - if (extra_ic_state == kStoreICStrict && IsContextual(object)) { - return ReferenceError("not_defined", name); + // Strict mode doesn't allow setting non-existent global property + // or an assignment to a read only property. + if (strict_mode == kStrictMode) { + if (lookup.IsFound() && lookup.IsReadOnly()) { + return TypeError("strict_read_only_property", object, name); + } else if (IsContextual(object)) { + return ReferenceError("not_defined", name); + } } } } @@ -1486,7 +1497,7 @@ MaybeObject* StoreIC::Store(State state, if (receiver->IsJSGlobalProxy()) { // Generate a generic stub that goes to the runtime when we see a global // proxy as receiver. - Code* stub = (extra_ic_state == kStoreICStrict) + Code* stub = (strict_mode == kStrictMode) ? global_proxy_stub_strict() : global_proxy_stub(); if (target() != stub) { @@ -1498,13 +1509,13 @@ MaybeObject* StoreIC::Store(State state, } // Set the property. - return receiver->SetProperty(*name, *value, NONE); + return receiver->SetProperty(*name, *value, NONE, strict_mode); } void StoreIC::UpdateCaches(LookupResult* lookup, State state, - Code::ExtraICState extra_ic_state, + StrictModeFlag strict_mode, Handle receiver, Handle name, Handle value) { @@ -1526,7 +1537,7 @@ void StoreIC::UpdateCaches(LookupResult* lookup, switch (type) { case FIELD: { maybe_code = StubCache::ComputeStoreField( - *name, *receiver, lookup->GetFieldIndex(), NULL, extra_ic_state); + *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode); break; } case MAP_TRANSITION: { @@ -1536,7 +1547,7 @@ void StoreIC::UpdateCaches(LookupResult* lookup, Handle transition(lookup->GetTransitionMap()); int index = transition->PropertyIndexFor(*name); maybe_code = StubCache::ComputeStoreField( - *name, *receiver, index, *transition, extra_ic_state); + *name, *receiver, index, *transition, strict_mode); break; } case NORMAL: { @@ -1548,10 +1559,10 @@ void StoreIC::UpdateCaches(LookupResult* lookup, JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); maybe_code = StubCache::ComputeStoreGlobal( - *name, *global, cell, extra_ic_state); + *name, *global, cell, strict_mode); } else { if (lookup->holder() != *receiver) return; - maybe_code = StubCache::ComputeStoreNormal(extra_ic_state); + maybe_code = StubCache::ComputeStoreNormal(strict_mode); } break; } @@ -1560,13 +1571,13 @@ void StoreIC::UpdateCaches(LookupResult* lookup, AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); if (v8::ToCData
(callback->setter()) == 0) return; maybe_code = StubCache::ComputeStoreCallback( - *name, *receiver, callback, extra_ic_state); + *name, *receiver, callback, strict_mode); break; } case INTERCEPTOR: { ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); maybe_code = StubCache::ComputeStoreInterceptor( - *name, *receiver, extra_ic_state); + *name, *receiver, strict_mode); break; } default: @@ -1583,7 +1594,7 @@ void StoreIC::UpdateCaches(LookupResult* lookup, } else if (state == MONOMORPHIC) { // Only move to megamorphic if the target changes. if (target() != Code::cast(code)) { - set_target(extra_ic_state == kStoreICStrict + set_target((strict_mode == kStrictMode) ? megamorphic_stub_strict() : megamorphic_stub()); } @@ -1599,6 +1610,7 @@ void StoreIC::UpdateCaches(LookupResult* lookup, MaybeObject* KeyedStoreIC::Store(State state, + StrictModeFlag strict_mode, Handle object, Handle key, Handle value) { @@ -1630,11 +1642,11 @@ MaybeObject* KeyedStoreIC::Store(State state, // Update inline cache and stub cache. if (FLAG_use_ic) { - UpdateCaches(&lookup, state, receiver, name, value); + UpdateCaches(&lookup, state, strict_mode, receiver, name, value); } // Set the property. - return receiver->SetProperty(*name, *value, NONE); + return receiver->SetProperty(*name, *value, NONE, strict_mode); } // Do not use ICs for objects that require access checks (including @@ -1643,23 +1655,25 @@ MaybeObject* KeyedStoreIC::Store(State state, ASSERT(!(use_ic && object->IsJSGlobalProxy())); if (use_ic) { - Code* stub = generic_stub(); + Code* stub = + (strict_mode == kStrictMode) ? generic_stub_strict() : generic_stub(); if (state == UNINITIALIZED) { if (object->IsJSObject()) { Handle receiver = Handle::cast(object); if (receiver->HasExternalArrayElements()) { MaybeObject* probe = - StubCache::ComputeKeyedLoadOrStoreExternalArray(*receiver, true); + StubCache::ComputeKeyedLoadOrStoreExternalArray( + *receiver, true, strict_mode); stub = probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); } else if (receiver->HasPixelElements()) { MaybeObject* probe = - StubCache::ComputeKeyedStorePixelArray(*receiver); + StubCache::ComputeKeyedStorePixelArray(*receiver, strict_mode); stub = probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); } else if (key->IsSmi() && receiver->map()->has_fast_elements()) { MaybeObject* probe = - StubCache::ComputeKeyedStoreSpecialized(*receiver); + StubCache::ComputeKeyedStoreSpecialized(*receiver, strict_mode); stub = probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); } @@ -1669,12 +1683,13 @@ MaybeObject* KeyedStoreIC::Store(State state, } // Set the property. - return Runtime::SetObjectProperty(object, key, value, NONE); + return Runtime::SetObjectProperty(object, key, value, NONE, strict_mode); } void KeyedStoreIC::UpdateCaches(LookupResult* lookup, State state, + StrictModeFlag strict_mode, Handle receiver, Handle name, Handle value) { @@ -1701,8 +1716,8 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup, switch (type) { case FIELD: { - maybe_code = StubCache::ComputeKeyedStoreField(*name, *receiver, - lookup->GetFieldIndex()); + maybe_code = StubCache::ComputeKeyedStoreField( + *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode); break; } case MAP_TRANSITION: { @@ -1711,8 +1726,8 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup, ASSERT(type == MAP_TRANSITION); Handle transition(lookup->GetTransitionMap()); int index = transition->PropertyIndexFor(*name); - maybe_code = StubCache::ComputeKeyedStoreField(*name, *receiver, - index, *transition); + maybe_code = StubCache::ComputeKeyedStoreField( + *name, *receiver, index, *transition, strict_mode); break; } // fall through. @@ -1720,7 +1735,9 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup, default: { // Always rewrite to the generic case so that we do not // repeatedly try to rewrite. - maybe_code = generic_stub(); + maybe_code = (strict_mode == kStrictMode) + ? generic_stub_strict() + : generic_stub(); break; } } @@ -1735,7 +1752,9 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup, if (state == UNINITIALIZED || state == PREMONOMORPHIC) { set_target(Code::cast(code)); } else if (state == MONOMORPHIC) { - set_target(megamorphic_stub()); + set_target((strict_mode == kStrictMode) + ? megamorphic_stub_strict() + : megamorphic_stub()); } #ifdef DEBUG @@ -1836,8 +1855,11 @@ MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) { StoreIC ic; IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); - return ic.Store(state, extra_ic_state, args.at(0), - args.at(1), args.at(2)); + return ic.Store(state, + static_cast(extra_ic_state & kStrictMode), + args.at(0), + args.at(1), + args.at(2)); } @@ -1901,7 +1923,11 @@ MUST_USE_RESULT MaybeObject* KeyedStoreIC_Miss(Arguments args) { ASSERT(args.length() == 3); KeyedStoreIC ic; IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); - return ic.Store(state, args.at(0), args.at(1), + Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); + return ic.Store(state, + static_cast(extra_ic_state & kStrictMode), + args.at(0), + args.at(1), args.at(2)); } diff --git a/src/ic.h b/src/ic.h index 96838c7..e12cbaf 100644 --- a/src/ic.h +++ b/src/ic.h @@ -398,16 +398,10 @@ class KeyedLoadIC: public IC { class StoreIC: public IC { public: - - enum StoreICStrictMode { - kStoreICNonStrict = kNonStrictMode, - kStoreICStrict = kStrictMode - }; - StoreIC() : IC(NO_EXTRA_FRAME) { ASSERT(target()->is_store_stub()); } MUST_USE_RESULT MaybeObject* Store(State state, - Code::ExtraICState extra_ic_state, + StrictModeFlag strict_mode, Handle object, Handle name, Handle value); @@ -416,10 +410,11 @@ class StoreIC: public IC { static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } static void GenerateMiss(MacroAssembler* masm); static void GenerateMegamorphic(MacroAssembler* masm, - Code::ExtraICState extra_ic_state); + StrictModeFlag strict_mode); static void GenerateArrayLength(MacroAssembler* masm); static void GenerateNormal(MacroAssembler* masm); - static void GenerateGlobalProxy(MacroAssembler* masm); + static void GenerateGlobalProxy(MacroAssembler* masm, + StrictModeFlag strict_mode); // Clear the use of an inlined version. static void ClearInlinedVersion(Address address); @@ -433,11 +428,18 @@ class StoreIC: public IC { // lookup result. void UpdateCaches(LookupResult* lookup, State state, - Code::ExtraICState extra_ic_state, + StrictModeFlag strict_mode, Handle receiver, Handle name, Handle value); + void set_target(Code* code) { + // Strict mode must be preserved across IC patching. + ASSERT((code->extra_ic_state() & kStrictMode) == + (target()->extra_ic_state() & kStrictMode)); + IC::set_target(code); + } + // Stub accessors. static Code* megamorphic_stub() { return Builtins::builtin(Builtins::StoreIC_Megamorphic); @@ -473,6 +475,7 @@ class KeyedStoreIC: public IC { KeyedStoreIC() : IC(NO_EXTRA_FRAME) { } MUST_USE_RESULT MaybeObject* Store(State state, + StrictModeFlag strict_mode, Handle object, Handle name, Handle value); @@ -480,8 +483,9 @@ class KeyedStoreIC: public IC { // Code generators for stub routines. Only called once at startup. static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } static void GenerateMiss(MacroAssembler* masm); - static void GenerateRuntimeSetProperty(MacroAssembler* masm); - static void GenerateGeneric(MacroAssembler* masm); + static void GenerateRuntimeSetProperty(MacroAssembler* masm, + StrictModeFlag strict_mode); + static void GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode); // Clear the inlined version so the IC is always hit. static void ClearInlinedVersion(Address address); @@ -493,20 +497,37 @@ class KeyedStoreIC: public IC { // Update the inline cache. void UpdateCaches(LookupResult* lookup, State state, + StrictModeFlag strict_mode, Handle receiver, Handle name, Handle value); + void set_target(Code* code) { + // Strict mode must be preserved across IC patching. + ASSERT((code->extra_ic_state() & kStrictMode) == + (target()->extra_ic_state() & kStrictMode)); + IC::set_target(code); + } + // Stub accessors. static Code* initialize_stub() { return Builtins::builtin(Builtins::KeyedStoreIC_Initialize); } + static Code* initialize_stub_strict() { + return Builtins::builtin(Builtins::KeyedStoreIC_Initialize_Strict); + } static Code* megamorphic_stub() { return Builtins::builtin(Builtins::KeyedStoreIC_Generic); } + static Code* megamorphic_stub_strict() { + return Builtins::builtin(Builtins::KeyedStoreIC_Generic_Strict); + } static Code* generic_stub() { return Builtins::builtin(Builtins::KeyedStoreIC_Generic); } + static Code* generic_stub_strict() { + return Builtins::builtin(Builtins::KeyedStoreIC_Generic_Strict); + } static void Clear(Address address, Code* target); diff --git a/src/messages.js b/src/messages.js index db33753..2c94912 100644 --- a/src/messages.js +++ b/src/messages.js @@ -228,6 +228,8 @@ function FormatMessage(message) { strict_delete_property: ["Cannot delete property '", "%0", "' of ", "%1"], strict_const: ["Use of const in strict mode."], strict_function: ["In strict mode code, functions can only be declared at top level or immediately within another function." ], + strict_read_only_property: ["Cannot assign to read only property '", "%0", "' of ", "%1"], + strict_cannot_assign: ["Cannot assign to read only '", "%0", "' in strict mode"], }; } var message_type = %MessageGetType(message); diff --git a/src/objects-inl.h b/src/objects-inl.h index f955d33..dedb199 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -2619,7 +2619,8 @@ Code::Flags Code::ComputeFlags(Kind kind, ASSERT(extra_ic_state == kNoExtraICState || (kind == CALL_IC && (ic_state == MONOMORPHIC || ic_state == MONOMORPHIC_PROTOTYPE_FAILURE)) || - (kind == STORE_IC)); + (kind == STORE_IC) || + (kind == KEYED_STORE_IC)); // Compute the bit mask. int bits = kind << kFlagsKindShift; if (in_loop) bits |= kFlagsICInLoopMask; @@ -3741,7 +3742,8 @@ MaybeObject* JSObject::SetHiddenPropertiesObject(Object* hidden_obj) { ASSERT(!IsJSGlobalProxy()); return SetPropertyPostInterceptor(Heap::hidden_symbol(), hidden_obj, - DONT_ENUM); + DONT_ENUM, + kNonStrictMode); } diff --git a/src/objects.cc b/src/objects.cc index 0b1d72a..0b7f60a 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -1444,14 +1444,15 @@ MaybeObject* JSObject::AddProperty(String* name, MaybeObject* JSObject::SetPropertyPostInterceptor( String* name, Object* value, - PropertyAttributes attributes) { + PropertyAttributes attributes, + StrictModeFlag strict) { // Check local property, ignore interceptor. LookupResult result; LocalLookupRealNamedProperty(name, &result); if (result.IsFound()) { // An existing property, a map transition or a null descriptor was // found. Use set property to handle all these cases. - return SetProperty(&result, name, value, attributes); + return SetProperty(&result, name, value, attributes, strict); } // Add a new real property. return AddProperty(name, value, attributes); @@ -1576,7 +1577,8 @@ MaybeObject* JSObject::ConvertDescriptorToField(String* name, MaybeObject* JSObject::SetPropertyWithInterceptor( String* name, Object* value, - PropertyAttributes attributes) { + PropertyAttributes attributes, + StrictModeFlag strict) { HandleScope scope; Handle this_handle(this); Handle name_handle(name); @@ -1605,7 +1607,8 @@ MaybeObject* JSObject::SetPropertyWithInterceptor( MaybeObject* raw_result = this_handle->SetPropertyPostInterceptor(*name_handle, *value_handle, - attributes); + attributes, + strict); RETURN_IF_SCHEDULED_EXCEPTION(); return raw_result; } @@ -1613,10 +1616,11 @@ MaybeObject* JSObject::SetPropertyWithInterceptor( MaybeObject* JSObject::SetProperty(String* name, Object* value, - PropertyAttributes attributes) { + PropertyAttributes attributes, + StrictModeFlag strict) { LookupResult result; LocalLookup(name, &result); - return SetProperty(&result, name, value, attributes); + return SetProperty(&result, name, value, attributes, strict); } @@ -1896,7 +1900,8 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result, MaybeObject* JSObject::SetProperty(LookupResult* result, String* name, Object* value, - PropertyAttributes attributes) { + PropertyAttributes attributes, + StrictModeFlag strict) { // Make sure that the top context does not change when doing callbacks or // interceptor calls. AssertNoContextChange ncc; @@ -1923,7 +1928,8 @@ MaybeObject* JSObject::SetProperty(LookupResult* result, Object* proto = GetPrototype(); if (proto->IsNull()) return value; ASSERT(proto->IsJSGlobalObject()); - return JSObject::cast(proto)->SetProperty(result, name, value, attributes); + return JSObject::cast(proto)->SetProperty( + result, name, value, attributes, strict); } if (!result->IsProperty() && !IsJSContextExtensionObject()) { @@ -1942,7 +1948,19 @@ MaybeObject* JSObject::SetProperty(LookupResult* result, // Neither properties nor transitions found. return AddProperty(name, value, attributes); } - if (result->IsReadOnly() && result->IsProperty()) return value; + if (result->IsReadOnly() && result->IsProperty()) { + if (strict == kStrictMode) { + HandleScope scope; + Handle key(name); + Handle holder(this); + Handle args[2] = { key, holder }; + return Top::Throw(*Factory::NewTypeError("strict_read_only_property", + HandleVector(args, 2))); + + } else { + return value; + } + } // This is a real property that is not read-only, or it is a // transition or null descriptor and there are no setters in the prototypes. switch (result->type()) { @@ -1970,7 +1988,7 @@ MaybeObject* JSObject::SetProperty(LookupResult* result, value, result->holder()); case INTERCEPTOR: - return SetPropertyWithInterceptor(name, value, attributes); + return SetPropertyWithInterceptor(name, value, attributes, strict); case CONSTANT_TRANSITION: { // If the same constant function is being added we can simply // transition to the target map. @@ -6287,7 +6305,8 @@ void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) { } break; case STORE_IC: - if (extra == StoreIC::kStoreICStrict) { + case KEYED_STORE_IC: + if (extra == kStrictMode) { name = "STRICT"; } break; diff --git a/src/objects.h b/src/objects.h index fbfc5fd..de15a73 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1361,11 +1361,13 @@ class JSObject: public HeapObject { MUST_USE_RESULT MaybeObject* SetProperty(String* key, Object* value, - PropertyAttributes attributes); + PropertyAttributes attributes, + StrictModeFlag strict); MUST_USE_RESULT MaybeObject* SetProperty(LookupResult* result, String* key, Object* value, - PropertyAttributes attributes); + PropertyAttributes attributes, + StrictModeFlag strict); MUST_USE_RESULT MaybeObject* SetPropertyWithFailedAccessCheck( LookupResult* result, String* name, @@ -1380,11 +1382,13 @@ class JSObject: public HeapObject { MUST_USE_RESULT MaybeObject* SetPropertyWithInterceptor( String* name, Object* value, - PropertyAttributes attributes); + PropertyAttributes attributes, + StrictModeFlag strict); MUST_USE_RESULT MaybeObject* SetPropertyPostInterceptor( String* name, Object* value, - PropertyAttributes attributes); + PropertyAttributes attributes, + StrictModeFlag strict); MUST_USE_RESULT MaybeObject* SetLocalPropertyIgnoreAttributes( String* key, Object* value, diff --git a/src/parser.cc b/src/parser.cc index 9fedfc9..8560310 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -1661,34 +1661,49 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, if (top_scope_->is_global_scope()) { // Compute the arguments for the runtime call. - ZoneList* arguments = new ZoneList(2); - // Be careful not to assign a value to the global variable if - // we're in a with. The initialization value should not - // necessarily be stored in the global object in that case, - // which is why we need to generate a separate assignment node. + ZoneList* arguments = new ZoneList(3); arguments->Add(new Literal(name)); // we have at least 1 parameter - if (is_const || (value != NULL && !inside_with())) { - arguments->Add(value); - value = NULL; // zap the value to avoid the unnecessary assignment - } - // Construct the call to Runtime::DeclareGlobal{Variable,Const}Locally - // and add it to the initialization statement block. Note that - // this function does different things depending on if we have - // 1 or 2 parameters. CallRuntime* initialize; + if (is_const) { + arguments->Add(value); + value = NULL; // zap the value to avoid the unnecessary assignment + + // Construct the call to Runtime_InitializeConstGlobal + // and add it to the initialization statement block. + // Note that the function does different things depending on + // the number of arguments (1 or 2). initialize = - new CallRuntime( - Factory::InitializeConstGlobal_symbol(), - Runtime::FunctionForId(Runtime::kInitializeConstGlobal), - arguments); + new CallRuntime( + Factory::InitializeConstGlobal_symbol(), + Runtime::FunctionForId(Runtime::kInitializeConstGlobal), + arguments); } else { + // Add strict mode. + // We may want to pass singleton to avoid Literal allocations. + arguments->Add(NewNumberLiteral( + temp_scope_->StrictMode() ? kStrictMode : kNonStrictMode)); + + // Be careful not to assign a value to the global variable if + // we're in a with. The initialization value should not + // necessarily be stored in the global object in that case, + // which is why we need to generate a separate assignment node. + if (value != NULL && !inside_with()) { + arguments->Add(value); + value = NULL; // zap the value to avoid the unnecessary assignment + } + + // Construct the call to Runtime_InitializeVarGlobal + // and add it to the initialization statement block. + // Note that the function does different things depending on + // the number of arguments (2 or 3). initialize = - new CallRuntime( - Factory::InitializeVarGlobal_symbol(), - Runtime::FunctionForId(Runtime::kInitializeVarGlobal), - arguments); + new CallRuntime( + Factory::InitializeVarGlobal_symbol(), + Runtime::FunctionForId(Runtime::kInitializeVarGlobal), + arguments); } + block->AddStatement(new ExpressionStatement(initialize)); } diff --git a/src/runtime.cc b/src/runtime.cc index dce2e15..6f5807d 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -160,7 +160,8 @@ MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) { if (!maybe_result->ToObject(&result)) return maybe_result; } { MaybeObject* maybe_result = - copy->SetProperty(key_string, result, NONE); + // Creating object copy for literals. No strict mode needed. + copy->SetProperty(key_string, result, NONE, kNonStrictMode); if (!maybe_result->ToObject(&result)) return maybe_result; } } @@ -546,7 +547,9 @@ static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) { // Assign the exception value to the catch variable and make sure // that the catch variable is DontDelete. { MaybeObject* maybe_value = - JSObject::cast(object)->SetProperty(key, value, DONT_DELETE); + // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4. + JSObject::cast(object)->SetProperty( + key, value, DONT_DELETE, kNonStrictMode); if (!maybe_value->ToObject(&value)) return maybe_value; } return object; @@ -994,12 +997,16 @@ static Failure* ThrowRedeclarationError(const char* type, Handle name) { static MaybeObject* Runtime_DeclareGlobals(Arguments args) { + ASSERT(args.length() == 4); HandleScope scope; Handle global = Handle(Top::context()->global()); Handle context = args.at(0); CONVERT_ARG_CHECKED(FixedArray, pairs, 1); bool is_eval = Smi::cast(args[2])->value() == 1; + StrictModeFlag strict_mode = + static_cast(Smi::cast(args[3])->value()); + ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode); // Compute the property attributes. According to ECMA-262, section // 13, page 71, the property must be read-only and @@ -1109,7 +1116,11 @@ static MaybeObject* Runtime_DeclareGlobals(Arguments args) { value, attributes)); } else { - RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, attributes)); + RETURN_IF_EMPTY_HANDLE(SetProperty(global, + name, + value, + attributes, + strict_mode)); } } @@ -1170,7 +1181,8 @@ static MaybeObject* Runtime_DeclareContextSlot(Arguments args) { // Slow case: The property is not in the FixedArray part of the context. Handle context_ext = Handle::cast(holder); RETURN_IF_EMPTY_HANDLE( - SetProperty(context_ext, name, initial_value, mode)); + SetProperty(context_ext, name, initial_value, + mode, kNonStrictMode)); } } @@ -1211,7 +1223,8 @@ static MaybeObject* Runtime_DeclareContextSlot(Arguments args) { return ThrowRedeclarationError("const", name); } } - RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, mode)); + RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, mode, + kNonStrictMode)); } return Heap::undefined_value(); @@ -1220,14 +1233,21 @@ static MaybeObject* Runtime_DeclareContextSlot(Arguments args) { static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) { NoHandleAllocation nha; + // args[0] == name + // args[1] == strict_mode + // args[2] == value (optional) // Determine if we need to assign to the variable if it already // exists (based on the number of arguments). - RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); - bool assign = args.length() == 2; + RUNTIME_ASSERT(args.length() == 2 || args.length() == 3); + bool assign = args.length() == 3; CONVERT_ARG_CHECKED(String, name, 0); GlobalObject* global = Top::context()->global(); + RUNTIME_ASSERT(args[1]->IsSmi()); + StrictModeFlag strict_mode = + static_cast(Smi::cast(args[1])->value()); + ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode); // According to ECMA-262, section 12.2, page 62, the property must // not be deletable. @@ -1283,8 +1303,9 @@ static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) { } // Assign the value (or undefined) to the property. - Object* value = (assign) ? args[1] : Heap::undefined_value(); - return real_holder->SetProperty(&lookup, *name, value, attributes); + Object* value = (assign) ? args[2] : Heap::undefined_value(); + return real_holder->SetProperty( + &lookup, *name, value, attributes, strict_mode); } Object* proto = real_holder->GetPrototype(); @@ -1298,7 +1319,9 @@ static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) { } global = Top::context()->global(); - if (assign) return global->SetProperty(*name, args[1], attributes); + if (assign) { + return global->SetProperty(*name, args[2], attributes, strict_mode); + } return Heap::undefined_value(); } @@ -1357,13 +1380,19 @@ static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) { // BUG 1213575: Handle the case where we have to set a read-only // property through an interceptor and only do it if it's // uninitialized, e.g. the hole. Nirk... - RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, attributes)); + // Passing non-strict mode because the property is writable. + RETURN_IF_EMPTY_HANDLE(SetProperty(global, + name, + value, + attributes, + kNonStrictMode)); return *value; } // Set the value, but only we're assigning the initial value to a // constant. For now, we determine this by checking if the // current value is the hole. + // Strict mode handling not needed (const disallowed in strict mode). PropertyType type = lookup.type(); if (type == FIELD) { FixedArray* properties = global->properties(); @@ -1439,7 +1468,9 @@ static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) { // context. if (attributes == ABSENT) { Handle global = Handle(Top::context()->global()); - RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, NONE)); + // Strict mode not needed (const disallowed in strict mode). + RETURN_IF_EMPTY_HANDLE( + SetProperty(global, name, value, NONE, kNonStrictMode)); return *value; } @@ -1476,8 +1507,9 @@ static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) { // The property was found in a different context extension object. // Set it if it is not a read-only property. if ((attributes & READ_ONLY) == 0) { + // Strict mode not needed (const disallowed in strict mode). RETURN_IF_EMPTY_HANDLE( - SetProperty(context_ext, name, value, attributes)); + SetProperty(context_ext, name, value, attributes, kNonStrictMode)); } } @@ -1643,7 +1675,7 @@ static Handle InstallBuiltin(Handle holder, code, false); optimized->shared()->DontAdaptArguments(); - SetProperty(holder, key, optimized, NONE); + SetProperty(holder, key, optimized, NONE, kStrictMode); return optimized; } @@ -3739,7 +3771,8 @@ static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) { MaybeObject* Runtime::SetObjectProperty(Handle object, Handle key, Handle value, - PropertyAttributes attr) { + PropertyAttributes attr, + StrictModeFlag strict) { HandleScope scope; if (object->IsUndefined() || object->IsNull()) { @@ -3769,6 +3802,7 @@ MaybeObject* Runtime::SetObjectProperty(Handle object, return *value; } + // TODO(1220): Implement SetElement strict mode. Handle result = SetElement(js_object, index, value); if (result.is_null()) return Failure::Exception(); return *value; @@ -3781,7 +3815,7 @@ MaybeObject* Runtime::SetObjectProperty(Handle object, } else { Handle key_string = Handle::cast(key); key_string->TryFlatten(); - result = SetProperty(js_object, key_string, value, attr); + result = SetProperty(js_object, key_string, value, attr, strict); } if (result.is_null()) return Failure::Exception(); return *value; @@ -3794,9 +3828,10 @@ MaybeObject* Runtime::SetObjectProperty(Handle object, Handle name = Handle::cast(converted); if (name->AsArrayIndex(&index)) { + // TODO(1220): Implement SetElement strict mode. return js_object->SetElement(index, *value); } else { - return js_object->SetProperty(*name, *value, attr); + return js_object->SetProperty(*name, *value, attr, strict); } } @@ -3888,23 +3923,27 @@ MaybeObject* Runtime::ForceDeleteObjectProperty(Handle js_object, static MaybeObject* Runtime_SetProperty(Arguments args) { NoHandleAllocation ha; - RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); + RUNTIME_ASSERT(args.length() == 4 || args.length() == 5); Handle object = args.at(0); Handle key = args.at(1); Handle value = args.at(2); - + CONVERT_SMI_CHECKED(unchecked_attributes, args[3]); + RUNTIME_ASSERT( + (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); // Compute attributes. - PropertyAttributes attributes = NONE; - if (args.length() == 4) { - CONVERT_CHECKED(Smi, value_obj, args[3]); - int unchecked_value = value_obj->value(); - // Only attribute bits should be set. - RUNTIME_ASSERT( - (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); - attributes = static_cast(unchecked_value); + PropertyAttributes attributes = + static_cast(unchecked_attributes); + + StrictModeFlag strict = kNonStrictMode; + if (args.length() == 5) { + CONVERT_SMI_CHECKED(strict_unchecked, args[4]); + RUNTIME_ASSERT(strict_unchecked == kStrictMode || + strict_unchecked == kNonStrictMode); + strict = static_cast(strict_unchecked); } - return Runtime::SetObjectProperty(object, key, value, attributes); + + return Runtime::SetObjectProperty(object, key, value, attributes, strict); } @@ -3938,7 +3977,7 @@ static MaybeObject* Runtime_DeleteProperty(Arguments args) { CONVERT_CHECKED(JSObject, object, args[0]); CONVERT_CHECKED(String, key, args[1]); CONVERT_SMI_CHECKED(strict, args[2]); - return object->DeleteProperty(key, strict == kStrictMode + return object->DeleteProperty(key, (strict == kStrictMode) ? JSObject::STRICT_DELETION : JSObject::NORMAL_DELETION); } @@ -7486,11 +7525,16 @@ static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) { static MaybeObject* Runtime_StoreContextSlot(Arguments args) { HandleScope scope; - ASSERT(args.length() == 3); + ASSERT(args.length() == 4); Handle value(args[0]); CONVERT_ARG_CHECKED(Context, context, 1); CONVERT_ARG_CHECKED(String, name, 2); + CONVERT_SMI_CHECKED(strict_unchecked, args[3]); + RUNTIME_ASSERT(strict_unchecked == kStrictMode || + strict_unchecked == kNonStrictMode); + StrictModeFlag strict = static_cast(strict_unchecked); + int index; PropertyAttributes attributes; @@ -7534,7 +7578,12 @@ static MaybeObject* Runtime_StoreContextSlot(Arguments args) { // extension object itself. if ((attributes & READ_ONLY) == 0 || (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) { - RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, NONE)); + RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, NONE, strict)); + } else if (strict == kStrictMode && (attributes & READ_ONLY) != 0) { + // Setting read only property in strict mode. + Handle error = + Factory::NewTypeError("strict_cannot_assign", HandleVector(&name, 1)); + return Top::Throw(*error); } return *value; } @@ -9267,7 +9316,9 @@ static bool CopyContextLocalsToScopeObject( RETURN_IF_EMPTY_HANDLE_VALUE( SetProperty(scope_object, scope_info.context_slot_name(i), - Handle(context->get(context_index)), NONE), + Handle(context->get(context_index)), + NONE, + kNonStrictMode), false); } } @@ -9293,7 +9344,9 @@ static Handle MaterializeLocalScope(JavaScriptFrame* frame) { RETURN_IF_EMPTY_HANDLE_VALUE( SetProperty(local_scope, scope_info.parameter_name(i), - Handle(frame->GetParameter(i)), NONE), + Handle(frame->GetParameter(i)), + NONE, + kNonStrictMode), Handle()); } @@ -9302,7 +9355,9 @@ static Handle MaterializeLocalScope(JavaScriptFrame* frame) { RETURN_IF_EMPTY_HANDLE_VALUE( SetProperty(local_scope, scope_info.stack_slot_name(i), - Handle(frame->GetExpression(i)), NONE), + Handle(frame->GetExpression(i)), + NONE, + kNonStrictMode), Handle()); } @@ -9326,7 +9381,11 @@ static Handle MaterializeLocalScope(JavaScriptFrame* frame) { ASSERT(keys->get(i)->IsString()); Handle key(String::cast(keys->get(i))); RETURN_IF_EMPTY_HANDLE_VALUE( - SetProperty(local_scope, key, GetProperty(ext, key), NONE), + SetProperty(local_scope, + key, + GetProperty(ext, key), + NONE, + kNonStrictMode), Handle()); } } @@ -9364,7 +9423,8 @@ static Handle MaterializeClosure(Handle context) { SetProperty(closure_scope, scope_info.parameter_name(i), Handle(element), - NONE), + NONE, + kNonStrictMode), Handle()); } } @@ -9385,7 +9445,11 @@ static Handle MaterializeClosure(Handle context) { ASSERT(keys->get(i)->IsString()); Handle key(String::cast(keys->get(i))); RETURN_IF_EMPTY_HANDLE_VALUE( - SetProperty(closure_scope, key, GetProperty(ext, key), NONE), + SetProperty(closure_scope, + key, + GetProperty(ext, key), + NONE, + kNonStrictMode), Handle()); } } diff --git a/src/runtime.h b/src/runtime.h index 06437ef..52a6e1f 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -241,7 +241,7 @@ namespace internal { F(ResolvePossiblyDirectEval, 4, 2) \ F(ResolvePossiblyDirectEvalNoLookup, 4, 2) \ \ - F(SetProperty, -1 /* 3 or 4 */, 1) \ + F(SetProperty, -1 /* 4 or 5 */, 1) \ F(DefineOrRedefineDataProperty, 4, 1) \ F(DefineOrRedefineAccessorProperty, 5, 1) \ F(IgnoreAttributesAndSetProperty, -1 /* 3 or 4 */, 1) \ @@ -288,12 +288,12 @@ namespace internal { F(DeleteContextSlot, 2, 1) \ F(LoadContextSlot, 2, 2) \ F(LoadContextSlotNoReferenceError, 2, 2) \ - F(StoreContextSlot, 3, 1) \ + F(StoreContextSlot, 4, 1) \ \ /* Declarations and initialization */ \ - F(DeclareGlobals, 3, 1) \ + F(DeclareGlobals, 4, 1) \ F(DeclareContextSlot, 4, 1) \ - F(InitializeVarGlobal, -1 /* 1 or 2 */, 1) \ + F(InitializeVarGlobal, -1 /* 2 or 3 */, 1) \ F(InitializeConstGlobal, 2, 1) \ F(InitializeConstContextSlot, 3, 1) \ F(OptimizeObjectForAddingMultipleProperties, 2, 1) \ @@ -538,7 +538,8 @@ class Runtime : public AllStatic { Handle object, Handle key, Handle value, - PropertyAttributes attr); + PropertyAttributes attr, + StrictModeFlag strict); MUST_USE_RESULT static MaybeObject* ForceSetObjectProperty( Handle object, diff --git a/src/stub-cache.cc b/src/stub-cache.cc index abb26d6..360f0b7 100644 --- a/src/stub-cache.cc +++ b/src/stub-cache.cc @@ -498,13 +498,13 @@ MaybeObject* StubCache::ComputeStoreField(String* name, JSObject* receiver, int field_index, Map* transition, - Code::ExtraICState extra_ic_state) { + StrictModeFlag strict_mode) { PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION; Code::Flags flags = Code::ComputeMonomorphicFlags( - Code::STORE_IC, type, extra_ic_state); + Code::STORE_IC, type, strict_mode); Object* code = receiver->map()->FindInCodeCache(name, flags); if (code->IsUndefined()) { - StoreStubCompiler compiler(extra_ic_state); + StoreStubCompiler compiler(strict_mode); { MaybeObject* maybe_code = compiler.CompileStoreField(receiver, field_index, transition, name); if (!maybe_code->ToObject(&code)) return maybe_code; @@ -521,13 +521,15 @@ MaybeObject* StubCache::ComputeStoreField(String* name, } -MaybeObject* StubCache::ComputeKeyedStoreSpecialized(JSObject* receiver) { +MaybeObject* StubCache::ComputeKeyedStoreSpecialized( + JSObject* receiver, + StrictModeFlag strict_mode) { Code::Flags flags = - Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL); + Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL, strict_mode); String* name = Heap::KeyedStoreSpecialized_symbol(); Object* code = receiver->map()->FindInCodeCache(name, flags); if (code->IsUndefined()) { - KeyedStoreStubCompiler compiler; + KeyedStoreStubCompiler compiler(strict_mode); { MaybeObject* maybe_code = compiler.CompileStoreSpecialized(receiver); if (!maybe_code->ToObject(&code)) return maybe_code; } @@ -542,7 +544,9 @@ MaybeObject* StubCache::ComputeKeyedStoreSpecialized(JSObject* receiver) { } -MaybeObject* StubCache::ComputeKeyedStorePixelArray(JSObject* receiver) { +MaybeObject* StubCache::ComputeKeyedStorePixelArray( + JSObject* receiver, + StrictModeFlag strict_mode) { // Using NORMAL as the PropertyType for array element stores is a misuse. The // generated stub always accesses fast elements, not slow-mode fields, but // some property type is required for the stub lookup. Note that overloading @@ -550,11 +554,11 @@ MaybeObject* StubCache::ComputeKeyedStorePixelArray(JSObject* receiver) { // other keyed field stores. This is guaranteed to be the case since all field // keyed stores that are not array elements go through a generic builtin stub. Code::Flags flags = - Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL); + Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL, strict_mode); String* name = Heap::KeyedStorePixelArray_symbol(); Object* code = receiver->map()->FindInCodeCache(name, flags); if (code->IsUndefined()) { - KeyedStoreStubCompiler compiler; + KeyedStoreStubCompiler compiler(strict_mode); { MaybeObject* maybe_code = compiler.CompileStorePixelArray(receiver); if (!maybe_code->ToObject(&code)) return maybe_code; } @@ -598,11 +602,13 @@ ExternalArrayType ElementsKindToExternalArrayType(JSObject::ElementsKind kind) { MaybeObject* StubCache::ComputeKeyedLoadOrStoreExternalArray( JSObject* receiver, - bool is_store) { + bool is_store, + StrictModeFlag strict_mode) { Code::Flags flags = Code::ComputeMonomorphicFlags( is_store ? Code::KEYED_STORE_IC : Code::KEYED_LOAD_IC, - NORMAL); + NORMAL, + strict_mode); ExternalArrayType array_type = ElementsKindToExternalArrayType(receiver->GetElementsKind()); String* name = @@ -615,9 +621,9 @@ MaybeObject* StubCache::ComputeKeyedLoadOrStoreExternalArray( Object* code = map->FindInCodeCache(name, flags); if (code->IsUndefined()) { ExternalArrayStubCompiler compiler; - { MaybeObject* maybe_code = - is_store ? compiler.CompileKeyedStoreStub(array_type, flags) : - compiler.CompileKeyedLoadStub(array_type, flags); + { MaybeObject* maybe_code = is_store + ? compiler.CompileKeyedStoreStub(array_type, flags) + : compiler.CompileKeyedLoadStub(array_type, flags); if (!maybe_code->ToObject(&code)) return maybe_code; } if (is_store) { @@ -637,8 +643,8 @@ MaybeObject* StubCache::ComputeKeyedLoadOrStoreExternalArray( } -MaybeObject* StubCache::ComputeStoreNormal(Code::ExtraICState extra_ic_state) { - return Builtins::builtin(extra_ic_state == StoreIC::kStoreICStrict +MaybeObject* StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) { + return Builtins::builtin((strict_mode == kStrictMode) ? Builtins::StoreIC_Normal_Strict : Builtins::StoreIC_Normal); } @@ -647,12 +653,12 @@ MaybeObject* StubCache::ComputeStoreNormal(Code::ExtraICState extra_ic_state) { MaybeObject* StubCache::ComputeStoreGlobal(String* name, GlobalObject* receiver, JSGlobalPropertyCell* cell, - Code::ExtraICState extra_ic_state) { + StrictModeFlag strict_mode) { Code::Flags flags = Code::ComputeMonomorphicFlags( - Code::STORE_IC, NORMAL, extra_ic_state); + Code::STORE_IC, NORMAL, strict_mode); Object* code = receiver->map()->FindInCodeCache(name, flags); if (code->IsUndefined()) { - StoreStubCompiler compiler(extra_ic_state); + StoreStubCompiler compiler(strict_mode); { MaybeObject* maybe_code = compiler.CompileStoreGlobal(receiver, cell, name); if (!maybe_code->ToObject(&code)) return maybe_code; @@ -673,13 +679,13 @@ MaybeObject* StubCache::ComputeStoreCallback( String* name, JSObject* receiver, AccessorInfo* callback, - Code::ExtraICState extra_ic_state) { + StrictModeFlag strict_mode) { ASSERT(v8::ToCData
(callback->setter()) != 0); Code::Flags flags = Code::ComputeMonomorphicFlags( - Code::STORE_IC, CALLBACKS, extra_ic_state); + Code::STORE_IC, CALLBACKS, strict_mode); Object* code = receiver->map()->FindInCodeCache(name, flags); if (code->IsUndefined()) { - StoreStubCompiler compiler(extra_ic_state); + StoreStubCompiler compiler(strict_mode); { MaybeObject* maybe_code = compiler.CompileStoreCallback(receiver, callback, name); if (!maybe_code->ToObject(&code)) return maybe_code; @@ -699,12 +705,12 @@ MaybeObject* StubCache::ComputeStoreCallback( MaybeObject* StubCache::ComputeStoreInterceptor( String* name, JSObject* receiver, - Code::ExtraICState extra_ic_state) { + StrictModeFlag strict_mode) { Code::Flags flags = Code::ComputeMonomorphicFlags( - Code::STORE_IC, INTERCEPTOR, extra_ic_state); + Code::STORE_IC, INTERCEPTOR, strict_mode); Object* code = receiver->map()->FindInCodeCache(name, flags); if (code->IsUndefined()) { - StoreStubCompiler compiler(extra_ic_state); + StoreStubCompiler compiler(strict_mode); { MaybeObject* maybe_code = compiler.CompileStoreInterceptor(receiver, name); if (!maybe_code->ToObject(&code)) return maybe_code; @@ -724,12 +730,14 @@ MaybeObject* StubCache::ComputeStoreInterceptor( MaybeObject* StubCache::ComputeKeyedStoreField(String* name, JSObject* receiver, int field_index, - Map* transition) { + Map* transition, + StrictModeFlag strict_mode) { PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION; - Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type); + Code::Flags flags = Code::ComputeMonomorphicFlags( + Code::KEYED_STORE_IC, type, strict_mode); Object* code = receiver->map()->FindInCodeCache(name, flags); if (code->IsUndefined()) { - KeyedStoreStubCompiler compiler; + KeyedStoreStubCompiler compiler(strict_mode); { MaybeObject* maybe_code = compiler.CompileStoreField(receiver, field_index, transition, name); if (!maybe_code->ToObject(&code)) return maybe_code; @@ -1417,12 +1425,17 @@ MaybeObject* LoadPropertyWithInterceptorForCall(Arguments args) { MaybeObject* StoreInterceptorProperty(Arguments args) { + ASSERT(args.length() == 4); JSObject* recv = JSObject::cast(args[0]); String* name = String::cast(args[1]); Object* value = args[2]; + StrictModeFlag strict = + static_cast(Smi::cast(args[3])->value()); + ASSERT(strict == kStrictMode || strict == kNonStrictMode); ASSERT(recv->HasNamedInterceptor()); PropertyAttributes attr = NONE; - MaybeObject* result = recv->SetPropertyWithInterceptor(name, value, attr); + MaybeObject* result = recv->SetPropertyWithInterceptor( + name, value, attr, strict); return result; } @@ -1675,8 +1688,8 @@ MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) { MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) { - Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type, - extra_ic_state_); + Code::Flags flags = Code::ComputeMonomorphicFlags( + Code::STORE_IC, type, strict_mode_); MaybeObject* result = GetCodeWithFlags(flags, name); if (!result->IsFailure()) { PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, @@ -1691,7 +1704,8 @@ MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) { MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) { - Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type); + Code::Flags flags = Code::ComputeMonomorphicFlags( + Code::KEYED_STORE_IC, type, strict_mode_); MaybeObject* result = GetCodeWithFlags(flags, name); if (!result->IsFailure()) { PROFILE(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, diff --git a/src/stub-cache.h b/src/stub-cache.h index 4638da2..6927076 100644 --- a/src/stub-cache.h +++ b/src/stub-cache.h @@ -143,27 +143,27 @@ class StubCache : public AllStatic { JSObject* receiver, int field_index, Map* transition, - Code::ExtraICState extra_ic_state); + StrictModeFlag strict_mode); MUST_USE_RESULT static MaybeObject* ComputeStoreNormal( - Code::ExtraICState extra_ic_state); + StrictModeFlag strict_mode); MUST_USE_RESULT static MaybeObject* ComputeStoreGlobal( String* name, GlobalObject* receiver, JSGlobalPropertyCell* cell, - Code::ExtraICState extra_ic_state); + StrictModeFlag strict_mode); MUST_USE_RESULT static MaybeObject* ComputeStoreCallback( String* name, JSObject* receiver, AccessorInfo* callback, - Code::ExtraICState extra_ic_state); + StrictModeFlag strict_mode); MUST_USE_RESULT static MaybeObject* ComputeStoreInterceptor( String* name, JSObject* receiver, - Code::ExtraICState extra_ic_state); + StrictModeFlag strict_mode); // --- @@ -171,17 +171,21 @@ class StubCache : public AllStatic { String* name, JSObject* receiver, int field_index, - Map* transition = NULL); + Map* transition, + StrictModeFlag strict_mode); MUST_USE_RESULT static MaybeObject* ComputeKeyedStoreSpecialized( - JSObject* receiver); + JSObject* receiver, + StrictModeFlag strict_mode); MUST_USE_RESULT static MaybeObject* ComputeKeyedStorePixelArray( - JSObject* receiver); + JSObject* receiver, + StrictModeFlag strict_mode); MUST_USE_RESULT static MaybeObject* ComputeKeyedLoadOrStoreExternalArray( JSObject* receiver, - bool is_store); + bool is_store, + StrictModeFlag strict_mode); // --- @@ -628,8 +632,8 @@ class KeyedLoadStubCompiler: public StubCompiler { class StoreStubCompiler: public StubCompiler { public: - explicit StoreStubCompiler(Code::ExtraICState extra_ic_state) - : extra_ic_state_(extra_ic_state) { } + explicit StoreStubCompiler(StrictModeFlag strict_mode) + : strict_mode_(strict_mode) { } MUST_USE_RESULT MaybeObject* CompileStoreField(JSObject* object, int index, @@ -649,12 +653,15 @@ class StoreStubCompiler: public StubCompiler { private: MaybeObject* GetCode(PropertyType type, String* name); - Code::ExtraICState extra_ic_state_; + StrictModeFlag strict_mode_; }; class KeyedStoreStubCompiler: public StubCompiler { public: + explicit KeyedStoreStubCompiler(StrictModeFlag strict_mode) + : strict_mode_(strict_mode) { } + MUST_USE_RESULT MaybeObject* CompileStoreField(JSObject* object, int index, Map* transition, @@ -666,6 +673,8 @@ class KeyedStoreStubCompiler: public StubCompiler { private: MaybeObject* GetCode(PropertyType type, String* name); + + StrictModeFlag strict_mode_; }; diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index dfee36e..6a71e6f 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -2747,7 +2747,8 @@ void CodeGenerator::DeclareGlobals(Handle pairs) { frame_->EmitPush(rsi); // The context is the first argument. frame_->EmitPush(kScratchRegister); frame_->EmitPush(Smi::FromInt(is_eval() ? 1 : 0)); - Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); + frame_->EmitPush(Smi::FromInt(strict_mode_flag())); + Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 4); // Return value is ignored. } @@ -4605,7 +4606,8 @@ void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { // by initialization. value = frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); } else { - value = frame_->CallRuntime(Runtime::kStoreContextSlot, 3); + frame_->Push(Smi::FromInt(strict_mode_flag())); + value = frame_->CallRuntime(Runtime::kStoreContextSlot, 4); } // Storing a variable must keep the (new) value on the expression // stack. This is necessary for compiling chained assignment @@ -4925,8 +4927,9 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { Load(property->key()); Load(property->value()); if (property->emit_store()) { + frame_->Push(Smi::FromInt(NONE)); // PropertyAttributes // Ignore the result. - Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3); + Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 4); } else { frame_->Drop(3); } @@ -8086,8 +8089,12 @@ class DeferredReferenceSetKeyedValue: public DeferredCode { public: DeferredReferenceSetKeyedValue(Register value, Register key, - Register receiver) - : value_(value), key_(key), receiver_(receiver) { + Register receiver, + StrictModeFlag strict_mode) + : value_(value), + key_(key), + receiver_(receiver), + strict_mode_(strict_mode) { set_comment("[ DeferredReferenceSetKeyedValue"); } @@ -8100,6 +8107,7 @@ class DeferredReferenceSetKeyedValue: public DeferredCode { Register key_; Register receiver_; Label patch_site_; + StrictModeFlag strict_mode_; }; @@ -8151,7 +8159,9 @@ void DeferredReferenceSetKeyedValue::Generate() { } // Call the IC stub. - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + (strict_mode_ == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); __ Call(ic, RelocInfo::CODE_TARGET); // The delta from the start of the map-compare instructions (initial movq) // to the test instruction. We use masm_-> directly here instead of the @@ -8492,7 +8502,8 @@ Result CodeGenerator::EmitKeyedStore(StaticType* key_type) { DeferredReferenceSetKeyedValue* deferred = new DeferredReferenceSetKeyedValue(result.reg(), key.reg(), - receiver.reg()); + receiver.reg(), + strict_mode_flag()); // Check that the receiver is not a smi. __ JumpIfSmi(receiver.reg(), deferred->entry_label()); @@ -8554,7 +8565,7 @@ Result CodeGenerator::EmitKeyedStore(StaticType* key_type) { deferred->BindExit(); } else { - result = frame()->CallKeyedStoreIC(); + result = frame()->CallKeyedStoreIC(strict_mode_flag()); // Make sure that we do not have a test instruction after the // call. A test instruction after the call is used to // indicate that we have generated an inline version of the diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 1381a94..472e406 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -742,7 +742,9 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, prop->key()->AsLiteral()->handle()->IsSmi()); __ Move(rcx, prop->key()->AsLiteral()->handle()); - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin(is_strict() + ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); } } @@ -759,7 +761,8 @@ void FullCodeGenerator::DeclareGlobals(Handle pairs) { __ push(rsi); // The context is the first argument. __ Push(pairs); __ Push(Smi::FromInt(is_eval() ? 1 : 0)); - __ CallRuntime(Runtime::kDeclareGlobals, 3); + __ Push(Smi::FromInt(strict_mode_flag())); + __ CallRuntime(Runtime::kDeclareGlobals, 4); // Return value is ignored. } @@ -1403,7 +1406,8 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForStackValue(key); VisitForStackValue(value); if (property->emit_store()) { - __ CallRuntime(Runtime::kSetProperty, 3); + __ Push(Smi::FromInt(NONE)); // PropertyAttributes + __ CallRuntime(Runtime::kSetProperty, 4); } else { __ Drop(3); } @@ -1750,7 +1754,9 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { __ movq(rdx, rax); __ pop(rax); // Restore value. __ Move(rcx, prop->key()->AsLiteral()->handle()); - Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); break; } @@ -1771,7 +1777,9 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { __ pop(rdx); } __ pop(rax); // Restore value. - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); break; } @@ -1866,7 +1874,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, __ push(rax); // Value. __ push(rsi); // Context. __ Push(var->name()); - __ CallRuntime(Runtime::kStoreContextSlot, 3); + __ Push(Smi::FromInt(strict_mode_flag())); + __ CallRuntime(Runtime::kStoreContextSlot, 4); break; } } @@ -1897,7 +1906,9 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { } else { __ pop(rdx); } - Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); // If the assignment ends an initialization block, revert to fast case. @@ -1935,7 +1946,9 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { } // Record source code position before IC call. SetSourcePosition(expr->position()); - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); // If the assignment ends an initialization block, revert to fast case. @@ -3450,7 +3463,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { case NAMED_PROPERTY: { __ Move(rcx, prop->key()->AsLiteral()->handle()); __ pop(rdx); - Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { @@ -3465,7 +3480,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { case KEYED_PROPERTY: { __ pop(rcx); __ pop(rdx); - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc index 55d837c..b3243cf 100644 --- a/src/x64/ic-x64.cc +++ b/src/x64/ic-x64.cc @@ -766,7 +766,8 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { } -void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { +void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, + StrictModeFlag strict_mode) { // ----------- S t a t e ------------- // -- rax : value // -- rcx : key @@ -813,7 +814,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { __ bind(&slow); __ Integer32ToSmi(rcx, rcx); __ bind(&slow_with_tagged_index); - GenerateRuntimeSetProperty(masm); + GenerateRuntimeSetProperty(masm, strict_mode); // Never returns to here. // Check whether the elements is a pixel array. @@ -1474,7 +1475,7 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { void StoreIC::GenerateMegamorphic(MacroAssembler* masm, - Code::ExtraICState extra_ic_state) { + StrictModeFlag strict_mode) { // ----------- S t a t e ------------- // -- rax : value // -- rcx : name @@ -1486,7 +1487,7 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm, Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, NOT_IN_LOOP, MONOMORPHIC, - extra_ic_state); + strict_mode); StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg); // Cache miss: Jump to runtime. @@ -1593,7 +1594,8 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) { } -void StoreIC::GenerateGlobalProxy(MacroAssembler* masm) { +void StoreIC::GenerateGlobalProxy(MacroAssembler* masm, + StrictModeFlag strict_mode) { // ----------- S t a t e ------------- // -- rax : value // -- rcx : name @@ -1604,14 +1606,17 @@ void StoreIC::GenerateGlobalProxy(MacroAssembler* masm) { __ push(rdx); __ push(rcx); __ push(rax); - __ push(rbx); + __ Push(Smi::FromInt(NONE)); // PropertyAttributes + __ Push(Smi::FromInt(strict_mode)); + __ push(rbx); // return address // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kSetProperty, 3, 1); + __ TailCallRuntime(Runtime::kSetProperty, 5, 1); } -void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) { +void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, + StrictModeFlag strict_mode) { // ----------- S t a t e ------------- // -- rax : value // -- rcx : key @@ -1623,10 +1628,12 @@ void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) { __ push(rdx); // receiver __ push(rcx); // key __ push(rax); // value + __ Push(Smi::FromInt(NONE)); // PropertyAttributes + __ Push(Smi::FromInt(strict_mode)); // Strict mode. __ push(rbx); // return address // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kSetProperty, 3, 1); + __ TailCallRuntime(Runtime::kSetProperty, 5, 1); } diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 791f5e7..9896562 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -2641,7 +2641,9 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { ASSERT(ToRegister(instr->value()).is(rax)); __ Move(rcx, instr->hydrogen()->name()); - Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + info_->is_strict() ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -2710,7 +2712,9 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { ASSERT(ToRegister(instr->key()).is(rcx)); ASSERT(ToRegister(instr->value()).is(rax)); - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + info_->is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); CallCode(ic, RelocInfo::CODE_TARGET, instr); } diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index 774de71..109985c 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -2408,12 +2408,13 @@ MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, __ push(rdx); // receiver __ push(rcx); // name __ push(rax); // value + __ Push(Smi::FromInt(strict_mode_)); __ push(rbx); // restore return address // Do tail-call to the runtime system. ExternalReference store_ic_property = ExternalReference(IC_Utility(IC::kStoreInterceptorProperty)); - __ TailCallExternalReference(store_ic_property, 3, 1); + __ TailCallExternalReference(store_ic_property, 4, 1); // Handle store cache miss. __ bind(&miss); @@ -3490,10 +3491,13 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( __ push(rdx); // receiver __ push(rcx); // key __ push(rax); // value + __ Push(Smi::FromInt(NONE)); // PropertyAttributes + __ Push(Smi::FromInt( + Code::ExtractExtraICStateFromFlags(flags) & kStrictMode)); __ push(rbx); // return address // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kSetProperty, 3, 1); + __ TailCallRuntime(Runtime::kSetProperty, 5, 1); return GetCode(flags); } diff --git a/src/x64/virtual-frame-x64.cc b/src/x64/virtual-frame-x64.cc index ea115f2..1787044 100644 --- a/src/x64/virtual-frame-x64.cc +++ b/src/x64/virtual-frame-x64.cc @@ -1124,9 +1124,9 @@ Result VirtualFrame::CallStoreIC(Handle name, StrictModeFlag strict_mode) { // Value and (if not contextual) receiver are on top of the frame. // The IC expects name in rcx, value in rax, and receiver in rdx. - Handle ic(Builtins::builtin(strict_mode == kStrictMode - ? Builtins::StoreIC_Initialize_Strict - : Builtins::StoreIC_Initialize)); + Handle ic(Builtins::builtin( + (strict_mode == kStrictMode) ? Builtins::StoreIC_Initialize_Strict + : Builtins::StoreIC_Initialize)); Result value = Pop(); RelocInfo::Mode mode; if (is_contextual) { @@ -1146,7 +1146,7 @@ Result VirtualFrame::CallStoreIC(Handle name, } -Result VirtualFrame::CallKeyedStoreIC() { +Result VirtualFrame::CallKeyedStoreIC(StrictModeFlag strict_mode) { // Value, key, and receiver are on the top of the frame. The IC // expects value in rax, key in rcx, and receiver in rdx. Result value = Pop(); @@ -1190,7 +1190,9 @@ Result VirtualFrame::CallKeyedStoreIC() { receiver.Unuse(); } - Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + Handle ic(Builtins::builtin( + (strict_mode == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict + : Builtins::KeyedStoreIC_Initialize)); return RawCallCodeObject(ic, RelocInfo::CODE_TARGET); } diff --git a/src/x64/virtual-frame-x64.h b/src/x64/virtual-frame-x64.h index 824743d..b568a78 100644 --- a/src/x64/virtual-frame-x64.h +++ b/src/x64/virtual-frame-x64.h @@ -343,7 +343,7 @@ class VirtualFrame : public ZoneObject { // Call keyed store IC. Value, key, and receiver are found on top // of the frame. All three are dropped. - Result CallKeyedStoreIC(); + Result CallKeyedStoreIC(StrictModeFlag strict_mode); // Call call IC. Function name, arguments, and receiver are found on top // of the frame and dropped by the call. diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index b3c52f1..f450a34 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -10091,10 +10091,11 @@ class RegExpStringModificationTest { // Inject the input as a global variable. i::Handle input_name = i::Factory::NewStringFromAscii(i::Vector("input", 5)); - i::Top::global_context()->global()->SetProperty(*input_name, - *input_, - NONE)->ToObjectChecked(); - + i::Top::global_context()->global()->SetProperty( + *input_name, + *input_, + NONE, + i::kNonStrictMode)->ToObjectChecked(); MorphThread morph_thread(this); morph_thread.Start(); diff --git a/test/cctest/test-compiler.cc b/test/cctest/test-compiler.cc index b424b7f..9f21b78 100644 --- a/test/cctest/test-compiler.cc +++ b/test/cctest/test-compiler.cc @@ -108,7 +108,7 @@ static void SetGlobalProperty(const char* name, Object* value) { Handle object(value); Handle symbol = Factory::LookupAsciiSymbol(name); Handle global(Top::context()->global()); - SetProperty(global, symbol, object, NONE); + SetProperty(global, symbol, object, NONE, kNonStrictMode); } diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc index 441aae6..7245e54 100644 --- a/test/cctest/test-debug.cc +++ b/test/cctest/test-debug.cc @@ -153,7 +153,8 @@ class DebugLocalContext { Handle debug_string = v8::internal::Factory::LookupAsciiSymbol("debug"); SetProperty(global, debug_string, - Handle(Debug::debug_context()->global_proxy()), DONT_ENUM); + Handle(Debug::debug_context()->global_proxy()), DONT_ENUM, + ::v8::internal::kNonStrictMode); } private: v8::Persistent context_; diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc index a23ee17..9cce01e 100644 --- a/test/cctest/test-heap.cc +++ b/test/cctest/test-heap.cc @@ -212,13 +212,14 @@ TEST(GarbageCollection) { Handle initial_map = Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); function->set_initial_map(*initial_map); - Top::context()->global()->SetProperty(*name, - *function, - NONE)->ToObjectChecked(); + Top::context()->global()->SetProperty( + *name, *function, NONE, kNonStrictMode)->ToObjectChecked(); // Allocate an object. Unrooted after leaving the scope. Handle obj = Factory::NewJSObject(function); - obj->SetProperty(*prop_name, Smi::FromInt(23), NONE)->ToObjectChecked(); - obj->SetProperty(*prop_namex, Smi::FromInt(24), NONE)->ToObjectChecked(); + obj->SetProperty( + *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked(); + obj->SetProperty( + *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked(); CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name)); CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex)); @@ -238,10 +239,10 @@ TEST(GarbageCollection) { HandleScope inner_scope; // Allocate another object, make it reachable from global. Handle obj = Factory::NewJSObject(function); - Top::context()->global()->SetProperty(*obj_name, - *obj, - NONE)->ToObjectChecked(); - obj->SetProperty(*prop_name, Smi::FromInt(23), NONE)->ToObjectChecked(); + Top::context()->global()->SetProperty( + *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked(); + obj->SetProperty( + *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked(); } // After gc, it should survive. @@ -540,12 +541,12 @@ TEST(FunctionAllocation) { Handle prop_name = Factory::LookupAsciiSymbol("theSlot"); Handle obj = Factory::NewJSObject(function); - obj->SetProperty(*prop_name, Smi::FromInt(23), NONE)->ToObjectChecked(); + obj->SetProperty( + *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked(); CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name)); // Check that we can add properties to function objects. - function->SetProperty(*prop_name, - Smi::FromInt(24), - NONE)->ToObjectChecked(); + function->SetProperty( + *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked(); CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name)); } @@ -567,7 +568,8 @@ TEST(ObjectProperties) { CHECK(!obj->HasLocalProperty(*first)); // add first - obj->SetProperty(*first, Smi::FromInt(1), NONE)->ToObjectChecked(); + obj->SetProperty( + *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked(); CHECK(obj->HasLocalProperty(*first)); // delete first @@ -575,8 +577,10 @@ TEST(ObjectProperties) { CHECK(!obj->HasLocalProperty(*first)); // add first and then second - obj->SetProperty(*first, Smi::FromInt(1), NONE)->ToObjectChecked(); - obj->SetProperty(*second, Smi::FromInt(2), NONE)->ToObjectChecked(); + obj->SetProperty( + *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked(); + obj->SetProperty( + *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked(); CHECK(obj->HasLocalProperty(*first)); CHECK(obj->HasLocalProperty(*second)); @@ -588,8 +592,10 @@ TEST(ObjectProperties) { CHECK(!obj->HasLocalProperty(*second)); // add first and then second - obj->SetProperty(*first, Smi::FromInt(1), NONE)->ToObjectChecked(); - obj->SetProperty(*second, Smi::FromInt(2), NONE)->ToObjectChecked(); + obj->SetProperty( + *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked(); + obj->SetProperty( + *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked(); CHECK(obj->HasLocalProperty(*first)); CHECK(obj->HasLocalProperty(*second)); @@ -603,14 +609,16 @@ TEST(ObjectProperties) { // check string and symbol match static const char* string1 = "fisk"; Handle s1 = Factory::NewStringFromAscii(CStrVector(string1)); - obj->SetProperty(*s1, Smi::FromInt(1), NONE)->ToObjectChecked(); + obj->SetProperty( + *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked(); Handle s1_symbol = Factory::LookupAsciiSymbol(string1); CHECK(obj->HasLocalProperty(*s1_symbol)); // check symbol and string match static const char* string2 = "fugl"; Handle s2_symbol = Factory::LookupAsciiSymbol(string2); - obj->SetProperty(*s2_symbol, Smi::FromInt(1), NONE)->ToObjectChecked(); + obj->SetProperty( + *s2_symbol, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked(); Handle s2 = Factory::NewStringFromAscii(CStrVector(string2)); CHECK(obj->HasLocalProperty(*s2)); } @@ -631,7 +639,8 @@ TEST(JSObjectMaps) { Handle obj = Factory::NewJSObject(function); // Set a propery - obj->SetProperty(*prop_name, Smi::FromInt(23), NONE)->ToObjectChecked(); + obj->SetProperty( + *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked(); CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name)); // Check the map has changed @@ -698,8 +707,10 @@ TEST(JSObjectCopy) { Handle first = Factory::LookupAsciiSymbol("first"); Handle second = Factory::LookupAsciiSymbol("second"); - obj->SetProperty(*first, Smi::FromInt(1), NONE)->ToObjectChecked(); - obj->SetProperty(*second, Smi::FromInt(2), NONE)->ToObjectChecked(); + obj->SetProperty( + *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked(); + obj->SetProperty( + *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked(); Object* ok = obj->SetElement(0, *first)->ToObjectChecked(); @@ -716,8 +727,10 @@ TEST(JSObjectCopy) { CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second)); // Flip the values. - clone->SetProperty(*first, Smi::FromInt(2), NONE)->ToObjectChecked(); - clone->SetProperty(*second, Smi::FromInt(1), NONE)->ToObjectChecked(); + clone->SetProperty( + *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked(); + clone->SetProperty( + *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked(); ok = clone->SetElement(0, *second)->ToObjectChecked(); ok = clone->SetElement(1, *first)->ToObjectChecked(); diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc index 86f105f..3e3175e 100644 --- a/test/cctest/test-mark-compact.cc +++ b/test/cctest/test-mark-compact.cc @@ -189,7 +189,8 @@ TEST(MarkCompactCollector) { function->set_initial_map(initial_map); Top::context()->global()->SetProperty(func_name, function, - NONE)->ToObjectChecked(); + NONE, + kNonStrictMode)->ToObjectChecked(); JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function)->ToObjectChecked()); @@ -208,10 +209,14 @@ TEST(MarkCompactCollector) { String::cast(Heap::LookupAsciiSymbol("theObject")->ToObjectChecked()); Top::context()->global()->SetProperty(obj_name, obj, - NONE)->ToObjectChecked(); + NONE, + kNonStrictMode)->ToObjectChecked(); String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot")->ToObjectChecked()); - obj->SetProperty(prop_name, Smi::FromInt(23), NONE)->ToObjectChecked(); + obj->SetProperty(prop_name, + Smi::FromInt(23), + NONE, + kNonStrictMode)->ToObjectChecked(); Heap::CollectGarbage(OLD_POINTER_SPACE); diff --git a/test/es5conform/es5conform.status b/test/es5conform/es5conform.status index e021fc5..d6f7caf 100644 --- a/test/es5conform/es5conform.status +++ b/test/es5conform/es5conform.status @@ -269,72 +269,6 @@ chapter11/11.13/11.13.1/11.13.1-4-3-s: FAIL # in strict mode (Global.length) chapter11/11.13/11.13.1/11.13.1-4-4-s: FAIL # simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Object.length) -chapter11/11.13/11.13.1/11.13.1-4-5-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Function.length) -chapter11/11.13/11.13.1/11.13.1-4-6-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Array.length) -chapter11/11.13/11.13.1/11.13.1-4-7-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (String.length) -chapter11/11.13/11.13.1/11.13.1-4-8-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Boolean.length) -chapter11/11.13/11.13.1/11.13.1-4-9-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Number.length) -chapter11/11.13/11.13.1/11.13.1-4-10-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Date.length) -chapter11/11.13/11.13.1/11.13.1-4-11-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (RegExp.length) -chapter11/11.13/11.13.1/11.13.1-4-12-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Error.length) -chapter11/11.13/11.13.1/11.13.1-4-13-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Number.MAX_VALUE) -chapter11/11.13/11.13.1/11.13.1-4-14-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Number.MIN_VALUE) -chapter11/11.13/11.13.1/11.13.1-4-15-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Number.NaN) -chapter11/11.13/11.13.1/11.13.1-4-16-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Number.NEGATIVE_INFINITY) -chapter11/11.13/11.13.1/11.13.1-4-17-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Number.POSITIVE_INFINITY) -chapter11/11.13/11.13.1/11.13.1-4-18-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Math.E) -chapter11/11.13/11.13.1/11.13.1-4-19-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Math.LN10) -chapter11/11.13/11.13.1/11.13.1-4-20-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Math.LN2) -chapter11/11.13/11.13.1/11.13.1-4-21-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Math.LOG2E) -chapter11/11.13/11.13.1/11.13.1-4-22-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Math.LOG10E) -chapter11/11.13/11.13.1/11.13.1-4-23-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Math.PI) -chapter11/11.13/11.13.1/11.13.1-4-24-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Math.SQRT1_2) -chapter11/11.13/11.13.1/11.13.1-4-25-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property -# in strict mode (Math.SQRT2) -chapter11/11.13/11.13.1/11.13.1-4-26-s: FAIL -# simple assignment throws TypeError if LeftHandSide is a readonly property # in strict mode (Global.undefined) chapter11/11.13/11.13.1/11.13.1-4-27-s: FAIL diff --git a/test/mjsunit/strict-mode.js b/test/mjsunit/strict-mode.js index 42d8355..4071232 100644 --- a/test/mjsunit/strict-mode.js +++ b/test/mjsunit/strict-mode.js @@ -713,3 +713,118 @@ repeat(10, function() { testAssignToUndefined(false); }); cleanup(Boolean); } })(); + + +(function ObjectEnvironment() { + var o = {}; + Object.defineProperty(o, "foo", { value: "FOO", writable: false }); + assertThrows( + function () { + with (o) { + (function() { + "use strict"; + foo = "Hello"; + })(); + } + }, + TypeError); +})(); + + +(function TestSetPropertyWithoutSetter() { + var o = { get foo() { return "Yey"; } }; + assertThrows( + function broken() { + "use strict"; + o.foo = (0xBADBAD00 >> 1); + }, + TypeError); +})(); + + +(function TestSetPropertyNonConfigurable() { + var frozen = Object.freeze({}); + var sealed = Object.seal({}); + + function strict(o) { + "use strict"; + o.property = "value"; + } + + assertThrows(function() { strict(frozen); }, TypeError); + assertThrows(function() { strict(sealed); }, TypeError); +})(); + + +(function TestAssignmentToReadOnlyProperty() { + "use strict"; + + var o = {}; + Object.defineProperty(o, "property", { value: 7 }); + + assertThrows(function() { o.property = "new value"; }, TypeError); + assertThrows(function() { o.property += 10; }, TypeError); + assertThrows(function() { o.property -= 10; }, TypeError); + assertThrows(function() { o.property *= 10; }, TypeError); + assertThrows(function() { o.property /= 10; }, TypeError); + assertThrows(function() { o.property++; }, TypeError); + assertThrows(function() { o.property--; }, TypeError); + assertThrows(function() { ++o.property; }, TypeError); + assertThrows(function() { --o.property; }, TypeError); + + var name = "prop" + "erty"; // to avoid symbol path. + assertThrows(function() { o[name] = "new value"; }, TypeError); + assertThrows(function() { o[name] += 10; }, TypeError); + assertThrows(function() { o[name] -= 10; }, TypeError); + assertThrows(function() { o[name] *= 10; }, TypeError); + assertThrows(function() { o[name] /= 10; }, TypeError); + assertThrows(function() { o[name]++; }, TypeError); + assertThrows(function() { o[name]--; }, TypeError); + assertThrows(function() { ++o[name]; }, TypeError); + assertThrows(function() { --o[name]; }, TypeError); + + assertEquals(o.property, 7); +})(); + + +(function TestAssignmentToReadOnlyLoop() { + var name = "prop" + "erty"; // to avoid symbol path. + var o = {}; + Object.defineProperty(o, "property", { value: 7 }); + + function strict(o, name) { + "use strict"; + o[name] = "new value"; + } + + for (var i = 0; i < 10; i ++) { + try { + strict(o, name); + assertUnreachable(); + } catch(e) { + assertInstanceof(e, TypeError); + } + } +})(); + + +// Specialized KeyedStoreIC experiencing miss. +(function testKeyedStoreICStrict() { + var o = [9,8,7,6,5,4,3,2,1]; + + function test(o, i, v) { + "use strict"; + o[i] = v; + } + + for (var i = 0; i < 10; i ++) { + test(o, 5, 17); // start specialized for smi indices + assertEquals(o[5], 17); + test(o, "a", 19); + assertEquals(o["a"], 19); + test(o, "5", 29); + assertEquals(o[5], 29); + test(o, 100000, 31); + assertEquals(o[100000], 31); + } +})();