Author: [EMAIL PROTECTED]
Date: Wed Dec 10 00:05:10 2008
New Revision: 955

Modified:
    branches/bleeding_edge/src/ic-arm.cc
    branches/bleeding_edge/src/ic-ia32.cc
    branches/bleeding_edge/src/runtime.cc
    branches/bleeding_edge/test/cctest/test-api.cc

Log:
Make sure that the generic stubs for keyed load and store and for
dictionary probing respects access check bit.
Review URL: http://codereview.chromium.org/13663

Modified: branches/bleeding_edge/src/ic-arm.cc
==============================================================================
--- branches/bleeding_edge/src/ic-arm.cc        (original)
+++ branches/bleeding_edge/src/ic-arm.cc        Wed Dec 10 00:05:10 2008
@@ -317,8 +317,8 @@
    __ b(eq, &miss);

    // Check that the receiver is a valid JS object.
-  __ ldr(r0, FieldMemOperand(r1, HeapObject::kMapOffset));
-  __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset));
+  __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ ldrb(r0, FieldMemOperand(r3, Map::kInstanceTypeOffset));
    __ cmp(r0, Operand(FIRST_JS_OBJECT_TYPE));
    __ b(lt, &miss);

@@ -333,6 +333,10 @@

    // Accessing global object: Load and invoke.
    __ bind(&global_object);
+  // Check that the global object does not require access checks.
+  __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
+  __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
+  __ b(ne, &miss);
    GenerateNormalHelper(masm, argc, true, &miss);

    // Accessing non-global object: Check for access to global proxy.
@@ -340,6 +344,11 @@
    __ bind(&non_global_object);
    __ cmp(r0, Operand(JS_GLOBAL_PROXY_TYPE));
    __ b(eq, &global_proxy);
+  // Check that the non-global, non-global-proxy object does not
+  // require access checks.
+  __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
+  __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
+  __ b(ne, &miss);
    __ bind(&invoke);
    GenerateNormalHelper(masm, argc, false, &miss);

@@ -441,8 +450,8 @@
    __ b(eq, &miss);

    // Check that the receiver is a valid JS object.
-  __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
-  __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
+  __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
+  __ ldrb(r1, FieldMemOperand(r3, Map::kInstanceTypeOffset));
    __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
    __ b(lt, &miss);
    // If this assert fails, we have to check upper bound too.
@@ -452,6 +461,11 @@
    __ cmp(r1, Operand(JS_GLOBAL_PROXY_TYPE));
    __ b(eq, &global);

+  // Check for non-global object that requires access check.
+  __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
+  __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
+  __ b(ne, &miss);
+
    __ bind(&probe);
    GenerateDictionaryLoad(masm, &miss, r1, r0);
    GenerateCheckNonFunctionOrLoaded(masm, &miss, r0, r1);
@@ -525,12 +539,19 @@
    __ tst(r1, Operand(kSmiTagMask));
    __ b(eq, &slow);

+  // Get the map of the receiver.
+  __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+  // Check that the receiver does not require access checks.  We need
+  // to check this explicitly since this generic stub does not perform
+  // map checks.
+  __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
+  __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
+  __ b(ne, &slow);
    // Check that the object is some kind of JS object EXCEPT JS Value type.
    // In the case that the object is a value-wrapper object,
    // we enter the runtime system to make sure that indexing into string
    // objects work as intended.
    ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
-  __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
    __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
    __ cmp(r2, Operand(JS_OBJECT_TYPE));
    __ b(lt, &slow);
@@ -597,10 +618,15 @@
    // Check that the object isn't a smi.
    __ tst(r3, Operand(kSmiTagMask));
    __ b(eq, &slow);
-  // Get the type of the object from its map.
+  // Get the map of the object.
    __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
-  __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+  // Check that the receiver does not require access checks.  We need
+  // to do this because this generic stub does not perform map checks.
+  __ ldrb(ip, FieldMemOperand(r2, Map::kBitFieldOffset));
+  __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
+  __ b(ne, &slow);
    // Check if the object is a JS array or not.
+  __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
    __ cmp(r2, Operand(JS_ARRAY_TYPE));
    // r1 == key.
    __ b(eq, &array);

Modified: branches/bleeding_edge/src/ic-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/ic-ia32.cc       (original)
+++ branches/bleeding_edge/src/ic-ia32.cc       Wed Dec 10 00:05:10 2008
@@ -215,18 +215,27 @@
    // -----------------------------------
    Label slow, fast, check_string, index_int, index_string;

+  // Load name and receiver.
    __ mov(eax, (Operand(esp, kPointerSize)));
    __ mov(ecx, (Operand(esp, 2 * kPointerSize)));

    // Check that the object isn't a smi.
    __ test(ecx, Immediate(kSmiTagMask));
    __ j(zero, &slow, not_taken);
