Implement assignment to undefined reference in ES5 Strict Mode.
authormmaly@chromium.org <mmaly@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 11 Feb 2011 21:39:59 +0000 (21:39 +0000)
committermmaly@chromium.org <mmaly@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 11 Feb 2011 21:39:59 +0000 (21:39 +0000)
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@6756 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

34 files changed:
.gitignore
src/arm/codegen-arm.cc
src/arm/full-codegen-arm.cc
src/arm/ic-arm.cc
src/arm/lithium-codegen-arm.cc
src/arm/virtual-frame-arm.cc
src/arm/virtual-frame-arm.h
src/assembler.h
src/builtins.cc
src/builtins.h
src/compiler.h
src/full-codegen.h
src/ia32/codegen-ia32.cc
src/ia32/full-codegen-ia32.cc
src/ia32/ic-ia32.cc
src/ia32/virtual-frame-ia32.cc
src/ia32/virtual-frame-ia32.h
src/ic.cc
src/ic.h
src/objects-inl.h
src/objects.cc
src/objects.h
src/serialize.cc
src/stub-cache.cc
src/stub-cache.h
src/x64/codegen-x64.cc
src/x64/full-codegen-x64.cc
src/x64/ic-x64.cc
src/x64/virtual-frame-x64.cc
src/x64/virtual-frame-x64.h
test/cctest/test-debug.cc
test/es5conform/es5conform.status
test/mjsunit/strict-mode.js
tools/v8.xcodeproj/project.pbxproj

index c68dadb..2eab942 100644 (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
index 87c4968..c827110 100644 (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;
index e357450..2685fcb 100644 (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
index 60c1067..8c76458 100644 (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.
index ca11d64..b8462dd 100644 (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);
 }
 
index 3266a16..b4b518c 100644 (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);
 }
 
 
index 82b4d08..b6e794a 100644 (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.
index e8bc5d6..b089b09 100644 (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,
index 0373cdc..8fdc1b1 100644 (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.
index 88d31c7..ada23a7 100644 (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)
index 9843dd6..239bea3 100644 (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) {
index b85c8c6..655e560 100644 (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(); }
index 0d8b03d..b977db8 100644 (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.
index 5dfbc02..18c9319 100644 (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
index 3fe8fdb..76681ce 100644 (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.
index 11e1aaf..1cc91a9 100644 (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);
 }
 
 
index b9faa46..729469f 100644 (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.
index 8e282ad..62ab0f2 100644 (file)
--- a/src/ic.cc
+++ b/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));
 }
 
 
index 409ad38..3b10d06 100644 (file)
--- a/src/ic.h
+++ b/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);
 
index 302c0a4..24887a0 100644 (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;
index bbb4f1c..5003b4f 100644 (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()));
index 9fa008f..264cc0b 100644 (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);
   }
index 60c2cbb..f8e98d3 100644 (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)
index 7317141..f87728b 100644 (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,
index 6d78279..8266352 100644 (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:
+  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_;
 };
 
 
index 6b63957..fe90567 100644 (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.
index 3574f72..556ec85 100644 (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
index 921c868..8c2856f 100644 (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.
index 3f7b1db..31f9527 100644 (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);
 }
 
 
index 0479ff0..4a9c720 100644 (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.
index b9f6038..441aae6 100644 (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",
index 434f9d1..39754ca 100644 (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
index ddddfab..6b775fc 100644 (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); });
index c201c4b..24321e5 100644 (file)
                                893E248E12B14B3D0083370F /* hydrogen-instructions.h */,
                                893E248F12B14B3D0083370F /* hydrogen.cc */,
                                893E249012B14B3D0083370F /* hydrogen.h */,
-                               897FF1490E719B8F00D62E90 /* ic-arm.cc */,
                                897FF14B0E719B8F00D62E90 /* ic-inl.h */,
                                897FF14C0E719B8F00D62E90 /* ic.cc */,
                                897FF14D0E719B8F00D62E90 /* ic.h */,
                                897FF1890E719B8F00D62E90 /* string-stream.h */,
                                893E24A312B14B3D0083370F /* strtod.cc */,
                                893E24A412B14B3D0083370F /* strtod.h */,
-                               897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */,
                                897FF18C0E719B8F00D62E90 /* stub-cache.cc */,
                                897FF18D0E719B8F00D62E90 /* stub-cache.h */,
                                897FF18E0E719B8F00D62E90 /* token.cc */,
                                898BD20C0EF6CC850068B00A /* debug-arm.cc */,
                                893E24C612B14B510083370F /* deoptimizer-arm.cc */,
                                9FA38BCB1175B30400C4CD55 /* full-codegen-arm.cc */,
+                               897FF1490E719B8F00D62E90 /* ic-arm.cc */,
                                9FA38BCC1175B30400C4CD55 /* jump-target-arm.cc */,
                                893E24C712B14B510083370F /* lithium-arm.cc */,
                                893E24C812B14B510083370F /* lithium-arm.h */,
                                895FA751107FFEAE006F39D4 /* register-allocator-arm.h */,
                                897FF17D0E719B8F00D62E90 /* simulator-arm.cc */,
                                897FF17E0E719B8F00D62E90 /* simulator-arm.h */,
+                               897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */,
                                893E24CB12B14B520083370F /* virtual-frame-arm-inl.h */,
                                9FA38BCD1175B30400C4CD55 /* virtual-frame-arm.cc */,
                                58950D570F55514900F3E8BA /* virtual-frame-arm.h */,