Implement assignment to undefined reference in ES5 Strict Mode.

Strict mode assignment to undefined reference.
Simple assignments (x = <value>) use CODE_TARGET_CONTEXT.
StoreIC stores its own strictness in extra_ic_state.
The strcitness is propagated as further ic stubs are generated.

Details:
* ReferenceError on assignment to non-resolvable reference in strict mode.
* Fix es5conform test expectation file.
* Add es5conform test suite into .gitignore.
* Fix Xcode project.
* Change implemented in virtual frame code generator, as well as full-codegen
  for all architectures.
* Fix debugger test.
* Fix comment for CODE_TARGET_CONTEXT
* Implement remaining StoreIC stubs to be strict mode aware.
* Trace extra_ic_state() for ic code stubs.

Code Review URL: http://codereview.chromium.org/6474026/

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6760 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mmaly@chromium.org 2011-02-13 16:19:53 +00:00
parent 26df17e714
commit e0be3072b5
34 changed files with 411 additions and 151 deletions

1
.gitignore vendored
View File

@ -20,6 +20,7 @@ d8_g
shell shell
shell_g shell_g
/obj/ /obj/
/test/es5conform/data/
/test/sputnik/sputniktests/ /test/sputnik/sputniktests/
/tools/oom_dump/oom_dump /tools/oom_dump/oom_dump
/tools/oom_dump/oom_dump.o /tools/oom_dump/oom_dump.o

View File

@ -6926,7 +6926,7 @@ void CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
Result result; Result result;
if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) { if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) {
frame()->CallStoreIC(name, is_contextual); frame()->CallStoreIC(name, is_contextual, strict_mode_flag());
} else { } else {
// Inline the in-object property case. // Inline the in-object property case.
JumpTarget slow, done; JumpTarget slow, done;

View File

@ -1685,8 +1685,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
// r2, and the global object in r1. // r2, and the global object in r1.
__ mov(r2, Operand(var->name())); __ mov(r2, Operand(var->name()));
__ ldr(r1, GlobalObjectOperand()); __ ldr(r1, GlobalObjectOperand());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(is_strict()
EmitCallIC(ic, RelocInfo::CODE_TARGET); ? Builtins::StoreIC_Initialize_Strict
: Builtins::StoreIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) {
// Perform the assignment for non-const variables and for initialization // Perform the assignment for non-const variables and for initialization

View File

@ -1533,7 +1533,8 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
} }
void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
Code::ExtraICState extra_ic_state) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r0 : value // -- r0 : value
// -- r1 : receiver // -- r1 : receiver
@ -1544,7 +1545,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
// Get the receiver from the stack and probe the stub cache. // Get the receiver from the stack and probe the stub cache.
Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
NOT_IN_LOOP, NOT_IN_LOOP,
MONOMORPHIC); MONOMORPHIC,
extra_ic_state);
StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5); StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
// Cache miss: Jump to runtime. // Cache miss: Jump to runtime.

View File

@ -2944,7 +2944,9 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
// Name is always in r2. // Name is always in r2.
__ mov(r2, Operand(instr->name())); __ 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); CallCode(ic, RelocInfo::CODE_TARGET, instr);
} }

View File

@ -329,18 +329,25 @@ void VirtualFrame::CallLoadIC(Handle<String> name, RelocInfo::Mode mode) {
} }
void VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) { void VirtualFrame::CallStoreIC(Handle<String> name,
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); bool is_contextual,
StrictModeFlag strict_mode) {
Handle<Code> ic(Builtins::builtin(strict_mode == kStrictMode
? Builtins::StoreIC_Initialize_Strict
: Builtins::StoreIC_Initialize));
PopToR0(); PopToR0();
RelocInfo::Mode mode;
if (is_contextual) { if (is_contextual) {
SpillAll(); SpillAll();
__ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); __ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
mode = RelocInfo::CODE_TARGET_CONTEXT;
} else { } else {
EmitPop(r1); EmitPop(r1);
SpillAll(); SpillAll();
mode = RelocInfo::CODE_TARGET;
} }
__ mov(r2, Operand(name)); __ mov(r2, Operand(name));
CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); CallCodeObject(ic, mode, 0);
} }

View File

