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:
parent
26df17e714
commit
e0be3072b5
1
.gitignore
vendored
1
.gitignore
vendored
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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,
|
||||||
|
@ -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.
|
||||||
|
168
src/builtins.h
168
src/builtins.h
@ -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)
|
||||||
|
@ -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) {
|
||||||
|
@ -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(); }
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
57
src/ic.cc
57
src/ic.cc
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
23
src/ic.h
23
src/ic.h
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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()));
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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",
|
||||||
|
@ -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
|
||||||
|
@ -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); });
|
||||||
|
@ -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 */,
|
||||||
|
Loading…
Reference in New Issue
Block a user