__ 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);
// 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.
__ 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);
__ 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.
__ 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);
__ 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);
// 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);
// -----------------------------------
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);
// 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;
// -- 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);
__ 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
__ 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);
// 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.
__ 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);
__ 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);
__ 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);
GenerateDictionaryLoad(masm, &miss, edx, eax, ebx, ecx);
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]);
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();