Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index d1a617e14dd5fe11e5441d1c5398a19b0ac80f1e..719ca3b201b0cc05f50efccb649ee8d955ede2d1 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -6689,6 +6689,11 @@ MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() { |
} |
+Handle<Map> Map::Copy(Handle<Map> map) { |
+ CALL_HEAP_FUNCTION(map->GetIsolate(), map->Copy(), Map); |
+} |
+ |
+ |
MaybeObject* Map::Copy() { |
DescriptorArray* descriptors = instance_descriptors(); |
DescriptorArray* new_descriptors; |
@@ -9400,6 +9405,11 @@ bool JSFunction::IsInlineable() { |
} |
+void JSObject::OptimizeAsPrototype(Handle<JSObject> object) { |
+ CALL_HEAP_FUNCTION_VOID(object->GetIsolate(), object->OptimizeAsPrototype()); |
+} |
+ |
+ |
MaybeObject* JSObject::OptimizeAsPrototype() { |
if (IsGlobalObject()) return this; |
@@ -11012,63 +11022,61 @@ MaybeObject* JSArray::SetElementsLength(Object* len) { |
} |
-Map* Map::GetPrototypeTransition(Object* prototype) { |
- FixedArray* cache = GetPrototypeTransitions(); |
- int number_of_transitions = NumberOfProtoTransitions(); |
+Handle<Map> Map::GetPrototypeTransition(Handle<Map> map, |
+ Handle<Object> prototype) { |
+ FixedArray* cache = map->GetPrototypeTransitions(); |
+ int number_of_transitions = map->NumberOfProtoTransitions(); |
const int proto_offset = |
kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset; |
const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset; |
const int step = kProtoTransitionElementsPerEntry; |
for (int i = 0; i < number_of_transitions; i++) { |
- if (cache->get(proto_offset + i * step) == prototype) { |
- Object* map = cache->get(map_offset + i * step); |
- return Map::cast(map); |
+ if (cache->get(proto_offset + i * step) == *prototype) { |
+ Object* result = cache->get(map_offset + i * step); |
+ return Handle<Map>(Map::cast(result)); |
rossberg
2013/07/02 12:08:01
Don't forget to pass the isolate.
Michael Starzinger
2013/07/02 15:20:15
As dicussed offline, it's not needed to pass the i
|
} |
} |
- return NULL; |
+ return Handle<Map>(); |
} |
-MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) { |
- ASSERT(map->IsMap()); |
- ASSERT(HeapObject::cast(prototype)->map()->IsMap()); |
+Handle<Map> Map::PutPrototypeTransition(Handle<Map> map, |
+ Handle<Object> prototype, |
+ Handle<Map> target_map) { |
+ ASSERT(target_map->IsMap()); |
+ ASSERT(HeapObject::cast(*prototype)->map()->IsMap()); |
// Don't cache prototype transition if this map is shared. |
- if (is_shared() || !FLAG_cache_prototype_transitions) return this; |
- |
- FixedArray* cache = GetPrototypeTransitions(); |
+ if (map->is_shared() || !FLAG_cache_prototype_transitions) return map; |
const int step = kProtoTransitionElementsPerEntry; |
const int header = kProtoTransitionHeaderSize; |
+ Handle<FixedArray> cache(map->GetPrototypeTransitions()); |
rossberg
2013/07/02 12:08:01
Pass the isolate.
Michael Starzinger
2013/07/02 15:20:15
Likeiwse.
|
int capacity = (cache->length() - header) / step; |
- |
- int transitions = NumberOfProtoTransitions() + 1; |
+ int transitions = map->NumberOfProtoTransitions() + 1; |
if (transitions > capacity) { |
- if (capacity > kMaxCachedPrototypeTransitions) return this; |
+ if (capacity > kMaxCachedPrototypeTransitions) return map; |
- FixedArray* new_cache; |
// Grow array by factor 2 over and above what we need. |
- { MaybeObject* maybe_cache = |
- GetHeap()->AllocateFixedArray(transitions * 2 * step + header); |
- if (!maybe_cache->To(&new_cache)) return maybe_cache; |
- } |
+ Factory* factory = map->GetIsolate()->factory(); |
+ cache = factory->CopySizeFixedArray(cache, transitions * 2 * step + header); |
- for (int i = 0; i < capacity * step; i++) { |
- new_cache->set(i + header, cache->get(i + header)); |
- } |
- cache = new_cache; |
- MaybeObject* set_result = SetPrototypeTransitions(cache); |
- if (set_result->IsFailure()) return set_result; |
+ CALL_AND_RETRY_OR_DIE(map->GetIsolate(), |
+ map->SetPrototypeTransitions(*cache), |
+ break, |
+ return Handle<Map>()); |
} |
- int last = transitions - 1; |
+ // Reload number of transitions as GC might shrink them. |
+ int last = map->NumberOfProtoTransitions(); |
+ int entry = header + last * step; |
- cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype); |
- cache->set(header + last * step + kProtoTransitionMapOffset, map); |
- SetNumberOfProtoTransitions(transitions); |
+ cache->set(entry + kProtoTransitionPrototypeOffset, *prototype); |
+ cache->set(entry + kProtoTransitionMapOffset, *target_map); |
+ map->SetNumberOfProtoTransitions(transitions); |
- return cache; |
+ return map; |
} |
@@ -11291,13 +11299,14 @@ void DependentCode::DeoptimizeDependentCodeGroup( |
} |
-MaybeObject* JSReceiver::SetPrototype(Object* value, |
+Handle<Object> JSObject::SetPrototype(Handle<JSObject> object, |
+ Handle<Object> value, |
bool skip_hidden_prototypes) { |
#ifdef DEBUG |
- int size = Size(); |
+ int size = object->Size(); |
#endif |
- Isolate* isolate = GetIsolate(); |
+ Isolate* isolate = object->GetIsolate(); |
Heap* heap = isolate->heap(); |
// Silently ignore the change if value is not a JSObject or null. |
// SpiderMonkey behaves this way. |
@@ -11311,70 +11320,64 @@ MaybeObject* JSReceiver::SetPrototype(Object* value, |
// Implementation specific extensions that modify [[Class]], [[Prototype]] |
// or [[Extensible]] must not violate the invariants defined in the preceding |
// paragraph. |
- if (!this->map()->is_extensible()) { |
- HandleScope scope(isolate); |
- Handle<Object> handle(this, isolate); |
- return isolate->Throw( |
- *isolate->factory()->NewTypeError("non_extensible_proto", |
- HandleVector<Object>(&handle, 1))); |
+ if (!object->map()->is_extensible()) { |
+ Handle<Object> args[] = { object }; |
+ Handle<Object> error = isolate->factory()->NewTypeError( |
+ "non_extensible_proto", HandleVector(args, ARRAY_SIZE(args))); |
+ isolate->Throw(*error); |
+ return Handle<Object>(); |
} |
// Before we can set the prototype we need to be sure |
// prototype cycles are prevented. |
// It is sufficient to validate that the receiver is not in the new prototype |
// chain. |
- for (Object* pt = value; |
+ for (Object* pt = *value; |
pt != heap->null_value(); |
pt = pt->GetPrototype(isolate)) { |
- if (JSReceiver::cast(pt) == this) { |
+ if (JSReceiver::cast(pt) == *object) { |
// Cycle detected. |
- HandleScope scope(isolate); |
- return isolate->Throw( |
- *isolate->factory()->NewError("cyclic_proto", |
- HandleVector<Object>(NULL, 0))); |
+ Handle<Object> error = isolate->factory()->NewError( |
+ "cyclic_proto", HandleVector<Object>(NULL, 0)); |
+ isolate->Throw(*error); |
+ return Handle<Object>(); |
} |
} |
- JSReceiver* real_receiver = this; |
+ Handle<JSObject> real_receiver = object; |
if (skip_hidden_prototypes) { |
// Find the first object in the chain whose prototype object is not |
// hidden and set the new prototype on that object. |
Object* current_proto = real_receiver->GetPrototype(); |
while (current_proto->IsJSObject() && |
- JSReceiver::cast(current_proto)->map()->is_hidden_prototype()) { |
- real_receiver = JSReceiver::cast(current_proto); |
+ JSObject::cast(current_proto)->map()->is_hidden_prototype()) { |
+ real_receiver = Handle<JSObject>(JSObject::cast(current_proto)); |
rossberg
2013/07/02 12:08:01
Pass the isolate. Also, you can use handle(..., is
Michael Starzinger
2013/07/02 15:20:15
Done, switched to handle(..., isolate) to avoid ty
|
current_proto = current_proto->GetPrototype(isolate); |
} |
} |
// Set the new prototype of the object. |
- Map* map = real_receiver->map(); |
+ Handle<Map> map(real_receiver->map()); |
rossberg
2013/07/02 12:08:01
Pass the isolate.
Michael Starzinger
2013/07/02 15:20:15
Likewise.
|
// Nothing to do if prototype is already set. |
- if (map->prototype() == value) return value; |
+ if (map->prototype() == *value) return value; |
if (value->IsJSObject()) { |
- MaybeObject* ok = JSObject::cast(value)->OptimizeAsPrototype(); |
- if (ok->IsFailure()) return ok; |
+ JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value)); |
} |
- Map* new_map = map->GetPrototypeTransition(value); |
- if (new_map == NULL) { |
- MaybeObject* maybe_new_map = map->Copy(); |
- if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
- |
- MaybeObject* maybe_new_cache = |
- map->PutPrototypeTransition(value, new_map); |
- if (maybe_new_cache->IsFailure()) return maybe_new_cache; |
- |
- new_map->set_prototype(value); |
+ Handle<Map> new_map = Map::GetPrototypeTransition(map, value); |
+ if (new_map.is_null()) { |
+ new_map = Map::Copy(map); |
+ Map::PutPrototypeTransition(map, value, new_map); |
+ new_map->set_prototype(*value); |
} |
- ASSERT(new_map->prototype() == value); |
- real_receiver->set_map(new_map); |
+ ASSERT(new_map->prototype() == *value); |
+ real_receiver->set_map(*new_map); |
heap->ClearInstanceofCache(); |
- ASSERT(size == Size()); |
+ ASSERT(size == object->Size()); |
return value; |
} |