Version 1.3.0.

Allowed RegExp objects to be called as functions (issue 132).

Fixed issue where global property cells would escape after detaching the global object; see http://crbug.com/16276.

Added support for stepping into setters and getters in the debugger.

Changed the debugger to avoid stopping in its own JavaScript code and in the code of built-in functions.

Fixed issue 345 by avoiding duplicate escaping labels.

Fixed ARM code generator crash in short-circuited boolean expressions and added regression tests.

Added an external allocation limit to avoid issues where small V8 objects would hold on to large amounts of external memory without causing garbage collections.

Finished more of the inline caching stubs for x64 targets. 


git-svn-id: http://v8.googlecode.com/svn/trunk@2537 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 099a461..457011b 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -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