Split the global object into two parts: The state holding global object and the global object proxy.

Fixed bug that affected the value of an assignment to an element in certain cases (issue 116).

Added GetPropertyNames functionality (issue 33) and extra Date functions (issue 77) to the API.

Changed WeakReferenceCallback to take a Persistent<Value> instead of a Persistent<Object> (issue 101).

Fixed issues with message reporting for exceptions in try-finally blocks (issues 73 and 75).

Optimized flattening of strings and string equality checking. 

Improved Boyer-Moore implementation for faster indexOf operations.

Added development shell (d8) which includes counters and completion support.

Fixed problem with the receiver passed to functions called from eval (issue 124).


git-svn-id: http://v8.googlecode.com/svn/trunk@572 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/macro-assembler-ia32.cc b/src/macro-assembler-ia32.cc
index e72eeb2..72808de 100644
--- a/src/macro-assembler-ia32.cc
+++ b/src/macro-assembler-ia32.cc
@@ -469,7 +469,7 @@
 
     // Only global objects and objects that do not require access
     // checks are allowed in stubs.
-    ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
+    ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
 
     JSObject* prototype = JSObject::cast(object->GetPrototype());
     if (Heap::InNewSpace(prototype)) {
@@ -481,16 +481,18 @@
       // Check access rights to the global object.  This has to happen
       // after the map check so that we know that the object is
       // actually a global object.
-      if (object->IsJSGlobalObject()) {
-        CheckAccessGlobal(reg, scratch, miss);
-        // Restore scratch register to be the map of the object.  We
-        // load the prototype from the map in the scratch register.
+      if (object->IsJSGlobalProxy()) {
+        CheckAccessGlobalProxy(reg, scratch, miss);
+
+        // Restore scratch register to be the map of the object.
+        // We load the prototype from the map in the scratch register.
         mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
       }
       // The prototype is in new space; we cannot store a reference
       // to it in the code. Load it from the map.
       reg = holder_reg;  // from now the object is in holder_reg
       mov(reg, FieldOperand(scratch, Map::kPrototypeOffset));
+
     } else {
       // Check the map of the current object.
       cmp(FieldOperand(reg, HeapObject::kMapOffset),
@@ -500,8 +502,8 @@
       // Check access rights to the global object.  This has to happen
       // after the map check so that we know that the object is
       // actually a global object.
-      if (object->IsJSGlobalObject()) {
-        CheckAccessGlobal(reg, scratch, miss);
+      if (object->IsJSGlobalProxy()) {
+        CheckAccessGlobalProxy(reg, scratch, miss);
       }
       // The prototype is in old space; load it directly.
       reg = holder_reg;  // from now the object is in holder_reg
@@ -523,37 +525,79 @@
   // Perform security check for access to the global object and return
   // the holder register.
   ASSERT(object == holder);
-  ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
-  if (object->IsJSGlobalObject()) {
-    CheckAccessGlobal(reg, scratch, miss);
+  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+  if (object->IsJSGlobalProxy()) {
+    CheckAccessGlobalProxy(reg, scratch, miss);
   }
   return reg;
 }
 
 
-void MacroAssembler::CheckAccessGlobal(Register holder_reg,
-                                       Register scratch,
-                                       Label* miss) {
+void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
+                                          Register scratch,
+                                          Label* miss) {
+  Label same_contexts;
+
   ASSERT(!holder_reg.is(scratch));
 
-  // Load the security context.
-  ExternalReference security_context =
-      ExternalReference(Top::k_security_context_address);
-  mov(scratch, Operand::StaticVariable(security_context));
-  // When generating debug code, make sure the security context is set.
+  // Load current lexical context from the stack frame.
+  mov(scratch, Operand(ebp, StandardFrameConstants::kContextOffset));
+
+  // When generating debug code, make sure the lexical context is set.
   if (FLAG_debug_code) {
     cmp(Operand(scratch), Immediate(0));
-    Check(not_equal, "we should not have an empty security context");
+    Check(not_equal, "we should not have an empty lexical context");
   }
-  // Load the global object of the security context.
+  // Load the global context of the current context.
   int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
   mov(scratch, FieldOperand(scratch, offset));
+  mov(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
+
+  // Check the context is a global context.
+  if (FLAG_debug_code) {
+    push(scratch);
+    // Read the first word and compare to global_context_map.
+    mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
+    cmp(scratch, Factory::global_context_map());
+    Check(equal, "JSGlobalObject::global_context should be a global context.");
+    pop(scratch);
+  }
+
+  // Check if both contexts are the same.
+  cmp(scratch, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
+  j(equal, &same_contexts, taken);
+
+  // Compare security tokens, save holder_reg on the stack so we can use it
+  // as a temporary register.
+  //
+  // TODO(119): avoid push(holder_reg)/pop(holder_reg)
+  push(holder_reg);
   // Check that the security token in the calling global object is
   // compatible with the security token in the receiving global
   // object.
-  mov(scratch, FieldOperand(scratch, JSGlobalObject::kSecurityTokenOffset));
-  cmp(scratch, FieldOperand(holder_reg, JSGlobalObject::kSecurityTokenOffset));
+  mov(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
+
+  // Check the context is a global context.
+  if (FLAG_debug_code) {
+    cmp(holder_reg, Factory::null_value());
+    Check(not_equal, "JSGlobalProxy::context() should not be null.");
+
+    push(holder_reg);
+    // Read the first word and compare to global_context_map(),
+    mov(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset));
+    cmp(holder_reg, Factory::global_context_map());
+    Check(equal, "JSGlobalObject::global_context should be a global context.");
+    pop(holder_reg);
+  }
+
+  int token_offset = Context::kHeaderSize +
+                     Context::SECURITY_TOKEN_INDEX * kPointerSize;
+  mov(scratch, FieldOperand(scratch, token_offset));
+  cmp(scratch, FieldOperand(holder_reg, token_offset));
+  pop(holder_reg);
   j(not_equal, miss, not_taken);
+
+  bind(&same_contexts);
 }