No more failures than before. It is ready to be reviewed.
authorfeng@chromium.org <feng@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 21 Oct 2008 20:11:50 +0000 (20:11 +0000)
committerfeng@chromium.org <feng@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 21 Oct 2008 20:11:50 +0000 (20:11 +0000)
Review URL: http://codereview.chromium.org/7420

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@544 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/builtins-arm.cc
src/codegen-arm.cc
src/codegen-arm.h
src/ic-arm.cc
src/macro-assembler-arm.cc
src/macro-assembler-arm.h
src/stub-cache-arm.cc

index 68b5f1d..c1b654f 100644 (file)
@@ -333,11 +333,12 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
     __ LeaveInternalFrame();
     __ b(&patch_receiver);
 
-    // Use the global object from the called function as the receiver.
+    // Use the global receiver object from the called function as the receiver.
     __ bind(&use_global_receiver);
     const int kGlobalIndex =
         Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
     __ ldr(r2, FieldMemOperand(cp, kGlobalIndex));
+    __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
 
     __ bind(&patch_receiver);
     __ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2));
@@ -472,10 +473,12 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
   __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
   __ b(&push_receiver);
 
-  // Use the current global object as the receiver.
+  // Use the current global receiver object as the receiver.
   __ bind(&use_global_receiver);
-  __ ldr(r0, FieldMemOperand(cp, Context::kHeaderSize +
-                             Context::GLOBAL_INDEX * kPointerSize));
+  const int kGlobalOffset =
+      Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
+  __ ldr(r0, FieldMemOperand(cp, kGlobalOffset));
+  __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
 
   // Push the receiver.
   // r0: receiver
index 92206dd..f89525d 100644 (file)
@@ -415,6 +415,13 @@ void CodeGenerator::LoadGlobal() {
 }
 
 
+void CodeGenerator::LoadGlobalReceiver(Register s) {
+  __ ldr(s, ContextOperand(cp, Context::GLOBAL_INDEX));
+  __ ldr(s, FieldMemOperand(s, GlobalObject::kGlobalReceiverOffset));
+  __ push(s);
+}
+
+
 // TODO(1241834): Get rid of this function in favor of just using Load, now
 // that we have the INSIDE_TYPEOF typeof state. => Need to handle global
 // variables w/o reference errors elsewhere.
