summaryrefslogtreecommitdiff
path: root/deps/v8/src/objects.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/objects.cc')
-rw-r--r--deps/v8/src/objects.cc1833
1 files changed, 997 insertions, 836 deletions
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc
index 23eac77f7..35646b8be 100644
--- a/deps/v8/src/objects.cc
+++ b/deps/v8/src/objects.cc
@@ -32,6 +32,7 @@
#include "arguments.h"
#include "bootstrapper.h"
#include "codegen.h"
+#include "cpu-profiler.h"
#include "debug.h"
#include "deoptimizer.h"
#include "date.h"
@@ -40,6 +41,7 @@
#include "full-codegen.h"
#include "hydrogen.h"
#include "isolate-inl.h"
+#include "log.h"
#include "objects-inl.h"
#include "objects-visiting.h"
#include "objects-visiting-inl.h"
@@ -83,23 +85,19 @@ MaybeObject* Object::ToObject(Context* native_context) {
}
-MaybeObject* Object::ToObject() {
+MaybeObject* Object::ToObject(Isolate* isolate) {
if (IsJSReceiver()) {
return this;
} else if (IsNumber()) {
- Isolate* isolate = Isolate::Current();
Context* native_context = isolate->context()->native_context();
return CreateJSValue(native_context->number_function(), this);
} else if (IsBoolean()) {
- Isolate* isolate = HeapObject::cast(this)->GetIsolate();
Context* native_context = isolate->context()->native_context();
return CreateJSValue(native_context->boolean_function(), this);
} else if (IsString()) {
- Isolate* isolate = HeapObject::cast(this)->GetIsolate();
Context* native_context = isolate->context()->native_context();
return CreateJSValue(native_context->string_function(), this);
} else if (IsSymbol()) {
- Isolate* isolate = HeapObject::cast(this)->GetIsolate();
Context* native_context = isolate->context()->native_context();
return CreateJSValue(native_context->symbol_function(), this);
}
@@ -135,7 +133,7 @@ void Object::Lookup(Name* name, LookupResult* result) {
} else if (IsBoolean()) {
holder = native_context->boolean_function()->instance_prototype();
} else {
- Isolate::Current()->PushStackTraceAndDie(
+ result->isolate()->PushStackTraceAndDie(
0xDEAD0000, this, JSReceiver::cast(this)->map(), 0xDEAD0001);
}
}
@@ -341,7 +339,7 @@ MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
AccessorDescriptor* callback =
reinterpret_cast<AccessorDescriptor*>(
Foreign::cast(structure)->foreign_address());
- MaybeObject* value = (callback->getter)(receiver, callback->data);
+ MaybeObject* value = (callback->getter)(isolate, receiver, callback->data);
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return value;
}
@@ -368,7 +366,8 @@ MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
}
ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(structure);
Object* fun_obj = data->getter();
- v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
+ v8::AccessorGetterCallback call_fun =
+ v8::ToCData<v8::AccessorGetterCallback>(fun_obj);
if (call_fun == NULL) return isolate->heap()->undefined_value();
HandleScope scope(isolate);
JSObject* self = JSObject::cast(receiver);
@@ -421,24 +420,22 @@ MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw,
}
-Handle<Object> Object::GetProperty(Handle<Object> object, Handle<Name> name) {
+Handle<Object> Object::GetProperty(Handle<Object> object,
+ Handle<Name> name) {
// TODO(rossberg): The index test should not be here but in the GetProperty
// method (or somewhere else entirely). Needs more global clean-up.
uint32_t index;
+ Isolate* isolate = name->GetIsolate();
if (name->AsArrayIndex(&index))
- return GetElement(object, index);
- Isolate* isolate = object->IsHeapObject()
- ? Handle<HeapObject>::cast(object)->GetIsolate()
- : Isolate::Current();
+ return GetElement(isolate, object, index);
CALL_HEAP_FUNCTION(isolate, object->GetProperty(*name), Object);
}
-Handle<Object> Object::GetElement(Handle<Object> object, uint32_t index) {
- Isolate* isolate = object->IsHeapObject()
- ? Handle<HeapObject>::cast(object)->GetIsolate()
- : Isolate::Current();
- CALL_HEAP_FUNCTION(isolate, object->GetElement(index), Object);
+Handle<Object> Object::GetElement(Isolate* isolate,
+ Handle<Object> object,
+ uint32_t index) {
+ CALL_HEAP_FUNCTION(isolate, object->GetElement(isolate, index), Object);
}
@@ -451,14 +448,17 @@ MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
}
-MaybeObject* JSProxy::SetElementWithHandler(JSReceiver* receiver,
- uint32_t index,
- Object* value,
- StrictModeFlag strict_mode) {
- String* name;
- MaybeObject* maybe = GetHeap()->Uint32ToString(index);
- if (!maybe->To<String>(&name)) return maybe;
- return SetPropertyWithHandler(receiver, name, value, NONE, strict_mode);
+Handle<Object> JSProxy::SetElementWithHandler(Handle<JSProxy> proxy,
+ Handle<JSReceiver> receiver,
+ uint32_t index,
+ Handle<Object> value,
+ StrictModeFlag strict_mode) {
+ Isolate* isolate = proxy->GetIsolate();
+ Handle<String> name = isolate->factory()->Uint32ToString(index);
+ CALL_HEAP_FUNCTION(isolate,
+ proxy->SetPropertyWithHandler(
+ *receiver, *name, *value, NONE, strict_mode),
+ Object);
}
@@ -487,8 +487,8 @@ MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
#endif
bool has_pending_exception;
- Handle<Object> result =
- Execution::Call(fun, self, 0, NULL, &has_pending_exception, true);
+ Handle<Object> result = Execution::Call(
+ isolate, fun, self, 0, NULL, &has_pending_exception, true);
// Check for pending exception and return the result.
if (has_pending_exception) return Failure::Exception();
return *result;
@@ -513,6 +513,12 @@ MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
return result->holder()->GetPropertyWithCallback(
receiver, result->GetCallbackObject(), name);
}
+ } else if (obj->IsAccessorPair()) {
+ AccessorPair* pair = AccessorPair::cast(obj);
+ if (pair->all_can_read()) {
+ return result->holder()->GetPropertyWithCallback(
+ receiver, result->GetCallbackObject(), name);
+ }
}
break;
}
@@ -573,6 +579,11 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
if (info->all_can_read()) {
return result->GetAttributes();
}
+ } else if (obj->IsAccessorPair()) {
+ AccessorPair* pair = AccessorPair::cast(obj);
+ if (pair->all_can_read()) {
+ return result->GetAttributes();
+ }
}
break;
}
@@ -786,9 +797,7 @@ Handle<Object> Object::GetProperty(Handle<Object> object,
LookupResult* result,
Handle<Name> key,
PropertyAttributes* attributes) {
- Isolate* isolate = object->IsHeapObject()
- ? Handle<HeapObject>::cast(object)->GetIsolate()
- : Isolate::Current();
+ Isolate* isolate = result->isolate();
CALL_HEAP_FUNCTION(
isolate,
object->GetProperty(*receiver, result, *key, attributes),
@@ -801,9 +810,7 @@ MaybeObject* Object::GetPropertyOrFail(Handle<Object> object,
LookupResult* result,
Handle<Name> key,
PropertyAttributes* attributes) {
- Isolate* isolate = object->IsHeapObject()
- ? Handle<HeapObject>::cast(object)->GetIsolate()
- : Isolate::Current();
+ Isolate* isolate = result->isolate();
CALL_HEAP_FUNCTION_PASS_EXCEPTION(
isolate,
object->GetProperty(*receiver, result, *key, attributes));
@@ -816,7 +823,8 @@ MaybeObject* Object::GetProperty(Object* receiver,
PropertyAttributes* attributes) {
// Make sure that the top context does not change when doing
// callbacks or interceptor calls.
- AssertNoContextChange ncc;
+ AssertNoContextChangeWithHandleScope ncc;
+
Isolate* isolate = name->GetIsolate();
Heap* heap = isolate->heap();
@@ -894,10 +902,9 @@ MaybeObject* Object::GetProperty(Object* receiver,
}
-MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
- Isolate* isolate = IsSmi()
- ? Isolate::Current()
- : HeapObject::cast(this)->GetIsolate();
+MaybeObject* Object::GetElementWithReceiver(Isolate* isolate,
+ Object* receiver,
+ uint32_t index) {
Heap* heap = isolate->heap();
Object* holder = this;
@@ -1449,6 +1456,66 @@ void JSObject::PrintElementsTransition(
}
+void Map::PrintGeneralization(FILE* file,
+ const char* reason,
+ int modify_index,
+ int split,
+ int descriptors,
+ bool constant_to_field,
+ Representation old_representation,
+ Representation new_representation) {
+ PrintF(file, "[generalizing ");
+ constructor_name()->PrintOn(file);
+ PrintF(file, "] ");
+ String::cast(instance_descriptors()->GetKey(modify_index))->PrintOn(file);
+ if (constant_to_field) {
+ PrintF(file, ":c->f");
+ } else {
+ PrintF(file, ":%s->%s",
+ old_representation.Mnemonic(),
+ new_representation.Mnemonic());
+ }
+ PrintF(file, " (");
+ if (strlen(reason) > 0) {
+ PrintF(file, "%s", reason);
+ } else {
+ PrintF(file, "+%i maps", descriptors - split);
+ }
+ PrintF(file, ") [");
+ JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
+ PrintF(file, "]\n");
+}
+
+
+void JSObject::PrintInstanceMigration(FILE* file,
+ Map* original_map,
+ Map* new_map) {
+ PrintF(file, "[migrating ");
+ map()->constructor_name()->PrintOn(file);
+ PrintF(file, "] ");
+ DescriptorArray* o = original_map->instance_descriptors();
+ DescriptorArray* n = new_map->instance_descriptors();
+ for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
+ Representation o_r = o->GetDetails(i).representation();
+ Representation n_r = n->GetDetails(i).representation();
+ if (!o_r.Equals(n_r)) {
+ String::cast(o->GetKey(i))->PrintOn(file);
+ PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
+ } else if (o->GetDetails(i).type() == CONSTANT &&
+ n->GetDetails(i).type() == FIELD) {
+ Name* name = o->GetKey(i);
+ if (name->IsString()) {
+ String::cast(name)->PrintOn(file);
+ } else {
+ PrintF(file, "???");
+ }
+ PrintF(file, " ");
+ }
+ }
+ PrintF(file, "\n");
+}
+
+
void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
Heap* heap = GetHeap();
if (!heap->Contains(this)) {
@@ -1783,14 +1850,14 @@ String* JSReceiver::class_name() {
}
-String* JSReceiver::constructor_name() {
- if (map()->constructor()->IsJSFunction()) {
- JSFunction* constructor = JSFunction::cast(map()->constructor());
+String* Map::constructor_name() {
+ if (constructor()->IsJSFunction()) {
+ JSFunction* constructor = JSFunction::cast(this->constructor());
String* name = String::cast(constructor->shared()->name());
if (name->length() > 0) return name;
String* inferred_name = constructor->shared()->inferred_name();
if (inferred_name->length() > 0) return inferred_name;
- Object* proto = GetPrototype();
+ Object* proto = prototype();
if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
}
// TODO(rossberg): what about proxies?
@@ -1799,6 +1866,11 @@ String* JSReceiver::constructor_name() {
}
+String* JSReceiver::constructor_name() {
+ return map()->constructor_name();
+}
+
+
MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
Name* name,
Object* value,
@@ -1828,30 +1900,12 @@ MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
}
-static bool IsIdentifier(UnicodeCache* cache, Name* name) {
- // Checks whether the buffer contains an identifier (no escape).
- if (!name->IsString()) return false;
- String* string = String::cast(name);
- if (string->length() == 0) return false;
- ConsStringIteratorOp op;
- StringCharacterStream stream(string, &op);
- if (!cache->IsIdentifierStart(stream.GetNext())) {
- return false;
- }
- while (stream.HasMore()) {
- if (!cache->IsIdentifierPart(stream.GetNext())) {
- return false;
- }
- }
- return true;
-}
-
-
MaybeObject* JSObject::AddFastProperty(Name* name,
Object* value,
PropertyAttributes attributes,
StoreFromKeyed store_mode,
- ValueType value_type) {
+ ValueType value_type,
+ TransitionFlag flag) {
ASSERT(!IsJSGlobalProxy());
ASSERT(DescriptorArray::kNotFound ==
map()->instance_descriptors()->Search(
@@ -1861,15 +1915,10 @@ MaybeObject* JSObject::AddFastProperty(Name* name,
// hidden strings) and is not a real identifier.
// Normalize the object if it will have too many fast properties.
Isolate* isolate = GetHeap()->isolate();
- if ((!name->IsSymbol() && !IsIdentifier(isolate->unicode_cache(), name)
- && name != isolate->heap()->hidden_string()) ||
- (map()->unused_property_fields() == 0 &&
- TooManyFastProperties(properties()->length(), store_mode))) {
- Object* obj;
- MaybeObject* maybe_obj =
+ if (!name->IsCacheable(isolate) || TooManyFastProperties(store_mode)) {
+ MaybeObject* maybe_failure =
NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
-
+ if (maybe_failure->IsFailure()) return maybe_failure;
return AddSlowProperty(name, value, attributes);
}
@@ -1882,66 +1931,36 @@ MaybeObject* JSObject::AddFastProperty(Name* name,
FieldDescriptor new_field(name, index, attributes, representation);
- ASSERT(index < map()->inobject_properties() ||
- (index - map()->inobject_properties()) < properties()->length() ||
- map()->unused_property_fields() == 0);
-
- FixedArray* values = NULL;
-
- // TODO(verwaest): Merge with AddFastPropertyUsingMap.
- if (map()->unused_property_fields() == 0) {
- // Make room for the new value
- MaybeObject* maybe_values =
- properties()->CopySize(properties()->length() + kFieldsAdded);
- if (!maybe_values->To(&values)) return maybe_values;
- }
-
- TransitionFlag flag = INSERT_TRANSITION;
-
- Heap* heap = isolate->heap();
-
- Object* storage;
- MaybeObject* maybe_storage =
- value->AllocateNewStorageFor(heap, representation);
- if (!maybe_storage->To(&storage)) return maybe_storage;
-
- // Note that Map::CopyAddDescriptor has side-effects, the new map is already
- // inserted in the transition tree. No more allocations that might fail are
- // allowed after this point.
Map* new_map;
MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&new_field, flag);
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
- if (map()->unused_property_fields() == 0) {
- ASSERT(values != NULL);
- set_properties(values);
- new_map->set_unused_property_fields(kFieldsAdded - 1);
- } else {
- new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
+ int unused_property_fields = map()->unused_property_fields() - 1;
+ if (unused_property_fields < 0) {
+ unused_property_fields += kFieldsAdded;
}
+ new_map->set_unused_property_fields(unused_property_fields);
- set_map(new_map);
-
- FastPropertyAtPut(index, storage);
- return value;
+ return AddFastPropertyUsingMap(new_map, name, value, index, representation);
}
MaybeObject* JSObject::AddConstantProperty(
Name* name,
Object* constant,
- PropertyAttributes attributes) {
+ PropertyAttributes attributes,
+ TransitionFlag initial_flag) {
// Allocate new instance descriptors with (name, constant) added
ConstantDescriptor d(name, constant, attributes);
TransitionFlag flag =
- // Do not add transitions to global objects.
+ // Do not add transitions to global objects.
(IsGlobalObject() ||
// Don't add transitions to special properties with non-trivial
// attributes.
attributes != NONE)
? OMIT_TRANSITION
- : INSERT_TRANSITION;
+ : initial_flag;
Map* new_map;
MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&d, flag);
@@ -2001,7 +2020,8 @@ MaybeObject* JSObject::AddProperty(Name* name,
JSReceiver::StoreFromKeyed store_mode,
ExtensibilityCheck extensibility_check,
ValueType value_type,
- StoreMode mode) {
+ StoreMode mode,
+ TransitionFlag transition_flag) {
ASSERT(!IsJSGlobalProxy());
Map* map_of_this = map();
Heap* heap = GetHeap();
@@ -2028,10 +2048,10 @@ MaybeObject* JSObject::AddProperty(Name* name,
// !value->IsTheHole() &&
// !value->IsConsString()) {
if (value->IsJSFunction()) {
- result = AddConstantProperty(name, value, attributes);
+ result = AddConstantProperty(name, value, attributes, transition_flag);
} else {
result = AddFastProperty(
- name, value, attributes, store_mode, value_type);
+ name, value, attributes, store_mode, value_type, transition_flag);
}
} else {
// Normalize the object to prevent very large instance descriptors.
@@ -2071,7 +2091,8 @@ void JSObject::EnqueueChangeRecord(Handle<JSObject> object,
}
Handle<Object> args[] = { type, object, name, old_value };
bool threw;
- Execution::Call(Handle<JSFunction>(isolate->observers_notify_change()),
+ Execution::Call(isolate,
+ Handle<JSFunction>(isolate->observers_notify_change()),
isolate->factory()->undefined_value(),
old_value->IsTheHole() ? 3 : 4, args,
&threw);
@@ -2083,6 +2104,7 @@ void JSObject::DeliverChangeRecords(Isolate* isolate) {
ASSERT(isolate->observer_delivery_pending());
bool threw = false;
Execution::Call(
+ isolate,
isolate->observers_deliver_changes(),
isolate->factory()->undefined_value(),
0,
@@ -2098,7 +2120,6 @@ MaybeObject* JSObject::SetPropertyPostInterceptor(
Object* value,
PropertyAttributes attributes,
StrictModeFlag strict_mode,
- ExtensibilityCheck extensibility_check,
StoreMode mode) {
// Check local property, ignore interceptor.
LookupResult result(GetIsolate());
@@ -2110,13 +2131,12 @@ MaybeObject* JSObject::SetPropertyPostInterceptor(
return SetProperty(&result, name, value, attributes, strict_mode);
}
bool done = false;
- MaybeObject* result_object;
- result_object =
+ MaybeObject* result_object =
SetPropertyViaPrototypes(name, value, attributes, strict_mode, &done);
if (done) return result_object;
// Add a new real property.
return AddProperty(name, value, attributes, strict_mode,
- MAY_BE_STORE_FROM_KEYED, extensibility_check,
+ MAY_BE_STORE_FROM_KEYED, PERFORM_EXTENSIBILITY_CHECK,
OPTIMAL_REPRESENTATION, mode);
}
@@ -2137,105 +2157,6 @@ MaybeObject* JSObject::ReplaceSlowProperty(Name* name,
}
-MaybeObject* JSObject::ConvertTransitionToMapTransition(
- int transition_index,
- Name* name,
- Object* new_value,
- PropertyAttributes attributes) {
- Map* old_map = map();
- Map* old_target = old_map->GetTransition(transition_index);
- Object* result;
-
- MaybeObject* maybe_result = ConvertDescriptorToField(
- name, new_value, attributes, OMIT_TRANSITION_KEEP_REPRESENTATIONS);
- if (!maybe_result->To(&result)) return maybe_result;
-
- if (!HasFastProperties()) return result;
-
- // This method should only be used to convert existing transitions.
- Map* new_map = map();
-
- // TODO(verwaest): From here on we lose existing map transitions, causing
- // invalid back pointers. This will change once we can store multiple
- // transitions with the same key.
- bool owned_descriptors = old_map->owns_descriptors();
- if (owned_descriptors ||
- old_target->instance_descriptors() == old_map->instance_descriptors()) {
- // Since the conversion above generated a new fast map with an additional
- // property which can be shared as well, install this descriptor pointer
- // along the entire chain of smaller maps.
- Map* map;
- DescriptorArray* new_descriptors = new_map->instance_descriptors();
- DescriptorArray* old_descriptors = old_map->instance_descriptors();
- for (Object* current = old_map;
- !current->IsUndefined();
- current = map->GetBackPointer()) {
- map = Map::cast(current);
- if (map->instance_descriptors() != old_descriptors) break;
- map->SetEnumLength(Map::kInvalidEnumCache);
- map->set_instance_descriptors(new_descriptors);
- }
- old_map->set_owns_descriptors(false);
- }
-
- old_target->DeprecateTransitionTree();
-
- old_map->SetTransition(transition_index, new_map);
- new_map->SetBackPointer(old_map);
- return result;
-}
-
-
-MaybeObject* JSObject::ConvertDescriptorToField(Name* name,
- Object* new_value,
- PropertyAttributes attributes,
- TransitionFlag flag) {
- if (map()->unused_property_fields() == 0 &&
- TooManyFastProperties(properties()->length(), MAY_BE_STORE_FROM_KEYED)) {
- Object* obj;
- MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- return ReplaceSlowProperty(name, new_value, attributes);
- }
-
- Representation representation = IsJSContextExtensionObject()
- ? Representation::Tagged() : new_value->OptimalRepresentation();
- int index = map()->NextFreePropertyIndex();
- FieldDescriptor new_field(name, index, attributes, representation);
-
- // Make a new map for the object.
- Map* new_map;
- MaybeObject* maybe_new_map = map()->CopyInsertDescriptor(&new_field, flag);
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
-
- // Make new properties array if necessary.
- FixedArray* new_properties = NULL;
- int new_unused_property_fields = map()->unused_property_fields() - 1;
- if (map()->unused_property_fields() == 0) {
- new_unused_property_fields = kFieldsAdded - 1;
- MaybeObject* maybe_new_properties =
- properties()->CopySize(properties()->length() + kFieldsAdded);
- if (!maybe_new_properties->To(&new_properties)) return maybe_new_properties;
- }
-
- Heap* heap = GetHeap();
- Object* storage;
- MaybeObject* maybe_storage =
- new_value->AllocateNewStorageFor(heap, representation);
- if (!maybe_storage->To(&storage)) return maybe_storage;
-
- // Update pointers to commit changes.
- // Object points to the new map.
- new_map->set_unused_property_fields(new_unused_property_fields);
- set_map(new_map);
- if (new_properties != NULL) {
- set_properties(new_properties);
- }
- FastPropertyAtPut(index, new_value);
- return new_value;
-}
-
-
const char* Representation::Mnemonic() const {
switch (kind_) {
case kNone: return "v";
@@ -2267,9 +2188,9 @@ static void ZapEndOfFixedArray(Address new_end, int to_trim) {
template<RightTrimMode trim_mode>
static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) {
- ASSERT(elms->map() != HEAP->fixed_cow_array_map());
+ ASSERT(elms->map() != heap->fixed_cow_array_map());
// For now this trick is only applied to fixed arrays in new and paged space.
- ASSERT(!HEAP->lo_space()->Contains(elms));
+ ASSERT(!heap->lo_space()->Contains(elms));
const int len = elms->length();
@@ -2382,6 +2303,10 @@ MaybeObject* JSObject::MigrateToMap(Map* new_map) {
PropertyDetails details = new_descriptors->GetDetails(i);
if (details.type() != FIELD) continue;
PropertyDetails old_details = old_descriptors->GetDetails(i);
+ if (old_details.type() == CALLBACKS) {
+ ASSERT(details.representation().IsTagged());
+ continue;
+ }
ASSERT(old_details.type() == CONSTANT ||
old_details.type() == FIELD);
Object* value = old_details.type() == CONSTANT
@@ -2438,10 +2363,11 @@ MaybeObject* JSObject::MigrateToMap(Map* new_map) {
MaybeObject* JSObject::GeneralizeFieldRepresentation(
int modify_index,
- Representation new_representation) {
+ Representation new_representation,
+ StoreMode store_mode) {
Map* new_map;
- MaybeObject* maybe_new_map =
- map()->GeneralizeRepresentation(modify_index, new_representation);
+ MaybeObject* maybe_new_map = map()->GeneralizeRepresentation(
+ modify_index, new_representation, store_mode);
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
if (map() == new_map) return this;
@@ -2459,16 +2385,40 @@ int Map::NumberOfFields() {
}
-MaybeObject* Map::CopyGeneralizeAllRepresentations() {
+MaybeObject* Map::CopyGeneralizeAllRepresentations(
+ int modify_index,
+ StoreMode store_mode,
+ PropertyAttributes attributes,
+ const char* reason) {
Map* new_map;
MaybeObject* maybe_map = this->Copy();
if (!maybe_map->To(&new_map)) return maybe_map;
- new_map->instance_descriptors()->InitializeRepresentations(
- Representation::Tagged());
+ DescriptorArray* descriptors = new_map->instance_descriptors();
+ descriptors->InitializeRepresentations(Representation::Tagged());
+
+ // Unless the instance is being migrated, ensure that modify_index is a field.
+ PropertyDetails details = descriptors->GetDetails(modify_index);
+ if (store_mode == FORCE_FIELD && details.type() != FIELD) {
+ FieldDescriptor d(descriptors->GetKey(modify_index),
+ new_map->NumberOfFields(),
+ attributes,
+ Representation::Tagged());
+ d.SetSortedKeyIndex(details.pointer());
+ descriptors->Set(modify_index, &d);
+ int unused_property_fields = new_map->unused_property_fields() - 1;
+ if (unused_property_fields < 0) {
+ unused_property_fields += JSObject::kFieldsAdded;
+ }
+ new_map->set_unused_property_fields(unused_property_fields);
+ }
+
if (FLAG_trace_generalization) {
- PrintF("failed generalization %p -> %p\n",
- static_cast<void*>(this), static_cast<void*>(new_map));
+ PrintGeneralization(stdout, reason, modify_index,
+ new_map->NumberOfOwnDescriptors(),
+ new_map->NumberOfOwnDescriptors(),
+ details.type() == CONSTANT && store_mode == FORCE_FIELD,
+ Representation::Tagged(), Representation::Tagged());
}
return new_map;
}
@@ -2613,11 +2563,12 @@ Map* Map::FindLastMatchMap(int verbatim,
// - Otherwise, invalidate the outdated transition target from |updated|, and
// replace its transition tree with a new branch for the updated descriptors.
MaybeObject* Map::GeneralizeRepresentation(int modify_index,
- Representation new_representation) {
+ Representation new_representation,
+ StoreMode store_mode) {
Map* old_map = this;
DescriptorArray* old_descriptors = old_map->instance_descriptors();
- Representation old_representation =
- old_descriptors->GetDetails(modify_index).representation();
+ PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
+ Representation old_representation = old_details.representation();
// It's fine to transition from None to anything but double without any
// modification to the object, because the default uninitialized value for
@@ -2626,12 +2577,6 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index,
if (old_representation.IsNone() &&
!new_representation.IsNone() &&
!new_representation.IsDouble()) {
- if (FLAG_trace_generalization) {
- PrintF("initializing representation %i: %p -> %s\n",
- modify_index,
- static_cast<void*>(this),
- new_representation.Mnemonic());
- }
old_descriptors->SetRepresentation(modify_index, new_representation);
return old_map;
}
@@ -2641,40 +2586,46 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index,
// Check the state of the root map.
if (!old_map->EquivalentToForTransition(root_map)) {
- return CopyGeneralizeAllRepresentations();
+ return CopyGeneralizeAllRepresentations(
+ modify_index, store_mode, old_details.attributes(), "not equivalent");
}
int verbatim = root_map->NumberOfOwnDescriptors();
+ if (store_mode != ALLOW_AS_CONSTANT && modify_index < verbatim) {
+ return CopyGeneralizeAllRepresentations(
+ modify_index, store_mode,
+ old_details.attributes(), "root modification");
+ }
+
Map* updated = root_map->FindUpdatedMap(
verbatim, descriptors, old_descriptors);
- if (updated == NULL) return CopyGeneralizeAllRepresentations();
+ if (updated == NULL) {
+ return CopyGeneralizeAllRepresentations(
+ modify_index, store_mode, old_details.attributes(), "incompatible");
+ }
DescriptorArray* updated_descriptors = updated->instance_descriptors();
int valid = updated->NumberOfOwnDescriptors();
+
+ // Directly change the map if the target map is more general. Ensure that the
+ // target type of the modify_index is a FIELD, unless we are migrating.
if (updated_descriptors->IsMoreGeneralThan(
- verbatim, valid, descriptors, old_descriptors)) {
+ verbatim, valid, descriptors, old_descriptors) &&
+ (store_mode == ALLOW_AS_CONSTANT ||
+ updated_descriptors->GetDetails(modify_index).type() == FIELD)) {
Representation updated_representation =
updated_descriptors->GetDetails(modify_index).representation();
- if (new_representation.fits_into(updated_representation)) {
- if (FLAG_trace_generalization &&
- !(modify_index == 0 && new_representation.IsNone())) {
- PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
- PrintF("migrating to existing map %p(%s) -> %p(%s)\n",
- static_cast<void*>(this),
- old_details.representation().Mnemonic(),
- static_cast<void*>(updated),
- updated_representation.Mnemonic());
- }
- return updated;
- }
+ if (new_representation.fits_into(updated_representation)) return updated;
}
DescriptorArray* new_descriptors;
MaybeObject* maybe_descriptors = updated_descriptors->Merge(
- verbatim, valid, descriptors, old_descriptors);
+ verbatim, valid, descriptors, modify_index, store_mode, old_descriptors);
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
+ ASSERT(store_mode == ALLOW_AS_CONSTANT ||
+ new_descriptors->GetDetails(modify_index).type() == FIELD);
old_representation =
new_descriptors->GetDetails(modify_index).representation();
@@ -2696,15 +2647,12 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index,
split_map->DeprecateTarget(
old_descriptors->GetKey(descriptor), new_descriptors);
- if (FLAG_trace_generalization &&
- !(modify_index == 0 && new_representation.IsNone())) {
- PrintF("migrating to new map %i: %p(%s) -> %p(%s) (%i steps)\n",
- modify_index,
- static_cast<void*>(this),
- old_representation.Mnemonic(),
- static_cast<void*>(new_descriptors),
- updated_representation.Mnemonic(),
- descriptors - descriptor);
+ if (FLAG_trace_generalization) {
+ PrintGeneralization(
+ stdout, "", modify_index, descriptor, descriptors,
+ old_descriptors->GetDetails(modify_index).type() == CONSTANT &&
+ store_mode == FORCE_FIELD,
+ old_representation, updated_representation);
}
Map* new_map = split_map;
@@ -2771,8 +2719,8 @@ MaybeObject* JSObject::SetPropertyWithInterceptor(
if (!interceptor->setter()->IsUndefined()) {
LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
PropertyCallbackArguments args(isolate, interceptor->data(), this, this);
- v8::NamedPropertySetter setter =
- v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
+ v8::NamedPropertySetterCallback setter =
+ v8::ToCData<v8::NamedPropertySetterCallback>(interceptor->setter());
Handle<Object> value_unhole(value->IsTheHole() ?
isolate->heap()->undefined_value() :
value,
@@ -2787,8 +2735,7 @@ MaybeObject* JSObject::SetPropertyWithInterceptor(
this_handle->SetPropertyPostInterceptor(*name_handle,
*value_handle,
attributes,
- strict_mode,
- PERFORM_EXTENSIBILITY_CHECK);
+ strict_mode);
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return raw_result;
}
@@ -2852,7 +2799,8 @@ MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
AccessorDescriptor* callback =
reinterpret_cast<AccessorDescriptor*>(
Foreign::cast(structure)->foreign_address());
- MaybeObject* obj = (callback->setter)(this, value, callback->data);
+ MaybeObject* obj = (callback->setter)(
+ isolate, this, value, callback->data);
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (obj->IsFailure()) return obj;
return *value_handle;
@@ -2874,7 +2822,8 @@ MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
// TODO(rossberg): Support symbols in the API.
if (name->IsSymbol()) return value;
Object* call_obj = data->setter();
- v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
+ v8::AccessorSetterCallback call_fun =
+ v8::ToCData<v8::AccessorSetterCallback>(call_obj);
if (call_fun == NULL) return value;
Handle<String> key(String::cast(name));
LOG(isolate, ApiNamedPropertyAccess("store", this, name));
@@ -2932,7 +2881,8 @@ MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter,
#endif
bool has_pending_exception;
Handle<Object> argv[] = { value_handle };
- Execution::Call(fun, self, ARRAY_SIZE(argv), argv, &has_pending_exception);
+ Execution::Call(
+ isolate, fun, self, ARRAY_SIZE(argv), argv, &has_pending_exception);
// Check for pending exception and return the result.
if (has_pending_exception) return Failure::Exception();
return *value_handle;
@@ -3056,48 +3006,101 @@ void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
}
-void Map::AppendCallbackDescriptors(Handle<Map> map,
- Handle<Object> descriptors) {
- Isolate* isolate = map->GetIsolate();
- Handle<DescriptorArray> array(map->instance_descriptors());
- NeanderArray callbacks(descriptors);
- int nof_callbacks = callbacks.length();
-
- ASSERT(array->NumberOfSlackDescriptors() >= nof_callbacks);
+template<class T>
+static int AppendUniqueCallbacks(NeanderArray* callbacks,
+ Handle<typename T::Array> array,
+ int valid_descriptors) {
+ int nof_callbacks = callbacks->length();
+ Isolate* isolate = array->GetIsolate();
// Ensure the keys are unique names before writing them into the
// instance descriptor. Since it may cause a GC, it has to be done before we
// temporarily put the heap in an invalid state while appending descriptors.
for (int i = 0; i < nof_callbacks; ++i) {
- Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks.get(i)));
- if (!entry->name()->IsUniqueName()) {
- Handle<String> key =
- isolate->factory()->InternalizedStringFromString(
- Handle<String>(String::cast(entry->name())));
- entry->set_name(*key);
- }
+ Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
+ if (entry->name()->IsUniqueName()) continue;
+ Handle<String> key =
+ isolate->factory()->InternalizedStringFromString(
+ Handle<String>(String::cast(entry->name())));
+ entry->set_name(*key);
}
- int nof = map->NumberOfOwnDescriptors();
-
// Fill in new callback descriptors. Process the callbacks from
// back to front so that the last callback with a given name takes
// precedence over previously added callbacks with that name.
for (int i = nof_callbacks - 1; i >= 0; i--) {
- AccessorInfo* entry = AccessorInfo::cast(callbacks.get(i));
+ AccessorInfo* entry = AccessorInfo::cast(callbacks->get(i));
Name* key = Name::cast(entry->name());
// Check if a descriptor with this name already exists before writing.
- if (array->Search(key, nof) == DescriptorArray::kNotFound) {
- CallbacksDescriptor desc(key, entry, entry->property_attributes());
- array->Append(&desc);
- nof += 1;
+ if (!T::Contains(key, entry, valid_descriptors, array)) {
+ T::Insert(key, entry, valid_descriptors, array);
+ valid_descriptors++;
}
}
+ return valid_descriptors;
+}
+
+struct DescriptorArrayAppender {
+ typedef DescriptorArray Array;
+ static bool Contains(Name* key,
+ AccessorInfo* entry,
+ int valid_descriptors,
+ Handle<DescriptorArray> array) {
+ return array->Search(key, valid_descriptors) != DescriptorArray::kNotFound;
+ }
+ static void Insert(Name* key,
+ AccessorInfo* entry,
+ int valid_descriptors,
+ Handle<DescriptorArray> array) {
+ CallbacksDescriptor desc(key, entry, entry->property_attributes());
+ array->Append(&desc);
+ }
+};
+
+
+struct FixedArrayAppender {
+ typedef FixedArray Array;
+ static bool Contains(Name* key,
+ AccessorInfo* entry,
+ int valid_descriptors,
+ Handle<FixedArray> array) {
+ for (int i = 0; i < valid_descriptors; i++) {
+ if (key == AccessorInfo::cast(array->get(i))->name()) return true;
+ }
+ return false;
+ }
+ static void Insert(Name* key,
+ AccessorInfo* entry,
+ int valid_descriptors,
+ Handle<FixedArray> array) {
+ array->set(valid_descriptors, entry);
+ }
+};
+
+
+void Map::AppendCallbackDescriptors(Handle<Map> map,
+ Handle<Object> descriptors) {
+ int nof = map->NumberOfOwnDescriptors();
+ Handle<DescriptorArray> array(map->instance_descriptors());
+ NeanderArray callbacks(descriptors);
+ ASSERT(array->NumberOfSlackDescriptors() >= callbacks.length());
+ nof = AppendUniqueCallbacks<DescriptorArrayAppender>(&callbacks, array, nof);
map->SetNumberOfOwnDescriptors(nof);
}
+int AccessorInfo::AppendUnique(Handle<Object> descriptors,
+ Handle<FixedArray> array,
+ int valid_descriptors) {
+ NeanderArray callbacks(descriptors);
+ ASSERT(array->length() >= callbacks.length() + valid_descriptors);
+ return AppendUniqueCallbacks<FixedArrayAppender>(&callbacks,
+ array,
+ valid_descriptors);
+}
+
+
static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
ASSERT(!map.is_null());
for (int i = 0; i < maps->length(); ++i) {
@@ -3361,6 +3364,15 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
result->holder(),
strict_mode);
}
+ } else if (obj->IsAccessorPair()) {
+ AccessorPair* pair = AccessorPair::cast(obj);
+ if (pair->all_can_read()) {
+ return SetPropertyWithCallback(result->GetCallbackObject(),
+ name,
+ value,
+ result->holder(),
+ strict_mode);
+ }
}
break;
}
@@ -3485,9 +3497,9 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyViaPrototypesWithHandler(
// Emulate [[GetProperty]] semantics for proxies.
bool has_pending_exception;
Handle<Object> argv[] = { result };
- Handle<Object> desc =
- Execution::Call(isolate->to_complete_property_descriptor(), result,
- ARRAY_SIZE(argv), argv, &has_pending_exception);
+ Handle<Object> desc = Execution::Call(
+ isolate, isolate->to_complete_property_descriptor(), result,
+ ARRAY_SIZE(argv), argv, &has_pending_exception);
if (has_pending_exception) return Failure::Exception();
// [[GetProperty]] requires to check that all properties are configurable.
@@ -3554,20 +3566,20 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyViaPrototypesWithHandler(
Handle<Object> JSProxy::DeletePropertyWithHandler(
- Handle<JSProxy> object, Handle<Name> name, DeleteMode mode) {
- Isolate* isolate = object->GetIsolate();
+ Handle<JSProxy> proxy, Handle<Name> name, DeleteMode mode) {
+ Isolate* isolate = proxy->GetIsolate();
// TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (name->IsSymbol()) return isolate->factory()->false_value();
Handle<Object> args[] = { name };
- Handle<Object> result = object->CallTrap(
+ Handle<Object> result = proxy->CallTrap(
"delete", Handle<Object>(), ARRAY_SIZE(args), args);
if (isolate->has_pending_exception()) return Handle<Object>();
bool result_bool = result->BooleanValue();
if (mode == STRICT_DELETION && !result_bool) {
- Handle<Object> handler(object->handler(), isolate);
+ Handle<Object> handler(proxy->handler(), isolate);
Handle<String> trap_name = isolate->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("delete"));
Handle<Object> args[] = { handler, trap_name };
@@ -3581,10 +3593,10 @@ Handle<Object> JSProxy::DeletePropertyWithHandler(
Handle<Object> JSProxy::DeleteElementWithHandler(
- Handle<JSProxy> object, uint32_t index, DeleteMode mode) {
- Isolate* isolate = object->GetIsolate();
+ Handle<JSProxy> proxy, uint32_t index, DeleteMode mode) {
+ Isolate* isolate = proxy->GetIsolate();
Handle<String> name = isolate->factory()->Uint32ToString(index);
- return JSProxy::DeletePropertyWithHandler(object, name, mode);
+ return JSProxy::DeletePropertyWithHandler(proxy, name, mode);
}
@@ -3610,9 +3622,9 @@ MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
bool has_pending_exception;
Handle<Object> argv[] = { result };
- Handle<Object> desc =
- Execution::Call(isolate->to_complete_property_descriptor(), result,
- ARRAY_SIZE(argv), argv, &has_pending_exception);
+ Handle<Object> desc = Execution::Call(
+ isolate, isolate->to_complete_property_descriptor(), result,
+ ARRAY_SIZE(argv), argv, &has_pending_exception);
if (has_pending_exception) return NONE;
// Convert result to PropertyAttributes.
@@ -3666,27 +3678,23 @@ MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler(
}
-void JSProxy::Fix() {
- Isolate* isolate = GetIsolate();
- HandleScope scope(isolate);
- Handle<JSProxy> self(this);
+void JSProxy::Fix(Handle<JSProxy> proxy) {
+ Isolate* isolate = proxy->GetIsolate();
// Save identity hash.
- MaybeObject* maybe_hash = GetIdentityHash(OMIT_CREATION);
+ Handle<Object> hash = JSProxy::GetIdentityHash(proxy, OMIT_CREATION);
- if (IsJSFunctionProxy()) {
- isolate->factory()->BecomeJSFunction(self);
+ if (proxy->IsJSFunctionProxy()) {
+ isolate->factory()->BecomeJSFunction(proxy);
// Code will be set on the JavaScript side.
} else {
- isolate->factory()->BecomeJSObject(self);
+ isolate->factory()->BecomeJSObject(proxy);
}
- ASSERT(self->IsJSObject());
+ ASSERT(proxy->IsJSObject());
// Inherit identity, if it was present.
- Object* hash;
- if (maybe_hash->To<Object>(&hash) && hash->IsSmi()) {
- Handle<JSObject> new_self(JSObject::cast(*self));
- isolate->factory()->SetIdentityHash(new_self, Smi::cast(hash));
+ if (hash->IsSmi()) {
+ JSObject::SetIdentityHash(Handle<JSObject>::cast(proxy), Smi::cast(*hash));
}
}
@@ -3714,7 +3722,7 @@ MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name,
}
bool threw;
- return Execution::Call(trap, handler, argc, argv, &threw);
+ return Execution::Call(isolate, trap, handler, argc, argv, &threw);
}
@@ -3726,11 +3734,6 @@ void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
void JSObject::MigrateInstance(Handle<JSObject> object) {
- if (FLAG_trace_migration) {
- PrintF("migrating instance %p (%p)\n",
- static_cast<void*>(*object),
- static_cast<void*>(object->map()));
- }
CALL_HEAP_FUNCTION_VOID(
object->GetIsolate(),
object->MigrateInstance());
@@ -3738,11 +3741,6 @@ void JSObject::MigrateInstance(Handle<JSObject> object) {
Handle<Object> JSObject::TryMigrateInstance(Handle<JSObject> object) {
- if (FLAG_trace_migration) {
- PrintF("migrating instance (no new maps) %p (%p)\n",
- static_cast<void*>(*object),
- static_cast<void*>(object->map()));
- }
CALL_HEAP_FUNCTION(
object->GetIsolate(),
object->MigrateInstance(),
@@ -3752,14 +3750,148 @@ Handle<Object> JSObject::TryMigrateInstance(Handle<JSObject> object) {
Handle<Map> Map::GeneralizeRepresentation(Handle<Map> map,
int modify_index,
- Representation representation) {
+ Representation representation,
+ StoreMode store_mode) {
CALL_HEAP_FUNCTION(
map->GetIsolate(),
- map->GeneralizeRepresentation(modify_index, representation),
+ map->GeneralizeRepresentation(modify_index, representation, store_mode),
Map);
}
+static MaybeObject* SetPropertyUsingTransition(LookupResult* lookup,
+ Handle<Name> name,
+ Handle<Object> value,
+ PropertyAttributes attributes) {
+ Map* transition_map = lookup->GetTransitionTarget();
+ int descriptor = transition_map->LastAdded();
+
+ DescriptorArray* descriptors = transition_map->instance_descriptors();
+ PropertyDetails details = descriptors->GetDetails(descriptor);
+
+ if (details.type() == CALLBACKS || attributes != details.attributes()) {
+ // AddProperty will either normalize the object, or create a new fast copy
+ // of the map. If we get a fast copy of the map, all field representations
+ // will be tagged since the transition is omitted.
+ return lookup->holder()->AddProperty(
+ *name, *value, attributes, kNonStrictMode,
+ JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED,
+ JSReceiver::OMIT_EXTENSIBILITY_CHECK,
+ JSObject::FORCE_TAGGED, FORCE_FIELD, OMIT_TRANSITION);
+ }
+
+ // Keep the target CONSTANT if the same value is stored.
+ // TODO(verwaest): Also support keeping the placeholder
+ // (value->IsUninitialized) as constant.
+ if (details.type() == CONSTANT &&
+ descriptors->GetValue(descriptor) == *value) {
+ lookup->holder()->set_map(transition_map);
+ return *value;
+ }
+
+ Representation representation = details.representation();
+
+ if (!value->FitsRepresentation(representation) ||
+ details.type() == CONSTANT) {
+ MaybeObject* maybe_map = transition_map->GeneralizeRepresentation(
+ descriptor, value->OptimalRepresentation(), FORCE_FIELD);
+ if (!maybe_map->To(&transition_map)) return maybe_map;
+ Object* back = transition_map->GetBackPointer();
+ if (back->IsMap()) {
+ MaybeObject* maybe_failure =
+ lookup->holder()->MigrateToMap(Map::cast(back));
+ if (maybe_failure->IsFailure()) return maybe_failure;
+ }
+ descriptors = transition_map->instance_descriptors();
+ representation = descriptors->GetDetails(descriptor).representation();
+ }
+
+ int field_index = descriptors->GetFieldIndex(descriptor);
+ return lookup->holder()->AddFastPropertyUsingMap(
+ transition_map, *name, *value, field_index, representation);
+}
+
+
+static MaybeObject* SetPropertyToField(LookupResult* lookup,
+ Handle<Name> name,
+ Handle<Object> value) {
+ Representation representation = lookup->representation();
+ if (!value->FitsRepresentation(representation) ||
+ lookup->type() == CONSTANT) {
+ MaybeObject* maybe_failure =
+ lookup->holder()->GeneralizeFieldRepresentation(
+ lookup->GetDescriptorIndex(),
+ value->OptimalRepresentation(),
+ FORCE_FIELD);
+ if (maybe_failure->IsFailure()) return maybe_failure;
+ DescriptorArray* desc = lookup->holder()->map()->instance_descriptors();
+ int descriptor = lookup->GetDescriptorIndex();
+ representation = desc->GetDetails(descriptor).representation();
+ }
+
+ if (FLAG_track_double_fields && representation.IsDouble()) {
+ HeapNumber* storage = HeapNumber::cast(lookup->holder()->RawFastPropertyAt(
+ lookup->GetFieldIndex().field_index()));
+ storage->set_value(value->Number());
+ return *value;
+ }
+
+ lookup->holder()->FastPropertyAtPut(
+ lookup->GetFieldIndex().field_index(), *value);
+ return *value;
+}
+
+
+static MaybeObject* ConvertAndSetLocalProperty(LookupResult* lookup,
+ Name* name,
+ Object* value,
+ PropertyAttributes attributes) {
+ JSObject* object = lookup->holder();
+ if (object->TooManyFastProperties()) {
+ MaybeObject* maybe_failure = object->NormalizeProperties(
+ CLEAR_INOBJECT_PROPERTIES, 0);
+ if (maybe_failure->IsFailure()) return maybe_failure;
+ }
+
+ if (!object->HasFastProperties()) {
+ return object->ReplaceSlowProperty(name, value, attributes);
+ }
+
+ int descriptor_index = lookup->GetDescriptorIndex();
+ if (lookup->GetAttributes() == attributes) {
+ MaybeObject* maybe_failure = object->GeneralizeFieldRepresentation(
+ descriptor_index, Representation::Tagged(), FORCE_FIELD);
+ if (maybe_failure->IsFailure()) return maybe_failure;
+ } else {
+ Map* map;
+ MaybeObject* maybe_map = object->map()->CopyGeneralizeAllRepresentations(
+ descriptor_index, FORCE_FIELD, attributes, "attributes mismatch");
+ if (!maybe_map->To(&map)) return maybe_map;
+ MaybeObject* maybe_failure = object->MigrateToMap(map);
+ if (maybe_failure->IsFailure()) return maybe_failure;
+ }
+
+ DescriptorArray* descriptors = object->map()->instance_descriptors();
+ int index = descriptors->GetDetails(descriptor_index).field_index();
+ object->FastPropertyAtPut(index, value);
+ return value;
+}
+
+
+static MaybeObject* SetPropertyToFieldWithAttributes(
+ LookupResult* lookup,
+ Handle<Name> name,
+ Handle<Object> value,
+ PropertyAttributes attributes) {
+ if (lookup->GetAttributes() == attributes) {
+ if (value->IsUninitialized()) return *value;
+ return SetPropertyToField(lookup, name, value);
+ } else {
+ return ConvertAndSetLocalProperty(lookup, *name, *value, attributes);
+ }
+}
+
+
MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup,
Name* name_raw,
Object* value_raw,
@@ -3768,9 +3900,10 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup,
StoreFromKeyed store_mode) {
Heap* heap = GetHeap();
Isolate* isolate = heap->isolate();
+
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
- AssertNoContextChange ncc;
+ AssertNoContextChangeWithHandleScope ncc;
// Optimization for 2-byte strings often used as keys in a decompression
// dictionary. We internalize these short keys to avoid constantly
@@ -3848,37 +3981,13 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup,
case NORMAL:
result = lookup->holder()->SetNormalizedProperty(lookup, *value);
break;
- case FIELD: {
- Representation representation = lookup->representation();
- if (!value->FitsRepresentation(representation)) {
- MaybeObject* maybe_failure =
- lookup->holder()->GeneralizeFieldRepresentation(
- lookup->GetDescriptorIndex(), value->OptimalRepresentation());
- if (maybe_failure->IsFailure()) return maybe_failure;
- DescriptorArray* desc = lookup->holder()->map()->instance_descriptors();
- int descriptor = lookup->GetDescriptorIndex();
- representation = desc->GetDetails(descriptor).representation();
- }
- if (FLAG_track_double_fields && representation.IsDouble()) {
- HeapNumber* storage =
- HeapNumber::cast(lookup->holder()->RawFastPropertyAt(
- lookup->GetFieldIndex().field_index()));
- storage->set_value(value->Number());
- result = *value;
- break;
- }
- lookup->holder()->FastPropertyAtPut(
- lookup->GetFieldIndex().field_index(), *value);
- result = *value;
+ case FIELD:
+ result = SetPropertyToField(lookup, name, value);
break;
- }
case CONSTANT:
// Only replace the constant if necessary.
if (*value == lookup->GetConstant()) return *value;
- // Preserve the attributes of this existing property.
- attributes = lookup->GetAttributes();
- result = lookup->holder()->ConvertDescriptorToField(
- *name, *value, attributes);
+ result = SetPropertyToField(lookup, name, value);
break;
case CALLBACKS: {
Object* callback_object = lookup->GetCallbackObject();
@@ -3890,55 +3999,7 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup,
*name, *value, attributes, strict_mode);
break;
case TRANSITION: {
- Map* transition_map = lookup->GetTransitionTarget();
- int descriptor = transition_map->LastAdded();
-
- DescriptorArray* descriptors = transition_map->instance_descriptors();
- PropertyDetails details = descriptors->GetDetails(descriptor);
-
- if (details.type() == FIELD) {
- if (attributes == details.attributes()) {
- Representation representation = details.representation();
- if (!value->FitsRepresentation(representation)) {
- MaybeObject* maybe_map = transition_map->GeneralizeRepresentation(
- descriptor, value->OptimalRepresentation());
- if (!maybe_map->To(&transition_map)) return maybe_map;
- Object* back = transition_map->GetBackPointer();
- if (back->IsMap()) {
- MaybeObject* maybe_failure =
- lookup->holder()->MigrateToMap(Map::cast(back));
- if (maybe_failure->IsFailure()) return maybe_failure;
- }
- descriptors = transition_map->instance_descriptors();
- representation =
- descriptors->GetDetails(descriptor).representation();
- }
- int field_index = descriptors->GetFieldIndex(descriptor);
- result = lookup->holder()->AddFastPropertyUsingMap(
- transition_map, *name, *value, field_index, representation);
- } else {
- result = lookup->holder()->ConvertDescriptorToField(
- *name, *value, attributes);
- }
- } else if (details.type() == CALLBACKS) {
- result = lookup->holder()->ConvertDescriptorToField(
- *name, *value, attributes);
- } else {
- ASSERT(details.type() == CONSTANT);
-
- Object* constant = descriptors->GetValue(descriptor);
- if (constant == *value) {
- // If the same constant function is being added we can simply
- // transition to the target map.
- lookup->holder()->set_map(transition_map);
- result = constant;
- } else {
- // Otherwise, replace with a map transition to a new map with a FIELD,
- // even if the value is a constant function.
- result = lookup->holder()->ConvertTransitionToMapTransition(
- lookup->GetTransitionIndex(), *name, *value, attributes);
- }
- }
+ result = SetPropertyUsingTransition(lookup, name, value, attributes);
break;
}
case HANDLER:
@@ -3968,6 +4029,29 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup,
}
+MaybeObject* JSObject::SetLocalPropertyIgnoreAttributesTrampoline(
+ Name* key,
+ Object* value,
+ PropertyAttributes attributes,
+ ValueType value_type,
+ StoreMode mode,
+ ExtensibilityCheck extensibility_check) {
+ // TODO(mstarzinger): The trampoline is a giant hack, don't use it anywhere
+ // else or handlification people will start hating you for all eternity.
+ HandleScope scope(GetIsolate());
+ IdempotentPointerToHandleCodeTrampoline trampoline(GetIsolate());
+ return trampoline.CallWithReturnValue(
+ &JSObject::SetLocalPropertyIgnoreAttributes,
+ Handle<JSObject>(this),
+ Handle<Name>(key),
+ Handle<Object>(value, GetIsolate()),
+ attributes,
+ value_type,
+ mode,
+ extensibility_check);
+}
+
+
// Set a real local property, even if it is READ_ONLY. If the property is not
// present, add it with attributes NONE. This code is an exact clone of
// SetProperty, with the check for IsReadOnly and the check for a
@@ -3983,11 +4067,12 @@ Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
Handle<Object> value,
PropertyAttributes attributes,
ValueType value_type,
- StoreMode mode) {
+ StoreMode mode,
+ ExtensibilityCheck extensibility_check) {
CALL_HEAP_FUNCTION(
object->GetIsolate(),
object->SetLocalPropertyIgnoreAttributes(
- *key, *value, attributes, value_type, mode),
+ *key, *value, attributes, value_type, mode, extensibility_check),
Object);
}
@@ -3997,10 +4082,11 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
Object* value_raw,
PropertyAttributes attributes,
ValueType value_type,
- StoreMode mode) {
+ StoreMode mode,
+ ExtensibilityCheck extensibility_check) {
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
- AssertNoContextChange ncc;
+ AssertNoContextChangeWithHandleScope ncc;
Isolate* isolate = GetIsolate();
LookupResult lookup(isolate);
LocalLookup(name_raw, &lookup, true);
@@ -4025,7 +4111,13 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
value_raw,
attributes,
value_type,
- mode);
+ mode,
+ extensibility_check);
+ }
+
+ if (lookup.IsFound() &&
+ (lookup.type() == INTERCEPTOR || lookup.type() == CALLBACKS)) {
+ LocalLookupRealNamedProperty(name_raw, &lookup);
}
// Check for accessor in prototype chain removed here in clone.
@@ -4033,7 +4125,7 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
// Neither properties nor transitions found.
return AddProperty(
name_raw, value_raw, attributes, kNonStrictMode,
- MAY_BE_STORE_FROM_KEYED, PERFORM_EXTENSIBILITY_CHECK, value_type, mode);
+ MAY_BE_STORE_FROM_KEYED, extensibility_check, value_type, mode);
}
// From this point on everything needs to be handlified.
@@ -4046,101 +4138,38 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
PropertyAttributes old_attributes = ABSENT;
bool is_observed = FLAG_harmony_observation && self->map()->is_observed();
if (is_observed && lookup.IsProperty()) {
- if (lookup.IsDataProperty()) old_value = Object::GetProperty(self, name);
+ if (lookup.IsDataProperty()) old_value =
+ Object::GetProperty(self, name);
old_attributes = lookup.GetAttributes();
}
// Check of IsReadOnly removed from here in clone.
MaybeObject* result = *value;
switch (lookup.type()) {
- case NORMAL: {
- PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
- result = self->SetNormalizedProperty(*name, *value, details);
+ case NORMAL:
+ result = self->ReplaceSlowProperty(*name, *value, attributes);
break;
- }
- case FIELD: {
- Representation representation = lookup.representation();
- Representation value_representation =
- value->OptimalRepresentation(value_type);
- if (value_representation.IsNone()) break;
- if (!value_representation.fits_into(representation)) {
- MaybeObject* maybe_failure = self->GeneralizeFieldRepresentation(
- lookup.GetDescriptorIndex(), value_representation);
- if (maybe_failure->IsFailure()) return maybe_failure;
- DescriptorArray* desc = self->map()->instance_descriptors();
- int descriptor = lookup.GetDescriptorIndex();
- representation = desc->GetDetails(descriptor).representation();
- }
- if (FLAG_track_double_fields && representation.IsDouble()) {
- HeapNumber* storage =
- HeapNumber::cast(self->RawFastPropertyAt(
- lookup.GetFieldIndex().field_index()));
- storage->set_value(value->Number());
- result = *value;
- break;
- }
- self->FastPropertyAtPut(lookup.GetFieldIndex().field_index(), *value);
- result = *value;
+ case FIELD:
+ result = SetPropertyToFieldWithAttributes(
+ &lookup, name, value, attributes);
break;
- }
case CONSTANT:
- // Only replace the function if necessary.
- if (*value != lookup.GetConstant()) {
- // Preserve the attributes of this existing property.
- attributes = lookup.GetAttributes();
- result = self->ConvertDescriptorToField(*name, *value, attributes);
+ // Only replace the constant if necessary.
+ if (lookup.GetAttributes() != attributes ||
+ *value != lookup.GetConstant()) {
+ result = SetPropertyToFieldWithAttributes(
+ &lookup, name, value, attributes);
}
break;
case CALLBACKS:
- case INTERCEPTOR:
- // Override callback in clone
- result = self->ConvertDescriptorToField(*name, *value, attributes);
+ result = ConvertAndSetLocalProperty(&lookup, *name, *value, attributes);
break;
- case TRANSITION: {
- Map* transition_map = lookup.GetTransitionTarget();
- int descriptor = transition_map->LastAdded();
-
- DescriptorArray* descriptors = transition_map->instance_descriptors();
- PropertyDetails details = descriptors->GetDetails(descriptor);
-
- if (details.type() == FIELD) {
- if (attributes == details.attributes()) {
- Representation representation = details.representation();
- Representation value_representation =
- value->OptimalRepresentation(value_type);
- if (!value_representation.fits_into(representation)) {
- MaybeObject* maybe_map = transition_map->GeneralizeRepresentation(
- descriptor, value_representation);
- if (!maybe_map->To(&transition_map)) return maybe_map;
- Object* back = transition_map->GetBackPointer();
- if (back->IsMap()) {
- MaybeObject* maybe_failure = self->MigrateToMap(Map::cast(back));
- if (maybe_failure->IsFailure()) return maybe_failure;
- }
- descriptors = transition_map->instance_descriptors();
- representation =
- descriptors->GetDetails(descriptor).representation();
- }
- int field_index = descriptors->GetFieldIndex(descriptor);
- result = self->AddFastPropertyUsingMap(
- transition_map, *name, *value, field_index, representation);
- } else {
- result = self->ConvertDescriptorToField(*name, *value, attributes);
- }
- } else if (details.type() == CALLBACKS) {
- result = self->ConvertDescriptorToField(*name, *value, attributes);
- } else {
- ASSERT(details.type() == CONSTANT);
-
- // Replace transition to CONSTANT FUNCTION with a map transition to a
- // new map with a FIELD, even if the value is a function.
- result = self->ConvertTransitionToMapTransition(
- lookup.GetTransitionIndex(), *name, *value, attributes);
- }
+ case TRANSITION:
+ result = SetPropertyUsingTransition(&lookup, name, value, attributes);
break;
- }
- case HANDLER:
case NONEXISTENT:
+ case HANDLER:
+ case INTERCEPTOR:
UNREACHABLE();
}
@@ -4202,20 +4231,20 @@ PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
if (name->IsSymbol()) return ABSENT;
Isolate* isolate = GetIsolate();
+ HandleScope scope(isolate);
// Make sure that the top context does not change when doing
// callbacks or interceptor calls.
AssertNoContextChange ncc;
- HandleScope scope(isolate);
Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
Handle<JSObject> receiver_handle(receiver);
Handle<JSObject> holder_handle(this);
Handle<String> name_handle(String::cast(name));
PropertyCallbackArguments args(isolate, interceptor->data(), receiver, this);
if (!interceptor->query()->IsUndefined()) {
- v8::NamedPropertyQuery query =
- v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
+ v8::NamedPropertyQueryCallback query =
+ v8::ToCData<v8::NamedPropertyQueryCallback>(interceptor->query());
LOG(isolate,
ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
v8::Handle<v8::Integer> result =
@@ -4225,8 +4254,8 @@ PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
return static_cast<PropertyAttributes>(result->Int32Value());
}
} else if (!interceptor->getter()->IsUndefined()) {
- v8::NamedPropertyGetter getter =
- v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
+ v8::NamedPropertyGetterCallback getter =
+ v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter());
LOG(isolate,
ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
v8::Handle<v8::Value> result =
@@ -4337,25 +4366,27 @@ PropertyAttributes JSObject::GetElementAttributeWithReceiver(
PropertyAttributes JSObject::GetElementAttributeWithInterceptor(
JSReceiver* receiver, uint32_t index, bool continue_search) {
Isolate* isolate = GetIsolate();
+ HandleScope scope(isolate);
+
// Make sure that the top context does not change when doing
// callbacks or interceptor calls.
AssertNoContextChange ncc;
- HandleScope scope(isolate);
+
Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Handle<JSReceiver> hreceiver(receiver);
Handle<JSObject> holder(this);
PropertyCallbackArguments args(isolate, interceptor->data(), receiver, this);
if (!interceptor->query()->IsUndefined()) {
- v8::IndexedPropertyQuery query =
- v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
+ v8::IndexedPropertyQueryCallback query =
+ v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
LOG(isolate,
ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
v8::Handle<v8::Integer> result = args.Call(query, index);
if (!result.IsEmpty())
return static_cast<PropertyAttributes>(result->Int32Value());
} else if (!interceptor->getter()->IsUndefined()) {
- v8::IndexedPropertyGetter getter =
- v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
+ v8::IndexedPropertyGetterCallback getter =
+ v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
LOG(isolate,
ApiIndexedPropertyAccess("interceptor-indexed-get-has", this, index));
v8::Handle<v8::Value> result = args.Call(getter, index);
@@ -4448,30 +4479,21 @@ void NormalizedMapCache::Clear() {
}
-void JSObject::UpdateMapCodeCache(Handle<JSObject> object,
- Handle<Name> name,
- Handle<Code> code) {
- Isolate* isolate = object->GetIsolate();
- CALL_HEAP_FUNCTION_VOID(isolate,
- object->UpdateMapCodeCache(*name, *code));
-}
-
-
-MaybeObject* JSObject::UpdateMapCodeCache(Name* name, Code* code) {
- if (map()->is_shared()) {
+void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
+ Handle<Name> name,
+ Handle<Code> code) {
+ Handle<Map> map(object->map());
+ if (map->is_shared()) {
+ Handle<JSObject> receiver = Handle<JSObject>::cast(object);
// Fast case maps are never marked as shared.
- ASSERT(!HasFastProperties());
+ ASSERT(!receiver->HasFastProperties());
// Replace the map with an identical copy that can be safely modified.
- Object* obj;
- { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
- UNIQUE_NORMALIZED_MAP);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
- GetIsolate()->counters()->normalized_maps()->Increment();
-
- set_map(Map::cast(obj));
+ map = Map::CopyNormalized(map, KEEP_INOBJECT_PROPERTIES,
+ UNIQUE_NORMALIZED_MAP);
+ receiver->GetIsolate()->counters()->normalized_maps()->Increment();
+ receiver->set_map(*map);
}
- return map()->UpdateCodeCache(name, code);
+ Map::UpdateCodeCache(map, name, code);
}
@@ -4722,7 +4744,7 @@ Smi* JSReceiver::GenerateIdentityHash() {
do {
// Generate a random 32-bit hash value but limit range to fit
// within a smi.
- hash_value = V8::RandomPrivate(isolate) & Smi::kMaxValue;
+ hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue;
attempts++;
} while (hash_value == 0 && attempts < 30);
hash_value = hash_value != 0 ? hash_value : 1; // never return 0
@@ -4731,17 +4753,16 @@ Smi* JSReceiver::GenerateIdentityHash() {
}
-MaybeObject* JSObject::SetIdentityHash(Smi* hash, CreationFlag flag) {
- MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_string(),
- hash);
- if (maybe->IsFailure()) return maybe;
- return this;
+void JSObject::SetIdentityHash(Handle<JSObject> object, Smi* hash) {
+ CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
+ object->SetHiddenProperty(
+ object->GetHeap()->identity_hash_string(), hash));
}
-int JSObject::GetIdentityHash(Handle<JSObject> obj) {
- CALL_AND_RETRY_OR_DIE(obj->GetIsolate(),
- obj->GetIdentityHash(ALLOW_CREATION),
+int JSObject::GetIdentityHash(Handle<JSObject> object) {
+ CALL_AND_RETRY_OR_DIE(object->GetIsolate(),
+ object->GetIdentityHash(ALLOW_CREATION),
return Smi::cast(__object__)->value(),
return 0);
}
@@ -4766,6 +4787,12 @@ MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
}
+Handle<Object> JSProxy::GetIdentityHash(Handle<JSProxy> proxy,
+ CreationFlag flag) {
+ CALL_HEAP_FUNCTION(proxy->GetIsolate(), proxy->GetIdentityHash(flag), Object);
+}
+
+
MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) {
Object* hash = this->hash();
if (!hash->IsSmi() && flag == ALLOW_CREATION) {
@@ -4858,30 +4885,27 @@ MaybeObject* JSObject::SetHiddenProperty(Name* key, Object* value) {
}
-void JSObject::DeleteHiddenProperty(Name* key) {
+void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) {
+ Isolate* isolate = object->GetIsolate();
ASSERT(key->IsUniqueName());
- if (IsJSGlobalProxy()) {
- // For a proxy, use the prototype as target object.
- Object* proxy_parent = GetPrototype();
- // If the proxy is detached, return immediately.
- if (proxy_parent->IsNull()) return;
- ASSERT(proxy_parent->IsJSGlobalObject());
- JSObject::cast(proxy_parent)->DeleteHiddenProperty(key);
- return;
+
+ if (object->IsJSGlobalProxy()) {
+ Handle<Object> proto(object->GetPrototype(), isolate);
+ if (proto->IsNull()) return;
+ ASSERT(proto->IsJSGlobalObject());
+ return DeleteHiddenProperty(Handle<JSObject>::cast(proto), key);
}
- ASSERT(!IsJSGlobalProxy());
+
MaybeObject* hidden_lookup =
- GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE);
+ object->GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE);
Object* inline_value = hidden_lookup->ToObjectUnchecked();
// We never delete (inline-stored) identity hashes.
- ASSERT(key != GetHeap()->identity_hash_string());
+ ASSERT(*key != isolate->heap()->identity_hash_string());
if (inline_value->IsUndefined() || inline_value->IsSmi()) return;
- ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value);
- MaybeObject* delete_result = hashtable->Put(key, GetHeap()->the_hole_value());
- USE(delete_result);
- ASSERT(!delete_result->IsFailure()); // Delete does not cause GC.
+ Handle<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value));
+ PutIntoObjectHashTable(hashtable, key, isolate->factory()->the_hole_value());
}
@@ -4952,13 +4976,13 @@ MaybeObject* JSObject::GetHiddenPropertiesHashTable(
ASSERT_EQ(hashtable, new_table);
}
- MaybeObject* store_result =
- SetPropertyPostInterceptor(GetHeap()->hidden_string(),
- hashtable,
- DONT_ENUM,
- kNonStrictMode,
- OMIT_EXTENSIBILITY_CHECK,
- FORCE_FIELD);
+ MaybeObject* store_result = SetLocalPropertyIgnoreAttributesTrampoline(
+ GetHeap()->hidden_string(),
+ hashtable,
+ DONT_ENUM,
+ OPTIMAL_REPRESENTATION,
+ ALLOW_AS_CONSTANT,
+ OMIT_EXTENSIBILITY_CHECK);
if (store_result->IsFailure()) return store_result;
return hashtable;
}
@@ -4985,13 +5009,13 @@ MaybeObject* JSObject::SetHiddenPropertiesHashTable(Object* value) {
}
}
}
- MaybeObject* store_result =
- SetPropertyPostInterceptor(GetHeap()->hidden_string(),
- value,
- DONT_ENUM,
- kNonStrictMode,
- OMIT_EXTENSIBILITY_CHECK,
- FORCE_FIELD);
+ MaybeObject* store_result = SetLocalPropertyIgnoreAttributesTrampoline(
+ GetHeap()->hidden_string(),
+ value,
+ DONT_ENUM,
+ OPTIMAL_REPRESENTATION,
+ ALLOW_AS_CONSTANT,
+ OMIT_EXTENSIBILITY_CHECK);
if (store_result->IsFailure()) return store_result;
return this;
}
@@ -5022,8 +5046,8 @@ Handle<Object> JSObject::DeletePropertyWithInterceptor(Handle<JSObject> object,
Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
if (!interceptor->deleter()->IsUndefined()) {
- v8::NamedPropertyDeleter deleter =
- v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
+ v8::NamedPropertyDeleterCallback deleter =
+ v8::ToCData<v8::NamedPropertyDeleterCallback>(interceptor->deleter());
LOG(isolate,
ApiNamedPropertyAccess("interceptor-named-delete", *object, *name));
PropertyCallbackArguments args(
@@ -5046,111 +5070,110 @@ Handle<Object> JSObject::DeletePropertyWithInterceptor(Handle<JSObject> object,
}
-MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
- Isolate* isolate = GetIsolate();
- Heap* heap = isolate->heap();
+// TODO(mstarzinger): Temporary wrapper until handlified.
+static Handle<Object> AccessorDelete(Handle<JSObject> object,
+ uint32_t index,
+ JSObject::DeleteMode mode) {
+ CALL_HEAP_FUNCTION(object->GetIsolate(),
+ object->GetElementsAccessor()->Delete(*object,
+ index,
+ mode),
+ Object);
+}
+
+
+Handle<Object> JSObject::DeleteElementWithInterceptor(Handle<JSObject> object,
+ uint32_t index) {
+ Isolate* isolate = object->GetIsolate();
+ Factory* factory = isolate->factory();
+
// Make sure that the top context does not change when doing
// callbacks or interceptor calls.
AssertNoContextChange ncc;
- HandleScope scope(isolate);
- Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
- if (interceptor->deleter()->IsUndefined()) return heap->false_value();
- v8::IndexedPropertyDeleter deleter =
- v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
- Handle<JSObject> this_handle(this);
+
+ Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
+ if (interceptor->deleter()->IsUndefined()) return factory->false_value();
+ v8::IndexedPropertyDeleterCallback deleter =
+ v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
LOG(isolate,
- ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
- PropertyCallbackArguments args(isolate, interceptor->data(), this, this);
+ ApiIndexedPropertyAccess("interceptor-indexed-delete", *object, index));
+ PropertyCallbackArguments args(
+ isolate, interceptor->data(), *object, *object);
v8::Handle<v8::Boolean> result = args.Call(deleter, index);
- RETURN_IF_SCHEDULED_EXCEPTION(isolate);
+ RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
if (!result.IsEmpty()) {
ASSERT(result->IsBoolean());
Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
result_internal->VerifyApiCallResultType();
- return *result_internal;
+ // Rebox CustomArguments::kReturnValueOffset before returning.
+ return handle(*result_internal, isolate);
}
- MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
- *this_handle,
- index,
- NORMAL_DELETION);
- RETURN_IF_SCHEDULED_EXCEPTION(isolate);
- return raw_result;
+ Handle<Object> delete_result = AccessorDelete(object, index, NORMAL_DELETION);
+ RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
+ return delete_result;
}
-Handle<Object> JSObject::DeleteElement(Handle<JSObject> obj,
+Handle<Object> JSObject::DeleteElement(Handle<JSObject> object,
uint32_t index,
DeleteMode mode) {
- CALL_HEAP_FUNCTION(obj->GetIsolate(),
- obj->DeleteElement(index, mode),
- Object);
-}
-
+ Isolate* isolate = object->GetIsolate();
+ Factory* factory = isolate->factory();
-MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
- Isolate* isolate = GetIsolate();
// Check access rights if needed.
- if (IsAccessCheckNeeded() &&
- !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
- isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
- RETURN_IF_SCHEDULED_EXCEPTION(isolate);
- return isolate->heap()->false_value();
+ if (object->IsAccessCheckNeeded() &&
+ !isolate->MayIndexedAccess(*object, index, v8::ACCESS_DELETE)) {
+ isolate->ReportFailedAccessCheck(*object, v8::ACCESS_DELETE);
+ RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
+ return factory->false_value();
}
- if (IsStringObjectWithCharacterAt(index)) {
+ if (object->IsStringObjectWithCharacterAt(index)) {
if (mode == STRICT_DELETION) {
// Deleting a non-configurable property in strict mode.
- HandleScope scope(isolate);
- Handle<Object> holder(this, isolate);
- Handle<Object> name = isolate->factory()->NewNumberFromUint(index);
- Handle<Object> args[2] = { name, holder };
+ Handle<Object> name = factory->NewNumberFromUint(index);
+ Handle<Object> args[2] = { name, object };
Handle<Object> error =
- isolate->factory()->NewTypeError("strict_delete_property",
- HandleVector(args, 2));
- return isolate->Throw(*error);
+ factory->NewTypeError("strict_delete_property",
+ HandleVector(args, 2));
+ isolate->Throw(*error);
+ return Handle<Object>();
}
- return isolate->heap()->false_value();
+ return factory->false_value();
}
- if (IsJSGlobalProxy()) {
- Object* proto = GetPrototype();
- if (proto->IsNull()) return isolate->heap()->false_value();
+ if (object->IsJSGlobalProxy()) {
+ Handle<Object> proto(object->GetPrototype(), isolate);
+ if (proto->IsNull()) return factory->false_value();
ASSERT(proto->IsJSGlobalObject());
- return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
+ return DeleteElement(Handle<JSObject>::cast(proto), index, mode);
}
- // From this point on everything needs to be handlified.
- HandleScope scope(isolate);
- Handle<JSObject> self(this);
-
Handle<Object> old_value;
bool should_enqueue_change_record = false;
- if (FLAG_harmony_observation && self->map()->is_observed()) {
- should_enqueue_change_record = self->HasLocalElement(index);
+ if (FLAG_harmony_observation && object->map()->is_observed()) {
+ should_enqueue_change_record = object->HasLocalElement(index);
if (should_enqueue_change_record) {
- old_value = self->GetLocalElementAccessorPair(index) != NULL
- ? Handle<Object>::cast(isolate->factory()->the_hole_value())
- : Object::GetElement(self, index);
+ old_value = object->GetLocalElementAccessorPair(index) != NULL
+ ? Handle<Object>::cast(factory->the_hole_value())
+ : Object::GetElement(isolate, object, index);
}
}
- MaybeObject* result;
// Skip interceptor if forcing deletion.
- if (self->HasIndexedInterceptor() && mode != FORCE_DELETION) {
- result = self->DeleteElementWithInterceptor(index);
+ Handle<Object> result;
+ if (object->HasIndexedInterceptor() && mode != FORCE_DELETION) {
+ result = DeleteElementWithInterceptor(object, index);
} else {
- result = self->GetElementsAccessor()->Delete(*self, index, mode);
+ result = AccessorDelete(object, index, mode);
}
- Handle<Object> hresult;
- if (!result->ToHandle(&hresult, isolate)) return result;
-
- if (should_enqueue_change_record && !self->HasLocalElement(index)) {
- Handle<String> name = isolate->factory()->Uint32ToString(index);
- EnqueueChangeRecord(self, "deleted", name, old_value);
+ if (should_enqueue_change_record && !object->HasLocalElement(index)) {
+ Handle<String> name = factory->Uint32ToString(index);
+ EnqueueChangeRecord(object, "deleted", name, old_value);
}
- return *hresult;
+ return result;
}
@@ -5923,7 +5946,8 @@ void JSObject::DefineElementAccessor(Handle<JSObject> object,
uint32_t index,
Handle<Object> getter,
Handle<Object> setter,
- PropertyAttributes attributes) {
+ PropertyAttributes attributes,
+ v8::AccessControl access_control) {
switch (object->GetElementsKind()) {
case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
@@ -5981,9 +6005,9 @@ void JSObject::DefineElementAccessor(Handle<JSObject> object,
Isolate* isolate = object->GetIsolate();
Handle<AccessorPair> accessors = isolate->factory()->NewAccessorPair();
accessors->SetComponents(*getter, *setter);
+ accessors->set_access_flags(access_control);
- CALL_HEAP_FUNCTION_VOID(
- isolate, object->SetElementCallback(index, *accessors, attributes));
+ SetElementCallback(object, index, accessors, attributes);
}
@@ -6012,11 +6036,13 @@ void JSObject::DefinePropertyAccessor(Handle<JSObject> object,
Handle<Name> name,
Handle<Object> getter,
Handle<Object> setter,
- PropertyAttributes attributes) {
+ PropertyAttributes attributes,
+ v8::AccessControl access_control) {
// 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.
bool only_attribute_changes = getter->IsNull() && setter->IsNull();
if (object->HasFastProperties() && !only_attribute_changes &&
+ access_control == v8::DEFAULT &&
(object->map()->NumberOfOwnDescriptors() <
DescriptorArray::kMaxNumberOfDescriptors)) {
bool getterOk = getter->IsNull() ||
@@ -6028,10 +6054,9 @@ void JSObject::DefinePropertyAccessor(Handle<JSObject> object,
Handle<AccessorPair> accessors = CreateAccessorPairFor(object, name);
accessors->SetComponents(*getter, *setter);
+ accessors->set_access_flags(access_control);
- CALL_HEAP_FUNCTION_VOID(
- object->GetIsolate(),
- object->SetPropertyCallback(*name, *accessors, attributes));
+ SetPropertyCallback(object, name, accessors, attributes);
}
@@ -6049,82 +6074,75 @@ bool JSObject::CanSetCallback(Name* name) {
LookupCallbackProperty(name, &callback_result);
if (callback_result.IsFound()) {
Object* obj = callback_result.GetCallbackObject();
- if (obj->IsAccessorInfo() &&
- AccessorInfo::cast(obj)->prohibits_overwriting()) {
- return false;
+ if (obj->IsAccessorInfo()) {
+ return !AccessorInfo::cast(obj)->prohibits_overwriting();
+ }
+ if (obj->IsAccessorPair()) {
+ return !AccessorPair::cast(obj)->prohibits_overwriting();
}
}
-
return true;
}
-MaybeObject* JSObject::SetElementCallback(uint32_t index,
- Object* structure,
- PropertyAttributes attributes) {
+void JSObject::SetElementCallback(Handle<JSObject> object,
+ uint32_t index,
+ Handle<Object> structure,
+ PropertyAttributes attributes) {
+ Heap* heap = object->GetHeap();
PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
// Normalize elements to make this operation simple.
- SeededNumberDictionary* dictionary;
- { MaybeObject* maybe_dictionary = NormalizeElements();
- if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
- }
- ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
+ Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
+ ASSERT(object->HasDictionaryElements() ||
+ object->HasDictionaryArgumentsElements());
// Update the dictionary with the new CALLBACKS property.
- { MaybeObject* maybe_dictionary = dictionary->Set(index, structure, details);
- if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
- }
-
+ dictionary = SeededNumberDictionary::Set(dictionary, index, structure,
+ details);
dictionary->set_requires_slow_elements();
+
// Update the dictionary backing store on the object.
- if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
+ if (object->elements()->map() == heap->non_strict_arguments_elements_map()) {
// Also delete any parameter alias.
//
// TODO(kmillikin): when deleting the last parameter alias we could
// switch to a direct backing store without the parameter map. This
// would allow GC of the context.
- FixedArray* parameter_map = FixedArray::cast(elements());
+ FixedArray* parameter_map = FixedArray::cast(object->elements());
if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
- parameter_map->set(index + 2, GetHeap()->the_hole_value());
+ parameter_map->set(index + 2, heap->the_hole_value());
}
- parameter_map->set(1, dictionary);
+ parameter_map->set(1, *dictionary);
} else {
- set_elements(dictionary);
+ object->set_elements(*dictionary);
}
-
- return GetHeap()->undefined_value();
}
-MaybeObject* JSObject::SetPropertyCallback(Name* name,
- Object* structure,
- PropertyAttributes attributes) {
+void JSObject::SetPropertyCallback(Handle<JSObject> object,
+ Handle<Name> name,
+ Handle<Object> structure,
+ PropertyAttributes attributes) {
// Normalize object to make this operation simple.
- MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
- if (maybe_ok->IsFailure()) return maybe_ok;
+ NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
// For the global object allocate a new map to invalidate the global inline
// caches which have a global property cell reference directly in the code.
- if (IsGlobalObject()) {
- Map* new_map;
- MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+ if (object->IsGlobalObject()) {
+ Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
ASSERT(new_map->is_dictionary_map());
+ object->set_map(*new_map);
- set_map(new_map);
// When running crankshaft, changing the map is not enough. We
// need to deoptimize all functions that rely on this global
// object.
- Deoptimizer::DeoptimizeGlobalObject(this);
+ Deoptimizer::DeoptimizeGlobalObject(*object);
}
// Update the dictionary with the new CALLBACKS property.
PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
- maybe_ok = SetNormalizedProperty(name, structure, details);
- if (maybe_ok->IsFailure()) return maybe_ok;
-
- return GetHeap()->undefined_value();
+ SetNormalizedProperty(object, name, structure, details);
}
@@ -6132,7 +6150,8 @@ void JSObject::DefineAccessor(Handle<JSObject> object,
Handle<Name> name,
Handle<Object> getter,
Handle<Object> setter,
- PropertyAttributes attributes) {
+ PropertyAttributes attributes,
+ v8::AccessControl access_control) {
Isolate* isolate = object->GetIsolate();
// Check access rights if needed.
if (object->IsAccessCheckNeeded() &&
@@ -6145,14 +6164,18 @@ void JSObject::DefineAccessor(Handle<JSObject> object,
Handle<Object> proto(object->GetPrototype(), isolate);
if (proto->IsNull()) return;
ASSERT(proto->IsJSGlobalObject());
- DefineAccessor(
- Handle<JSObject>::cast(proto), name, getter, setter, attributes);
+ DefineAccessor(Handle<JSObject>::cast(proto),
+ name,
+ getter,
+ setter,
+ attributes,
+ access_control);
return;
}
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
- AssertNoContextChange ncc;
+ AssertNoContextChangeWithHandleScope ncc;
// Try to flatten before operating on the string.
if (name->IsString()) String::cast(*name)->TryFlatten();
@@ -6169,7 +6192,7 @@ void JSObject::DefineAccessor(Handle<JSObject> object,
if (is_element) {
preexists = object->HasLocalElement(index);
if (preexists && object->GetLocalElementAccessorPair(index) == NULL) {
- old_value = Object::GetElement(object, index);
+ old_value = Object::GetElement(isolate, object, index);
}
} else {
LookupResult lookup(isolate);
@@ -6182,9 +6205,11 @@ void JSObject::DefineAccessor(Handle<JSObject> object,
}
if (is_element) {
- DefineElementAccessor(object, index, getter, setter, attributes);
+ DefineElementAccessor(
+ object, index, getter, setter, attributes, access_control);
} else {
- DefinePropertyAccessor(object, name, getter, setter, attributes);
+ DefinePropertyAccessor(
+ object, name, getter, setter, attributes, access_control);
}
if (is_observed) {
@@ -6313,22 +6338,25 @@ bool JSObject::DefineFastAccessor(Handle<JSObject> object,
}
-MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
- Isolate* isolate = GetIsolate();
- Name* name = Name::cast(info->name());
+Handle<Object> JSObject::SetAccessor(Handle<JSObject> object,
+ Handle<AccessorInfo> info) {
+ Isolate* isolate = object->GetIsolate();
+ Factory* factory = isolate->factory();
+ Handle<Name> name(Name::cast(info->name()));
+
// Check access rights if needed.
- if (IsAccessCheckNeeded() &&
- !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
- isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
- RETURN_IF_SCHEDULED_EXCEPTION(isolate);
- return isolate->heap()->undefined_value();
+ if (object->IsAccessCheckNeeded() &&
+ !isolate->MayNamedAccess(*object, *name, v8::ACCESS_SET)) {
+ isolate->ReportFailedAccessCheck(*object, v8::ACCESS_SET);
+ RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
+ return factory->undefined_value();
}
- if (IsJSGlobalProxy()) {
- Object* proto = GetPrototype();
- if (proto->IsNull()) return this;
+ if (object->IsJSGlobalProxy()) {
+ Handle<Object> proto(object->GetPrototype(), isolate);
+ if (proto->IsNull()) return object;
ASSERT(proto->IsJSGlobalObject());
- return JSObject::cast(proto)->DefineAccessor(info);
+ return SetAccessor(Handle<JSObject>::cast(proto), info);
}
// Make sure that the top context does not change when doing callbacks or
@@ -6336,18 +6364,18 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
AssertNoContextChange ncc;
// Try to flatten before operating on the string.
- if (name->IsString()) String::cast(name)->TryFlatten();
+ if (name->IsString()) FlattenString(Handle<String>::cast(name));
- if (!CanSetCallback(name)) return isolate->heap()->undefined_value();
+ if (!object->CanSetCallback(*name)) return factory->undefined_value();
uint32_t index = 0;
bool is_element = name->AsArrayIndex(&index);
if (is_element) {
- if (IsJSArray()) return isolate->heap()->undefined_value();
+ if (object->IsJSArray()) return factory->undefined_value();
// Accessors overwrite previous callbacks (cf. with getters/setters).
- switch (GetElementsKind()) {
+ switch (object->GetElementsKind()) {
case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
@@ -6366,7 +6394,7 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
case EXTERNAL_DOUBLE_ELEMENTS:
// Ignore getters and setters on pixel and external array
// elements.
- return isolate->heap()->undefined_value();
+ return factory->undefined_value();
case DICTIONARY_ELEMENTS:
break;
case NON_STRICT_ARGUMENTS_ELEMENTS:
@@ -6374,25 +6402,21 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
break;
}
- MaybeObject* maybe_ok =
- SetElementCallback(index, info, info->property_attributes());
- if (maybe_ok->IsFailure()) return maybe_ok;
+ SetElementCallback(object, index, info, info->property_attributes());
} else {
// Lookup the name.
LookupResult result(isolate);
- LocalLookup(name, &result, true);
+ object->LocalLookup(*name, &result, true);
// ES5 forbids turning a property into an accessor if it's not
// configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
if (result.IsFound() && (result.IsReadOnly() || result.IsDontDelete())) {
- return isolate->heap()->undefined_value();
+ return factory->undefined_value();
}
- MaybeObject* maybe_ok =
- SetPropertyCallback(name, info, info->property_attributes());
- if (maybe_ok->IsFailure()) return maybe_ok;
+ SetPropertyCallback(object, name, info, info->property_attributes());
}
- return this;
+ return object;
}
@@ -6401,7 +6425,7 @@ MaybeObject* JSObject::LookupAccessor(Name* name, AccessorComponent component) {
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
- AssertNoContextChange ncc;
+ AssertNoContextChangeWithHandleScope ncc;
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
@@ -6501,6 +6525,15 @@ MaybeObject* Map::RawCopy(int instance_size) {
}
+Handle<Map> Map::CopyNormalized(Handle<Map> map,
+ PropertyNormalizationMode mode,
+ NormalizedMapSharingMode sharing) {
+ CALL_HEAP_FUNCTION(map->GetIsolate(),
+ map->CopyNormalized(mode, sharing),
+ Map);
+}
+
+
MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
NormalizedMapSharingMode sharing) {
int new_instance_size = instance_size();
@@ -6580,7 +6613,7 @@ MaybeObject* Map::ShareDescriptor(DescriptorArray* descriptors,
} else {
// Descriptor arrays grow by 50%.
MaybeObject* maybe_descriptors = DescriptorArray::Allocate(
- old_size, old_size < 4 ? 1 : old_size / 2);
+ GetIsolate(), old_size, old_size < 4 ? 1 : old_size / 2);
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
DescriptorArray::WhitenessWitness witness(new_descriptors);
@@ -6645,7 +6678,7 @@ MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors,
if (!maybe_transitions->To(&transitions)) return maybe_transitions;
set_transitions(transitions);
result->SetBackPointer(this);
- } else if (flag != OMIT_TRANSITION_KEEP_REPRESENTATIONS) {
+ } else {
descriptors->InitializeRepresentations(Representation::Tagged());
}
@@ -6830,7 +6863,8 @@ MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor,
}
DescriptorArray* new_descriptors;
- MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size, 1);
+ MaybeObject* maybe_descriptors =
+ DescriptorArray::Allocate(GetIsolate(), old_size, 1);
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
DescriptorArray::WhitenessWitness witness(new_descriptors);
@@ -6877,7 +6911,7 @@ MaybeObject* DescriptorArray::CopyUpToAddAttributes(
int size = enumeration_index;
DescriptorArray* descriptors;
- MaybeObject* maybe_descriptors = Allocate(size);
+ MaybeObject* maybe_descriptors = Allocate(GetIsolate(), size);
if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
DescriptorArray::WhitenessWitness witness(descriptors);
@@ -6924,7 +6958,8 @@ MaybeObject* Map::CopyReplaceDescriptor(DescriptorArray* descriptors,
ASSERT_LT(insertion_index, new_size);
DescriptorArray* new_descriptors;
- MaybeObject* maybe_descriptors = DescriptorArray::Allocate(new_size);
+ MaybeObject* maybe_descriptors =
+ DescriptorArray::Allocate(GetIsolate(), new_size);
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
DescriptorArray::WhitenessWitness witness(new_descriptors);
@@ -7714,8 +7749,10 @@ bool FixedArray::IsEqualTo(FixedArray* other) {
#endif
-MaybeObject* DescriptorArray::Allocate(int number_of_descriptors, int slack) {
- Heap* heap = Isolate::Current()->heap();
+MaybeObject* DescriptorArray::Allocate(Isolate* isolate,
+ int number_of_descriptors,
+ int slack) {
+ Heap* heap = isolate->heap();
// Do not use DescriptorArray::cast on incomplete object.
int size = number_of_descriptors + slack;
if (size == 0) return heap->empty_descriptor_array();
@@ -7773,6 +7810,8 @@ void DescriptorArray::CopyFrom(int dst_index,
MaybeObject* DescriptorArray::Merge(int verbatim,
int valid,
int new_size,
+ int modify_index,
+ StoreMode store_mode,
DescriptorArray* other) {
ASSERT(verbatim <= valid);
ASSERT(valid <= new_size);
@@ -7781,7 +7820,8 @@ MaybeObject* DescriptorArray::Merge(int verbatim,
// Allocate a new descriptor array large enough to hold the required
// descriptors, with minimally the exact same size as this descriptor array.
MaybeObject* maybe_descriptors = DescriptorArray::Allocate(
- new_size, Max(new_size, other->number_of_descriptors()) - new_size);
+ GetIsolate(), new_size,
+ Max(new_size, other->number_of_descriptors()) - new_size);
if (!maybe_descriptors->To(&result)) return maybe_descriptors;
ASSERT(result->length() > length() ||
result->NumberOfSlackDescriptors() > 0 ||
@@ -7796,7 +7836,7 @@ MaybeObject* DescriptorArray::Merge(int verbatim,
int current_offset = 0;
for (descriptor = 0; descriptor < verbatim; descriptor++) {
if (GetDetails(descriptor).type() == FIELD) current_offset++;
- result->CopyFrom(descriptor, this, descriptor, witness);
+ result->CopyFrom(descriptor, other, descriptor, witness);
}
// |verbatim| -> |valid|
@@ -7806,6 +7846,7 @@ MaybeObject* DescriptorArray::Merge(int verbatim,
PropertyDetails other_details = other->GetDetails(descriptor);
if (details.type() == FIELD || other_details.type() == FIELD ||
+ (store_mode == FORCE_FIELD && descriptor == modify_index) ||
(details.type() == CONSTANT &&
other_details.type() == CONSTANT &&
GetValue(descriptor) != other->GetValue(descriptor))) {
@@ -7824,7 +7865,8 @@ MaybeObject* DescriptorArray::Merge(int verbatim,
// |valid| -> |new_size|
for (; descriptor < new_size; descriptor++) {
PropertyDetails details = other->GetDetails(descriptor);
- if (details.type() == FIELD) {
+ if (details.type() == FIELD ||
+ (store_mode == FORCE_FIELD && descriptor == modify_index)) {
Name* key = other->GetKey(descriptor);
FieldDescriptor d(key,
current_offset++,
@@ -7939,19 +7981,21 @@ Object* AccessorPair::GetComponent(AccessorComponent component) {
}
-MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
+MaybeObject* DeoptimizationInputData::Allocate(Isolate* isolate,
+ int deopt_entry_count,
PretenureFlag pretenure) {
ASSERT(deopt_entry_count > 0);
- return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
- pretenure);
+ return isolate->heap()->AllocateFixedArray(LengthFor(deopt_entry_count),
+ pretenure);
}
-MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
+MaybeObject* DeoptimizationOutputData::Allocate(Isolate* isolate,
+ int number_of_deopt_points,
PretenureFlag pretenure) {
- if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
- return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
- pretenure);
+ if (number_of_deopt_points == 0) return isolate->heap()->empty_fixed_array();
+ return isolate->heap()->AllocateFixedArray(
+ LengthOfFixedArray(number_of_deopt_points), pretenure);
}
@@ -7968,8 +8012,34 @@ bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
#endif
+static bool IsIdentifier(UnicodeCache* cache, Name* name) {
+ // Checks whether the buffer contains an identifier (no escape).
+ if (!name->IsString()) return false;
+ String* string = String::cast(name);
+ if (string->length() == 0) return false;
+ ConsStringIteratorOp op;
+ StringCharacterStream stream(string, &op);
+ if (!cache->IsIdentifierStart(stream.GetNext())) {
+ return false;
+ }
+ while (stream.HasMore()) {
+ if (!cache->IsIdentifierPart(stream.GetNext())) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+bool Name::IsCacheable(Isolate* isolate) {
+ return IsSymbol() ||
+ IsIdentifier(isolate->unicode_cache(), this) ||
+ this == isolate->heap()->hidden_string();
+}
+
+
bool String::LooksValid() {
- if (!Isolate::Current()->heap()->Contains(this)) return false;
+ if (!GetIsolate()->heap()->Contains(this)) return false;
return true;
}
@@ -8129,8 +8199,7 @@ const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
}
-void Relocatable::PostGarbageCollectionProcessing() {
- Isolate* isolate = Isolate::Current();
+void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
Relocatable* current = isolate->relocatable_top();
while (current != NULL) {
current->PostGarbageCollection();
@@ -8141,7 +8210,7 @@ void Relocatable::PostGarbageCollectionProcessing() {
// Reserve space for statics needing saving and restoring.
int Relocatable::ArchiveSpacePerThread() {
- return sizeof(Isolate::Current()->relocatable_top());
+ return sizeof(Relocatable*); // NOLINT
}
@@ -8167,8 +8236,7 @@ char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
}
-void Relocatable::Iterate(ObjectVisitor* v) {
- Isolate* isolate = Isolate::Current();
+void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) {
Iterate(v, isolate->relocatable_top());
}
@@ -8944,6 +9012,7 @@ AllocationMemento* AllocationMemento::FindForJSObject(JSObject* object) {
// involves carefully checking the object immediately after the JSArray
// (if there is one) to see if it's an AllocationMemento.
if (FLAG_track_allocation_sites && object->GetHeap()->InNewSpace(object)) {
+ ASSERT(object->GetHeap()->InToSpace(object));
Address ptr_end = (reinterpret_cast<Address>(object) - kHeapObjectTag) +
object->Size();
if ((ptr_end + AllocationMemento::kSize) <=
@@ -8954,7 +9023,7 @@ AllocationMemento* AllocationMemento::FindForJSObject(JSObject* object) {
if (*possible_allocation_memento_map ==
object->GetHeap()->allocation_memento_map()) {
AllocationMemento* memento = AllocationMemento::cast(
- reinterpret_cast<Object*>(ptr_end + 1));
+ reinterpret_cast<Object*>(ptr_end + kHeapObjectTag));
return memento;
}
}
@@ -9229,46 +9298,34 @@ void JSFunction::MarkForLazyRecompilation() {
}
-void JSFunction::MarkForParallelRecompilation() {
+void JSFunction::MarkForConcurrentRecompilation() {
ASSERT(is_compiled() || GetIsolate()->DebuggerHasBreakPoints());
ASSERT(!IsOptimized());
ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
ASSERT(!shared()->is_generator());
- ASSERT(FLAG_parallel_recompilation);
- if (FLAG_trace_parallel_recompilation) {
+ ASSERT(FLAG_concurrent_recompilation);
+ if (FLAG_trace_concurrent_recompilation) {
PrintF(" ** Marking ");
PrintName();
- PrintF(" for parallel recompilation.\n");
+ PrintF(" for concurrent recompilation.\n");
}
set_code_no_write_barrier(
- GetIsolate()->builtins()->builtin(Builtins::kParallelRecompile));
- // No write barrier required, since the builtin is part of the root set.
-}
-
-
-void JSFunction::MarkForInstallingRecompiledCode() {
- // 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(
- GetIsolate()->builtins()->builtin(Builtins::kInstallRecompiledCode));
+ GetIsolate()->builtins()->builtin(Builtins::kConcurrentRecompile));
// No write barrier required, since the builtin is part of the root set.
}
void JSFunction::MarkInRecompileQueue() {
- // We can only arrive here via the parallel-recompilation builtin. If
+ // We can only arrive here via the concurrent-recompilation builtin. If
// break points were set, the code would point to the lazy-compile builtin.
ASSERT(!GetIsolate()->DebuggerHasBreakPoints());
- ASSERT(IsMarkedForParallelRecompilation() && !IsOptimized());
+ ASSERT(IsMarkedForConcurrentRecompilation() && !IsOptimized());
ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
- ASSERT(FLAG_parallel_recompilation);
- if (FLAG_trace_parallel_recompilation) {
+ ASSERT(FLAG_concurrent_recompilation);
+ if (FLAG_trace_concurrent_recompilation) {
PrintF(" ** Queueing ");
PrintName();
- PrintF(" for parallel recompilation.\n");
+ PrintF(" for concurrent recompilation.\n");
}
set_code_no_write_barrier(
GetIsolate()->builtins()->builtin(Builtins::kInRecompileQueue));
@@ -9282,7 +9339,7 @@ static bool CompileLazyHelper(CompilationInfo* info,
ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
ASSERT(!info->isolate()->has_pending_exception());
bool result = Compiler::CompileLazy(info);
- ASSERT(result != Isolate::Current()->has_pending_exception());
+ ASSERT(result != info->isolate()->has_pending_exception());
if (!result && flag == CLEAR_EXCEPTION) {
info->isolate()->clear_pending_exception();
}
@@ -9451,11 +9508,25 @@ bool JSFunction::CompileLazy(Handle<JSFunction> function,
}
+Handle<Code> JSFunction::CompileOsr(Handle<JSFunction> function,
+ BailoutId osr_ast_id,
+ ClearExceptionFlag flag) {
+ CompilationInfoWithZone info(function);
+ info.SetOptimizing(osr_ast_id);
+ if (CompileLazyHelper(&info, flag)) {
+ // TODO(titzer): don't install the OSR code.
+ // ASSERT(function->code() != *info.code());
+ return info.code();
+ } else {
+ return Handle<Code>::null();
+ }
+}
+
+
bool JSFunction::CompileOptimized(Handle<JSFunction> function,
- BailoutId osr_ast_id,
ClearExceptionFlag flag) {
CompilationInfoWithZone info(function);
- info.SetOptimizing(osr_ast_id);
+ info.SetOptimizing(BailoutId::None());
return CompileLazyHelper(&info, flag);
}
@@ -9481,21 +9552,13 @@ bool JSFunction::IsInlineable() {
void JSObject::OptimizeAsPrototype(Handle<JSObject> object) {
- CALL_HEAP_FUNCTION_VOID(object->GetIsolate(), object->OptimizeAsPrototype());
-}
-
-
-MaybeObject* JSObject::OptimizeAsPrototype() {
- if (IsGlobalObject()) return this;
+ if (object->IsGlobalObject()) return;
// Make sure prototypes are fast objects and their maps have the bit set
// so they remain fast.
- if (!HasFastProperties()) {
- MaybeObject* new_proto = TransformToFastProperties(0);
- if (new_proto->IsFailure()) return new_proto;
- ASSERT(new_proto == this);
+ if (!object->HasFastProperties()) {
+ TransformToFastProperties(object, 0);
}
- return this;
}
@@ -9647,40 +9710,38 @@ Context* JSFunction::NativeContextFromLiterals(FixedArray* literals) {
}
-bool JSFunction::PassesHydrogenFilter() {
+// The filter is a pattern that matches function names in this way:
+// "*" all; the default
+// "-" all but the top-level function
+// "-name" all but the function "name"
+// "" only the top-level function
+// "name" only the function "name"
+// "name*" only functions starting with "name"
+bool JSFunction::PassesFilter(const char* raw_filter) {
+ if (*raw_filter == '*') return true;
String* name = shared()->DebugName();
- // The filter string is a pattern that matches functions in this way:
- // "*" all; the default
- // "-" all but the top-level function
- // "-name" all but the function "name"
- // "" only the top-level function
- // "name" only the function "name"
- // "name*" only functions starting with "name"
- if (*FLAG_hydrogen_filter != '*') {
- Vector<const char> filter = CStrVector(FLAG_hydrogen_filter);
- if (filter.length() == 0) return name->length() == 0;
- if (filter[0] != '-' && name->IsUtf8EqualTo(filter)) return true;
- if (filter[0] == '-' &&
- !name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
- return true;
- }
- if (filter[filter.length() - 1] == '*' &&
- name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
- return true;
- }
- return false;
+ Vector<const char> filter = CStrVector(raw_filter);
+ if (filter.length() == 0) return name->length() == 0;
+ if (filter[0] != '-' && name->IsUtf8EqualTo(filter)) return true;
+ if (filter[0] == '-' &&
+ !name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
+ return true;
}
-
- return true;
+ if (filter[filter.length() - 1] == '*' &&
+ name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
+ return true;
+ }
+ return false;
}
-MaybeObject* Oddball::Initialize(const char* to_string,
+MaybeObject* Oddball::Initialize(Heap* heap,
+ const char* to_string,
Object* to_number,
byte kind) {
String* internalized_to_string;
{ MaybeObject* maybe_string =
- Isolate::Current()->heap()->InternalizeUtf8String(
+ heap->InternalizeUtf8String(
CStrVector(to_string));
if (!maybe_string->To(&internalized_to_string)) return maybe_string;
}
@@ -9814,12 +9875,16 @@ void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
// non-optimizable if optimization is disabled for the shared
// function info.
set_optimization_disabled(true);
+ set_bailout_reason(reason);
// Code should be the lazy compilation stub or else unoptimized. If the
// latter, disable optimization for the code too.
ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
if (code()->kind() == Code::FUNCTION) {
code()->set_optimizable(false);
}
+ PROFILE(GetIsolate(),
+ LogExistingFunction(Handle<SharedFunctionInfo>(this),
+ Handle<Code>(code())));
if (FLAG_trace_opt) {
PrintF("[disabled optimization for ");
ShortPrint();
@@ -10317,7 +10382,7 @@ void Code::ClearInlineCaches() {
RelocInfo* info = it.rinfo();
Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
if (target->is_inline_cache_stub()) {
- IC::Clear(info->pc());
+ IC::Clear(this->GetIsolate(), info->pc());
}
}
}
@@ -10341,6 +10406,18 @@ void Code::ClearTypeFeedbackCells(Heap* heap) {
}
+BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
+ DisallowHeapAllocation no_gc;
+ ASSERT(kind() == FUNCTION);
+ for (FullCodeGenerator::BackEdgeTableIterator it(this, &no_gc);
+ !it.Done();
+ it.Next()) {
+ if (it.pc_offset() == pc_offset) return it.ast_id();
+ }
+ return BailoutId::None();
+}
+
+
bool Code::allowed_in_shared_map_code_cache() {
return is_keyed_load_stub() || is_keyed_store_stub() ||
(is_compare_ic_stub() &&
@@ -10401,7 +10478,7 @@ int Code::GetAge() {
void Code::GetCodeAgeAndParity(Code* code, Age* age,
MarkingParity* parity) {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = code->GetIsolate();
Builtins* builtins = isolate->builtins();
Code* stub = NULL;
#define HANDLE_CODE_AGE(AGE) \
@@ -10801,7 +10878,8 @@ void Code::Disassemble(const char* name, FILE* out) {
// If there is no back edge table, the "table start" will be at or after
// (due to alignment) the end of the instruction stream.
if (static_cast<int>(offset) < instruction_size()) {
- FullCodeGenerator::BackEdgeTableIterator back_edges(this);
+ DisallowHeapAllocation no_gc;
+ FullCodeGenerator::BackEdgeTableIterator back_edges(this, &no_gc);
PrintF(out, "Back edges (size = %u)\n", back_edges.table_length());
PrintF(out, "ast_id pc_offset loop_depth\n");
@@ -10977,7 +11055,7 @@ static bool GetOldValue(Isolate* isolate,
ASSERT(attributes != ABSENT);
if (attributes == DONT_DELETE) return false;
old_values->Add(object->GetLocalElementAccessorPair(index) == NULL
- ? Object::GetElement(object, index)
+ ? Object::GetElement(isolate, object, index)
: Handle<Object>::cast(isolate->factory()->the_hole_value()));
indices->Add(index);
return true;
@@ -10997,7 +11075,8 @@ static void EnqueueSpliceRecord(Handle<JSArray> object,
{ object, index_object, deleted, add_count_object };
bool threw;
- Execution::Call(Handle<JSFunction>(isolate->observers_enqueue_splice()),
+ Execution::Call(isolate,
+ Handle<JSFunction>(isolate->observers_enqueue_splice()),
isolate->factory()->undefined_value(), ARRAY_SIZE(args), args,
&threw);
ASSERT(!threw);
@@ -11010,7 +11089,8 @@ static void BeginPerformSplice(Handle<JSArray> object) {
Handle<Object> args[] = { object };
bool threw;
- Execution::Call(Handle<JSFunction>(isolate->observers_begin_perform_splice()),
+ Execution::Call(isolate,
+ Handle<JSFunction>(isolate->observers_begin_perform_splice()),
isolate->factory()->undefined_value(), ARRAY_SIZE(args), args,
&threw);
ASSERT(!threw);
@@ -11023,7 +11103,8 @@ static void EndPerformSplice(Handle<JSArray> object) {
Handle<Object> args[] = { object };
bool threw;
- Execution::Call(Handle<JSFunction>(isolate->observers_end_perform_splice()),
+ Execution::Call(isolate,
+ Handle<JSFunction>(isolate->observers_end_perform_splice()),
isolate->factory()->undefined_value(), ARRAY_SIZE(args), args,
&threw);
ASSERT(!threw);
@@ -11343,8 +11424,9 @@ void DependentCode::RemoveCompilationInfo(DependentCode::DependencyGroup group,
bool DependentCode::Contains(DependencyGroup group, Code* code) {
GroupStartIndexes starts(this);
- int number_of_entries = starts.number_of_entries();
- for (int i = 0; i < number_of_entries; i++) {
+ int start = starts.at(group);
+ int end = starts.at(group + 1);
+ for (int i = start; i < end; i++) {
if (object_at(i) == code) return true;
}
return false;
@@ -11362,13 +11444,15 @@ void DependentCode::DeoptimizeDependentCodeGroup(
int code_entries = starts.number_of_entries();
if (start == end) return;
- // Collect all the code to deoptimize.
- Zone zone(isolate);
- ZoneList<Code*> codes(end - start, &zone);
+ // Mark all the code that needs to be deoptimized.
+ bool marked = false;
for (int i = start; i < end; i++) {
if (is_code_at(i)) {
Code* code = code_at(i);
- if (!code->marked_for_deoptimization()) codes.Add(code, &zone);
+ if (!code->marked_for_deoptimization()) {
+ code->set_marked_for_deoptimization(true);
+ marked = true;
+ }
} else {
CompilationInfo* info = compilation_info_at(i);
info->AbortDueToDependencyChange();
@@ -11384,7 +11468,8 @@ void DependentCode::DeoptimizeDependentCodeGroup(
clear_at(i);
}
set_number_of_entries(group, 0);
- Deoptimizer::DeoptimizeCodeList(isolate, &codes);
+
+ if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate);
}
@@ -11539,16 +11624,18 @@ MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
bool check_prototype,
SetPropertyMode set_mode) {
Isolate* isolate = GetIsolate();
+ HandleScope scope(isolate);
+
// Make sure that the top context does not change when doing
// callbacks or interceptor calls.
AssertNoContextChange ncc;
- HandleScope scope(isolate);
+
Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Handle<JSObject> this_handle(this);
Handle<Object> value_handle(value, isolate);
if (!interceptor->setter()->IsUndefined()) {
- v8::IndexedPropertySetter setter =
- v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
+ v8::IndexedPropertySetterCallback setter =
+ v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
LOG(isolate,
ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
PropertyCallbackArguments args(isolate, interceptor->data(), this, this);
@@ -11581,7 +11668,8 @@ MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
Handle<ExecutableAccessorInfo> data(
ExecutableAccessorInfo::cast(structure));
Object* fun_obj = data->getter();
- v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
+ v8::AccessorGetterCallback call_fun =
+ v8::ToCData<v8::AccessorGetterCallback>(fun_obj);
if (call_fun == NULL) return isolate->heap()->undefined_value();
HandleScope scope(isolate);
Handle<JSObject> self(JSObject::cast(receiver));
@@ -11646,7 +11734,8 @@ MaybeObject* JSObject::SetElementWithCallback(Object* structure,
Handle<ExecutableAccessorInfo> data(
ExecutableAccessorInfo::cast(structure));
Object* call_obj = data->setter();
- v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
+ v8::AccessorSetterCallback call_fun =
+ v8::ToCData<v8::AccessorSetterCallback>(call_obj);
if (call_fun == NULL) return value;
Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Handle<String> key(isolate->factory()->NumberToString(number));
@@ -12100,18 +12189,17 @@ MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
}
-MaybeObject* JSReceiver::SetElement(uint32_t index,
- Object* value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode,
- bool check_proto) {
- if (IsJSProxy()) {
- return JSProxy::cast(this)->SetElementWithHandler(
- this, index, value, strict_mode);
- } else {
- return JSObject::cast(this)->SetElement(
- index, value, attributes, strict_mode, check_proto);
+Handle<Object> JSReceiver::SetElement(Handle<JSReceiver> object,
+ uint32_t index,
+ Handle<Object> value,
+ PropertyAttributes attributes,
+ StrictModeFlag strict_mode) {
+ if (object->IsJSProxy()) {
+ return JSProxy::SetElementWithHandler(
+ Handle<JSProxy>::cast(object), object, index, value, strict_mode);
}
+ return JSObject::SetElement(
+ Handle<JSObject>::cast(object), index, value, attributes, strict_mode);
}
@@ -12136,7 +12224,8 @@ Handle<Object> JSObject::SetElement(Handle<JSObject> object,
if (object->HasExternalArrayElements()) {
if (!value->IsNumber() && !value->IsUndefined()) {
bool has_exception;
- Handle<Object> number = Execution::ToNumber(value, &has_exception);
+ Handle<Object> number =
+ Execution::ToNumber(object->GetIsolate(), value, &has_exception);
if (has_exception) return Handle<Object>();
value = number;
}
@@ -12213,7 +12302,7 @@ MaybeObject* JSObject::SetElement(uint32_t index,
if (old_attributes != ABSENT) {
if (self->GetLocalElementAccessorPair(index) == NULL)
- old_value = Object::GetElement(self, index);
+ old_value = Object::GetElement(isolate, self, index);
} else if (self->IsJSArray()) {
// Store old array length in case adding an element grows the array.
old_length_handle = handle(Handle<JSArray>::cast(self)->length(), isolate);
@@ -12255,7 +12344,7 @@ MaybeObject* JSObject::SetElement(uint32_t index,
} else if (old_value->IsTheHole()) {
EnqueueChangeRecord(self, "reconfigured", name, old_value);
} else {
- Handle<Object> new_value = Object::GetElement(self, index);
+ Handle<Object> new_value = Object::GetElement(isolate, self, index);
bool value_changed = !old_value->SameValue(*new_value);
if (old_attributes != new_attributes) {
if (!value_changed) old_value = isolate->factory()->the_hole_value();
@@ -12547,16 +12636,18 @@ MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
uint32_t index) {
Isolate* isolate = GetIsolate();
+ HandleScope scope(isolate);
+
// Make sure that the top context does not change when doing
// callbacks or interceptor calls.
AssertNoContextChange ncc;
- HandleScope scope(isolate);
+
Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
Handle<Object> this_handle(receiver, isolate);
Handle<JSObject> holder_handle(this, isolate);
if (!interceptor->getter()->IsUndefined()) {
- v8::IndexedPropertyGetter getter =
- v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
+ v8::IndexedPropertyGetterCallback getter =
+ v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
LOG(isolate,
ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
PropertyCallbackArguments
@@ -12581,7 +12672,7 @@ MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
Object* pt = holder_handle->GetPrototype();
if (pt == heap->null_value()) return heap->undefined_value();
- return pt->GetElementWithReceiver(*this_handle, index);
+ return pt->GetElementWithReceiver(isolate, *this_handle, index);
}
@@ -12860,8 +12951,8 @@ MaybeObject* JSObject::GetPropertyWithInterceptor(
Handle<String> name_handle(String::cast(name));
if (!interceptor->getter()->IsUndefined()) {
- v8::NamedPropertyGetter getter =
- v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
+ v8::NamedPropertyGetterCallback getter =
+ v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter());
LOG(isolate,
ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
PropertyCallbackArguments
@@ -13697,6 +13788,74 @@ MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
template<typename Shape, typename Key>
+uint32_t HashTable<Shape, Key>::EntryForProbe(Key key,
+ Object* k,
+ int probe,
+ uint32_t expected) {
+ uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
+ uint32_t capacity = Capacity();
+ uint32_t entry = FirstProbe(hash, capacity);
+ for (int i = 1; i < probe; i++) {
+ if (entry == expected) return expected;
+ entry = NextProbe(entry, i, capacity);
+ }
+ return entry;
+}
+
+
+template<typename Shape, typename Key>
+void HashTable<Shape, Key>::Swap(uint32_t entry1,
+ uint32_t entry2,
+ WriteBarrierMode mode) {
+ int index1 = EntryToIndex(entry1);
+ int index2 = EntryToIndex(entry2);
+ Object* temp[Shape::kEntrySize];
+ for (int j = 0; j < Shape::kEntrySize; j++) {
+ temp[j] = get(index1 + j);
+ }
+ for (int j = 0; j < Shape::kEntrySize; j++) {
+ set(index1 + j, get(index2 + j), mode);
+ }
+ for (int j = 0; j < Shape::kEntrySize; j++) {
+ set(index2 + j, temp[j], mode);
+ }
+}
+
+
+template<typename Shape, typename Key>
+void HashTable<Shape, Key>::Rehash(Key key) {
+ DisallowHeapAllocation no_gc;
+ WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
+ uint32_t capacity = Capacity();
+ bool done = false;
+ for (int probe = 1; !done; probe++) {
+ // All elements at entries given by one of the first _probe_ probes
+ // are placed correctly. Other elements might need to be moved.
+ done = true;
+ for (uint32_t current = 0; current < capacity; current++) {
+ Object* current_key = get(EntryToIndex(current));
+ if (IsKey(current_key)) {
+ uint32_t target = EntryForProbe(key, current_key, probe, current);
+ if (current == target) continue;
+ Object* target_key = get(EntryToIndex(target));
+ if (!IsKey(target_key) ||
+ EntryForProbe(key, target_key, probe, target) != target) {
+ // Put the current element into the correct position.
+ Swap(current, target, mode);
+ // The other element will be processed on the next iteration.
+ current--;
+ } else {
+ // The place for the current element is occupied. Leave the element
+ // for the next probe.
+ done = false;
+ }
+ }
+ }
+ }
+}
+
+
+template<typename Shape, typename Key>
MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
int capacity = Capacity();
int nof = NumberOfElements() + n;
@@ -15226,7 +15385,7 @@ MaybeObject* NameDictionary::TransformPropertiesToFastFor(
// Allocate the instance descriptor.
DescriptorArray* descriptors;
MaybeObject* maybe_descriptors =
- DescriptorArray::Allocate(instance_descriptor_length);
+ DescriptorArray::Allocate(GetIsolate(), instance_descriptor_length);
if (!maybe_descriptors->To(&descriptors)) {
return maybe_descriptors;
}
@@ -15333,6 +15492,7 @@ MaybeObject* ObjectHashSet::Add(Object* key) {
int hash;
{ MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
if (maybe_hash->IsFailure()) return maybe_hash;
+ ASSERT(key->GetHash(OMIT_CREATION) == maybe_hash);
hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
}
int entry = FindEntry(key);
@@ -15394,6 +15554,7 @@ MaybeObject* ObjectHashTable::Put(Object* key, Object* value) {
int hash;
{ MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
if (maybe_hash->IsFailure()) return maybe_hash;
+ ASSERT(key->GetHash(OMIT_CREATION) == maybe_hash);
hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
}
int entry = FindEntry(key);
@@ -15517,7 +15678,7 @@ void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
int code_position,
Handle<Object> break_point_object) {
Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
- Isolate::Current());
+ debug_info->GetIsolate());
if (break_point_info->IsUndefined()) return;
BreakPointInfo::ClearBreakPoint(
Handle<BreakPointInfo>::cast(break_point_info),
@@ -15530,7 +15691,7 @@ void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
int source_position,
int statement_position,
Handle<Object> break_point_object) {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = debug_info->GetIsolate();
Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
isolate);
if (!break_point_info->IsUndefined()) {
@@ -15644,7 +15805,7 @@ int DebugInfo::GetBreakPointInfoIndex(int code_position) {
// Remove the specified break point object.
void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
Handle<Object> break_point_object) {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = break_point_info->GetIsolate();
// If there are no break points just ignore.
if (break_point_info->break_point_objects()->IsUndefined()) return;
// If there is a single break point clear it if it is the same.