aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/runtime/runtime-object.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/runtime/runtime-object.cc')
-rw-r--r--deps/v8/src/runtime/runtime-object.cc180
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());