Merge V8 5.2.361.47 DO NOT MERGE
https://chromium.googlesource.com/v8/v8/+/5.2.361.47
FPIIM-449
Change-Id: Ibec421b85a9b88cb3a432ada642e469fe7e78346
(cherry picked from commit bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8)
diff --git a/src/objects.cc b/src/objects.cc
index 1a82c3c..addf97a 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -12,9 +12,9 @@
#include "src/accessors.h"
#include "src/allocation-site-scopes.h"
-#include "src/api.h"
#include "src/api-arguments.h"
#include "src/api-natives.h"
+#include "src/api.h"
#include "src/base/bits.h"
#include "src/base/utils/random-number-generator.h"
#include "src/bootstrapper.h"
@@ -22,6 +22,8 @@
#include "src/codegen.h"
#include "src/compilation-dependencies.h"
#include "src/compiler.h"
+#include "src/counters-inl.h"
+#include "src/counters.h"
#include "src/date.h"
#include "src/debug/debug.h"
#include "src/deoptimizer.h"
@@ -30,6 +32,7 @@
#include "src/field-index-inl.h"
#include "src/field-index.h"
#include "src/field-type.h"
+#include "src/frames-inl.h"
#include "src/full-codegen/full-codegen.h"
#include "src/ic/ic.h"
#include "src/identity-map.h"
@@ -122,7 +125,7 @@
if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
if (*object == isolate->heap()->null_value() ||
*object == isolate->heap()->undefined_value()) {
- return handle(isolate->global_proxy(), isolate);
+ return isolate->global_proxy();
}
return Object::ToObject(isolate, object);
}
@@ -568,6 +571,88 @@
NumberToInt32(*rhs));
}
+// static
+MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate,
+ Handle<Object> callable,
+ Handle<Object> object) {
+ // The {callable} must have a [[Call]] internal method.
+ if (!callable->IsCallable()) return isolate->factory()->false_value();
+
+ // Check if {callable} is a bound function, and if so retrieve its
+ // [[BoundTargetFunction]] and use that instead of {callable}.
+ if (callable->IsJSBoundFunction()) {
+ Handle<Object> bound_callable(
+ Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
+ isolate);
+ return Object::InstanceOf(isolate, object, bound_callable);
+ }
+
+ // If {object} is not a receiver, return false.
+ if (!object->IsJSReceiver()) return isolate->factory()->false_value();
+
+ // Get the "prototype" of {callable}; raise an error if it's not a receiver.
+ Handle<Object> prototype;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, prototype,
+ Object::GetProperty(callable, isolate->factory()->prototype_string()),
+ Object);
+ if (!prototype->IsJSReceiver()) {
+ THROW_NEW_ERROR(
+ isolate,
+ NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype),
+ Object);
+ }
+
+ // Return whether or not {prototype} is in the prototype chain of {object}.
+ Maybe<bool> result = JSReceiver::HasInPrototypeChain(
+ isolate, Handle<JSReceiver>::cast(object), prototype);
+ if (result.IsNothing()) return MaybeHandle<Object>();
+ return isolate->factory()->ToBoolean(result.FromJust());
+}
+
+// static
+MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object,
+ Handle<Object> callable) {
+ if (FLAG_harmony_instanceof) {
+ // The {callable} must be a receiver.
+ if (!callable->IsJSReceiver()) {
+ THROW_NEW_ERROR(
+ isolate, NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck),
+ Object);
+ }
+
+ // Lookup the @@hasInstance method on {callable}.
+ Handle<Object> inst_of_handler;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, inst_of_handler,
+ JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable),
+ isolate->factory()->has_instance_symbol()),
+ Object);
+ if (!inst_of_handler->IsUndefined()) {
+ // Call the {inst_of_handler} on the {callable}.
+ Handle<Object> result;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, result,
+ Execution::Call(isolate, inst_of_handler, callable, 1, &object),
+ Object);
+ return isolate->factory()->ToBoolean(result->BooleanValue());
+ }
+ }
+
+ // The {callable} must have a [[Call]] internal method.
+ if (!callable->IsCallable()) {
+ THROW_NEW_ERROR(
+ isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck),
+ Object);
+ }
+
+ // Fall back to OrdinaryHasInstance with {callable} and {object}.
+ Handle<Object> result;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, result,
+ JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object);
+ return result;
+}
Maybe<bool> Object::IsArray(Handle<Object> object) {
if (object->IsJSArray()) return Just(true);
@@ -594,7 +679,7 @@
auto isolate = js_object->GetIsolate();
// TODO(dcarney): this should just be read from the symbol registry so as not
// to be context dependent.
- auto key = isolate->factory()->promise_status_symbol();
+ auto key = isolate->factory()->promise_state_symbol();
// Shouldn't be possible to throw here.
return JSObject::HasRealNamedProperty(js_object, key).FromJust();
}
@@ -762,17 +847,6 @@
}
-#define STACK_CHECK(result_value) \
- do { \
- StackLimitCheck stack_check(isolate); \
- if (stack_check.HasOverflowed()) { \
- isolate->Throw(*isolate->factory()->NewRangeError( \
- MessageTemplate::kStackOverflow)); \
- return result_value; \
- } \
- } while (false)
-
-
// static
MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
Handle<JSProxy> proxy,
@@ -788,7 +862,7 @@
}
DCHECK(!name->IsPrivate());
- STACK_CHECK(MaybeHandle<Object>());
+ STACK_CHECK(isolate, MaybeHandle<Object>());
Handle<Name> trap_name = isolate->factory()->get_string();
// 1. Assert: IsPropertyKey(P) is true.
// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
@@ -1001,7 +1075,7 @@
Isolate* isolate = proxy->GetIsolate();
Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
- STACK_CHECK(MaybeHandle<Object>());
+ STACK_CHECK(isolate, MaybeHandle<Object>());
// 1. Let handler be the value of the [[ProxyHandler]] internal slot.
// 2. If handler is null, throw a TypeError exception.
@@ -1117,6 +1191,20 @@
return ReadAbsentProperty(isolate, receiver, it->GetName());
}
+// static
+Address AccessorInfo::redirect(Isolate* isolate, Address address,
+ AccessorComponent component) {
+ ApiFunction fun(address);
+ DCHECK_EQ(ACCESSOR_GETTER, component);
+ ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
+ return ExternalReference(&fun, type, isolate).address();
+}
+
+Address AccessorInfo::redirected_getter() const {
+ Address accessor = v8::ToCData<Address>(getter());
+ if (accessor == nullptr) return nullptr;
+ return redirect(GetIsolate(), accessor, ACCESSOR_GETTER);
+}
bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate,
Handle<AccessorInfo> info,
@@ -1383,6 +1471,7 @@
}
}
+// static
Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
Handle<JSReceiver> object,
Handle<Object> proto) {
@@ -1396,7 +1485,6 @@
}
}
-
Map* Object::GetRootMap(Isolate* isolate) {
DisallowHeapAllocation no_alloc;
if (IsSmi()) {
@@ -1555,7 +1643,6 @@
MaybeHandle<Object> Object::ArraySpeciesConstructor(
Isolate* isolate, Handle<Object> original_array) {
- Handle<Context> native_context = isolate->native_context();
Handle<Object> default_species = isolate->array_function();
if (!FLAG_harmony_species) {
return default_species;
@@ -1580,7 +1667,7 @@
isolate, constructor_context,
JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
Object);
- if (*constructor_context != *native_context &&
+ if (*constructor_context != *isolate->native_context() &&
*constructor == constructor_context->array_function()) {
constructor = isolate->factory()->undefined_value();
}
@@ -1905,15 +1992,7 @@
}
case JS_BOUND_FUNCTION_TYPE: {
JSBoundFunction* bound_function = JSBoundFunction::cast(this);
- Object* name = bound_function->name();
accumulator->Add("<JS BoundFunction");
- if (name->IsString()) {
- String* str = String::cast(name);
- if (str->length() > 0) {
- accumulator->Add(" ");
- accumulator->Put(str);
- }
- }
accumulator->Add(
" (BoundTargetFunction %p)>",
reinterpret_cast<void*>(bound_function->bound_target_function()));
@@ -1946,6 +2025,18 @@
if (!printed) {
accumulator->Add("<JS Function");
}
+ if (FLAG_trace_file_names) {
+ Object* source_name =
+ Script::cast(function->shared()->script())->name();
+ if (source_name->IsString()) {
+ String* str = String::cast(source_name);
+ if (str->length() > 0) {
+ accumulator->Add(" <");
+ accumulator->Put(str);
+ accumulator->Add(">");
+ }
+ }
+ }
accumulator->Add(" (SharedFunctionInfo %p)",
reinterpret_cast<void*>(function->shared()));
accumulator->Put('>');
@@ -2227,7 +2318,9 @@
} else if (IsFalse()) {
os << "<false>";
} else {
- os << "<Odd Oddball>";
+ os << "<Odd Oddball: ";
+ os << Oddball::cast(this)->to_string()->ToCString().get();
+ os << ">";
}
break;
}
@@ -2644,24 +2737,6 @@
}
-MaybeHandle<Object> JSObject::EnqueueChangeRecord(Handle<JSObject> object,
- const char* type_str,
- Handle<Name> name,
- Handle<Object> old_value) {
- DCHECK(!object->IsJSGlobalProxy());
- DCHECK(!object->IsJSGlobalObject());
- Isolate* isolate = object->GetIsolate();
- HandleScope scope(isolate);
- Handle<String> type = isolate->factory()->InternalizeUtf8String(type_str);
- Handle<Object> args[] = { type, object, name, old_value };
- int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4;
-
- return Execution::Call(isolate,
- Handle<JSFunction>(isolate->observers_notify_change()),
- isolate->factory()->undefined_value(), argc, args);
-}
-
-
const char* Representation::Mnemonic() const {
switch (kind_) {
case kNone: return "v";
@@ -2677,6 +2752,16 @@
}
}
+bool Map::InstancesNeedRewriting(Map* target) {
+ int target_number_of_fields = target->NumberOfFields();
+ int target_inobject = target->GetInObjectProperties();
+ int target_unused = target->unused_property_fields();
+ int old_number_of_fields;
+
+ return InstancesNeedRewriting(target, target_number_of_fields,
+ target_inobject, target_unused,
+ &old_number_of_fields);
+}
bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
int target_inobject, int target_unused,
@@ -3137,10 +3222,10 @@
return result;
}
-
Handle<Map> Map::CopyGeneralizeAllRepresentations(
- Handle<Map> map, int modify_index, StoreMode store_mode, PropertyKind kind,
- PropertyAttributes attributes, const char* reason) {
+ Handle<Map> map, ElementsKind elements_kind, int modify_index,
+ StoreMode store_mode, PropertyKind kind, PropertyAttributes attributes,
+ const char* reason) {
Isolate* isolate = map->GetIsolate();
Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
int number_of_own_descriptors = map->NumberOfOwnDescriptors();
@@ -3196,6 +3281,7 @@
MaybeHandle<Object>());
}
}
+ new_map->set_elements_kind(elements_kind);
return new_map;
}
@@ -3448,9 +3534,9 @@
}
}
-
-// Reconfigures property at |modify_index| with |new_kind|, |new_attributes|,
-// |store_mode| and/or |new_representation|/|new_field_type|.
+// Reconfigures elements kind to |new_elements_kind| and/or property at
+// |modify_index| with |new_kind|, |new_attributes|, |store_mode| and/or
+// |new_representation|/|new_field_type|.
// If |modify_index| is negative then no properties are reconfigured but the
// map is migrated to the up-to-date non-deprecated state.
//
@@ -3460,6 +3546,7 @@
// any potential new (partial) version of the type in the transition tree.
// To do this, on each rewrite:
// - Search the root of the transition tree using FindRootMap.
+// - Find/create a |root_map| with requested |new_elements_kind|.
// - Find |target_map|, the newest matching version of this map using the
// virtually "enhanced" |old_map|'s descriptor array (i.e. whose entry at
// |modify_index| is considered to be of |new_kind| and having
@@ -3475,12 +3562,13 @@
// Return it.
// - Otherwise, invalidate the outdated transition target from |target_map|, and
// replace its transition tree with a new branch for the updated descriptors.
-Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
- PropertyKind new_kind,
- PropertyAttributes new_attributes,
- Representation new_representation,
- Handle<FieldType> new_field_type,
- StoreMode store_mode) {
+Handle<Map> Map::Reconfigure(Handle<Map> old_map,
+ ElementsKind new_elements_kind, int modify_index,
+ PropertyKind new_kind,
+ PropertyAttributes new_attributes,
+ Representation new_representation,
+ Handle<FieldType> new_field_type,
+ StoreMode store_mode) {
DCHECK_NE(kAccessor, new_kind); // TODO(ishell): not supported yet.
DCHECK(store_mode != FORCE_FIELD || modify_index >= 0);
Isolate* isolate = old_map->GetIsolate();
@@ -3495,7 +3583,8 @@
// uninitialized value for representation None can be overwritten by both
// smi and tagged values. Doubles, however, would require a box allocation.
if (modify_index >= 0 && !new_representation.IsNone() &&
- !new_representation.IsDouble()) {
+ !new_representation.IsDouble() &&
+ old_map->elements_kind() == new_elements_kind) {
PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
Representation old_representation = old_details.representation();
@@ -3528,38 +3617,39 @@
// Check the state of the root map.
Handle<Map> root_map(old_map->FindRootMap(), isolate);
if (!old_map->EquivalentToForTransition(*root_map)) {
- return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
- new_kind, new_attributes,
- "GenAll_NotEquivalent");
+ return CopyGeneralizeAllRepresentations(
+ old_map, new_elements_kind, modify_index, store_mode, new_kind,
+ new_attributes, "GenAll_NotEquivalent");
}
ElementsKind from_kind = root_map->elements_kind();
- ElementsKind to_kind = old_map->elements_kind();
+ ElementsKind to_kind = new_elements_kind;
// TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
+ to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
!(IsTransitionableFastElementsKind(from_kind) &&
IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
- return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
- new_kind, new_attributes,
- "GenAll_InvalidElementsTransition");
+ return CopyGeneralizeAllRepresentations(
+ old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
+ "GenAll_InvalidElementsTransition");
}
int root_nof = root_map->NumberOfOwnDescriptors();
if (modify_index >= 0 && modify_index < root_nof) {
PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
if (old_details.kind() != new_kind ||
old_details.attributes() != new_attributes) {
- return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
- new_kind, new_attributes,
- "GenAll_RootModification1");
+ return CopyGeneralizeAllRepresentations(
+ old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
+ "GenAll_RootModification1");
}
if ((old_details.type() != DATA && store_mode == FORCE_FIELD) ||
(old_details.type() == DATA &&
(!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) ||
!new_representation.fits_into(old_details.representation())))) {
- return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
- new_kind, new_attributes,
- "GenAll_RootModification2");
+ return CopyGeneralizeAllRepresentations(
+ old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
+ "GenAll_RootModification2");
}
}
@@ -3613,9 +3703,9 @@
if (next_kind == kAccessor &&
!EqualImmutableValues(old_descriptors->GetValue(i),
tmp_descriptors->GetValue(i))) {
- return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
- new_kind, new_attributes,
- "GenAll_Incompatible");
+ return CopyGeneralizeAllRepresentations(
+ old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
+ "GenAll_Incompatible");
}
if (next_location == kField && tmp_details.location() == kDescriptor) break;
@@ -3708,9 +3798,9 @@
if (next_kind == kAccessor &&
!EqualImmutableValues(old_descriptors->GetValue(i),
tmp_descriptors->GetValue(i))) {
- return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
- new_kind, new_attributes,
- "GenAll_Incompatible");
+ return CopyGeneralizeAllRepresentations(
+ old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
+ "GenAll_Incompatible");
}
DCHECK(!tmp_map->is_deprecated());
target_map = tmp_map;
@@ -3941,9 +4031,9 @@
// could be inserted regardless of whether transitions array is full or not.
if (maybe_transition == NULL &&
!TransitionArray::CanHaveMoreTransitions(split_map)) {
- return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
- new_kind, new_attributes,
- "GenAll_CantHaveMoreTransitions");
+ return CopyGeneralizeAllRepresentations(
+ old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
+ "GenAll_CantHaveMoreTransitions");
}
old_map->NotifyLeafMapLayoutChange();
@@ -4024,18 +4114,27 @@
if (root_map == NULL) return MaybeHandle<Map>();
// From here on, use the map with correct elements kind as root map.
}
- int root_nof = root_map->NumberOfOwnDescriptors();
+ Map* new_map = root_map->TryReplayPropertyTransitions(*old_map);
+ if (new_map == nullptr) return MaybeHandle<Map>();
+ return handle(new_map);
+}
+
+Map* Map::TryReplayPropertyTransitions(Map* old_map) {
+ DisallowHeapAllocation no_allocation;
+ DisallowDeoptimization no_deoptimization(GetIsolate());
+
+ int root_nof = NumberOfOwnDescriptors();
int old_nof = old_map->NumberOfOwnDescriptors();
DescriptorArray* old_descriptors = old_map->instance_descriptors();
- Map* new_map = root_map;
+ Map* new_map = this;
for (int i = root_nof; i < old_nof; ++i) {
PropertyDetails old_details = old_descriptors->GetDetails(i);
Map* transition = TransitionArray::SearchTransition(
new_map, old_details.kind(), old_descriptors->GetKey(i),
old_details.attributes());
- if (transition == NULL) return MaybeHandle<Map>();
+ if (transition == NULL) return nullptr;
new_map = transition;
DescriptorArray* new_descriptors = new_map->instance_descriptors();
@@ -4043,7 +4142,7 @@
DCHECK_EQ(old_details.kind(), new_details.kind());
DCHECK_EQ(old_details.attributes(), new_details.attributes());
if (!old_details.representation().fits_into(new_details.representation())) {
- return MaybeHandle<Map>();
+ return nullptr;
}
switch (new_details.type()) {
case DATA: {
@@ -4051,20 +4150,20 @@
// Cleared field types need special treatment. They represent lost
// knowledge, so we must first generalize the new_type to "Any".
if (FieldTypeIsCleared(new_details.representation(), new_type)) {
- return MaybeHandle<Map>();
+ return nullptr;
}
PropertyType old_property_type = old_details.type();
if (old_property_type == DATA) {
FieldType* old_type = old_descriptors->GetFieldType(i);
if (FieldTypeIsCleared(old_details.representation(), old_type) ||
!old_type->NowIs(new_type)) {
- return MaybeHandle<Map>();
+ return nullptr;
}
} else {
DCHECK(old_property_type == DATA_CONSTANT);
Object* old_value = old_descriptors->GetValue(i);
if (!new_type->NowContains(old_value)) {
- return MaybeHandle<Map>();
+ return nullptr;
}
}
break;
@@ -4082,14 +4181,14 @@
Object* old_value = old_descriptors->GetValue(i);
Object* new_value = new_descriptors->GetValue(i);
if (old_details.location() == kField || old_value != new_value) {
- return MaybeHandle<Map>();
+ return nullptr;
}
break;
}
}
}
- if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle<Map>();
- return handle(new_map);
+ if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr;
+ return new_map;
}
@@ -4166,6 +4265,7 @@
LanguageMode language_mode,
StoreFromKeyed store_mode,
bool* found) {
+ it->UpdateProtector();
DCHECK(it->IsFound());
ShouldThrow should_throw =
is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
@@ -4190,23 +4290,38 @@
return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
value, it->GetReceiver(), language_mode);
- case LookupIterator::INTERCEPTOR:
+ case LookupIterator::INTERCEPTOR: {
+ Handle<Map> store_target_map =
+ handle(it->GetStoreTarget()->map(), it->isolate());
if (it->HolderIsReceiverOrHiddenPrototype()) {
Maybe<bool> result =
JSObject::SetPropertyWithInterceptor(it, should_throw, value);
if (result.IsNothing() || result.FromJust()) return result;
+ // Interceptor modified the store target but failed to set the
+ // property.
+ Utils::ApiCheck(*store_target_map == it->GetStoreTarget()->map(),
+ it->IsElement() ? "v8::IndexedPropertySetterCallback"
+ : "v8::NamedPropertySetterCallback",
+ "Interceptor silently changed store target.");
} else {
Maybe<PropertyAttributes> maybe_attributes =
JSObject::GetPropertyAttributesWithInterceptor(it);
if (!maybe_attributes.IsJust()) return Nothing<bool>();
- if (maybe_attributes.FromJust() == ABSENT) break;
if ((maybe_attributes.FromJust() & READ_ONLY) != 0) {
return WriteToReadOnlyProperty(it, value, should_throw);
}
+ // Interceptor modified the store target but failed to set the
+ // property.
+ Utils::ApiCheck(*store_target_map == it->GetStoreTarget()->map(),
+ it->IsElement() ? "v8::IndexedPropertySetterCallback"
+ : "v8::NamedPropertySetterCallback",
+ "Interceptor silently changed store target.");
+ if (maybe_attributes.FromJust() == ABSENT) break;
*found = false;
return Nothing<bool>();
}
break;
+ }
case LookupIterator::ACCESSOR: {
if (it->IsReadOnly()) {
@@ -4248,7 +4363,6 @@
Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
LanguageMode language_mode,
StoreFromKeyed store_mode) {
- it->UpdateProtector();
if (it->IsFound()) {
bool found = true;
Maybe<bool> result =
@@ -4276,7 +4390,6 @@
StoreFromKeyed store_mode) {
Isolate* isolate = it->isolate();
- it->UpdateProtector();
if (it->IsFound()) {
bool found = true;
Maybe<bool> result =
@@ -4284,6 +4397,8 @@
if (found) return result;
}
+ it->UpdateProtector();
+
// The property either doesn't exist on the holder or exists there as a data
// property.
@@ -4295,7 +4410,7 @@
}
Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
- LookupIterator::Configuration c = LookupIterator::HIDDEN;
+ LookupIterator::Configuration c = LookupIterator::OWN;
LookupIterator own_lookup =
it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
: LookupIterator(receiver, it->name(), c);
@@ -4419,14 +4534,6 @@
// Store on the holder which may be hidden behind the receiver.
DCHECK(it->HolderIsReceiverOrHiddenPrototype());
- // Old value for the observation change record.
- // Fetch before transforming the object since the encoding may become
- // incompatible with what's cached in |it|.
- bool is_observed = receiver->map()->is_observed() &&
- (it->IsElement() || !it->name()->IsPrivate());
- MaybeHandle<Object> maybe_old;
- if (is_observed) maybe_old = it->GetDataValue();
-
Handle<Object> to_assign = value;
// Convert the incoming value to a number for storing into typed arrays.
if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
@@ -4449,15 +4556,6 @@
// Write the property value.
it->WriteDataValue(to_assign);
- // Send the change record if there are observers.
- if (is_observed && !value->SameValue(*maybe_old.ToHandleChecked())) {
- RETURN_ON_EXCEPTION_VALUE(
- it->isolate(),
- JSObject::EnqueueChangeRecord(receiver, "update", it->GetName(),
- maybe_old.ToHandleChecked()),
- Nothing<bool>());
- }
-
#if VERIFY_HEAP
if (FLAG_verify_heap) {
receiver->JSObjectVerify();
@@ -4467,47 +4565,6 @@
}
-MUST_USE_RESULT static MaybeHandle<Object> BeginPerformSplice(
- Handle<JSArray> object) {
- Isolate* isolate = object->GetIsolate();
- HandleScope scope(isolate);
- Handle<Object> args[] = {object};
-
- return Execution::Call(
- isolate, Handle<JSFunction>(isolate->observers_begin_perform_splice()),
- isolate->factory()->undefined_value(), arraysize(args), args);
-}
-
-
-MUST_USE_RESULT static MaybeHandle<Object> EndPerformSplice(
- Handle<JSArray> object) {
- Isolate* isolate = object->GetIsolate();
- HandleScope scope(isolate);
- Handle<Object> args[] = {object};
-
- return Execution::Call(
- isolate, Handle<JSFunction>(isolate->observers_end_perform_splice()),
- isolate->factory()->undefined_value(), arraysize(args), args);
-}
-
-
-MUST_USE_RESULT static MaybeHandle<Object> EnqueueSpliceRecord(
- Handle<JSArray> object, uint32_t index, Handle<JSArray> deleted,
- uint32_t add_count) {
- Isolate* isolate = object->GetIsolate();
- HandleScope scope(isolate);
- Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index);
- Handle<Object> add_count_object =
- isolate->factory()->NewNumberFromUint(add_count);
-
- Handle<Object> args[] = {object, index_object, deleted, add_count_object};
-
- return Execution::Call(
- isolate, Handle<JSFunction>(isolate->observers_enqueue_splice()),
- isolate->factory()->undefined_value(), arraysize(args), args);
-}
-
-
Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
PropertyAttributes attributes,
ShouldThrow should_throw,
@@ -4562,6 +4619,7 @@
JSObject::ValidateElements(receiver);
return result;
} else {
+ it->UpdateProtector();
// Migrate to the most up-to-date map that will be able to store |value|
// under it->name() with |attributes|.
it->PrepareTransitionToDataProperty(receiver, value, attributes,
@@ -4578,13 +4636,6 @@
it->WriteDataValue(value);
}
- // Send the change record if there are observers.
- if (receiver->map()->is_observed() && !it->name()->IsPrivate()) {
- RETURN_ON_EXCEPTION_VALUE(isolate, JSObject::EnqueueChangeRecord(
- receiver, "add", it->name(),
- it->factory()->the_hole_value()),
- Nothing<bool>());
- }
#if VERIFY_HEAP
if (FLAG_verify_heap) {
receiver->JSObjectVerify();
@@ -4745,17 +4796,30 @@
return false;
}
+Map* Map::FindElementsKindTransitionedMap(MapHandleList* candidates) {
+ DisallowHeapAllocation no_allocation;
+ DisallowDeoptimization no_deoptimization(GetIsolate());
-Handle<Map> Map::FindTransitionedMap(Handle<Map> map,
- MapHandleList* candidates) {
- ElementsKind kind = map->elements_kind();
+ ElementsKind kind = elements_kind();
bool packed = IsFastPackedElementsKind(kind);
Map* transition = nullptr;
if (IsTransitionableFastElementsKind(kind)) {
- for (Map* current = map->ElementsTransitionMap();
- current != nullptr && current->has_fast_elements();
- current = current->ElementsTransitionMap()) {
+ // Check the state of the root map.
+ Map* root_map = FindRootMap();
+ if (!EquivalentToForTransition(root_map)) return nullptr;
+ root_map = root_map->LookupElementsTransitionMap(kind);
+ DCHECK_NOT_NULL(root_map);
+ // Starting from the next existing elements kind transition try to
+ // replay the property transitions that does not involve instance rewriting
+ // (ElementsTransitionAndStoreStub does not support that).
+ for (root_map = root_map->ElementsTransitionMap();
+ root_map != nullptr && root_map->has_fast_elements();
+ root_map = root_map->ElementsTransitionMap()) {
+ Map* current = root_map->TryReplayPropertyTransitions(this);
+ if (current == nullptr) continue;
+ if (InstancesNeedRewriting(current)) continue;
+
if (ContainsMap(candidates, current) &&
(packed || !IsFastPackedElementsKind(current->elements_kind()))) {
transition = current;
@@ -4763,11 +4827,14 @@
}
}
}
- return transition == nullptr ? Handle<Map>() : handle(transition);
+ return transition;
}
static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
+ // Ensure we are requested to search elements kind transition "near the root".
+ DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
+ map->NumberOfOwnDescriptors());
Map* current_map = map;
ElementsKind kind = map->elements_kind();
@@ -4896,7 +4963,7 @@
return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
}
- return Map::AsElementsKind(map, to_kind);
+ return Map::ReconfigureElementsKind(map, to_kind);
}
@@ -4929,7 +4996,7 @@
Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
Handle<Name> name) {
DCHECK(!name->IsPrivate());
- STACK_CHECK(Nothing<bool>());
+ STACK_CHECK(isolate, Nothing<bool>());
// 1. (Assert)
// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
Handle<Object> handler(proxy->handler(), isolate);
@@ -4998,7 +5065,7 @@
LanguageMode language_mode) {
DCHECK(!name->IsPrivate());
Isolate* isolate = proxy->GetIsolate();
- STACK_CHECK(Nothing<bool>());
+ STACK_CHECK(isolate, Nothing<bool>());
Factory* factory = isolate->factory();
Handle<String> trap_name = factory->set_string();
ShouldThrow should_throw =
@@ -5069,7 +5136,7 @@
ShouldThrow should_throw =
is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
Isolate* isolate = proxy->GetIsolate();
- STACK_CHECK(Nothing<bool>());
+ STACK_CHECK(isolate, Nothing<bool>());
Factory* factory = isolate->factory();
Handle<String> trap_name = factory->deleteProperty_string();
@@ -5160,6 +5227,44 @@
handle(function->bound_target_function()));
}
+// static
+MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
+ Handle<JSBoundFunction> function) {
+ Handle<String> prefix = isolate->factory()->bound__string();
+ if (!function->bound_target_function()->IsJSFunction()) return prefix;
+ Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
+ isolate);
+ Handle<Object> target_name = JSFunction::GetName(isolate, target);
+ if (!target_name->IsString()) return prefix;
+ Factory* factory = isolate->factory();
+ return factory->NewConsString(prefix, Handle<String>::cast(target_name));
+}
+
+// static
+Handle<Object> JSFunction::GetName(Isolate* isolate,
+ Handle<JSFunction> function) {
+ if (function->shared()->name_should_print_as_anonymous()) {
+ return isolate->factory()->anonymous_string();
+ }
+ return handle(function->shared()->name(), isolate);
+}
+
+// static
+MaybeHandle<Smi> JSFunction::GetLength(Isolate* isolate,
+ Handle<JSFunction> function) {
+ int length = 0;
+ if (function->shared()->is_compiled()) {
+ length = function->shared()->length();
+ } else {
+ // If the function isn't compiled yet, the length is not computed
+ // correctly yet. Compile it now and return the right length.
+ if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
+ length = function->shared()->length();
+ }
+ if (isolate->has_pending_exception()) return MaybeHandle<Smi>();
+ }
+ return handle(Smi::FromInt(length), isolate);
+}
// static
Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
@@ -5220,7 +5325,7 @@
} else {
TransitionElementsKind(object, to_kind);
}
- map = Map::AsElementsKind(map, to_kind);
+ map = Map::ReconfigureElementsKind(map, to_kind);
}
JSObject::MigrateToMap(object, map);
}
@@ -5302,8 +5407,6 @@
ShouldThrow should_throw, AccessorInfoHandling handling) {
it->UpdateProtector();
Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
- bool is_observed = object->map()->is_observed() &&
- (it->IsElement() || !it->name()->IsPrivate());
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
@@ -5363,14 +5466,6 @@
it->ReconfigureDataProperty(value, attributes);
}
- if (is_observed) {
- RETURN_ON_EXCEPTION_VALUE(
- it->isolate(),
- EnqueueChangeRecord(object, "reconfigure", it->GetName(),
- it->factory()->the_hole_value()),
- Nothing<bool>());
- }
-
return Just(true);
}
case LookupIterator::INTEGER_INDEXED_EXOTIC:
@@ -5391,20 +5486,8 @@
}
// Reconfigure the data property if the attributes mismatch.
- Handle<Object> old_value = it->factory()->the_hole_value();
- if (is_observed) old_value = it->GetDataValue();
-
it->ReconfigureDataProperty(value, attributes);
- if (is_observed) {
- if (old_value->SameValue(*value)) {
- old_value = it->factory()->the_hole_value();
- }
- RETURN_ON_EXCEPTION_VALUE(
- it->isolate(), EnqueueChangeRecord(object, "reconfigure",
- it->GetName(), old_value),
- Nothing<bool>());
- }
return Just(true);
}
}
@@ -5893,162 +5976,6 @@
}
-Object* JSObject::GetHiddenProperty(Handle<Name> key) {
- DisallowHeapAllocation no_gc;
- DCHECK(key->IsUniqueName());
- if (IsJSGlobalProxy()) {
- // For a proxy, use the prototype as target object.
- PrototypeIterator iter(GetIsolate(), this);
- // If the proxy is detached, return undefined.
- if (iter.IsAtEnd()) return GetHeap()->the_hole_value();
- DCHECK(iter.GetCurrent()->IsJSGlobalObject());
- return iter.GetCurrent<JSObject>()->GetHiddenProperty(key);
- }
- DCHECK(!IsJSGlobalProxy());
- Object* inline_value = GetHiddenPropertiesHashTable();
-
- if (inline_value->IsUndefined()) return GetHeap()->the_hole_value();
-
- ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value);
- Object* entry = hashtable->Lookup(key);
- return entry;
-}
-
-
-Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> object,
- Handle<Name> key,
- Handle<Object> value) {
- Isolate* isolate = object->GetIsolate();
-
- DCHECK(key->IsUniqueName());
- if (object->IsJSGlobalProxy()) {
- // For a proxy, use the prototype as target object.
- PrototypeIterator iter(isolate, object);
- // If the proxy is detached, return undefined.
- if (iter.IsAtEnd()) return isolate->factory()->undefined_value();
- DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
- return SetHiddenProperty(PrototypeIterator::GetCurrent<JSObject>(iter), key,
- value);
- }
- DCHECK(!object->IsJSGlobalProxy());
-
- Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
-
- Handle<ObjectHashTable> hashtable =
- GetOrCreateHiddenPropertiesHashtable(object);
-
- // If it was found, check if the key is already in the dictionary.
- Handle<ObjectHashTable> new_table = ObjectHashTable::Put(hashtable, key,
- value);
- if (*new_table != *hashtable) {
- // If adding the key expanded the dictionary (i.e., Add returned a new
- // dictionary), store it back to the object.
- SetHiddenPropertiesHashTable(object, new_table);
- }
-
- // Return this to mark success.
- return object;
-}
-
-
-void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) {
- Isolate* isolate = object->GetIsolate();
- DCHECK(key->IsUniqueName());
-
- if (object->IsJSGlobalProxy()) {
- PrototypeIterator iter(isolate, object);
- if (iter.IsAtEnd()) return;
- DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
- return DeleteHiddenProperty(PrototypeIterator::GetCurrent<JSObject>(iter),
- key);
- }
-
- Object* inline_value = object->GetHiddenPropertiesHashTable();
-
- if (inline_value->IsUndefined()) return;
-
- Handle<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value));
- bool was_present = false;
- ObjectHashTable::Remove(hashtable, key, &was_present);
-}
-
-
-bool JSObject::HasHiddenProperties(Handle<JSObject> object) {
- Isolate* isolate = object->GetIsolate();
- Handle<Symbol> hidden = isolate->factory()->hidden_properties_symbol();
- LookupIterator it(object, hidden, object);
- Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
- // Cannot get an exception since the hidden_properties_symbol isn't exposed to
- // JS.
- DCHECK(maybe.IsJust());
- return maybe.FromJust() != ABSENT;
-}
-
-
-Object* JSObject::GetHiddenPropertiesHashTable() {
- DCHECK(!IsJSGlobalProxy());
- if (HasFastProperties()) {
- // If the object has fast properties, check whether the first slot
- // in the descriptor array matches the hidden string. Since the
- // hidden strings hash code is zero (and no other name has hash
- // code zero) it will always occupy the first entry if present.
- DescriptorArray* descriptors = this->map()->instance_descriptors();
- if (descriptors->number_of_descriptors() > 0) {
- int sorted_index = descriptors->GetSortedKeyIndex(0);
- if (descriptors->GetKey(sorted_index) ==
- GetHeap()->hidden_properties_symbol() &&
- sorted_index < map()->NumberOfOwnDescriptors()) {
- DCHECK(descriptors->GetType(sorted_index) == DATA);
- DCHECK(descriptors->GetDetails(sorted_index).representation().
- IsCompatibleForLoad(Representation::Tagged()));
- FieldIndex index = FieldIndex::ForDescriptor(this->map(),
- sorted_index);
- return this->RawFastPropertyAt(index);
- } else {
- return GetHeap()->undefined_value();
- }
- } else {
- return GetHeap()->undefined_value();
- }
- } else {
- Isolate* isolate = GetIsolate();
- Handle<Symbol> hidden = isolate->factory()->hidden_properties_symbol();
- Handle<JSObject> receiver(this, isolate);
- LookupIterator it(receiver, hidden, receiver);
- // Access check is always skipped for the hidden string anyways.
- return *GetDataProperty(&it);
- }
-}
-
-Handle<ObjectHashTable> JSObject::GetOrCreateHiddenPropertiesHashtable(
- Handle<JSObject> object) {
- Isolate* isolate = object->GetIsolate();
-
- static const int kInitialCapacity = 4;
- Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
- if (inline_value->IsHashTable()) {
- return Handle<ObjectHashTable>::cast(inline_value);
- }
-
- Handle<ObjectHashTable> hashtable = ObjectHashTable::New(
- isolate, kInitialCapacity, USE_CUSTOM_MINIMUM_CAPACITY);
-
- DCHECK(inline_value->IsUndefined());
- SetHiddenPropertiesHashTable(object, hashtable);
- return hashtable;
-}
-
-
-Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object,
- Handle<Object> value) {
- DCHECK(!object->IsJSGlobalProxy());
- Isolate* isolate = object->GetIsolate();
- Handle<Symbol> name = isolate->factory()->hidden_properties_symbol();
- SetOwnPropertyIgnoreAttributes(object, name, value, DONT_ENUM).Assert();
- return object;
-}
-
-
Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
ShouldThrow should_throw) {
Isolate* isolate = it->isolate();
@@ -6145,11 +6072,6 @@
}
Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
- bool is_observed = receiver->map()->is_observed() &&
- (it->IsElement() || !it->name()->IsPrivate());
-
- Handle<Object> old_value = it->factory()->the_hole_value();
-
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
case LookupIterator::JSPROXY:
@@ -6177,10 +6099,6 @@
case LookupIterator::INTEGER_INDEXED_EXOTIC:
return Just(true);
case LookupIterator::DATA:
- if (is_observed) {
- old_value = it->GetDataValue();
- }
- // Fall through.
case LookupIterator::ACCESSOR: {
if (!it->IsConfigurable()) {
// Fail if the property is not configurable.
@@ -6195,13 +6113,6 @@
it->Delete();
- if (is_observed) {
- RETURN_ON_EXCEPTION_VALUE(
- isolate, JSObject::EnqueueChangeRecord(receiver, "delete",
- it->GetName(), old_value),
- Nothing<bool>());
- }
-
return Just(true);
}
}
@@ -6214,7 +6125,7 @@
Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
LanguageMode language_mode) {
LookupIterator it(object->GetIsolate(), object, index, object,
- LookupIterator::HIDDEN);
+ LookupIterator::OWN);
return DeleteProperty(&it, language_mode);
}
@@ -6222,7 +6133,7 @@
Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
Handle<Name> name,
LanguageMode language_mode) {
- LookupIterator it(object, name, object, LookupIterator::HIDDEN);
+ LookupIterator it(object, name, object, LookupIterator::OWN);
return DeleteProperty(&it, language_mode);
}
@@ -6231,13 +6142,15 @@
Handle<Name> name,
LanguageMode language_mode) {
LookupIterator it = LookupIterator::PropertyOrElement(
- name->GetIsolate(), object, name, object, LookupIterator::HIDDEN);
+ name->GetIsolate(), object, name, object, LookupIterator::OWN);
return DeleteProperty(&it, language_mode);
}
// ES6 7.1.14
-MaybeHandle<Object> ToPropertyKey(Isolate* isolate, Handle<Object> value) {
+// static
+MaybeHandle<Object> Object::ToPropertyKey(Isolate* isolate,
+ Handle<Object> value) {
// 1. Let key be ToPrimitive(argument, hint String).
MaybeHandle<Object> maybe_key =
Object::ToPrimitive(value, ToPrimitiveHint::kString);
@@ -6330,7 +6243,7 @@
// 7b. ReturnIfAbrupt(propDesc).
bool success = false;
LookupIterator it = LookupIterator::PropertyOrElement(
- isolate, props, next_key, &success, LookupIterator::HIDDEN);
+ isolate, props, next_key, &success, LookupIterator::OWN);
DCHECK(success);
Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
if (!maybe.IsJust()) return MaybeHandle<Object>();
@@ -6405,7 +6318,7 @@
bool success = false;
DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
LookupIterator it = LookupIterator::PropertyOrElement(
- isolate, object, key, &success, LookupIterator::HIDDEN);
+ isolate, object, key, &success, LookupIterator::OWN);
DCHECK(success); // ...so creating a LookupIterator can't fail.
// Deal with access checks first.
@@ -6950,10 +6863,7 @@
// (Not needed.)
}
// Most of steps 16 through 19 is implemented by JSArray::SetLength.
- if (JSArray::ObservableSetLength(a, new_len).is_null()) {
- DCHECK(isolate->has_pending_exception());
- return Nothing<bool>();
- }
+ JSArray::SetLength(a, new_len);
// Steps 19d-ii, 20.
if (!new_writable) {
PropertyDescriptor readonly;
@@ -6985,7 +6895,7 @@
Handle<Object> key,
PropertyDescriptor* desc,
ShouldThrow should_throw) {
- STACK_CHECK(Nothing<bool>());
+ STACK_CHECK(isolate, Nothing<bool>());
if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc,
should_throw);
@@ -7135,7 +7045,7 @@
bool success = false;
DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
LookupIterator it = LookupIterator::PropertyOrElement(
- isolate, object, key, &success, LookupIterator::HIDDEN);
+ isolate, object, key, &success, LookupIterator::OWN);
DCHECK(success); // ...so creating a LookupIterator can't fail.
return GetOwnPropertyDescriptor(&it, desc);
}
@@ -7206,7 +7116,7 @@
Handle<Name> name,
PropertyDescriptor* desc) {
DCHECK(!name->IsPrivate());
- STACK_CHECK(Nothing<bool>());
+ STACK_CHECK(isolate, Nothing<bool>());
Handle<String> trap_name =
isolate->factory()->getOwnPropertyDescriptor_string();
@@ -7460,8 +7370,7 @@
if (receiver->IsJSObject()) {
Handle<JSObject> object = Handle<JSObject>::cast(receiver);
- if (!object->HasSloppyArgumentsElements() &&
- !object->map()->is_observed()) { // Fast path.
+ if (!object->HasSloppyArgumentsElements()) { // Fast path.
if (level == SEALED) {
return JSObject::PreventExtensionsWithTransition<SEALED>(object,
should_throw);
@@ -7565,7 +7474,7 @@
Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
ShouldThrow should_throw) {
Isolate* isolate = proxy->GetIsolate();
- STACK_CHECK(Nothing<bool>());
+ STACK_CHECK(isolate, Nothing<bool>());
Factory* factory = isolate->factory();
Handle<String> trap_name = factory->preventExtensions_string();
@@ -7612,7 +7521,7 @@
ShouldThrow should_throw) {
Isolate* isolate = object->GetIsolate();
- if (!object->HasSloppyArgumentsElements() && !object->map()->is_observed()) {
+ if (!object->HasSloppyArgumentsElements()) {
return PreventExtensionsWithTransition<NONE>(object, should_throw);
}
@@ -7653,13 +7562,6 @@
JSObject::MigrateToMap(object, new_map);
DCHECK(!object->map()->is_extensible());
- if (object->map()->is_observed()) {
- RETURN_ON_EXCEPTION_VALUE(
- isolate,
- EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
- isolate->factory()->the_hole_value()),
- Nothing<bool>());
- }
return Just(true);
}
@@ -7674,7 +7576,7 @@
Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
Isolate* isolate = proxy->GetIsolate();
- STACK_CHECK(Nothing<bool>());
+ STACK_CHECK(isolate, Nothing<bool>());
Factory* factory = isolate->factory();
Handle<String> trap_name = factory->isExtensible_string();
@@ -7760,7 +7662,6 @@
// Sealing/freezing sloppy arguments should be handled elsewhere.
DCHECK(!object->HasSloppyArgumentsElements());
- DCHECK(!object->map()->is_observed());
Isolate* isolate = object->GetIsolate();
if (object->IsAccessCheckNeeded() &&
@@ -7879,28 +7780,6 @@
}
-void JSObject::SetObserved(Handle<JSObject> object) {
- DCHECK(!object->IsJSGlobalProxy());
- DCHECK(!object->IsJSGlobalObject());
- Isolate* isolate = object->GetIsolate();
- Handle<Map> new_map;
- Handle<Map> old_map(object->map(), isolate);
- DCHECK(!old_map->is_observed());
- Map* transition = TransitionArray::SearchSpecial(
- *old_map, isolate->heap()->observed_symbol());
- if (transition != NULL) {
- new_map = handle(transition, isolate);
- DCHECK(new_map->is_observed());
- } else if (TransitionArray::CanHaveMoreTransitions(old_map)) {
- new_map = Map::CopyForObserved(old_map);
- } else {
- new_map = Map::Copy(old_map, "SlowObserved");
- new_map->set_is_observed();
- }
- JSObject::MigrateToMap(object, new_map);
-}
-
-
Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
Representation representation,
FieldIndex index) {
@@ -8031,7 +7910,7 @@
ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE);
KeyAccumulator accumulator(isolate, OWN_ONLY, filter);
accumulator.NextPrototype();
- copy->CollectOwnPropertyNames(&accumulator, filter);
+ accumulator.CollectOwnPropertyNames(copy);
Handle<FixedArray> names = accumulator.GetKeys();
for (int i = 0; i < names->length(); i++) {
DCHECK(names->get(i)->IsName());
@@ -8295,28 +8174,6 @@
return true;
}
-// Tests for the fast common case for property enumeration:
-// - This object and all prototypes has an enum cache (which means that
-// it is no proxy, has no interceptors and needs no access checks).
-// - This object has no elements.
-// - No prototype has enumerable properties/elements.
-bool JSReceiver::IsSimpleEnum() {
- for (PrototypeIterator iter(GetIsolate(), this,
- PrototypeIterator::START_AT_RECEIVER);
- !iter.IsAtEnd(); iter.Advance()) {
- if (!iter.GetCurrent()->IsJSObject()) return false;
- JSObject* current = iter.GetCurrent<JSObject>();
- int enum_length = current->map()->EnumLength();
- if (enum_length == kInvalidEnumCacheSentinel) return false;
- if (current->IsAccessCheckNeeded()) return false;
- DCHECK(!current->HasNamedInterceptor());
- DCHECK(!current->HasIndexedInterceptor());
- if (current->HasEnumerableElements()) return false;
- if (current != this && enum_length != 0) return false;
- }
- return true;
-}
-
int Map::NumberOfDescribedProperties(DescriptorFlag which,
PropertyFilter filter) {
@@ -8350,23 +8207,6 @@
}
-static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
- int len = array->length();
- for (int i = 0; i < len; i++) {
- Object* e = array->get(i);
- if (!(e->IsName() || e->IsNumber())) return false;
- }
- return true;
-}
-
-
-static Handle<FixedArray> ReduceFixedArrayTo(
- Handle<FixedArray> array, int length) {
- DCHECK_LE(length, array->length());
- if (array->length() == length) return array;
- return array->GetIsolate()->factory()->CopyFixedArrayUpTo(array, length);
-}
-
bool Map::OnlyHasSimpleProperties() {
// Wrapped string elements aren't explicitly stored in the elements backing
// store, but are loaded indirectly from the underlying string.
@@ -8375,419 +8215,13 @@
!has_hidden_prototype() && !is_dictionary_map();
}
-// static
-Handle<FixedArray> JSObject::GetFastEnumPropertyKeys(Isolate* isolate,
- Handle<JSObject> object) {
- Handle<Map> map(object->map());
- bool cache_enum_length = map->OnlyHasSimpleProperties();
-
- Handle<DescriptorArray> descs =
- Handle<DescriptorArray>(map->instance_descriptors(), isolate);
- int own_property_count = map->EnumLength();
- // If the enum length of the given map is set to kInvalidEnumCache, this
- // means that the map itself has never used the present enum cache. The
- // first step to using the cache is to set the enum length of the map by
- // counting the number of own descriptors that are ENUMERABLE_STRINGS.
- if (own_property_count == kInvalidEnumCacheSentinel) {
- own_property_count =
- map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS);
- } else {
- DCHECK(
- own_property_count ==
- map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS));
- }
-
- if (descs->HasEnumCache()) {
- Handle<FixedArray> keys(descs->GetEnumCache(), isolate);
- // In case the number of properties required in the enum are actually
- // present, we can reuse the enum cache. Otherwise, this means that the
- // enum cache was generated for a previous (smaller) version of the
- // Descriptor Array. In that case we regenerate the enum cache.
- if (own_property_count <= keys->length()) {
- isolate->counters()->enum_cache_hits()->Increment();
- if (cache_enum_length) map->SetEnumLength(own_property_count);
- return ReduceFixedArrayTo(keys, own_property_count);
- }
- }
-
- if (descs->IsEmpty()) {
- isolate->counters()->enum_cache_hits()->Increment();
- if (cache_enum_length) map->SetEnumLength(0);
- return isolate->factory()->empty_fixed_array();
- }
-
- isolate->counters()->enum_cache_misses()->Increment();
-
- Handle<FixedArray> storage =
- isolate->factory()->NewFixedArray(own_property_count);
- Handle<FixedArray> indices =
- isolate->factory()->NewFixedArray(own_property_count);
-
- int size = map->NumberOfOwnDescriptors();
- int index = 0;
-
- for (int i = 0; i < size; i++) {
- PropertyDetails details = descs->GetDetails(i);
- if (details.IsDontEnum()) continue;
- Object* key = descs->GetKey(i);
- if (key->IsSymbol()) continue;
- storage->set(index, key);
- if (!indices.is_null()) {
- if (details.type() != DATA) {
- indices = Handle<FixedArray>();
- } else {
- FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
- int load_by_field_index = field_index.GetLoadByFieldIndex();
- indices->set(index, Smi::FromInt(load_by_field_index));
- }
- }
- index++;
- }
- DCHECK(index == storage->length());
-
- DescriptorArray::SetEnumCache(descs, isolate, storage, indices);
- if (cache_enum_length) {
- map->SetEnumLength(own_property_count);
- }
- return storage;
-}
-
-
-Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object) {
- Isolate* isolate = object->GetIsolate();
- if (object->HasFastProperties()) {
- return GetFastEnumPropertyKeys(isolate, object);
- } else if (object->IsJSGlobalObject()) {
- Handle<GlobalDictionary> dictionary(object->global_dictionary());
- int length = dictionary->NumberOfEnumElements();
- if (length == 0) {
- return isolate->factory()->empty_fixed_array();
- }
- Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
- dictionary->CopyEnumKeysTo(*storage);
- return storage;
- } else {
- Handle<NameDictionary> dictionary(object->property_dictionary());
- int length = dictionary->NumberOfEnumElements();
- if (length == 0) {
- return isolate->factory()->empty_fixed_array();
- }
- Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
- dictionary->CopyEnumKeysTo(*storage);
- return storage;
- }
-}
-
-
-enum IndexedOrNamed { kIndexed, kNamed };
-
-
-// Returns |true| on success, |nothing| on exception.
-template <class Callback, IndexedOrNamed type>
-static Maybe<bool> GetKeysFromInterceptor(Isolate* isolate,
- Handle<JSReceiver> receiver,
- Handle<JSObject> object,
- PropertyFilter filter,
- KeyAccumulator* accumulator) {
- if (type == kIndexed) {
- if (!object->HasIndexedInterceptor()) return Just(true);
- } else {
- if (!object->HasNamedInterceptor()) return Just(true);
- }
- Handle<InterceptorInfo> interceptor(type == kIndexed
- ? object->GetIndexedInterceptor()
- : object->GetNamedInterceptor(),
- isolate);
- if ((filter & ONLY_ALL_CAN_READ) && !interceptor->all_can_read()) {
- return Just(true);
- }
- PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
- *object, Object::DONT_THROW);
- Handle<JSObject> result;
- if (!interceptor->enumerator()->IsUndefined()) {
- Callback enum_fun = v8::ToCData<Callback>(interceptor->enumerator());
- const char* log_tag = type == kIndexed ? "interceptor-indexed-enum"
- : "interceptor-named-enum";
- LOG(isolate, ApiObjectAccess(log_tag, *object));
- result = args.Call(enum_fun);
- }
- RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
- if (result.is_null()) return Just(true);
- DCHECK(result->IsJSArray() || result->HasSloppyArgumentsElements());
- // The accumulator takes care of string/symbol filtering.
- if (type == kIndexed) {
- accumulator->AddElementKeysFromInterceptor(result);
- } else {
- accumulator->AddKeys(result, DO_NOT_CONVERT);
- }
- return Just(true);
-}
-
-
-// Returns |true| on success, |false| if prototype walking should be stopped,
-// |nothing| if an exception was thrown.
-static Maybe<bool> GetKeysFromJSObject(Isolate* isolate,
- Handle<JSReceiver> receiver,
- Handle<JSObject> object,
- PropertyFilter* filter,
- KeyCollectionType type,
- KeyAccumulator* accumulator) {
- accumulator->NextPrototype();
- // Check access rights if required.
- if (object->IsAccessCheckNeeded() &&
- !isolate->MayAccess(handle(isolate->context()), object)) {
- // The cross-origin spec says that [[Enumerate]] shall return an empty
- // iterator when it doesn't have access...
- if (type == INCLUDE_PROTOS) {
- return Just(false);
- }
- // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties.
- DCHECK_EQ(OWN_ONLY, type);
- *filter = static_cast<PropertyFilter>(*filter | ONLY_ALL_CAN_READ);
- }
-
- JSObject::CollectOwnElementKeys(object, accumulator, *filter);
-
- // Add the element keys from the interceptor.
- Maybe<bool> success =
- GetKeysFromInterceptor<v8::IndexedPropertyEnumeratorCallback, kIndexed>(
- isolate, receiver, object, *filter, accumulator);
- MAYBE_RETURN(success, Nothing<bool>());
-
- if (*filter == ENUMERABLE_STRINGS) {
- Handle<FixedArray> enum_keys = JSObject::GetEnumPropertyKeys(object);
- accumulator->AddKeys(enum_keys, DO_NOT_CONVERT);
- } else {
- object->CollectOwnPropertyNames(accumulator, *filter);
- }
-
- // Add the property keys from the interceptor.
- success = GetKeysFromInterceptor<v8::GenericNamedPropertyEnumeratorCallback,
- kNamed>(isolate, receiver, object, *filter,
- accumulator);
- MAYBE_RETURN(success, Nothing<bool>());
- return Just(true);
-}
-
-
-// Helper function for JSReceiver::GetKeys() below. Can be called recursively.
-// Returns |true| or |nothing|.
-static Maybe<bool> GetKeys_Internal(Isolate* isolate,
- Handle<JSReceiver> receiver,
- Handle<JSReceiver> object,
- KeyCollectionType type,
- PropertyFilter filter,
- KeyAccumulator* accumulator) {
- // Proxies have no hidden prototype and we should not trigger the
- // [[GetPrototypeOf]] trap on the last iteration when using
- // AdvanceFollowingProxies.
- if (type == OWN_ONLY && object->IsJSProxy()) {
- MAYBE_RETURN(JSProxy::OwnPropertyKeys(isolate, receiver,
- Handle<JSProxy>::cast(object), filter,
- accumulator),
- Nothing<bool>());
- return Just(true);
- }
-
- PrototypeIterator::WhereToEnd end = type == OWN_ONLY
- ? PrototypeIterator::END_AT_NON_HIDDEN
- : PrototypeIterator::END_AT_NULL;
- for (PrototypeIterator iter(isolate, object,
- PrototypeIterator::START_AT_RECEIVER, end);
- !iter.IsAtEnd();) {
- Handle<JSReceiver> current =
- PrototypeIterator::GetCurrent<JSReceiver>(iter);
- Maybe<bool> result = Just(false); // Dummy initialization.
- if (current->IsJSProxy()) {
- result = JSProxy::OwnPropertyKeys(isolate, receiver,
- Handle<JSProxy>::cast(current), filter,
- accumulator);
- } else {
- DCHECK(current->IsJSObject());
- result = GetKeysFromJSObject(isolate, receiver,
- Handle<JSObject>::cast(current), &filter,
- type, accumulator);
- }
- MAYBE_RETURN(result, Nothing<bool>());
- if (!result.FromJust()) break; // |false| means "stop iterating".
- // Iterate through proxies but ignore access checks for the ALL_CAN_READ
- // case on API objects for OWN_ONLY keys handlede in GgetKeysFromJSObject.
- if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) {
- return Nothing<bool>();
- }
- }
- return Just(true);
-}
-
-
-// ES6 9.5.12
-// Returns |true| on success, |nothing| in case of exception.
-// static
-Maybe<bool> JSProxy::OwnPropertyKeys(Isolate* isolate,
- Handle<JSReceiver> receiver,
- Handle<JSProxy> proxy,
- PropertyFilter filter,
- KeyAccumulator* accumulator) {
- STACK_CHECK(Nothing<bool>());
- // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
- Handle<Object> handler(proxy->handler(), isolate);
- // 2. If handler is null, throw a TypeError exception.
- // 3. Assert: Type(handler) is Object.
- if (proxy->IsRevoked()) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kProxyRevoked, isolate->factory()->ownKeys_string()));
- return Nothing<bool>();
- }
- // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
- Handle<JSReceiver> target(proxy->target(), isolate);
- // 5. Let trap be ? GetMethod(handler, "ownKeys").
- Handle<Object> trap;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
- isolate->factory()->ownKeys_string()),
- Nothing<bool>());
- // 6. If trap is undefined, then
- if (trap->IsUndefined()) {
- // 6a. Return target.[[OwnPropertyKeys]]().
- return GetKeys_Internal(isolate, receiver, target, OWN_ONLY, filter,
- accumulator);
- }
- // 7. Let trapResultArray be Call(trap, handler, «target»).
- Handle<Object> trap_result_array;
- Handle<Object> args[] = {target};
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate, trap_result_array,
- Execution::Call(isolate, trap, handler, arraysize(args), args),
- Nothing<bool>());
- // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray,
- // «String, Symbol»).
- Handle<FixedArray> trap_result;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate, trap_result,
- Object::CreateListFromArrayLike(isolate, trap_result_array,
- ElementTypes::kStringAndSymbol),
- Nothing<bool>());
- // 9. Let extensibleTarget be ? IsExtensible(target).
- Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
- MAYBE_RETURN(maybe_extensible, Nothing<bool>());
- bool extensible_target = maybe_extensible.FromJust();
- // 10. Let targetKeys be ? target.[[OwnPropertyKeys]]().
- Handle<FixedArray> target_keys;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_keys,
- JSReceiver::OwnPropertyKeys(target),
- Nothing<bool>());
- // 11. (Assert)
- // 12. Let targetConfigurableKeys be an empty List.
- // To save memory, we're re-using target_keys and will modify it in-place.
- Handle<FixedArray> target_configurable_keys = target_keys;
- // 13. Let targetNonconfigurableKeys be an empty List.
- Handle<FixedArray> target_nonconfigurable_keys =
- isolate->factory()->NewFixedArray(target_keys->length());
- int nonconfigurable_keys_length = 0;
- // 14. Repeat, for each element key of targetKeys:
- for (int i = 0; i < target_keys->length(); ++i) {
- // 14a. Let desc be ? target.[[GetOwnProperty]](key).
- PropertyDescriptor desc;
- Maybe<bool> found = JSReceiver::GetOwnPropertyDescriptor(
- isolate, target, handle(target_keys->get(i), isolate), &desc);
- MAYBE_RETURN(found, Nothing<bool>());
- // 14b. If desc is not undefined and desc.[[Configurable]] is false, then
- if (found.FromJust() && !desc.configurable()) {
- // 14b i. Append key as an element of targetNonconfigurableKeys.
- target_nonconfigurable_keys->set(nonconfigurable_keys_length,
- target_keys->get(i));
- nonconfigurable_keys_length++;
- // The key was moved, null it out in the original list.
- target_keys->set(i, Smi::FromInt(0));
- } else {
- // 14c. Else,
- // 14c i. Append key as an element of targetConfigurableKeys.
- // (No-op, just keep it in |target_keys|.)
- }
- }
- accumulator->NextPrototype(); // Prepare for accumulating keys.
- // 15. If extensibleTarget is true and targetNonconfigurableKeys is empty,
- // then:
- if (extensible_target && nonconfigurable_keys_length == 0) {
- // 15a. Return trapResult.
- return accumulator->AddKeysFromProxy(proxy, trap_result);
- }
- // 16. Let uncheckedResultKeys be a new List which is a copy of trapResult.
- Zone set_zone(isolate->allocator());
- const int kPresent = 1;
- const int kGone = 0;
- IdentityMap<int> unchecked_result_keys(isolate->heap(), &set_zone);
- int unchecked_result_keys_size = 0;
- for (int i = 0; i < trap_result->length(); ++i) {
- DCHECK(trap_result->get(i)->IsUniqueName());
- Object* key = trap_result->get(i);
- int* entry = unchecked_result_keys.Get(key);
- if (*entry != kPresent) {
- *entry = kPresent;
- unchecked_result_keys_size++;
- }
- }
- // 17. Repeat, for each key that is an element of targetNonconfigurableKeys:
- for (int i = 0; i < nonconfigurable_keys_length; ++i) {
- Object* key = target_nonconfigurable_keys->get(i);
- // 17a. If key is not an element of uncheckedResultKeys, throw a
- // TypeError exception.
- int* found = unchecked_result_keys.Find(key);
- if (found == nullptr || *found == kGone) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate)));
- return Nothing<bool>();
- }
- // 17b. Remove key from uncheckedResultKeys.
- *found = kGone;
- unchecked_result_keys_size--;
- }
- // 18. If extensibleTarget is true, return trapResult.
- if (extensible_target) {
- return accumulator->AddKeysFromProxy(proxy, trap_result);
- }
- // 19. Repeat, for each key that is an element of targetConfigurableKeys:
- for (int i = 0; i < target_configurable_keys->length(); ++i) {
- Object* key = target_configurable_keys->get(i);
- if (key->IsSmi()) continue; // Zapped entry, was nonconfigurable.
- // 19a. If key is not an element of uncheckedResultKeys, throw a
- // TypeError exception.
- int* found = unchecked_result_keys.Find(key);
- if (found == nullptr || *found == kGone) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate)));
- return Nothing<bool>();
- }
- // 19b. Remove key from uncheckedResultKeys.
- *found = kGone;
- unchecked_result_keys_size--;
- }
- // 20. If uncheckedResultKeys is not empty, throw a TypeError exception.
- if (unchecked_result_keys_size != 0) {
- DCHECK_GT(unchecked_result_keys_size, 0);
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kProxyOwnKeysNonExtensible));
- return Nothing<bool>();
- }
- // 21. Return trapResult.
- return accumulator->AddKeysFromProxy(proxy, trap_result);
-}
-
MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
KeyCollectionType type,
PropertyFilter filter,
GetKeysConversion keys_conversion,
bool filter_proxy_keys) {
- USE(ContainsOnlyValidKeys);
- Isolate* isolate = object->GetIsolate();
- KeyAccumulator accumulator(isolate, type, filter);
- accumulator.set_filter_proxy_keys(filter_proxy_keys);
- MAYBE_RETURN(
- GetKeys_Internal(isolate, object, object, type, filter, &accumulator),
- MaybeHandle<FixedArray>());
- Handle<FixedArray> keys = accumulator.GetKeys(keys_conversion);
- DCHECK(ContainsOnlyValidKeys(keys));
- return keys;
+ return KeyAccumulator::GetKeys(object, type, filter, keys_conversion,
+ filter_proxy_keys);
}
MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
@@ -8881,11 +8315,9 @@
PropertyFilter key_filter =
static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
KeyAccumulator accumulator(isolate, OWN_ONLY, key_filter);
- MAYBE_RETURN(GetKeys_Internal(isolate, object, object, OWN_ONLY, key_filter,
- &accumulator),
+ MAYBE_RETURN(accumulator.CollectKeys(object, object),
MaybeHandle<FixedArray>());
Handle<FixedArray> keys = accumulator.GetKeys(CONVERT_TO_STRING);
- DCHECK(ContainsOnlyValidKeys(keys));
values_or_entries = isolate->factory()->NewFixedArray(keys->length());
int length = 0;
@@ -8970,7 +8402,7 @@
Isolate* isolate = object->GetIsolate();
LookupIterator it = LookupIterator::PropertyOrElement(
- isolate, object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
+ isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
return DefineAccessor(&it, getter, setter, attributes);
}
@@ -8998,40 +8430,11 @@
return it->factory()->undefined_value();
}
- Handle<Object> old_value = isolate->factory()->the_hole_value();
- bool is_observed = object->map()->is_observed() &&
- (it->IsElement() || !it->name()->IsPrivate());
- bool preexists = false;
- if (is_observed) {
- CHECK(GetPropertyAttributes(it).IsJust());
- preexists = it->IsFound();
- if (preexists && (it->state() == LookupIterator::DATA ||
- it->GetAccessors()->IsAccessorInfo())) {
- old_value = Object::GetProperty(it).ToHandleChecked();
- }
- }
-
DCHECK(getter->IsCallable() || getter->IsUndefined() || getter->IsNull() ||
getter->IsFunctionTemplateInfo());
DCHECK(setter->IsCallable() || setter->IsUndefined() || setter->IsNull() ||
getter->IsFunctionTemplateInfo());
- // At least one of the accessors needs to be a new value.
- DCHECK(!getter->IsNull() || !setter->IsNull());
- if (!getter->IsNull()) {
- it->TransitionToAccessorProperty(ACCESSOR_GETTER, getter, attributes);
- }
- if (!setter->IsNull()) {
- it->TransitionToAccessorProperty(ACCESSOR_SETTER, setter, attributes);
- }
-
- if (is_observed) {
- // Make sure the top context isn't changed.
- AssertNoContextChange ncc(isolate);
- const char* type = preexists ? "reconfigure" : "add";
- RETURN_ON_EXCEPTION(
- isolate, EnqueueChangeRecord(object, type, it->GetName(), old_value),
- Object);
- }
+ it->TransitionToAccessorProperty(getter, setter, attributes);
return isolate->factory()->undefined_value();
}
@@ -9043,7 +8446,7 @@
Handle<Name> name(Name::cast(info->name()), isolate);
LookupIterator it = LookupIterator::PropertyOrElement(
- isolate, object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
+ isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
// Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
// the FailedAccessCheckCallbackFunction doesn't throw an exception.
@@ -9077,53 +8480,6 @@
return object;
}
-
-MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
- Handle<Name> name,
- AccessorComponent component) {
- Isolate* isolate = object->GetIsolate();
-
- // Make sure that the top context does not change when doing callbacks or
- // interceptor calls.
- AssertNoContextChange ncc(isolate);
-
- LookupIterator it = LookupIterator::PropertyOrElement(
- isolate, object, name, LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
-
- for (; it.IsFound(); it.Next()) {
- switch (it.state()) {
- case LookupIterator::INTERCEPTOR:
- case LookupIterator::NOT_FOUND:
- case LookupIterator::TRANSITION:
- UNREACHABLE();
-
- case LookupIterator::ACCESS_CHECK:
- if (it.HasAccess()) continue;
- isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
- return isolate->factory()->undefined_value();
-
- case LookupIterator::JSPROXY:
- return isolate->factory()->undefined_value();
-
- case LookupIterator::INTEGER_INDEXED_EXOTIC:
- return isolate->factory()->undefined_value();
- case LookupIterator::DATA:
- continue;
- case LookupIterator::ACCESSOR: {
- Handle<Object> maybe_pair = it.GetAccessors();
- if (maybe_pair->IsAccessorPair()) {
- return AccessorPair::GetComponent(
- Handle<AccessorPair>::cast(maybe_pair), component);
- }
- }
- }
- }
-
- return isolate->factory()->undefined_value();
-}
-
-
Object* JSObject::SlowReverseLookup(Object* value) {
if (HasFastProperties()) {
int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
@@ -9562,6 +8918,10 @@
TransitionFlag flag) {
Map* maybe_elements_transition_map = NULL;
if (flag == INSERT_TRANSITION) {
+ // Ensure we are requested to add elements kind transition "near the root".
+ DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(),
+ map->NumberOfOwnDescriptors());
+
maybe_elements_transition_map = map->ElementsTransitionMap();
DCHECK(maybe_elements_transition_map == NULL ||
(maybe_elements_transition_map->elements_kind() ==
@@ -9641,30 +9001,6 @@
}
-Handle<Map> Map::CopyForObserved(Handle<Map> map) {
- DCHECK(!map->is_observed());
-
- Isolate* isolate = map->GetIsolate();
-
- bool insert_transition =
- TransitionArray::CanHaveMoreTransitions(map) && !map->is_prototype_map();
-
- if (insert_transition) {
- Handle<Map> new_map = CopyForTransition(map, "CopyForObserved");
- new_map->set_is_observed();
-
- Handle<Name> name = isolate->factory()->observed_symbol();
- ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
- return new_map;
- }
-
- // Create a new free-floating map only if we are not allowed to store it.
- Handle<Map> new_map = Map::Copy(map, "CopyForObserved");
- new_map->set_is_observed();
- return new_map;
-}
-
-
Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) {
DCHECK(!map->is_prototype_map());
Handle<Map> new_map = CopyDropDescriptors(map);
@@ -9825,6 +9161,11 @@
Handle<Object> value,
PropertyAttributes attributes,
StoreFromKeyed store_mode) {
+ RuntimeCallTimerScope stats_scope(
+ *map, map->is_prototype_map()
+ ? &RuntimeCallStats::PrototypeMap_TransitionToDataProperty
+ : &RuntimeCallStats::Map_TransitionToDataProperty);
+
DCHECK(name->IsUniqueName());
DCHECK(!map->is_dictionary_map());
@@ -9885,7 +9226,7 @@
// There is no benefit from reconstructing transition tree for maps without
// back pointers.
return CopyGeneralizeAllRepresentations(
- map, descriptor, FORCE_FIELD, kind, attributes,
+ map, map->elements_kind(), descriptor, FORCE_FIELD, kind, attributes,
"GenAll_AttributesMismatchProtoMap");
}
@@ -9900,13 +9241,20 @@
return new_map;
}
-Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
+Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
Handle<Name> name, int descriptor,
- AccessorComponent component,
- Handle<Object> accessor,
+ Handle<Object> getter,
+ Handle<Object> setter,
PropertyAttributes attributes) {
+ RuntimeCallTimerScope stats_scope(
+ isolate,
+ map->is_prototype_map()
+ ? &RuntimeCallStats::PrototypeMap_TransitionToAccessorProperty
+ : &RuntimeCallStats::Map_TransitionToAccessorProperty);
+
+ // At least one of the accessors needs to be a new value.
+ DCHECK(!getter->IsNull() || !setter->IsNull());
DCHECK(name->IsUniqueName());
- Isolate* isolate = name->GetIsolate();
// Dictionary maps can always have additional data properties.
if (map->is_dictionary_map()) return map;
@@ -9935,7 +9283,7 @@
}
Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
- if (pair->get(component) != *accessor) {
+ if (!pair->Equals(*getter, *setter)) {
return Map::Normalize(map, mode, "TransitionToDifferentAccessor");
}
@@ -9962,10 +9310,19 @@
return Map::Normalize(map, mode, "AccessorsOverwritingNonPair");
}
- Object* current = Handle<AccessorPair>::cast(maybe_pair)->get(component);
- if (current == *accessor) return map;
+ Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair);
+ if (current_pair->Equals(*getter, *setter)) return map;
- if (!current->IsTheHole()) {
+ bool overwriting_accessor = false;
+ if (!getter->IsNull() && !current_pair->get(ACCESSOR_GETTER)->IsNull() &&
+ current_pair->get(ACCESSOR_GETTER) != *getter) {
+ overwriting_accessor = true;
+ }
+ if (!setter->IsNull() && !current_pair->get(ACCESSOR_SETTER)->IsNull() &&
+ current_pair->get(ACCESSOR_SETTER) != *setter) {
+ overwriting_accessor = true;
+ }
+ if (overwriting_accessor) {
return Map::Normalize(map, mode, "AccessorsOverwritingAccessors");
}
@@ -9977,7 +9334,8 @@
pair = isolate->factory()->NewAccessorPair();
}
- pair->set(component, *accessor);
+ pair->SetComponents(*getter, *setter);
+
TransitionFlag flag = INSERT_TRANSITION;
AccessorConstantDescriptor new_desc(name, pair, attributes);
return Map::CopyInsertDescriptor(map, &new_desc, flag);
@@ -10128,215 +9486,22 @@
Isolate* isolate = map->GetIsolate();
HandleScope scope(isolate);
// Allocate the code cache if not present.
- if (map->code_cache()->IsFixedArray()) {
- Handle<Object> result = isolate->factory()->NewCodeCache();
+ if (!map->has_code_cache()) {
+ Handle<Object> result =
+ CodeCacheHashTable::New(isolate, CodeCacheHashTable::kInitialSize);
map->set_code_cache(*result);
}
// Update the code cache.
- Handle<CodeCache> code_cache(CodeCache::cast(map->code_cache()), isolate);
- CodeCache::Update(code_cache, name, code);
-}
-
-
-Object* Map::FindInCodeCache(Name* name, Code::Flags flags) {
- // Do a lookup if a code cache exists.
- if (!code_cache()->IsFixedArray()) {
- return CodeCache::cast(code_cache())->Lookup(name, flags);
- } else {
- return GetHeap()->undefined_value();
- }
-}
-
-
-int Map::IndexInCodeCache(Object* name, Code* code) {
- // Get the internal index if a code cache exists.
- if (!code_cache()->IsFixedArray()) {
- return CodeCache::cast(code_cache())->GetIndex(name, code);
- }
- return -1;
-}
-
-
-void Map::RemoveFromCodeCache(Name* name, Code* code, int index) {
- // No GC is supposed to happen between a call to IndexInCodeCache and
- // RemoveFromCodeCache so the code cache must be there.
- DCHECK(!code_cache()->IsFixedArray());
- CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
-}
-
-
-void CodeCache::Update(
- Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
- // The number of monomorphic stubs for normal load/store/call IC's can grow to
- // a large number and therefore they need to go into a hash table. They are
- // used to load global properties from cells.
- if (code->type() == Code::NORMAL) {
- // Make sure that a hash table is allocated for the normal load code cache.
- if (code_cache->normal_type_cache()->IsUndefined()) {
- Handle<Object> result =
- CodeCacheHashTable::New(code_cache->GetIsolate(),
- CodeCacheHashTable::kInitialSize);
- code_cache->set_normal_type_cache(*result);
- }
- UpdateNormalTypeCache(code_cache, name, code);
- } else {
- DCHECK(code_cache->default_cache()->IsFixedArray());
- UpdateDefaultCache(code_cache, name, code);
- }
-}
-
-
-void CodeCache::UpdateDefaultCache(
- Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
- Isolate* isolate = code_cache->GetIsolate();
- // When updating the default code cache we disregard the type encoded in the
- // flags. This allows call constant stubs to overwrite call field
- // stubs, etc.
- Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
-
- // First check whether we can update existing code cache without
- // extending it.
- Handle<FixedArray> cache = handle(code_cache->default_cache());
- int length = cache->length();
- {
- DisallowHeapAllocation no_alloc;
- int deleted_index = -1;
- Object* null = isolate->heap()->null_value();
- Object* undefined = isolate->heap()->undefined_value();
- DCHECK(name->IsUniqueName());
- for (int i = 0; i < length; i += kCodeCacheEntrySize) {
- Object* key = cache->get(i);
- if (key == null) {
- if (deleted_index < 0) deleted_index = i;
- continue;
- }
- if (key == undefined) {
- if (deleted_index >= 0) i = deleted_index;
- cache->set(i + kCodeCacheEntryNameOffset, *name);
- cache->set(i + kCodeCacheEntryCodeOffset, *code);
- return;
- }
- DCHECK(key->IsUniqueName());
- if (*name == key) {
- Code::Flags found =
- Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
- if (Code::RemoveTypeFromFlags(found) == flags) {
- cache->set(i + kCodeCacheEntryCodeOffset, *code);
- return;
- }
- }
- }
-
- // Reached the end of the code cache. If there were deleted
- // elements, reuse the space for the first of them.
- if (deleted_index >= 0) {
- cache->set(deleted_index + kCodeCacheEntryNameOffset, *name);
- cache->set(deleted_index + kCodeCacheEntryCodeOffset, *code);
- return;
- }
- }
-
- // Extend the code cache with some new entries (at least one). Must be a
- // multiple of the entry size.
- int new_length = length + (length >> 1) + kCodeCacheEntrySize;
- new_length = new_length - new_length % kCodeCacheEntrySize;
- DCHECK((new_length % kCodeCacheEntrySize) == 0);
- cache = isolate->factory()->CopyFixedArrayAndGrow(cache, new_length - length);
-
- // Add the (name, code) pair to the new cache.
- cache->set(length + kCodeCacheEntryNameOffset, *name);
- cache->set(length + kCodeCacheEntryCodeOffset, *code);
- code_cache->set_default_cache(*cache);
-}
-
-
-void CodeCache::UpdateNormalTypeCache(
- Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
- // Adding a new entry can cause a new cache to be allocated.
- Handle<CodeCacheHashTable> cache(
- CodeCacheHashTable::cast(code_cache->normal_type_cache()));
+ Handle<CodeCacheHashTable> cache(CodeCacheHashTable::cast(map->code_cache()),
+ isolate);
Handle<Object> new_cache = CodeCacheHashTable::Put(cache, name, code);
- code_cache->set_normal_type_cache(*new_cache);
+ map->set_code_cache(*new_cache);
}
-
-Object* CodeCache::Lookup(Name* name, Code::Flags flags) {
- Object* result = LookupDefaultCache(name, Code::RemoveTypeFromFlags(flags));
- if (result->IsCode()) {
- if (Code::cast(result)->flags() == flags) return result;
- return GetHeap()->undefined_value();
- }
- return LookupNormalTypeCache(name, flags);
-}
-
-
-Object* CodeCache::LookupDefaultCache(Name* name, Code::Flags flags) {
- FixedArray* cache = default_cache();
- Heap* heap = GetHeap();
- Object* null = heap->null_value();
- Object* undefined = heap->undefined_value();
- int length = cache->length();
- DCHECK(name->IsUniqueName());
- for (int i = 0; i < length; i += kCodeCacheEntrySize) {
- Object* key = cache->get(i + kCodeCacheEntryNameOffset);
- // Skip deleted elements.
- if (key == null) continue;
- if (key == undefined) return key;
- DCHECK(key->IsUniqueName());
- if (name == key) {
- Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
- if (Code::RemoveTypeFromFlags(code->flags()) == flags) {
- return code;
- }
- }
- }
- return GetHeap()->undefined_value();
-}
-
-
-Object* CodeCache::LookupNormalTypeCache(Name* name, Code::Flags flags) {
- if (!normal_type_cache()->IsUndefined()) {
- CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
- return cache->Lookup(name, flags);
- } else {
- return GetHeap()->undefined_value();
- }
-}
-
-
-int CodeCache::GetIndex(Object* name, Code* code) {
- if (code->type() == Code::NORMAL) {
- if (normal_type_cache()->IsUndefined()) return -1;
- CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
- return cache->GetIndex(Name::cast(name), code->flags());
- }
-
- FixedArray* array = default_cache();
- int len = array->length();
- for (int i = 0; i < len; i += kCodeCacheEntrySize) {
- if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
- }
- return -1;
-}
-
-
-void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
- if (code->type() == Code::NORMAL) {
- DCHECK(!normal_type_cache()->IsUndefined());
- CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
- DCHECK(cache->GetIndex(Name::cast(name), code->flags()) == index);
- cache->RemoveByIndex(index);
- } else {
- FixedArray* array = default_cache();
- DCHECK(array->length() >= index && array->get(index)->IsCode());
- // Use null instead of undefined for deleted elements to distinguish
- // deleted elements from unused elements. This distinction is used
- // when looking up in the cache and when updating the cache.
- DCHECK_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
- array->set_null(index - 1); // Name.
- array->set_null(index); // Code.
- }
+Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) {
+ if (!has_code_cache()) return nullptr;
+ return CodeCacheHashTable::cast(code_cache())->Lookup(name, flags);
}
@@ -10347,20 +9512,23 @@
class CodeCacheHashTableKey : public HashTableKey {
public:
CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
- : name_(name), flags_(flags), code_() { }
+ : name_(name), flags_(flags), code_() {
+ DCHECK(name_->IsUniqueName());
+ }
CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
- : name_(name), flags_(code->flags()), code_(code) { }
+ : name_(name), flags_(code->flags()), code_(code) {
+ DCHECK(name_->IsUniqueName());
+ }
bool IsMatch(Object* other) override {
- if (!other->IsFixedArray()) return false;
+ DCHECK(other->IsFixedArray());
FixedArray* pair = FixedArray::cast(other);
Name* name = Name::cast(pair->get(0));
Code::Flags flags = Code::cast(pair->get(1))->flags();
- if (flags != flags_) {
- return false;
- }
- return name_->Equals(name);
+ if (flags != flags_) return false;
+ DCHECK(name->IsUniqueName());
+ return *name_ == name;
}
static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
@@ -10392,15 +9560,6 @@
};
-Object* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
- DisallowHeapAllocation no_alloc;
- CodeCacheHashTableKey key(handle(name), flags);
- int entry = FindEntry(&key);
- if (entry == kNotFound) return GetHeap()->undefined_value();
- return get(EntryToIndex(entry) + 1);
-}
-
-
Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) {
CodeCacheHashTableKey key(name, code);
@@ -10411,179 +9570,18 @@
Handle<Object> k = key.AsHandle(cache->GetIsolate());
new_cache->set(EntryToIndex(entry), *k);
- new_cache->set(EntryToIndex(entry) + 1, *code);
new_cache->ElementAdded();
return new_cache;
}
-
-int CodeCacheHashTable::GetIndex(Name* name, Code::Flags flags) {
+Code* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
DisallowHeapAllocation no_alloc;
CodeCacheHashTableKey key(handle(name), flags);
int entry = FindEntry(&key);
- return (entry == kNotFound) ? -1 : entry;
+ if (entry == kNotFound) return nullptr;
+ return Code::cast(FixedArray::cast(get(EntryToIndex(entry)))->get(1));
}
-
-void CodeCacheHashTable::RemoveByIndex(int index) {
- DCHECK(index >= 0);
- Heap* heap = GetHeap();
- set(EntryToIndex(index), heap->the_hole_value());
- set(EntryToIndex(index) + 1, heap->the_hole_value());
- ElementRemoved();
-}
-
-
-void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> code_cache,
- MapHandleList* maps,
- Code::Flags flags,
- Handle<Code> code) {
- Isolate* isolate = code_cache->GetIsolate();
- if (code_cache->cache()->IsUndefined()) {
- Handle<PolymorphicCodeCacheHashTable> result =
- PolymorphicCodeCacheHashTable::New(
- isolate,
- PolymorphicCodeCacheHashTable::kInitialSize);
- code_cache->set_cache(*result);
- } else {
- // This entry shouldn't be contained in the cache yet.
- DCHECK(PolymorphicCodeCacheHashTable::cast(code_cache->cache())
- ->Lookup(maps, flags)->IsUndefined());
- }
- Handle<PolymorphicCodeCacheHashTable> hash_table =
- handle(PolymorphicCodeCacheHashTable::cast(code_cache->cache()));
- Handle<PolymorphicCodeCacheHashTable> new_cache =
- PolymorphicCodeCacheHashTable::Put(hash_table, maps, flags, code);
- code_cache->set_cache(*new_cache);
-}
-
-
-Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
- Code::Flags flags) {
- if (!cache()->IsUndefined()) {
- PolymorphicCodeCacheHashTable* hash_table =
- PolymorphicCodeCacheHashTable::cast(cache());
- return Handle<Object>(hash_table->Lookup(maps, flags), GetIsolate());
- } else {
- return GetIsolate()->factory()->undefined_value();
- }
-}
-
-
-// Despite their name, object of this class are not stored in the actual
-// hash table; instead they're temporarily used for lookups. It is therefore
-// safe to have a weak (non-owning) pointer to a MapList as a member field.
-class PolymorphicCodeCacheHashTableKey : public HashTableKey {
- public:
- // Callers must ensure that |maps| outlives the newly constructed object.
- PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
- : maps_(maps),
- code_flags_(code_flags) {}
-
- bool IsMatch(Object* other) override {
- MapHandleList other_maps(kDefaultListAllocationSize);
- int other_flags;
- FromObject(other, &other_flags, &other_maps);
- if (code_flags_ != other_flags) return false;
- if (maps_->length() != other_maps.length()) return false;
- // Compare just the hashes first because it's faster.
- int this_hash = MapsHashHelper(maps_, code_flags_);
- int other_hash = MapsHashHelper(&other_maps, other_flags);
- if (this_hash != other_hash) return false;
-
- // Full comparison: for each map in maps_, look for an equivalent map in
- // other_maps. This implementation is slow, but probably good enough for
- // now because the lists are short (<= 4 elements currently).
- for (int i = 0; i < maps_->length(); ++i) {
- bool match_found = false;
- for (int j = 0; j < other_maps.length(); ++j) {
- if (*(maps_->at(i)) == *(other_maps.at(j))) {
- match_found = true;
- break;
- }
- }
- if (!match_found) return false;
- }
- return true;
- }
-
- static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
- uint32_t hash = code_flags;
- for (int i = 0; i < maps->length(); ++i) {
- hash ^= maps->at(i)->Hash();
- }
- return hash;
- }
-
- uint32_t Hash() override { return MapsHashHelper(maps_, code_flags_); }
-
- uint32_t HashForObject(Object* obj) override {
- MapHandleList other_maps(kDefaultListAllocationSize);
- int other_flags;
- FromObject(obj, &other_flags, &other_maps);
- return MapsHashHelper(&other_maps, other_flags);
- }
-
- MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
- // The maps in |maps_| must be copied to a newly allocated FixedArray,
- // both because the referenced MapList is short-lived, and because C++
- // objects can't be stored in the heap anyway.
- Handle<FixedArray> list =
- isolate->factory()->NewUninitializedFixedArray(maps_->length() + 1);
- list->set(0, Smi::FromInt(code_flags_));
- for (int i = 0; i < maps_->length(); ++i) {
- list->set(i + 1, *maps_->at(i));
- }
- return list;
- }
-
- private:
- static MapHandleList* FromObject(Object* obj,
- int* code_flags,
- MapHandleList* maps) {
- FixedArray* list = FixedArray::cast(obj);
- maps->Rewind(0);
- *code_flags = Smi::cast(list->get(0))->value();
- for (int i = 1; i < list->length(); ++i) {
- maps->Add(Handle<Map>(Map::cast(list->get(i))));
- }
- return maps;
- }
-
- MapHandleList* maps_; // weak.
- int code_flags_;
- static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
-};
-
-
-Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
- int code_kind) {
- DisallowHeapAllocation no_alloc;
- PolymorphicCodeCacheHashTableKey key(maps, code_kind);
- int entry = FindEntry(&key);
- if (entry == kNotFound) return GetHeap()->undefined_value();
- return get(EntryToIndex(entry) + 1);
-}
-
-
-Handle<PolymorphicCodeCacheHashTable> PolymorphicCodeCacheHashTable::Put(
- Handle<PolymorphicCodeCacheHashTable> hash_table,
- MapHandleList* maps,
- int code_kind,
- Handle<Code> code) {
- PolymorphicCodeCacheHashTableKey key(maps, code_kind);
- Handle<PolymorphicCodeCacheHashTable> cache =
- EnsureCapacity(hash_table, 1, &key);
- int entry = cache->FindInsertionEntry(key.Hash());
-
- Handle<Object> obj = key.AsHandle(hash_table->GetIsolate());
- cache->set(EntryToIndex(entry), *obj);
- cache->set(EntryToIndex(entry) + 1, *code);
- cache->ElementAdded();
- return cache;
-}
-
-
void FixedArray::Shrink(int new_length) {
DCHECK(0 <= new_length && new_length <= length());
if (new_length < length()) {
@@ -10939,7 +9937,7 @@
.ToHandleChecked();
}
Isolate* isolate = accessor_pair->GetIsolate();
- if (accessor->IsTheHole()) {
+ if (accessor->IsNull()) {
return isolate->factory()->undefined_value();
}
return handle(accessor, isolate);
@@ -11268,25 +10266,6 @@
}
-base::SmartArrayPointer<uc16> String::ToWideCString(
- RobustnessFlag robust_flag) {
- if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
- return base::SmartArrayPointer<uc16>();
- }
- StringCharacterStream stream(this);
-
- uc16* result = NewArray<uc16>(length() + 1);
-
- int i = 0;
- while (stream.HasMore()) {
- uint16_t character = stream.GetNext();
- result[i++] = character;
- }
- result[i] = 0;
- return base::SmartArrayPointer<uc16>(result);
-}
-
-
const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
return reinterpret_cast<uc16*>(
reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
@@ -12332,15 +11311,18 @@
return false;
}
+void JSFunction::MarkForBaseline() {
+ Isolate* isolate = GetIsolate();
+ set_code_no_write_barrier(
+ isolate->builtins()->builtin(Builtins::kCompileBaseline));
+ // No write barrier required, since the builtin is part of the root set.
+}
void JSFunction::MarkForOptimization() {
Isolate* isolate = GetIsolate();
- // Do not optimize if function contains break points.
- if (shared()->HasDebugInfo()) return;
DCHECK(!IsOptimized());
DCHECK(shared()->allows_lazy_compilation() ||
!shared()->optimization_disabled());
- DCHECK(!shared()->HasDebugInfo());
set_code_no_write_barrier(
isolate->builtins()->builtin(Builtins::kCompileOptimized));
// No write barrier required, since the builtin is part of the root set.
@@ -12839,6 +11821,8 @@
// static
void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype,
PrototypeOptimizationMode proto_mode) {
+ RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype);
+
bool is_hidden = false;
if (prototype->IsJSObject()) {
Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
@@ -12964,8 +11948,13 @@
new_map->SetConstructor(*value);
new_map->set_non_instance_prototype(true);
Isolate* isolate = new_map->GetIsolate();
+
construct_prototype = handle(
- function->context()->native_context()->initial_object_prototype(),
+ IsGeneratorFunction(function->shared()->kind())
+ ? function->context()
+ ->native_context()
+ ->initial_generator_prototype()
+ : function->context()->native_context()->initial_object_prototype(),
isolate);
} else {
function->map()->set_non_instance_prototype(false);
@@ -13020,50 +12009,52 @@
bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
switch (instance_type) {
- case JS_OBJECT_TYPE:
- case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
- case JS_GENERATOR_OBJECT_TYPE:
- case JS_MODULE_TYPE:
- case JS_VALUE_TYPE:
- case JS_DATE_TYPE:
- case JS_ARRAY_TYPE:
- case JS_MESSAGE_OBJECT_TYPE:
+ case JS_API_OBJECT_TYPE:
case JS_ARRAY_BUFFER_TYPE:
- case JS_TYPED_ARRAY_TYPE:
+ case JS_ARRAY_TYPE:
+ case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_DATA_VIEW_TYPE:
- case JS_SET_TYPE:
- case JS_MAP_TYPE:
- case JS_SET_ITERATOR_TYPE:
+ case JS_DATE_TYPE:
+ case JS_FUNCTION_TYPE:
+ case JS_GENERATOR_OBJECT_TYPE:
case JS_MAP_ITERATOR_TYPE:
- case JS_WEAK_MAP_TYPE:
- case JS_WEAK_SET_TYPE:
+ case JS_MAP_TYPE:
+ case JS_MESSAGE_OBJECT_TYPE:
+ case JS_MODULE_TYPE:
+ case JS_OBJECT_TYPE:
case JS_PROMISE_TYPE:
case JS_REGEXP_TYPE:
- case JS_FUNCTION_TYPE:
+ case JS_SET_ITERATOR_TYPE:
+ case JS_SET_TYPE:
+ case JS_SPECIAL_API_OBJECT_TYPE:
+ case JS_TYPED_ARRAY_TYPE:
+ case JS_VALUE_TYPE:
+ case JS_WEAK_MAP_TYPE:
+ case JS_WEAK_SET_TYPE:
return true;
- case JS_BOUND_FUNCTION_TYPE:
- case JS_PROXY_TYPE:
- case JS_GLOBAL_PROXY_TYPE:
- case JS_GLOBAL_OBJECT_TYPE:
+ case BYTECODE_ARRAY_TYPE:
+ case BYTE_ARRAY_TYPE:
+ case CELL_TYPE:
+ case CODE_TYPE:
+ case FILLER_TYPE:
case FIXED_ARRAY_TYPE:
case FIXED_DOUBLE_ARRAY_TYPE:
- case ODDBALL_TYPE:
case FOREIGN_TYPE:
- case MAP_TYPE:
- case CODE_TYPE:
- case CELL_TYPE:
- case PROPERTY_CELL_TYPE:
- case WEAK_CELL_TYPE:
- case SYMBOL_TYPE:
- case BYTECODE_ARRAY_TYPE:
- case HEAP_NUMBER_TYPE:
- case MUTABLE_HEAP_NUMBER_TYPE:
- case SIMD128_VALUE_TYPE:
- case FILLER_TYPE:
- case BYTE_ARRAY_TYPE:
case FREE_SPACE_TYPE:
+ case HEAP_NUMBER_TYPE:
+ case JS_BOUND_FUNCTION_TYPE:
+ case JS_GLOBAL_OBJECT_TYPE:
+ case JS_GLOBAL_PROXY_TYPE:
+ case JS_PROXY_TYPE:
+ case MAP_TYPE:
+ case MUTABLE_HEAP_NUMBER_TYPE:
+ case ODDBALL_TYPE:
+ case PROPERTY_CELL_TYPE:
case SHARED_FUNCTION_INFO_TYPE:
+ case SIMD128_VALUE_TYPE:
+ case SYMBOL_TYPE:
+ case WEAK_CELL_TYPE:
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
case FIXED_##TYPE##_ARRAY_TYPE:
@@ -13085,7 +12076,7 @@
void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
- DCHECK(function->IsConstructor() || function->shared()->is_generator());
+ DCHECK(function->IsConstructor() || function->shared()->is_resumable());
if (function->has_initial_map()) return;
Isolate* isolate = function->GetIsolate();
@@ -13096,7 +12087,7 @@
// First create a new map with the size and number of in-object properties
// suggested by the function.
InstanceType instance_type;
- if (function->shared()->is_generator()) {
+ if (function->shared()->is_resumable()) {
instance_type = JS_GENERATOR_OBJECT_TYPE;
} else {
instance_type = JS_OBJECT_TYPE;
@@ -13296,18 +12287,6 @@
return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
}
-// static
-MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
- Handle<JSBoundFunction> function) {
- Handle<String> prefix = isolate->factory()->bound__string();
- if (!function->bound_target_function()->IsJSFunction()) return prefix;
- Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
- isolate);
- Handle<Object> target_name = JSFunction::GetName(target);
- if (!target_name->IsString()) return prefix;
- Factory* factory = isolate->factory();
- return factory->NewConsString(prefix, Handle<String>::cast(target_name));
-}
// static
Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
@@ -13341,10 +12320,16 @@
IncrementalStringBuilder builder(isolate);
if (!shared_info->is_arrow()) {
if (shared_info->is_concise_method()) {
- if (shared_info->is_generator()) builder.AppendCharacter('*');
+ if (shared_info->is_generator()) {
+ builder.AppendCharacter('*');
+ } else if (shared_info->is_async()) {
+ builder.AppendCString("async ");
+ }
} else {
if (shared_info->is_generator()) {
builder.AppendCString("function* ");
+ } else if (shared_info->is_async()) {
+ builder.AppendCString("async function ");
} else {
builder.AppendCString("function ");
}
@@ -13366,6 +12351,7 @@
isolate->factory()->InternalizeUtf8String(to_string);
Handle<String> internalized_type_of =
isolate->factory()->InternalizeUtf8String(type_of);
+ oddball->set_to_number_raw(to_number->Number());
oddball->set_to_boolean(isolate->heap()->ToBoolean(to_boolean));
oddball->set_to_number(*to_number);
oddball->set_to_string(*internalized_to_string);
@@ -13373,6 +12359,45 @@
oddball->set_kind(kind);
}
+void Script::SetEvalOrigin(Handle<Script> script,
+ Handle<SharedFunctionInfo> outer_info,
+ int eval_position) {
+ if (eval_position == RelocInfo::kNoPosition) {
+ // If the position is missing, attempt to get the code offset from the
+ // current activation. Do not translate the code offset into source
+ // position, but store it as negative value for lazy translation.
+ StackTraceFrameIterator it(script->GetIsolate());
+ if (!it.done() && it.is_javascript()) {
+ FrameSummary summary = FrameSummary::GetFirst(it.javascript_frame());
+ script->set_eval_from_shared(summary.function()->shared());
+ script->set_eval_from_position(-summary.code_offset());
+ return;
+ }
+ eval_position = 0;
+ }
+ script->set_eval_from_shared(*outer_info);
+ script->set_eval_from_position(eval_position);
+}
+
+int Script::GetEvalPosition() {
+ DisallowHeapAllocation no_gc;
+ DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL);
+ int position = eval_from_position();
+ if (position < 0) {
+ // Due to laziness, the position may not have been translated from code
+ // offset yet, which would be encoded as negative integer. In that case,
+ // translate and set the position.
+ if (eval_from_shared()->IsUndefined()) {
+ position = 0;
+ } else {
+ SharedFunctionInfo* shared = SharedFunctionInfo::cast(eval_from_shared());
+ position = shared->abstract_code()->SourcePosition(-position);
+ }
+ DCHECK(position >= 0);
+ set_eval_from_position(position);
+ }
+ return position;
+}
void Script::InitLineEnds(Handle<Script> script) {
if (!script->line_ends()->IsUndefined()) return;
@@ -13515,7 +12540,8 @@
SharedFunctionInfo* shared;
while ((shared = iterator.Next<SharedFunctionInfo>())) {
if (fun->function_token_position() == shared->function_token_position() &&
- fun->start_position() == shared->start_position()) {
+ fun->start_position() == shared->start_position() &&
+ fun->end_position() == shared->end_position()) {
return Handle<SharedFunctionInfo>(shared);
}
}
@@ -13813,6 +12839,32 @@
}
}
+namespace {
+
+// Sets the expected number of properties based on estimate from parser.
+void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
+ FunctionLiteral* literal) {
+ int estimate = literal->expected_property_count();
+
+ // If no properties are added in the constructor, they are more likely
+ // to be added later.
+ if (estimate == 0) estimate = 2;
+
+ // TODO(yangguo): check whether those heuristics are still up-to-date.
+ // We do not shrink objects that go into a snapshot (yet), so we adjust
+ // the estimate conservatively.
+ if (shared->GetIsolate()->serializer_enabled()) {
+ estimate += 2;
+ } else {
+ // Inobject slack tracking will reclaim redundant inobject space later,
+ // so we can afford to adjust the estimate generously.
+ estimate += 8;
+ }
+
+ shared->set_expected_nof_properties(estimate);
+}
+
+} // namespace
void SharedFunctionInfo::InitFromFunctionLiteral(
Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) {
@@ -13838,6 +12890,7 @@
}
shared_info->set_dont_crankshaft(lit->flags() &
AstProperties::kDontCrankshaft);
+ shared_info->set_never_compiled(true);
shared_info->set_kind(lit->kind());
if (!IsConstructable(lit->kind(), lit->language_mode())) {
shared_info->set_construct_stub(
@@ -13845,6 +12898,7 @@
}
shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
shared_info->set_asm_function(lit->scope()->asm_function());
+ SetExpectedNofPropertiesFromEstimate(shared_info, lit);
}
@@ -13880,8 +12934,15 @@
set_ic_age(new_ic_age);
if (code()->kind() == Code::FUNCTION) {
code()->set_profiler_ticks(0);
- if (optimization_disabled() &&
- opt_count() >= FLAG_max_opt_count) {
+ if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) {
+ // Re-enable optimizations if they were disabled due to opt_count limit.
+ set_optimization_disabled(false);
+ }
+ set_opt_count(0);
+ set_deopt_count(0);
+ } else if (code()->is_interpreter_entry_trampoline()) {
+ set_profiler_ticks(0);
+ if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) {
// Re-enable optimizations if they were disabled due to opt_count limit.
set_optimization_disabled(false);
}
@@ -13941,12 +13002,6 @@
: LiteralsArray::cast(literals_cell->value())};
}
}
- if (FLAG_trace_opt && !OptimizedCodeMapIsCleared() &&
- result.code == nullptr) {
- PrintF("[didn't find optimized code in optimized code map for ");
- ShortPrint();
- PrintF("]\n");
- }
return result;
}
@@ -14230,126 +13285,14 @@
}
-void Code::FindAllMaps(MapHandleList* maps) {
- DCHECK(is_inline_cache_stub());
- DisallowHeapAllocation no_allocation;
- int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- for (RelocIterator it(this, mask); !it.done(); it.next()) {
- RelocInfo* info = it.rinfo();
- Object* object = info->target_object();
- if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
- if (object->IsMap()) maps->Add(handle(Map::cast(object)));
- }
-}
-
-
-Code* Code::FindFirstHandler() {
- DCHECK(is_inline_cache_stub());
- DisallowHeapAllocation no_allocation;
- int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
- RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- bool skip_next_handler = false;
- for (RelocIterator it(this, mask); !it.done(); it.next()) {
- RelocInfo* info = it.rinfo();
- if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
- Object* obj = info->target_object();
- skip_next_handler |= obj->IsWeakCell() && WeakCell::cast(obj)->cleared();
- } else {
- Code* code = Code::GetCodeFromTargetAddress(info->target_address());
- if (code->kind() == Code::HANDLER) {
- if (!skip_next_handler) return code;
- skip_next_handler = false;
- }
- }
- }
- return NULL;
-}
-
-
-bool Code::FindHandlers(CodeHandleList* code_list, int length) {
- DCHECK(is_inline_cache_stub());
- DisallowHeapAllocation no_allocation;
- int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
- RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- bool skip_next_handler = false;
- int i = 0;
- for (RelocIterator it(this, mask); !it.done(); it.next()) {
- if (i == length) return true;
- RelocInfo* info = it.rinfo();
- if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
- Object* obj = info->target_object();
- skip_next_handler |= obj->IsWeakCell() && WeakCell::cast(obj)->cleared();
- } else {
- Code* code = Code::GetCodeFromTargetAddress(info->target_address());
- // IC stubs with handlers never contain non-handler code objects before
- // handler targets.
- if (code->kind() != Code::HANDLER) break;
- if (!skip_next_handler) {
- code_list->Add(Handle<Code>(code));
- i++;
- }
- skip_next_handler = false;
- }
- }
- return i == length;
-}
-
-
-MaybeHandle<Code> Code::FindHandlerForMap(Map* map) {
- DCHECK(is_inline_cache_stub());
- int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
- RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- bool return_next = false;
- for (RelocIterator it(this, mask); !it.done(); it.next()) {
- RelocInfo* info = it.rinfo();
- if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
- Object* object = info->target_object();
- if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
- if (object == map) return_next = true;
- } else if (return_next) {
- Code* code = Code::GetCodeFromTargetAddress(info->target_address());
- DCHECK(code->kind() == Code::HANDLER);
- return handle(code);
- }
- }
- return MaybeHandle<Code>();
-}
-
-
-Name* Code::FindFirstName() {
- DCHECK(is_inline_cache_stub());
- DisallowHeapAllocation no_allocation;
- int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- for (RelocIterator it(this, mask); !it.done(); it.next()) {
- RelocInfo* info = it.rinfo();
- Object* object = info->target_object();
- if (object->IsName()) return Name::cast(object);
- }
- return NULL;
-}
-
-
void Code::ClearInlineCaches() {
- ClearInlineCaches(NULL);
-}
-
-
-void Code::ClearInlineCaches(Code::Kind kind) {
- ClearInlineCaches(&kind);
-}
-
-
-void Code::ClearInlineCaches(Code::Kind* kind) {
int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
for (RelocIterator it(this, mask); !it.done(); it.next()) {
RelocInfo* info = it.rinfo();
Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
if (target->is_inline_cache_stub()) {
- if (kind == NULL || *kind == target->kind()) {
- IC::Clear(this->GetIsolate(), info->pc(),
- info->host()->constant_pool());
- }
+ IC::Clear(this->GetIsolate(), info->pc(), info->host()->constant_pool());
}
}
}
@@ -14841,8 +13784,9 @@
int pc_and_state = this->PcAndState(i)->value();
os << std::setw(6) << this->AstId(i).ToInt() << " " << std::setw(8)
<< FullCodeGenerator::PcField::decode(pc_and_state) << " "
- << FullCodeGenerator::State2String(
- FullCodeGenerator::StateField::decode(pc_and_state)) << "\n";
+ << Deoptimizer::BailoutStateToString(
+ FullCodeGenerator::BailoutStateField::decode(pc_and_state))
+ << "\n";
}
}
@@ -14881,8 +13825,8 @@
case UNINITIALIZED: return "UNINITIALIZED";
case PREMONOMORPHIC: return "PREMONOMORPHIC";
case MONOMORPHIC: return "MONOMORPHIC";
- case PROTOTYPE_FAILURE:
- return "PROTOTYPE_FAILURE";
+ case RECOMPUTE_HANDLER:
+ return "RECOMPUTE_HANDLER";
case POLYMORPHIC: return "POLYMORPHIC";
case MEGAMORPHIC: return "MEGAMORPHIC";
case GENERIC: return "GENERIC";
@@ -14893,16 +13837,6 @@
}
-const char* Code::StubType2String(StubType type) {
- switch (type) {
- case NORMAL: return "NORMAL";
- case FAST: return "FAST";
- }
- UNREACHABLE(); // keep the compiler happy
- return NULL;
-}
-
-
void Code::PrintExtraICState(std::ostream& os, // NOLINT
Kind kind, ExtraICState extra) {
os << "extra_ic_state = ";
@@ -14924,9 +13858,6 @@
if (is_inline_cache_stub()) {
os << "ic_state = " << ICState2String(ic_state()) << "\n";
PrintExtraICState(os, kind(), extra_ic_state());
- if (ic_state() == MONOMORPHIC) {
- os << "type = " << StubType2String(type()) << "\n";
- }
if (is_compare_ic_stub()) {
DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC);
CompareICStub stub(stub_key(), GetIsolate());
@@ -15103,7 +14034,6 @@
void BytecodeArray::Disassemble(std::ostream& os) {
os << "Parameter count " << parameter_count() << "\n";
os << "Frame size " << frame_size() << "\n";
- Vector<char> buf = Vector<char>::New(50);
const uint8_t* base_address = GetFirstBytecodeAddress();
interpreter::SourcePositionTableIterator source_positions(
@@ -15120,12 +14050,13 @@
os << " ";
}
const uint8_t* current_address = base_address + iterator.current_offset();
- SNPrintF(buf, "%p", current_address);
- os << buf.start() << " : ";
+ os << reinterpret_cast<const void*>(current_address) << " @ "
+ << std::setw(4) << iterator.current_offset() << " : ";
interpreter::Bytecodes::Decode(os, current_address, parameter_count());
if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) {
- SNPrintF(buf, " (%p)", base_address + iterator.GetJumpTargetOffset());
- os << buf.start();
+ const void* jump_target = base_address + iterator.GetJumpTargetOffset();
+ os << " (" << jump_target << " @ " << iterator.GetJumpTargetOffset()
+ << ")";
}
os << std::endl;
iterator.Advance();
@@ -15158,29 +14089,6 @@
array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
}
-
-// Returns false if the passed-in index is marked non-configurable, which will
-// cause the truncation operation to halt, and thus no further old values need
-// be collected.
-static bool GetOldValue(Isolate* isolate,
- Handle<JSObject> object,
- uint32_t index,
- List<Handle<Object> >* old_values,
- List<uint32_t>* indices) {
- LookupIterator it(isolate, object, index, object, LookupIterator::HIDDEN);
- CHECK(JSReceiver::GetPropertyAttributes(&it).IsJust());
- DCHECK(it.IsFound());
- if (!it.IsConfigurable()) return false;
- Handle<Object> value =
- it.state() == LookupIterator::ACCESSOR
- ? Handle<Object>::cast(isolate->factory()->the_hole_value())
- : JSReceiver::GetDataProperty(&it);
- old_values->Add(value);
- indices->Add(index);
- return true;
-}
-
-
void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
// We should never end in here with a pixel or external array.
DCHECK(array->AllowsSetLength());
@@ -15191,91 +14099,6 @@
}
-MaybeHandle<Object> JSArray::ObservableSetLength(Handle<JSArray> array,
- uint32_t new_length) {
- if (!array->map()->is_observed()) {
- SetLength(array, new_length);
- return array;
- }
-
- Isolate* isolate = array->GetIsolate();
- List<uint32_t> indices;
- List<Handle<Object> > old_values;
- Handle<Object> old_length_handle(array->length(), isolate);
- uint32_t old_length = 0;
- CHECK(old_length_handle->ToArrayLength(&old_length));
-
- int num_elements = array->NumberOfOwnElements(ALL_PROPERTIES);
- if (num_elements > 0) {
- if (old_length == static_cast<uint32_t>(num_elements)) {
- // Simple case for arrays without holes.
- for (uint32_t i = old_length - 1; i + 1 > new_length; --i) {
- if (!GetOldValue(isolate, array, i, &old_values, &indices)) break;
- }
- } else {
- // For sparse arrays, only iterate over existing elements.
- // TODO(rafaelw): For fast, sparse arrays, we can avoid iterating over
- // the to-be-removed indices twice.
- Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements);
- array->GetOwnElementKeys(*keys, ALL_PROPERTIES);
- while (num_elements-- > 0) {
- uint32_t index = NumberToUint32(keys->get(num_elements));
- if (index < new_length) break;
- if (!GetOldValue(isolate, array, index, &old_values, &indices)) break;
- }
- }
- }
-
- SetLength(array, new_length);
-
- CHECK(array->length()->ToArrayLength(&new_length));
- if (old_length == new_length) return array;
-
- RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object);
-
- for (int i = 0; i < indices.length(); ++i) {
- // For deletions where the property was an accessor, old_values[i]
- // will be the hole, which instructs EnqueueChangeRecord to elide
- // the "oldValue" property.
- RETURN_ON_EXCEPTION(
- isolate,
- JSObject::EnqueueChangeRecord(
- array, "delete", isolate->factory()->Uint32ToString(indices[i]),
- old_values[i]),
- Object);
- }
-
- RETURN_ON_EXCEPTION(isolate,
- JSObject::EnqueueChangeRecord(
- array, "update", isolate->factory()->length_string(),
- old_length_handle),
- Object);
-
- RETURN_ON_EXCEPTION(isolate, EndPerformSplice(array), Object);
-
- uint32_t index = Min(old_length, new_length);
- uint32_t add_count = new_length > old_length ? new_length - old_length : 0;
- uint32_t delete_count = new_length < old_length ? old_length - new_length : 0;
- Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
- if (delete_count > 0) {
- for (int i = indices.length() - 1; i >= 0; i--) {
- // Skip deletions where the property was an accessor, leaving holes
- // in the array of old values.
- if (old_values[i]->IsTheHole()) continue;
- JSObject::AddDataElement(deleted, indices[i] - index, old_values[i], NONE)
- .Assert();
- }
-
- JSArray::SetLength(deleted, delete_count);
- }
-
- RETURN_ON_EXCEPTION(
- isolate, EnqueueSpliceRecord(array, index, deleted, add_count), Object);
-
- return array;
-}
-
-
// static
void Map::AddDependentCode(Handle<Map> map,
DependentCode::DependencyGroup group,
@@ -15603,7 +14426,7 @@
bool from_javascript,
ShouldThrow should_throw) {
Isolate* isolate = proxy->GetIsolate();
- STACK_CHECK(Nothing<bool>());
+ STACK_CHECK(isolate, Nothing<bool>());
Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
// 1. Assert: Either Type(V) is Object or Type(V) is Null.
DCHECK(value->IsJSReceiver() || value->IsNull());
@@ -15674,46 +14497,10 @@
ShouldThrow should_throw) {
Isolate* isolate = object->GetIsolate();
- const bool observed = from_javascript && object->map()->is_observed();
- Handle<Object> old_value;
- if (observed) {
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, old_value,
- JSReceiver::GetPrototype(isolate, object),
- Nothing<bool>());
- }
-
- Maybe<bool> result =
- SetPrototypeUnobserved(object, value, from_javascript, should_throw);
- MAYBE_RETURN(result, Nothing<bool>());
-
- if (result.FromJust() && observed) {
- Handle<Object> new_value;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, new_value,
- JSReceiver::GetPrototype(isolate, object),
- Nothing<bool>());
- if (!new_value->SameValue(*old_value)) {
- RETURN_ON_EXCEPTION_VALUE(
- isolate, JSObject::EnqueueChangeRecord(
- object, "setPrototype",
- isolate->factory()->proto_string(), old_value),
- Nothing<bool>());
- }
- }
-
- return result;
-}
-
-
-Maybe<bool> JSObject::SetPrototypeUnobserved(Handle<JSObject> object,
- Handle<Object> value,
- bool from_javascript,
- ShouldThrow should_throw) {
#ifdef DEBUG
int size = object->Size();
#endif
- Isolate* isolate = object->GetIsolate();
-
if (from_javascript) {
if (object->IsAccessCheckNeeded() &&
!isolate->MayAccess(handle(isolate->context()), object)) {
@@ -15949,12 +14736,8 @@
uint32_t old_length = 0;
uint32_t new_capacity = 0;
- Handle<Object> old_length_handle;
if (object->IsJSArray()) {
CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
- if (object->map()->is_observed()) {
- old_length_handle = handle(JSArray::cast(*object)->length(), isolate);
- }
}
ElementsKind kind = object->GetElementsKind();
@@ -15998,38 +14781,6 @@
JSArray::cast(*object)->set_length(*new_length_handle);
}
- if (!old_length_handle.is_null() && new_length != old_length) {
- // |old_length_handle| is kept null above unless the object is observed.
- DCHECK(object->map()->is_observed());
- Handle<JSArray> array = Handle<JSArray>::cast(object);
- Handle<String> name = isolate->factory()->Uint32ToString(index);
-
- RETURN_ON_EXCEPTION_VALUE(isolate, BeginPerformSplice(array),
- Nothing<bool>());
- RETURN_ON_EXCEPTION_VALUE(
- isolate, EnqueueChangeRecord(array, "add", name,
- isolate->factory()->the_hole_value()),
- Nothing<bool>());
- RETURN_ON_EXCEPTION_VALUE(
- isolate, EnqueueChangeRecord(array, "update",
- isolate->factory()->length_string(),
- old_length_handle),
- Nothing<bool>());
- RETURN_ON_EXCEPTION_VALUE(isolate, EndPerformSplice(array),
- Nothing<bool>());
- Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
- RETURN_ON_EXCEPTION_VALUE(isolate,
- EnqueueSpliceRecord(array, old_length, deleted,
- new_length - old_length),
- Nothing<bool>());
- } else if (object->map()->is_observed()) {
- Handle<String> name = isolate->factory()->Uint32ToString(index);
- RETURN_ON_EXCEPTION_VALUE(
- isolate, EnqueueChangeRecord(object, "add", name,
- isolate->factory()->the_hole_value()),
- Nothing<bool>());
- }
-
return Just(true);
}
@@ -16520,188 +15271,25 @@
}
}
-void JSObject::CollectOwnPropertyNames(KeyAccumulator* keys,
- PropertyFilter filter) {
- if (HasFastProperties()) {
- int real_size = map()->NumberOfOwnDescriptors();
- Handle<DescriptorArray> descs(map()->instance_descriptors());
- for (int i = 0; i < real_size; i++) {
- PropertyDetails details = descs->GetDetails(i);
- if ((details.attributes() & filter) != 0) continue;
- if (filter & ONLY_ALL_CAN_READ) {
- if (details.kind() != kAccessor) continue;
- Object* accessors = descs->GetValue(i);
- if (!accessors->IsAccessorInfo()) continue;
- if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
- }
- Name* key = descs->GetKey(i);
- if (key->FilterKey(filter)) continue;
- keys->AddKey(key, DO_NOT_CONVERT);
- }
- } else if (IsJSGlobalObject()) {
- GlobalDictionary::CollectKeysTo(handle(global_dictionary()), keys, filter);
- } else {
- NameDictionary::CollectKeysTo(handle(property_dictionary()), keys, filter);
- }
-}
-
-
-int JSObject::NumberOfOwnElements(PropertyFilter filter) {
- // Fast case for objects with no elements.
- if (!IsJSValue() && HasFastElements()) {
- uint32_t length =
- IsJSArray()
- ? static_cast<uint32_t>(
- Smi::cast(JSArray::cast(this)->length())->value())
- : static_cast<uint32_t>(FixedArrayBase::cast(elements())->length());
- if (length == 0) return 0;
- }
- // Compute the number of enumerable elements.
- return GetOwnElementKeys(NULL, filter);
-}
-
-void JSObject::CollectOwnElementKeys(Handle<JSObject> object,
- KeyAccumulator* keys,
- PropertyFilter filter) {
- if (filter & SKIP_STRINGS) return;
- ElementsAccessor* accessor = object->GetElementsAccessor();
- accessor->CollectElementIndices(object, keys, kMaxUInt32, filter, 0);
-}
-
-
-int JSObject::GetOwnElementKeys(FixedArray* storage, PropertyFilter filter) {
- int counter = 0;
-
- // If this is a String wrapper, add the string indices first,
- // as they're guaranteed to precede the elements in numerical order
- // and ascending order is required by ECMA-262, 6th, 9.1.12.
- if (IsJSValue()) {
- Object* val = JSValue::cast(this)->value();
- if (val->IsString()) {
- String* str = String::cast(val);
- if (storage) {
- for (int i = 0; i < str->length(); i++) {
- storage->set(counter + i, Smi::FromInt(i));
- }
- }
- counter += str->length();
+bool JSObject::WasConstructedFromApiFunction() {
+ auto instance_type = map()->instance_type();
+ bool is_api_object = instance_type == JS_API_OBJECT_TYPE ||
+ instance_type == JS_SPECIAL_API_OBJECT_TYPE;
+#ifdef ENABLE_SLOW_DCHECKS
+ if (FLAG_enable_slow_asserts) {
+ Object* maybe_constructor = map()->GetConstructor();
+ if (!maybe_constructor->IsJSFunction()) return false;
+ JSFunction* constructor = JSFunction::cast(maybe_constructor);
+ if (constructor->shared()->IsApiFunction()) {
+ DCHECK(is_api_object);
+ } else {
+ DCHECK(!is_api_object);
}
}
-
- switch (GetElementsKind()) {
- case FAST_SMI_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_ELEMENTS:
- case FAST_STRING_WRAPPER_ELEMENTS: {
- int length = IsJSArray() ?
- Smi::cast(JSArray::cast(this)->length())->value() :
- FixedArray::cast(elements())->length();
- for (int i = 0; i < length; i++) {
- if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
- if (storage != NULL) {
- storage->set(counter, Smi::FromInt(i));
- }
- counter++;
- }
- }
- DCHECK(!storage || storage->length() >= counter);
- break;
- }
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS: {
- int length = IsJSArray() ?
- Smi::cast(JSArray::cast(this)->length())->value() :
- FixedArrayBase::cast(elements())->length();
- for (int i = 0; i < length; i++) {
- if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
- if (storage != NULL) {
- storage->set(counter, Smi::FromInt(i));
- }
- counter++;
- }
- }
- DCHECK(!storage || storage->length() >= counter);
- break;
- }
-
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case TYPE##_ELEMENTS: \
-
- TYPED_ARRAYS(TYPED_ARRAY_CASE)
-#undef TYPED_ARRAY_CASE
- {
- int length = FixedArrayBase::cast(elements())->length();
- while (counter < length) {
- if (storage != NULL) {
- storage->set(counter, Smi::FromInt(counter));
- }
- counter++;
- }
- DCHECK(!storage || storage->length() >= counter);
- break;
- }
-
- case DICTIONARY_ELEMENTS:
- case SLOW_STRING_WRAPPER_ELEMENTS: {
- if (storage != NULL) {
- element_dictionary()->CopyKeysTo(storage, counter, filter,
- SeededNumberDictionary::SORTED);
- }
- counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
- break;
- }
- case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
- case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
- FixedArray* parameter_map = FixedArray::cast(elements());
- int mapped_length = parameter_map->length() - 2;
- FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
- if (arguments->IsDictionary()) {
- // Copy the keys from arguments first, because Dictionary::CopyKeysTo
- // will insert in storage starting at index 0.
- SeededNumberDictionary* dictionary =
- SeededNumberDictionary::cast(arguments);
- if (storage != NULL) {
- dictionary->CopyKeysTo(storage, counter, filter,
- SeededNumberDictionary::UNSORTED);
- }
- counter += dictionary->NumberOfElementsFilterAttributes(filter);
- for (int i = 0; i < mapped_length; ++i) {
- if (!parameter_map->get(i + 2)->IsTheHole()) {
- if (storage != NULL) storage->set(counter, Smi::FromInt(i));
- ++counter;
- }
- }
- if (storage != NULL) storage->SortPairs(storage, counter);
-
- } else {
- int backing_length = arguments->length();
- int i = 0;
- for (; i < mapped_length; ++i) {
- if (!parameter_map->get(i + 2)->IsTheHole()) {
- if (storage != NULL) storage->set(counter, Smi::FromInt(i));
- ++counter;
- } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
- if (storage != NULL) storage->set(counter, Smi::FromInt(i));
- ++counter;
- }
- }
- for (; i < backing_length; ++i) {
- if (storage != NULL) storage->set(counter, Smi::FromInt(i));
- ++counter;
- }
- }
- break;
- }
- case NO_ELEMENTS:
- break;
- }
-
- DCHECK(!storage || storage->length() == counter);
- return counter;
+#endif
+ return is_api_object;
}
-
MaybeHandle<String> Object::ObjectProtoToString(Isolate* isolate,
Handle<Object> object) {
if (object->IsUndefined()) return isolate->factory()->undefined_to_string();
@@ -16900,22 +15488,6 @@
// static
-MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern,
- Handle<String> flags_string) {
- Isolate* isolate = pattern->GetIsolate();
- bool success = false;
- Flags flags = RegExpFlagsFromString(flags_string, &success);
- if (!success) {
- THROW_NEW_ERROR(
- isolate,
- NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
- JSRegExp);
- }
- return New(pattern, flags);
-}
-
-
-// static
Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
Isolate* const isolate = regexp->GetIsolate();
return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
@@ -17006,6 +15578,9 @@
ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
EscapeRegExpSource(isolate, source), JSRegExp);
+ RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags),
+ JSRegExp);
+
regexp->set_source(*escaped_source);
regexp->set_flags(Smi::FromInt(flags));
@@ -17026,9 +15601,6 @@
.Check();
}
- RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags),
- JSRegExp);
-
return regexp;
}
@@ -17238,10 +15810,13 @@
// Rehash the elements.
int capacity = this->Capacity();
+ Heap* heap = new_table->GetHeap();
+ Object* the_hole = heap->the_hole_value();
+ Object* undefined = heap->undefined_value();
for (int i = 0; i < capacity; i++) {
uint32_t from_index = EntryToIndex(i);
Object* k = this->get(from_index);
- if (IsKey(k)) {
+ if (k != the_hole && k != undefined) {
uint32_t hash = this->HashForObject(key, k);
uint32_t insertion_index =
EntryToIndex(new_table->FindInsertionEntry(hash));
@@ -17415,9 +15990,12 @@
uint32_t entry = FirstProbe(hash, capacity);
uint32_t count = 1;
// EnsureCapacity will guarantee the hash table is never full.
+ Heap* heap = GetHeap();
+ Object* the_hole = heap->the_hole_value();
+ Object* undefined = heap->undefined_value();
while (true) {
Object* element = KeyAt(entry);
- if (element->IsUndefined() || element->IsTheHole()) break;
+ if (element == the_hole || element == undefined) break;
entry = NextProbe(entry, count++, capacity);
}
return entry;
@@ -17564,6 +16142,30 @@
template int NameDictionaryBase<NameDictionary, NameDictionaryShape>::FindEntry(
Handle<Name>);
+template int Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
+ NumberOfElementsFilterAttributes(PropertyFilter filter);
+
+template int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::
+ NumberOfElementsFilterAttributes(PropertyFilter filter);
+
+template void Dictionary<GlobalDictionary, GlobalDictionaryShape,
+ Handle<Name>>::CopyEnumKeysTo(FixedArray* storage);
+
+template void Dictionary<NameDictionary, NameDictionaryShape,
+ Handle<Name>>::CopyEnumKeysTo(FixedArray* storage);
+
+template void
+Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
+ CollectKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
+ Handle<Name>>>
+ dictionary,
+ KeyAccumulator* keys, PropertyFilter filter);
+
+template void
+Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CollectKeysTo(
+ Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
+ dictionary,
+ KeyAccumulator* keys, PropertyFilter filter);
Handle<Object> JSObject::PrepareSlowElementsForSort(
Handle<JSObject> object, uint32_t limit) {
@@ -17660,8 +16262,7 @@
Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
uint32_t limit) {
Isolate* isolate = object->GetIsolate();
- if (object->HasSloppyArgumentsElements() ||
- object->map()->is_observed()) {
+ if (object->HasSloppyArgumentsElements()) {
return handle(Smi::FromInt(-1), isolate);
}
@@ -17991,6 +16592,16 @@
Handle<ConsString> cons = Handle<ConsString>::cast(string);
cons->set_first(*result);
cons->set_second(isolate->heap()->empty_string());
+ } else if (string->IsSlicedString()) {
+ STATIC_ASSERT(ConsString::kSize == SlicedString::kSize);
+ DisallowHeapAllocation no_gc;
+ bool one_byte = result->IsOneByteRepresentation();
+ Handle<Map> map = one_byte ? isolate->factory()->cons_one_byte_string_map()
+ : isolate->factory()->cons_string_map();
+ string->set_map(*map);
+ Handle<ConsString> cons = Handle<ConsString>::cast(string);
+ cons->set_first(*result);
+ cons->set_second(isolate->heap()->empty_string());
}
return result;
}
@@ -18097,23 +16708,11 @@
Isolate* isolate = cache->GetIsolate();
Handle<SharedFunctionInfo> shared(context->closure()->shared());
StringSharedKey key(src, shared, language_mode, RelocInfo::kNoPosition);
- {
- Handle<Object> k = key.AsHandle(isolate);
- DisallowHeapAllocation no_allocation_scope;
- int entry = cache->FindEntry(&key);
- if (entry != kNotFound) {
- cache->set(EntryToIndex(entry), *k);
- cache->set(EntryToIndex(entry) + 1, *value);
- return cache;
- }
- }
-
+ Handle<Object> k = key.AsHandle(isolate);
cache = EnsureCapacity(cache, 1, &key);
int entry = cache->FindInsertionEntry(key.Hash());
- Handle<Object> k =
- isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
cache->set(EntryToIndex(entry), *k);
- cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
+ cache->set(EntryToIndex(entry) + 1, *value);
cache->ElementAdded();
return cache;
}
@@ -18542,30 +17141,6 @@
}
}
-
-template <typename Derived, typename Shape, typename Key>
-int Dictionary<Derived, Shape, Key>::CopyKeysTo(
- FixedArray* storage, int index, PropertyFilter filter,
- typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
- DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
- int start_index = index;
- int capacity = this->Capacity();
- for (int i = 0; i < capacity; i++) {
- Object* k = this->KeyAt(i);
- if (!this->IsKey(k) || k->FilterKey(filter)) continue;
- if (this->IsDeleted(i)) continue;
- PropertyDetails details = this->DetailsAt(i);
- PropertyAttributes attr = details.attributes();
- if ((attr & filter) != 0) continue;
- storage->set(index++, k);
- }
- if (sort_mode == Dictionary::SORTED) {
- storage->SortPairs(storage, index);
- }
- DCHECK(storage->length() >= index);
- return index - start_index;
-}
-
template <typename Derived, typename Shape, typename Key>
void Dictionary<Derived, Shape, Key>::CollectKeysTo(
Handle<Dictionary<Derived, Shape, Key> > dictionary, KeyAccumulator* keys,
@@ -18690,7 +17265,7 @@
return table;
}
- // Rehash if more than 25% of the entries are deleted entries.
+ // Rehash if more than 33% of the entries are deleted entries.
// TODO(jochen): Consider to shrink the fixed array in place.
if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
table->Rehash(isolate->factory()->undefined_value());
@@ -18907,21 +17482,23 @@
template<class Derived, class Iterator, int entrysize>
Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash(
Handle<Derived> table, int new_capacity) {
+ Isolate* isolate = table->GetIsolate();
+ Heap* heap = isolate->heap();
DCHECK(!table->IsObsolete());
- Handle<Derived> new_table =
- Allocate(table->GetIsolate(),
- new_capacity,
- table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
+ Handle<Derived> new_table = Allocate(
+ isolate, new_capacity, heap->InNewSpace(*table) ? NOT_TENURED : TENURED);
int nof = table->NumberOfElements();
int nod = table->NumberOfDeletedElements();
int new_buckets = new_table->NumberOfBuckets();
int new_entry = 0;
int removed_holes_index = 0;
+ DisallowHeapAllocation no_gc;
+ Object* the_hole = heap->the_hole_value();
for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
Object* key = table->KeyAt(old_entry);
- if (key->IsTheHole()) {
+ if (key == the_hole) {
table->SetRemovedIndexAt(removed_holes_index++, old_entry);
continue;
}