+
+  // Get the map of the receiver.
+  __ mov(edx, FieldOperand(ecx, HeapObject::kMapOffset));
+  // Check that the receiver does not require access checks.  We need
+  // to check this explicitly since this generic stub does not perform
+  // map checks.
+  __ movzx_b(ebx, FieldOperand(edx, Map::kBitFieldOffset));
+  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
+  __ j(not_zero, &slow, not_taken);
    // Check that the object is some kind of JS object EXCEPT JS Value type.
    // In the case that the object is a value-wrapper object,
    // we enter the runtime system to make sure that indexing
    // into string objects work as intended.
    ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
-  __ mov(edx, FieldOperand(ecx, HeapObject::kMapOffset));
    __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset));
    __ cmp(edx, JS_OBJECT_TYPE);
    __ j(less, &slow, not_taken);
@@ -268,7 +277,7 @@
    // bits have been subtracted to allow space for the length and the cached
    // array index.
    ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
-             (1 << (String::kShortLengthShift - String::kHashShift)));
+         (1 << (String::kShortLengthShift - String::kHashShift)));
    __ bind(&index_string);
    const int kLengthFieldLimit =
        (String::kMaxCachedArrayIndexLength + 1) <<  
String::kShortLengthShift;
@@ -298,17 +307,25 @@
    //  -- esp[8] : receiver
    // -----------------------------------
    Label slow, fast, array, extra;
-  // Get the key and the object from the stack.
-  __ mov(ebx, Operand(esp, 1 * kPointerSize));  // 1 ~ return address
+
+  // Get the receiver from the stack.
    __ mov(edx, Operand(esp, 2 * kPointerSize));  // 2 ~ return address, key
-  // Check that the key is a smi.
-  __ test(ebx, Immediate(kSmiTagMask));
-  __ j(not_zero, &slow, not_taken);
    // Check that the object isn't a smi.
    __ test(edx, Immediate(kSmiTagMask));
    __ j(zero, &slow, not_taken);
-  // Get the type of the object from its map.
+  // Get the map from the receiver.
    __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+  // Check that the receiver does not require access checks.  We need
+  // to do this because this generic stub does not perform map checks.
+  __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
+  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
+  __ j(not_zero, &slow, not_taken);
+  // Get the key from the stack.
+  __ mov(ebx, Operand(esp, 1 * kPointerSize));  // 1 ~ return address
+  // Check that the key is a smi.
+  __ test(ebx, Immediate(kSmiTagMask));
+  __ j(not_zero, &slow, not_taken);
+  // Get the instance type from the map of the receiver.
    __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
    // Check if the object is a JS array or not.
    __ cmp(ecx, JS_ARRAY_TYPE);
@@ -317,7 +334,6 @@
    __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
    __ j(less, &slow, not_taken);

-
    // Object case: Check key against length in the elements array.
    // eax: value
    // edx: JSObject
@@ -515,8 +531,8 @@
    __ j(zero, &miss, not_taken);

    // Check that the receiver is a valid JS object.
-  __ mov(eax, FieldOperand(edx, HeapObject::kMapOffset));
-  __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset));
+  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
+  __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceTypeOffset));
    __ cmp(eax, FIRST_JS_OBJECT_TYPE);
    __ j(less, &miss, not_taken);

@@ -531,6 +547,10 @@

    // Accessing global object: Load and invoke.
    __ bind(&global_object);
+  // Check that the global object does not require access checks.
+  __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
+  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
+  __ j(not_equal, &miss, not_taken);
    GenerateNormalHelper(masm, argc, true, &miss);

    // Accessing non-global object: Check for access to global proxy.
@@ -538,6 +558,11 @@
    __ bind(&non_global_object);
    __ cmp(eax, JS_GLOBAL_PROXY_TYPE);
    __ j(equal, &global_proxy, not_taken);
+  // Check that the non-global, non-global-proxy object does not
+  // require access checks.
+  __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
+  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
+  __ j(not_equal, &miss, not_taken);
    __ bind(&invoke);
    GenerateNormalHelper(masm, argc, false, &miss);

@@ -642,8 +667,8 @@
    __ j(zero, &miss, not_taken);

    // Check that the receiver is a valid JS object.
-  __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
-  __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset));
+  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
+  __ movzx_b(edx, FieldOperand(ebx, Map::kInstanceTypeOffset));
    __ cmp(edx, FIRST_JS_OBJECT_TYPE);
    __ j(less, &miss, not_taken);

@@ -653,6 +678,11 @@
    // Check for access to global object (unlikely).
    __ cmp(edx, JS_GLOBAL_PROXY_TYPE);
    __ j(equal, &global, not_taken);
+
+  // Check for non-global object that requires access check.
+  __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
+  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
+  __ j(not_zero, &miss, not_taken);

    // Search the dictionary placing the result in eax.
    __ bind(&probe);

Modified: branches/bleeding_edge/src/runtime.cc
==============================================================================
--- branches/bleeding_edge/src/runtime.cc       (original)
+++ branches/bleeding_edge/src/runtime.cc       Wed Dec 10 00:05:10 2008
@@ -1733,13 +1733,19 @@
    ASSERT(args.length() == 2);

    // Fast cases for getting named properties of the receiver JSObject
