Reviewers: Jakob,

Message:
PTAL

Description:
Always fail when trying to store to an undeclared global variable, even if it
was found.

Finding a property, but not using an IC, indicates that the variable was
found on the prototype (in DOMWindow). Those properties need to be
ignored while storing global properties via the IC.


Please review this at https://chromiumcodereview.appspot.com/12040039/

SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge

Affected files:
  M src/ic.h
  M src/ic.cc
  M src/stub-cache.cc
  M test/cctest/cctest.gyp
  A + test/cctest/test-global-object.cc


Index: src/ic.cc
diff --git a/src/ic.cc b/src/ic.cc
index b90436ae42c5f38feed72cf4d44be0d6f6b8b04f..17d2bb45ee5ce661cd516532ce18c8cbf273f8eb 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -542,7 +542,7 @@ MaybeObject* CallICBase::LoadFunction(State state,
   if (!lookup.IsFound()) {
     // If the object does not have the requested property, check which
     // exception we need to throw.
-    return IsContextual(object)
+    return IsUndeclaredGlobal(object)
         ? ReferenceError("not_defined", name)
         : TypeError("undefined_method", object, name);
   }
@@ -561,7 +561,7 @@ MaybeObject* CallICBase::LoadFunction(State state,
   if (lookup.IsInterceptor() && attr == ABSENT) {
     // If the object does not have the requested property, check which
     // exception we need to throw.
-    return IsContextual(object)
+    return IsUndeclaredGlobal(object)
         ? ReferenceError("not_defined", name)
         : TypeError("undefined_method", object, name);
   }
@@ -933,7 +933,7 @@ MaybeObject* IC::Load(State state,

   // If we did not find a property, check if we need to throw an exception.
   if (!lookup.IsFound()) {
-    if (IsContextual(object)) {
+    if (IsUndeclaredGlobal(object)) {
       return ReferenceError("not_defined", name);
     }
     LOG(isolate(), SuspectReadEvent(*name, *object));
@@ -952,7 +952,7 @@ MaybeObject* IC::Load(State state,
     RETURN_IF_EMPTY_HANDLE(isolate(), result);
     // If the property is not present, check if we need to throw an
     // exception.
-    if (attr == ABSENT && IsContextual(object)) {
+    if (attr == ABSENT && IsUndeclaredGlobal(object)) {
       return ReferenceError("not_defined", name);
     }
     return *result;
@@ -1390,11 +1390,8 @@ MaybeObject* IC::Store(State state,
     if (FLAG_use_ic) {
UpdateStoreCaches(&lookup, state, strict_mode, receiver, name, value);
     }
-  } else if (strict_mode == kStrictMode &&
-             !lookup.IsFound() &&
-             IsContextual(object)) {
-    // Strict mode doesn't allow setting non-existent global property
-    // or an assignment to a read only property.
+  } else if (strict_mode == kStrictMode && IsUndeclaredGlobal(object)) {
+    // Strict mode doesn't allow setting non-existent global property.
     return ReferenceError("not_defined", name);
   }

Index: src/ic.h
diff --git a/src/ic.h b/src/ic.h
index 784512a1c49f8b2f421495dc93cee5d1a1fafadb..04b0bb5a83a06962f788ea3e7347b364c0e3e542 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -110,16 +110,16 @@ class IC {

   // Returns if this IC is for contextual (no explicit receiver)
   // access to properties.
-  bool IsContextual(Handle<Object> receiver) {
+  bool IsUndeclaredGlobal(Handle<Object> receiver) {
     if (receiver->IsGlobalObject()) {
-      return SlowIsContextual();
+      return SlowIsUndeclaredGlobal();
     } else {
-      ASSERT(!SlowIsContextual());
+      ASSERT(!SlowIsUndeclaredGlobal());
       return false;
     }
   }

-  bool SlowIsContextual() {
+  bool SlowIsUndeclaredGlobal() {
     return ComputeMode() == RelocInfo::CODE_TARGET_CONTEXT;
   }

Index: src/stub-cache.cc
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 08954ba618ae7ef761a9e9a8df1fc8289fb9b9d9..0e8f755c9ff72612826d04f9be1aaf278bdefea5 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -1057,7 +1057,7 @@ static MaybeObject* ThrowReferenceError(String* name) {
   // can't use either LoadIC or KeyedLoadIC constructors.
   IC ic(IC::NO_EXTRA_FRAME, Isolate::Current());
   ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
-  if (!ic.SlowIsContextual()) return HEAP->undefined_value();
+  if (!ic.SlowIsUndeclaredGlobal()) return HEAP->undefined_value();

   // Throw a reference error.
   HandleScope scope;
Index: test/cctest/cctest.gyp
diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp
index 80eecfd0316f2e87d8590bfdbdd0cc03c0a95072..18a116ab65641df60e6cd882cf04b10e28a513f7 100644
--- a/test/cctest/cctest.gyp
+++ b/test/cctest/cctest.gyp
@@ -69,6 +69,7 @@
         'test-fixed-dtoa.cc',
         'test-flags.cc',
         'test-func-name-inference.cc',
+        'test-global-object.cc',
         'test-hashing.cc',
         'test-hashmap.cc',
         'test-heap.cc',
Index: test/cctest/test-global-object.cc
diff --git a/test/mjsunit/regress/regress-2499.js b/test/cctest/test-global-object.cc
similarity index 65%
copy from test/mjsunit/regress/regress-2499.js
copy to test/cctest/test-global-object.cc
index 52aad874db6fcdc89f5ee1ae4db45304e64b0e77..049b53d117b61f7b918fca9e6e368aca6520ebb7 100644
--- a/test/mjsunit/regress/regress-2499.js
+++ b/test/cctest/test-global-object.cc
@@ -25,16 +25,29 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-// Flags: --allow-natives-syntax
+#include "v8.h"

-function foo(word, nBits) {
-  return (word[1] >>> nBits) | (word[0] << (32 - nBits));
-}
+#include "cctest.h"

-word = [0x1001, 0];
+using namespace v8;

-var expected = foo(word, 1);
-foo(word, 1);
-%OptimizeFunctionOnNextCall(foo);
-var optimized = foo(word, 1);
-assertEquals(expected, optimized)
+// This test fails if properties on the prototype of the global object appear
+// as declared globals.
+TEST(StrictUndeclaredGlobalVariable) {
+  HandleScope scope;
+  v8::Local<v8::String> var_name = v8_str("x");
+  v8::Local<v8::String> result_name = v8_str("z");
+  LocalContext context;
+  v8::Local<v8::Script> script =
+      v8_compile("\"use strict\";"
+                 "var z;"
+                 "try { x = 42; z = 10; } catch (e) { z = 20; };");
+  v8::Handle<v8::Object> proto = v8::Object::New();
+  v8::Handle<v8::Object> global =
+      context->Global()->GetPrototype().As<v8::Object>();
+  proto->Set(var_name, v8_num(100));
+  global->SetPrototype(proto);
+  script->Run();
+  v8::Local<v8::Value> result = context->Global()->Get(result_name);
+  CHECK_EQ(20, result->Int32Value());
+}


--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to