| Index: src/x64/macro-assembler-x64.cc
|
| ===================================================================
|
| --- src/x64/macro-assembler-x64.cc (revision 2483)
|
| +++ src/x64/macro-assembler-x64.cc (working copy)
|
| @@ -882,4 +882,154 @@
|
| }
|
|
|
|
|
| +Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
|
| + JSObject* holder, Register holder_reg,
|
| + Register scratch,
|
| + Label* miss) {
|
| + // Make sure there's no overlap between scratch and the other
|
| + // registers.
|
| + ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg));
|
| +
|
| + // Keep track of the current object in register reg. On the first
|
| + // iteration, reg is an alias for object_reg, on later iterations,
|
| + // it is an alias for holder_reg.
|
| + Register reg = object_reg;
|
| + int depth = 1;
|
| +
|
| + // Check the maps in the prototype chain.
|
| + // Traverse the prototype chain from the object and do map checks.
|
| + while (object != holder) {
|
| + depth++;
|
| +
|
| + // Only global objects and objects that do not require access
|
| + // checks are allowed in stubs.
|
| + ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
|
| +
|
| + JSObject* prototype = JSObject::cast(object->GetPrototype());
|
| + if (Heap::InNewSpace(prototype)) {
|
| + // Get the map of the current object.
|
| + movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
|
| + Cmp(scratch, Handle<Map>(object->map()));
|
| + // Branch on the result of the map check.
|
| + j(not_equal, miss);
|
| + // 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->IsJSGlobalProxy()) {
|
| + CheckAccessGlobalProxy(reg, scratch, miss);
|
| +
|
| + // Restore scratch register to be the map of the object.
|
| + // We load the prototype from the map in the scratch register.
|
| + movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
|
| + }
|
| + // The prototype is in new space; we cannot store a reference
|
| + // to it in the code. Load it from the map.
|
| + reg = holder_reg; // from now the object is in holder_reg
|
| + movq(reg, FieldOperand(scratch, Map::kPrototypeOffset));
|
| +
|
| + } else {
|
| + // Check the map of the current object.
|
| + Cmp(FieldOperand(reg, HeapObject::kMapOffset),
|
| + Handle<Map>(object->map()));
|
| + // Branch on the result of the map check.
|
| + j(not_equal, miss);
|
| + // 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->IsJSGlobalProxy()) {
|
| + CheckAccessGlobalProxy(reg, scratch, miss);
|
| + }
|
| + // The prototype is in old space; load it directly.
|
| + reg = holder_reg; // from now the object is in holder_reg
|
| + Move(reg, Handle<JSObject>(prototype));
|
| + }
|
| +
|
| + // Go to the next object in the prototype chain.
|
| + object = prototype;
|
| + }
|
| +
|
| + // Check the holder map.
|
| + Cmp(FieldOperand(reg, HeapObject::kMapOffset),
|
| + Handle<Map>(holder->map()));
|
| + j(not_equal, miss);
|
| +
|
| + // Log the check depth.
|
| + LOG(IntEvent("check-maps-depth", depth));
|
| +
|
| + // Perform security check for access to the global object and return
|
| + // the holder register.
|
| + ASSERT(object == holder);
|
| + ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
|
| + if (object->IsJSGlobalProxy()) {
|
| + CheckAccessGlobalProxy(reg, scratch, miss);
|
| + }
|
| + return reg;
|
| +}
|
| +
|
| +
|
| +
|
| +
|
| +void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
|
| + Register scratch,
|
| + Label* miss) {
|
| + Label same_contexts;
|
| +
|
| + ASSERT(!holder_reg.is(scratch));
|
| + ASSERT(!scratch.is(kScratchRegister));
|
| + // Load current lexical context from the stack frame.
|
| + movq(scratch, Operand(rbp, StandardFrameConstants::kContextOffset));
|
| +
|
| + // When generating debug code, make sure the lexical context is set.
|
| + if (FLAG_debug_code) {
|
| + cmpq(scratch, Immediate(0));
|
| + Check(not_equal, "we should not have an empty lexical context");
|
| + }
|
| + // Load the global context of the current context.
|
| + int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
|
| + movq(scratch, FieldOperand(scratch, offset));
|
| + movq(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
|
| +
|
| + // Check the context is a global context.
|
| + if (FLAG_debug_code) {
|
| + Cmp(FieldOperand(scratch, HeapObject::kMapOffset),
|
| + Factory::global_context_map());
|
| + Check(equal, "JSGlobalObject::global_context should be a global context.");
|
| + }
|
| +
|
| + // Check if both contexts are the same.
|
| + cmpq(scratch, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
|
| + j(equal, &same_contexts);
|
| +
|
| + // Compare security tokens.
|
| + // Check that the security token in the calling global object is
|
| + // compatible with the security token in the receiving global
|
| + // object.
|
| +
|
| + // Check the context is a global context.
|
| + if (FLAG_debug_code) {
|
| + // Preserve original value of holder_reg.
|
| + push(holder_reg);
|
| + movq(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
|
| + Cmp(holder_reg, Factory::null_value());
|
| + Check(not_equal, "JSGlobalProxy::context() should not be null.");
|
| +
|
| + // Read the first word and compare to global_context_map(),
|
| + movq(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset));
|
| + Cmp(holder_reg, Factory::global_context_map());
|
| + Check(equal, "JSGlobalObject::global_context should be a global context.");
|
| + pop(holder_reg);
|
| + }
|
| +
|
| + movq(kScratchRegister,
|
| + FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
|
| + int token_offset = Context::kHeaderSize +
|
| + Context::SECURITY_TOKEN_INDEX * kPointerSize;
|
| + movq(scratch, FieldOperand(scratch, token_offset));
|
| + cmpq(scratch, FieldOperand(kScratchRegister, token_offset));
|
| + j(not_equal, miss);
|
| +
|
| + bind(&same_contexts);
|
| +}
|
| +
|
| +
|
| } } // namespace v8::internal
|
|
|