diff options
Diffstat (limited to 'deps/v8/src/runtime/runtime-object.cc')
-rw-r--r-- | deps/v8/src/runtime/runtime-object.cc | 180 |
1 files changed, 114 insertions, 66 deletions
diff --git a/deps/v8/src/runtime/runtime-object.cc b/deps/v8/src/runtime/runtime-object.cc index e38bed3620..8b94d83f31 100644 --- a/deps/v8/src/runtime/runtime-object.cc +++ b/deps/v8/src/runtime/runtime-object.cc @@ -2,17 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "src/arguments-inl.h" -#include "src/bootstrapper.h" -#include "src/counters.h" #include "src/debug/debug.h" +#include "src/execution/arguments-inl.h" +#include "src/execution/isolate-inl.h" +#include "src/execution/message-template.h" #include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop. -#include "src/isolate-inl.h" -#include "src/message-template.h" +#include "src/init/bootstrapper.h" +#include "src/logging/counters.h" #include "src/objects/hash-table-inl.h" #include "src/objects/js-array-inl.h" #include "src/objects/property-descriptor-object.h" -#include "src/property-descriptor.h" +#include "src/objects/property-descriptor.h" #include "src/runtime/runtime-utils.h" #include "src/runtime/runtime.h" @@ -42,8 +42,8 @@ MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, if (is_found_out) *is_found_out = it.IsFound(); if (!it.IsFound() && key->IsSymbol() && - Symbol::cast(*key)->is_private_name()) { - Handle<Object> name_string(Symbol::cast(*key)->name(), isolate); + Symbol::cast(*key).is_private_name()) { + Handle<Object> name_string(Symbol::cast(*key).name(), isolate); DCHECK(name_string->IsString()); THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kInvalidPrivateFieldRead, @@ -81,75 +81,91 @@ namespace { bool DeleteObjectPropertyFast(Isolate* isolate, Handle<JSReceiver> receiver, Handle<Object> raw_key) { - DisallowHeapAllocation no_allocation; // This implements a special case for fast property deletion: when the // last property in an object is deleted, then instead of normalizing // the properties, we can undo the last map transition, with a few // prerequisites: // (1) The receiver must be a regular object and the key a unique name. - Map map = receiver->map(); - if (map->IsSpecialReceiverMap()) return false; + Handle<Map> receiver_map(receiver->map(), isolate); + if (receiver_map->IsSpecialReceiverMap()) return false; if (!raw_key->IsUniqueName()) return false; Handle<Name> key = Handle<Name>::cast(raw_key); // (2) The property to be deleted must be the last property. - int nof = map->NumberOfOwnDescriptors(); + int nof = receiver_map->NumberOfOwnDescriptors(); if (nof == 0) return false; int descriptor = nof - 1; - DescriptorArray descriptors = map->instance_descriptors(); + Handle<DescriptorArray> descriptors(receiver_map->instance_descriptors(), + isolate); if (descriptors->GetKey(descriptor) != *key) return false; // (3) The property to be deleted must be deletable. PropertyDetails details = descriptors->GetDetails(descriptor); if (!details.IsConfigurable()) return false; - // TODO(bmeurer): This optimization is unsound if the property is currently - // marked as constant, as there's no way that we can learn that it is not - // constant when we later follow the same transition again with a different - // value on the same object. As a quick-fix we just disable the optimization - // in case of constant fields. We might want to restructure the code here to - // update the {map} instead and deoptimize all code that depends on it. - if (details.constness() == PropertyConstness::kConst) return false; // (4) The map must have a back pointer. - Object backpointer = map->GetBackPointer(); + Handle<Object> backpointer(receiver_map->GetBackPointer(), isolate); if (!backpointer->IsMap()) return false; + Handle<Map> parent_map = Handle<Map>::cast(backpointer); // (5) The last transition must have been caused by adding a property // (and not any kind of special transition). - if (Map::cast(backpointer)->NumberOfOwnDescriptors() != nof - 1) return false; + if (parent_map->NumberOfOwnDescriptors() != nof - 1) return false; // Preconditions successful. No more bailouts after this point. + // If the {descriptor} was "const" so far, we need to update the + // {receiver_map} here, otherwise we could get the constants wrong, i.e. + // + // o.x = 1; + // delete o.x; + // o.x = 2; + // + // could trick V8 into thinking that `o.x` is still 1 even after the second + // assignment. + if (details.constness() == PropertyConstness::kConst && + details.location() == kField) { + Handle<FieldType> field_type(descriptors->GetFieldType(descriptor), + isolate); + Map::GeneralizeField(isolate, receiver_map, descriptor, + PropertyConstness::kMutable, details.representation(), + field_type); + DCHECK_EQ(PropertyConstness::kMutable, + descriptors->GetDetails(descriptor).constness()); + } + // Zap the property to avoid keeping objects alive. Zapping is not necessary // for properties stored in the descriptor array. if (details.location() == kField) { - isolate->heap()->NotifyObjectLayoutChange(*receiver, map->instance_size(), - no_allocation); - FieldIndex index = FieldIndex::ForPropertyIndex(map, details.field_index()); + DisallowHeapAllocation no_allocation; + isolate->heap()->NotifyObjectLayoutChange( + *receiver, receiver_map->instance_size(), no_allocation); + FieldIndex index = + FieldIndex::ForPropertyIndex(*receiver_map, details.field_index()); // Special case deleting the last out-of object property. if (!index.is_inobject() && index.outobject_array_index() == 0) { - DCHECK(!Map::cast(backpointer)->HasOutOfObjectProperties()); + DCHECK(!parent_map->HasOutOfObjectProperties()); // Clear out the properties backing store. receiver->SetProperties(ReadOnlyRoots(isolate).empty_fixed_array()); } else { Object filler = ReadOnlyRoots(isolate).one_pointer_filler_map(); - JSObject::cast(*receiver)->RawFastPropertyAtPut(index, filler); + JSObject::cast(*receiver).RawFastPropertyAtPut(index, filler); // We must clear any recorded slot for the deleted property, because // subsequent object modifications might put a raw double there. // Slot clearing is the reason why this entire function cannot currently // be implemented in the DeleteProperty stub. - if (index.is_inobject() && !map->IsUnboxedDoubleField(index)) { + if (index.is_inobject() && !receiver_map->IsUnboxedDoubleField(index)) { isolate->heap()->ClearRecordedSlot(*receiver, receiver->RawField(index.offset())); } } } - // If the map was marked stable before, then there could be optimized code - // that depends on the assumption that no object that reached this map - // transitions away from it without triggering the "deoptimize dependent - // code" mechanism. - map->NotifyLeafMapLayoutChange(isolate); + // If the {receiver_map} was marked stable before, then there could be + // optimized code that depends on the assumption that no object that + // reached this {receiver_map} transitions away from it without triggering + // the "deoptimize dependent code" mechanism. + receiver_map->NotifyLeafMapLayoutChange(isolate); // Finally, perform the map rollback. - receiver->synchronized_set_map(Map::cast(backpointer)); + receiver->synchronized_set_map(*parent_map); #if VERIFY_HEAP receiver->HeapObjectVerify(isolate); - receiver->property_array()->PropertyArrayVerify(isolate); + receiver->property_array().PropertyArrayVerify(isolate); #endif return true; } @@ -288,9 +304,9 @@ RUNTIME_FUNCTION(Runtime_ObjectHasOwnProperty) { } Map map = js_obj->map(); - if (!map->has_hidden_prototype() && - (key_is_array_index ? !map->has_indexed_interceptor() - : !map->has_named_interceptor())) { + if (!map.has_hidden_prototype() && + (key_is_array_index ? !map.has_indexed_interceptor() + : !map.has_named_interceptor())) { return ReadOnlyRoots(isolate).false_value(); } @@ -319,7 +335,7 @@ RUNTIME_FUNCTION(Runtime_ObjectHasOwnProperty) { } else if (object->IsString()) { return isolate->heap()->ToBoolean( key_is_array_index - ? index < static_cast<uint32_t>(String::cast(*object)->length()) + ? index < static_cast<uint32_t>(String::cast(*object).length()) : key->Equals(ReadOnlyRoots(isolate).length_string())); } else if (object->IsNullOrUndefined(isolate)) { THROW_NEW_ERROR_RETURN_FAILURE( @@ -391,8 +407,8 @@ MaybeHandle<Object> Runtime::SetObjectProperty( if (!success) return MaybeHandle<Object>(); if (!it.IsFound() && key->IsSymbol() && - Symbol::cast(*key)->is_private_name()) { - Handle<Object> name_string(Symbol::cast(*key)->name(), isolate); + Symbol::cast(*key).is_private_name()) { + Handle<Object> name_string(Symbol::cast(*key).name(), isolate); DCHECK(name_string->IsString()); THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kInvalidPrivateFieldWrite, @@ -507,7 +523,7 @@ RUNTIME_FUNCTION(Runtime_GetProperty) { // Convert string-index keys to their number variant to avoid internalization // below; and speed up subsequent conversion to index. uint32_t index; - if (key_obj->IsString() && String::cast(*key_obj)->AsArrayIndex(&index)) { + if (key_obj->IsString() && String::cast(*key_obj).AsArrayIndex(&index)) { key_obj = isolate->factory()->NewNumberFromUint(index); } if (receiver_obj->IsJSObject()) { @@ -521,23 +537,23 @@ RUNTIME_FUNCTION(Runtime_GetProperty) { if (receiver->IsJSGlobalObject()) { // Attempt dictionary lookup. GlobalDictionary dictionary = - JSGlobalObject::cast(*receiver)->global_dictionary(); - int entry = dictionary->FindEntry(isolate, key); + JSGlobalObject::cast(*receiver).global_dictionary(); + int entry = dictionary.FindEntry(isolate, key); if (entry != GlobalDictionary::kNotFound) { - PropertyCell cell = dictionary->CellAt(entry); - if (cell->property_details().kind() == kData) { - Object value = cell->value(); - if (!value->IsTheHole(isolate)) return value; + PropertyCell cell = dictionary.CellAt(entry); + if (cell.property_details().kind() == kData) { + Object value = cell.value(); + if (!value.IsTheHole(isolate)) return value; // If value is the hole (meaning, absent) do the general lookup. } } } else if (!receiver->HasFastProperties()) { // Attempt dictionary lookup. NameDictionary dictionary = receiver->property_dictionary(); - int entry = dictionary->FindEntry(isolate, key); + int entry = dictionary.FindEntry(isolate, key); if ((entry != NameDictionary::kNotFound) && - (dictionary->DetailsAt(entry).kind() == kData)) { - return dictionary->ValueAt(entry); + (dictionary.DetailsAt(entry).kind() == kData)) { + return dictionary.ValueAt(entry); } } } else if (key_obj->IsSmi()) { @@ -550,7 +566,7 @@ RUNTIME_FUNCTION(Runtime_GetProperty) { Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj); ElementsKind elements_kind = js_object->GetElementsKind(); if (IsDoubleElementsKind(elements_kind)) { - if (Smi::ToInt(*key_obj) >= js_object->elements()->length()) { + if (Smi::ToInt(*key_obj) >= js_object->elements().length()) { elements_kind = IsHoleyElementsKind(elements_kind) ? HOLEY_ELEMENTS : PACKED_ELEMENTS; JSObject::TransitionElementsKind(js_object, elements_kind); @@ -737,6 +753,15 @@ RUNTIME_FUNCTION(Runtime_NewObject) { JSObject::New(target, new_target, Handle<AllocationSite>::null())); } +RUNTIME_FUNCTION(Runtime_GetDerivedMap) { + HandleScope scope(isolate); + DCHECK_EQ(2, args.length()); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0); + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, 1); + RETURN_RESULT_OR_FAILURE( + isolate, JSFunction::GetDerivedMap(isolate, target, new_target)); +} + RUNTIME_FUNCTION(Runtime_CompleteInobjectSlackTrackingForMap) { DisallowHeapAllocation no_gc; HandleScope scope(isolate); @@ -756,7 +781,7 @@ RUNTIME_FUNCTION(Runtime_TryMigrateInstance) { if (!object->IsJSObject()) return Smi::kZero; Handle<JSObject> js_object = Handle<JSObject>::cast(object); // It could have been a DCHECK but we call this function directly from tests. - if (!js_object->map()->is_deprecated()) return Smi::kZero; + if (!js_object->map().is_deprecated()) return Smi::kZero; // This call must not cause lazy deopts, because it's called from deferred // code where we can't handle lazy deopts for lack of a suitable bailout // ID. So we just try migration and signal failure if necessary, @@ -834,14 +859,14 @@ RUNTIME_FUNCTION(Runtime_DefineDataPropertyInLiteral) { if (flags & DataPropertyInLiteralFlag::kSetFunctionName) { DCHECK(value->IsJSFunction()); Handle<JSFunction> function = Handle<JSFunction>::cast(value); - DCHECK(!function->shared()->HasSharedName()); + DCHECK(!function->shared().HasSharedName()); Handle<Map> function_map(function->map(), isolate); if (!JSFunction::SetName(function, name, isolate->factory()->empty_string())) { return ReadOnlyRoots(isolate).exception(); } // Class constructors do not reserve in-object space for name field. - CHECK_IMPLIES(!IsClassConstructor(function->shared()->kind()), + CHECK_IMPLIES(!IsClassConstructor(function->shared().kind()), *function_map == function->map()); } @@ -872,7 +897,7 @@ RUNTIME_FUNCTION(Runtime_CollectTypeProfile) { type = Handle<String>(ReadOnlyRoots(isolate).null_string(), isolate); } - DCHECK(vector->metadata()->HasTypeProfileSlot()); + DCHECK(vector->metadata().HasTypeProfileSlot()); FeedbackNexus nexus(vector, vector->GetTypeProfileSlot()); nexus.Collect(type, position->value()); @@ -884,7 +909,7 @@ RUNTIME_FUNCTION(Runtime_HasFastPackedElements) { DCHECK_EQ(1, args.length()); CONVERT_ARG_CHECKED(HeapObject, obj, 0); return isolate->heap()->ToBoolean( - IsFastPackedElementsKind(obj->map()->elements_kind())); + IsFastPackedElementsKind(obj.map().elements_kind())); } @@ -892,7 +917,7 @@ RUNTIME_FUNCTION(Runtime_IsJSReceiver) { SealHandleScope shs(isolate); DCHECK_EQ(1, args.length()); CONVERT_ARG_CHECKED(Object, obj, 0); - return isolate->heap()->ToBoolean(obj->IsJSReceiver()); + return isolate->heap()->ToBoolean(obj.IsJSReceiver()); } @@ -900,8 +925,8 @@ RUNTIME_FUNCTION(Runtime_ClassOf) { SealHandleScope shs(isolate); DCHECK_EQ(1, args.length()); CONVERT_ARG_CHECKED(Object, obj, 0); - if (!obj->IsJSReceiver()) return ReadOnlyRoots(isolate).null_value(); - return JSReceiver::cast(obj)->class_name(); + if (!obj.IsJSReceiver()) return ReadOnlyRoots(isolate).null_value(); + return JSReceiver::cast(obj).class_name(); } RUNTIME_FUNCTION(Runtime_GetFunctionName) { @@ -919,7 +944,7 @@ RUNTIME_FUNCTION(Runtime_DefineGetterPropertyUnchecked) { CONVERT_ARG_HANDLE_CHECKED(JSFunction, getter, 2); CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); - if (String::cast(getter->shared()->Name())->length() == 0) { + if (String::cast(getter->shared().Name()).length() == 0) { Handle<Map> getter_map(getter->map(), isolate); if (!JSFunction::SetName(getter, name, isolate->factory()->get_string())) { return ReadOnlyRoots(isolate).exception(); @@ -986,7 +1011,7 @@ RUNTIME_FUNCTION(Runtime_CopyDataPropertiesWithExcludedProperties) { // instead because of our call to %ToName() in the desugaring for // computed properties. if (property->IsString() && - String::cast(*property)->AsArrayIndex(&property_num)) { + String::cast(*property).AsArrayIndex(&property_num)) { property = isolate->factory()->NewNumberFromUint(property_num); } @@ -1009,7 +1034,7 @@ RUNTIME_FUNCTION(Runtime_DefineSetterPropertyUnchecked) { CONVERT_ARG_HANDLE_CHECKED(JSFunction, setter, 2); CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); - if (String::cast(setter->shared()->Name())->length() == 0) { + if (String::cast(setter->shared().Name()).length() == 0) { Handle<Map> setter_map(setter->map(), isolate); if (!JSFunction::SetName(setter, name, isolate->factory()->set_string())) { return ReadOnlyRoots(isolate).exception(); @@ -1052,15 +1077,13 @@ RUNTIME_FUNCTION(Runtime_ToLength) { RETURN_RESULT_OR_FAILURE(isolate, Object::ToLength(isolate, input)); } - -RUNTIME_FUNCTION(Runtime_ToString) { +RUNTIME_FUNCTION(Runtime_ToStringRT) { HandleScope scope(isolate); DCHECK_EQ(1, args.length()); CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); RETURN_RESULT_OR_FAILURE(isolate, Object::ToString(isolate, input)); } - RUNTIME_FUNCTION(Runtime_ToName) { HandleScope scope(isolate); DCHECK_EQ(1, args.length()); @@ -1122,6 +1145,31 @@ RUNTIME_FUNCTION(Runtime_GetOwnPropertyDescriptor) { return *desc.ToPropertyDescriptorObject(isolate); } +RUNTIME_FUNCTION(Runtime_AddPrivateBrand) { + HandleScope scope(isolate); + DCHECK_EQ(args.length(), 2); + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); + CONVERT_ARG_HANDLE_CHECKED(Symbol, brand, 1); + DCHECK(brand->is_private_name()); + + LookupIterator it = LookupIterator::PropertyOrElement( + isolate, receiver, brand, LookupIterator::OWN); + + if (it.IsFound()) { + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, NewTypeError(MessageTemplate::kVarRedeclaration, brand)); + } + + PropertyAttributes attributes = + static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY); + // TODO(joyee): we could use this slot to store something useful. For now, + // store the brand itself. + CHECK(Object::AddDataProperty(&it, brand, attributes, Just(kDontThrow), + StoreOrigin::kMaybeKeyed) + .FromJust()); + return *receiver; +} + RUNTIME_FUNCTION(Runtime_AddPrivateField) { HandleScope scope(isolate); DCHECK_EQ(3, args.length()); |