Index: src/runtime.cc |
=================================================================== |
--- src/runtime.cc (revision 1865) |
+++ src/runtime.cc (working copy) |
@@ -474,6 +474,42 @@ |
} |
+// Inserts an object as the hidden prototype of another object. |
+static Object* Runtime_SetHiddenPrototype(Arguments args) { |
+ NoHandleAllocation ha; |
+ ASSERT(args.length() == 2); |
+ CONVERT_CHECKED(JSObject, jsobject, args[0]); |
+ CONVERT_CHECKED(JSObject, proto, args[1]); |
+ |
+ // Sanity checks. The old prototype (that we are replacing) could |
+ // theoretically be null, but if it is not null then check that we |
+ // didn't already install a hidden prototype here. |
+ RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() || |
+ !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype()); |
+ RUNTIME_ASSERT(!proto->map()->is_hidden_prototype()); |
+ |
+ // Allocate up front before we start altering state in case we get a GC. |
+ Object* map_or_failure = proto->map()->CopyDropTransitions(); |
+ if (map_or_failure->IsFailure()) return map_or_failure; |
+ Map* new_proto_map = Map::cast(map_or_failure); |
+ |
+ map_or_failure = jsobject->map()->CopyDropTransitions(); |
+ if (map_or_failure->IsFailure()) return map_or_failure; |
+ Map* new_map = Map::cast(map_or_failure); |
+ |
+ // Set proto's prototype to be the old prototype of the object. |
+ new_proto_map->set_prototype(jsobject->GetPrototype()); |
+ proto->set_map(new_proto_map); |
+ new_proto_map->set_is_hidden_prototype(); |
+ |
+ // Set the object's prototype to proto. |
+ new_map->set_prototype(proto); |
+ jsobject->set_map(new_map); |
+ |
+ return Heap::undefined_value(); |
+} |
+ |
+ |
static Object* Runtime_IsConstructCall(Arguments args) { |
NoHandleAllocation ha; |
ASSERT(args.length() == 0); |
@@ -2796,20 +2832,24 @@ |
} |
-static Object* Runtime_HasLocalProperty(Arguments args) { |
- NoHandleAllocation ha; |
- ASSERT(args.length() == 2); |
- CONVERT_CHECKED(String, key, args[1]); |
- |
+static Object* HasLocalPropertyImplementation(Object* obj, String* key) { |
// Only JS objects can have properties. |
- if (args[0]->IsJSObject()) { |
- JSObject* object = JSObject::cast(args[0]); |
+ if (obj->IsJSObject()) { |
+ JSObject* object = JSObject::cast(obj); |
if (object->HasLocalProperty(key)) return Heap::true_value(); |
- } else if (args[0]->IsString()) { |
+ // Handle hidden prototypes. If there's a hidden prototype above this thing |
+ // then we have to check it for properties, because they are supposed to |
+ // look like they are on this object. |
+ Object* proto = object->GetPrototype(); |
+ if (proto->IsJSObject() && |
+ JSObject::cast(proto)->map()->is_hidden_prototype()) { |
+ return HasLocalPropertyImplementation(object->GetPrototype(), key); |
+ } |
+ } else if (obj->IsString()) { |
// Well, there is one exception: Handle [] on strings. |
uint32_t index; |
if (key->AsArrayIndex(&index)) { |
- String* string = String::cast(args[0]); |
+ String* string = String::cast(obj); |
if (index < static_cast<uint32_t>(string->length())) |
return Heap::true_value(); |
} |
@@ -2818,6 +2858,15 @@ |
} |
+static Object* Runtime_HasLocalProperty(Arguments args) { |
+ NoHandleAllocation ha; |
+ ASSERT(args.length() == 2); |
+ CONVERT_CHECKED(String, key, args[1]); |
+ |
+ return HasLocalPropertyImplementation(args[0], key); |
+} |
+ |
+ |
static Object* Runtime_HasProperty(Arguments args) { |
NoHandleAllocation na; |
ASSERT(args.length() == 2); |