__ mov(r0, Operand(var->name()));
__ push(r0);
- // TODO(120): Use global object for function lookup and inline
- // cache, and use global proxy as 'this' for invocation.
- LoadGlobalReceiver(r0);
+ // Pass the global object as the receiver and let the IC stub
+ // patch the stack to use the global proxy as 'this' in the
+ // invoked function.
+ LoadGlobal();
// Load the arguments.
for (int i = 0; i < args->length(); i++) Load(args->at(i));
// Push the name of the function and the receiver onto the stack.
frame_->Push(Immediate(var->name()));
- // TODO(120): Use global object for function lookup and inline
- // cache, and use global proxy as 'this' for invocation.
- LoadGlobalReceiver(eax);
+ // Pass the global object as the receiver and let the IC stub
+ // patch the stack to use the global proxy as 'this' in the
+ // invoked function.
+ LoadGlobal();
// Load the arguments.
for (int i = 0; i < args->length(); i++) {
// Helper function used from LoadIC/CallIC GenerateNormal.
static void GenerateDictionaryLoad(MacroAssembler* masm,
- Label* done_label,
- Label* miss_label,
+ Label* miss,
Register t0,
Register t1) {
// Register use:
//
// r2 - holds the name of the property and is unchanges.
+ Label done;
+
// Check for the absence of an interceptor.
// Load the map into t0.
__ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset));
__ ldr(t0, FieldMemOperand(t1, Map::kInstanceAttributesOffset));
__ tst(t0, Operand(1 << (Map::kHasNamedInterceptor + (3 * 8))));
// Jump to miss if the interceptor bit is set.
- __ b(ne, miss_label);
+ __ b(ne, miss);
// Check that the properties array is a dictionary.
__ ldr(t0, FieldMemOperand(t1, JSObject::kPropertiesOffset));
__ ldr(r3, FieldMemOperand(t0, HeapObject::kMapOffset));
__ cmp(r3, Operand(Factory::hash_table_map()));
- __ b(ne, miss_label);
+ __ b(ne, miss);
// Compute the capacity mask.
const int kCapacityOffset =
__ ldr(ip, FieldMemOperand(t1, kElementsStartOffset));
__ cmp(r2, Operand(ip));
if (i != kProbes - 1) {
- __ b(eq, done_label);
+ __ b(eq, &done);
} else {
- __ b(ne, miss_label);
+ __ b(ne, miss);
}
}
// Check that the value is a normal property.
- __ bind(done_label); // t1 == t0 + 4*index
+ __ bind(&done); // t1 == t0 + 4*index
__ ldr(r3, FieldMemOperand(t1, kElementsStartOffset + 2 * kPointerSize));
__ tst(r3, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
- __ b(ne, miss_label);
+ __ b(ne, miss);
// Get the value at the masked, scaled index and return.
__ ldr(t1, FieldMemOperand(t1, kElementsStartOffset + 1 * kPointerSize));
}
+static void GenerateNormalHelper(MacroAssembler* masm,
+ int argc,
+ bool is_global_object,
+ Label* miss) {
+ // Search dictionary - put result in register r1.
+ GenerateDictionaryLoad(masm, miss, r0, r1);
+
+ // Check that the value isn't a smi.
+ __ tst(r1, Operand(kSmiTagMask));
+ __ b(eq, miss);
+
+ // Check that the value is a JSFunction.
+ __ ldr(r0, FieldMemOperand(r1, HeapObject::kMapOffset));
+ __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset));
+ __ cmp(r0, Operand(JS_FUNCTION_TYPE));
+ __ b(ne, miss);
+
+ // Patch the receiver with the global proxy if necessary.
+ if (is_global_object) {
+ __ ldr(r2, MemOperand(sp, argc * kPointerSize));
+ __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
+ __ str(r2, MemOperand(sp, argc * kPointerSize));
+ }
+
+ // Invoke the function.
+ ParameterCount actual(argc);
+ __ InvokeFunction(r1, actual, JUMP_FUNCTION);
+}
+
+
void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
// -- lr: return address
// -----------------------------------
- Label miss, probe, done, global;
+ Label miss, global_object, non_global_object;
// Get the receiver of the function from the stack into r1.
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
// If this assert fails, we have to check upper bound too.
ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
- // Check for access to global proxy.
- __ cmp(r0, Operand(JS_GLOBAL_PROXY_TYPE));
- __ b(eq, &global);
-
- // Search the dictionary placing the result in r1.
- __ bind(&probe);
- GenerateDictionaryLoad(masm, &done, &miss, r0, r1);
-
- // Check that the value isn't a smi.
- __ tst(r1, Operand(kSmiTagMask));
- __ b(eq, &miss);
-
- // Check that the value is a JSFunction.
- __ ldr(r0, FieldMemOperand(r1, HeapObject::kMapOffset));
- __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset));
- __ cmp(r0, Operand(JS_FUNCTION_TYPE));
- __ b(ne, &miss);
+ // Check for access to global object.
+ __ cmp(r0, Operand(JS_GLOBAL_OBJECT_TYPE));
+ __ b(eq, &global_object);
+ __ cmp(r0, Operand(JS_BUILTINS_OBJECT_TYPE));
+ __ b(ne, &non_global_object);
- // TODO(120): Check for access to global object. Needs patching of
- // receiver but no security check.
+ // Accessing global object: Load and invoke.
+ __ bind(&global_object);
+ GenerateNormalHelper(masm, argc, true, &miss);
- // Invoke the function.
- ParameterCount actual(argc);
- __ InvokeFunction(r1, actual, JUMP_FUNCTION);
+ // Accessing non-global object: Check for access to global proxy.
+ Label global_proxy, invoke;
+ __ bind(&non_global_object);
+ __ cmp(r0, Operand(JS_GLOBAL_PROXY_TYPE));
+ __ b(eq, &global_proxy);
+ __ bind(&invoke);
+ GenerateNormalHelper(masm, argc, false, &miss);
// Global object access: Check access rights.
- __ bind(&global);
+ __ bind(&global_proxy);
__ CheckAccessGlobalProxy(r1, r0, &miss);
- __ b(&probe);
+ __ b(&invoke);
// Cache miss: Jump to runtime.
__ bind(&miss);
__ mov(r1, Operand(r0));
__ LeaveInternalFrame();
- // TODO(120): Check for access to to global object. Needs patching
- // of receiver but no security check.
+ // Check if the receiver is a global object of some sort.
+ Label invoke, global;
+ __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver
+ __ tst(r2, Operand(kSmiTagMask));
+ __ b(eq, &invoke);
+ __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
+ __ ldrb(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset));
+ __ cmp(r3, Operand(JS_GLOBAL_OBJECT_TYPE));
+ __ b(eq, &global);
+ __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
+ __ b(ne, &invoke);
+
+ // Patch the receiver on the stack.
+ __ bind(&global);
+ __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
+ __ str(r2, MemOperand(sp, argc * kPointerSize));
// Invoke the function.
ParameterCount actual(argc);
+ __ bind(&invoke);
__ InvokeFunction(r1, actual, JUMP_FUNCTION);
}
// -- [sp] : receiver
// -----------------------------------
- Label miss, probe, done, global;
+ Label miss, probe, global;
__ ldr(r0, MemOperand(sp, 0));
// Check that the receiver isn't a smi.
__ b(eq, &global);
__ bind(&probe);
- GenerateDictionaryLoad(masm, &done, &miss, r1, r0);
+ GenerateDictionaryLoad(masm, &miss, r1, r0);
__ Ret();
// Global object access: Check access rights.
}
+static void GenerateNormalHelper(MacroAssembler* masm,
+ int argc,
+ bool is_global_object,
+ Label* miss) {
+ // Search dictionary - put result in register edx.
+ GenerateDictionaryLoad(masm, miss, eax, edx, ebx, ecx);
+
+ // Move the result to register edi and check that it isn't a smi.
+ __ mov(edi, Operand(edx));
+ __ test(edx, Immediate(kSmiTagMask));
+ __ j(zero, miss, not_taken);
+
+ // Check that the value is a JavaScript function.
+ __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
+ __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset));
+ __ cmp(edx, JS_FUNCTION_TYPE);
+ __ j(not_equal, miss, not_taken);
+
+ // Patch the receiver with the global proxy if necessary.
+ if (is_global_object) {
+ __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
+ __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
+ __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
+ }
+
+ // Invoke the function.
+ ParameterCount actual(argc);
+ __ InvokeFunction(edi, actual, JUMP_FUNCTION);
+}
+
+
void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
// -----------------------------------
- Label miss, probe, global;
+ Label miss, global_object, non_global_object;
// Get the receiver of the function from the stack; 1 ~ return address.
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
// If this assert fails, we have to check upper bound too.
ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
- // Check for access to global proxy.
- __ cmp(eax, JS_GLOBAL_PROXY_TYPE);
- __ j(equal, &global, not_taken);
-
- // Search the dictionary placing the result in edx.
- __ bind(&probe);
- GenerateDictionaryLoad(masm, &miss, eax, edx, ebx, ecx);
-
- // Move the result to register edi and check that it isn't a smi.
- __ mov(edi, Operand(edx));
- __ test(edx, Immediate(kSmiTagMask));
- __ j(zero, &miss, not_taken);
-
- // Check that the value is a JavaScript function.
- __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
- __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset));
- __ cmp(edx, JS_FUNCTION_TYPE);
- __ j(not_equal, &miss, not_taken);
+ // Check for access to global object.
+ __ cmp(eax, JS_GLOBAL_OBJECT_TYPE);
+ __ j(equal, &global_object);
+ __ cmp(eax, JS_BUILTINS_OBJECT_TYPE);
+ __ j(not_equal, &non_global_object);
- // TODO(120): Check for access to global object. Needs patching of
- // receiver but no security check.
+ // Accessing global object: Load and invoke.
+ __ bind(&global_object);
+ GenerateNormalHelper(masm, argc, true, &miss);
- // Invoke the function.
- ParameterCount actual(argc);
- __ InvokeFunction(edi, actual, JUMP_FUNCTION);
+ // Accessing non-global object: Check for access to global proxy.
+ Label global_proxy, invoke;
+ __ bind(&non_global_object);
+ __ cmp(eax, JS_GLOBAL_PROXY_TYPE);
+ __ j(equal, &global_proxy, not_taken);
+ __ bind(&invoke);
+ GenerateNormalHelper(masm, argc, false, &miss);
// Global object proxy access: Check access rights.
- __ bind(&global);
+ __ bind(&global_proxy);
__ CheckAccessGlobalProxy(edx, eax, &miss);
- __ jmp(&probe);
+ __ jmp(&invoke);
// Cache miss: Jump to runtime.
__ bind(&miss);
__ mov(Operand(edi), eax);
__ LeaveInternalFrame();
- // TODO(120): Check for access to to global object. Needs patching
- // of receiver but no security check.
+ // Check if the receiver is a global object of some sort.
+ Label invoke, global;
+ __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver
+ __ test(edx, Immediate(kSmiTagMask));
+ __ j(zero, &invoke, not_taken);
+ __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+ __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+ __ cmp(ecx, JS_GLOBAL_OBJECT_TYPE);
+ __ j(equal, &global);
+ __ cmp(ecx, JS_BUILTINS_OBJECT_TYPE);
+ __ j(not_equal, &invoke);
+
+ // Patch the receiver on the stack.
+ __ bind(&global);
+ __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
+ __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
// Invoke the function.
ParameterCount actual(argc);
+ __ bind(&invoke);
__ InvokeFunction(edi, actual, JUMP_FUNCTION);
}
const int argc = arguments().immediate();
- // Get the receiver of the function from the stack into r1.
- __ ldr(r1, MemOperand(sp, argc * kPointerSize));
+ // Get the receiver of the function from the stack into r0.
+ __ ldr(r0, MemOperand(sp, argc * kPointerSize));
// Check that the receiver isn't a smi.
- __ tst(r1, Operand(kSmiTagMask));
+ __ tst(r0, Operand(kSmiTagMask));
__ b(eq, &miss);
// Do the right check and compute the holder register.
Register reg =
- __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
+ __ CheckMaps(JSObject::cast(object), r0, holder, r3, r2, &miss);
GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
// Check that the function really is a function.
__ cmp(r2, Operand(JS_FUNCTION_TYPE));
__ b(ne, &miss);
+ // Patch the receiver on the stack with the global proxy if
+ // necessary.
if (object->IsGlobalObject()) {
- // TODO(120): Patch receiver with the global proxy.
+ __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
+ __ str(r3, MemOperand(sp, argc * kPointerSize));
}
// Invoke the function.
__ b(eq, &miss);
}
+ // Make sure that it's okay not to patch the on stack receiver
+ // unless we're doing a receiver map check.
+ ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
+
switch (check) {
case RECEIVER_MAP_CHECK:
// Check that the maps haven't changed.
__ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
+
+ // Patch the receiver on the stack with the global proxy if
+ // necessary.
+ if (object->IsGlobalObject()) {
+ __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
+ __ str(r3, MemOperand(sp, argc * kPointerSize));
+ }
break;
case STRING_CHECK:
__ mov(r1, Operand(Handle<JSFunction>(function)));
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
- if (object->IsGlobalObject()) {
- // TODO(120): Patch receiver with the global proxy.
- }
-
// Jump to the cached code (tail call).
Handle<Code> code(function->code());
ParameterCount expected(function->shared()->formal_parameter_count());
__ cmp(ebx, JS_FUNCTION_TYPE);
__ j(not_equal, &miss, not_taken);
+ // Patch the receiver on the stack with the global proxy if
+ // necessary.
if (object->IsGlobalObject()) {
- // TODO(120): Patch receiver with the global proxy.
+ __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
+ __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
}
// Invoke the function.
__ j(zero, &miss, not_taken);
}
+ // Make sure that it's okay not to patch the on stack receiver
+ // unless we're doing a receiver map check.
+ ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
+
switch (check) {
case RECEIVER_MAP_CHECK:
// Check that the maps haven't changed.
__ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
+
+ // Patch the receiver on the stack with the global proxy if
+ // necessary.
+ if (object->IsGlobalObject()) {
+ __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
+ __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
+ }
break;
case STRING_CHECK:
__ mov(Operand(edi), Immediate(Handle<JSFunction>(function)));
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
- if (object->IsGlobalObject()) {
- // TODO(120): Patch receiver with the global proxy.
- }
-
// Jump to the cached code (tail call).
Handle<Code> code(function->code());
ParameterCount expected(function->shared()->formal_parameter_count());
// Get the receiver from the stack.
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
+
// Check that the receiver isn't a smi.
__ test(edx, Immediate(kSmiTagMask));
__ j(zero, &miss, not_taken);
__ cmp(ebx, JS_FUNCTION_TYPE);
__ j(not_equal, &miss, not_taken);
+ // Patch the receiver on the stack with the global proxy if
+ // necessary.
if (object->IsGlobalObject()) {
- // TODO(120): Patch receiver with the global proxy.
+ __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
+ __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
}
// Invoke the function.