| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index d8a6f13307b68fde02432d19acb520d202ec2a6d..944bfa6232ee9d5704d2b5c3b587c41727bb9f00 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -28,6 +28,7 @@
|
| #include "v8.h"
|
|
|
| #include "accessors.h"
|
| +#include "allocation-site-scopes.h"
|
| #include "api.h"
|
| #include "arguments.h"
|
| #include "bootstrapper.h"
|
| @@ -142,6 +143,20 @@ void Object::Lookup(Name* name, LookupResult* result) {
|
| }
|
|
|
|
|
| +Handle<Object> Object::GetPropertyWithReceiver(
|
| + Handle<Object> object,
|
| + Handle<Object> receiver,
|
| + Handle<Name> name,
|
| + PropertyAttributes* attributes) {
|
| + LookupResult lookup(name->GetIsolate());
|
| + object->Lookup(*name, &lookup);
|
| + Handle<Object> result =
|
| + GetProperty(object, receiver, &lookup, name, attributes);
|
| + ASSERT(*attributes <= ABSENT);
|
| + return result;
|
| +}
|
| +
|
| +
|
| MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
|
| Name* name,
|
| PropertyAttributes* attributes) {
|
| @@ -328,9 +343,10 @@ static MaybeObject* GetDeclaredAccessorProperty(Object* receiver,
|
| }
|
|
|
|
|
| -MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
|
| - Object* structure,
|
| - Name* name) {
|
| +Handle<Object> JSObject::GetPropertyWithCallback(Handle<JSObject> object,
|
| + Handle<Object> receiver,
|
| + Handle<Object> structure,
|
| + Handle<Name> name) {
|
| Isolate* isolate = name->GetIsolate();
|
| // To accommodate both the old and the new api we switch on the
|
| // data structure used to store the callbacks. Eventually foreign
|
| @@ -338,66 +354,71 @@ MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
|
| if (structure->IsForeign()) {
|
| AccessorDescriptor* callback =
|
| reinterpret_cast<AccessorDescriptor*>(
|
| - Foreign::cast(structure)->foreign_address());
|
| - MaybeObject* value = (callback->getter)(isolate, receiver, callback->data);
|
| - RETURN_IF_SCHEDULED_EXCEPTION(isolate);
|
| - return value;
|
| + Handle<Foreign>::cast(structure)->foreign_address());
|
| + CALL_HEAP_FUNCTION(isolate,
|
| + (callback->getter)(isolate, *receiver, callback->data),
|
| + Object);
|
| }
|
|
|
| // api style callbacks.
|
| if (structure->IsAccessorInfo()) {
|
| - if (!AccessorInfo::cast(structure)->IsCompatibleReceiver(receiver)) {
|
| - Handle<Object> name_handle(name, isolate);
|
| - Handle<Object> receiver_handle(receiver, isolate);
|
| - Handle<Object> args[2] = { name_handle, receiver_handle };
|
| + Handle<AccessorInfo> accessor_info = Handle<AccessorInfo>::cast(structure);
|
| + if (!accessor_info->IsCompatibleReceiver(*receiver)) {
|
| + Handle<Object> args[2] = { name, receiver };
|
| Handle<Object> error =
|
| isolate->factory()->NewTypeError("incompatible_method_receiver",
|
| HandleVector(args,
|
| ARRAY_SIZE(args)));
|
| - return isolate->Throw(*error);
|
| + isolate->Throw(*error);
|
| + return Handle<Object>::null();
|
| }
|
| // TODO(rossberg): Handling symbols in the API requires changing the API,
|
| // so we do not support it for now.
|
| - if (name->IsSymbol()) return isolate->heap()->undefined_value();
|
| + if (name->IsSymbol()) return isolate->factory()->undefined_value();
|
| if (structure->IsDeclaredAccessorInfo()) {
|
| - return GetDeclaredAccessorProperty(receiver,
|
| - DeclaredAccessorInfo::cast(structure),
|
| - isolate);
|
| + CALL_HEAP_FUNCTION(
|
| + isolate,
|
| + GetDeclaredAccessorProperty(*receiver,
|
| + DeclaredAccessorInfo::cast(*structure),
|
| + isolate),
|
| + Object);
|
| }
|
| - ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(structure);
|
| - Object* fun_obj = data->getter();
|
| +
|
| + Handle<ExecutableAccessorInfo> data =
|
| + Handle<ExecutableAccessorInfo>::cast(structure);
|
| v8::AccessorGetterCallback call_fun =
|
| - v8::ToCData<v8::AccessorGetterCallback>(fun_obj);
|
| - if (call_fun == NULL) return isolate->heap()->undefined_value();
|
| + v8::ToCData<v8::AccessorGetterCallback>(data->getter());
|
| + if (call_fun == NULL) return isolate->factory()->undefined_value();
|
| +
|
| HandleScope scope(isolate);
|
| - JSObject* self = JSObject::cast(receiver);
|
| - Handle<String> key(String::cast(name));
|
| - LOG(isolate, ApiNamedPropertyAccess("load", self, name));
|
| - PropertyCallbackArguments args(isolate, data->data(), self, this);
|
| + Handle<JSObject> self = Handle<JSObject>::cast(receiver);
|
| + Handle<String> key = Handle<String>::cast(name);
|
| + LOG(isolate, ApiNamedPropertyAccess("load", *self, *name));
|
| + PropertyCallbackArguments args(isolate, data->data(), *self, *object);
|
| v8::Handle<v8::Value> result =
|
| args.Call(call_fun, v8::Utils::ToLocal(key));
|
| - RETURN_IF_SCHEDULED_EXCEPTION(isolate);
|
| + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
|
| if (result.IsEmpty()) {
|
| - return isolate->heap()->undefined_value();
|
| + return isolate->factory()->undefined_value();
|
| }
|
| - Object* return_value = *v8::Utils::OpenHandle(*result);
|
| + Handle<Object> return_value = v8::Utils::OpenHandle(*result);
|
| return_value->VerifyApiCallResultType();
|
| - return return_value;
|
| + return scope.CloseAndEscape(return_value);
|
| }
|
|
|
| // __defineGetter__ callback
|
| - if (structure->IsAccessorPair()) {
|
| - Object* getter = AccessorPair::cast(structure)->getter();
|
| - if (getter->IsSpecFunction()) {
|
| - // TODO(rossberg): nicer would be to cast to some JSCallable here...
|
| - return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
|
| - }
|
| - // Getter is not a function.
|
| - return isolate->heap()->undefined_value();
|
| + Handle<Object> getter(Handle<AccessorPair>::cast(structure)->getter(),
|
| + isolate);
|
| + if (getter->IsSpecFunction()) {
|
| + // TODO(rossberg): nicer would be to cast to some JSCallable here...
|
| + CALL_HEAP_FUNCTION(
|
| + isolate,
|
| + object->GetPropertyWithDefinedGetter(*receiver,
|
| + JSReceiver::cast(*getter)),
|
| + Object);
|
| }
|
| -
|
| - UNREACHABLE();
|
| - return NULL;
|
| + // Getter is not a function.
|
| + return isolate->factory()->undefined_value();
|
| }
|
|
|
|
|
| @@ -493,56 +514,51 @@ MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
|
|
|
|
|
| // Only deal with CALLBACKS and INTERCEPTOR
|
| -MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
|
| - Object* receiver,
|
| +Handle<Object> JSObject::GetPropertyWithFailedAccessCheck(
|
| + Handle<JSObject> object,
|
| + Handle<Object> receiver,
|
| LookupResult* result,
|
| - Name* name,
|
| + Handle<Name> name,
|
| PropertyAttributes* attributes) {
|
| + Isolate* isolate = name->GetIsolate();
|
| if (result->IsProperty()) {
|
| switch (result->type()) {
|
| case CALLBACKS: {
|
| // Only allow API accessors.
|
| - Object* obj = result->GetCallbackObject();
|
| - if (obj->IsAccessorInfo()) {
|
| - AccessorInfo* info = AccessorInfo::cast(obj);
|
| - if (info->all_can_read()) {
|
| - *attributes = result->GetAttributes();
|
| - 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);
|
| - }
|
| + Handle<Object> callback_obj(result->GetCallbackObject(), isolate);
|
| + if (callback_obj->IsAccessorInfo()) {
|
| + if (!AccessorInfo::cast(*callback_obj)->all_can_read()) break;
|
| + *attributes = result->GetAttributes();
|
| + // Fall through to GetPropertyWithCallback.
|
| + } else if (callback_obj->IsAccessorPair()) {
|
| + if (!AccessorPair::cast(*callback_obj)->all_can_read()) break;
|
| + // Fall through to GetPropertyWithCallback.
|
| + } else {
|
| + break;
|
| }
|
| - break;
|
| + Handle<JSObject> holder(result->holder(), isolate);
|
| + return GetPropertyWithCallback(holder, receiver, callback_obj, name);
|
| }
|
| case NORMAL:
|
| case FIELD:
|
| case CONSTANT: {
|
| // Search ALL_CAN_READ accessors in prototype chain.
|
| - LookupResult r(GetIsolate());
|
| - result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
|
| + LookupResult r(isolate);
|
| + result->holder()->LookupRealNamedPropertyInPrototypes(*name, &r);
|
| if (r.IsProperty()) {
|
| - return GetPropertyWithFailedAccessCheck(receiver,
|
| - &r,
|
| - name,
|
| - attributes);
|
| + return GetPropertyWithFailedAccessCheck(
|
| + object, receiver, &r, name, attributes);
|
| }
|
| break;
|
| }
|
| case INTERCEPTOR: {
|
| // If the object has an interceptor, try real named properties.
|
| // No access check in GetPropertyAttributeWithInterceptor.
|
| - LookupResult r(GetIsolate());
|
| - result->holder()->LookupRealNamedProperty(name, &r);
|
| + LookupResult r(isolate);
|
| + result->holder()->LookupRealNamedProperty(*name, &r);
|
| if (r.IsProperty()) {
|
| - return GetPropertyWithFailedAccessCheck(receiver,
|
| - &r,
|
| - name,
|
| - attributes);
|
| + return GetPropertyWithFailedAccessCheck(
|
| + object, receiver, &r, name, attributes);
|
| }
|
| break;
|
| }
|
| @@ -553,11 +569,9 @@ MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
|
|
|
| // No accessible property found.
|
| *attributes = ABSENT;
|
| - Heap* heap = name->GetHeap();
|
| - Isolate* isolate = heap->isolate();
|
| - isolate->ReportFailedAccessCheck(this, v8::ACCESS_GET);
|
| - RETURN_IF_SCHEDULED_EXCEPTION(isolate);
|
| - return heap->undefined_value();
|
| + isolate->ReportFailedAccessCheck(*object, v8::ACCESS_GET);
|
| + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
|
| + return isolate->factory()->undefined_value();
|
| }
|
|
|
|
|
| @@ -803,6 +817,7 @@ MaybeObject* Object::GetPropertyOrFail(Handle<Object> object,
|
| }
|
|
|
|
|
| +// TODO(yangguo): handlify this and get rid of.
|
| MaybeObject* Object::GetProperty(Object* receiver,
|
| LookupResult* result,
|
| Name* name,
|
| @@ -841,11 +856,16 @@ MaybeObject* Object::GetProperty(Object* receiver,
|
| // property from the current object, we still check that we have
|
| // access to it.
|
| JSObject* checked = JSObject::cast(current);
|
| - if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
|
| - return checked->GetPropertyWithFailedAccessCheck(receiver,
|
| - result,
|
| - name,
|
| - attributes);
|
| + if (!isolate->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
|
| + HandleScope scope(isolate);
|
| + Handle<Object> value = JSObject::GetPropertyWithFailedAccessCheck(
|
| + handle(checked, isolate),
|
| + handle(receiver, isolate),
|
| + result,
|
| + handle(name, isolate),
|
| + attributes);
|
| + RETURN_IF_EMPTY_HANDLE(isolate, value);
|
| + return *value;
|
| }
|
| }
|
| // Stop traversing the chain once we reach the last object in the
|
| @@ -876,14 +896,28 @@ MaybeObject* Object::GetProperty(Object* receiver,
|
| }
|
| case CONSTANT:
|
| return result->GetConstant();
|
| - case CALLBACKS:
|
| - return result->holder()->GetPropertyWithCallback(
|
| - receiver, result->GetCallbackObject(), name);
|
| + case CALLBACKS: {
|
| + HandleScope scope(isolate);
|
| + Handle<Object> value = JSObject::GetPropertyWithCallback(
|
| + handle(result->holder(), isolate),
|
| + handle(receiver, isolate),
|
| + handle(result->GetCallbackObject(), isolate),
|
| + handle(name, isolate));
|
| + RETURN_IF_EMPTY_HANDLE(isolate, value);
|
| + return *value;
|
| + }
|
| case HANDLER:
|
| return result->proxy()->GetPropertyWithHandler(receiver, name);
|
| - case INTERCEPTOR:
|
| - return result->holder()->GetPropertyWithInterceptor(
|
| - receiver, name, attributes);
|
| + case INTERCEPTOR: {
|
| + HandleScope scope(isolate);
|
| + Handle<Object> value = JSObject::GetPropertyWithInterceptor(
|
| + handle(result->holder(), isolate),
|
| + handle(receiver, isolate),
|
| + handle(name, isolate),
|
| + attributes);
|
| + RETURN_IF_EMPTY_HANDLE(isolate, value);
|
| + return *value;
|
| + }
|
| case TRANSITION:
|
| case NONEXISTENT:
|
| UNREACHABLE();
|
| @@ -1704,6 +1738,9 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
|
| case FIXED_ARRAY_TYPE:
|
| FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
|
| break;
|
| + case CONSTANT_POOL_ARRAY_TYPE:
|
| + reinterpret_cast<ConstantPoolArray*>(this)->ConstantPoolIterateBody(v);
|
| + break;
|
| case FIXED_DOUBLE_ARRAY_TYPE:
|
| break;
|
| case JS_OBJECT_TYPE:
|
| @@ -2100,7 +2137,9 @@ Handle<Object> JSObject::AddProperty(Handle<JSObject> object,
|
| AddSlowProperty(object, name, value, attributes);
|
| }
|
|
|
| - if (FLAG_harmony_observation && object->map()->is_observed()) {
|
| + if (FLAG_harmony_observation &&
|
| + object->map()->is_observed() &&
|
| + *name != isolate->heap()->hidden_string()) {
|
| Handle<Object> old_value = isolate->factory()->the_hole_value();
|
| EnqueueChangeRecord(object, "new", name, old_value);
|
| }
|
| @@ -2251,6 +2290,13 @@ static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) {
|
| MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta);
|
| }
|
| }
|
| +
|
| + // The array may not be moved during GC,
|
| + // and size has to be adjusted nevertheless.
|
| + HeapProfiler* profiler = heap->isolate()->heap_profiler();
|
| + if (profiler->is_tracking_allocations()) {
|
| + profiler->UpdateObjectSizeEvent(elms->address(), elms->Size());
|
| + }
|
| }
|
|
|
|
|
| @@ -2388,6 +2434,16 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) {
|
| }
|
|
|
|
|
| +Handle<TransitionArray> Map::AddTransition(Handle<Map> map,
|
| + Handle<Name> key,
|
| + Handle<Map> target,
|
| + SimpleTransitionFlag flag) {
|
| + CALL_HEAP_FUNCTION(map->GetIsolate(),
|
| + map->AddTransition(*key, *target, flag),
|
| + TransitionArray);
|
| +}
|
| +
|
| +
|
| void JSObject::GeneralizeFieldRepresentation(Handle<JSObject> object,
|
| int modify_index,
|
| Representation new_representation,
|
| @@ -2688,6 +2744,21 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
|
| }
|
|
|
|
|
| +// Generalize the representation of all FIELD descriptors.
|
| +Handle<Map> Map::GeneralizeAllFieldRepresentations(
|
| + Handle<Map> map,
|
| + Representation new_representation) {
|
| + Handle<DescriptorArray> descriptors(map->instance_descriptors());
|
| + for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
|
| + PropertyDetails details = descriptors->GetDetails(i);
|
| + if (details.type() == FIELD) {
|
| + map = GeneralizeRepresentation(map, i, new_representation, FORCE_FIELD);
|
| + }
|
| + }
|
| + return map;
|
| +}
|
| +
|
| +
|
| Map* Map::CurrentMapForDeprecated() {
|
| DisallowHeapAllocation no_allocation;
|
| if (!is_deprecated()) return this;
|
| @@ -3971,8 +4042,10 @@ Handle<Object> JSObject::SetPropertyForResult(Handle<JSObject> object,
|
| }
|
|
|
| Handle<Object> old_value = isolate->factory()->the_hole_value();
|
| - if (FLAG_harmony_observation &&
|
| - object->map()->is_observed() && lookup->IsDataProperty()) {
|
| + bool is_observed = FLAG_harmony_observation &&
|
| + object->map()->is_observed() &&
|
| + *name != isolate->heap()->hidden_string();
|
| + if (is_observed && lookup->IsDataProperty()) {
|
| old_value = Object::GetProperty(object, name);
|
| }
|
|
|
| @@ -4011,7 +4084,7 @@ Handle<Object> JSObject::SetPropertyForResult(Handle<JSObject> object,
|
|
|
| RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<Object>());
|
|
|
| - if (FLAG_harmony_observation && object->map()->is_observed()) {
|
| + if (is_observed) {
|
| if (lookup->IsTransition()) {
|
| EnqueueChangeRecord(object, "new", name, old_value);
|
| } else {
|
| @@ -4112,7 +4185,9 @@ Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
|
|
|
| Handle<Object> old_value = isolate->factory()->the_hole_value();
|
| PropertyAttributes old_attributes = ABSENT;
|
| - bool is_observed = FLAG_harmony_observation && object->map()->is_observed();
|
| + bool is_observed = FLAG_harmony_observation &&
|
| + object->map()->is_observed() &&
|
| + *name != isolate->heap()->hidden_string();
|
| if (is_observed && lookup.IsProperty()) {
|
| if (lookup.IsDataProperty()) old_value =
|
| Object::GetProperty(object, name);
|
| @@ -4398,14 +4473,14 @@ PropertyAttributes JSObject::GetElementAttributeWithoutInterceptor(
|
| Handle<Map> NormalizedMapCache::Get(Handle<NormalizedMapCache> cache,
|
| Handle<JSObject> obj,
|
| PropertyNormalizationMode mode) {
|
| - Map* fast = obj->map();
|
| - int index = fast->Hash() % kEntries;
|
| - Object* result = cache->get(index);
|
| + int index = obj->map()->Hash() % kEntries;
|
| + Handle<Object> result = handle(cache->get(index), cache->GetIsolate());
|
| if (result->IsMap() &&
|
| - Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
|
| + Handle<Map>::cast(result)->EquivalentToForNormalization(obj->map(),
|
| + mode)) {
|
| #ifdef VERIFY_HEAP
|
| if (FLAG_verify_heap) {
|
| - Map::cast(result)->SharedMapVerify();
|
| + Handle<Map>::cast(result)->SharedMapVerify();
|
| }
|
| #endif
|
| #ifdef DEBUG
|
| @@ -4413,27 +4488,25 @@ Handle<Map> NormalizedMapCache::Get(Handle<NormalizedMapCache> cache,
|
| // The cached map should match newly created normalized map bit-by-bit,
|
| // except for the code cache, which can contain some ics which can be
|
| // applied to the shared map.
|
| - Object* fresh;
|
| - MaybeObject* maybe_fresh =
|
| - fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
|
| - if (maybe_fresh->ToObject(&fresh)) {
|
| - ASSERT(memcmp(Map::cast(fresh)->address(),
|
| - Map::cast(result)->address(),
|
| - Map::kCodeCacheOffset) == 0);
|
| - STATIC_ASSERT(Map::kDependentCodeOffset ==
|
| - Map::kCodeCacheOffset + kPointerSize);
|
| - int offset = Map::kDependentCodeOffset + kPointerSize;
|
| - ASSERT(memcmp(Map::cast(fresh)->address() + offset,
|
| - Map::cast(result)->address() + offset,
|
| - Map::kSize - offset) == 0);
|
| - }
|
| + Handle<Map> fresh = Map::CopyNormalized(handle(obj->map()), mode,
|
| + SHARED_NORMALIZED_MAP);
|
| +
|
| + ASSERT(memcmp(fresh->address(),
|
| + Handle<Map>::cast(result)->address(),
|
| + Map::kCodeCacheOffset) == 0);
|
| + STATIC_ASSERT(Map::kDependentCodeOffset ==
|
| + Map::kCodeCacheOffset + kPointerSize);
|
| + int offset = Map::kDependentCodeOffset + kPointerSize;
|
| + ASSERT(memcmp(fresh->address() + offset,
|
| + Handle<Map>::cast(result)->address() + offset,
|
| + Map::kSize - offset) == 0);
|
| }
|
| #endif
|
| - return handle(Map::cast(result));
|
| + return Handle<Map>::cast(result);
|
| }
|
|
|
| Isolate* isolate = cache->GetIsolate();
|
| - Handle<Map> map = Map::CopyNormalized(handle(fast), mode,
|
| + Handle<Map> map = Map::CopyNormalized(handle(obj->map()), mode,
|
| SHARED_NORMALIZED_MAP);
|
| ASSERT(map->is_dictionary_map());
|
| cache->set(index, *map);
|
| @@ -5176,7 +5249,9 @@ Handle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
| }
|
|
|
| Handle<Object> old_value = isolate->factory()->the_hole_value();
|
| - bool is_observed = FLAG_harmony_observation && object->map()->is_observed();
|
| + bool is_observed = FLAG_harmony_observation &&
|
| + object->map()->is_observed() &&
|
| + *name != isolate->heap()->hidden_string();
|
| if (is_observed && lookup.IsDataProperty()) {
|
| old_value = Object::GetProperty(object, name);
|
| }
|
| @@ -5538,37 +5613,42 @@ Handle<Object> JSObject::Freeze(Handle<JSObject> object) {
|
| }
|
|
|
|
|
| -MUST_USE_RESULT MaybeObject* JSObject::SetObserved(Isolate* isolate) {
|
| - if (map()->is_observed())
|
| - return isolate->heap()->undefined_value();
|
| +void JSObject::SetObserved(Handle<JSObject> object) {
|
| + Isolate* isolate = object->GetIsolate();
|
|
|
| - Heap* heap = isolate->heap();
|
| + if (object->map()->is_observed())
|
| + return;
|
|
|
| - if (!HasExternalArrayElements()) {
|
| + if (!object->HasExternalArrayElements()) {
|
| // Go to dictionary mode, so that we don't skip map checks.
|
| - MaybeObject* maybe = NormalizeElements();
|
| - if (maybe->IsFailure()) return maybe;
|
| - ASSERT(!HasFastElements());
|
| + NormalizeElements(object);
|
| + ASSERT(!object->HasFastElements());
|
| }
|
|
|
| LookupResult result(isolate);
|
| - map()->LookupTransition(this, heap->observed_symbol(), &result);
|
| + object->map()->LookupTransition(*object,
|
| + isolate->heap()->observed_symbol(),
|
| + &result);
|
|
|
| - Map* new_map;
|
| + Handle<Map> new_map;
|
| if (result.IsTransition()) {
|
| - new_map = result.GetTransitionTarget();
|
| + new_map = handle(result.GetTransitionTarget());
|
| ASSERT(new_map->is_observed());
|
| - } else if (map()->CanHaveMoreTransitions()) {
|
| - MaybeObject* maybe_new_map = map()->CopyForObserved();
|
| - if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
| + } else if (object->map()->CanHaveMoreTransitions()) {
|
| + new_map = Map::CopyForObserved(handle(object->map()));
|
| } else {
|
| - MaybeObject* maybe_copy = map()->Copy();
|
| - if (!maybe_copy->To(&new_map)) return maybe_copy;
|
| + new_map = Map::Copy(handle(object->map()));
|
| new_map->set_is_observed(true);
|
| }
|
| - set_map(new_map);
|
| + object->set_map(*new_map);
|
| +}
|
|
|
| - return heap->undefined_value();
|
| +
|
| +Handle<JSObject> JSObject::Copy(Handle<JSObject> object,
|
| + Handle<AllocationSite> site) {
|
| + Isolate* isolate = object->GetIsolate();
|
| + CALL_HEAP_FUNCTION(isolate,
|
| + isolate->heap()->CopyJSObject(*object, *site), JSObject);
|
| }
|
|
|
|
|
| @@ -5581,45 +5661,93 @@ Handle<JSObject> JSObject::Copy(Handle<JSObject> object) {
|
|
|
| class JSObjectWalkVisitor {
|
| public:
|
| - explicit JSObjectWalkVisitor() {}
|
| + explicit JSObjectWalkVisitor(AllocationSiteContext* site_context) :
|
| + site_context_(site_context) {}
|
| virtual ~JSObjectWalkVisitor() {}
|
|
|
| Handle<JSObject> Visit(Handle<JSObject> object) {
|
| return StructureWalk(object);
|
| }
|
|
|
| - // Returns true if the visitor is a copying visitor.
|
| virtual bool is_copying() = 0;
|
|
|
| protected:
|
| Handle<JSObject> StructureWalk(Handle<JSObject> object);
|
|
|
| - // The returned handle should point to a new object if the visitor is a
|
| - // copying visitor, otherwise it should be the same as the input object.
|
| + // The returned handle will be used for the object in all subsequent usages.
|
| + // This allows VisitObject to make a copy of the object if desired.
|
| virtual Handle<JSObject> VisitObject(Handle<JSObject> object) = 0;
|
| -
|
| - // The returned handle should point to a new value if the visitor is a
|
| - // copying visitor, otherwise it should be the same as the input value.
|
| virtual Handle<JSObject> VisitElementOrProperty(Handle<JSObject> object,
|
| Handle<JSObject> value) = 0;
|
| +
|
| + AllocationSiteContext* site_context() { return site_context_; }
|
| +
|
| + private:
|
| + AllocationSiteContext* site_context_;
|
| };
|
|
|
|
|
| class JSObjectCopyVisitor: public JSObjectWalkVisitor {
|
| public:
|
| - explicit JSObjectCopyVisitor() {}
|
| + explicit JSObjectCopyVisitor(AllocationSiteContext* site_context)
|
| + : JSObjectWalkVisitor(site_context) {}
|
|
|
| virtual bool is_copying() V8_OVERRIDE { return true; }
|
|
|
| - protected:
|
| + // The returned handle will be used for the object in all
|
| + // subsequent usages. This allows VisitObject to make a copy
|
| + // of the object if desired.
|
| + virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE {
|
| + // Only create a memento if
|
| + // 1) we have a JSArray, and
|
| + // 2) the elements kind is palatable
|
| + // 3) allow_mementos is true
|
| + Handle<JSObject> copy;
|
| + if (site_context()->activated() &&
|
| + AllocationSite::CanTrack(object->map()->instance_type()) &&
|
| + AllocationSite::GetMode(object->GetElementsKind()) ==
|
| + TRACK_ALLOCATION_SITE) {
|
| + copy = JSObject::Copy(object, site_context()->current());
|
| + } else {
|
| + copy = JSObject::Copy(object);
|
| + }
|
| +
|
| + return copy;
|
| + }
|
| +
|
| + virtual Handle<JSObject> VisitElementOrProperty(
|
| + Handle<JSObject> object,
|
| + Handle<JSObject> value) V8_OVERRIDE {
|
| + Handle<AllocationSite> current_site = site_context()->EnterNewScope();
|
| + Handle<JSObject> copy_of_value = StructureWalk(value);
|
| + site_context()->ExitScope(current_site, value);
|
| + return copy_of_value;
|
| + }
|
| +};
|
| +
|
| +
|
| +class JSObjectCreateAllocationSitesVisitor: public JSObjectWalkVisitor {
|
| + public:
|
| + explicit JSObjectCreateAllocationSitesVisitor(
|
| + AllocationSiteContext* site_context)
|
| + : JSObjectWalkVisitor(site_context) {}
|
| +
|
| + virtual bool is_copying() V8_OVERRIDE { return false; }
|
| +
|
| + // The returned handle will be used for the object in all
|
| + // subsequent usages. This allows VisitObject to make a copy
|
| + // of the object if desired.
|
| virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE {
|
| - return JSObject::Copy(object);
|
| + return object;
|
| }
|
|
|
| virtual Handle<JSObject> VisitElementOrProperty(
|
| Handle<JSObject> object,
|
| Handle<JSObject> value) V8_OVERRIDE {
|
| - return StructureWalk(value);
|
| + Handle<AllocationSite> current_site = site_context()->EnterNewScope();
|
| + value = StructureWalk(value);
|
| + site_context()->ExitScope(current_site, value);
|
| + return value;
|
| }
|
| };
|
|
|
| @@ -5766,8 +5894,19 @@ Handle<JSObject> JSObjectWalkVisitor::StructureWalk(Handle<JSObject> object) {
|
| }
|
|
|
|
|
| -Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
|
| - JSObjectCopyVisitor v;
|
| +Handle<JSObject> JSObject::DeepWalk(Handle<JSObject> object,
|
| + AllocationSiteContext* site_context) {
|
| + JSObjectCreateAllocationSitesVisitor v(site_context);
|
| + Handle<JSObject> result = v.Visit(object);
|
| + ASSERT(!v.is_copying() &&
|
| + (result.is_null() || result.is_identical_to(object)));
|
| + return result;
|
| +}
|
| +
|
| +
|
| +Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object,
|
| + AllocationSiteContext* site_context) {
|
| + JSObjectCopyVisitor v(site_context);
|
| Handle<JSObject> copy = v.Visit(object);
|
| ASSERT(v.is_copying() && !copy.is_identical_to(object));
|
| return copy;
|
| @@ -6184,7 +6323,9 @@ void JSObject::DefineAccessor(Handle<JSObject> object,
|
| bool is_element = name->AsArrayIndex(&index);
|
|
|
| Handle<Object> old_value = isolate->factory()->the_hole_value();
|
| - bool is_observed = FLAG_harmony_observation && object->map()->is_observed();
|
| + bool is_observed = FLAG_harmony_observation &&
|
| + object->map()->is_observed() &&
|
| + *name != isolate->heap()->hidden_string();
|
| bool preexists = false;
|
| if (is_observed) {
|
| if (is_element) {
|
| @@ -6439,7 +6580,7 @@ Handle<Object> JSObject::GetAccessor(Handle<JSObject> object,
|
| uint32_t index = 0;
|
| if (name->AsArrayIndex(&index)) {
|
| for (Handle<Object> obj = object;
|
| - *obj != isolate->heap()->null_value();
|
| + !obj->IsNull();
|
| obj = handle(JSReceiver::cast(*obj)->GetPrototype(), isolate)) {
|
| if (obj->IsJSObject() && JSObject::cast(*obj)->HasDictionaryElements()) {
|
| JSObject* js_object = JSObject::cast(*obj);
|
| @@ -6457,7 +6598,7 @@ Handle<Object> JSObject::GetAccessor(Handle<JSObject> object,
|
| }
|
| } else {
|
| for (Handle<Object> obj = object;
|
| - *obj != isolate->heap()->null_value();
|
| + !obj->IsNull();
|
| obj = handle(JSReceiver::cast(*obj)->GetPrototype(), isolate)) {
|
| LookupResult result(isolate);
|
| JSReceiver::cast(*obj)->LocalLookup(*name, &result);
|
| @@ -6506,6 +6647,14 @@ Object* JSObject::SlowReverseLookup(Object* value) {
|
| }
|
|
|
|
|
| +Handle<Map> Map::RawCopy(Handle<Map> map,
|
| + int instance_size) {
|
| + CALL_HEAP_FUNCTION(map->GetIsolate(),
|
| + map->RawCopy(instance_size),
|
| + Map);
|
| +}
|
| +
|
| +
|
| MaybeObject* Map::RawCopy(int instance_size) {
|
| Map* result;
|
| MaybeObject* maybe_result =
|
| @@ -6530,25 +6679,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();
|
| + int new_instance_size = map->instance_size();
|
| if (mode == CLEAR_INOBJECT_PROPERTIES) {
|
| - new_instance_size -= inobject_properties() * kPointerSize;
|
| + new_instance_size -= map->inobject_properties() * kPointerSize;
|
| }
|
|
|
| - Map* result;
|
| - MaybeObject* maybe_result = RawCopy(new_instance_size);
|
| - if (!maybe_result->To(&result)) return maybe_result;
|
| + Handle<Map> result = Map::RawCopy(map, new_instance_size);
|
|
|
| if (mode != CLEAR_INOBJECT_PROPERTIES) {
|
| - result->set_inobject_properties(inobject_properties());
|
| + result->set_inobject_properties(map->inobject_properties());
|
| }
|
|
|
| result->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
|
| @@ -6698,31 +6837,21 @@ MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors,
|
| }
|
|
|
|
|
| +// Since this method is used to rewrite an existing transition tree, it can
|
| +// always insert transitions without checking.
|
| Handle<Map> Map::CopyInstallDescriptors(Handle<Map> map,
|
| int new_descriptor,
|
| Handle<DescriptorArray> descriptors) {
|
| - CALL_HEAP_FUNCTION(map->GetIsolate(),
|
| - map->CopyInstallDescriptors(new_descriptor, *descriptors),
|
| - Map);
|
| -}
|
| -
|
| -
|
| -// Since this method is used to rewrite an existing transition tree, it can
|
| -// always insert transitions without checking.
|
| -MaybeObject* Map::CopyInstallDescriptors(int new_descriptor,
|
| - DescriptorArray* descriptors) {
|
| ASSERT(descriptors->IsSortedNoDuplicates());
|
|
|
| - Map* result;
|
| - MaybeObject* maybe_result = CopyDropDescriptors();
|
| - if (!maybe_result->To(&result)) return maybe_result;
|
| + Handle<Map> result = Map::CopyDropDescriptors(map);
|
|
|
| - result->InitializeDescriptors(descriptors);
|
| + result->InitializeDescriptors(*descriptors);
|
| result->SetNumberOfOwnDescriptors(new_descriptor + 1);
|
|
|
| - int unused_property_fields = this->unused_property_fields();
|
| + int unused_property_fields = map->unused_property_fields();
|
| if (descriptors->GetDetails(new_descriptor).type() == FIELD) {
|
| - unused_property_fields = this->unused_property_fields() - 1;
|
| + unused_property_fields = map->unused_property_fields() - 1;
|
| if (unused_property_fields < 0) {
|
| unused_property_fields += JSObject::kFieldsAdded;
|
| }
|
| @@ -6731,14 +6860,12 @@ MaybeObject* Map::CopyInstallDescriptors(int new_descriptor,
|
| result->set_unused_property_fields(unused_property_fields);
|
| result->set_owns_descriptors(false);
|
|
|
| - Name* name = descriptors->GetKey(new_descriptor);
|
| - TransitionArray* transitions;
|
| - MaybeObject* maybe_transitions =
|
| - AddTransition(name, result, SIMPLE_TRANSITION);
|
| - if (!maybe_transitions->To(&transitions)) return maybe_transitions;
|
| + Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
|
| + Handle<TransitionArray> transitions = Map::AddTransition(map, name, result,
|
| + SIMPLE_TRANSITION);
|
|
|
| - set_transitions(transitions);
|
| - result->SetBackPointer(this);
|
| + map->set_transitions(*transitions);
|
| + result->SetBackPointer(*map);
|
|
|
| return result;
|
| }
|
| @@ -6796,35 +6923,34 @@ MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) {
|
| }
|
|
|
|
|
| -MaybeObject* Map::CopyForObserved() {
|
| - ASSERT(!is_observed());
|
| +Handle<Map> Map::CopyForObserved(Handle<Map> map) {
|
| + ASSERT(!map->is_observed());
|
| +
|
| + Isolate* isolate = map->GetIsolate();
|
|
|
| // In case the map owned its own descriptors, share the descriptors and
|
| // transfer ownership to the new map.
|
| - Map* new_map;
|
| - MaybeObject* maybe_new_map;
|
| - if (owns_descriptors()) {
|
| - maybe_new_map = CopyDropDescriptors();
|
| + Handle<Map> new_map;
|
| + if (map->owns_descriptors()) {
|
| + new_map = Map::CopyDropDescriptors(map);
|
| } else {
|
| - maybe_new_map = Copy();
|
| + new_map = Map::Copy(map);
|
| }
|
| - if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
|
|
| - TransitionArray* transitions;
|
| - MaybeObject* maybe_transitions = AddTransition(GetHeap()->observed_symbol(),
|
| - new_map,
|
| - FULL_TRANSITION);
|
| - if (!maybe_transitions->To(&transitions)) return maybe_transitions;
|
| - set_transitions(transitions);
|
| + Handle<TransitionArray> transitions =
|
| + Map::AddTransition(map, isolate->factory()->observed_symbol(), new_map,
|
| + FULL_TRANSITION);
|
| +
|
| + map->set_transitions(*transitions);
|
|
|
| new_map->set_is_observed(true);
|
|
|
| - if (owns_descriptors()) {
|
| - new_map->InitializeDescriptors(instance_descriptors());
|
| - set_owns_descriptors(false);
|
| + if (map->owns_descriptors()) {
|
| + new_map->InitializeDescriptors(map->instance_descriptors());
|
| + map->set_owns_descriptors(false);
|
| }
|
|
|
| - new_map->SetBackPointer(this);
|
| + new_map->SetBackPointer(*map);
|
| return new_map;
|
| }
|
|
|
| @@ -9266,6 +9392,7 @@ void Map::ClearNonLiveTransitions(Heap* heap) {
|
| if (number_of_own_descriptors > 0) {
|
| TrimDescriptorArray(heap, this, descriptors, number_of_own_descriptors);
|
| ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors);
|
| + set_owns_descriptors(true);
|
| } else {
|
| ASSERT(descriptors == GetHeap()->empty_descriptor_array());
|
| }
|
| @@ -9322,6 +9449,16 @@ bool Map::EquivalentToForNormalization(Map* other,
|
| }
|
|
|
|
|
| +void ConstantPoolArray::ConstantPoolIterateBody(ObjectVisitor* v) {
|
| + int first_ptr_offset = OffsetOfElementAt(first_ptr_index());
|
| + int last_ptr_offset =
|
| + OffsetOfElementAt(first_ptr_index() + count_of_ptr_entries());
|
| + v->VisitPointers(
|
| + HeapObject::RawField(this, first_ptr_offset),
|
| + HeapObject::RawField(this, last_ptr_offset));
|
| +}
|
| +
|
| +
|
| void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
|
| // Iterate over all fields in the body but take care in dealing with
|
| // the code entry.
|
| @@ -10174,7 +10311,7 @@ void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
|
|
|
| void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
|
| Address* p = rinfo->target_reference_address();
|
| - VisitExternalReferences(p, p + 1);
|
| + VisitExternalReference(p);
|
| }
|
|
|
|
|
| @@ -10231,6 +10368,10 @@ void Code::CopyFrom(const CodeDesc& desc) {
|
| } else if (RelocInfo::IsRuntimeEntry(mode)) {
|
| Address p = it.rinfo()->target_runtime_entry(origin);
|
| it.rinfo()->set_target_runtime_entry(p, SKIP_WRITE_BARRIER);
|
| + } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
|
| + Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
|
| + Code* code = Code::cast(*p);
|
| + it.rinfo()->set_code_age_stub(code);
|
| } else {
|
| it.rinfo()->apply(delta);
|
| }
|
| @@ -10468,7 +10609,13 @@ BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
|
|
|
|
|
| void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
|
| - PatchPlatformCodeAge(isolate, sequence, kNoAge, NO_MARKING_PARITY);
|
| + PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge, NO_MARKING_PARITY);
|
| +}
|
| +
|
| +
|
| +void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
|
| + PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge,
|
| + NO_MARKING_PARITY);
|
| }
|
|
|
|
|
| @@ -10489,18 +10636,14 @@ void Code::MakeOlder(MarkingParity current_parity) {
|
|
|
|
|
| bool Code::IsOld() {
|
| - byte* sequence = FindCodeAgeSequence();
|
| - if (sequence == NULL) return false;
|
| - Age age;
|
| - MarkingParity parity;
|
| - GetCodeAgeAndParity(sequence, &age, &parity);
|
| - return age >= kSexagenarianCodeAge;
|
| + Age age = GetAge();
|
| + return age >= kIsOldCodeAge;
|
| }
|
|
|
|
|
| byte* Code::FindCodeAgeSequence() {
|
| return FLAG_age_code &&
|
| - prologue_offset() != kPrologueOffsetNotSet &&
|
| + prologue_offset() != Code::kPrologueOffsetNotSet &&
|
| (kind() == OPTIMIZED_FUNCTION ||
|
| (kind() == FUNCTION && !has_debug_break_slots()))
|
| ? instruction_start() + prologue_offset()
|
| @@ -10508,10 +10651,10 @@ byte* Code::FindCodeAgeSequence() {
|
| }
|
|
|
|
|
| -int Code::GetAge() {
|
| +Code::Age Code::GetAge() {
|
| byte* sequence = FindCodeAgeSequence();
|
| if (sequence == NULL) {
|
| - return Code::kNoAge;
|
| + return Code::kNoAgeCodeAge;
|
| }
|
| Age age;
|
| MarkingParity parity;
|
| @@ -10540,6 +10683,20 @@ void Code::GetCodeAgeAndParity(Code* code, Age* age,
|
| }
|
| CODE_AGE_LIST(HANDLE_CODE_AGE)
|
| #undef HANDLE_CODE_AGE
|
| + stub = *builtins->MarkCodeAsExecutedOnce();
|
| + if (code == stub) {
|
| + // Treat that's never been executed as old immediatly.
|
| + *age = kIsOldCodeAge;
|
| + *parity = NO_MARKING_PARITY;
|
| + return;
|
| + }
|
| + stub = *builtins->MarkCodeAsExecutedTwice();
|
| + if (code == stub) {
|
| + // Pre-age code that has only been executed once.
|
| + *age = kPreAgedCodeAge;
|
| + *parity = NO_MARKING_PARITY;
|
| + return;
|
| + }
|
| UNREACHABLE();
|
| }
|
|
|
| @@ -10556,6 +10713,14 @@ Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
|
| }
|
| CODE_AGE_LIST(HANDLE_CODE_AGE)
|
| #undef HANDLE_CODE_AGE
|
| + case kNotExecutedCodeAge: {
|
| + ASSERT(parity == NO_MARKING_PARITY);
|
| + return *builtins->MarkCodeAsExecutedOnce();
|
| + }
|
| + case kExecutedOnceCodeAge: {
|
| + ASSERT(parity == NO_MARKING_PARITY);
|
| + return *builtins->MarkCodeAsExecutedTwice();
|
| + }
|
| default:
|
| UNREACHABLE();
|
| break;
|
| @@ -12520,6 +12685,20 @@ void JSObject::TransitionElementsKind(Handle<JSObject> object,
|
| }
|
|
|
|
|
| +bool AllocationSite::IsNestedSite() {
|
| + ASSERT(FLAG_trace_track_allocation_sites);
|
| + Object* current = GetHeap()->allocation_sites_list();
|
| + while (current != NULL && current->IsAllocationSite()) {
|
| + AllocationSite* current_site = AllocationSite::cast(current);
|
| + if (current_site->nested_site() == this) {
|
| + return true;
|
| + }
|
| + current = current_site->weak_next();
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +
|
| MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) {
|
| if (!FLAG_track_allocation_sites || !IsJSArray()) {
|
| return this;
|
| @@ -12532,7 +12711,8 @@ MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) {
|
|
|
| // Walk through to the Allocation Site
|
| AllocationSite* site = memento->GetAllocationSite();
|
| - if (site->IsLiteralSite()) {
|
| + if (site->SitePointsToLiteral() &&
|
| + site->transition_info()->IsJSArray()) {
|
| JSArray* transition_info = JSArray::cast(site->transition_info());
|
| ElementsKind kind = transition_info->GetElementsKind();
|
| // if kind is holey ensure that to_kind is as well.
|
| @@ -12546,9 +12726,11 @@ MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) {
|
| CHECK(transition_info->length()->ToArrayIndex(&length));
|
| if (length <= AllocationSite::kMaximumArrayBytesToPretransition) {
|
| if (FLAG_trace_track_allocation_sites) {
|
| + bool is_nested = site->IsNestedSite();
|
| PrintF(
|
| - "AllocationSite: JSArray %p boilerplate updated %s->%s\n",
|
| + "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
|
| reinterpret_cast<void*>(this),
|
| + is_nested ? "(nested)" : "",
|
| ElementsKindToString(kind),
|
| ElementsKindToString(to_kind));
|
| }
|
| @@ -12951,21 +13133,26 @@ InterceptorInfo* JSObject::GetIndexedInterceptor() {
|
| }
|
|
|
|
|
| -MaybeObject* JSObject::GetPropertyPostInterceptor(
|
| - Object* receiver,
|
| - Name* name,
|
| +Handle<Object> JSObject::GetPropertyPostInterceptor(
|
| + Handle<JSObject> object,
|
| + Handle<Object> receiver,
|
| + Handle<Name> name,
|
| PropertyAttributes* attributes) {
|
| // Check local property in holder, ignore interceptor.
|
| - LookupResult result(GetIsolate());
|
| - LocalLookupRealNamedProperty(name, &result);
|
| - if (result.IsFound()) {
|
| - return GetProperty(receiver, &result, name, attributes);
|
| + Isolate* isolate = object->GetIsolate();
|
| + LookupResult lookup(isolate);
|
| + object->LocalLookupRealNamedProperty(*name, &lookup);
|
| + Handle<Object> result;
|
| + if (lookup.IsFound()) {
|
| + result = GetProperty(object, receiver, &lookup, name, attributes);
|
| + } else {
|
| + // Continue searching via the prototype chain.
|
| + Handle<Object> prototype(object->GetPrototype(), isolate);
|
| + *attributes = ABSENT;
|
| + if (prototype->IsNull()) return isolate->factory()->undefined_value();
|
| + result = GetPropertyWithReceiver(prototype, receiver, name, attributes);
|
| }
|
| - // Continue searching via the prototype chain.
|
| - Object* pt = GetPrototype();
|
| - *attributes = ABSENT;
|
| - if (pt->IsNull()) return GetHeap()->undefined_value();
|
| - return pt->GetPropertyWithReceiver(receiver, name, attributes);
|
| + return result;
|
| }
|
|
|
|
|
| @@ -12983,93 +13170,98 @@ MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
|
| }
|
|
|
|
|
| -MaybeObject* JSObject::GetPropertyWithInterceptor(
|
| - Object* receiver,
|
| - Name* name,
|
| +Handle<Object> JSObject::GetPropertyWithInterceptor(
|
| + Handle<JSObject> object,
|
| + Handle<Object> receiver,
|
| + Handle<Name> name,
|
| PropertyAttributes* attributes) {
|
| + Isolate* isolate = object->GetIsolate();
|
| +
|
| // TODO(rossberg): Support symbols in the API.
|
| - if (name->IsSymbol()) return GetHeap()->undefined_value();
|
| + if (name->IsSymbol()) return isolate->factory()->undefined_value();
|
|
|
| - Isolate* isolate = GetIsolate();
|
| - InterceptorInfo* interceptor = GetNamedInterceptor();
|
| - HandleScope scope(isolate);
|
| - Handle<Object> receiver_handle(receiver, isolate);
|
| - Handle<JSObject> holder_handle(this);
|
| - Handle<String> name_handle(String::cast(name));
|
| + Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor(), isolate);
|
| + Handle<String> name_string = Handle<String>::cast(name);
|
|
|
| if (!interceptor->getter()->IsUndefined()) {
|
| v8::NamedPropertyGetterCallback getter =
|
| v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter());
|
| LOG(isolate,
|
| - ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
|
| + ApiNamedPropertyAccess("interceptor-named-get", *object, *name));
|
| PropertyCallbackArguments
|
| - args(isolate, interceptor->data(), receiver, this);
|
| + args(isolate, interceptor->data(), *receiver, *object);
|
| v8::Handle<v8::Value> result =
|
| - args.Call(getter, v8::Utils::ToLocal(name_handle));
|
| - RETURN_IF_SCHEDULED_EXCEPTION(isolate);
|
| + args.Call(getter, v8::Utils::ToLocal(name_string));
|
| + RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
|
| if (!result.IsEmpty()) {
|
| *attributes = NONE;
|
| Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
|
| result_internal->VerifyApiCallResultType();
|
| - return *result_internal;
|
| + // Rebox handle to escape this scope.
|
| + return handle(*result_internal, isolate);
|
| }
|
| }
|
|
|
| - MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
|
| - *receiver_handle,
|
| - *name_handle,
|
| - attributes);
|
| - RETURN_IF_SCHEDULED_EXCEPTION(isolate);
|
| - return result;
|
| + return GetPropertyPostInterceptor(object, receiver, name, attributes);
|
| }
|
|
|
|
|
| -bool JSObject::HasRealNamedProperty(Isolate* isolate, Name* key) {
|
| +bool JSObject::HasRealNamedProperty(Handle<JSObject> object,
|
| + Handle<Name> key) {
|
| + Isolate* isolate = object->GetIsolate();
|
| + SealHandleScope shs(isolate);
|
| // Check access rights if needed.
|
| - if (IsAccessCheckNeeded()) {
|
| - if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
|
| - isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
|
| + if (object->IsAccessCheckNeeded()) {
|
| + if (!isolate->MayNamedAccess(*object, *key, v8::ACCESS_HAS)) {
|
| + isolate->ReportFailedAccessCheck(*object, v8::ACCESS_HAS);
|
| return false;
|
| }
|
| }
|
|
|
| LookupResult result(isolate);
|
| - LocalLookupRealNamedProperty(key, &result);
|
| + object->LocalLookupRealNamedProperty(*key, &result);
|
| return result.IsFound() && !result.IsInterceptor();
|
| }
|
|
|
|
|
| -bool JSObject::HasRealElementProperty(Isolate* isolate, uint32_t index) {
|
| +bool JSObject::HasRealElementProperty(Handle<JSObject> object, uint32_t index) {
|
| + Isolate* isolate = object->GetIsolate();
|
| + SealHandleScope shs(isolate);
|
| // Check access rights if needed.
|
| - if (IsAccessCheckNeeded()) {
|
| - if (!isolate->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
|
| - isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
|
| + if (object->IsAccessCheckNeeded()) {
|
| + if (!isolate->MayIndexedAccess(*object, index, v8::ACCESS_HAS)) {
|
| + isolate->ReportFailedAccessCheck(*object, v8::ACCESS_HAS);
|
| return false;
|
| }
|
| }
|
|
|
| - if (IsJSGlobalProxy()) {
|
| - Object* proto = GetPrototype();
|
| + if (object->IsJSGlobalProxy()) {
|
| + HandleScope scope(isolate);
|
| + Handle<Object> proto(object->GetPrototype(), isolate);
|
| if (proto->IsNull()) return false;
|
| ASSERT(proto->IsJSGlobalObject());
|
| - return JSObject::cast(proto)->HasRealElementProperty(isolate, index);
|
| + return HasRealElementProperty(Handle<JSObject>::cast(proto), index);
|
| }
|
|
|
| - return GetElementAttributeWithoutInterceptor(this, index, false) != ABSENT;
|
| + return object->GetElementAttributeWithoutInterceptor(
|
| + *object, index, false) != ABSENT;
|
| }
|
|
|
|
|
| -bool JSObject::HasRealNamedCallbackProperty(Isolate* isolate, Name* key) {
|
| +bool JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
|
| + Handle<Name> key) {
|
| + Isolate* isolate = object->GetIsolate();
|
| + SealHandleScope shs(isolate);
|
| // Check access rights if needed.
|
| - if (IsAccessCheckNeeded()) {
|
| - if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
|
| - isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
|
| + if (object->IsAccessCheckNeeded()) {
|
| + if (!isolate->MayNamedAccess(*object, *key, v8::ACCESS_HAS)) {
|
| + isolate->ReportFailedAccessCheck(*object, v8::ACCESS_HAS);
|
| return false;
|
| }
|
| }
|
|
|
| LookupResult result(isolate);
|
| - LocalLookupRealNamedProperty(key, &result);
|
| + object->LocalLookupRealNamedProperty(*key, &result);
|
| return result.IsPropertyCallbacks();
|
| }
|
|
|
| @@ -16147,8 +16339,8 @@ void PropertyCell::set_type(Type* type, WriteBarrierMode ignored) {
|
| }
|
|
|
|
|
| -Type* PropertyCell::UpdateType(Handle<PropertyCell> cell,
|
| - Handle<Object> value) {
|
| +Handle<Type> PropertyCell::UpdatedType(Handle<PropertyCell> cell,
|
| + Handle<Object> value) {
|
| Isolate* isolate = cell->GetIsolate();
|
| Handle<Type> old_type(cell->type(), isolate);
|
| // TODO(2803): Do not track ConsString as constant because they cannot be
|
| @@ -16158,42 +16350,27 @@ Type* PropertyCell::UpdateType(Handle<PropertyCell> cell,
|
| : Type::Constant(value, isolate), isolate);
|
|
|
| if (new_type->Is(old_type)) {
|
| - return *old_type;
|
| + return old_type;
|
| }
|
|
|
| cell->dependent_code()->DeoptimizeDependentCodeGroup(
|
| isolate, DependentCode::kPropertyCellChangedGroup);
|
|
|
| if (old_type->Is(Type::None()) || old_type->Is(Type::Undefined())) {
|
| - return *new_type;
|
| + return new_type;
|
| }
|
|
|
| - return Type::Any();
|
| + return handle(Type::Any(), isolate);
|
| }
|
|
|
|
|
| void PropertyCell::SetValueInferType(Handle<PropertyCell> cell,
|
| - Handle<Object> value,
|
| - WriteBarrierMode mode) {
|
| - CALL_HEAP_FUNCTION_VOID(cell->GetIsolate(),
|
| - cell->SetValueInferType(*value, mode));
|
| -}
|
| -
|
| -
|
| -MaybeObject* PropertyCell::SetValueInferType(Object* value,
|
| - WriteBarrierMode ignored) {
|
| - set_value(value, ignored);
|
| - if (!Type::Any()->Is(type())) {
|
| - IdempotentPointerToHandleCodeTrampoline trampoline(GetIsolate());
|
| - MaybeObject* maybe_type = trampoline.CallWithReturnValue(
|
| - &PropertyCell::UpdateType,
|
| - Handle<PropertyCell>(this),
|
| - Handle<Object>(value, GetIsolate()));
|
| - Type* new_type = NULL;
|
| - if (!maybe_type->To(&new_type)) return maybe_type;
|
| - set_type(new_type);
|
| + Handle<Object> value) {
|
| + cell->set_value(*value);
|
| + if (!Type::Any()->Is(cell->type())) {
|
| + Handle<Type> new_type = UpdatedType(cell, value);
|
| + cell->set_type(*new_type);
|
| }
|
| - return value;
|
| }
|
|
|
|
|
|
|