@ -294,7 +294,8 @@ class VirtualFrame : public ZoneObject {
// Call store IC. If the load is contextual, value is found on top of the // 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. // frame. If not, value and receiver are on the frame. Both are consumed.
// Result is returned in r0. // 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. // Call keyed load IC. Key and receiver are on the stack. Both are consumed.
// Result is returned in r0. // Result is returned in r0.

View File

@ -181,7 +181,7 @@ class RelocInfo BASE_EMBEDDED {
enum Mode { enum Mode {
// Please note the order is important (see IsCodeTarget, IsGCRelocMode). // Please note the order is important (see IsCodeTarget, IsGCRelocMode).
CONSTRUCT_CALL, // code target that is a call to a JavaScript constructor. 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. DEBUG_BREAK, // Code target for the debugger statement.
CODE_TARGET, // Code target which is not any of the above. CODE_TARGET, // Code target which is not any of the above.
EMBEDDED_OBJECT, EMBEDDED_OBJECT,

View File

@ -1307,6 +1307,11 @@ static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
} }
static void Generate_StoreIC_Initialize_Strict(MacroAssembler* masm) {
StoreIC::GenerateInitialize(masm);
}
static void Generate_StoreIC_Miss(MacroAssembler* masm) { static void Generate_StoreIC_Miss(MacroAssembler* masm) {
StoreIC::GenerateMiss(masm); StoreIC::GenerateMiss(masm);
} }
@ -1317,8 +1322,18 @@ static void Generate_StoreIC_Normal(MacroAssembler* masm) {
} }
static void Generate_StoreIC_Normal_Strict(MacroAssembler* masm) {
StoreIC::GenerateNormal(masm);
}
static void Generate_StoreIC_Megamorphic(MacroAssembler* 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);
} }
@ -1327,11 +1342,21 @@ static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
} }
static void Generate_StoreIC_ArrayLength_Strict(MacroAssembler* masm) {
StoreIC::GenerateArrayLength(masm);
}
static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) { static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) {
StoreIC::GenerateGlobalProxy(masm); StoreIC::GenerateGlobalProxy(masm);
} }
static void Generate_StoreIC_GlobalProxy_Strict(MacroAssembler* masm) {
StoreIC::GenerateGlobalProxy(masm);
}
static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) { static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
KeyedStoreIC::GenerateGeneric(masm); KeyedStoreIC::GenerateGeneric(masm);
} }
@ -1444,13 +1469,13 @@ void Builtins::Setup(bool create_heap_objects) {
extra_args \ extra_args \
}, },
#define DEF_FUNCTION_PTR_A(name, kind, state) \ #define DEF_FUNCTION_PTR_A(name, kind, state, extra) \
{ FUNCTION_ADDR(Generate_##name), \ { FUNCTION_ADDR(Generate_##name), \
NULL, \ NULL, \
#name, \ #name, \
name, \ name, \
Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state), \ Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state, extra), \
NO_EXTRA_ARGUMENTS \ NO_EXTRA_ARGUMENTS \
}, },
// Define array of pointers to generators and C builtin functions. // Define array of pointers to generators and C builtin functions.

View File

