}
+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;
}
+void JSObject::OptimizeAsPrototype(Handle<JSObject> object) {
+ CALL_HEAP_FUNCTION_VOID(object->GetIsolate(), object->OptimizeAsPrototype());
+}
+
+
MaybeObject* JSObject::OptimizeAsPrototype() {
if (IsGlobalObject()) return this;
}
-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));
}
}
- 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());
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;
}
}
-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.
// 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::cast(current_proto), isolate);
current_proto = current_proto->GetPrototype(isolate);
}
}
// Set the new prototype of the object.
- Map* map = real_receiver->map();
+ Handle<Map> map(real_receiver->map());
// 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;
}
// Return the constructor function (may be Heap::null_value()).
inline Object* GetConstructor();
- // Set the object's prototype (only JSReceiver and null are allowed).
- MUST_USE_RESULT MaybeObject* SetPrototype(Object* value,
- bool skip_hidden_prototypes);
-
// Retrieves a permanent object identity hash code. The undefined value might
// be returned in case no hash was created yet and OMIT_CREATION was used.
inline MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag);
MUST_USE_RESULT MaybeObject* DeleteNormalizedProperty(Name* name,
DeleteMode mode);
+ static void OptimizeAsPrototype(Handle<JSObject> object);
MUST_USE_RESULT MaybeObject* OptimizeAsPrototype();
// Retrieve interceptors.
WriteBarrierMode mode
= UPDATE_WRITE_BARRIER);
+ // Set the object's prototype (only JSReceiver and null are allowed values).
+ static Handle<Object> SetPrototype(Handle<JSObject> object,
+ Handle<Object> value,
+ bool skip_hidden_prototypes = false);
+
// Initializes the body after properties slot, properties slot is
// initialized by set_properties. Fill the pre-allocated fields with
// pre_allocated_value and the rest with filler_value.
// Returns a copy of the map, with all transitions dropped from the
// instance descriptors.
+ static Handle<Map> Copy(Handle<Map> map);
MUST_USE_RESULT MaybeObject* Copy();
// Returns the next free property index (only valid for FAST MODE).
// transitions are in the form of a map where the keys are prototype objects
// and the values are the maps the are transitioned to.
static const int kMaxCachedPrototypeTransitions = 256;
-
- Map* GetPrototypeTransition(Object* prototype);
-
- MUST_USE_RESULT MaybeObject* PutPrototypeTransition(Object* prototype,
- Map* map);
+ static Handle<Map> GetPrototypeTransition(Handle<Map> map,
+ Handle<Object> prototype);
+ static Handle<Map> PutPrototypeTransition(Handle<Map> map,
+ Handle<Object> prototype,
+ Handle<Map> target_map);
static const int kMaxPreAllocatedPropertyFields = 255;
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetPrototype) {
- SealHandleScope shs(isolate);
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
- CONVERT_ARG_CHECKED(JSObject, obj, 0);
- CONVERT_ARG_CHECKED(Object, prototype, 1);
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+ CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
if (FLAG_harmony_observation && obj->map()->is_observed()) {
- HandleScope scope(isolate);
- Handle<JSObject> receiver(obj);
- Handle<Object> value(prototype, isolate);
Handle<Object> old_value(
- GetPrototypeSkipHiddenPrototypes(isolate, *receiver), isolate);
+ GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate);
- MaybeObject* result = receiver->SetPrototype(*value, true);
- Handle<Object> hresult;
- if (!result->ToHandle(&hresult, isolate)) return result;
+ Handle<Object> result = JSObject::SetPrototype(obj, prototype, true);
+ if (result.is_null()) return Failure::Exception();
Handle<Object> new_value(
- GetPrototypeSkipHiddenPrototypes(isolate, *receiver), isolate);
+ GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate);
if (!new_value->SameValue(*old_value)) {
- JSObject::EnqueueChangeRecord(receiver, "prototype",
+ JSObject::EnqueueChangeRecord(obj, "prototype",
isolate->factory()->proto_string(),
old_value);
}
- return *hresult;
+ return *result;
}
- return obj->SetPrototype(prototype, true);
+ Handle<Object> result = JSObject::SetPrototype(obj, prototype, true);
+ if (result.is_null()) return Failure::Exception();
+ return *result;
}