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_g
|
||||
/obj/
|
||||
/test/es5conform/data/
|
||||
/test/sputnik/sputniktests/
|
||||
/tools/oom_dump/oom_dump
|
||||
/tools/oom_dump/oom_dump.o
|
||||
|
@ -6926,7 +6926,7 @@ void CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
|
||||
|
||||
Result result;
|
||||
if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) {
|
||||
frame()->CallStoreIC(name, is_contextual);
|
||||
frame()->CallStoreIC(name, is_contextual, strict_mode_flag());
|
||||
} else {
|
||||
// Inline the in-object property case.
|
||||
JumpTarget slow, done;
|
||||
|
@ -1685,8 +1685,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
|
||||
// r2, and the global object in r1.
|
||||
__ mov(r2, Operand(var->name()));
|
||||
__ ldr(r1, GlobalObjectOperand());
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
||||
Handle<Code> ic(Builtins::builtin(is_strict()
|
||||
? Builtins::StoreIC_Initialize_Strict
|
||||
: Builtins::StoreIC_Initialize));
|
||||
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
||||
|
||||
} else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) {
|
||||
// Perform the assignment for non-const variables and for initialization
|
||||
|
@ -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 -------------
|
||||
// -- r0 : value
|
||||
// -- r1 : receiver
|
||||
@ -1544,7 +1545,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
|
||||
// Get the receiver from the stack and probe the stub cache.
|
||||
Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
|
||||
NOT_IN_LOOP,
|
||||
MONOMORPHIC);
|
||||
MONOMORPHIC,
|
||||
extra_ic_state);
|
||||
StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
|
||||
|
||||
// Cache miss: Jump to runtime.
|
||||
|
@ -2944,7 +2944,9 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
|
||||
|
||||
// Name is always in r2.
|
||||
__ mov(r2, Operand(instr->name()));
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
Handle<Code> ic(Builtins::builtin(info_->is_strict()
|
||||
? Builtins::StoreIC_Initialize_Strict
|
||||
: Builtins::StoreIC_Initialize));
|
||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||
}
|
||||
|
||||
|
@ -329,18 +329,25 @@ void VirtualFrame::CallLoadIC(Handle<String> name, RelocInfo::Mode mode) {
|
||||
}
|
||||
|
||||
|
||||
void VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) {
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
void VirtualFrame::CallStoreIC(Handle<String> name,
|
||||
bool is_contextual,
|
||||
StrictModeFlag strict_mode) {
|
||||
Handle<Code> ic(Builtins::builtin(strict_mode == kStrictMode
|
||||
? Builtins::StoreIC_Initialize_Strict
|
||||
: Builtins::StoreIC_Initialize));
|
||||
PopToR0();
|
||||
RelocInfo::Mode mode;
|
||||
if (is_contextual) {
|
||||
SpillAll();
|
||||
__ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
||||
mode = RelocInfo::CODE_TARGET_CONTEXT;
|
||||
} else {
|
||||
EmitPop(r1);
|
||||
SpillAll();
|
||||
mode = RelocInfo::CODE_TARGET;
|
||||
}
|
||||
__ mov(r2, Operand(name));
|
||||
CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
|
||||
CallCodeObject(ic, mode, 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -294,7 +294,8 @@ class VirtualFrame : public ZoneObject {
|
||||
// Call store IC. If the load is contextual, value is found on top of the
|
||||
// frame. If not, value and receiver are on the frame. Both are consumed.
|
||||
// Result is returned in r0.
|
||||
void CallStoreIC(Handle<String> name, bool is_contextual);
|
||||
void CallStoreIC(Handle<String> name, bool is_contextual,
|
||||
StrictModeFlag strict_mode);
|
||||
|
||||
// Call keyed load IC. Key and receiver are on the stack. Both are consumed.
|
||||
// Result is returned in r0.
|
||||
|
@ -181,7 +181,7 @@ class RelocInfo BASE_EMBEDDED {
|
||||
enum Mode {
|
||||
// Please note the order is important (see IsCodeTarget, IsGCRelocMode).
|
||||
CONSTRUCT_CALL, // code target that is a call to a JavaScript constructor.
|
||||
CODE_TARGET_CONTEXT, // Code target used for contextual loads.
|
||||
CODE_TARGET_CONTEXT, // Code target used for contextual loads and stores.
|
||||
DEBUG_BREAK, // Code target for the debugger statement.
|
||||
CODE_TARGET, // Code target which is not any of the above.
|
||||
EMBEDDED_OBJECT,
|
||||
|
@ -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) {
|
||||
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) {
|
||||
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) {
|
||||
StoreIC::GenerateGlobalProxy(masm);
|
||||
}
|
||||
|
||||
|
||||
static void Generate_StoreIC_GlobalProxy_Strict(MacroAssembler* masm) {
|
||||
StoreIC::GenerateGlobalProxy(masm);
|
||||
}
|
||||
|
||||
|
||||
static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
|
||||
KeyedStoreIC::GenerateGeneric(masm);
|
||||
}
|
||||
@ -1444,13 +1469,13 @@ void Builtins::Setup(bool create_heap_objects) {
|
||||
extra_args \
|
||||
},
|
||||
|
||||
#define DEF_FUNCTION_PTR_A(name, kind, state) \
|
||||
{ FUNCTION_ADDR(Generate_##name), \
|
||||
NULL, \
|
||||
#name, \
|
||||
name, \
|
||||
Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state), \
|
||||
NO_EXTRA_ARGUMENTS \
|
||||
#define DEF_FUNCTION_PTR_A(name, kind, state, extra) \
|
||||
{ FUNCTION_ADDR(Generate_##name), \
|
||||
NULL, \
|
||||
#name, \
|
||||
name, \
|
||||
Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state, extra), \
|
||||
NO_EXTRA_ARGUMENTS \
|
||||
},
|
||||
|
||||
// Define array of pointers to generators and C builtin functions.
|
||||
|
168
src/builtins.h
168
src/builtins.h
@ -63,73 +63,135 @@ enum BuiltinExtraArguments {
|
||||
|
||||
// Define list of builtins implemented in assembly.
|
||||
#define BUILTIN_LIST_A(V) \
|
||||
V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED) \
|
||||
V(JSConstructCall, BUILTIN, UNINITIALIZED) \
|
||||
V(JSConstructStubCountdown, BUILTIN, UNINITIALIZED) \
|
||||
V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED) \
|
||||
V(JSConstructStubApi, BUILTIN, UNINITIALIZED) \
|
||||
V(JSEntryTrampoline, BUILTIN, UNINITIALIZED) \
|
||||
V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED) \
|
||||
V(LazyCompile, BUILTIN, UNINITIALIZED) \
|
||||
V(LazyRecompile, BUILTIN, UNINITIALIZED) \
|
||||
V(NotifyDeoptimized, BUILTIN, UNINITIALIZED) \
|
||||
V(NotifyLazyDeoptimized, BUILTIN, UNINITIALIZED) \
|
||||
V(NotifyOSR, BUILTIN, UNINITIALIZED) \
|
||||
V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(JSConstructCall, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(JSConstructStubCountdown, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(JSConstructStubApi, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(JSEntryTrampoline, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(LazyCompile, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(LazyRecompile, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(NotifyDeoptimized, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(NotifyLazyDeoptimized, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(NotifyOSR, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
\
|
||||
V(LoadIC_Miss, BUILTIN, UNINITIALIZED) \
|
||||
V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED) \
|
||||
V(StoreIC_Miss, BUILTIN, UNINITIALIZED) \
|
||||
V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED) \
|
||||
V(LoadIC_Miss, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(StoreIC_Miss, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
\
|
||||
V(LoadIC_Initialize, LOAD_IC, UNINITIALIZED) \
|
||||
V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC) \
|
||||
V(LoadIC_Normal, LOAD_IC, MONOMORPHIC) \
|
||||
V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC) \
|
||||
V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC) \
|
||||
V(LoadIC_StringWrapperLength, LOAD_IC, MONOMORPHIC) \
|
||||
V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC) \
|
||||
V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC) \
|
||||
V(LoadIC_Initialize, LOAD_IC, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC, \
|
||||
Code::kNoExtraICState) \
|
||||
V(LoadIC_Normal, LOAD_IC, MONOMORPHIC, \
|
||||
Code::kNoExtraICState) \
|
||||
V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC, \
|
||||
Code::kNoExtraICState) \
|
||||
V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC, \
|
||||
Code::kNoExtraICState) \
|
||||
V(LoadIC_StringWrapperLength, LOAD_IC, MONOMORPHIC, \
|
||||
Code::kNoExtraICState) \
|
||||
V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC, \
|
||||
Code::kNoExtraICState) \
|
||||
V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC, \
|
||||
Code::kNoExtraICState) \
|
||||
\
|
||||
V(KeyedLoadIC_Initialize, KEYED_LOAD_IC, UNINITIALIZED) \
|
||||
V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC) \
|
||||
V(KeyedLoadIC_Generic, KEYED_LOAD_IC, MEGAMORPHIC) \
|
||||
V(KeyedLoadIC_String, KEYED_LOAD_IC, MEGAMORPHIC) \
|
||||
V(KeyedLoadIC_IndexedInterceptor, KEYED_LOAD_IC, MEGAMORPHIC) \
|
||||
V(KeyedLoadIC_Initialize, KEYED_LOAD_IC, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC, \
|
||||
Code::kNoExtraICState) \
|
||||
V(KeyedLoadIC_Generic, KEYED_LOAD_IC, MEGAMORPHIC, \
|
||||
Code::kNoExtraICState) \
|
||||
V(KeyedLoadIC_String, KEYED_LOAD_IC, MEGAMORPHIC, \
|
||||
Code::kNoExtraICState) \
|
||||
V(KeyedLoadIC_IndexedInterceptor, KEYED_LOAD_IC, MEGAMORPHIC, \
|
||||
Code::kNoExtraICState) \
|
||||
\
|
||||
V(StoreIC_Initialize, STORE_IC, UNINITIALIZED) \
|
||||
V(StoreIC_ArrayLength, STORE_IC, MONOMORPHIC) \
|
||||
V(StoreIC_Normal, STORE_IC, MONOMORPHIC) \
|
||||
V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC) \
|
||||
V(StoreIC_GlobalProxy, STORE_IC, MEGAMORPHIC) \
|
||||
V(StoreIC_Initialize, STORE_IC, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(StoreIC_ArrayLength, STORE_IC, MONOMORPHIC, \
|
||||
Code::kNoExtraICState) \
|
||||
V(StoreIC_Normal, STORE_IC, MONOMORPHIC, \
|
||||
Code::kNoExtraICState) \
|
||||
V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC, \
|
||||
Code::kNoExtraICState) \
|
||||
V(StoreIC_GlobalProxy, STORE_IC, MEGAMORPHIC, \
|
||||
Code::kNoExtraICState) \
|
||||
V(StoreIC_Initialize_Strict, STORE_IC, UNINITIALIZED, \
|
||||
StoreIC::kStoreICStrict) \
|
||||
V(StoreIC_ArrayLength_Strict, STORE_IC, MONOMORPHIC, \
|
||||
StoreIC::kStoreICStrict) \
|
||||
V(StoreIC_Normal_Strict, STORE_IC, MONOMORPHIC, \
|
||||
StoreIC::kStoreICStrict) \
|
||||
V(StoreIC_Megamorphic_Strict, STORE_IC, MEGAMORPHIC, \
|
||||
StoreIC::kStoreICStrict) \
|
||||
V(StoreIC_GlobalProxy_Strict, STORE_IC, MEGAMORPHIC, \
|
||||
StoreIC::kStoreICStrict) \
|
||||
\
|
||||
V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED) \
|
||||
V(KeyedStoreIC_Generic, KEYED_STORE_IC, MEGAMORPHIC) \
|
||||
V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(KeyedStoreIC_Generic, KEYED_STORE_IC, MEGAMORPHIC, \
|
||||
Code::kNoExtraICState) \
|
||||
\
|
||||
/* Uses KeyedLoadIC_Initialize; must be after in list. */ \
|
||||
V(FunctionCall, BUILTIN, UNINITIALIZED) \
|
||||
V(FunctionApply, BUILTIN, UNINITIALIZED) \
|
||||
V(FunctionCall, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(FunctionApply, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
\
|
||||
V(ArrayCode, BUILTIN, UNINITIALIZED) \
|
||||
V(ArrayConstructCode, BUILTIN, UNINITIALIZED) \
|
||||
V(ArrayCode, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
V(ArrayConstructCode, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
\
|
||||
V(StringConstructCode, BUILTIN, UNINITIALIZED) \
|
||||
V(StringConstructCode, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState) \
|
||||
\
|
||||
V(OnStackReplacement, BUILTIN, UNINITIALIZED)
|
||||
V(OnStackReplacement, BUILTIN, UNINITIALIZED, \
|
||||
Code::kNoExtraICState)
|
||||
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
// Define list of builtins used by the debugger implemented in assembly.
|
||||
#define BUILTIN_LIST_DEBUG_A(V) \
|
||||
V(Return_DebugBreak, BUILTIN, DEBUG_BREAK) \
|
||||
V(ConstructCall_DebugBreak, BUILTIN, DEBUG_BREAK) \
|
||||
V(StubNoRegisters_DebugBreak, BUILTIN, DEBUG_BREAK) \
|
||||
V(LoadIC_DebugBreak, LOAD_IC, DEBUG_BREAK) \
|
||||
V(KeyedLoadIC_DebugBreak, KEYED_LOAD_IC, DEBUG_BREAK) \
|
||||
V(StoreIC_DebugBreak, STORE_IC, DEBUG_BREAK) \
|
||||
V(KeyedStoreIC_DebugBreak, KEYED_STORE_IC, DEBUG_BREAK) \
|
||||
V(Slot_DebugBreak, BUILTIN, DEBUG_BREAK) \
|
||||
V(PlainReturn_LiveEdit, BUILTIN, DEBUG_BREAK) \
|
||||
V(FrameDropper_LiveEdit, BUILTIN, DEBUG_BREAK)
|
||||
V(Return_DebugBreak, BUILTIN, DEBUG_BREAK, \
|
||||
Code::kNoExtraICState) \
|
||||
V(ConstructCall_DebugBreak, BUILTIN, DEBUG_BREAK, \
|
||||
Code::kNoExtraICState) \
|
||||
V(StubNoRegisters_DebugBreak, BUILTIN, DEBUG_BREAK, \
|
||||
Code::kNoExtraICState) \
|
||||
V(LoadIC_DebugBreak, LOAD_IC, DEBUG_BREAK, \
|
||||
Code::kNoExtraICState) \
|
||||
V(KeyedLoadIC_DebugBreak, KEYED_LOAD_IC, DEBUG_BREAK, \
|
||||
Code::kNoExtraICState) \
|
||||
V(StoreIC_DebugBreak, STORE_IC, DEBUG_BREAK, \
|
||||
Code::kNoExtraICState) \
|
||||
V(KeyedStoreIC_DebugBreak, KEYED_STORE_IC, DEBUG_BREAK, \
|
||||
Code::kNoExtraICState) \
|
||||
V(Slot_DebugBreak, BUILTIN, DEBUG_BREAK, \
|
||||
Code::kNoExtraICState) \
|
||||
V(PlainReturn_LiveEdit, BUILTIN, DEBUG_BREAK, \
|
||||
Code::kNoExtraICState) \
|
||||
V(FrameDropper_LiveEdit, BUILTIN, DEBUG_BREAK, \
|
||||
Code::kNoExtraICState)
|
||||
#else
|
||||
#define BUILTIN_LIST_DEBUG_A(V)
|
||||
#endif
|
||||
@ -186,7 +248,7 @@ class Builtins : public AllStatic {
|
||||
|
||||
enum Name {
|
||||
#define DEF_ENUM_C(name, ignore) name,
|
||||
#define DEF_ENUM_A(name, kind, state) name,
|
||||
#define DEF_ENUM_A(name, kind, state, extra) name,
|
||||
BUILTIN_LIST_C(DEF_ENUM_C)
|
||||
BUILTIN_LIST_A(DEF_ENUM_A)
|
||||
BUILTIN_LIST_DEBUG_A(DEF_ENUM_A)
|
||||
|
@ -71,7 +71,6 @@ class CompilationInfo BASE_EMBEDDED {
|
||||
flags_ |= IsGlobal::encode(true);
|
||||
}
|
||||
void MarkAsStrict() {
|
||||
ASSERT(!is_lazy());
|
||||
flags_ |= IsStrict::encode(true);
|
||||
}
|
||||
StrictModeFlag StrictMode() {
|
||||
@ -153,6 +152,9 @@ class CompilationInfo BASE_EMBEDDED {
|
||||
|
||||
void Initialize(Mode mode) {
|
||||
mode_ = V8::UseCrankshaft() ? mode : NONOPT;
|
||||
if (!shared_info_.is_null() && shared_info_->strict_mode()) {
|
||||
MarkAsStrict();
|
||||
}
|
||||
}
|
||||
|
||||
void SetMode(Mode mode) {
|
||||
|
@ -531,8 +531,9 @@ class FullCodeGenerator: public AstVisitor {
|
||||
|
||||
Handle<Script> script() { return info_->script(); }
|
||||
bool is_eval() { return info_->is_eval(); }
|
||||
bool is_strict() { return function()->strict_mode(); }
|
||||
StrictModeFlag strict_mode_flag() {
|
||||
return function()->strict_mode() ? kStrictMode : kNonStrictMode;
|
||||
return is_strict() ? kStrictMode : kNonStrictMode;
|
||||
}
|
||||
FunctionLiteral* function() { return info_->function(); }
|
||||
Scope* scope() { return info_->scope(); }
|
||||
|
@ -5588,7 +5588,8 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
|
||||
Load(property->value());
|
||||
if (property->emit_store()) {
|
||||
Result ignored =
|
||||
frame_->CallStoreIC(Handle<String>::cast(key), false);
|
||||
frame_->CallStoreIC(Handle<String>::cast(key), false,
|
||||
strict_mode_flag());
|
||||
// A test eax instruction following the store IC call would
|
||||
// indicate the presence of an inlined version of the
|
||||
// store. Add a nop to indicate that there is no such
|
||||
@ -9671,7 +9672,7 @@ Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
|
||||
|
||||
Result result;
|
||||
if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) {
|
||||
result = frame()->CallStoreIC(name, is_contextual);
|
||||
result = frame()->CallStoreIC(name, is_contextual, strict_mode_flag());
|
||||
// A test eax instruction following the call signals that the inobject
|
||||
// property case was inlined. Ensure that there is not a test eax
|
||||
// instruction here.
|
||||
@ -9755,7 +9756,7 @@ Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
|
||||
slow.Bind(&value, &receiver);
|
||||
frame()->Push(&receiver);
|
||||
frame()->Push(&value);
|
||||
result = frame()->CallStoreIC(name, is_contextual);
|
||||
result = frame()->CallStoreIC(name, is_contextual, strict_mode_flag());
|
||||
// Encode the offset to the map check instruction and the offset
|
||||
// to the write barrier store address computation in a test eax
|
||||
// instruction.
|
||||
|
@ -2013,8 +2013,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
|
||||
// ecx, and the global object on the stack.
|
||||
__ mov(ecx, var->name());
|
||||
__ mov(edx, GlobalObjectOperand());
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
||||
Handle<Code> ic(Builtins::builtin(
|
||||
is_strict() ? Builtins::StoreIC_Initialize_Strict
|
||||
: Builtins::StoreIC_Initialize));
|
||||
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
||||
|
||||
} else if (op == Token::INIT_CONST) {
|
||||
// Like var declarations, const declarations are hoisted to function
|
||||
|
@ -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 -------------
|
||||
// -- eax : value
|
||||
// -- ecx : name
|
||||
@ -1498,7 +1499,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
|
||||
|
||||
Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
|
||||
NOT_IN_LOOP,
|
||||
MONOMORPHIC);
|
||||
MONOMORPHIC,
|
||||
extra_ic_state);
|
||||
StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
|
||||
|
||||
// Cache miss: Jump to runtime.
|
||||
|
@ -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.
|
||||
// The IC expects name in ecx, value in eax, and receiver in edx.
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
Handle<Code> ic(Builtins::builtin(strict_mode == kStrictMode
|
||||
? Builtins::StoreIC_Initialize_Strict
|
||||
: Builtins::StoreIC_Initialize));
|
||||
|
||||
Result value = Pop();
|
||||
RelocInfo::Mode mode;
|
||||
if (is_contextual) {
|
||||
PrepareForCall(0, 0);
|
||||
value.ToRegister(eax);
|
||||
__ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
||||
value.Unuse();
|
||||
mode = RelocInfo::CODE_TARGET_CONTEXT;
|
||||
} else {
|
||||
Result receiver = Pop();
|
||||
PrepareForCall(0, 0);
|
||||
MoveResultsToRegisters(&value, &receiver, eax, edx);
|
||||
mode = RelocInfo::CODE_TARGET;
|
||||
}
|
||||
__ mov(ecx, name);
|
||||
return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
|
||||
return RawCallCodeObject(ic, mode);
|
||||
}
|
||||
|
||||
|
||||
|
@ -365,7 +365,8 @@ class VirtualFrame: public ZoneObject {
|
||||
|
||||
// Call store IC. If the load is contextual, value is found on top of the
|
||||
// frame. If not, value and receiver are on the frame. Both are dropped.
|
||||
Result CallStoreIC(Handle<String> name, bool is_contextual);
|
||||
Result CallStoreIC(Handle<String> name, bool is_contextual,
|
||||
StrictModeFlag strict_mode);
|
||||
|
||||
// Call keyed store IC. Value, key, and receiver are found on top
|
||||
// of the frame. All three are dropped.
|
||||
|
57
src/ic.cc
57
src/ic.cc
@ -342,7 +342,10 @@ void StoreIC::ClearInlinedVersion(Address address) {
|
||||
void StoreIC::Clear(Address address, Code* target) {
|
||||
if (target->ic_state() == UNINITIALIZED) return;
|
||||
ClearInlinedVersion(address);
|
||||
SetTargetAtAddress(address, initialize_stub());
|
||||
SetTargetAtAddress(address,
|
||||
target->extra_ic_state() == kStoreICStrict
|
||||
? initialize_stub_strict()
|
||||
: initialize_stub());
|
||||
}
|
||||
|
||||
|
||||
@ -1368,6 +1371,7 @@ static bool LookupForWrite(JSObject* object,
|
||||
|
||||
|
||||
MaybeObject* StoreIC::Store(State state,
|
||||
Code::ExtraICState extra_ic_state,
|
||||
Handle<Object> object,
|
||||
Handle<String> name,
|
||||
Handle<Object> value) {
|
||||
@ -1397,8 +1401,10 @@ MaybeObject* StoreIC::Store(State state,
|
||||
#ifdef DEBUG
|
||||
if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n");
|
||||
#endif
|
||||
Code* target = Builtins::builtin(Builtins::StoreIC_ArrayLength);
|
||||
set_target(target);
|
||||
Builtins::Name target = (extra_ic_state == kStoreICStrict)
|
||||
? Builtins::StoreIC_ArrayLength_Strict
|
||||
: Builtins::StoreIC_ArrayLength;
|
||||
set_target(Builtins::builtin(target));
|
||||
return receiver->SetProperty(*name, *value, NONE);
|
||||
}
|
||||
|
||||
@ -1456,15 +1462,23 @@ MaybeObject* StoreIC::Store(State state,
|
||||
|
||||
// If no inlined store ic was patched, generate a stub for this
|
||||
// store.
|
||||
UpdateCaches(&lookup, state, receiver, name, value);
|
||||
UpdateCaches(&lookup, state, extra_ic_state, receiver, name, value);
|
||||
} else {
|
||||
// Strict mode doesn't allow setting non-existent global property.
|
||||
if (extra_ic_state == kStoreICStrict && IsContextual(object)) {
|
||||
return ReferenceError("not_defined", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (receiver->IsJSGlobalProxy()) {
|
||||
// Generate a generic stub that goes to the runtime when we see a global
|
||||
// proxy as receiver.
|
||||
if (target() != global_proxy_stub()) {
|
||||
set_target(global_proxy_stub());
|
||||
Code* stub = (extra_ic_state == kStoreICStrict)
|
||||
? global_proxy_stub_strict()
|
||||
: global_proxy_stub();
|
||||
if (target() != stub) {
|
||||
set_target(stub);
|
||||
#ifdef DEBUG
|
||||
TraceIC("StoreIC", name, state, target());
|
||||
#endif
|
||||
@ -1478,6 +1492,7 @@ MaybeObject* StoreIC::Store(State state,
|
||||
|
||||
void StoreIC::UpdateCaches(LookupResult* lookup,
|
||||
State state,
|
||||
Code::ExtraICState extra_ic_state,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<String> name,
|
||||
Handle<Object> value) {
|
||||
@ -1498,8 +1513,8 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
|
||||
Object* code = NULL;
|
||||
switch (type) {
|
||||
case FIELD: {
|
||||
maybe_code = StubCache::ComputeStoreField(*name, *receiver,
|
||||
lookup->GetFieldIndex());
|
||||
maybe_code = StubCache::ComputeStoreField(
|
||||
*name, *receiver, lookup->GetFieldIndex(), NULL, extra_ic_state);
|
||||
break;
|
||||
}
|
||||
case MAP_TRANSITION: {
|
||||
@ -1508,8 +1523,8 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
|
||||
ASSERT(type == MAP_TRANSITION);
|
||||
Handle<Map> transition(lookup->GetTransitionMap());
|
||||
int index = transition->PropertyIndexFor(*name);
|
||||
maybe_code = StubCache::ComputeStoreField(*name, *receiver,
|
||||
index, *transition);
|
||||
maybe_code = StubCache::ComputeStoreField(
|
||||
*name, *receiver, index, *transition, extra_ic_state);
|
||||
break;
|
||||
}
|
||||
case NORMAL: {
|
||||
@ -1520,10 +1535,11 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
|
||||
Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
|
||||
JSGlobalPropertyCell* cell =
|
||||
JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
|
||||
maybe_code = StubCache::ComputeStoreGlobal(*name, *global, cell);
|
||||
maybe_code = StubCache::ComputeStoreGlobal(
|
||||
*name, *global, cell, extra_ic_state);
|
||||
} else {
|
||||
if (lookup->holder() != *receiver) return;
|
||||
maybe_code = StubCache::ComputeStoreNormal();
|
||||
maybe_code = StubCache::ComputeStoreNormal(extra_ic_state);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1531,12 +1547,14 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
|
||||
if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
|
||||
AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
|
||||
if (v8::ToCData<Address>(callback->setter()) == 0) return;
|
||||
maybe_code = StubCache::ComputeStoreCallback(*name, *receiver, callback);
|
||||
maybe_code = StubCache::ComputeStoreCallback(
|
||||
*name, *receiver, callback, extra_ic_state);
|
||||
break;
|
||||
}
|
||||
case INTERCEPTOR: {
|
||||
ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined());
|
||||
maybe_code = StubCache::ComputeStoreInterceptor(*name, *receiver);
|
||||
maybe_code = StubCache::ComputeStoreInterceptor(
|
||||
*name, *receiver, extra_ic_state);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -1552,7 +1570,11 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
|
||||
set_target(Code::cast(code));
|
||||
} else if (state == MONOMORPHIC) {
|
||||
// Only move to megamorphic if the target changes.
|
||||
if (target() != Code::cast(code)) set_target(megamorphic_stub());
|
||||
if (target() != Code::cast(code)) {
|
||||
set_target(extra_ic_state == kStoreICStrict
|
||||
? megamorphic_stub_strict()
|
||||
: megamorphic_stub());
|
||||
}
|
||||
} else if (state == MEGAMORPHIC) {
|
||||
// Update the stub cache.
|
||||
StubCache::Set(*name, receiver->map(), Code::cast(code));
|
||||
@ -1795,8 +1817,9 @@ MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) {
|
||||
ASSERT(args.length() == 3);
|
||||
StoreIC ic;
|
||||
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
|
||||
return ic.Store(state, args.at<Object>(0), args.at<String>(1),
|
||||
args.at<Object>(2));
|
||||
Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
|
||||
return ic.Store(state, extra_ic_state, args.at<Object>(0),
|
||||
args.at<String>(1), args.at<Object>(2));
|
||||
}
|
||||
|
||||
|
||||
|
23
src/ic.h
23
src/ic.h
@ -398,9 +398,16 @@ class KeyedLoadIC: public IC {
|
||||
|
||||
class StoreIC: public IC {
|
||||
public:
|
||||
|
||||
enum StoreICStrictMode {
|
||||
kStoreICNonStrict = kNonStrictMode,
|
||||
kStoreICStrict = kStrictMode
|
||||
};
|
||||
|
||||
StoreIC() : IC(NO_EXTRA_FRAME) { ASSERT(target()->is_store_stub()); }
|
||||
|
||||
MUST_USE_RESULT MaybeObject* Store(State state,
|
||||
Code::ExtraICState extra_ic_state,
|
||||
Handle<Object> object,
|
||||
Handle<String> name,
|
||||
Handle<Object> value);
|
||||
@ -408,7 +415,8 @@ class StoreIC: public IC {
|
||||
// Code generators for stub routines. Only called once at startup.
|
||||
static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
|
||||
static void GenerateMiss(MacroAssembler* masm);
|
||||
static void GenerateMegamorphic(MacroAssembler* masm);
|
||||
static void GenerateMegamorphic(MacroAssembler* masm,
|
||||
Code::ExtraICState extra_ic_state);
|
||||
static void GenerateArrayLength(MacroAssembler* masm);
|
||||
static void GenerateNormal(MacroAssembler* masm);
|
||||
static void GenerateGlobalProxy(MacroAssembler* masm);
|
||||
@ -424,7 +432,9 @@ class StoreIC: public IC {
|
||||
// Update the inline cache and the global stub cache based on the
|
||||
// lookup result.
|
||||
void UpdateCaches(LookupResult* lookup,
|
||||
State state, Handle<JSObject> receiver,
|
||||
State state,
|
||||
Code::ExtraICState extra_ic_state,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<String> name,
|
||||
Handle<Object> value);
|
||||
|
||||
@ -432,12 +442,21 @@ class StoreIC: public IC {
|
||||
static Code* megamorphic_stub() {
|
||||
return Builtins::builtin(Builtins::StoreIC_Megamorphic);
|
||||
}
|
||||
static Code* megamorphic_stub_strict() {
|
||||
return Builtins::builtin(Builtins::StoreIC_Megamorphic_Strict);
|
||||
}
|
||||
static Code* initialize_stub() {
|
||||
return Builtins::builtin(Builtins::StoreIC_Initialize);
|
||||
}
|
||||
static Code* initialize_stub_strict() {
|
||||
return Builtins::builtin(Builtins::StoreIC_Initialize_Strict);
|
||||
}
|
||||
static Code* global_proxy_stub() {
|
||||
return Builtins::builtin(Builtins::StoreIC_GlobalProxy);
|
||||
}
|
||||
static Code* global_proxy_stub_strict() {
|
||||
return Builtins::builtin(Builtins::StoreIC_GlobalProxy_Strict);
|
||||
}
|
||||
|
||||
static void Clear(Address address, Code* target);
|
||||
|
||||
|
@ -2610,10 +2610,12 @@ Code::Flags Code::ComputeFlags(Kind kind,
|
||||
PropertyType type,
|
||||
int argc,
|
||||
InlineCacheHolderFlag holder) {
|
||||
// Extra IC state is only allowed for monomorphic call IC stubs.
|
||||
// Extra IC state is only allowed for monomorphic call IC stubs
|
||||
// or for store IC stubs.
|
||||
ASSERT(extra_ic_state == kNoExtraICState ||
|
||||
(kind == CALL_IC && (ic_state == MONOMORPHIC ||
|
||||
ic_state == MONOMORPHIC_PROTOTYPE_FAILURE)));
|
||||
ic_state == MONOMORPHIC_PROTOTYPE_FAILURE)) ||
|
||||
(kind == STORE_IC));
|
||||
// Compute the bit mask.
|
||||
int bits = kind << kFlagsKindShift;
|
||||
if (in_loop) bits |= kFlagsICInLoopMask;
|
||||
|
@ -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) {
|
||||
PrintF(out, "kind = %s\n", Kind2String(kind()));
|
||||
if (is_inline_cache_stub()) {
|
||||
PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
|
||||
PrintExtraICState(out, kind(), extra_ic_state());
|
||||
PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
|
||||
if (ic_state() == MONOMORPHIC) {
|
||||
PrintF(out, "type = %s\n", PropertyType2String(type()));
|
||||
|
@ -3200,6 +3200,7 @@ class Code: public HeapObject {
|
||||
static const char* Kind2String(Kind kind);
|
||||
static const char* ICState2String(InlineCacheState state);
|
||||
static const char* PropertyType2String(PropertyType type);
|
||||
static void PrintExtraICState(FILE* out, Kind kind, ExtraICState extra);
|
||||
inline void Disassemble(const char* name) {
|
||||
Disassemble(name, stdout);
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ void ExternalReferenceTable::PopulateTable() {
|
||||
{ BUILTIN, \
|
||||
Builtins::name, \
|
||||
"Builtins::" #name },
|
||||
#define DEF_ENTRY_A(name, kind, state) DEF_ENTRY_C(name, ignored)
|
||||
#define DEF_ENTRY_A(name, kind, state, extra) DEF_ENTRY_C(name, ignored)
|
||||
|
||||
BUILTIN_LIST_C(DEF_ENTRY_C)
|
||||
BUILTIN_LIST_A(DEF_ENTRY_A)
|
||||
|
@ -497,12 +497,14 @@ MaybeObject* StubCache::ComputeKeyedLoadPixelArray(JSObject* receiver) {
|
||||
MaybeObject* StubCache::ComputeStoreField(String* name,
|
||||
JSObject* receiver,
|
||||
int field_index,
|
||||
Map* transition) {
|
||||
Map* transition,
|
||||
Code::ExtraICState extra_ic_state) {
|
||||
PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
|
||||
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
|
||||
Code::Flags flags = Code::ComputeMonomorphicFlags(
|
||||
Code::STORE_IC, type, extra_ic_state);
|
||||
Object* code = receiver->map()->FindInCodeCache(name, flags);
|
||||
if (code->IsUndefined()) {
|
||||
StoreStubCompiler compiler;
|
||||
StoreStubCompiler compiler(extra_ic_state);
|
||||
{ MaybeObject* maybe_code =
|
||||
compiler.CompileStoreField(receiver, field_index, transition, name);
|
||||
if (!maybe_code->ToObject(&code)) return maybe_code;
|
||||
@ -608,18 +610,22 @@ MaybeObject* StubCache::ComputeKeyedLoadOrStoreExternalArray(
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* StubCache::ComputeStoreNormal() {
|
||||
return Builtins::builtin(Builtins::StoreIC_Normal);
|
||||
MaybeObject* StubCache::ComputeStoreNormal(Code::ExtraICState extra_ic_state) {
|
||||
return Builtins::builtin(extra_ic_state == StoreIC::kStoreICStrict
|
||||
? Builtins::StoreIC_Normal_Strict
|
||||
: Builtins::StoreIC_Normal);
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* StubCache::ComputeStoreGlobal(String* name,
|
||||
GlobalObject* receiver,
|
||||
JSGlobalPropertyCell* cell) {
|
||||
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL);
|
||||
JSGlobalPropertyCell* cell,
|
||||
Code::ExtraICState extra_ic_state) {
|
||||
Code::Flags flags = Code::ComputeMonomorphicFlags(
|
||||
Code::STORE_IC, NORMAL, extra_ic_state);
|
||||
Object* code = receiver->map()->FindInCodeCache(name, flags);
|
||||
if (code->IsUndefined()) {
|
||||
StoreStubCompiler compiler;
|
||||
StoreStubCompiler compiler(extra_ic_state);
|
||||
{ MaybeObject* maybe_code =
|
||||
compiler.CompileStoreGlobal(receiver, cell, name);
|
||||
if (!maybe_code->ToObject(&code)) return maybe_code;
|
||||
@ -636,14 +642,17 @@ MaybeObject* StubCache::ComputeStoreGlobal(String* name,
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* StubCache::ComputeStoreCallback(String* name,
|
||||
JSObject* receiver,
|
||||
AccessorInfo* callback) {
|
||||
MaybeObject* StubCache::ComputeStoreCallback(
|
||||
String* name,
|
||||
JSObject* receiver,
|
||||
AccessorInfo* callback,
|
||||
Code::ExtraICState extra_ic_state) {
|
||||
ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
|
||||
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, CALLBACKS);
|
||||
Code::Flags flags = Code::ComputeMonomorphicFlags(
|
||||
Code::STORE_IC, CALLBACKS, extra_ic_state);
|
||||
Object* code = receiver->map()->FindInCodeCache(name, flags);
|
||||
if (code->IsUndefined()) {
|
||||
StoreStubCompiler compiler;
|
||||
StoreStubCompiler compiler(extra_ic_state);
|
||||
{ MaybeObject* maybe_code =
|
||||
compiler.CompileStoreCallback(receiver, callback, name);
|
||||
if (!maybe_code->ToObject(&code)) return maybe_code;
|
||||
@ -660,13 +669,15 @@ MaybeObject* StubCache::ComputeStoreCallback(String* name,
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* StubCache::ComputeStoreInterceptor(String* name,
|
||||
JSObject* receiver) {
|
||||
Code::Flags flags =
|
||||
Code::ComputeMonomorphicFlags(Code::STORE_IC, INTERCEPTOR);
|
||||
MaybeObject* StubCache::ComputeStoreInterceptor(
|
||||
String* name,
|
||||
JSObject* receiver,
|
||||
Code::ExtraICState extra_ic_state) {
|
||||
Code::Flags flags = Code::ComputeMonomorphicFlags(
|
||||
Code::STORE_IC, INTERCEPTOR, extra_ic_state);
|
||||
Object* code = receiver->map()->FindInCodeCache(name, flags);
|
||||
if (code->IsUndefined()) {
|
||||
StoreStubCompiler compiler;
|
||||
StoreStubCompiler compiler(extra_ic_state);
|
||||
{ MaybeObject* maybe_code =
|
||||
compiler.CompileStoreInterceptor(receiver, name);
|
||||
if (!maybe_code->ToObject(&code)) return maybe_code;
|
||||
@ -1637,7 +1648,8 @@ MaybeObject* KeyedLoadStubCompiler::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);
|
||||
if (!result->IsFailure()) {
|
||||
PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG,
|
||||
|
@ -138,26 +138,32 @@ class StubCache : public AllStatic {
|
||||
|
||||
// ---
|
||||
|
||||
MUST_USE_RESULT static MaybeObject* ComputeStoreField(String* name,
|
||||
JSObject* receiver,
|
||||
int field_index,
|
||||
Map* transition = NULL);
|
||||
MUST_USE_RESULT static MaybeObject* ComputeStoreField(
|
||||
String* name,
|
||||
JSObject* receiver,
|
||||
int field_index,
|
||||
Map* transition,
|
||||
Code::ExtraICState extra_ic_state);
|
||||
|
||||
MUST_USE_RESULT static MaybeObject* ComputeStoreNormal();
|
||||
MUST_USE_RESULT static MaybeObject* ComputeStoreNormal(
|
||||
Code::ExtraICState extra_ic_state);
|
||||
|
||||
MUST_USE_RESULT static MaybeObject* ComputeStoreGlobal(
|
||||
String* name,
|
||||
GlobalObject* receiver,
|
||||
JSGlobalPropertyCell* cell);
|
||||
JSGlobalPropertyCell* cell,
|
||||
Code::ExtraICState extra_ic_state);
|
||||
|
||||
MUST_USE_RESULT static MaybeObject* ComputeStoreCallback(
|
||||
String* name,
|
||||
JSObject* receiver,
|
||||
AccessorInfo* callback);
|
||||
AccessorInfo* callback,
|
||||
Code::ExtraICState extra_ic_state);
|
||||
|
||||
MUST_USE_RESULT static MaybeObject* ComputeStoreInterceptor(
|
||||
String* name,
|
||||
JSObject* receiver);
|
||||
JSObject* receiver,
|
||||
Code::ExtraICState extra_ic_state);
|
||||
|
||||
// ---
|
||||
|
||||
@ -619,6 +625,9 @@ class KeyedLoadStubCompiler: public StubCompiler {
|
||||
|
||||
class StoreStubCompiler: public StubCompiler {
|
||||
public:
|
||||
explicit StoreStubCompiler(Code::ExtraICState extra_ic_state)
|
||||
: extra_ic_state_(extra_ic_state) { }
|
||||
|
||||
MUST_USE_RESULT MaybeObject* CompileStoreField(JSObject* object,
|
||||
int index,
|
||||
Map* transition,
|
||||
@ -636,6 +645,8 @@ class StoreStubCompiler: public StubCompiler {
|
||||
|
||||
private:
|
||||
MaybeObject* GetCode(PropertyType type, String* name);
|
||||
|
||||
Code::ExtraICState extra_ic_state_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -4894,7 +4894,8 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
|
||||
Load(property->value());
|
||||
if (property->emit_store()) {
|
||||
Result ignored =
|
||||
frame_->CallStoreIC(Handle<String>::cast(key), false);
|
||||
frame_->CallStoreIC(Handle<String>::cast(key), false,
|
||||
strict_mode_flag());
|
||||
// A test rax instruction following the store IC call would
|
||||
// indicate the presence of an inlined version of the
|
||||
// store. Add a nop to indicate that there is no such
|
||||
@ -8234,7 +8235,7 @@ Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
|
||||
|
||||
Result result;
|
||||
if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) {
|
||||
result = frame()->CallStoreIC(name, is_contextual);
|
||||
result = frame()->CallStoreIC(name, is_contextual, strict_mode_flag());
|
||||
// A test rax instruction following the call signals that the inobject
|
||||
// property case was inlined. Ensure that there is not a test rax
|
||||
// instruction here.
|
||||
@ -8334,7 +8335,7 @@ Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
|
||||
slow.Bind(&value, &receiver);
|
||||
frame()->Push(&receiver);
|
||||
frame()->Push(&value);
|
||||
result = frame()->CallStoreIC(name, is_contextual);
|
||||
result = frame()->CallStoreIC(name, is_contextual, strict_mode_flag());
|
||||
// Encode the offset to the map check instruction and the offset
|
||||
// to the write barrier store address computation in a test rax
|
||||
// instruction.
|
||||
|
@ -1715,8 +1715,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
|
||||
// rcx, and the global object on the stack.
|
||||
__ Move(rcx, var->name());
|
||||
__ movq(rdx, GlobalObjectOperand());
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
||||
Handle<Code> ic(Builtins::builtin(is_strict()
|
||||
? Builtins::StoreIC_Initialize_Strict
|
||||
: Builtins::StoreIC_Initialize));
|
||||
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
||||
|
||||
} else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) {
|
||||
// Perform the assignment for non-const variables and for initialization
|
||||
|
@ -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 -------------
|
||||
// -- rax : value
|
||||
// -- rcx : name
|
||||
@ -1484,7 +1485,8 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
|
||||
// Get the receiver from the stack and probe the stub cache.
|
||||
Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
|
||||
NOT_IN_LOOP,
|
||||
MONOMORPHIC);
|
||||
MONOMORPHIC,
|
||||
extra_ic_state);
|
||||
StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg);
|
||||
|
||||
// Cache miss: Jump to runtime.
|
||||
|
@ -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.
|
||||
// The IC expects name in rcx, value in rax, and receiver in rdx.
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
Handle<Code> ic(Builtins::builtin(strict_mode == kStrictMode
|
||||
? Builtins::StoreIC_Initialize_Strict
|
||||
: Builtins::StoreIC_Initialize));
|
||||
Result value = Pop();
|
||||
RelocInfo::Mode mode;
|
||||
if (is_contextual) {
|
||||
PrepareForCall(0, 0);
|
||||
value.ToRegister(rax);
|
||||
__ movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
||||
value.Unuse();
|
||||
mode = RelocInfo::CODE_TARGET_CONTEXT;
|
||||
} else {
|
||||
Result receiver = Pop();
|
||||
PrepareForCall(0, 0);
|
||||
MoveResultsToRegisters(&value, &receiver, rax, rdx);
|
||||
mode = RelocInfo::CODE_TARGET;
|
||||
}
|
||||
__ Move(rcx, name);
|
||||
return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
|
||||
return RawCallCodeObject(ic, mode);
|
||||
}
|
||||
|
||||
|
||||
|
@ -338,7 +338,8 @@ class VirtualFrame : public ZoneObject {
|
||||
|
||||
// Call store IC. If the load is contextual, value is found on top of the
|
||||
// frame. If not, value and receiver are on the frame. Both are dropped.
|
||||
Result CallStoreIC(Handle<String> name, bool is_contextual);
|
||||
Result CallStoreIC(Handle<String> name, bool is_contextual,
|
||||
StrictModeFlag strict_mode);
|
||||
|
||||
// Call keyed store IC. Value, key, and receiver are found on top
|
||||
// of the frame. All three are dropped.
|
||||
|
@ -997,7 +997,7 @@ TEST(DebugStub) {
|
||||
CheckDebugBreakFunction(&env,
|
||||
"function f2(){x=1;}", "f2",
|
||||
0,
|
||||
v8::internal::RelocInfo::CODE_TARGET,
|
||||
v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
|
||||
Builtins::builtin(Builtins::StoreIC_DebugBreak));
|
||||
CheckDebugBreakFunction(&env,
|
||||
"function f3(){var a=x;}", "f3",
|
||||
|
@ -264,9 +264,6 @@ chapter10/10.6/10.6-13-c-1-s: FAIL
|
||||
# arguments.callee is non-configurable in strict mode
|
||||
chapter10/10.6/10.6-13-c-3-s: FAIL
|
||||
|
||||
# simple assignment throws ReferenceError if LeftHandSide is an unresolvable
|
||||
# reference in strict mode
|
||||
chapter11/11.13/11.13.1/11.13.1-1-5-s: FAIL
|
||||
# simple assignment throws TypeError if LeftHandSide is a property reference
|
||||
# with a primitive base value (this is undefined)
|
||||
chapter11/11.13/11.13.1/11.13.1-1-7-s: FAIL
|
||||
|
@ -335,4 +335,42 @@ for (var i = 0; i < future_reserved_words.length; 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 */,
|
||||
893E248F12B14B3D0083370F /* hydrogen.cc */,
|
||||
893E249012B14B3D0083370F /* hydrogen.h */,
|
||||
897FF1490E719B8F00D62E90 /* ic-arm.cc */,
|
||||
897FF14B0E719B8F00D62E90 /* ic-inl.h */,
|
||||
897FF14C0E719B8F00D62E90 /* ic.cc */,
|
||||
897FF14D0E719B8F00D62E90 /* ic.h */,
|
||||
@ -1285,7 +1284,6 @@
|
||||
897FF1890E719B8F00D62E90 /* string-stream.h */,
|
||||
893E24A312B14B3D0083370F /* strtod.cc */,
|
||||
893E24A412B14B3D0083370F /* strtod.h */,
|
||||
897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */,
|
||||
897FF18C0E719B8F00D62E90 /* stub-cache.cc */,
|
||||
897FF18D0E719B8F00D62E90 /* stub-cache.h */,
|
||||
897FF18E0E719B8F00D62E90 /* token.cc */,
|
||||
@ -1534,6 +1532,7 @@
|
||||
898BD20C0EF6CC850068B00A /* debug-arm.cc */,
|
||||
893E24C612B14B510083370F /* deoptimizer-arm.cc */,
|
||||
9FA38BCB1175B30400C4CD55 /* full-codegen-arm.cc */,
|
||||
897FF1490E719B8F00D62E90 /* ic-arm.cc */,
|
||||
9FA38BCC1175B30400C4CD55 /* jump-target-arm.cc */,
|
||||
893E24C712B14B510083370F /* lithium-arm.cc */,
|
||||
893E24C812B14B510083370F /* lithium-arm.h */,
|
||||
@ -1548,6 +1547,7 @@
|
||||
895FA751107FFEAE006F39D4 /* register-allocator-arm.h */,
|
||||
897FF17D0E719B8F00D62E90 /* simulator-arm.cc */,
|
||||
897FF17E0E719B8F00D62E90 /* simulator-arm.h */,
|
||||
897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */,
|
||||
893E24CB12B14B520083370F /* virtual-frame-arm-inl.h */,
|
||||
9FA38BCD1175B30400C4CD55 /* virtual-frame-arm.cc */,
|
||||
58950D570F55514900F3E8BA /* virtual-frame-arm.h */,
|
||||
|
Loading…
Reference in New Issue
Block a user