Implement assignment to undefined reference in ES5 Strict Mode.

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

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

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

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

1
.gitignore vendored
View File

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

View File

@ -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;

View File

@ -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

View File

@ -1533,7 +1533,8 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
}
void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
Code::ExtraICState extra_ic_state) {
// ----------- S t a t e -------------
// -- 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.

View File

@ -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);
}

View File

@ -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);
}

View File

@ -294,7 +294,8 @@ class VirtualFrame : public ZoneObject {
// Call store IC. If the load is contextual, value is found on top of the
// 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.

View File

@ -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,

View File

@ -1307,6 +1307,11 @@ static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
}
static void Generate_StoreIC_Initialize_Strict(MacroAssembler* masm) {
StoreIC::GenerateInitialize(masm);
}
static void Generate_StoreIC_Miss(MacroAssembler* masm) {
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.

View File

@ -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)

View File

@ -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) {

View File

@ -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(); }

View File

@ -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.

View File

@ -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

View File

@ -1488,7 +1488,8 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
}
void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
Code::ExtraICState extra_ic_state) {
// ----------- S t a t e -------------
// -- 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.

View File

@ -1033,23 +1033,31 @@ Result VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) {
}
Result VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) {
Result VirtualFrame::CallStoreIC(Handle<String> name,
bool is_contextual,
StrictModeFlag strict_mode) {
// Value and (if not contextual) receiver are on top of the frame.
// 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);
}

View File

@ -365,7 +365,8 @@ class VirtualFrame: public ZoneObject {
// Call store IC. If the load is contextual, value is found on top of the
// 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.

View File

@ -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));
}

View File

@ -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);

View File

@ -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;

View File

@ -6238,10 +6238,35 @@ const char* Code::PropertyType2String(PropertyType type) {
}
void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
const char* name = NULL;
switch (kind) {
case CALL_IC:
if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
name = "STRING_INDEX_OUT_OF_BOUNDS";
}
break;
case STORE_IC:
if (extra == StoreIC::kStoreICStrict) {
name = "STRICT";
}
break;
default:
break;
}
if (name != NULL) {
PrintF(out, "extra_ic_state = %s\n", name);
} else {
PrintF(out, "etra_ic_state = %d\n", extra);
}
}
void Code::Disassemble(const char* name, FILE* out) {
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()));

View File

@ -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);
}

View File

@ -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)

View File

@ -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,

View File

@ -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_;
};

View File

@ -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.

View File

@ -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

View File

@ -1473,7 +1473,8 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
}
void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
Code::ExtraICState extra_ic_state) {
// ----------- S t a t e -------------
// -- 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.

View File

@ -1119,23 +1119,30 @@ Result VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) {
}
Result VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) {
Result VirtualFrame::CallStoreIC(Handle<String> name,
bool is_contextual,
StrictModeFlag strict_mode) {
// Value and (if not contextual) receiver are on top of the frame.
// 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);
}

View File

@ -338,7 +338,8 @@ class VirtualFrame : public ZoneObject {
// Call store IC. If the load is contextual, value is found on top of the
// 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.

View File

@ -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",

View File

@ -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

View File

@ -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); });

View File

@ -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 */,