-  // itself. The global proxy objects has to be excluded since
-  // LocalLookup on the global proxy object can return a valid result
-  // eventhough the global proxy object never has properties.  This is
-  // the case because the global proxy object forwards everything to
-  // its hidden prototype including local lookups.
+  // itself.
+  //
+  // The global proxy objects has to be excluded since LocalLookup on
+  // the global proxy object can return a valid result eventhough the
+  // global proxy object never has properties.  This is the case
+  // because the global proxy object forwards everything to its hidden
+  // prototype including local lookups.
+  //
+  // Additionally, we need to make sure that we do not cache results
+  // for objects that require access checks.
    if (args[0]->IsJSObject() &&
        !args[0]->IsJSGlobalProxy() &&
+      !args[0]->IsAccessCheckNeeded() &&
        args[1]->IsString()) {
      JSObject* receiver = JSObject::cast(args[0]);
      String* key = String::cast(args[1]);

Modified: branches/bleeding_edge/test/cctest/test-api.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-api.cc      (original)
+++ branches/bleeding_edge/test/cctest/test-api.cc      Wed Dec 10 00:05:10 2008
@@ -3681,29 +3681,81 @@
    v8::Handle<Value> value;

    // Check that the named access-control function is called every time.
-  value = v8_compile("for (var i = 0; i < 10; i++)  obj.prop = 1;")->Run();
-  value = v8_compile("for (var i = 0; i < 10; i++)  obj.prop;"
-                     "obj.prop")->Run();
+  CompileRun("function testProp(obj) {"
+             "  for (var i = 0; i < 10; i++) obj.prop = 1;"
+             "  for (var j = 0; j < 10; j++) obj.prop;"
+             "  return obj.prop"
+             "}");
+  value = CompileRun("testProp(obj)");
    CHECK(value->IsNumber());
    CHECK_EQ(1, value->Int32Value());
    CHECK_EQ(21, named_access_count);

    // Check that the named access-control function is called every time.
-  value = v8_compile("var p = 'prop';")->Run();
-  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
-  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
-                     "obj[p]")->Run();
+  CompileRun("var p = 'prop';"
+             "function testKeyed(obj) {"
+             "  for (var i = 0; i < 10; i++) obj[p] = 1;"
+             "  for (var j = 0; j < 10; j++) obj[p];"
+             "  return obj[p];"
+             "}");
+  // Use obj which requires access checks.  No inline caching is used
+  // in that case.
+  value = CompileRun("testKeyed(obj)");
    CHECK(value->IsNumber());
    CHECK_EQ(1, value->Int32Value());
    CHECK_EQ(42, named_access_count);
+  // Force the inline caches into generic state and try again.
+  CompileRun("testKeyed({ a: 0 })");
+  CompileRun("testKeyed({ b: 0 })");
+  value = CompileRun("testKeyed(obj)");
+  CHECK(value->IsNumber());
+  CHECK_EQ(1, value->Int32Value());
+  CHECK_EQ(63, named_access_count);

    // Check that the indexed access-control function is called every time.
-  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
-  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
-                     "obj[0]")->Run();
+  CompileRun("function testIndexed(obj) {"
+             "  for (var i = 0; i < 10; i++) obj[0] = 1;"
+             "  for (var j = 0; j < 10; j++) obj[0];"
+             "  return obj[0]"
+             "}");
+  value = CompileRun("testIndexed(obj)");
    CHECK(value->IsNumber());
    CHECK_EQ(1, value->Int32Value());
    CHECK_EQ(21, indexed_access_count);
+  // Force the inline caches into generic state.
+  CompileRun("testIndexed(new Array(1))");
+  // Test that the indexed access check is called.
+  value = CompileRun("testIndexed(obj)");
+  CHECK(value->IsNumber());
+  CHECK_EQ(1, value->Int32Value());
+  CHECK_EQ(42, indexed_access_count);
+
+  // Check that the named access check is called when invoking
+  // functions on an object that requires access checks.
+  CompileRun("obj.f = function() {}");
+  CompileRun("function testCallNormal(obj) {"
+             "  for (var i = 0; i < 10; i++) obj.f();"
+             "}");
+  CompileRun("testCallNormal(obj)");
+  CHECK_EQ(74, named_access_count);
+
+  // Force obj into slow case.
+  value = CompileRun("delete obj.prop");
+  CHECK(value->BooleanValue());
+  // Force inline caches into dictionary probing mode.
+  CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
+  // Test that the named access check is called.
+  value = CompileRun("testProp(obj);");
+  CHECK(value->IsNumber());
+  CHECK_EQ(1, value->Int32Value());
+  CHECK_EQ(96, named_access_count);
+
+  // Force the call inline cache into dictionary probing mode.
+  CompileRun("o.f = function() {}; testCallNormal(o)");
+  // Test that the named access check is still called for each
+  // invocation of the function.
+  value = CompileRun("testCallNormal(obj)");
+  CHECK_EQ(106, named_access_count);

    context1->Exit();
    context0->Exit();

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

Reply via email to