| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 7bdcd0116df5cdfcbfa9a8a2a459f0e36f5a9ea1..4c00cb853ed9a749afc50d08c32b9c498415df7f 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -39,6 +39,7 @@
|
| #include "execution.h"
|
| #include "full-codegen.h"
|
| #include "hydrogen.h"
|
| +#include "isolate-inl.h"
|
| #include "objects-inl.h"
|
| #include "objects-visiting.h"
|
| #include "objects-visiting-inl.h"
|
| @@ -629,12 +630,23 @@ Object* JSObject::GetNormalizedProperty(LookupResult* result) {
|
| }
|
|
|
|
|
| -Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
|
| +Handle<Object> JSObject::SetNormalizedProperty(Handle<JSObject> object,
|
| + LookupResult* result,
|
| + Handle<Object> value) {
|
| + CALL_HEAP_FUNCTION(object->GetIsolate(),
|
| + object->SetNormalizedProperty(result, *value),
|
| + Object);
|
| +}
|
| +
|
| +
|
| +MaybeObject* JSObject::SetNormalizedProperty(LookupResult* result,
|
| + Object* value) {
|
| ASSERT(!HasFastProperties());
|
| if (IsGlobalObject()) {
|
| PropertyCell* cell = PropertyCell::cast(
|
| property_dictionary()->ValueAt(result->GetDictionaryEntry()));
|
| - cell->set_value(value);
|
| + MaybeObject* maybe_type = cell->SetValueInferType(value);
|
| + if (maybe_type->IsFailure()) return maybe_type;
|
| } else {
|
| property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
|
| }
|
| @@ -690,7 +702,8 @@ MaybeObject* JSObject::SetNormalizedProperty(Name* name,
|
| if (IsGlobalObject()) {
|
| PropertyCell* cell =
|
| PropertyCell::cast(property_dictionary()->ValueAt(entry));
|
| - cell->set_value(value);
|
| + MaybeObject* maybe_type = cell->SetValueInferType(value);
|
| + if (maybe_type->IsFailure()) return maybe_type;
|
| // Please note we have to update the property details.
|
| property_dictionary()->DetailsAtPut(entry, details);
|
| } else {
|
| @@ -722,7 +735,9 @@ MaybeObject* JSObject::DeleteNormalizedProperty(Name* name, DeleteMode mode) {
|
| set_map(new_map);
|
| }
|
| PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry));
|
| - cell->set_value(cell->GetHeap()->the_hole_value());
|
| + MaybeObject* maybe_type =
|
| + cell->SetValueInferType(cell->GetHeap()->the_hole_value());
|
| + if (maybe_type->IsFailure()) return maybe_type;
|
| dictionary->DetailsAtPut(entry, details.AsDeleted());
|
| } else {
|
| Object* deleted = dictionary->DeleteProperty(entry, mode);
|
| @@ -1929,7 +1944,9 @@ MaybeObject* JSObject::AddSlowProperty(Name* name,
|
| int entry = dict->FindEntry(name);
|
| if (entry != NameDictionary::kNotFound) {
|
| store_value = dict->ValueAt(entry);
|
| - PropertyCell::cast(store_value)->set_value(value);
|
| + MaybeObject* maybe_type =
|
| + PropertyCell::cast(store_value)->SetValueInferType(value);
|
| + if (maybe_type->IsFailure()) return maybe_type;
|
| // Assign an enumeration index to the property and update
|
| // SetNextEnumerationIndex.
|
| int index = dict->NextEnumerationIndex();
|
| @@ -1943,7 +1960,9 @@ MaybeObject* JSObject::AddSlowProperty(Name* name,
|
| heap->AllocatePropertyCell(value);
|
| if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
|
| }
|
| - PropertyCell::cast(store_value)->set_value(value);
|
| + MaybeObject* maybe_type =
|
| + PropertyCell::cast(store_value)->SetValueInferType(value);
|
| + if (maybe_type->IsFailure()) return maybe_type;
|
| }
|
| PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
|
| Object* result;
|
| @@ -5838,11 +5857,12 @@ static bool UpdateGetterSetterInDictionary(
|
| }
|
|
|
|
|
| -MaybeObject* JSObject::DefineElementAccessor(uint32_t index,
|
| - Object* getter,
|
| - Object* setter,
|
| - PropertyAttributes attributes) {
|
| - switch (GetElementsKind()) {
|
| +void JSObject::DefineElementAccessor(Handle<JSObject> object,
|
| + uint32_t index,
|
| + Handle<Object> getter,
|
| + Handle<Object> setter,
|
| + PropertyAttributes attributes) {
|
| + switch (object->GetElementsKind()) {
|
| case FAST_SMI_ELEMENTS:
|
| case FAST_ELEMENTS:
|
| case FAST_DOUBLE_ELEMENTS:
|
| @@ -5860,21 +5880,21 @@ MaybeObject* JSObject::DefineElementAccessor(uint32_t index,
|
| case EXTERNAL_FLOAT_ELEMENTS:
|
| case EXTERNAL_DOUBLE_ELEMENTS:
|
| // Ignore getters and setters on pixel and external array elements.
|
| - return GetHeap()->undefined_value();
|
| + return;
|
| case DICTIONARY_ELEMENTS:
|
| - if (UpdateGetterSetterInDictionary(element_dictionary(),
|
| + if (UpdateGetterSetterInDictionary(object->element_dictionary(),
|
| index,
|
| - getter,
|
| - setter,
|
| + *getter,
|
| + *setter,
|
| attributes)) {
|
| - return GetHeap()->undefined_value();
|
| + return;
|
| }
|
| break;
|
| case NON_STRICT_ARGUMENTS_ELEMENTS: {
|
| // Ascertain whether we have read-only properties or an existing
|
| // getter/setter pair in an arguments elements dictionary backing
|
| // store.
|
| - FixedArray* parameter_map = FixedArray::cast(elements());
|
| + FixedArray* parameter_map = FixedArray::cast(object->elements());
|
| uint32_t length = parameter_map->length();
|
| Object* probe =
|
| index < (length - 2) ? parameter_map->get(index + 2) : NULL;
|
| @@ -5885,10 +5905,10 @@ MaybeObject* JSObject::DefineElementAccessor(uint32_t index,
|
| SeededNumberDictionary::cast(arguments);
|
| if (UpdateGetterSetterInDictionary(dictionary,
|
| index,
|
| - getter,
|
| - setter,
|
| + *getter,
|
| + *setter,
|
| attributes)) {
|
| - return GetHeap()->undefined_value();
|
| + return;
|
| }
|
| }
|
| }
|
| @@ -5896,19 +5916,20 @@ MaybeObject* JSObject::DefineElementAccessor(uint32_t index,
|
| }
|
| }
|
|
|
| - AccessorPair* accessors;
|
| - { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
|
| - if (!maybe_accessors->To(&accessors)) return maybe_accessors;
|
| - }
|
| - accessors->SetComponents(getter, setter);
|
| + Isolate* isolate = object->GetIsolate();
|
| + Handle<AccessorPair> accessors = isolate->factory()->NewAccessorPair();
|
| + accessors->SetComponents(*getter, *setter);
|
|
|
| - return SetElementCallback(index, accessors, attributes);
|
| + CALL_HEAP_FUNCTION_VOID(
|
| + isolate, object->SetElementCallback(index, *accessors, attributes));
|
| }
|
|
|
|
|
| -MaybeObject* JSObject::CreateAccessorPairFor(Name* name) {
|
| - LookupResult result(GetHeap()->isolate());
|
| - LocalLookupRealNamedProperty(name, &result);
|
| +Handle<AccessorPair> JSObject::CreateAccessorPairFor(Handle<JSObject> object,
|
| + Handle<Name> name) {
|
| + Isolate* isolate = object->GetIsolate();
|
| + LookupResult result(isolate);
|
| + object->LocalLookupRealNamedProperty(*name, &result);
|
| if (result.IsPropertyCallbacks()) {
|
| // Note that the result can actually have IsDontDelete() == true when we
|
| // e.g. have to fall back to the slow case while adding a setter after
|
| @@ -5918,47 +5939,37 @@ MaybeObject* JSObject::CreateAccessorPairFor(Name* name) {
|
| // DefinePropertyAccessor below.
|
| Object* obj = result.GetCallbackObject();
|
| if (obj->IsAccessorPair()) {
|
| - return AccessorPair::cast(obj)->Copy();
|
| + return AccessorPair::Copy(handle(AccessorPair::cast(obj), isolate));
|
| }
|
| }
|
| - return GetHeap()->AllocateAccessorPair();
|
| + return isolate->factory()->NewAccessorPair();
|
| }
|
|
|
|
|
| -MaybeObject* JSObject::DefinePropertyAccessor(Name* name,
|
| - Object* getter,
|
| - Object* setter,
|
| - PropertyAttributes attributes) {
|
| +void JSObject::DefinePropertyAccessor(Handle<JSObject> object,
|
| + Handle<Name> name,
|
| + Handle<Object> getter,
|
| + Handle<Object> setter,
|
| + PropertyAttributes attributes) {
|
| // We could assert that the property is configurable here, but we would need
|
| // to do a lookup, which seems to be a bit of overkill.
|
| - Heap* heap = GetHeap();
|
| bool only_attribute_changes = getter->IsNull() && setter->IsNull();
|
| - if (HasFastProperties() && !only_attribute_changes &&
|
| - (map()->NumberOfOwnDescriptors() <
|
| + if (object->HasFastProperties() && !only_attribute_changes &&
|
| + (object->map()->NumberOfOwnDescriptors() <
|
| DescriptorArray::kMaxNumberOfDescriptors)) {
|
| - MaybeObject* getterOk = heap->undefined_value();
|
| - if (!getter->IsNull()) {
|
| - getterOk = DefineFastAccessor(name, ACCESSOR_GETTER, getter, attributes);
|
| - if (getterOk->IsFailure()) return getterOk;
|
| - }
|
| -
|
| - MaybeObject* setterOk = heap->undefined_value();
|
| - if (getterOk != heap->null_value() && !setter->IsNull()) {
|
| - setterOk = DefineFastAccessor(name, ACCESSOR_SETTER, setter, attributes);
|
| - if (setterOk->IsFailure()) return setterOk;
|
| - }
|
| -
|
| - if (getterOk != heap->null_value() && setterOk != heap->null_value()) {
|
| - return heap->undefined_value();
|
| - }
|
| + bool getterOk = getter->IsNull() ||
|
| + DefineFastAccessor(object, name, ACCESSOR_GETTER, getter, attributes);
|
| + bool setterOk = !getterOk || setter->IsNull() ||
|
| + DefineFastAccessor(object, name, ACCESSOR_SETTER, setter, attributes);
|
| + if (getterOk && setterOk) return;
|
| }
|
|
|
| - AccessorPair* accessors;
|
| - MaybeObject* maybe_accessors = CreateAccessorPairFor(name);
|
| - if (!maybe_accessors->To(&accessors)) return maybe_accessors;
|
| + Handle<AccessorPair> accessors = CreateAccessorPairFor(object, name);
|
| + accessors->SetComponents(*getter, *setter);
|
|
|
| - accessors->SetComponents(getter, setter);
|
| - return SetPropertyCallback(name, accessors, attributes);
|
| + CALL_HEAP_FUNCTION_VOID(
|
| + object->GetIsolate(),
|
| + object->SetPropertyCallback(*name, *accessors, attributes));
|
| }
|
|
|
|
|
| @@ -6060,29 +6071,21 @@ void JSObject::DefineAccessor(Handle<JSObject> object,
|
| Handle<Object> getter,
|
| Handle<Object> setter,
|
| PropertyAttributes attributes) {
|
| - CALL_HEAP_FUNCTION_VOID(
|
| - object->GetIsolate(),
|
| - object->DefineAccessor(*name, *getter, *setter, attributes));
|
| -}
|
| -
|
| -MaybeObject* JSObject::DefineAccessor(Name* name_raw,
|
| - Object* getter_raw,
|
| - Object* setter_raw,
|
| - PropertyAttributes attributes) {
|
| - Isolate* isolate = GetIsolate();
|
| + Isolate* isolate = object->GetIsolate();
|
| // Check access rights if needed.
|
| - if (IsAccessCheckNeeded() &&
|
| - !isolate->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) {
|
| - isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
|
| - return isolate->heap()->undefined_value();
|
| + if (object->IsAccessCheckNeeded() &&
|
| + !isolate->MayNamedAccess(*object, *name, v8::ACCESS_SET)) {
|
| + isolate->ReportFailedAccessCheck(*object, v8::ACCESS_SET);
|
| + return;
|
| }
|
|
|
| - if (IsJSGlobalProxy()) {
|
| - Object* proto = GetPrototype();
|
| - if (proto->IsNull()) return this;
|
| + if (object->IsJSGlobalProxy()) {
|
| + Handle<Object> proto(object->GetPrototype(), isolate);
|
| + if (proto->IsNull()) return;
|
| ASSERT(proto->IsJSGlobalObject());
|
| - return JSObject::cast(proto)->DefineAccessor(
|
| - name_raw, getter_raw, setter_raw, attributes);
|
| + DefineAccessor(
|
| + Handle<JSObject>::cast(proto), name, getter, setter, attributes);
|
| + return;
|
| }
|
|
|
| // Make sure that the top context does not change when doing callbacks or
|
| @@ -6090,68 +6093,58 @@ MaybeObject* JSObject::DefineAccessor(Name* name_raw,
|
| AssertNoContextChange ncc;
|
|
|
| // Try to flatten before operating on the string.
|
| - if (name_raw->IsString()) String::cast(name_raw)->TryFlatten();
|
| + if (name->IsString()) String::cast(*name)->TryFlatten();
|
|
|
| - if (!CanSetCallback(name_raw)) return isolate->heap()->undefined_value();
|
| -
|
| - // From this point on everything needs to be handlified.
|
| - HandleScope scope(isolate);
|
| - Handle<JSObject> self(this);
|
| - Handle<Name> name(name_raw);
|
| - Handle<Object> getter(getter_raw, isolate);
|
| - Handle<Object> setter(setter_raw, isolate);
|
| + if (!object->CanSetCallback(*name)) return;
|
|
|
| uint32_t index = 0;
|
| bool is_element = name->AsArrayIndex(&index);
|
|
|
| Handle<Object> old_value = isolate->factory()->the_hole_value();
|
| - bool is_observed = FLAG_harmony_observation && self->map()->is_observed();
|
| + bool is_observed = FLAG_harmony_observation && object->map()->is_observed();
|
| bool preexists = false;
|
| if (is_observed) {
|
| if (is_element) {
|
| - preexists = HasLocalElement(index);
|
| - if (preexists && self->GetLocalElementAccessorPair(index) == NULL) {
|
| - old_value = Object::GetElement(self, index);
|
| + preexists = object->HasLocalElement(index);
|
| + if (preexists && object->GetLocalElementAccessorPair(index) == NULL) {
|
| + old_value = Object::GetElement(object, index);
|
| }
|
| } else {
|
| LookupResult lookup(isolate);
|
| - LocalLookup(*name, &lookup, true);
|
| + object->LocalLookup(*name, &lookup, true);
|
| preexists = lookup.IsProperty();
|
| if (preexists && lookup.IsDataProperty()) {
|
| - old_value = Object::GetProperty(self, name);
|
| + old_value = Object::GetProperty(object, name);
|
| }
|
| }
|
| }
|
|
|
| - MaybeObject* result = is_element ?
|
| - self->DefineElementAccessor(index, *getter, *setter, attributes) :
|
| - self->DefinePropertyAccessor(*name, *getter, *setter, attributes);
|
| -
|
| - Handle<Object> hresult;
|
| - if (!result->ToHandle(&hresult, isolate)) return result;
|
| + if (is_element) {
|
| + DefineElementAccessor(object, index, getter, setter, attributes);
|
| + } else {
|
| + DefinePropertyAccessor(object, name, getter, setter, attributes);
|
| + }
|
|
|
| if (is_observed) {
|
| const char* type = preexists ? "reconfigured" : "new";
|
| - EnqueueChangeRecord(self, type, name, old_value);
|
| + EnqueueChangeRecord(object, type, name, old_value);
|
| }
|
| -
|
| - return *hresult;
|
| }
|
|
|
|
|
| -static MaybeObject* TryAccessorTransition(JSObject* self,
|
| - Map* transitioned_map,
|
| - int target_descriptor,
|
| - AccessorComponent component,
|
| - Object* accessor,
|
| - PropertyAttributes attributes) {
|
| +static bool TryAccessorTransition(JSObject* self,
|
| + Map* transitioned_map,
|
| + int target_descriptor,
|
| + AccessorComponent component,
|
| + Object* accessor,
|
| + PropertyAttributes attributes) {
|
| DescriptorArray* descs = transitioned_map->instance_descriptors();
|
| PropertyDetails details = descs->GetDetails(target_descriptor);
|
|
|
| // If the transition target was not callbacks, fall back to the slow case.
|
| - if (details.type() != CALLBACKS) return self->GetHeap()->null_value();
|
| + if (details.type() != CALLBACKS) return false;
|
| Object* descriptor = descs->GetCallbacksObject(target_descriptor);
|
| - if (!descriptor->IsAccessorPair()) return self->GetHeap()->null_value();
|
| + if (!descriptor->IsAccessorPair()) return false;
|
|
|
| Object* target_accessor = AccessorPair::cast(descriptor)->get(component);
|
| PropertyAttributes target_attributes = details.attributes();
|
| @@ -6159,25 +6152,46 @@ static MaybeObject* TryAccessorTransition(JSObject* self,
|
| // Reuse transition if adding same accessor with same attributes.
|
| if (target_accessor == accessor && target_attributes == attributes) {
|
| self->set_map(transitioned_map);
|
| - return self;
|
| + return true;
|
| }
|
|
|
| // If either not the same accessor, or not the same attributes, fall back to
|
| // the slow case.
|
| - return self->GetHeap()->null_value();
|
| + return false;
|
| }
|
|
|
|
|
| -MaybeObject* JSObject::DefineFastAccessor(Name* name,
|
| - AccessorComponent component,
|
| - Object* accessor,
|
| - PropertyAttributes attributes) {
|
| +static MaybeObject* CopyInsertDescriptor(Map* map,
|
| + Name* name,
|
| + AccessorPair* accessors,
|
| + PropertyAttributes attributes) {
|
| + CallbacksDescriptor new_accessors_desc(name, accessors, attributes);
|
| + return map->CopyInsertDescriptor(&new_accessors_desc, INSERT_TRANSITION);
|
| +}
|
| +
|
| +
|
| +static Handle<Map> CopyInsertDescriptor(Handle<Map> map,
|
| + Handle<Name> name,
|
| + Handle<AccessorPair> accessors,
|
| + PropertyAttributes attributes) {
|
| + CALL_HEAP_FUNCTION(map->GetIsolate(),
|
| + CopyInsertDescriptor(*map, *name, *accessors, attributes),
|
| + Map);
|
| +}
|
| +
|
| +
|
| +bool JSObject::DefineFastAccessor(Handle<JSObject> object,
|
| + Handle<Name> name,
|
| + AccessorComponent component,
|
| + Handle<Object> accessor,
|
| + PropertyAttributes attributes) {
|
| ASSERT(accessor->IsSpecFunction() || accessor->IsUndefined());
|
| - LookupResult result(GetIsolate());
|
| - LocalLookup(name, &result);
|
| + Isolate* isolate = object->GetIsolate();
|
| + LookupResult result(isolate);
|
| + object->LocalLookup(*name, &result);
|
|
|
| if (result.IsFound() && !result.IsPropertyCallbacks()) {
|
| - return GetHeap()->null_value();
|
| + return false;
|
| }
|
|
|
| // Return success if the same accessor with the same attributes already exist.
|
| @@ -6187,65 +6201,53 @@ MaybeObject* JSObject::DefineFastAccessor(Name* name,
|
| if (callback_value->IsAccessorPair()) {
|
| source_accessors = AccessorPair::cast(callback_value);
|
| Object* entry = source_accessors->get(component);
|
| - if (entry == accessor && result.GetAttributes() == attributes) {
|
| - return this;
|
| + if (entry == *accessor && result.GetAttributes() == attributes) {
|
| + return true;
|
| }
|
| } else {
|
| - return GetHeap()->null_value();
|
| + return false;
|
| }
|
|
|
| int descriptor_number = result.GetDescriptorIndex();
|
|
|
| - map()->LookupTransition(this, name, &result);
|
| + object->map()->LookupTransition(*object, *name, &result);
|
|
|
| if (result.IsFound()) {
|
| Map* target = result.GetTransitionTarget();
|
| ASSERT(target->NumberOfOwnDescriptors() ==
|
| - map()->NumberOfOwnDescriptors());
|
| + object->map()->NumberOfOwnDescriptors());
|
| // This works since descriptors are sorted in order of addition.
|
| - ASSERT(map()->instance_descriptors()->GetKey(descriptor_number) == name);
|
| - return TryAccessorTransition(
|
| - this, target, descriptor_number, component, accessor, attributes);
|
| + ASSERT(object->map()->instance_descriptors()->
|
| + GetKey(descriptor_number) == *name);
|
| + return TryAccessorTransition(*object, target, descriptor_number,
|
| + component, *accessor, attributes);
|
| }
|
| } else {
|
| // If not, lookup a transition.
|
| - map()->LookupTransition(this, name, &result);
|
| + object->map()->LookupTransition(*object, *name, &result);
|
|
|
| // If there is a transition, try to follow it.
|
| if (result.IsFound()) {
|
| Map* target = result.GetTransitionTarget();
|
| int descriptor_number = target->LastAdded();
|
| ASSERT(target->instance_descriptors()->GetKey(descriptor_number)
|
| - ->Equals(name));
|
| - return TryAccessorTransition(
|
| - this, target, descriptor_number, component, accessor, attributes);
|
| + ->Equals(*name));
|
| + return TryAccessorTransition(*object, target, descriptor_number,
|
| + component, *accessor, attributes);
|
| }
|
| }
|
|
|
| // If there is no transition yet, add a transition to the a new accessor pair
|
| - // containing the accessor.
|
| - AccessorPair* accessors;
|
| - MaybeObject* maybe_accessors;
|
| -
|
| - // Allocate a new pair if there were no source accessors. Otherwise, copy the
|
| - // pair and modify the accessor.
|
| - if (source_accessors != NULL) {
|
| - maybe_accessors = source_accessors->Copy();
|
| - } else {
|
| - maybe_accessors = GetHeap()->AllocateAccessorPair();
|
| - }
|
| - if (!maybe_accessors->To(&accessors)) return maybe_accessors;
|
| - accessors->set(component, accessor);
|
| -
|
| - CallbacksDescriptor new_accessors_desc(name, accessors, attributes);
|
| -
|
| - Map* new_map;
|
| - MaybeObject* maybe_new_map =
|
| - map()->CopyInsertDescriptor(&new_accessors_desc, INSERT_TRANSITION);
|
| - if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
| -
|
| - set_map(new_map);
|
| - return this;
|
| + // containing the accessor. Allocate a new pair if there were no source
|
| + // accessors. Otherwise, copy the pair and modify the accessor.
|
| + Handle<AccessorPair> accessors = source_accessors != NULL
|
| + ? AccessorPair::Copy(Handle<AccessorPair>(source_accessors))
|
| + : isolate->factory()->NewAccessorPair();
|
| + accessors->set(component, *accessor);
|
| + Handle<Map> new_map = CopyInsertDescriptor(Handle<Map>(object->map()),
|
| + name, accessors, attributes);
|
| + object->set_map(*new_map);
|
| + return true;
|
| }
|
|
|
|
|
| @@ -6689,6 +6691,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;
|
| @@ -7820,14 +7827,10 @@ void DescriptorArray::Sort() {
|
| }
|
|
|
|
|
| -MaybeObject* AccessorPair::Copy() {
|
| - Heap* heap = GetHeap();
|
| - AccessorPair* copy;
|
| - MaybeObject* maybe_copy = heap->AllocateAccessorPair();
|
| - if (!maybe_copy->To(©)) return maybe_copy;
|
| -
|
| - copy->set_getter(getter());
|
| - copy->set_setter(setter());
|
| +Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
|
| + Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
|
| + copy->set_getter(pair->getter());
|
| + copy->set_setter(pair->setter());
|
| return copy;
|
| }
|
|
|
| @@ -8862,21 +8865,6 @@ AllocationSiteInfo* AllocationSiteInfo::FindForJSObject(JSObject* object) {
|
| }
|
|
|
|
|
| -bool AllocationSiteInfo::GetElementsKindPayload(ElementsKind* kind) {
|
| - ASSERT(kind != NULL);
|
| - if (payload()->IsCell()) {
|
| - Cell* cell = Cell::cast(payload());
|
| - Object* cell_contents = cell->value();
|
| - if (cell_contents->IsSmi()) {
|
| - *kind = static_cast<ElementsKind>(
|
| - Smi::cast(cell_contents)->value());
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -
|
| uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
|
| // For array indexes mix the length into the hash as an array index could
|
| // be zero.
|
| @@ -9140,7 +9128,8 @@ void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
|
|
|
|
|
| void JSFunction::MarkForLazyRecompilation() {
|
| - ASSERT(is_compiled() && !IsOptimized());
|
| + ASSERT(is_compiled() || GetIsolate()->DebuggerHasBreakPoints());
|
| + ASSERT(!IsOptimized());
|
| ASSERT(shared()->allows_lazy_compilation() ||
|
| code()->optimizable());
|
| set_code_no_write_barrier(
|
| @@ -9150,7 +9139,8 @@ void JSFunction::MarkForLazyRecompilation() {
|
|
|
|
|
| void JSFunction::MarkForParallelRecompilation() {
|
| - ASSERT(is_compiled() && !IsOptimized());
|
| + ASSERT(is_compiled() || GetIsolate()->DebuggerHasBreakPoints());
|
| + ASSERT(!IsOptimized());
|
| ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
|
| if (!FLAG_parallel_recompilation) {
|
| JSFunction::MarkForLazyRecompilation();
|
| @@ -9168,7 +9158,9 @@ void JSFunction::MarkForParallelRecompilation() {
|
|
|
|
|
| void JSFunction::MarkForInstallingRecompiledCode() {
|
| - ASSERT(is_compiled() && !IsOptimized());
|
| + // The debugger could have switched the builtin to lazy compile.
|
| + // In that case, simply carry on. It will be dealt with later.
|
| + ASSERT(!IsOptimized());
|
| ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
|
| ASSERT(FLAG_parallel_recompilation);
|
| set_code_no_write_barrier(
|
| @@ -9178,7 +9170,10 @@ void JSFunction::MarkForInstallingRecompiledCode() {
|
|
|
|
|
| void JSFunction::MarkInRecompileQueue() {
|
| - ASSERT(is_compiled() && !IsOptimized());
|
| + // We can only arrive here via the parallel-recompilation builtin. If
|
| + // break points were set, the code would point to the lazy-compile builtin.
|
| + ASSERT(!GetIsolate()->DebuggerHasBreakPoints());
|
| + ASSERT(IsMarkedForParallelRecompilation() && !IsOptimized());
|
| ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
|
| ASSERT(FLAG_parallel_recompilation);
|
| if (FLAG_trace_parallel_recompilation) {
|
| @@ -9396,6 +9391,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;
|
|
|
| @@ -9963,22 +9963,26 @@ void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
|
| CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
|
| }
|
|
|
| +
|
| void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
|
| ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
|
| VisitPointer(rinfo->target_object_address());
|
| }
|
|
|
| +
|
| void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
|
| Address* p = rinfo->target_reference_address();
|
| VisitExternalReferences(p, p + 1);
|
| }
|
|
|
| +
|
| byte Code::compare_nil_state() {
|
| ASSERT(is_compare_nil_ic_stub());
|
| return CompareNilICStub::ExtractTypesFromExtraICState(
|
| extended_extra_ic_state());
|
| }
|
|
|
| +
|
| byte Code::compare_nil_value() {
|
| ASSERT(is_compare_nil_ic_stub());
|
| return CompareNilICStub::ExtractNilValueFromExtraICState(
|
| @@ -10250,7 +10254,11 @@ void Code::ClearTypeFeedbackCells(Heap* heap) {
|
| TypeFeedbackInfo::cast(raw_info)->type_feedback_cells();
|
| for (int i = 0; i < type_feedback_cells->CellCount(); i++) {
|
| Cell* cell = type_feedback_cells->GetCell(i);
|
| - cell->set_value(TypeFeedbackCells::RawUninitializedSentinel(heap));
|
| + // Don't clear AllocationSites
|
| + Object* value = cell->value();
|
| + if (value == NULL || !value->IsAllocationSite()) {
|
| + cell->set_value(TypeFeedbackCells::RawUninitializedSentinel(heap));
|
| + }
|
| }
|
| }
|
| }
|
| @@ -10381,6 +10389,19 @@ void Code::PrintDeoptLocation(int bailout_id) {
|
| }
|
|
|
|
|
| +bool Code::CanDeoptAt(Address pc) {
|
| + DeoptimizationInputData* deopt_data =
|
| + DeoptimizationInputData::cast(deoptimization_data());
|
| + Address code_start_address = instruction_start();
|
| + for (int i = 0; i < deopt_data->DeoptCount(); i++) {
|
| + if (deopt_data->Pc(i)->value() == -1) continue;
|
| + Address address = code_start_address + deopt_data->Pc(i)->value();
|
| + if (address == pc) return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +
|
| // Identify kind of code.
|
| const char* Code::Kind2String(Kind kind) {
|
| switch (kind) {
|
| @@ -10599,6 +10620,7 @@ const char* Code::StubType2String(StubType type) {
|
|
|
|
|
| void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
|
| + PrintF(out, "extra_ic_state = ");
|
| const char* name = NULL;
|
| switch (kind) {
|
| case CALL_IC:
|
| @@ -10616,9 +10638,9 @@ void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
|
| break;
|
| }
|
| if (name != NULL) {
|
| - PrintF(out, "extra_ic_state = %s\n", name);
|
| + PrintF(out, "%s\n", name);
|
| } else {
|
| - PrintF(out, "extra_ic_state = %d\n", extra);
|
| + PrintF(out, "%d\n", extra);
|
| }
|
| }
|
|
|
| @@ -10627,7 +10649,8 @@ void Code::Disassemble(const char* name, FILE* out) {
|
| PrintF(out, "kind = %s\n", Kind2String(kind()));
|
| if (is_inline_cache_stub()) {
|
| PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
|
| - PrintExtraICState(out, kind(), extra_ic_state());
|
| + PrintExtraICState(out, kind(), needs_extended_extra_ic_state(kind()) ?
|
| + extended_extra_ic_state() : extra_ic_state());
|
| if (ic_state() == MONOMORPHIC) {
|
| PrintF(out, "type = %s\n", StubType2String(type()));
|
| }
|
| @@ -11008,63 +11031,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));
|
| }
|
| }
|
| - 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;
|
| }
|
|
|
|
|
| @@ -11287,13 +11308,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.
|
| @@ -11307,70 +11329,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::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;
|
| }
|
|
|
| @@ -11707,7 +11723,7 @@ MaybeObject* JSObject::SetFastElement(uint32_t index,
|
| ? FAST_HOLEY_DOUBLE_ELEMENTS
|
| : FAST_DOUBLE_ELEMENTS;
|
|
|
| - MaybeObject* maybe_failure = UpdateAllocationSiteInfo(to_kind);
|
| + MaybeObject* maybe_failure = UpdateAllocationSite(to_kind);
|
| if (maybe_failure->IsFailure()) return maybe_failure;
|
|
|
| MaybeObject* maybe =
|
| @@ -11724,7 +11740,7 @@ MaybeObject* JSObject::SetFastElement(uint32_t index,
|
| ? FAST_HOLEY_ELEMENTS
|
| : FAST_ELEMENTS;
|
|
|
| - MaybeObject* maybe_failure = UpdateAllocationSiteInfo(kind);
|
| + MaybeObject* maybe_failure = UpdateAllocationSite(kind);
|
| if (maybe_failure->IsFailure()) return maybe_failure;
|
|
|
| MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(),
|
| @@ -12287,28 +12303,30 @@ Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object,
|
| }
|
|
|
|
|
| -MaybeObject* JSObject::UpdateAllocationSiteInfo(ElementsKind to_kind) {
|
| +MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) {
|
| if (!FLAG_track_allocation_sites || !IsJSArray()) {
|
| return this;
|
| }
|
|
|
| AllocationSiteInfo* info = AllocationSiteInfo::FindForJSObject(this);
|
| - if (info == NULL) {
|
| + if (info == NULL || !info->IsValid()) {
|
| return this;
|
| }
|
|
|
| - if (info->payload()->IsJSArray()) {
|
| - JSArray* payload = JSArray::cast(info->payload());
|
| + // Walk through to the Allocation Site
|
| + AllocationSite* site = info->GetAllocationSite();
|
| + if (site->IsLiteralSite()) {
|
| + JSArray* payload = JSArray::cast(site->payload());
|
| ElementsKind kind = payload->GetElementsKind();
|
| - if (AllocationSiteInfo::GetMode(kind, to_kind) == TRACK_ALLOCATION_SITE) {
|
| + if (AllocationSite::GetMode(kind, to_kind) == TRACK_ALLOCATION_SITE) {
|
| // If the array is huge, it's not likely to be defined in a local
|
| // function, so we shouldn't make new instances of it very often.
|
| uint32_t length = 0;
|
| CHECK(payload->length()->ToArrayIndex(&length));
|
| - if (length <= AllocationSiteInfo::kMaximumArrayBytesToPretransition) {
|
| + if (length <= AllocationSite::kMaximumArrayBytesToPretransition) {
|
| if (FLAG_trace_track_allocation_sites) {
|
| PrintF(
|
| - "AllocationSiteInfo: JSArray %p boilerplate updated %s->%s\n",
|
| + "AllocationSite: JSArray %p boilerplate updated %s->%s\n",
|
| reinterpret_cast<void*>(this),
|
| ElementsKindToString(kind),
|
| ElementsKindToString(to_kind));
|
| @@ -12316,21 +12334,16 @@ MaybeObject* JSObject::UpdateAllocationSiteInfo(ElementsKind to_kind) {
|
| return payload->TransitionElementsKind(to_kind);
|
| }
|
| }
|
| - } else if (info->payload()->IsCell()) {
|
| - Cell* cell = Cell::cast(info->payload());
|
| - Object* cell_contents = cell->value();
|
| - if (cell_contents->IsSmi()) {
|
| - ElementsKind kind = static_cast<ElementsKind>(
|
| - Smi::cast(cell_contents)->value());
|
| - if (AllocationSiteInfo::GetMode(kind, to_kind) == TRACK_ALLOCATION_SITE) {
|
| - if (FLAG_trace_track_allocation_sites) {
|
| - PrintF("AllocationSiteInfo: JSArray %p info updated %s->%s\n",
|
| - reinterpret_cast<void*>(this),
|
| - ElementsKindToString(kind),
|
| - ElementsKindToString(to_kind));
|
| - }
|
| - cell->set_value(Smi::FromInt(to_kind));
|
| + } else {
|
| + ElementsKind kind = site->GetElementsKindPayload();
|
| + if (AllocationSite::GetMode(kind, to_kind) == TRACK_ALLOCATION_SITE) {
|
| + if (FLAG_trace_track_allocation_sites) {
|
| + PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
|
| + reinterpret_cast<void*>(this),
|
| + ElementsKindToString(kind),
|
| + ElementsKindToString(to_kind));
|
| }
|
| + site->set_payload(Smi::FromInt(to_kind));
|
| }
|
| }
|
| return this;
|
| @@ -12347,7 +12360,7 @@ MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
|
|
|
| if (from_kind == to_kind) return this;
|
|
|
| - MaybeObject* maybe_failure = UpdateAllocationSiteInfo(to_kind);
|
| + MaybeObject* maybe_failure = UpdateAllocationSite(to_kind);
|
| if (maybe_failure->IsFailure()) return maybe_failure;
|
|
|
| Isolate* isolate = GetIsolate();
|
| @@ -13295,6 +13308,7 @@ class RegExpKey : public HashTableKey {
|
| Smi* flags_;
|
| };
|
|
|
| +
|
| // Utf8StringKey carries a vector of chars as key.
|
| class Utf8StringKey : public HashTableKey {
|
| public:
|
| @@ -13661,6 +13675,7 @@ uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
|
| return entry;
|
| }
|
|
|
| +
|
| // Force instantiation of template instances class.
|
| // Please note this list is compiler dependent.
|
|
|
| @@ -14023,6 +14038,7 @@ MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
|
| return result_double;
|
| }
|
|
|
| +
|
| ExternalArrayType JSTypedArray::type() {
|
| switch (elements()->map()->instance_type()) {
|
| case EXTERNAL_BYTE_ARRAY_TYPE:
|
| @@ -14237,39 +14253,36 @@ PropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
|
| }
|
|
|
|
|
| -Handle<PropertyCell> GlobalObject::EnsurePropertyCell(
|
| - Handle<GlobalObject> global,
|
| - Handle<Name> name) {
|
| - Isolate* isolate = global->GetIsolate();
|
| - CALL_HEAP_FUNCTION(isolate,
|
| - global->EnsurePropertyCell(*name),
|
| - PropertyCell);
|
| +// TODO(mstarzinger): Temporary wrapper until handlified.
|
| +static Handle<NameDictionary> NameDictionaryAdd(Handle<NameDictionary> dict,
|
| + Handle<Name> name,
|
| + Handle<Object> value,
|
| + PropertyDetails details) {
|
| + CALL_HEAP_FUNCTION(dict->GetIsolate(),
|
| + dict->Add(*name, *value, details),
|
| + NameDictionary);
|
| }
|
|
|
|
|
| -MaybeObject* GlobalObject::EnsurePropertyCell(Name* name) {
|
| - ASSERT(!HasFastProperties());
|
| - int entry = property_dictionary()->FindEntry(name);
|
| +Handle<PropertyCell> GlobalObject::EnsurePropertyCell(
|
| + Handle<GlobalObject> global,
|
| + Handle<Name> name) {
|
| + ASSERT(!global->HasFastProperties());
|
| + int entry = global->property_dictionary()->FindEntry(*name);
|
| if (entry == NameDictionary::kNotFound) {
|
| - Heap* heap = GetHeap();
|
| - Object* cell;
|
| - { MaybeObject* maybe_cell =
|
| - heap->AllocatePropertyCell(heap->the_hole_value());
|
| - if (!maybe_cell->ToObject(&cell)) return maybe_cell;
|
| - }
|
| + Isolate* isolate = global->GetIsolate();
|
| + Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(
|
| + isolate->factory()->the_hole_value());
|
| PropertyDetails details(NONE, NORMAL, 0);
|
| details = details.AsDeleted();
|
| - Object* dictionary;
|
| - { MaybeObject* maybe_dictionary =
|
| - property_dictionary()->Add(name, cell, details);
|
| - if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
|
| - }
|
| - set_properties(NameDictionary::cast(dictionary));
|
| + Handle<NameDictionary> dictionary = NameDictionaryAdd(
|
| + handle(global->property_dictionary()), name, cell, details);
|
| + global->set_properties(*dictionary);
|
| return cell;
|
| } else {
|
| - Object* value = property_dictionary()->ValueAt(entry);
|
| + Object* value = global->property_dictionary()->ValueAt(entry);
|
| ASSERT(value->IsPropertyCell());
|
| - return value;
|
| + return handle(PropertyCell::cast(value));
|
| }
|
| }
|
|
|
| @@ -14402,6 +14415,7 @@ MaybeObject* StringTable::LookupTwoByteString(Vector<const uc16> str,
|
| return LookupKey(&key, s);
|
| }
|
|
|
| +
|
| MaybeObject* StringTable::LookupKey(HashTableKey* key, Object** s) {
|
| int entry = FindEntry(key);
|
|
|
| @@ -15798,10 +15812,52 @@ Type* PropertyCell::type() {
|
|
|
|
|
| void PropertyCell::set_type(Type* type, WriteBarrierMode ignored) {
|
| + ASSERT(IsPropertyCell());
|
| set_type_raw(type, ignored);
|
| }
|
|
|
|
|
| +Type* PropertyCell::UpdateType(Handle<PropertyCell> cell,
|
| + Handle<Object> value) {
|
| + Isolate* isolate = cell->GetIsolate();
|
| + Handle<Type> old_type(cell->type(), isolate);
|
| + Handle<Type> new_type((value->IsSmi() || value->IsJSFunction() ||
|
| + value->IsUndefined())
|
| + ? Type::Constant(value, isolate)
|
| + : Type::Any(), isolate);
|
| +
|
| + if (new_type->Is(old_type)) {
|
| + return *old_type;
|
| + }
|
| +
|
| + cell->dependent_code()->DeoptimizeDependentCodeGroup(
|
| + isolate, DependentCode::kPropertyCellChangedGroup);
|
| +
|
| + if (old_type->Is(Type::None()) || old_type->Is(Type::Undefined())) {
|
| + return *new_type;
|
| + }
|
| +
|
| + return Type::Any();
|
| +}
|
| +
|
| +
|
| +MaybeObject* PropertyCell::SetValueInferType(Object* value,
|
| + WriteBarrierMode ignored) {
|
| + set_value(value, ignored);
|
| + if (!Type::Any()->Is(type())) {
|
| + IdempotentPointerToHandleCodeTrampoline trampoline(GetIsolate());
|
| + MaybeObject* maybe_type = trampoline.CallWithReturnValue(
|
| + &PropertyCell::UpdateType,
|
| + Handle<PropertyCell>(this),
|
| + Handle<Object>(value, GetIsolate()));
|
| + if (maybe_type->IsFailure()) return maybe_type;
|
| + Type* new_type = static_cast<Type*>(maybe_type);
|
| + set_type(new_type);
|
| + }
|
| + return value;
|
| +}
|
| +
|
| +
|
| void PropertyCell::AddDependentCompilationInfo(CompilationInfo* info) {
|
| Handle<DependentCode> dep(dependent_code());
|
| Handle<DependentCode> codes =
|
|
|