shell
shell_g
/obj/
+/test/es5conform/data/
/test/sputnik/sputniktests/
/tools/oom_dump/oom_dump
/tools/oom_dump/oom_dump.o
Result result;
if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) {
- frame()->CallStoreIC(name, is_contextual);
+ frame()->CallStoreIC(name, is_contextual, strict_mode_flag());
} else {
// Inline the in-object property case.
JumpTarget slow, done;
// r2, and the global object in r1.
__ mov(r2, Operand(var->name()));
__ ldr(r1, GlobalObjectOperand());
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
- EmitCallIC(ic, RelocInfo::CODE_TARGET);
+ Handle<Code> ic(Builtins::builtin(is_strict()
+ ? Builtins::StoreIC_Initialize_Strict
+ : Builtins::StoreIC_Initialize));
+ EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) {
// Perform the assignment for non-const variables and for initialization
}
-void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
+void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
+ Code::ExtraICState extra_ic_state) {
// ----------- S t a t e -------------
// -- r0 : value
// -- r1 : receiver
// Get the receiver from the stack and probe the stub cache.
Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
NOT_IN_LOOP,
- MONOMORPHIC);
+ MONOMORPHIC,
+ extra_ic_state);
StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
// Cache miss: Jump to runtime.
// Name is always in r2.
__ mov(r2, Operand(instr->name()));
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+ Handle<Code> ic(Builtins::builtin(info_->is_strict()
+ ? Builtins::StoreIC_Initialize_Strict
+ : Builtins::StoreIC_Initialize));
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
}
-void VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) {
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+void VirtualFrame::CallStoreIC(Handle<String> name,
+ bool is_contextual,
+ StrictModeFlag strict_mode) {
+ Handle<Code> ic(Builtins::builtin(strict_mode == kStrictMode
+ ? Builtins::StoreIC_Initialize_Strict
+ : Builtins::StoreIC_Initialize));
PopToR0();
+ RelocInfo::Mode mode;
if (is_contextual) {
SpillAll();
__ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ mode = RelocInfo::CODE_TARGET_CONTEXT;
} else {
EmitPop(r1);
SpillAll();
+ mode = RelocInfo::CODE_TARGET;
}
__ mov(r2, Operand(name));
- CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
+ CallCodeObject(ic, mode, 0);
}
// Call store IC. If the load is contextual, value is found on top of the
// frame. If not, value and receiver are on the frame. Both are consumed.
// Result is returned in r0.
- void CallStoreIC(Handle<String> name, bool is_contextual);
+ void CallStoreIC(Handle<String> name, bool is_contextual,
+ StrictModeFlag strict_mode);
// Call keyed load IC. Key and receiver are on the stack. Both are consumed.
// Result is returned in r0.
enum Mode {
// Please note the order is important (see IsCodeTarget, IsGCRelocMode).
CONSTRUCT_CALL, // code target that is a call to a JavaScript constructor.
- CODE_TARGET_CONTEXT, // Code target used for contextual loads.
+ CODE_TARGET_CONTEXT, // Code target used for contextual loads and stores.
DEBUG_BREAK, // Code target for the debugger statement.
CODE_TARGET, // Code target which is not any of the above.
EMBEDDED_OBJECT,
}
+static void Generate_StoreIC_Initialize_Strict(MacroAssembler* masm) {
+ StoreIC::GenerateInitialize(masm);
+}
+
+
static void Generate_StoreIC_Miss(MacroAssembler* masm) {
StoreIC::GenerateMiss(masm);
}
}
+static void Generate_StoreIC_Normal_Strict(MacroAssembler* masm) {
+ StoreIC::GenerateNormal(masm);
+}
+
+
static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
- StoreIC::GenerateMegamorphic(masm);
+ StoreIC::GenerateMegamorphic(masm, StoreIC::kStoreICNonStrict);
+}
+
+
+static void Generate_StoreIC_Megamorphic_Strict(MacroAssembler* masm) {
+ StoreIC::GenerateMegamorphic(masm, StoreIC::kStoreICStrict);
}
}
+static void Generate_StoreIC_ArrayLength_Strict(MacroAssembler* masm) {
+ StoreIC::GenerateArrayLength(masm);
+}
+
+
static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) {
StoreIC::GenerateGlobalProxy(masm);
}
+static void Generate_StoreIC_GlobalProxy_Strict(MacroAssembler* masm) {
+ StoreIC::GenerateGlobalProxy(masm);
+}
+
+
static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
KeyedStoreIC::GenerateGeneric(masm);
}
extra_args \
},
-#define DEF_FUNCTION_PTR_A(name, kind, state) \
- { FUNCTION_ADDR(Generate_##name), \
- NULL, \
- #name, \
- name, \
- Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state), \
- NO_EXTRA_ARGUMENTS \
+#define DEF_FUNCTION_PTR_A(name, kind, state, extra) \
+ { FUNCTION_ADDR(Generate_##name), \
+ NULL, \
+ #name, \
+ name, \
+ Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state, extra), \
+ NO_EXTRA_ARGUMENTS \
},
// Define array of pointers to generators and C builtin functions.
// Define list of builtins implemented in assembly.
#define BUILTIN_LIST_A(V) \
- V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED) \
- V(JSConstructCall, BUILTIN, UNINITIALIZED) \
- V(JSConstructStubCountdown, BUILTIN, UNINITIALIZED) \
- V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED) \
- V(JSConstructStubApi, BUILTIN, UNINITIALIZED) \
- V(JSEntryTrampoline, BUILTIN, UNINITIALIZED) \
- V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED) \
- V(LazyCompile, BUILTIN, UNINITIALIZED) \
- V(LazyRecompile, BUILTIN, UNINITIALIZED) \
- V(NotifyDeoptimized, BUILTIN, UNINITIALIZED) \
- V(NotifyLazyDeoptimized, BUILTIN, UNINITIALIZED) \
- V(NotifyOSR, BUILTIN, UNINITIALIZED) \
+ 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) \
- V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED) \
- V(StoreIC_Miss, BUILTIN, UNINITIALIZED) \
- V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED) \
+ 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) \
- V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC) \
- V(LoadIC_Normal, LOAD_IC, MONOMORPHIC) \
- V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC) \
- V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC) \
- V(LoadIC_StringWrapperLength, LOAD_IC, MONOMORPHIC) \
- V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC) \
- V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC) \
+ 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) \
- V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC) \
- V(KeyedLoadIC_Generic, KEYED_LOAD_IC, MEGAMORPHIC) \
- V(KeyedLoadIC_String, KEYED_LOAD_IC, MEGAMORPHIC) \
- V(KeyedLoadIC_IndexedInterceptor, KEYED_LOAD_IC, MEGAMORPHIC) \
+ 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) \
- V(StoreIC_ArrayLength, STORE_IC, MONOMORPHIC) \
- V(StoreIC_Normal, STORE_IC, MONOMORPHIC) \
- V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC) \
- V(StoreIC_GlobalProxy, STORE_IC, MEGAMORPHIC) \
+ 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) \
- V(KeyedStoreIC_Generic, KEYED_STORE_IC, MEGAMORPHIC) \
+ 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) \
- V(FunctionApply, BUILTIN, UNINITIALIZED) \
+ V(FunctionCall, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(FunctionApply, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
\
- V(ArrayCode, BUILTIN, UNINITIALIZED) \
- V(ArrayConstructCode, BUILTIN, UNINITIALIZED) \
+ V(ArrayCode, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
+ V(ArrayConstructCode, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
\
- V(StringConstructCode, BUILTIN, UNINITIALIZED) \
+ V(StringConstructCode, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState) \
\
- V(OnStackReplacement, BUILTIN, UNINITIALIZED)
+ V(OnStackReplacement, BUILTIN, UNINITIALIZED, \
+ Code::kNoExtraICState)
#ifdef ENABLE_DEBUGGER_SUPPORT
// Define list of builtins used by the debugger implemented in assembly.
#define BUILTIN_LIST_DEBUG_A(V) \
- V(Return_DebugBreak, BUILTIN, DEBUG_BREAK) \
- V(ConstructCall_DebugBreak, BUILTIN, DEBUG_BREAK) \
- V(StubNoRegisters_DebugBreak, BUILTIN, DEBUG_BREAK) \
- V(LoadIC_DebugBreak, LOAD_IC, DEBUG_BREAK) \
- V(KeyedLoadIC_DebugBreak, KEYED_LOAD_IC, DEBUG_BREAK) \
- V(StoreIC_DebugBreak, STORE_IC, DEBUG_BREAK) \
- V(KeyedStoreIC_DebugBreak, KEYED_STORE_IC, DEBUG_BREAK) \
- V(Slot_DebugBreak, BUILTIN, DEBUG_BREAK) \
- V(PlainReturn_LiveEdit, BUILTIN, DEBUG_BREAK) \
- V(FrameDropper_LiveEdit, BUILTIN, DEBUG_BREAK)
+ V(Return_DebugBreak, BUILTIN, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(ConstructCall_DebugBreak, BUILTIN, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(StubNoRegisters_DebugBreak, BUILTIN, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(LoadIC_DebugBreak, LOAD_IC, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(KeyedLoadIC_DebugBreak, KEYED_LOAD_IC, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(StoreIC_DebugBreak, STORE_IC, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(KeyedStoreIC_DebugBreak, KEYED_STORE_IC, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(Slot_DebugBreak, BUILTIN, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(PlainReturn_LiveEdit, BUILTIN, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(FrameDropper_LiveEdit, BUILTIN, DEBUG_BREAK, \
+ Code::kNoExtraICState)
#else
#define BUILTIN_LIST_DEBUG_A(V)
#endif
enum Name {
#define DEF_ENUM_C(name, ignore) name,
-#define DEF_ENUM_A(name, kind, state) name,
+#define DEF_ENUM_A(name, kind, state, extra) name,
BUILTIN_LIST_C(DEF_ENUM_C)
BUILTIN_LIST_A(DEF_ENUM_A)
BUILTIN_LIST_DEBUG_A(DEF_ENUM_A)
flags_ |= IsGlobal::encode(true);
}
void MarkAsStrict() {
- ASSERT(!is_lazy());
flags_ |= IsStrict::encode(true);
}
StrictModeFlag StrictMode() {
void Initialize(Mode mode) {
mode_ = V8::UseCrankshaft() ? mode : NONOPT;
+ if (!shared_info_.is_null() && shared_info_->strict_mode()) {
+ MarkAsStrict();
+ }
}
void SetMode(Mode mode) {
Handle<Script> script() { return info_->script(); }
bool is_eval() { return info_->is_eval(); }
+ bool is_strict() { return function()->strict_mode(); }
StrictModeFlag strict_mode_flag() {
- return function()->strict_mode() ? kStrictMode : kNonStrictMode;
+ return is_strict() ? kStrictMode : kNonStrictMode;
}
FunctionLiteral* function() { return info_->function(); }
Scope* scope() { return info_->scope(); }
Load(property->value());
if (property->emit_store()) {
Result ignored =
- frame_->CallStoreIC(Handle<String>::cast(key), false);
+ frame_->CallStoreIC(Handle<String>::cast(key), false,
+ strict_mode_flag());
// A test eax instruction following the store IC call would
// indicate the presence of an inlined version of the
// store. Add a nop to indicate that there is no such
Result result;
if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) {
- result = frame()->CallStoreIC(name, is_contextual);
+ result = frame()->CallStoreIC(name, is_contextual, strict_mode_flag());
// A test eax instruction following the call signals that the inobject
// property case was inlined. Ensure that there is not a test eax
// instruction here.
slow.Bind(&value, &receiver);
frame()->Push(&receiver);
frame()->Push(&value);
- result = frame()->CallStoreIC(name, is_contextual);
+ result = frame()->CallStoreIC(name, is_contextual, strict_mode_flag());
// Encode the offset to the map check instruction and the offset
// to the write barrier store address computation in a test eax
// instruction.
// ecx, and the global object on the stack.
__ mov(ecx, var->name());
__ mov(edx, GlobalObjectOperand());
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
- EmitCallIC(ic, RelocInfo::CODE_TARGET);
+ Handle<Code> ic(Builtins::builtin(
+ is_strict() ? Builtins::StoreIC_Initialize_Strict
+ : Builtins::StoreIC_Initialize));
+ EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) {
// Like var declarations, const declarations are hoisted to function
}
-void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
+void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
+ Code::ExtraICState extra_ic_state) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : name
Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
NOT_IN_LOOP,
- MONOMORPHIC);
+ MONOMORPHIC,
+ extra_ic_state);
StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
// Cache miss: Jump to runtime.
}
-Result VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) {
+Result VirtualFrame::CallStoreIC(Handle<String> name,
+ bool is_contextual,
+ 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<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+ Handle<Code> ic(Builtins::builtin(strict_mode == kStrictMode
+ ? Builtins::StoreIC_Initialize_Strict
+ : Builtins::StoreIC_Initialize));
+
Result value = Pop();
+ RelocInfo::Mode mode;
if (is_contextual) {
PrepareForCall(0, 0);
value.ToRegister(eax);
__ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
value.Unuse();
+ mode = RelocInfo::CODE_TARGET_CONTEXT;
} else {
Result receiver = Pop();
PrepareForCall(0, 0);
MoveResultsToRegisters(&value, &receiver, eax, edx);
+ mode = RelocInfo::CODE_TARGET;
}
__ mov(ecx, name);
- return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
+ return RawCallCodeObject(ic, mode);
}
// Call store IC. If the load is contextual, value is found on top of the
// frame. If not, value and receiver are on the frame. Both are dropped.
- Result CallStoreIC(Handle<String> name, bool is_contextual);
+ Result CallStoreIC(Handle<String> name, bool is_contextual,
+ StrictModeFlag strict_mode);
// Call keyed store IC. Value, key, and receiver are found on top
// of the frame. All three are dropped.
void StoreIC::Clear(Address address, Code* target) {
if (target->ic_state() == UNINITIALIZED) return;
ClearInlinedVersion(address);
- SetTargetAtAddress(address, initialize_stub());
+ SetTargetAtAddress(address,
+ target->extra_ic_state() == kStoreICStrict
+ ? initialize_stub_strict()
+ : initialize_stub());
}
MaybeObject* StoreIC::Store(State state,
+ Code::ExtraICState extra_ic_state,
Handle<Object> object,
Handle<String> name,
Handle<Object> value) {
#ifdef DEBUG
if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n");
#endif
- Code* target = Builtins::builtin(Builtins::StoreIC_ArrayLength);
- set_target(target);
+ Builtins::Name target = (extra_ic_state == kStoreICStrict)
+ ? Builtins::StoreIC_ArrayLength_Strict
+ : Builtins::StoreIC_ArrayLength;
+ set_target(Builtins::builtin(target));
return receiver->SetProperty(*name, *value, NONE);
}
// If no inlined store ic was patched, generate a stub for this
// store.
- UpdateCaches(&lookup, state, receiver, name, value);
+ UpdateCaches(&lookup, state, extra_ic_state, 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);
+ }
}
}
if (receiver->IsJSGlobalProxy()) {
// Generate a generic stub that goes to the runtime when we see a global
// proxy as receiver.
- if (target() != global_proxy_stub()) {
- set_target(global_proxy_stub());
+ Code* stub = (extra_ic_state == kStoreICStrict)
+ ? global_proxy_stub_strict()
+ : global_proxy_stub();
+ if (target() != stub) {
+ set_target(stub);
#ifdef DEBUG
TraceIC("StoreIC", name, state, target());
#endif
void StoreIC::UpdateCaches(LookupResult* lookup,
State state,
+ Code::ExtraICState extra_ic_state,
Handle<JSObject> receiver,
Handle<String> name,
Handle<Object> value) {
Object* code = NULL;
switch (type) {
case FIELD: {
- maybe_code = StubCache::ComputeStoreField(*name, *receiver,
- lookup->GetFieldIndex());
+ maybe_code = StubCache::ComputeStoreField(
+ *name, *receiver, lookup->GetFieldIndex(), NULL, extra_ic_state);
break;
}
case MAP_TRANSITION: {
ASSERT(type == MAP_TRANSITION);
Handle<Map> transition(lookup->GetTransitionMap());
int index = transition->PropertyIndexFor(*name);
- maybe_code = StubCache::ComputeStoreField(*name, *receiver,
- index, *transition);
+ maybe_code = StubCache::ComputeStoreField(
+ *name, *receiver, index, *transition, extra_ic_state);
break;
}
case NORMAL: {
Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
JSGlobalPropertyCell* cell =
JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
- maybe_code = StubCache::ComputeStoreGlobal(*name, *global, cell);
+ maybe_code = StubCache::ComputeStoreGlobal(
+ *name, *global, cell, extra_ic_state);
} else {
if (lookup->holder() != *receiver) return;
- maybe_code = StubCache::ComputeStoreNormal();
+ maybe_code = StubCache::ComputeStoreNormal(extra_ic_state);
}
break;
}
if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
if (v8::ToCData<Address>(callback->setter()) == 0) return;
- maybe_code = StubCache::ComputeStoreCallback(*name, *receiver, callback);
+ maybe_code = StubCache::ComputeStoreCallback(
+ *name, *receiver, callback, extra_ic_state);
break;
}
case INTERCEPTOR: {
ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined());
- maybe_code = StubCache::ComputeStoreInterceptor(*name, *receiver);
+ maybe_code = StubCache::ComputeStoreInterceptor(
+ *name, *receiver, extra_ic_state);
break;
}
default:
set_target(Code::cast(code));
} else if (state == MONOMORPHIC) {
// Only move to megamorphic if the target changes.
- if (target() != Code::cast(code)) set_target(megamorphic_stub());
+ if (target() != Code::cast(code)) {
+ set_target(extra_ic_state == kStoreICStrict
+ ? megamorphic_stub_strict()
+ : megamorphic_stub());
+ }
} else if (state == MEGAMORPHIC) {
// Update the stub cache.
StubCache::Set(*name, receiver->map(), Code::cast(code));
ASSERT(args.length() == 3);
StoreIC ic;
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
- return ic.Store(state, args.at<Object>(0), args.at<String>(1),
- args.at<Object>(2));
+ Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
+ return ic.Store(state, extra_ic_state, args.at<Object>(0),
+ args.at<String>(1), args.at<Object>(2));
}
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,
Handle<Object> object,
Handle<String> name,
Handle<Object> value);
// Code generators for stub routines. Only called once at startup.
static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
static void GenerateMiss(MacroAssembler* masm);
- static void GenerateMegamorphic(MacroAssembler* masm);
+ static void GenerateMegamorphic(MacroAssembler* masm,
+ Code::ExtraICState extra_ic_state);
static void GenerateArrayLength(MacroAssembler* masm);
static void GenerateNormal(MacroAssembler* masm);
static void GenerateGlobalProxy(MacroAssembler* masm);
// Update the inline cache and the global stub cache based on the
// lookup result.
void UpdateCaches(LookupResult* lookup,
- State state, Handle<JSObject> receiver,
+ State state,
+ Code::ExtraICState extra_ic_state,
+ Handle<JSObject> receiver,
Handle<String> name,
Handle<Object> value);
static Code* megamorphic_stub() {
return Builtins::builtin(Builtins::StoreIC_Megamorphic);
}
+ static Code* megamorphic_stub_strict() {
+ return Builtins::builtin(Builtins::StoreIC_Megamorphic_Strict);
+ }
static Code* initialize_stub() {
return Builtins::builtin(Builtins::StoreIC_Initialize);
}
+ static Code* initialize_stub_strict() {
+ return Builtins::builtin(Builtins::StoreIC_Initialize_Strict);
+ }
static Code* global_proxy_stub() {
return Builtins::builtin(Builtins::StoreIC_GlobalProxy);
}
+ static Code* global_proxy_stub_strict() {
+ return Builtins::builtin(Builtins::StoreIC_GlobalProxy_Strict);
+ }
static void Clear(Address address, Code* target);
PropertyType type,
int argc,
InlineCacheHolderFlag holder) {
- // Extra IC state is only allowed for monomorphic call IC stubs.
+ // Extra IC state is only allowed for monomorphic call IC stubs
+ // or for store IC stubs.
ASSERT(extra_ic_state == kNoExtraICState ||
(kind == CALL_IC && (ic_state == MONOMORPHIC ||
- ic_state == MONOMORPHIC_PROTOTYPE_FAILURE)));
+ ic_state == MONOMORPHIC_PROTOTYPE_FAILURE)) ||
+ (kind == STORE_IC));
// Compute the bit mask.
int bits = kind << kFlagsKindShift;
if (in_loop) bits |= kFlagsICInLoopMask;
}
+void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
+ const char* name = NULL;
+ switch (kind) {
+ case CALL_IC:
+ if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
+ name = "STRING_INDEX_OUT_OF_BOUNDS";
+ }
+ break;
+ case STORE_IC:
+ if (extra == StoreIC::kStoreICStrict) {
+ name = "STRICT";
+ }
+ break;
+ default:
+ break;
+ }
+ if (name != NULL) {
+ PrintF(out, "extra_ic_state = %s\n", name);
+ } else {
+ PrintF(out, "etra_ic_state = %d\n", extra);
+ }
+}
+
+
void Code::Disassemble(const char* name, FILE* out) {
PrintF(out, "kind = %s\n", Kind2String(kind()));
if (is_inline_cache_stub()) {
PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
+ PrintExtraICState(out, kind(), extra_ic_state());
PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
if (ic_state() == MONOMORPHIC) {
PrintF(out, "type = %s\n", PropertyType2String(type()));
static const char* Kind2String(Kind kind);
static const char* ICState2String(InlineCacheState state);
static const char* PropertyType2String(PropertyType type);
+ static void PrintExtraICState(FILE* out, Kind kind, ExtraICState extra);
inline void Disassemble(const char* name) {
Disassemble(name, stdout);
}
{ BUILTIN, \
Builtins::name, \
"Builtins::" #name },
-#define DEF_ENTRY_A(name, kind, state) DEF_ENTRY_C(name, ignored)
+#define DEF_ENTRY_A(name, kind, state, extra) DEF_ENTRY_C(name, ignored)
BUILTIN_LIST_C(DEF_ENTRY_C)
BUILTIN_LIST_A(DEF_ENTRY_A)
MaybeObject* StubCache::ComputeStoreField(String* name,
JSObject* receiver,
int field_index,
- Map* transition) {
+ Map* transition,
+ Code::ExtraICState extra_ic_state) {
PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
- Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
+ Code::Flags flags = Code::ComputeMonomorphicFlags(
+ Code::STORE_IC, type, extra_ic_state);
Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
- StoreStubCompiler compiler;
+ StoreStubCompiler compiler(extra_ic_state);
{ MaybeObject* maybe_code =
compiler.CompileStoreField(receiver, field_index, transition, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
-MaybeObject* StubCache::ComputeStoreNormal() {
- return Builtins::builtin(Builtins::StoreIC_Normal);
+MaybeObject* StubCache::ComputeStoreNormal(Code::ExtraICState extra_ic_state) {
+ return Builtins::builtin(extra_ic_state == StoreIC::kStoreICStrict
+ ? Builtins::StoreIC_Normal_Strict
+ : Builtins::StoreIC_Normal);
}
MaybeObject* StubCache::ComputeStoreGlobal(String* name,
GlobalObject* receiver,
- JSGlobalPropertyCell* cell) {
- Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL);
+ JSGlobalPropertyCell* cell,
+ Code::ExtraICState extra_ic_state) {
+ Code::Flags flags = Code::ComputeMonomorphicFlags(
+ Code::STORE_IC, NORMAL, extra_ic_state);
Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
- StoreStubCompiler compiler;
+ StoreStubCompiler compiler(extra_ic_state);
{ MaybeObject* maybe_code =
compiler.CompileStoreGlobal(receiver, cell, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
-MaybeObject* StubCache::ComputeStoreCallback(String* name,
- JSObject* receiver,
- AccessorInfo* callback) {
+MaybeObject* StubCache::ComputeStoreCallback(
+ String* name,
+ JSObject* receiver,
+ AccessorInfo* callback,
+ Code::ExtraICState extra_ic_state) {
ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
- Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, CALLBACKS);
+ Code::Flags flags = Code::ComputeMonomorphicFlags(
+ Code::STORE_IC, CALLBACKS, extra_ic_state);
Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
- StoreStubCompiler compiler;
+ StoreStubCompiler compiler(extra_ic_state);
{ MaybeObject* maybe_code =
compiler.CompileStoreCallback(receiver, callback, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
-MaybeObject* StubCache::ComputeStoreInterceptor(String* name,
- JSObject* receiver) {
- Code::Flags flags =
- Code::ComputeMonomorphicFlags(Code::STORE_IC, INTERCEPTOR);
+MaybeObject* StubCache::ComputeStoreInterceptor(
+ String* name,
+ JSObject* receiver,
+ Code::ExtraICState extra_ic_state) {
+ Code::Flags flags = Code::ComputeMonomorphicFlags(
+ Code::STORE_IC, INTERCEPTOR, extra_ic_state);
Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
- StoreStubCompiler compiler;
+ StoreStubCompiler compiler(extra_ic_state);
{ MaybeObject* maybe_code =
compiler.CompileStoreInterceptor(receiver, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
- Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
+ Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type,
+ extra_ic_state_);
MaybeObject* result = GetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG,
// ---
- MUST_USE_RESULT static MaybeObject* ComputeStoreField(String* name,
- JSObject* receiver,
- int field_index,
- Map* transition = NULL);
+ MUST_USE_RESULT static MaybeObject* ComputeStoreField(
+ String* name,
+ JSObject* receiver,
+ int field_index,
+ Map* transition,
+ Code::ExtraICState extra_ic_state);
- MUST_USE_RESULT static MaybeObject* ComputeStoreNormal();
+ MUST_USE_RESULT static MaybeObject* ComputeStoreNormal(
+ Code::ExtraICState extra_ic_state);
MUST_USE_RESULT static MaybeObject* ComputeStoreGlobal(
String* name,
GlobalObject* receiver,
- JSGlobalPropertyCell* cell);
+ JSGlobalPropertyCell* cell,
+ Code::ExtraICState extra_ic_state);
MUST_USE_RESULT static MaybeObject* ComputeStoreCallback(
String* name,
JSObject* receiver,
- AccessorInfo* callback);
+ AccessorInfo* callback,
+ Code::ExtraICState extra_ic_state);
MUST_USE_RESULT static MaybeObject* ComputeStoreInterceptor(
String* name,
- JSObject* receiver);
+ JSObject* receiver,
+ Code::ExtraICState extra_ic_state);
// ---
class StoreStubCompiler: public StubCompiler {
public:
+ StoreStubCompiler(Code::ExtraICState extra_ic_state)
+ : extra_ic_state_(extra_ic_state) { }
+
MUST_USE_RESULT MaybeObject* CompileStoreField(JSObject* object,
int index,
Map* transition,
private:
MaybeObject* GetCode(PropertyType type, String* name);
+
+ Code::ExtraICState extra_ic_state_;
};
Load(property->value());
if (property->emit_store()) {
Result ignored =
- frame_->CallStoreIC(Handle<String>::cast(key), false);
+ frame_->CallStoreIC(Handle<String>::cast(key), false,
+ strict_mode_flag());
// A test rax instruction following the store IC call would
// indicate the presence of an inlined version of the
// store. Add a nop to indicate that there is no such
Result result;
if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) {
- result = frame()->CallStoreIC(name, is_contextual);
+ result = frame()->CallStoreIC(name, is_contextual, strict_mode_flag());
// A test rax instruction following the call signals that the inobject
// property case was inlined. Ensure that there is not a test rax
// instruction here.
slow.Bind(&value, &receiver);
frame()->Push(&receiver);
frame()->Push(&value);
- result = frame()->CallStoreIC(name, is_contextual);
+ result = frame()->CallStoreIC(name, is_contextual, strict_mode_flag());
// Encode the offset to the map check instruction and the offset
// to the write barrier store address computation in a test rax
// instruction.
// rcx, and the global object on the stack.
__ Move(rcx, var->name());
__ movq(rdx, GlobalObjectOperand());
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
- EmitCallIC(ic, RelocInfo::CODE_TARGET);
+ Handle<Code> ic(Builtins::builtin(is_strict()
+ ? Builtins::StoreIC_Initialize_Strict
+ : Builtins::StoreIC_Initialize));
+ EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) {
// Perform the assignment for non-const variables and for initialization
}
-void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
+void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
+ Code::ExtraICState extra_ic_state) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : name
// Get the receiver from the stack and probe the stub cache.
Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
NOT_IN_LOOP,
- MONOMORPHIC);
+ MONOMORPHIC,
+ extra_ic_state);
StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg);
// Cache miss: Jump to runtime.
}
-Result VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) {
+Result VirtualFrame::CallStoreIC(Handle<String> name,
+ bool is_contextual,
+ 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<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+ Handle<Code> ic(Builtins::builtin(strict_mode == kStrictMode
+ ? Builtins::StoreIC_Initialize_Strict
+ : Builtins::StoreIC_Initialize));
Result value = Pop();
+ RelocInfo::Mode mode;
if (is_contextual) {
PrepareForCall(0, 0);
value.ToRegister(rax);
__ movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
value.Unuse();
+ mode = RelocInfo::CODE_TARGET_CONTEXT;
} else {
Result receiver = Pop();
PrepareForCall(0, 0);
MoveResultsToRegisters(&value, &receiver, rax, rdx);
+ mode = RelocInfo::CODE_TARGET;
}
__ Move(rcx, name);
- return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
+ return RawCallCodeObject(ic, mode);
}
// Call store IC. If the load is contextual, value is found on top of the
// frame. If not, value and receiver are on the frame. Both are dropped.
- Result CallStoreIC(Handle<String> name, bool is_contextual);
+ Result CallStoreIC(Handle<String> name, bool is_contextual,
+ StrictModeFlag strict_mode);
// Call keyed store IC. Value, key, and receiver are found on top
// of the frame. All three are dropped.
CheckDebugBreakFunction(&env,
"function f2(){x=1;}", "f2",
0,
- v8::internal::RelocInfo::CODE_TARGET,
+ v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
Builtins::builtin(Builtins::StoreIC_DebugBreak));
CheckDebugBreakFunction(&env,
"function f3(){var a=x;}", "f3",
# arguments.callee is non-configurable in strict mode
chapter10/10.6/10.6-13-c-3-s: FAIL
-# simple assignment throws ReferenceError if LeftHandSide is an unresolvable
-# reference in strict mode
-chapter11/11.13/11.13.1/11.13.1-1-5-s: FAIL
# simple assignment throws TypeError if LeftHandSide is a property reference
# with a primitive base value (this is undefined)
chapter11/11.13/11.13.1/11.13.1-1-7-s: FAIL
testFutureReservedWord(future_reserved_words[i]);
}
+function testAssignToUndefined(should_throw) {
+ "use strict";
+ try {
+ possibly_undefined_variable_for_strict_mode_test = "should throw?";
+ } catch (e) {
+ assertTrue(should_throw, "strict mode");
+ assertInstanceof(e, ReferenceError, "strict mode");
+ return;
+ }
+ assertFalse(should_throw, "strict mode");
+}
+
+testAssignToUndefined(true);
+testAssignToUndefined(true);
+testAssignToUndefined(true);
+
+possibly_undefined_variable_for_strict_mode_test = "value";
+
+testAssignToUndefined(false);
+testAssignToUndefined(false);
+testAssignToUndefined(false);
+
+delete possibly_undefined_variable_for_strict_mode_test;
+
+testAssignToUndefined(true);
+testAssignToUndefined(true);
+testAssignToUndefined(true);
+
+function repeat(n, f) {
+ for (var i = 0; i < n; i ++) { f(); }
+}
+repeat(10, function() { testAssignToUndefined(true); });
+possibly_undefined_variable_for_strict_mode_test = "value";
+repeat(10, function() { testAssignToUndefined(false); });
+delete possibly_undefined_variable_for_strict_mode_test;
+repeat(10, function() { testAssignToUndefined(true); });
+possibly_undefined_variable_for_strict_mode_test = undefined;
+repeat(10, function() { testAssignToUndefined(false); });
893E248E12B14B3D0083370F /* hydrogen-instructions.h */,
893E248F12B14B3D0083370F /* hydrogen.cc */,
893E249012B14B3D0083370F /* hydrogen.h */,
- 897FF1490E719B8F00D62E90 /* ic-arm.cc */,
897FF14B0E719B8F00D62E90 /* ic-inl.h */,
897FF14C0E719B8F00D62E90 /* ic.cc */,
897FF14D0E719B8F00D62E90 /* ic.h */,
897FF1890E719B8F00D62E90 /* string-stream.h */,
893E24A312B14B3D0083370F /* strtod.cc */,
893E24A412B14B3D0083370F /* strtod.h */,
- 897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */,
897FF18C0E719B8F00D62E90 /* stub-cache.cc */,
897FF18D0E719B8F00D62E90 /* stub-cache.h */,
897FF18E0E719B8F00D62E90 /* token.cc */,
898BD20C0EF6CC850068B00A /* debug-arm.cc */,
893E24C612B14B510083370F /* deoptimizer-arm.cc */,
9FA38BCB1175B30400C4CD55 /* full-codegen-arm.cc */,
+ 897FF1490E719B8F00D62E90 /* ic-arm.cc */,
9FA38BCC1175B30400C4CD55 /* jump-target-arm.cc */,
893E24C712B14B510083370F /* lithium-arm.cc */,
893E24C812B14B510083370F /* lithium-arm.h */,
895FA751107FFEAE006F39D4 /* register-allocator-arm.h */,
897FF17D0E719B8F00D62E90 /* simulator-arm.cc */,
897FF17E0E719B8F00D62E90 /* simulator-arm.h */,
+ 897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */,
893E24CB12B14B520083370F /* virtual-frame-arm-inl.h */,
9FA38BCD1175B30400C4CD55 /* virtual-frame-arm.cc */,
58950D570F55514900F3E8BA /* virtual-frame-arm.h */,