@@ -2220,7 +2227,10 @@ void CodeGenerator::VisitCall(Call* node) {
     // Push the name of the function and the receiver onto the stack.
     __ mov(r0, Operand(var->name()));
     __ push(r0);
-    LoadGlobal();
+
+    // TODO(120): use JSGlobalObject for function lookup and inline cache,
+    // and use global proxy as 'this' for invocation.
+    LoadGlobalReceiver(r0);
 
     // Load the arguments.
     for (int i = 0; i < args->length(); i++) Load(args->at(i));
@@ -2308,7 +2318,10 @@ void CodeGenerator::VisitCall(Call* node) {
     // Load the function.
     Load(function);
     // Pass the global object as the receiver.
-    LoadGlobal();
+
+    // TODO(120): use JSGlobalObject for function lookup and inline cache,
+    // and use global proxy as 'this' for invocation.
+    LoadGlobalReceiver(r0);
     // Call the function.
     CallWithArguments(args, node->position());
     __ push(r0);
@@ -2328,7 +2341,7 @@ void CodeGenerator::VisitCallNew(CallNew* node) {
   // Compute function to call and use the global object as the
   // receiver.
   Load(node->expression());
-  LoadGlobal();
+  LoadGlobalReceiver(r0);
 
   // Push the arguments ("left-to-right") on the stack.
   ZoneList<Expression*>* args = node->arguments();
@@ -2873,12 +2886,11 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
   // inlining a null check instead of calling the (very) general
   // runtime routine for checking equality.
 
-  bool left_is_null =
-    left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
-  bool right_is_null =
-    right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
-
   if (op == Token::EQ || op == Token::EQ_STRICT) {
+    bool left_is_null =
+      left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
+    bool right_is_null =
+      right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
     // The 'null' value is only equal to 'null' or 'undefined'.
     if (left_is_null || right_is_null) {
       Load(left_is_null ? right : left);
index 5342b5a..0300f81 100644 (file)
@@ -225,6 +225,7 @@ class CodeGenerator: public Visitor {
                      bool force_cc);
   void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF);
   void LoadGlobal();
+  void LoadGlobalReceiver(Register scratch);
 
   // Read a value from a slot and leave it on top of the expression stack.
   void LoadFromSlot(Slot* slot, TypeofState typeof_state);
index 5a60322..d08e7b7 100644 (file)
@@ -366,7 +366,7 @@ void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
   ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
 
   // Check for access to global object (unlikely).
-  __ cmp(r0, Operand(JS_GLOBAL_OBJECT_TYPE));
+  __ cmp(r0, Operand(JS_GLOBAL_PROXY_TYPE));
   __ b(eq, &global);
 
   // Search the dictionary placing the result in r1.
@@ -392,7 +392,7 @@ void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
 
   // Global object access: Check access rights.
   __ bind(&global);
-  __ CheckAccessGlobal(r1, r0, &miss);
+  __ CheckAccessGlobalProxy(r1, r0, &miss);
   __ b(&probe);
 
   // Cache miss: Jump to runtime.
@@ -482,7 +482,7 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
   ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
 
   // Check for access to global object (unlikely).
-  __ cmp(r1, Operand(JS_GLOBAL_OBJECT_TYPE));
+  __ cmp(r1, Operand(JS_GLOBAL_PROXY_TYPE));
   __ b(eq, &global);
 
 
@@ -492,7 +492,7 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
 
   // Global object access: Check access rights.
   __ bind(&global);
-  __ CheckAccessGlobal(r0, r1, &miss);
+  __ CheckAccessGlobalProxy(r0, r1, &miss);
   __ b(&probe);
 
   // Cache miss: Restore receiver from stack and jump to runtime.
index c7139f4..92666af 100644 (file)
@@ -593,7 +593,7 @@ Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
 
     // 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());
 
     // Get the map of the current object.
     ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
@@ -605,8 +605,8 @@ Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
     // 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);
       // Restore scratch register to be the map of the object.  In the
       // new space case below, we load the prototype from the map in
       // the scratch register.
@@ -639,38 +639,73 @@ Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
   // 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));
+  ASSERT(!holder_reg.is(ip));
+  ASSERT(!scratch.is(ip));
 
-  // Load the security context.
-  mov(scratch, Operand(Top::security_context_address()));
-  ldr(scratch, MemOperand(scratch));
-  // In debug mode, make sure the security context is set.
+  // Load current lexical context from the stack frame.
+  ldr(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  // In debug mode, make sure the lexical context is set.
   if (kDebug) {
     cmp(scratch, Operand(0));
-    Check(ne, "we should not have an empty security context");
+    Check(ne, "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;
   ldr(scratch, FieldMemOperand(scratch, offset));
+  ldr(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset));
+
+  // Check the context is a global context.
+  if (FLAG_debug_code) {
+    // Read the first word and compare to the global_context_map.
+    ldr(ip, FieldMemOperand(scratch, HeapObject::kMapOffset));
+    cmp(ip, Operand(Factory::global_context_map()));
+    Check(eq, "JSGlobalObject::global_context should be a global context.");
+  }
+
+  // Check if both contexts are the same.
+  ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kContextOffset));
+  cmp(scratch, Operand(ip));
+  b(eq, &same_contexts);
+
+  // Check the context is a global context.
+  if (FLAG_debug_code) {
+    cmp(ip, Operand(Factory::null_value()));
+    Check(ne, "JSGlobalProxy::context() should not be null.");
+
+    ldr(ip, FieldMemOperand(ip, HeapObject::kMapOffset));
+    cmp(ip, Operand(Factory::global_context_map()));
+    Check(eq, "JSGlobalObject::global_context should be a global context.");
+    // Restore ip to holder's context.
+    ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kContextOffset));
+  }
+
   // Check that the security token in the calling global object is
   // compatible with the security token in the receiving global
   // object.
-  ldr(scratch, FieldMemOperand(scratch, JSGlobalObject::kSecurityTokenOffset));
-  ldr(ip, FieldMemOperand(holder_reg, JSGlobalObject::kSecurityTokenOffset));
+  int token_offset = Context::kHeaderSize +
+                     Context::SECURITY_TOKEN_INDEX * kPointerSize;
+
+  ldr(scratch, FieldMemOperand(scratch, token_offset));
+  ldr(ip, FieldMemOperand(ip, token_offset));
   cmp(scratch, Operand(ip));
   b(ne, miss);
+
+  bind(&same_contexts);
 }
 
 
index d1a4a44..956cd71 100644 (file)
@@ -176,7 +176,9 @@ class MacroAssembler: public Assembler {
   // Generate code for checking access rights - used for security checks
   // on access to global objects across environments. The holder register
   // is left untouched, whereas both scratch registers are clobbered.
-  void CheckAccessGlobal(Register holder_reg, Register scratch, Label* miss);
+  void CheckAccessGlobalProxy(Register holder_reg,
+                              Register scratch,
+                              Label* miss);
 
 
   // ---------------------------------------------------------------------------
index 5bcc6b0..085c04a 100644 (file)
@@ -420,13 +420,13 @@ Object* StoreStubCompiler::CompileStoreField(JSObject* object,
   __ b(ne, &miss);
 
   // Perform global security token check if needed.
-  if (object->IsJSGlobalObject()) {
-    __ CheckAccessGlobal(r3, r1, &miss);
+  if (object->IsJSGlobalProxy()) {
+    __ CheckAccessGlobalProxy(r3, r1, &miss);
   }
 
   // Stub never generated for non-global objects that require access
   // checks.
-  ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
+  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
 
   // Perform map transition for the receiver if necessary.
   if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
@@ -522,13 +522,13 @@ Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
   __ b(ne, &miss);
 
   // Perform global security token check if needed.
-  if (object->IsJSGlobalObject()) {
-    __ CheckAccessGlobal(r3, r1, &miss);
+  if (object->IsJSGlobalProxy()) {
+    __ CheckAccessGlobalProxy(r3, r1, &miss);
   }
 
   // Stub never generated for non-global objects that require access
   // checks.
-  ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
+  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
 
   __ ldr(ip, MemOperand(sp));  // receiver
   __ push(ip);
@@ -578,13 +578,13 @@ Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
   __ b(ne, &miss);
 
   // Perform global security token check if needed.
-  if (receiver->IsJSGlobalObject()) {
-    __ CheckAccessGlobal(r3, r1, &miss);
+  if (receiver->IsJSGlobalProxy()) {
+    __ CheckAccessGlobalProxy(r3, r1, &miss);
   }
 
   // Stub never generated for non-global objects that require access
   // checks.
-  ASSERT(receiver->IsJSGlobalObject() || !receiver->IsAccessCheckNeeded());
+  ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
 
   __ ldr(ip, MemOperand(sp));  // receiver
   __ push(ip);