@ -63,73 +63,135 @@ enum BuiltinExtraArguments {
// Define list of builtins implemented in assembly. // Define list of builtins implemented in assembly.
#define BUILTIN_LIST_A(V) \ #define BUILTIN_LIST_A(V) \
V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED) \ V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED, \
V(JSConstructCall, BUILTIN, UNINITIALIZED) \ Code::kNoExtraICState) \
V(JSConstructStubCountdown, BUILTIN, UNINITIALIZED) \ V(JSConstructCall, BUILTIN, UNINITIALIZED, \
V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED) \ Code::kNoExtraICState) \
V(JSConstructStubApi, BUILTIN, UNINITIALIZED) \ V(JSConstructStubCountdown, BUILTIN, UNINITIALIZED, \
V(JSEntryTrampoline, BUILTIN, UNINITIALIZED) \ Code::kNoExtraICState) \
V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED) \ V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED, \
V(LazyCompile, BUILTIN, UNINITIALIZED) \ Code::kNoExtraICState) \
V(LazyRecompile, BUILTIN, UNINITIALIZED) \ V(JSConstructStubApi, BUILTIN, UNINITIALIZED, \
V(NotifyDeoptimized, BUILTIN, UNINITIALIZED) \ Code::kNoExtraICState) \
V(NotifyLazyDeoptimized, BUILTIN, UNINITIALIZED) \ V(JSEntryTrampoline, BUILTIN, UNINITIALIZED, \
V(NotifyOSR, 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(LoadIC_Miss, BUILTIN, UNINITIALIZED, \
V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED) \ Code::kNoExtraICState) \
V(StoreIC_Miss, BUILTIN, UNINITIALIZED) \ V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED, \
V(KeyedStoreIC_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_Initialize, LOAD_IC, UNINITIALIZED, \
V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC) \ Code::kNoExtraICState) \
V(LoadIC_Normal, LOAD_IC, MONOMORPHIC) \ V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC, \
V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC) \ Code::kNoExtraICState) \
V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC) \ V(LoadIC_Normal, LOAD_IC, MONOMORPHIC, \
V(LoadIC_StringWrapperLength, LOAD_IC, MONOMORPHIC) \ Code::kNoExtraICState) \
V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC) \ V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC, \
V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC) \ 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_Initialize, KEYED_LOAD_IC, UNINITIALIZED, \
V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC) \ Code::kNoExtraICState) \
V(KeyedLoadIC_Generic, KEYED_LOAD_IC, MEGAMORPHIC) \ V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC, \
V(KeyedLoadIC_String, KEYED_LOAD_IC, MEGAMORPHIC) \ Code::kNoExtraICState) \
V(KeyedLoadIC_IndexedInterceptor, KEYED_LOAD_IC, MEGAMORPHIC) \ 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_Initialize, STORE_IC, UNINITIALIZED, \
V(StoreIC_ArrayLength, STORE_IC, MONOMORPHIC) \ Code::kNoExtraICState) \
V(StoreIC_Normal, STORE_IC, MONOMORPHIC) \ V(StoreIC_ArrayLength, STORE_IC, MONOMORPHIC, \
V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC) \ Code::kNoExtraICState) \
V(StoreIC_GlobalProxy, STORE_IC, MEGAMORPHIC) \ 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_Initialize, KEYED_STORE_IC, UNINITIALIZED, \
V(KeyedStoreIC_Generic, KEYED_STORE_IC, MEGAMORPHIC) \ Code::kNoExtraICState) \
V(KeyedStoreIC_Generic, KEYED_STORE_IC, MEGAMORPHIC, \
Code::kNoExtraICState) \
\ \
/* Uses KeyedLoadIC_Initialize; must be after in list. */ \ /* Uses KeyedLoadIC_Initialize; must be after in list. */ \
V(FunctionCall, BUILTIN, UNINITIALIZED) \ V(FunctionCall, BUILTIN, UNINITIALIZED, \
V(FunctionApply, BUILTIN, UNINITIALIZED) \ Code::kNoExtraICState) \
V(FunctionApply, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
\ \
V(ArrayCode, BUILTIN, UNINITIALIZED) \ V(ArrayCode, BUILTIN, UNINITIALIZED, \
V(ArrayConstructCode, 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 #ifdef ENABLE_DEBUGGER_SUPPORT
// Define list of builtins used by the debugger implemented in assembly. // Define list of builtins used by the debugger implemented in assembly.
#define BUILTIN_LIST_DEBUG_A(V) \ #define BUILTIN_LIST_DEBUG_A(V) \
V(Return_DebugBreak, BUILTIN, DEBUG_BREAK) \ V(Return_DebugBreak, BUILTIN, DEBUG_BREAK, \
V(ConstructCall_DebugBreak, BUILTIN, DEBUG_BREAK) \ Code::kNoExtraICState) \
V(StubNoRegisters_DebugBreak, BUILTIN, DEBUG_BREAK) \ V(ConstructCall_DebugBreak, BUILTIN, DEBUG_BREAK, \
V(LoadIC_DebugBreak, LOAD_IC, DEBUG_BREAK) \ Code::kNoExtraICState) \
V(KeyedLoadIC_DebugBreak, KEYED_LOAD_IC, DEBUG_BREAK) \ V(StubNoRegisters_DebugBreak, BUILTIN, DEBUG_BREAK, \
V(StoreIC_DebugBreak, STORE_IC, DEBUG_BREAK) \ Code::kNoExtraICState) \
V(KeyedStoreIC_DebugBreak, KEYED_STORE_IC, DEBUG_BREAK) \ V(LoadIC_DebugBreak, LOAD_IC, DEBUG_BREAK, \
V(Slot_DebugBreak, BUILTIN, DEBUG_BREAK) \ Code::kNoExtraICState) \
V(PlainReturn_LiveEdit, BUILTIN, DEBUG_BREAK) \ V(KeyedLoadIC_DebugBreak, KEYED_LOAD_IC, DEBUG_BREAK, \
V(FrameDropper_LiveEdit, BUILTIN, 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 #else
#define BUILTIN_LIST_DEBUG_A(V) #define BUILTIN_LIST_DEBUG_A(V)
#endif #endif
@ -186,7 +248,7 @@ class Builtins : public AllStatic {
enum Name { enum Name {
#define DEF_ENUM_C(name, ignore) 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_C(DEF_ENUM_C)
BUILTIN_LIST_A(DEF_ENUM_A) BUILTIN_LIST_A(DEF_ENUM_A)
BUILTIN_LIST_DEBUG_A(DEF_ENUM_A) BUILTIN_LIST_DEBUG_A(DEF_ENUM_A)

View File

@ -71,7 +71,6 @@ class CompilationInfo BASE_EMBEDDED {
flags_ |= IsGlobal::encode(true); flags_ |= IsGlobal::encode(true);
} }
void MarkAsStrict() { void MarkAsStrict() {
ASSERT(!is_lazy());
flags_ |= IsStrict::encode(true); flags_ |= IsStrict::encode(true);
} }
StrictModeFlag StrictMode() { StrictModeFlag StrictMode() {
@ -153,6 +152,9 @@ class CompilationInfo BASE_EMBEDDED {
void Initialize(Mode mode) { void Initialize(Mode mode) {
mode_ = V8::UseCrankshaft() ? mode : NONOPT; mode_ = V8::UseCrankshaft() ? mode : NONOPT;
if (!shared_info_.is_null() && shared_info_->strict_mode()) {
MarkAsStrict();
}
} }
void SetMode(Mode mode) { void SetMode(Mode mode) {

View File

@ -531,8 +531,9 @@ class FullCodeGenerator: public AstVisitor {
Handle<Script> script() { return info_->script(); } Handle<Script> script() { return info_->script(); }
bool is_eval() { return info_->is_eval(); } bool is_eval() { return info_->is_eval(); }
bool is_strict() { return function()->strict_mode(); }
StrictModeFlag strict_mode_flag() { StrictModeFlag strict_mode_flag() {
return function()->strict_mode() ? kStrictMode : kNonStrictMode; return is_strict() ? kStrictMode : kNonStrictMode;
} }
FunctionLiteral* function() { return info_->function(); } FunctionLiteral* function() { return info_->function(); }
Scope* scope() { return info_->scope(); } Scope* scope() { return info_->scope(); }

View File

@ -5588,7 +5588,8 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
Load(property->value()); Load(property->value());
if (property->emit_store()) { if (property->emit_store()) {
Result ignored = 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 // A test eax instruction following the store IC call would
// indicate the presence of an inlined version of the // indicate the presence of an inlined version of the
// store. Add a nop to indicate that there is no such // store. Add a nop to indicate that there is no such
@ -9671,7 +9672,7 @@ Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
Result result; Result result;
if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) { 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 // A test eax instruction following the call signals that the inobject
// property case was inlined. Ensure that there is not a test eax // property case was inlined. Ensure that there is not a test eax
// instruction here. // instruction here.
@ -9755,7 +9756,7 @@ Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
slow.Bind(&value, &receiver); slow.Bind(&value, &receiver);
frame()->Push(&receiver); frame()->Push(&receiver);
frame()->Push(&value); 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 // Encode the offset to the map check instruction and the offset
// to the write barrier store address computation in a test eax // to the write barrier store address computation in a test eax
// instruction. // instruction.

View File

@ -2013,8 +2013,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
// ecx, and the global object on the stack. // ecx, and the global object on the stack.
__ mov(ecx, var->name()); __ mov(ecx, var->name());
__ mov(edx, GlobalObjectOperand()); __ mov(edx, GlobalObjectOperand());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(
EmitCallIC(ic, RelocInfo::CODE_TARGET); is_strict() ? Builtins::StoreIC_Initialize_Strict
: Builtins::StoreIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) { } else if (op == Token::INIT_CONST) {
// Like var declarations, const declarations are hoisted to function // Like var declarations, const declarations are hoisted to function

View File

@ -1488,7 +1488,8 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
} }
void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
Code::ExtraICState extra_ic_state) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- eax : value // -- eax : value
// -- ecx : name // -- ecx : name
@ -1498,7 +1499,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
NOT_IN_LOOP, NOT_IN_LOOP,
MONOMORPHIC); MONOMORPHIC,
extra_ic_state);
StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg); StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
// Cache miss: Jump to runtime. // Cache miss: Jump to runtime.

View File

@ -1033,23 +1033,31 @@ Result VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) {
} }
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. // 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. // 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(); Result value = Pop();
RelocInfo::Mode mode;
if (is_contextual) { if (is_contextual) {
PrepareForCall(0, 0); PrepareForCall(0, 0);
value.ToRegister(eax); value.ToRegister(eax);
__ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
value.Unuse(); value.Unuse();
mode = RelocInfo::CODE_TARGET_CONTEXT;
} else { } else {
Result receiver = Pop(); Result receiver = Pop();
PrepareForCall(0, 0); PrepareForCall(0, 0);
MoveResultsToRegisters(&value, &receiver, eax, edx); MoveResultsToRegisters(&value, &receiver, eax, edx);
mode = RelocInfo::CODE_TARGET;
} }
__ mov(ecx, name); __ mov(ecx, name);
return RawCallCodeObject(ic, RelocInfo::CODE_TARGET); return RawCallCodeObject(ic, mode);
} }

View File

@ -365,7 +365,8 @@ class VirtualFrame: public ZoneObject {
// Call store IC. If the load is contextual, value is found on top of the // 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. // 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 // Call keyed store IC. Value, key, and receiver are found on top
// of the frame. All three are dropped. // of the frame. All three are dropped.

View File

@ -342,7 +342,10 @@ void StoreIC::ClearInlinedVersion(Address address) {
void StoreIC::Clear(Address address, Code* target) { void StoreIC::Clear(Address address, Code* target) {
if (target->ic_state() == UNINITIALIZED) return; if (target->ic_state() == UNINITIALIZED) return;
ClearInlinedVersion(address); ClearInlinedVersion(address);
SetTargetAtAddress(address, initialize_stub()); SetTargetAtAddress(address,
target->extra_ic_state() == kStoreICStrict
? initialize_stub_strict()
: initialize_stub());
} }
@ -1368,6 +1371,7 @@ static bool LookupForWrite(JSObject* object,
MaybeObject* StoreIC::Store(State state, MaybeObject* StoreIC::Store(State state,
Code::ExtraICState extra_ic_state,
Handle<Object> object, Handle<Object> object,
Handle<String> name, Handle<String> name,
Handle<Object> value) { Handle<Object> value) {
@ -1397,8 +1401,10 @@ MaybeObject* StoreIC::Store(State state,
#ifdef DEBUG #ifdef DEBUG
if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n");
#endif #endif
Code* target = Builtins::builtin(Builtins::StoreIC_ArrayLength); Builtins::Name target = (extra_ic_state == kStoreICStrict)
set_target(target); ? Builtins::StoreIC_ArrayLength_Strict
: Builtins::StoreIC_ArrayLength;
set_target(Builtins::builtin(target));
return receiver->SetProperty(*name, *value, NONE); return receiver->SetProperty(*name, *value, NONE);
} }
@ -1456,15 +1462,23 @@ MaybeObject* StoreIC::Store(State state,
// If no inlined store ic was patched, generate a stub for this // If no inlined store ic was patched, generate a stub for this
// store. // 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()) { if (receiver->IsJSGlobalProxy()) {
// Generate a generic stub that goes to the runtime when we see a global // Generate a generic stub that goes to the runtime when we see a global
// proxy as receiver. // proxy as receiver.
if (target() != global_proxy_stub()) { Code* stub = (extra_ic_state == kStoreICStrict)
set_target(global_proxy_stub()); ? global_proxy_stub_strict()
: global_proxy_stub();
if (target() != stub) {
set_target(stub);
#ifdef DEBUG #ifdef DEBUG
TraceIC("StoreIC", name, state, target()); TraceIC("StoreIC", name, state, target());
#endif #endif
@ -1478,6 +1492,7 @@ MaybeObject* StoreIC::Store(State state,
void StoreIC::UpdateCaches(LookupResult* lookup, void StoreIC::UpdateCaches(LookupResult* lookup,
State state, State state,
Code::ExtraICState extra_ic_state,
Handle<JSObject> receiver, Handle<JSObject> receiver,
Handle<String> name, Handle<String> name,
Handle<Object> value) { Handle<Object> value) {
@ -1498,8 +1513,8 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
Object* code = NULL; Object* code = NULL;
switch (type) { switch (type) {
case FIELD: { case FIELD: {
maybe_code = StubCache::ComputeStoreField(*name, *receiver, maybe_code = StubCache::ComputeStoreField(
lookup->GetFieldIndex()); *name, *receiver, lookup->GetFieldIndex(), NULL, extra_ic_state);
break; break;
} }
case MAP_TRANSITION: { case MAP_TRANSITION: {
@ -1508,8 +1523,8 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
ASSERT(type == MAP_TRANSITION); ASSERT(type == MAP_TRANSITION);
Handle<Map> transition(lookup->GetTransitionMap()); Handle<Map> transition(lookup->GetTransitionMap());
int index = transition->PropertyIndexFor(*name); int index = transition->PropertyIndexFor(*name);
maybe_code = StubCache::ComputeStoreField(*name, *receiver, maybe_code = StubCache::ComputeStoreField(
index, *transition); *name, *receiver, index, *transition, extra_ic_state);
break; break;
} }
case NORMAL: { case NORMAL: {
@ -1520,10 +1535,11 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
JSGlobalPropertyCell* cell = JSGlobalPropertyCell* cell =
JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
maybe_code = StubCache::ComputeStoreGlobal(*name, *global, cell); maybe_code = StubCache::ComputeStoreGlobal(
*name, *global, cell, extra_ic_state);
} else { } else {
if (lookup->holder() != *receiver) return; if (lookup->holder() != *receiver) return;
maybe_code = StubCache::ComputeStoreNormal(); maybe_code = StubCache::ComputeStoreNormal(extra_ic_state);
} }
break; break;
} }
@ -1531,12 +1547,14 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
if (v8::ToCData<Address>(callback->setter()) == 0) return; 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; break;
} }
case INTERCEPTOR: { case INTERCEPTOR: {
ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined());
maybe_code = StubCache::ComputeStoreInterceptor(*name, *receiver); maybe_code = StubCache::ComputeStoreInterceptor(
*name, *receiver, extra_ic_state);
break; break;
} }
default: default:
@ -1552,7 +1570,11 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
set_target(Code::cast(code)); set_target(Code::cast(code));
} else if (state == MONOMORPHIC) { } else if (state == MONOMORPHIC) {
// Only move to megamorphic if the target changes. // 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) { } else if (state == MEGAMORPHIC) {
// Update the stub cache. // Update the stub cache.
StubCache::Set(*name, receiver->map(), Code::cast(code)); StubCache::Set(*name, receiver->map(), Code::cast(code));
@ -1795,8 +1817,9 @@ MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) {
ASSERT(args.length() == 3); ASSERT(args.length() == 3);
StoreIC ic; StoreIC ic;
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
return ic.Store(state, args.at<Object>(0), args.at<String>(1), Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
args.at<Object>(2)); return ic.Store(state, extra_ic_state, args.at<Object>(0),
args.at<String>(1), args.at<Object>(2));
} }

View File

@ -398,9 +398,16 @@ class KeyedLoadIC: public IC {
class StoreIC: public IC { class StoreIC: public IC {
public: public:
enum StoreICStrictMode {
kStoreICNonStrict = kNonStrictMode,
kStoreICStrict = kStrictMode
};
StoreIC() : IC(NO_EXTRA_FRAME) { ASSERT(target()->is_store_stub()); } StoreIC() : IC(NO_EXTRA_FRAME) { ASSERT(target()->is_store_stub()); }
MUST_USE_RESULT MaybeObject* Store(State state, MUST_USE_RESULT MaybeObject* Store(State state,
Code::ExtraICState extra_ic_state,
Handle<Object> object, Handle<Object> object,
Handle<String> name, Handle<String> name,
Handle<Object> value); Handle<Object> value);
@ -408,7 +415,8 @@ class StoreIC: public IC {
// Code generators for stub routines. Only called once at startup. // Code generators for stub routines. Only called once at startup.
static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
static void GenerateMiss(MacroAssembler* 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 GenerateArrayLength(MacroAssembler* masm);
static void GenerateNormal(MacroAssembler* masm); static void GenerateNormal(MacroAssembler* masm);
static void GenerateGlobalProxy(MacroAssembler* masm); static void GenerateGlobalProxy(MacroAssembler* masm);
@ -424,7 +432,9 @@ class StoreIC: public IC {
// Update the inline cache and the global stub cache based on the // Update the inline cache and the global stub cache based on the
// lookup result. // lookup result.
void UpdateCaches(LookupResult* lookup, void UpdateCaches(LookupResult* lookup,
State state, Handle<JSObject> receiver, State state,
Code::ExtraICState extra_ic_state,
Handle<JSObject> receiver,
Handle<String> name, Handle<String> name,
Handle<Object> value); Handle<Object> value);
@ -432,12 +442,21 @@ class StoreIC: public IC {
static Code* megamorphic_stub() { static Code* megamorphic_stub() {
return Builtins::builtin(Builtins::StoreIC_Megamorphic); return Builtins::builtin(Builtins::StoreIC_Megamorphic);
} }
static Code* megamorphic_stub_strict() {
return Builtins::builtin(Builtins::StoreIC_Megamorphic_Strict);
}
static Code* initialize_stub() { static Code* initialize_stub() {
return Builtins::builtin(Builtins::StoreIC_Initialize); return Builtins::builtin(Builtins::StoreIC_Initialize);
} }
static Code* initialize_stub_strict() {
return Builtins::builtin(Builtins::StoreIC_Initialize_Strict);
}
static Code* global_proxy_stub() { static Code* global_proxy_stub() {
return Builtins::builtin(Builtins::StoreIC_GlobalProxy); 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); static void Clear(Address address, Code* target);

View File

@ -2610,10 +2610,12 @@ Code::Flags Code::ComputeFlags(Kind kind,
PropertyType type, PropertyType type,
int argc, int argc,
InlineCacheHolderFlag holder) { 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 || ASSERT(extra_ic_state == kNoExtraICState ||
(kind == CALL_IC && (ic_state == MONOMORPHIC || (kind == CALL_IC && (ic_state == MONOMORPHIC ||
ic_state == MONOMORPHIC_PROTOTYPE_FAILURE))); ic_state == MONOMORPHIC_PROTOTYPE_FAILURE)) ||
(kind == STORE_IC));
// Compute the bit mask. // Compute the bit mask.
int bits = kind << kFlagsKindShift; int bits = kind << kFlagsKindShift;
if (in_loop) bits |= kFlagsICInLoopMask; if (in_loop) bits |= kFlagsICInLoopMask;

View File

@ -6238,10 +6238,35 @@ const char* Code::PropertyType2String(PropertyType type) {
} }
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) { void Code::Disassemble(const char* name, FILE* out) {
PrintF(out, "kind = %s\n", Kind2String(kind())); PrintF(out, "kind = %s\n", Kind2String(kind()));
if (is_inline_cache_stub()) { if (is_inline_cache_stub()) {
PrintF(out, "ic_state = %s\n", ICState2String(ic_state())); 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); PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
if (ic_state() == MONOMORPHIC) { if (ic_state() == MONOMORPHIC) {
PrintF(out, "type = %s\n", PropertyType2String(type())); PrintF(out, "type = %s\n", PropertyType2String(type()));

View File

@ -3200,6 +3200,7 @@ class Code: public HeapObject {
static const char* Kind2String(Kind kind); static const char* Kind2String(Kind kind);
static const char* ICState2String(InlineCacheState state); static const char* ICState2String(InlineCacheState state);
static const char* PropertyType2String(PropertyType type); static const char* PropertyType2String(PropertyType type);
static void PrintExtraICState(FILE* out, Kind kind, ExtraICState extra);
inline void Disassemble(const char* name) { inline void Disassemble(const char* name) {
Disassemble(name, stdout); Disassemble(name, stdout);
} }

View File

@ -192,7 +192,7 @@ void ExternalReferenceTable::PopulateTable() {
{ BUILTIN, \ { BUILTIN, \
Builtins::name, \ Builtins::name, \
"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_C(DEF_ENTRY_C)
BUILTIN_LIST_A(DEF_ENTRY_A) BUILTIN_LIST_A(DEF_ENTRY_A)

View File

@ -497,12 +497,14 @@ MaybeObject* StubCache::ComputeKeyedLoadPixelArray(JSObject* receiver) {
MaybeObject* StubCache::ComputeStoreField(String* name, MaybeObject* StubCache::ComputeStoreField(String* name,
JSObject* receiver, JSObject* receiver,
int field_index, int field_index,
Map* transition) { Map* transition,
Code::ExtraICState extra_ic_state) {
PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION; 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); Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) { if (code->IsUndefined()) {
StoreStubCompiler compiler; StoreStubCompiler compiler(extra_ic_state);
{ MaybeObject* maybe_code = { MaybeObject* maybe_code =
compiler.CompileStoreField(receiver, field_index, transition, name); compiler.CompileStoreField(receiver, field_index, transition, name);
if (!maybe_code->ToObject(&code)) return maybe_code; if (!maybe_code->ToObject(&code)) return maybe_code;
@ -608,18 +610,22 @@ MaybeObject* StubCache::ComputeKeyedLoadOrStoreExternalArray(
} }
MaybeObject* StubCache::ComputeStoreNormal() { MaybeObject* StubCache::ComputeStoreNormal(Code::ExtraICState extra_ic_state) {
return Builtins::builtin(Builtins::StoreIC_Normal); return Builtins::builtin(extra_ic_state == StoreIC::kStoreICStrict
? Builtins::StoreIC_Normal_Strict
: Builtins::StoreIC_Normal);
} }
MaybeObject* StubCache::ComputeStoreGlobal(String* name, MaybeObject* StubCache::ComputeStoreGlobal(String* name,
GlobalObject* receiver, GlobalObject* receiver,
JSGlobalPropertyCell* cell) { JSGlobalPropertyCell* cell,
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL); Code::ExtraICState extra_ic_state) {
Code::Flags flags = Code::ComputeMonomorphicFlags(
Code::STORE_IC, NORMAL, extra_ic_state);
Object* code = receiver->map()->FindInCodeCache(name, flags); Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) { if (code->IsUndefined()) {
StoreStubCompiler compiler; StoreStubCompiler compiler(extra_ic_state);
{ MaybeObject* maybe_code = { MaybeObject* maybe_code =
compiler.CompileStoreGlobal(receiver, cell, name); compiler.CompileStoreGlobal(receiver, cell, name);
if (!maybe_code->ToObject(&code)) return maybe_code; if (!maybe_code->ToObject(&code)) return maybe_code;
@ -636,14 +642,17 @@ MaybeObject* StubCache::ComputeStoreGlobal(String* name,
} }
MaybeObject* StubCache::ComputeStoreCallback(String* name, MaybeObject* StubCache::ComputeStoreCallback(
JSObject* receiver, String* name,
AccessorInfo* callback) { JSObject* receiver,
AccessorInfo* callback,
Code::ExtraICState extra_ic_state) {
ASSERT(v8::ToCData<Address>(callback->setter()) != 0); 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); Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) { if (code->IsUndefined()) {
StoreStubCompiler compiler; StoreStubCompiler compiler(extra_ic_state);
{ MaybeObject* maybe_code = { MaybeObject* maybe_code =
compiler.CompileStoreCallback(receiver, callback, name); compiler.CompileStoreCallback(receiver, callback, name);
if (!maybe_code->ToObject(&code)) return maybe_code; if (!maybe_code->ToObject(&code)) return maybe_code;
@ -660,13 +669,15 @@ MaybeObject* StubCache::ComputeStoreCallback(String* name,
} }
MaybeObject* StubCache::ComputeStoreInterceptor(String* name, MaybeObject* StubCache::ComputeStoreInterceptor(
JSObject* receiver) { String* name,
Code::Flags flags = JSObject* receiver,
Code::ComputeMonomorphicFlags(Code::STORE_IC, INTERCEPTOR); Code::ExtraICState extra_ic_state) {
Code::Flags flags = Code::ComputeMonomorphicFlags(
Code::STORE_IC, INTERCEPTOR, extra_ic_state);
Object* code = receiver->map()->FindInCodeCache(name, flags); Object* code = receiver->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) { if (code->IsUndefined()) {
StoreStubCompiler compiler; StoreStubCompiler compiler(extra_ic_state);
{ MaybeObject* maybe_code = { MaybeObject* maybe_code =
compiler.CompileStoreInterceptor(receiver, name); compiler.CompileStoreInterceptor(receiver, name);
if (!maybe_code->ToObject(&code)) return maybe_code; if (!maybe_code->ToObject(&code)) return maybe_code;
@ -1637,7 +1648,8 @@ MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) { 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); MaybeObject* result = GetCodeWithFlags(flags, name);
if (!result->IsFailure()) { if (!result->IsFailure()) {
PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG,

View File

@ -138,26 +138,32 @@ class StubCache : public AllStatic {
// --- // ---
MUST_USE_RESULT static MaybeObject* ComputeStoreField(String* name, MUST_USE_RESULT static MaybeObject* ComputeStoreField(
JSObject* receiver, String* name,
int field_index, JSObject* receiver,
Map* transition = NULL); 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( MUST_USE_RESULT static MaybeObject* ComputeStoreGlobal(
String* name, String* name,
GlobalObject* receiver, GlobalObject* receiver,
JSGlobalPropertyCell* cell); JSGlobalPropertyCell* cell,
Code::ExtraICState extra_ic_state);
MUST_USE_RESULT static MaybeObject* ComputeStoreCallback( MUST_USE_RESULT static MaybeObject* ComputeStoreCallback(
String* name, String* name,
JSObject* receiver, JSObject* receiver,
AccessorInfo* callback); AccessorInfo* callback,
Code::ExtraICState extra_ic_state);
MUST_USE_RESULT static MaybeObject* ComputeStoreInterceptor( MUST_USE_RESULT static MaybeObject* ComputeStoreInterceptor(
String* name, String* name,
JSObject* receiver); JSObject* receiver,
Code::ExtraICState extra_ic_state);
// --- // ---
@ -619,6 +625,9 @@ class KeyedLoadStubCompiler: public StubCompiler {
class StoreStubCompiler: public StubCompiler { class StoreStubCompiler: public StubCompiler {
public: public:
explicit StoreStubCompiler(Code::ExtraICState extra_ic_state)
: extra_ic_state_(extra_ic_state) { }
MUST_USE_RESULT MaybeObject* CompileStoreField(JSObject* object, MUST_USE_RESULT MaybeObject* CompileStoreField(JSObject* object,
int index, int index,
Map* transition, Map* transition,
@ -636,6 +645,8 @@ class StoreStubCompiler: public StubCompiler {
private: private:
MaybeObject* GetCode(PropertyType type, String* name); MaybeObject* GetCode(PropertyType type, String* name);
Code::ExtraICState extra_ic_state_;
}; };

View File

@ -4894,7 +4894,8 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
Load(property->value()); Load(property->value());
if (property->emit_store()) { if (property->emit_store()) {
Result ignored = 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 // A test rax instruction following the store IC call would
// indicate the presence of an inlined version of the // indicate the presence of an inlined version of the
// store. Add a nop to indicate that there is no such // store. Add a nop to indicate that there is no such
@ -8234,7 +8235,7 @@ Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
Result result; Result result;
if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) { 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 // A test rax instruction following the call signals that the inobject
// property case was inlined. Ensure that there is not a test rax // property case was inlined. Ensure that there is not a test rax
// instruction here. // instruction here.
@ -8334,7 +8335,7 @@ Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
slow.Bind(&value, &receiver); slow.Bind(&value, &receiver);
frame()->Push(&receiver); frame()->Push(&receiver);
frame()->Push(&value); 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 // Encode the offset to the map check instruction and the offset
// to the write barrier store address computation in a test rax // to the write barrier store address computation in a test rax
// instruction. // instruction.

View File

@ -1715,8 +1715,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
// rcx, and the global object on the stack. // rcx, and the global object on the stack.
__ Move(rcx, var->name()); __ Move(rcx, var->name());
__ movq(rdx, GlobalObjectOperand()); __ movq(rdx, GlobalObjectOperand());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(is_strict()
EmitCallIC(ic, RelocInfo::CODE_TARGET); ? Builtins::StoreIC_Initialize_Strict
: Builtins::StoreIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) {
// Perform the assignment for non-const variables and for initialization // Perform the assignment for non-const variables and for initialization

View File

@ -1473,7 +1473,8 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
} }
void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
Code::ExtraICState extra_ic_state) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rax : value // -- rax : value
// -- rcx : name // -- rcx : name
@ -1484,7 +1485,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
// Get the receiver from the stack and probe the stub cache. // Get the receiver from the stack and probe the stub cache.
Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
NOT_IN_LOOP, NOT_IN_LOOP,
MONOMORPHIC); MONOMORPHIC,
extra_ic_state);
StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg); StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg);
// Cache miss: Jump to runtime. // Cache miss: Jump to runtime.

View File

@ -1119,23 +1119,30 @@ Result VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) {
} }
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. // 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. // 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(); Result value = Pop();
RelocInfo::Mode mode;
if (is_contextual) { if (is_contextual) {
PrepareForCall(0, 0); PrepareForCall(0, 0);
value.ToRegister(rax); value.ToRegister(rax);
__ movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); __ movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
value.Unuse(); value.Unuse();
mode = RelocInfo::CODE_TARGET_CONTEXT;
} else { } else {
Result receiver = Pop(); Result receiver = Pop();
PrepareForCall(0, 0); PrepareForCall(0, 0);
MoveResultsToRegisters(&value, &receiver, rax, rdx); MoveResultsToRegisters(&value, &receiver, rax, rdx);
mode = RelocInfo::CODE_TARGET;
} }
__ Move(rcx, name); __ Move(rcx, name);
return RawCallCodeObject(ic, RelocInfo::CODE_TARGET); return RawCallCodeObject(ic, mode);
} }

View File

@ -338,7 +338,8 @@ class VirtualFrame : public ZoneObject {
// Call store IC. If the load is contextual, value is found on top of the // 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. // 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 // Call keyed store IC. Value, key, and receiver are found on top
// of the frame. All three are dropped. // of the frame. All three are dropped.

View File

@ -997,7 +997,7 @@ TEST(DebugStub) {
CheckDebugBreakFunction(&env, CheckDebugBreakFunction(&env,
"function f2(){x=1;}", "f2", "function f2(){x=1;}", "f2",
0, 0,
v8::internal::RelocInfo::CODE_TARGET, v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
Builtins::builtin(Builtins::StoreIC_DebugBreak)); Builtins::builtin(Builtins::StoreIC_DebugBreak));
CheckDebugBreakFunction(&env, CheckDebugBreakFunction(&env,
"function f3(){var a=x;}", "f3", "function f3(){var a=x;}", "f3",

View File

@ -264,9 +264,6 @@ chapter10/10.6/10.6-13-c-1-s: FAIL
# arguments.callee is non-configurable in strict mode # arguments.callee is non-configurable in strict mode
chapter10/10.6/10.6-13-c-3-s: FAIL 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 # simple assignment throws TypeError if LeftHandSide is a property reference
# with a primitive base value (this is undefined) # with a primitive base value (this is undefined)
chapter11/11.13/11.13.1/11.13.1-1-7-s: FAIL chapter11/11.13/11.13.1/11.13.1-1-7-s: FAIL

View File

@ -335,4 +335,42 @@ for (var i = 0; i < future_reserved_words.length; i++) {
testFutureReservedWord(future_reserved_words[i]); 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); });

View File

@ -1170,7 +1170,6 @@
893E248E12B14B3D0083370F /* hydrogen-instructions.h */, 893E248E12B14B3D0083370F /* hydrogen-instructions.h */,
893E248F12B14B3D0083370F /* hydrogen.cc */, 893E248F12B14B3D0083370F /* hydrogen.cc */,
893E249012B14B3D0083370F /* hydrogen.h */, 893E249012B14B3D0083370F /* hydrogen.h */,
897FF1490E719B8F00D62E90 /* ic-arm.cc */,
897FF14B0E719B8F00D62E90 /* ic-inl.h */, 897FF14B0E719B8F00D62E90 /* ic-inl.h */,
897FF14C0E719B8F00D62E90 /* ic.cc */, 897FF14C0E719B8F00D62E90 /* ic.cc */,
897FF14D0E719B8F00D62E90 /* ic.h */, 897FF14D0E719B8F00D62E90 /* ic.h */,
@ -1285,7 +1284,6 @@
897FF1890E719B8F00D62E90 /* string-stream.h */, 897FF1890E719B8F00D62E90 /* string-stream.h */,
893E24A312B14B3D0083370F /* strtod.cc */, 893E24A312B14B3D0083370F /* strtod.cc */,
893E24A412B14B3D0083370F /* strtod.h */, 893E24A412B14B3D0083370F /* strtod.h */,
897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */,
897FF18C0E719B8F00D62E90 /* stub-cache.cc */, 897FF18C0E719B8F00D62E90 /* stub-cache.cc */,
897FF18D0E719B8F00D62E90 /* stub-cache.h */, 897FF18D0E719B8F00D62E90 /* stub-cache.h */,
897FF18E0E719B8F00D62E90 /* token.cc */, 897FF18E0E719B8F00D62E90 /* token.cc */,
@ -1534,6 +1532,7 @@
898BD20C0EF6CC850068B00A /* debug-arm.cc */, 898BD20C0EF6CC850068B00A /* debug-arm.cc */,
893E24C612B14B510083370F /* deoptimizer-arm.cc */, 893E24C612B14B510083370F /* deoptimizer-arm.cc */,
9FA38BCB1175B30400C4CD55 /* full-codegen-arm.cc */, 9FA38BCB1175B30400C4CD55 /* full-codegen-arm.cc */,
897FF1490E719B8F00D62E90 /* ic-arm.cc */,
9FA38BCC1175B30400C4CD55 /* jump-target-arm.cc */, 9FA38BCC1175B30400C4CD55 /* jump-target-arm.cc */,
893E24C712B14B510083370F /* lithium-arm.cc */, 893E24C712B14B510083370F /* lithium-arm.cc */,
893E24C812B14B510083370F /* lithium-arm.h */, 893E24C812B14B510083370F /* lithium-arm.h */,
@ -1548,6 +1547,7 @@
895FA751107FFEAE006F39D4 /* register-allocator-arm.h */, 895FA751107FFEAE006F39D4 /* register-allocator-arm.h */,
897FF17D0E719B8F00D62E90 /* simulator-arm.cc */, 897FF17D0E719B8F00D62E90 /* simulator-arm.cc */,
897FF17E0E719B8F00D62E90 /* simulator-arm.h */, 897FF17E0E719B8F00D62E90 /* simulator-arm.h */,
897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */,
893E24CB12B14B520083370F /* virtual-frame-arm-inl.h */, 893E24CB12B14B520083370F /* virtual-frame-arm-inl.h */,
9FA38BCD1175B30400C4CD55 /* virtual-frame-arm.cc */, 9FA38BCD1175B30400C4CD55 /* virtual-frame-arm.cc */,
58950D570F55514900F3E8BA /* virtual-frame-arm.h */, 58950D570F55514900F3E8BA /* virtual-frame-arm.h */,