__ 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));
__ 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
}
+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.
// 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));
// 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);
// 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();
// 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);
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);
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.
// Global object access: Check access rights.
__ bind(&global);
- __ CheckAccessGlobal(r1, r0, &miss);
+ __ CheckAccessGlobalProxy(r1, r0, &miss);
__ b(&probe);
// Cache miss: Jump to runtime.
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);
// 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.
// 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));
// 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.
// 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);
}
// 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);
// ---------------------------------------------------------------------------
__ 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)) {
__ 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);
__ 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);