aboutsummaryrefslogtreecommitdiff
path: root/src/objects.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/objects.cc')
-rw-r--r--src/objects.cc3377
1 files changed, 1567 insertions, 1810 deletions
diff --git a/src/objects.cc b/src/objects.cc
index e711a219..9f9a6280 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -18,6 +18,7 @@
#include "src/api-arguments-inl.h"
#include "src/api-natives.h"
#include "src/api.h"
+#include "src/arguments.h"
#include "src/base/bits.h"
#include "src/base/utils/random-number-generator.h"
#include "src/bootstrapper.h"
@@ -28,6 +29,7 @@
#include "src/counters-inl.h"
#include "src/counters.h"
#include "src/date.h"
+#include "src/debug/debug-evaluate.h"
#include "src/debug/debug.h"
#include "src/deoptimizer.h"
#include "src/elements.h"
@@ -49,6 +51,7 @@
#include "src/log.h"
#include "src/lookup.h"
#include "src/macro-assembler.h"
+#include "src/map-updater.h"
#include "src/messages.h"
#include "src/objects-body-descriptors-inl.h"
#include "src/property-descriptor.h"
@@ -139,7 +142,8 @@ MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate,
}
// static
-MaybeHandle<Object> Object::ToNumber(Handle<Object> input) {
+MaybeHandle<Object> Object::ConvertToNumber(Isolate* isolate,
+ Handle<Object> input) {
while (true) {
if (input->IsNumber()) {
return input;
@@ -150,15 +154,10 @@ MaybeHandle<Object> Object::ToNumber(Handle<Object> input) {
if (input->IsOddball()) {
return Oddball::ToNumber(Handle<Oddball>::cast(input));
}
- Isolate* const isolate = Handle<HeapObject>::cast(input)->GetIsolate();
if (input->IsSymbol()) {
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
Object);
}
- if (input->IsSimd128Value()) {
- THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSimdToNumber),
- Object);
- }
ASSIGN_RETURN_ON_EXCEPTION(
isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
ToPrimitiveHint::kNumber),
@@ -166,28 +165,33 @@ MaybeHandle<Object> Object::ToNumber(Handle<Object> input) {
}
}
-
// static
-MaybeHandle<Object> Object::ToInteger(Isolate* isolate, Handle<Object> input) {
- ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
+MaybeHandle<Object> Object::ConvertToInteger(Isolate* isolate,
+ Handle<Object> input) {
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input),
+ Object);
+ if (input->IsSmi()) return input;
return isolate->factory()->NewNumber(DoubleToInteger(input->Number()));
}
-
// static
-MaybeHandle<Object> Object::ToInt32(Isolate* isolate, Handle<Object> input) {
- ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
+MaybeHandle<Object> Object::ConvertToInt32(Isolate* isolate,
+ Handle<Object> input) {
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input),
+ Object);
+ if (input->IsSmi()) return input;
return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number()));
}
-
// static
-MaybeHandle<Object> Object::ToUint32(Isolate* isolate, Handle<Object> input) {
- ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
+MaybeHandle<Object> Object::ConvertToUint32(Isolate* isolate,
+ Handle<Object> input) {
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input),
+ Object);
+ if (input->IsSmi()) return handle(Smi::cast(*input)->ToUint32Smi(), isolate);
return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number()));
}
-
// static
MaybeHandle<Name> Object::ConvertToName(Isolate* isolate,
Handle<Object> input) {
@@ -198,12 +202,35 @@ MaybeHandle<Name> Object::ConvertToName(Isolate* isolate,
return ToString(isolate, input);
}
+// ES6 7.1.14
// static
-MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) {
- while (true) {
- if (input->IsString()) {
- return Handle<String>::cast(input);
+MaybeHandle<Object> Object::ConvertToPropertyKey(Isolate* isolate,
+ Handle<Object> value) {
+ // 1. Let key be ToPrimitive(argument, hint String).
+ MaybeHandle<Object> maybe_key =
+ Object::ToPrimitive(value, ToPrimitiveHint::kString);
+ // 2. ReturnIfAbrupt(key).
+ Handle<Object> key;
+ if (!maybe_key.ToHandle(&key)) return key;
+ // 3. If Type(key) is Symbol, then return key.
+ if (key->IsSymbol()) return key;
+ // 4. Return ToString(key).
+ // Extending spec'ed behavior, we'd be happy to return an element index.
+ if (key->IsSmi()) return key;
+ if (key->IsHeapNumber()) {
+ uint32_t uint_value;
+ if (value->ToArrayLength(&uint_value) &&
+ uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
+ return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
}
+ }
+ return Object::ToString(isolate, key);
+}
+
+// static
+MaybeHandle<String> Object::ConvertToString(Isolate* isolate,
+ Handle<Object> input) {
+ while (true) {
if (input->IsOddball()) {
return handle(Handle<Oddball>::cast(input)->to_string(), isolate);
}
@@ -214,13 +241,15 @@ MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) {
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString),
String);
}
- if (input->IsSimd128Value()) {
- return Simd128Value::ToString(Handle<Simd128Value>::cast(input));
- }
ASSIGN_RETURN_ON_EXCEPTION(
isolate, input, JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
ToPrimitiveHint::kString),
String);
+ // The previous isString() check happened in Object::ToString and thus we
+ // put it at the end of the loop in this helper.
+ if (input->IsString()) {
+ return Handle<String>::cast(input);
+ }
}
}
@@ -268,8 +297,7 @@ Handle<String> Object::NoSideEffectsToString(Isolate* isolate,
Handle<Object> input) {
DisallowJavascriptExecution no_js(isolate);
- if (input->IsString() || input->IsNumber() || input->IsOddball() ||
- input->IsSimd128Value()) {
+ if (input->IsString() || input->IsNumber() || input->IsOddball()) {
return Object::ToString(isolate, input).ToHandleChecked();
} else if (input->IsFunction()) {
// -- F u n c t i o n
@@ -375,11 +403,16 @@ Handle<String> Object::NoSideEffectsToString(Isolate* isolate,
}
// static
-MaybeHandle<Object> Object::ToLength(Isolate* isolate, Handle<Object> input) {
+MaybeHandle<Object> Object::ConvertToLength(Isolate* isolate,
+ Handle<Object> input) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
+ if (input->IsSmi()) {
+ int value = std::max(Smi::cast(*input)->value(), 0);
+ return handle(Smi::FromInt(value), isolate);
+ }
double len = DoubleToInteger(input->Number());
if (len <= 0.0) {
- len = 0.0;
+ return handle(Smi::kZero, isolate);
} else if (len >= kMaxSafeInteger) {
len = kMaxSafeInteger;
}
@@ -387,10 +420,12 @@ MaybeHandle<Object> Object::ToLength(Isolate* isolate, Handle<Object> input) {
}
// static
-MaybeHandle<Object> Object::ToIndex(Isolate* isolate, Handle<Object> input,
- MessageTemplate::Template error_index) {
- if (input->IsUndefined(isolate)) return isolate->factory()->NewNumber(0.0);
+MaybeHandle<Object> Object::ConvertToIndex(
+ Isolate* isolate, Handle<Object> input,
+ MessageTemplate::Template error_index) {
+ if (input->IsUndefined(isolate)) return handle(Smi::kZero, isolate);
ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
+ if (input->IsSmi() && Smi::cast(*input)->value() >= 0) return input;
double len = DoubleToInteger(input->Number()) + 0.0;
auto js_len = isolate->factory()->NewNumber(len);
if (len < 0.0 || len > kMaxSafeInteger) {
@@ -404,7 +439,7 @@ bool Object::BooleanValue() {
DCHECK(IsHeapObject());
Isolate* isolate = HeapObject::cast(this)->GetIsolate();
if (IsBoolean()) return IsTrue(isolate);
- if (IsUndefined(isolate) || IsNull(isolate)) return false;
+ if (IsNullOrUndefined(isolate)) return false;
if (IsUndetectable()) return false; // Undetectable object is false.
if (IsString()) return String::cast(this)->length() != 0;
if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
@@ -537,18 +572,6 @@ Maybe<bool> Object::Equals(Handle<Object> x, Handle<Object> y) {
} else {
return Just(false);
}
- } else if (x->IsSimd128Value()) {
- if (y->IsSimd128Value()) {
- return Just(Simd128Value::Equals(Handle<Simd128Value>::cast(x),
- Handle<Simd128Value>::cast(y)));
- } else if (y->IsJSReceiver()) {
- if (!JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(y))
- .ToHandle(&y)) {
- return Nothing<bool>();
- }
- } else {
- return Just(false);
- }
} else if (x->IsJSReceiver()) {
if (y->IsJSReceiver()) {
return Just(x.is_identical_to(y));
@@ -574,9 +597,6 @@ bool Object::StrictEquals(Object* that) {
} else if (this->IsString()) {
if (!that->IsString()) return false;
return String::cast(this)->Equals(String::cast(that));
- } else if (this->IsSimd128Value()) {
- if (!that->IsSimd128Value()) return false;
- return Simd128Value::cast(this)->Equals(Simd128Value::cast(that));
}
return this == that;
}
@@ -592,10 +612,6 @@ Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
if (object->IsString()) return isolate->factory()->string_string();
if (object->IsSymbol()) return isolate->factory()->symbol_string();
if (object->IsString()) return isolate->factory()->string_string();
-#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
- if (object->Is##Type()) return isolate->factory()->type##_string();
- SIMD128_TYPES(SIMD128_TYPE)
-#undef SIMD128_TYPE
if (object->IsCallable()) return isolate->factory()->function_string();
return isolate->factory()->object_string();
}
@@ -847,7 +863,7 @@ MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
Isolate* isolate = receiver->GetIsolate();
ASSIGN_RETURN_ON_EXCEPTION(isolate, func,
JSReceiver::GetProperty(receiver, name), Object);
- if (func->IsNull(isolate) || func->IsUndefined(isolate)) {
+ if (func->IsNullOrUndefined(isolate)) {
return isolate->factory()->undefined_value();
}
if (!func->IsCallable()) {
@@ -858,10 +874,30 @@ MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
return func;
}
+namespace {
+MaybeHandle<FixedArray> CreateListFromArrayLikeFastPath(
+ Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
+ if (element_types != ElementTypes::kAll || !object->IsJSArray()) {
+ return MaybeHandle<FixedArray>();
+ }
+ Handle<JSArray> array = Handle<JSArray>::cast(object);
+ uint32_t length;
+ if (!array->HasArrayPrototype(isolate) ||
+ !array->length()->ToUint32(&length) || !array->HasFastElements() ||
+ !JSObject::PrototypeHasNoElements(isolate, *array)) {
+ return MaybeHandle<FixedArray>();
+ }
+ return array->GetElementsAccessor()->CreateListFromArray(isolate, array);
+}
+} // namespace
// static
MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
+ // Fast-path for JS_ARRAY_TYPE.
+ MaybeHandle<FixedArray> fast_result =
+ CreateListFromArrayLikeFastPath(isolate, object, element_types);
+ if (!fast_result.is_null()) return fast_result;
// 1. ReturnIfAbrupt(object).
// 2. (default elementTypes -- not applicable.)
// 3. If Type(obj) is not Object, throw a TypeError exception.
@@ -872,6 +908,7 @@ MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
"CreateListFromArrayLike")),
FixedArray);
}
+
// 4. Let len be ? ToLength(? Get(obj, "length")).
Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
Handle<Object> raw_length_number;
@@ -1790,11 +1827,13 @@ MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
GetPropertyWithInterceptor(it, &done), Object);
if (done) return result;
}
+
} else {
- MaybeHandle<Object> result;
+ Handle<Object> result;
bool done;
- result = GetPropertyWithInterceptorInternal(it, interceptor, &done);
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, result,
+ GetPropertyWithInterceptorInternal(it, interceptor, &done), Object);
if (done) return result;
}
@@ -1830,7 +1869,7 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
} else {
Maybe<PropertyAttributes> result =
GetPropertyAttributesWithInterceptorInternal(it, interceptor);
- RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
+ if (isolate->has_pending_exception()) return Nothing<PropertyAttributes>();
if (result.FromMaybe(ABSENT) != ABSENT) return result;
}
isolate->ReportFailedAccessCheck(checked);
@@ -1866,10 +1905,9 @@ Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
} else {
Maybe<bool> result = SetPropertyWithInterceptorInternal(
it, interceptor, should_throw, value);
- RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
+ if (isolate->has_pending_exception()) return Nothing<bool>();
if (result.IsJust()) return result;
}
-
isolate->ReportFailedAccessCheck(checked);
RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
return Just(true);
@@ -1937,6 +1975,178 @@ Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
}
}
+namespace {
+
+bool HasExcludedProperty(
+ const ScopedVector<Handle<Object>>* excluded_properties,
+ Handle<Object> search_element) {
+ // TODO(gsathya): Change this to be a hashtable.
+ for (int i = 0; i < excluded_properties->length(); i++) {
+ if (search_element->SameValue(*excluded_properties->at(i))) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+MUST_USE_RESULT Maybe<bool> FastAssign(
+ Handle<JSReceiver> target, Handle<Object> source,
+ const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
+ // Non-empty strings are the only non-JSReceivers that need to be handled
+ // explicitly by Object.assign.
+ if (!source->IsJSReceiver()) {
+ return Just(!source->IsString() || String::cast(*source)->length() == 0);
+ }
+
+ // If the target is deprecated, the object will be updated on first store. If
+ // the source for that store equals the target, this will invalidate the
+ // cached representation of the source. Preventively upgrade the target.
+ // Do this on each iteration since any property load could cause deprecation.
+ if (target->map()->is_deprecated()) {
+ JSObject::MigrateInstance(Handle<JSObject>::cast(target));
+ }
+
+ Isolate* isolate = target->GetIsolate();
+ Handle<Map> map(JSReceiver::cast(*source)->map(), isolate);
+
+ if (!map->IsJSObjectMap()) return Just(false);
+ if (!map->OnlyHasSimpleProperties()) return Just(false);
+
+ Handle<JSObject> from = Handle<JSObject>::cast(source);
+ if (from->elements() != isolate->heap()->empty_fixed_array()) {
+ return Just(false);
+ }
+
+ Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
+ int length = map->NumberOfOwnDescriptors();
+
+ bool stable = true;
+
+ for (int i = 0; i < length; i++) {
+ Handle<Name> next_key(descriptors->GetKey(i), isolate);
+ Handle<Object> prop_value;
+ // Directly decode from the descriptor array if |from| did not change shape.
+ if (stable) {
+ PropertyDetails details = descriptors->GetDetails(i);
+ if (!details.IsEnumerable()) continue;
+ if (details.kind() == kData) {
+ if (details.location() == kDescriptor) {
+ prop_value = handle(descriptors->GetValue(i), isolate);
+ } else {
+ Representation representation = details.representation();
+ FieldIndex index = FieldIndex::ForDescriptor(*map, i);
+ prop_value = JSObject::FastPropertyAt(from, representation, index);
+ }
+ } else {
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, prop_value, JSReceiver::GetProperty(from, next_key),
+ Nothing<bool>());
+ stable = from->map() == *map;
+ }
+ } else {
+ // If the map did change, do a slower lookup. We are still guaranteed that
+ // the object has a simple shape, and that the key is a name.
+ LookupIterator it(from, next_key, from,
+ LookupIterator::OWN_SKIP_INTERCEPTOR);
+ if (!it.IsFound()) continue;
+ DCHECK(it.state() == LookupIterator::DATA ||
+ it.state() == LookupIterator::ACCESSOR);
+ if (!it.IsEnumerable()) continue;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
+ }
+
+ if (use_set) {
+ LookupIterator it(target, next_key, target);
+ bool call_to_js = it.IsFound() && it.state() != LookupIterator::DATA;
+ Maybe<bool> result = Object::SetProperty(
+ &it, prop_value, STRICT, Object::CERTAINLY_NOT_STORE_FROM_KEYED);
+ if (result.IsNothing()) return result;
+ if (stable && call_to_js) stable = from->map() == *map;
+ } else {
+ if (excluded_properties != nullptr &&
+ HasExcludedProperty(excluded_properties, next_key)) {
+ continue;
+ }
+
+ // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue).
+ bool success;
+ LookupIterator it = LookupIterator::PropertyOrElement(
+ isolate, target, next_key, &success, LookupIterator::OWN);
+ CHECK(success);
+ CHECK(
+ JSObject::CreateDataProperty(&it, prop_value, Object::THROW_ON_ERROR)
+ .FromJust());
+ }
+ }
+
+ return Just(true);
+}
+} // namespace
+
+// static
+Maybe<bool> JSReceiver::SetOrCopyDataProperties(
+ Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source,
+ const ScopedVector<Handle<Object>>* excluded_properties, bool use_set) {
+ Maybe<bool> fast_assign =
+ FastAssign(target, source, excluded_properties, use_set);
+ if (fast_assign.IsNothing()) return Nothing<bool>();
+ if (fast_assign.FromJust()) return Just(true);
+
+ Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked();
+ // 3b. Let keys be ? from.[[OwnPropertyKeys]]().
+ Handle<FixedArray> keys;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, keys,
+ KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
+ GetKeysConversion::kKeepNumbers),
+ Nothing<bool>());
+
+ // 4. Repeat for each element nextKey of keys in List order,
+ for (int j = 0; j < keys->length(); ++j) {
+ Handle<Object> next_key(keys->get(j), isolate);
+ // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey).
+ PropertyDescriptor desc;
+ Maybe<bool> found =
+ JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc);
+ if (found.IsNothing()) return Nothing<bool>();
+ // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then
+ if (found.FromJust() && desc.enumerable()) {
+ // 4a ii 1. Let propValue be ? Get(from, nextKey).
+ Handle<Object> prop_value;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, prop_value,
+ Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>());
+
+ if (use_set) {
+ // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true).
+ Handle<Object> status;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, status, Runtime::SetObjectProperty(
+ isolate, target, next_key, prop_value, STRICT),
+ Nothing<bool>());
+ } else {
+ if (excluded_properties != nullptr &&
+ HasExcludedProperty(excluded_properties, next_key)) {
+ continue;
+ }
+
+ // 4a ii 2. Perform ! CreateDataProperty(target, nextKey, propValue).
+ bool success;
+ LookupIterator it = LookupIterator::PropertyOrElement(
+ isolate, target, next_key, &success, LookupIterator::OWN);
+ CHECK(success);
+ CHECK(JSObject::CreateDataProperty(&it, prop_value,
+ Object::THROW_ON_ERROR)
+ .FromJust());
+ }
+ }
+ }
+
+ return Just(true);
+}
+
Map* Object::GetPrototypeChainRootMap(Isolate* isolate) {
DisallowHeapAllocation no_alloc;
if (IsSmi()) {
@@ -1944,8 +2154,8 @@ Map* Object::GetPrototypeChainRootMap(Isolate* isolate) {
return native_context->number_function()->initial_map();
}
- // The object is either a number, a string, a symbol, a boolean, a SIMD value,
- // a real JS object, or a Harmony proxy.
+ // The object is either a number, a string, a symbol, a boolean, a real JS
+ // object, or a Harmony proxy.
HeapObject* heap_object = HeapObject::cast(this);
return heap_object->map()->GetPrototypeChainRootMap(isolate);
}
@@ -1971,8 +2181,8 @@ namespace {
// objects. This avoids a double lookup in the cases where we know we will
// add the hash to the JSObject if it does not already exist.
Object* GetSimpleHash(Object* object) {
- // The object is either a Smi, a HeapNumber, a name, an odd-ball,
- // a SIMD value type, a real JS object, or a Harmony proxy.
+ // The object is either a Smi, a HeapNumber, a name, an odd-ball, a real JS
+ // object, or a Harmony proxy.
if (object->IsSmi()) {
uint32_t hash =
ComputeIntegerHash(Smi::cast(object)->value(), kZeroHashSeed);
@@ -1996,10 +2206,6 @@ Object* GetSimpleHash(Object* object) {
uint32_t hash = Oddball::cast(object)->to_string()->Hash();
return Smi::FromInt(hash);
}
- if (object->IsSimd128Value()) {
- uint32_t hash = Simd128Value::cast(object)->Hash();
- return Smi::FromInt(hash & Smi::kMaxValue);
- }
DCHECK(object->IsJSReceiver());
// Simply return the receiver as it is guaranteed to not be a SMI.
return object;
@@ -2046,23 +2252,6 @@ bool Object::SameValue(Object* other) {
if (IsString() && other->IsString()) {
return String::cast(this)->Equals(String::cast(other));
}
- if (IsFloat32x4() && other->IsFloat32x4()) {
- Float32x4* a = Float32x4::cast(this);
- Float32x4* b = Float32x4::cast(other);
- for (int i = 0; i < 4; i++) {
- float x = a->get_lane(i);
- float y = b->get_lane(i);
- // Implements the ES5 SameValue operation for floating point types.
- // http://www.ecma-international.org/ecma-262/6.0/#sec-samevalue
- if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
- if (std::signbit(x) != std::signbit(y)) return false;
- }
- return true;
- } else if (IsSimd128Value() && other->IsSimd128Value()) {
- Simd128Value* a = Simd128Value::cast(this);
- Simd128Value* b = Simd128Value::cast(other);
- return a->map() == b->map() && a->BitwiseEquals(b);
- }
return false;
}
@@ -2082,23 +2271,6 @@ bool Object::SameValueZero(Object* other) {
if (IsString() && other->IsString()) {
return String::cast(this)->Equals(String::cast(other));
}
- if (IsFloat32x4() && other->IsFloat32x4()) {
- Float32x4* a = Float32x4::cast(this);
- Float32x4* b = Float32x4::cast(other);
- for (int i = 0; i < 4; i++) {
- float x = a->get_lane(i);
- float y = b->get_lane(i);
- // Implements the ES6 SameValueZero operation for floating point types.
- // http://www.ecma-international.org/ecma-262/6.0/#sec-samevaluezero
- if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
- // SameValueZero doesn't distinguish between 0 and -0.
- }
- return true;
- } else if (IsSimd128Value() && other->IsSimd128Value()) {
- Simd128Value* a = Simd128Value::cast(this);
- Simd128Value* b = Simd128Value::cast(other);
- return a->map() == b->map() && a->BitwiseEquals(b);
- }
return false;
}
@@ -2154,6 +2326,40 @@ MaybeHandle<Object> Object::ArraySpeciesConstructor(
}
}
+bool Object::IterationHasObservableEffects() {
+ // Check that this object is an array.
+ if (!IsJSArray()) return true;
+ JSArray* spread_array = JSArray::cast(this);
+ Isolate* isolate = spread_array->GetIsolate();
+
+ // Check that we have the original ArrayPrototype.
+ JSObject* array_proto = JSObject::cast(spread_array->map()->prototype());
+ if (!isolate->is_initial_array_prototype(array_proto)) return true;
+
+ // Check that the ArrayPrototype hasn't been modified in a way that would
+ // affect iteration.
+ if (!isolate->IsArrayIteratorLookupChainIntact()) return true;
+
+ // Check that the map of the initial array iterator hasn't changed.
+ Map* iterator_map = isolate->initial_array_iterator_prototype()->map();
+ if (!isolate->is_initial_array_iterator_prototype_map(iterator_map)) {
+ return true;
+ }
+
+ // For FastPacked kinds, iteration will have the same effect as simply
+ // accessing each property in order.
+ ElementsKind array_kind = spread_array->GetElementsKind();
+ if (IsFastPackedElementsKind(array_kind)) return false;
+
+ // For FastHoley kinds, an element access on a hole would cause a lookup on
+ // the prototype. This could have different results if the prototype has been
+ // changed.
+ if (IsFastHoleyElementsKind(array_kind) &&
+ isolate->IsFastArrayConstructorPrototypeChainIntact()) {
+ return false;
+ }
+ return true;
+}
void Object::ShortPrint(FILE* out) {
OFStream os(out);
@@ -2182,9 +2388,6 @@ std::ostream& operator<<(std::ostream& os, const Brief& v) {
return os;
}
-// Declaration of the static Smi::kZero constant.
-Smi* const Smi::kZero(nullptr);
-
void Smi::SmiPrint(std::ostream& os) const { // NOLINT
os << value();
}
@@ -2219,7 +2422,16 @@ Handle<String> String::SlowFlatten(Handle<ConsString> cons,
DCHECK(cons->second()->length() != 0);
// TurboFan can create cons strings with empty first parts.
- if (cons->first()->length() == 0) return handle(cons->second());
+ while (cons->first()->length() == 0) {
+ // We do not want to call this function recursively. Therefore we call
+ // String::Flatten only in those cases where String::SlowFlatten is not
+ // called again.
+ if (cons->second()->IsConsString() && !cons->second()->IsFlat()) {
+ cons = handle(ConsString::cast(cons->second()));
+ } else {
+ return String::Flatten(handle(cons->second()));
+ }
+ }
DCHECK(AllowHeapAllocation::IsAllowed());
Isolate* isolate = cons->GetIsolate();
@@ -2270,7 +2482,7 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
Heap* heap = GetHeap();
bool is_one_byte = this->IsOneByteRepresentation();
bool is_internalized = this->IsInternalizedString();
- bool has_pointers = this->IsConsString() || this->IsSlicedString();
+ bool has_pointers = StringShape(this).IsIndirect();
// Morph the string to an external string by replacing the map and
// reinitializing the fields. This won't work if the space the existing
@@ -2311,7 +2523,7 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
self->set_resource(resource);
if (is_internalized) self->Hash(); // Force regeneration of the hash value.
- heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER);
+ heap->AdjustLiveBytes(this, new_size - size);
return true;
}
@@ -2342,7 +2554,7 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
if (size < ExternalString::kShortSize) return false;
Heap* heap = GetHeap();
bool is_internalized = this->IsInternalizedString();
- bool has_pointers = this->IsConsString() || this->IsSlicedString();
+ bool has_pointers = StringShape(this).IsIndirect();
// Morph the string to an external string by replacing the map and
// reinitializing the fields. This won't work if the space the existing
@@ -2377,7 +2589,7 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
self->set_resource(resource);
if (is_internalized) self->Hash(); // Force regeneration of the hash value.
- heap->AdjustLiveBytes(this, new_size - size, Heap::CONCURRENT_TO_SWEEPER);
+ heap->AdjustLiveBytes(this, new_size - size);
return true;
}
@@ -2619,10 +2831,10 @@ void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
void Map::PrintGeneralization(
FILE* file, const char* reason, int modify_index, int split,
- int descriptors, bool constant_to_field, Representation old_representation,
- Representation new_representation, MaybeHandle<FieldType> old_field_type,
- MaybeHandle<Object> old_value, MaybeHandle<FieldType> new_field_type,
- MaybeHandle<Object> new_value) {
+ int descriptors, bool descriptor_to_field,
+ Representation old_representation, Representation new_representation,
+ MaybeHandle<FieldType> old_field_type, MaybeHandle<Object> old_value,
+ MaybeHandle<FieldType> new_field_type, MaybeHandle<Object> new_value) {
OFStream os(file);
os << "[generalizing]";
Name* name = instance_descriptors()->GetKey(modify_index);
@@ -2632,7 +2844,7 @@ void Map::PrintGeneralization(
os << "{symbol " << static_cast<void*>(name) << "}";
}
os << ":";
- if (constant_to_field) {
+ if (descriptor_to_field) {
os << "c";
} else {
os << old_representation.Mnemonic() << "{";
@@ -2673,8 +2885,8 @@ void JSObject::PrintInstanceMigration(FILE* file,
if (!o_r.Equals(n_r)) {
String::cast(o->GetKey(i))->PrintOn(file);
PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
- } else if (o->GetDetails(i).type() == DATA_CONSTANT &&
- n->GetDetails(i).type() == DATA) {
+ } else if (o->GetDetails(i).location() == kDescriptor &&
+ n->GetDetails(i).location() == kField) {
Name* name = o->GetKey(i);
if (name->IsString()) {
String::cast(name)->PrintOn(file);
@@ -2809,17 +3021,6 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
os << '>';
break;
}
- case SIMD128_VALUE_TYPE: {
-#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
- if (Is##Type()) { \
- os << "<" #Type ">"; \
- break; \
- }
- SIMD128_TYPES(SIMD128_TYPE)
-#undef SIMD128_TYPE
- UNREACHABLE();
- break;
- }
case JS_PROXY_TYPE:
os << "<JSProxy>";
break;
@@ -2910,101 +3111,6 @@ void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT
#define READ_BYTE_FIELD(p, offset) \
(*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset)))
-
-// static
-Handle<String> Simd128Value::ToString(Handle<Simd128Value> input) {
-#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
- if (input->Is##Type()) return Type::ToString(Handle<Type>::cast(input));
- SIMD128_TYPES(SIMD128_TYPE)
-#undef SIMD128_TYPE
- UNREACHABLE();
- return Handle<String>::null();
-}
-
-
-// static
-Handle<String> Float32x4::ToString(Handle<Float32x4> input) {
- Isolate* const isolate = input->GetIsolate();
- char arr[100];
- Vector<char> buffer(arr, arraysize(arr));
- std::ostringstream os;
- os << "SIMD.Float32x4("
- << std::string(DoubleToCString(input->get_lane(0), buffer)) << ", "
- << std::string(DoubleToCString(input->get_lane(1), buffer)) << ", "
- << std::string(DoubleToCString(input->get_lane(2), buffer)) << ", "
- << std::string(DoubleToCString(input->get_lane(3), buffer)) << ")";
- return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str());
-}
-
-
-#define SIMD128_BOOL_TO_STRING(Type, lane_count) \
- Handle<String> Type::ToString(Handle<Type> input) { \
- Isolate* const isolate = input->GetIsolate(); \
- std::ostringstream os; \
- os << "SIMD." #Type "("; \
- os << (input->get_lane(0) ? "true" : "false"); \
- for (int i = 1; i < lane_count; i++) { \
- os << ", " << (input->get_lane(i) ? "true" : "false"); \
- } \
- os << ")"; \
- return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \
- }
-SIMD128_BOOL_TO_STRING(Bool32x4, 4)
-SIMD128_BOOL_TO_STRING(Bool16x8, 8)
-SIMD128_BOOL_TO_STRING(Bool8x16, 16)
-#undef SIMD128_BOOL_TO_STRING
-
-
-#define SIMD128_INT_TO_STRING(Type, lane_count) \
- Handle<String> Type::ToString(Handle<Type> input) { \
- Isolate* const isolate = input->GetIsolate(); \
- char arr[100]; \
- Vector<char> buffer(arr, arraysize(arr)); \
- std::ostringstream os; \
- os << "SIMD." #Type "("; \
- os << IntToCString(input->get_lane(0), buffer); \
- for (int i = 1; i < lane_count; i++) { \
- os << ", " << IntToCString(input->get_lane(i), buffer); \
- } \
- os << ")"; \
- return isolate->factory()->NewStringFromAsciiChecked(os.str().c_str()); \
- }
-SIMD128_INT_TO_STRING(Int32x4, 4)
-SIMD128_INT_TO_STRING(Uint32x4, 4)
-SIMD128_INT_TO_STRING(Int16x8, 8)
-SIMD128_INT_TO_STRING(Uint16x8, 8)
-SIMD128_INT_TO_STRING(Int8x16, 16)
-SIMD128_INT_TO_STRING(Uint8x16, 16)
-#undef SIMD128_INT_TO_STRING
-
-
-bool Simd128Value::BitwiseEquals(const Simd128Value* other) const {
- return READ_INT64_FIELD(this, kValueOffset) ==
- READ_INT64_FIELD(other, kValueOffset) &&
- READ_INT64_FIELD(this, kValueOffset + kInt64Size) ==
- READ_INT64_FIELD(other, kValueOffset + kInt64Size);
-}
-
-
-uint32_t Simd128Value::Hash() const {
- uint32_t seed = v8::internal::kZeroHashSeed;
- uint32_t hash;
- hash = ComputeIntegerHash(READ_INT32_FIELD(this, kValueOffset), seed);
- hash = ComputeIntegerHash(
- READ_INT32_FIELD(this, kValueOffset + 1 * kInt32Size), hash * 31);
- hash = ComputeIntegerHash(
- READ_INT32_FIELD(this, kValueOffset + 2 * kInt32Size), hash * 31);
- hash = ComputeIntegerHash(
- READ_INT32_FIELD(this, kValueOffset + 3 * kInt32Size), hash * 31);
- return hash;
-}
-
-
-void Simd128Value::CopyBits(void* destination) const {
- memcpy(destination, &READ_BYTE_FIELD(this, kValueOffset), kSimd128Size);
-}
-
-
String* JSReceiver::class_name() {
if (IsFunction()) {
return GetHeap()->Function_string();
@@ -3064,8 +3170,7 @@ Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
: result;
}
-
-Context* JSReceiver::GetCreationContext() {
+Handle<Context> JSReceiver::GetCreationContext() {
JSReceiver* receiver = this;
while (receiver->IsJSBoundFunction()) {
receiver = JSBoundFunction::cast(receiver)->bound_target_function();
@@ -3081,17 +3186,29 @@ Context* JSReceiver::GetCreationContext() {
function = JSFunction::cast(receiver);
}
- return function->context()->native_context();
+ return function->has_context()
+ ? Handle<Context>(function->context()->native_context())
+ : Handle<Context>::null();
}
-static Handle<Object> WrapType(Handle<FieldType> type) {
+Handle<Object> Map::WrapFieldType(Handle<FieldType> type) {
if (type->IsClass()) return Map::WeakCellForMap(type->AsClass());
return type;
}
+FieldType* Map::UnwrapFieldType(Object* wrapped_type) {
+ Object* value = wrapped_type;
+ if (value->IsWeakCell()) {
+ if (WeakCell::cast(value)->cleared()) return FieldType::None();
+ value = WeakCell::cast(value)->value();
+ }
+ return FieldType::cast(value);
+}
+
MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name,
Handle<FieldType> type,
PropertyAttributes attributes,
+ PropertyConstness constness,
Representation representation,
TransitionFlag flag) {
DCHECK(DescriptorArray::kNotFound ==
@@ -3113,11 +3230,12 @@ MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name,
type = FieldType::Any(isolate);
}
- Handle<Object> wrapped_type(WrapType(type));
+ Handle<Object> wrapped_type(WrapFieldType(type));
- DataDescriptor new_field_desc(name, index, wrapped_type, attributes,
- representation);
- Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
+ DCHECK_IMPLIES(!FLAG_track_constant_fields, constness == kMutable);
+ Descriptor d = Descriptor::DataField(name, index, attributes, constness,
+ representation, wrapped_type);
+ Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag);
int unused_property_fields = new_map->unused_property_fields() - 1;
if (unused_property_fields < 0) {
unused_property_fields += JSObject::kFieldsAdded;
@@ -3137,9 +3255,18 @@ MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
return MaybeHandle<Map>();
}
- // Allocate new instance descriptors with (name, constant) added.
- DataConstantDescriptor new_constant_desc(name, constant, attributes);
- return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
+ if (FLAG_track_constant_fields) {
+ Isolate* isolate = map->GetIsolate();
+ Representation representation = constant->OptimalRepresentation();
+ Handle<FieldType> type = constant->OptimalType(isolate, representation);
+ return CopyWithField(map, name, type, attributes, kConst, representation,
+ flag);
+ } else {
+ // Allocate new instance descriptors with (name, constant) added.
+ Descriptor d = Descriptor::DataConstant(name, 0, constant, attributes);
+ Handle<Map> new_map = Map::CopyAddDescriptor(map, &d, flag);
+ return new_map;
+ }
}
const char* Representation::Mnemonic() const {
@@ -3157,6 +3284,34 @@ const char* Representation::Mnemonic() const {
}
}
+bool Map::TransitionRemovesTaggedField(Map* target) {
+ int inobject = GetInObjectProperties();
+ int target_inobject = target->GetInObjectProperties();
+ for (int i = target_inobject; i < inobject; i++) {
+ FieldIndex index = FieldIndex::ForPropertyIndex(this, i);
+ if (!IsUnboxedDoubleField(index)) return true;
+ }
+ return false;
+}
+
+bool Map::TransitionChangesTaggedFieldToUntaggedField(Map* target) {
+ int inobject = GetInObjectProperties();
+ int target_inobject = target->GetInObjectProperties();
+ int limit = Min(inobject, target_inobject);
+ for (int i = 0; i < limit; i++) {
+ FieldIndex index = FieldIndex::ForPropertyIndex(target, i);
+ if (!IsUnboxedDoubleField(index) && target->IsUnboxedDoubleField(index)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Map::TransitionRequiresSynchronizationWithGC(Map* target) {
+ return TransitionRemovesTaggedField(target) ||
+ TransitionChangesTaggedFieldToUntaggedField(target);
+}
+
bool Map::InstancesNeedRewriting(Map* target) {
int target_number_of_fields = target->NumberOfFields();
int target_inobject = target->GetInObjectProperties();
@@ -3276,7 +3431,7 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
DCHECK(details.representation().IsDouble());
DCHECK(!new_map->IsUnboxedDoubleField(index));
- Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE);
+ Handle<Object> value = isolate->factory()->NewMutableHeapNumber();
object->RawFastPropertyAtPut(index, *value);
object->synchronized_set_map(*new_map);
return;
@@ -3292,11 +3447,12 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
// Properly initialize newly added property.
Handle<Object> value;
if (details.representation().IsDouble()) {
- value = isolate->factory()->NewHeapNumber(0, MUTABLE);
+ value = isolate->factory()->NewMutableHeapNumber();
} else {
value = isolate->factory()->uninitialized_value();
}
- DCHECK_EQ(DATA, details.type());
+ DCHECK_EQ(kField, details.location());
+ DCHECK_EQ(kData, details.kind());
int target_index = details.field_index() - new_map->GetInObjectProperties();
DCHECK(target_index >= 0); // Must be a backing store index.
new_storage->set(target_index, *value);
@@ -3339,36 +3495,40 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
for (int i = 0; i < old_nof; i++) {
PropertyDetails details = new_descriptors->GetDetails(i);
- if (details.type() != DATA) continue;
+ if (details.location() != kField) continue;
+ DCHECK_EQ(kData, details.kind());
PropertyDetails old_details = old_descriptors->GetDetails(i);
Representation old_representation = old_details.representation();
Representation representation = details.representation();
Handle<Object> value;
- if (old_details.type() == ACCESSOR_CONSTANT) {
- // In case of kAccessor -> kData property reconfiguration, the property
- // must already be prepared for data or certain type.
- DCHECK(!details.representation().IsNone());
- if (details.representation().IsDouble()) {
- value = isolate->factory()->NewHeapNumber(0, MUTABLE);
+ if (old_details.location() == kDescriptor) {
+ if (old_details.kind() == kAccessor) {
+ // In case of kAccessor -> kData property reconfiguration, the property
+ // must already be prepared for data of certain type.
+ DCHECK(!details.representation().IsNone());
+ if (details.representation().IsDouble()) {
+ value = isolate->factory()->NewMutableHeapNumber();
+ } else {
+ value = isolate->factory()->uninitialized_value();
+ }
} else {
- value = isolate->factory()->uninitialized_value();
+ DCHECK_EQ(kData, old_details.kind());
+ value = handle(old_descriptors->GetValue(i), isolate);
+ DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
}
- } else if (old_details.type() == DATA_CONSTANT) {
- value = handle(old_descriptors->GetValue(i), isolate);
- DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
} else {
+ DCHECK_EQ(kField, old_details.location());
FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
if (object->IsUnboxedDoubleField(index)) {
- double old = object->RawFastDoublePropertyAt(index);
- value = isolate->factory()->NewHeapNumber(
- old, representation.IsDouble() ? MUTABLE : IMMUTABLE);
+ uint64_t old_bits = object->RawFastDoublePropertyAsBitsAt(index);
+ value = isolate->factory()->NewHeapNumberFromBits(
+ old_bits, representation.IsDouble() ? MUTABLE : IMMUTABLE);
} else {
value = handle(object->RawFastPropertyAt(index), isolate);
if (!old_representation.IsDouble() && representation.IsDouble()) {
- if (old_representation.IsNone()) {
- value = handle(Smi::kZero, isolate);
- }
+ DCHECK_IMPLIES(old_representation.IsNone(),
+ value->IsUninitialized(isolate));
value = Object::NewStorageFor(isolate, value, representation);
} else if (old_representation.IsDouble() &&
!representation.IsDouble()) {
@@ -3384,10 +3544,11 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
for (int i = old_nof; i < new_nof; i++) {
PropertyDetails details = new_descriptors->GetDetails(i);
- if (details.type() != DATA) continue;
+ if (details.location() != kField) continue;
+ DCHECK_EQ(kData, details.kind());
Handle<Object> value;
if (details.representation().IsDouble()) {
- value = isolate->factory()->NewHeapNumber(0, MUTABLE);
+ value = isolate->factory()->NewMutableHeapNumber();
} else {
value = isolate->factory()->uninitialized_value();
}
@@ -3401,6 +3562,8 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
Heap* heap = isolate->heap();
+ heap->NotifyObjectLayoutChange(*object, no_allocation);
+
// Copy (real) inobject properties. If necessary, stop at number_of_fields to
// avoid overwriting |one_pointer_filler_map|.
int limit = Min(inobject, number_of_fields);
@@ -3411,12 +3574,16 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
// yet.
if (new_map->IsUnboxedDoubleField(index)) {
DCHECK(value->IsMutableHeapNumber());
- object->RawFastDoublePropertyAtPut(index,
- HeapNumber::cast(value)->value());
+ // Ensure that all bits of the double value are preserved.
+ object->RawFastDoublePropertyAsBitsAtPut(
+ index, HeapNumber::cast(value)->value_as_bits());
if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) {
// Transition from tagged to untagged slot.
heap->ClearRecordedSlot(*object,
HeapObject::RawField(*object, index.offset()));
+ } else {
+ DCHECK(!heap->HasRecordedSlot(
+ *object, HeapObject::RawField(*object, index.offset())));
}
} else {
object->RawFastPropertyAtPut(index, value);
@@ -3427,7 +3594,7 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
// If there are properties in the new backing store, trim it to the correct
// size and install the backing store into the object.
if (external > 0) {
- heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*array, inobject);
+ heap->RightTrimFixedArray(*array, inobject);
object->set_properties(*array);
}
@@ -3440,8 +3607,7 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
Address address = object->address();
heap->CreateFillerObjectAt(address + new_instance_size, instance_size_delta,
ClearRecordedSlots::kYes);
- heap->AdjustLiveBytes(*object, -instance_size_delta,
- Heap::CONCURRENT_TO_SWEEPER);
+ heap->AdjustLiveBytes(*object, -instance_size_delta);
}
// We are storing the new map using release store after creating a filler for
@@ -3476,17 +3642,10 @@ void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
for (int i = 0; i < real_size; i++) {
PropertyDetails details = descs->GetDetails(i);
Handle<Name> key(descs->GetKey(i));
- switch (details.type()) {
- case DATA_CONSTANT: {
- Handle<Object> value(descs->GetConstant(i), isolate);
- PropertyDetails d(details.attributes(), DATA, i + 1,
- PropertyCellType::kNoCell);
- dictionary = NameDictionary::Add(dictionary, key, value, d);
- break;
- }
- case DATA: {
- FieldIndex index = FieldIndex::ForDescriptor(*map, i);
- Handle<Object> value;
+ Handle<Object> value;
+ if (details.location() == kField) {
+ FieldIndex index = FieldIndex::ForDescriptor(*map, i);
+ if (details.kind() == kData) {
if (object->IsUnboxedDoubleField(index)) {
double old_value = object->RawFastDoublePropertyAt(index);
value = isolate->factory()->NewHeapNumber(old_value);
@@ -3498,27 +3657,19 @@ void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
value = isolate->factory()->NewHeapNumber(old->value());
}
}
- PropertyDetails d(details.attributes(), DATA, i + 1,
- PropertyCellType::kNoCell);
- dictionary = NameDictionary::Add(dictionary, key, value, d);
- break;
- }
- case ACCESSOR: {
- FieldIndex index = FieldIndex::ForDescriptor(*map, i);
- Handle<Object> value(object->RawFastPropertyAt(index), isolate);
- PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
- PropertyCellType::kNoCell);
- dictionary = NameDictionary::Add(dictionary, key, value, d);
- break;
- }
- case ACCESSOR_CONSTANT: {
- Handle<Object> value(descs->GetCallbacksObject(i), isolate);
- PropertyDetails d(details.attributes(), ACCESSOR_CONSTANT, i + 1,
- PropertyCellType::kNoCell);
- dictionary = NameDictionary::Add(dictionary, key, value, d);
- break;
+ } else {
+ DCHECK_EQ(kAccessor, details.kind());
+ value = handle(object->RawFastPropertyAt(index), isolate);
}
+
+ } else {
+ DCHECK_EQ(kDescriptor, details.location());
+ value = handle(descs->GetValue(i), isolate);
}
+ DCHECK(!value.is_null());
+ PropertyDetails d(details.kind(), details.attributes(), i + 1,
+ PropertyCellType::kNoCell);
+ dictionary = NameDictionary::Add(dictionary, key, value, d);
}
// Copy the next enumeration index from instance descriptor.
@@ -3527,17 +3678,18 @@ void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
// From here on we cannot fail and we shouldn't GC anymore.
DisallowHeapAllocation no_allocation;
+ Heap* heap = isolate->heap();
+ heap->NotifyObjectLayoutChange(*object, no_allocation);
+
// Resize the object in the heap if necessary.
int new_instance_size = new_map->instance_size();
int instance_size_delta = map->instance_size() - new_instance_size;
DCHECK(instance_size_delta >= 0);
if (instance_size_delta > 0) {
- Heap* heap = isolate->heap();
heap->CreateFillerObjectAt(object->address() + new_instance_size,
instance_size_delta, ClearRecordedSlots::kYes);
- heap->AdjustLiveBytes(*object, -instance_size_delta,
- Heap::CONCURRENT_TO_SWEEPER);
+ heap->AdjustLiveBytes(*object, -instance_size_delta);
}
// We are storing the new map using release store after creating a filler for
@@ -3647,22 +3799,31 @@ int Map::NumberOfFields() {
return result;
}
-Handle<Map> Map::CopyGeneralizeAllRepresentations(
- Handle<Map> map, ElementsKind elements_kind, int modify_index,
- StoreMode store_mode, PropertyKind kind, PropertyAttributes attributes,
- const char* reason) {
+void DescriptorArray::GeneralizeAllFields() {
+ int length = number_of_descriptors();
+ for (int i = 0; i < length; i++) {
+ PropertyDetails details = GetDetails(i);
+ details = details.CopyWithRepresentation(Representation::Tagged());
+ if (details.location() == kField) {
+ DCHECK_EQ(kData, details.kind());
+ details = details.CopyWithConstness(kMutable);
+ SetValue(i, FieldType::Any());
+ }
+ set(ToDetailsIndex(i), details.AsSmi());
+ }
+}
+
+Handle<Map> Map::CopyGeneralizeAllFields(Handle<Map> map,
+ ElementsKind elements_kind,
+ int modify_index, 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();
Handle<DescriptorArray> descriptors =
DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors);
-
- for (int i = 0; i < number_of_own_descriptors; i++) {
- descriptors->SetRepresentation(i, Representation::Tagged());
- if (descriptors->GetDetails(i).type() == DATA) {
- descriptors->SetValue(i, FieldType::Any());
- }
- }
+ descriptors->GeneralizeAllFields();
Handle<LayoutDescriptor> new_layout_descriptor(
LayoutDescriptor::FastPointerLayout(), isolate);
@@ -3673,14 +3834,16 @@ Handle<Map> Map::CopyGeneralizeAllRepresentations(
// Unless the instance is being migrated, ensure that modify_index is a field.
if (modify_index >= 0) {
PropertyDetails details = descriptors->GetDetails(modify_index);
- if (store_mode == FORCE_FIELD &&
- (details.type() != DATA || details.attributes() != attributes)) {
- int field_index = details.type() == DATA ? details.field_index()
- : new_map->NumberOfFields();
- DataDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
- field_index, attributes, Representation::Tagged());
+ if (details.constness() != kMutable || details.location() != kField ||
+ details.attributes() != attributes) {
+ int field_index = details.location() == kField
+ ? details.field_index()
+ : new_map->NumberOfFields();
+ Descriptor d = Descriptor::DataField(
+ handle(descriptors->GetKey(modify_index), isolate), field_index,
+ attributes, Representation::Tagged());
descriptors->Replace(modify_index, &d);
- if (details.type() != DATA) {
+ if (details.location() != kField) {
int unused_property_fields = new_map->unused_property_fields() - 1;
if (unused_property_fields < 0) {
unused_property_fields += JSObject::kFieldsAdded;
@@ -3693,14 +3856,13 @@ Handle<Map> Map::CopyGeneralizeAllRepresentations(
if (FLAG_trace_generalization) {
MaybeHandle<FieldType> field_type = FieldType::None(isolate);
- if (details.type() == DATA) {
+ if (details.location() == kField) {
field_type = handle(
map->instance_descriptors()->GetFieldType(modify_index), isolate);
}
map->PrintGeneralization(
stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
- new_map->NumberOfOwnDescriptors(),
- details.type() == DATA_CONSTANT && store_mode == FORCE_FIELD,
+ new_map->NumberOfOwnDescriptors(), details.location() == kDescriptor,
details.representation(), Representation::Tagged(), field_type,
MaybeHandle<Object>(), FieldType::Any(isolate),
MaybeHandle<Object>());
@@ -3725,13 +3887,6 @@ void Map::DeprecateTransitionTree() {
}
-static inline bool EqualImmutableValues(Object* obj1, Object* obj2) {
- if (obj1 == obj2) return true; // Valid for both kData and kAccessor kinds.
- // TODO(ishell): compare AccessorPairs.
- return false;
-}
-
-
// Installs |new_descriptors| over the current instance_descriptors to ensure
// proper sharing of descriptor arrays.
void Map::ReplaceDescriptors(DescriptorArray* new_descriptors,
@@ -3774,50 +3929,9 @@ Map* Map::FindRootMap() {
}
-Map* Map::FindLastMatchMap(int verbatim,
- int length,
- DescriptorArray* descriptors) {
- DisallowHeapAllocation no_allocation;
-
- // This can only be called on roots of transition trees.
- DCHECK_EQ(verbatim, NumberOfOwnDescriptors());
-
- Map* current = this;
-
- for (int i = verbatim; i < length; i++) {
- Name* name = descriptors->GetKey(i);
- PropertyDetails details = descriptors->GetDetails(i);
- Map* next = TransitionArray::SearchTransition(current, details.kind(), name,
- details.attributes());
- if (next == NULL) break;
- DescriptorArray* next_descriptors = next->instance_descriptors();
-
- PropertyDetails next_details = next_descriptors->GetDetails(i);
- DCHECK_EQ(details.kind(), next_details.kind());
- DCHECK_EQ(details.attributes(), next_details.attributes());
- if (details.location() != next_details.location()) break;
- if (!details.representation().Equals(next_details.representation())) break;
-
- if (next_details.location() == kField) {
- FieldType* next_field_type = next_descriptors->GetFieldType(i);
- if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
- break;
- }
- } else {
- if (!EqualImmutableValues(descriptors->GetValue(i),
- next_descriptors->GetValue(i))) {
- break;
- }
- }
- current = next;
- }
- return current;
-}
-
-
Map* Map::FindFieldOwner(int descriptor) {
DisallowHeapAllocation no_allocation;
- DCHECK_EQ(DATA, instance_descriptors()->GetDetails(descriptor).type());
+ DCHECK_EQ(kField, instance_descriptors()->GetDetails(descriptor).location());
Map* result = this;
Isolate* isolate = GetIsolate();
while (true) {
@@ -3830,15 +3944,16 @@ Map* Map::FindFieldOwner(int descriptor) {
return result;
}
-
void Map::UpdateFieldType(int descriptor, Handle<Name> name,
+ PropertyConstness new_constness,
Representation new_representation,
Handle<Object> new_wrapped_type) {
DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell());
// We store raw pointers in the queue, so no allocations are allowed.
DisallowHeapAllocation no_allocation;
PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
- if (details.type() != DATA) return;
+ if (details.location() != kField) return;
+ DCHECK_EQ(kData, details.kind());
Zone zone(GetIsolate()->allocator(), ZONE_NAME);
ZoneQueue<Map*> backlog(&zone);
@@ -3857,15 +3972,19 @@ void Map::UpdateFieldType(int descriptor, Handle<Name> name,
DescriptorArray* descriptors = current->instance_descriptors();
PropertyDetails details = descriptors->GetDetails(descriptor);
+ // Currently constness change implies map change.
+ DCHECK_EQ(new_constness, details.constness());
+
// It is allowed to change representation here only from None to something.
DCHECK(details.representation().Equals(new_representation) ||
details.representation().IsNone());
// Skip if already updated the shared descriptor.
if (descriptors->GetValue(descriptor) != *new_wrapped_type) {
- DataDescriptor d(name, descriptors->GetFieldIndex(descriptor),
- new_wrapped_type, details.attributes(),
- new_representation);
+ DCHECK_IMPLIES(!FLAG_track_constant_fields, new_constness == kMutable);
+ Descriptor d = Descriptor::DataField(
+ name, descriptors->GetFieldIndex(descriptor), details.attributes(),
+ new_constness, new_representation, new_wrapped_type);
descriptors->Replace(descriptor, &d);
}
}
@@ -3895,25 +4014,28 @@ Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
// static
-void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
- Representation new_representation,
- Handle<FieldType> new_field_type) {
+void Map::GeneralizeField(Handle<Map> map, int modify_index,
+ PropertyConstness new_constness,
+ Representation new_representation,
+ Handle<FieldType> new_field_type) {
Isolate* isolate = map->GetIsolate();
// Check if we actually need to generalize the field type at all.
Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
- Representation old_representation =
- old_descriptors->GetDetails(modify_index).representation();
+ PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
+ PropertyConstness old_constness = old_details.constness();
+ Representation old_representation = old_details.representation();
Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
isolate);
- if (old_representation.Equals(new_representation) &&
+ if (old_constness == new_constness &&
+ old_representation.Equals(new_representation) &&
!FieldTypeIsCleared(new_representation, *new_field_type) &&
// Checking old_field_type for being cleared is not necessary because
// the NowIs check below would fail anyway in that case.
new_field_type->NowIs(old_field_type)) {
- DCHECK(Map::GeneralizeFieldType(old_representation, old_field_type,
- new_representation, new_field_type, isolate)
+ DCHECK(GeneralizeFieldType(old_representation, old_field_type,
+ new_representation, new_field_type, isolate)
->NowIs(old_field_type));
return;
}
@@ -3931,9 +4053,9 @@ void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
PropertyDetails details = descriptors->GetDetails(modify_index);
Handle<Name> name(descriptors->GetKey(modify_index));
- Handle<Object> wrapped_type(WrapType(new_field_type));
- field_owner->UpdateFieldType(modify_index, name, new_representation,
- wrapped_type);
+ Handle<Object> wrapped_type(WrapFieldType(new_field_type));
+ field_owner->UpdateFieldType(modify_index, name, new_constness,
+ new_representation, wrapped_type);
field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
isolate, DependentCode::kFieldOwnerGroup);
@@ -3946,577 +4068,40 @@ void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
}
}
-static inline Handle<FieldType> GetFieldType(
- Isolate* isolate, Handle<DescriptorArray> descriptors, int descriptor,
- PropertyLocation location, Representation representation) {
-#ifdef DEBUG
- PropertyDetails details = descriptors->GetDetails(descriptor);
- DCHECK_EQ(kData, details.kind());
- DCHECK_EQ(details.location(), location);
-#endif
- if (location == kField) {
- return handle(descriptors->GetFieldType(descriptor), isolate);
- } else {
- return descriptors->GetValue(descriptor)
- ->OptimalType(isolate, representation);
- }
-}
-
-// 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.
-//
-// This method rewrites or completes the transition tree to reflect the new
-// change. To avoid high degrees over polymorphism, and to stabilize quickly,
-// on every rewrite the new type is deduced by merging the current type with
-// 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
-// |new_attributes|) to walk the transition tree.
-// - Merge/generalize the "enhanced" descriptor array of the |old_map| and
-// descriptor array of the |target_map|.
-// - Generalize the |modify_index| descriptor using |new_representation| and
-// |new_field_type|.
-// - Walk the tree again starting from the root towards |target_map|. Stop at
-// |split_map|, the first map who's descriptor array does not match the merged
-// descriptor array.
-// - If |target_map| == |split_map|, |target_map| is in the expected state.
-// 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::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();
-
- Handle<DescriptorArray> old_descriptors(
- old_map->instance_descriptors(), isolate);
- int old_nof = old_map->NumberOfOwnDescriptors();
-
- // If it's just a representation generalization case (i.e. property kind and
- // attributes stays unchanged) it's fine to transition from None to anything
- // but double without any modification to the object, because the default
- // 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() &&
- old_map->elements_kind() == new_elements_kind) {
- PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
- Representation old_representation = old_details.representation();
-
- if (old_representation.IsNone()) {
- DCHECK_EQ(new_kind, old_details.kind());
- DCHECK_EQ(new_attributes, old_details.attributes());
- DCHECK_EQ(DATA, old_details.type());
- if (FLAG_trace_generalization) {
- old_map->PrintGeneralization(
- stdout, "uninitialized field", modify_index,
- old_map->NumberOfOwnDescriptors(),
- old_map->NumberOfOwnDescriptors(), false, old_representation,
- new_representation,
- handle(old_descriptors->GetFieldType(modify_index), isolate),
- MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
- }
- Handle<Map> field_owner(old_map->FindFieldOwner(modify_index), isolate);
-
- GeneralizeFieldType(field_owner, modify_index, new_representation,
- new_field_type);
- DCHECK(old_descriptors->GetDetails(modify_index)
- .representation()
- .Equals(new_representation));
- DCHECK(
- old_descriptors->GetFieldType(modify_index)->NowIs(new_field_type));
- return old_map;
- }
- }
-
- // 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, new_elements_kind, modify_index, store_mode, new_kind,
- new_attributes, "GenAll_NotEquivalent");
- }
-
- ElementsKind from_kind = root_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, 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, 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, to_kind, modify_index, store_mode, new_kind, new_attributes,
- "GenAll_RootModification2");
- }
- }
-
- // From here on, use the map with correct elements kind as root map.
- if (from_kind != to_kind) {
- root_map = Map::AsElementsKind(root_map, to_kind);
- }
-
- Handle<Map> target_map = root_map;
- for (int i = root_nof; i < old_nof; ++i) {
- PropertyDetails old_details = old_descriptors->GetDetails(i);
- PropertyKind next_kind;
- PropertyLocation next_location;
- PropertyAttributes next_attributes;
- Representation next_representation;
- bool property_kind_reconfiguration = false;
-
- if (modify_index == i) {
- DCHECK_EQ(FORCE_FIELD, store_mode);
- property_kind_reconfiguration = old_details.kind() != new_kind;
-
- next_kind = new_kind;
- next_location = kField;
- next_attributes = new_attributes;
- // If property kind is not reconfigured merge the result with
- // representation/field type from the old descriptor.
- next_representation = new_representation;
- if (!property_kind_reconfiguration) {
- next_representation =
- next_representation.generalize(old_details.representation());
- }
-
- } else {
- next_kind = old_details.kind();
- next_location = old_details.location();
- next_attributes = old_details.attributes();
- next_representation = old_details.representation();
- }
- Map* transition = TransitionArray::SearchTransition(
- *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
- if (transition == NULL) break;
- Handle<Map> tmp_map(transition, isolate);
-
- Handle<DescriptorArray> tmp_descriptors = handle(
- tmp_map->instance_descriptors(), isolate);
-
- // Check if target map is incompatible.
- PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
- DCHECK_EQ(next_kind, tmp_details.kind());
- DCHECK_EQ(next_attributes, tmp_details.attributes());
- if (next_kind == kAccessor &&
- !EqualImmutableValues(old_descriptors->GetValue(i),
- tmp_descriptors->GetValue(i))) {
- 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;
-
- Representation tmp_representation = tmp_details.representation();
- if (!next_representation.fits_into(tmp_representation)) break;
-
- PropertyLocation old_location = old_details.location();
- PropertyLocation tmp_location = tmp_details.location();
- if (tmp_location == kField) {
- if (next_kind == kData) {
- Handle<FieldType> next_field_type;
- if (modify_index == i) {
- next_field_type = new_field_type;
- if (!property_kind_reconfiguration) {
- Handle<FieldType> old_field_type =
- GetFieldType(isolate, old_descriptors, i,
- old_details.location(), tmp_representation);
- Representation old_representation = old_details.representation();
- next_field_type = GeneralizeFieldType(
- old_representation, old_field_type, new_representation,
- next_field_type, isolate);
- }
- } else {
- Handle<FieldType> old_field_type =
- GetFieldType(isolate, old_descriptors, i, old_details.location(),
- tmp_representation);
- next_field_type = old_field_type;
- }
- GeneralizeFieldType(tmp_map, i, tmp_representation, next_field_type);
- }
- } else if (old_location == kField ||
- !EqualImmutableValues(old_descriptors->GetValue(i),
- tmp_descriptors->GetValue(i))) {
- break;
- }
- DCHECK(!tmp_map->is_deprecated());
- target_map = tmp_map;
- }
-
- // Directly change the map if the target map is more general.
- Handle<DescriptorArray> target_descriptors(
- target_map->instance_descriptors(), isolate);
- int target_nof = target_map->NumberOfOwnDescriptors();
- if (target_nof == old_nof &&
- (store_mode != FORCE_FIELD ||
- (modify_index >= 0 &&
- target_descriptors->GetDetails(modify_index).location() == kField))) {
-#ifdef DEBUG
- if (modify_index >= 0) {
- PropertyDetails details = target_descriptors->GetDetails(modify_index);
- DCHECK_EQ(new_kind, details.kind());
- DCHECK_EQ(new_attributes, details.attributes());
- DCHECK(new_representation.fits_into(details.representation()));
- DCHECK(details.location() != kField ||
- new_field_type->NowIs(
- target_descriptors->GetFieldType(modify_index)));
- }
-#endif
- if (*target_map != *old_map) {
- old_map->NotifyLeafMapLayoutChange();
- }
- return target_map;
- }
-
- // Find the last compatible target map in the transition tree.
- for (int i = target_nof; i < old_nof; ++i) {
- PropertyDetails old_details = old_descriptors->GetDetails(i);
- PropertyKind next_kind;
- PropertyAttributes next_attributes;
- if (modify_index == i) {
- next_kind = new_kind;
- next_attributes = new_attributes;
- } else {
- next_kind = old_details.kind();
- next_attributes = old_details.attributes();
- }
- Map* transition = TransitionArray::SearchTransition(
- *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
- if (transition == NULL) break;
- Handle<Map> tmp_map(transition, isolate);
- Handle<DescriptorArray> tmp_descriptors(
- tmp_map->instance_descriptors(), isolate);
-
- // Check if target map is compatible.
-#ifdef DEBUG
- PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
- DCHECK_EQ(next_kind, tmp_details.kind());
- DCHECK_EQ(next_attributes, tmp_details.attributes());
-#endif
- if (next_kind == kAccessor &&
- !EqualImmutableValues(old_descriptors->GetValue(i),
- tmp_descriptors->GetValue(i))) {
- 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;
- }
- target_nof = target_map->NumberOfOwnDescriptors();
- target_descriptors = handle(target_map->instance_descriptors(), isolate);
-
- // Allocate a new descriptor array large enough to hold the required
- // descriptors, with minimally the exact same size as the old descriptor
- // array.
- int new_slack = Max(
- old_nof, old_descriptors->number_of_descriptors()) - old_nof;
- Handle<DescriptorArray> new_descriptors = DescriptorArray::Allocate(
- isolate, old_nof, new_slack);
- DCHECK(new_descriptors->length() > target_descriptors->length() ||
- new_descriptors->NumberOfSlackDescriptors() > 0 ||
- new_descriptors->number_of_descriptors() ==
- old_descriptors->number_of_descriptors());
- DCHECK(new_descriptors->number_of_descriptors() == old_nof);
-
- // 0 -> |root_nof|
- int current_offset = 0;
- for (int i = 0; i < root_nof; ++i) {
- PropertyDetails old_details = old_descriptors->GetDetails(i);
- if (old_details.location() == kField) {
- current_offset += old_details.field_width_in_words();
- }
- Descriptor d(handle(old_descriptors->GetKey(i), isolate),
- handle(old_descriptors->GetValue(i), isolate),
- old_details);
- new_descriptors->Set(i, &d);
- }
-
- // |root_nof| -> |target_nof|
- for (int i = root_nof; i < target_nof; ++i) {
- Handle<Name> target_key(target_descriptors->GetKey(i), isolate);
- PropertyDetails old_details = old_descriptors->GetDetails(i);
- PropertyDetails target_details = target_descriptors->GetDetails(i);
-
- PropertyKind next_kind;
- PropertyAttributes next_attributes;
- PropertyLocation next_location;
- Representation next_representation;
- bool property_kind_reconfiguration = false;
-
- if (modify_index == i) {
- DCHECK_EQ(FORCE_FIELD, store_mode);
- property_kind_reconfiguration = old_details.kind() != new_kind;
-
- next_kind = new_kind;
- next_attributes = new_attributes;
- next_location = kField;
-
- // Merge new representation/field type with ones from the target
- // descriptor. If property kind is not reconfigured merge the result with
- // representation/field type from the old descriptor.
- next_representation =
- new_representation.generalize(target_details.representation());
- if (!property_kind_reconfiguration) {
- next_representation =
- next_representation.generalize(old_details.representation());
- }
- } else {
- // Merge old_descriptor and target_descriptor entries.
- DCHECK_EQ(target_details.kind(), old_details.kind());
- next_kind = target_details.kind();
- next_attributes = target_details.attributes();
- next_location =
- old_details.location() == kField ||
- target_details.location() == kField ||
- !EqualImmutableValues(target_descriptors->GetValue(i),
- old_descriptors->GetValue(i))
- ? kField
- : kDescriptor;
-
- next_representation = old_details.representation().generalize(
- target_details.representation());
- }
- DCHECK_EQ(next_kind, target_details.kind());
- DCHECK_EQ(next_attributes, target_details.attributes());
-
- if (next_location == kField) {
- if (next_kind == kData) {
- Handle<FieldType> target_field_type =
- GetFieldType(isolate, target_descriptors, i,
- target_details.location(), next_representation);
-
- Handle<FieldType> next_field_type;
- if (modify_index == i) {
- next_field_type = GeneralizeFieldType(
- target_details.representation(), target_field_type,
- new_representation, new_field_type, isolate);
- if (!property_kind_reconfiguration) {
- Handle<FieldType> old_field_type =
- GetFieldType(isolate, old_descriptors, i,
- old_details.location(), next_representation);
- next_field_type = GeneralizeFieldType(
- old_details.representation(), old_field_type,
- next_representation, next_field_type, isolate);
- }
- } else {
- Handle<FieldType> old_field_type =
- GetFieldType(isolate, old_descriptors, i, old_details.location(),
- next_representation);
- next_field_type = GeneralizeFieldType(
- old_details.representation(), old_field_type, next_representation,
- target_field_type, isolate);
- }
- Handle<Object> wrapped_type(WrapType(next_field_type));
- DataDescriptor d(target_key, current_offset, wrapped_type,
- next_attributes, next_representation);
- current_offset += d.GetDetails().field_width_in_words();
- new_descriptors->Set(i, &d);
- } else {
- UNIMPLEMENTED(); // TODO(ishell): implement.
- }
- } else {
- PropertyDetails details(next_attributes, next_kind, next_location,
- next_representation);
- Descriptor d(target_key, handle(target_descriptors->GetValue(i), isolate),
- details);
- new_descriptors->Set(i, &d);
- }
- }
-
- // |target_nof| -> |old_nof|
- for (int i = target_nof; i < old_nof; ++i) {
- PropertyDetails old_details = old_descriptors->GetDetails(i);
- Handle<Name> old_key(old_descriptors->GetKey(i), isolate);
-
- // Merge old_descriptor entry and modified details together.
- PropertyKind next_kind;
- PropertyAttributes next_attributes;
- PropertyLocation next_location;
- Representation next_representation;
- bool property_kind_reconfiguration = false;
-
- if (modify_index == i) {
- DCHECK_EQ(FORCE_FIELD, store_mode);
- // In case of property kind reconfiguration it is not necessary to
- // take into account representation/field type of the old descriptor.
- property_kind_reconfiguration = old_details.kind() != new_kind;
-
- next_kind = new_kind;
- next_attributes = new_attributes;
- next_location = kField;
- next_representation = new_representation;
- if (!property_kind_reconfiguration) {
- next_representation =
- next_representation.generalize(old_details.representation());
- }
- } else {
- next_kind = old_details.kind();
- next_attributes = old_details.attributes();
- next_location = old_details.location();
- next_representation = old_details.representation();
- }
-
- if (next_location == kField) {
- if (next_kind == kData) {
- Handle<FieldType> next_field_type;
- if (modify_index == i) {
- next_field_type = new_field_type;
- if (!property_kind_reconfiguration) {
- Handle<FieldType> old_field_type =
- GetFieldType(isolate, old_descriptors, i,
- old_details.location(), next_representation);
- next_field_type = GeneralizeFieldType(
- old_details.representation(), old_field_type,
- next_representation, next_field_type, isolate);
- }
- } else {
- Handle<FieldType> old_field_type =
- GetFieldType(isolate, old_descriptors, i, old_details.location(),
- next_representation);
- next_field_type = old_field_type;
- }
-
- Handle<Object> wrapped_type(WrapType(next_field_type));
-
- DataDescriptor d(old_key, current_offset, wrapped_type, next_attributes,
- next_representation);
- current_offset += d.GetDetails().field_width_in_words();
- new_descriptors->Set(i, &d);
- } else {
- UNIMPLEMENTED(); // TODO(ishell): implement.
- }
- } else {
- PropertyDetails details(next_attributes, next_kind, next_location,
- next_representation);
- Descriptor d(old_key, handle(old_descriptors->GetValue(i), isolate),
- details);
- new_descriptors->Set(i, &d);
- }
- }
-
- new_descriptors->Sort();
-
- DCHECK(store_mode != FORCE_FIELD ||
- new_descriptors->GetDetails(modify_index).location() == kField);
-
- Handle<Map> split_map(root_map->FindLastMatchMap(
- root_nof, old_nof, *new_descriptors), isolate);
- int split_nof = split_map->NumberOfOwnDescriptors();
- DCHECK_NE(old_nof, split_nof);
-
- PropertyKind split_kind;
- PropertyAttributes split_attributes;
- if (modify_index == split_nof) {
- split_kind = new_kind;
- split_attributes = new_attributes;
- } else {
- PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof);
- split_kind = split_prop_details.kind();
- split_attributes = split_prop_details.attributes();
- }
-
- // Invalidate a transition target at |key|.
- Map* maybe_transition = TransitionArray::SearchTransition(
- *split_map, split_kind, old_descriptors->GetKey(split_nof),
- split_attributes);
- if (maybe_transition != NULL) {
- maybe_transition->DeprecateTransitionTree();
- }
-
- // If |maybe_transition| is not NULL then the transition array already
- // contains entry for given descriptor. This means that the transition
- // could be inserted regardless of whether transitions array is full or not.
- if (maybe_transition == NULL &&
- !TransitionArray::CanHaveMoreTransitions(split_map)) {
- return CopyGeneralizeAllRepresentations(
- old_map, to_kind, modify_index, store_mode, new_kind, new_attributes,
- "GenAll_CantHaveMoreTransitions");
- }
-
- old_map->NotifyLeafMapLayoutChange();
-
- if (FLAG_trace_generalization && modify_index >= 0) {
- PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
- PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
- MaybeHandle<FieldType> old_field_type;
- MaybeHandle<FieldType> new_field_type;
- MaybeHandle<Object> old_value;
- MaybeHandle<Object> new_value;
- if (old_details.type() == DATA) {
- old_field_type =
- handle(old_descriptors->GetFieldType(modify_index), isolate);
- } else {
- old_value = handle(old_descriptors->GetValue(modify_index), isolate);
- }
- if (new_details.type() == DATA) {
- new_field_type =
- handle(new_descriptors->GetFieldType(modify_index), isolate);
- } else {
- new_value = handle(new_descriptors->GetValue(modify_index), isolate);
- }
-
- old_map->PrintGeneralization(
- stdout, "", modify_index, split_nof, old_nof,
- old_details.location() == kDescriptor && store_mode == FORCE_FIELD,
- old_details.representation(), new_details.representation(),
- old_field_type, old_value, new_field_type, new_value);
- }
-
- Handle<LayoutDescriptor> new_layout_descriptor =
- LayoutDescriptor::New(split_map, new_descriptors, old_nof);
-
- Handle<Map> new_map =
- AddMissingTransitions(split_map, new_descriptors, new_layout_descriptor);
-
- // Deprecated part of the transition tree is no longer reachable, so replace
- // current instance descriptors in the "survived" part of the tree with
- // the new descriptors to maintain descriptors sharing invariant.
- split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor);
- return new_map;
+// TODO(ishell): remove.
+// static
+Handle<Map> Map::ReconfigureProperty(Handle<Map> map, int modify_index,
+ PropertyKind new_kind,
+ PropertyAttributes new_attributes,
+ Representation new_representation,
+ Handle<FieldType> new_field_type) {
+ DCHECK_EQ(kData, new_kind); // Only kData case is supported.
+ MapUpdater mu(map->GetIsolate(), map);
+ return mu.ReconfigureToDataField(modify_index, new_attributes, kConst,
+ new_representation, new_field_type);
+}
+
+// TODO(ishell): remove.
+// static
+Handle<Map> Map::ReconfigureElementsKind(Handle<Map> map,
+ ElementsKind new_elements_kind) {
+ MapUpdater mu(map->GetIsolate(), map);
+ return mu.ReconfigureElementsKind(new_elements_kind);
}
+// Generalize all fields and update the transition tree.
+Handle<Map> Map::GeneralizeAllFields(Handle<Map> map) {
+ Isolate* isolate = map->GetIsolate();
+ Handle<FieldType> any_type = FieldType::Any(isolate);
-// Generalize the representation of all DATA descriptors.
-Handle<Map> Map::GeneralizeAllFieldRepresentations(
- Handle<Map> map) {
Handle<DescriptorArray> descriptors(map->instance_descriptors());
for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
PropertyDetails details = descriptors->GetDetails(i);
- if (details.type() == DATA) {
- map = ReconfigureProperty(map, i, kData, details.attributes(),
- Representation::Tagged(),
- FieldType::Any(map->GetIsolate()), FORCE_FIELD);
+ if (details.location() == kField) {
+ DCHECK_EQ(kData, details.kind());
+ MapUpdater mu(isolate, map);
+ map = mu.ReconfigureToDataField(i, details.attributes(), kMutable,
+ Representation::Tagged(), any_type);
}
}
return map;
@@ -4569,49 +4154,51 @@ Map* Map::TryReplayPropertyTransitions(Map* old_map) {
PropertyDetails new_details = new_descriptors->GetDetails(i);
DCHECK_EQ(old_details.kind(), new_details.kind());
DCHECK_EQ(old_details.attributes(), new_details.attributes());
+ if (!IsGeneralizableTo(old_details.constness(), new_details.constness())) {
+ return nullptr;
+ }
+ DCHECK(IsGeneralizableTo(old_details.location(), new_details.location()));
if (!old_details.representation().fits_into(new_details.representation())) {
return nullptr;
}
- switch (new_details.type()) {
- case DATA: {
+ if (new_details.location() == kField) {
+ if (new_details.kind() == kData) {
FieldType* new_type = new_descriptors->GetFieldType(i);
// 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 nullptr;
}
- PropertyType old_property_type = old_details.type();
- if (old_property_type == DATA) {
+ DCHECK_EQ(kData, old_details.kind());
+ if (old_details.location() == kField) {
FieldType* old_type = old_descriptors->GetFieldType(i);
if (FieldTypeIsCleared(old_details.representation(), old_type) ||
!old_type->NowIs(new_type)) {
return nullptr;
}
} else {
- DCHECK(old_property_type == DATA_CONSTANT);
+ DCHECK_EQ(kDescriptor, old_details.location());
+ DCHECK(!FLAG_track_constant_fields);
Object* old_value = old_descriptors->GetValue(i);
if (!new_type->NowContains(old_value)) {
return nullptr;
}
}
- break;
- }
- case ACCESSOR: {
+
+ } else {
+ DCHECK_EQ(kAccessor, new_details.kind());
#ifdef DEBUG
FieldType* new_type = new_descriptors->GetFieldType(i);
DCHECK(new_type->IsAny());
#endif
- break;
+ UNREACHABLE();
}
-
- case DATA_CONSTANT:
- case ACCESSOR_CONSTANT: {
- Object* old_value = old_descriptors->GetValue(i);
- Object* new_value = new_descriptors->GetValue(i);
- if (old_details.location() == kField || old_value != new_value) {
- return nullptr;
- }
- break;
+ } else {
+ DCHECK_EQ(kDescriptor, new_details.location());
+ Object* old_value = old_descriptors->GetValue(i);
+ Object* new_value = new_descriptors->GetValue(i);
+ if (old_details.location() == kField || old_value != new_value) {
+ return nullptr;
}
}
}
@@ -4623,9 +4210,8 @@ Map* Map::TryReplayPropertyTransitions(Map* old_map) {
// static
Handle<Map> Map::Update(Handle<Map> map) {
if (!map->is_deprecated()) return map;
- return ReconfigureProperty(map, -1, kData, NONE, Representation::None(),
- FieldType::None(map->GetIsolate()),
- ALLOW_IN_DESCRIPTOR);
+ MapUpdater mu(map->GetIsolate(), map);
+ return mu.Update();
}
Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
@@ -4915,7 +4501,7 @@ Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
it->PrepareForDataProperty(to_assign);
// Write the property value.
- it->WriteDataValue(to_assign);
+ it->WriteDataValue(to_assign, false);
#if VERIFY_HEAP
if (FLAG_verify_heap) {
@@ -4989,7 +4575,7 @@ Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
it->ApplyTransitionToDataProperty(receiver);
// Write the property value.
- it->WriteDataValue(value);
+ it->WriteDataValue(value, true);
#if VERIFY_HEAP
if (FLAG_verify_heap) {
@@ -5045,6 +4631,36 @@ void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
map->UpdateDescriptors(*new_descriptors, layout_descriptor);
}
+// static
+Handle<Map> Map::GetObjectCreateMap(Handle<HeapObject> prototype) {
+ Isolate* isolate = prototype->GetIsolate();
+ Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
+ isolate);
+ if (map->prototype() == *prototype) return map;
+ if (prototype->IsNull(isolate)) {
+ return isolate->slow_object_with_null_prototype_map();
+ }
+ if (prototype->IsJSObject()) {
+ Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
+ if (!js_prototype->map()->is_prototype_map()) {
+ JSObject::OptimizeAsPrototype(js_prototype, FAST_PROTOTYPE);
+ }
+ Handle<PrototypeInfo> info =
+ Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
+ // TODO(verwaest): Use inobject slack tracking for this map.
+ if (info->HasObjectCreateMap()) {
+ map = handle(info->ObjectCreateMap(), isolate);
+ } else {
+ map = Map::CopyInitialMap(map);
+ Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
+ PrototypeInfo::SetObjectCreateMap(info, map);
+ }
+ return map;
+ }
+
+ return Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE);
+}
+
template <class T>
static int AppendUniqueCallbacks(Handle<TemplateList> callbacks,
Handle<typename T::Array> array,
@@ -5094,8 +4710,9 @@ struct DescriptorArrayAppender {
int valid_descriptors,
Handle<DescriptorArray> array) {
DisallowHeapAllocation no_gc;
- AccessorConstantDescriptor desc(key, entry, entry->property_attributes());
- array->Append(&desc);
+ Descriptor d =
+ Descriptor::AccessorConstant(key, entry, entry->property_attributes());
+ array->Append(&d);
}
};
@@ -5631,7 +5248,7 @@ Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
DCHECK(object->map()->is_constructor());
DCHECK(!object->IsJSFunction());
- return handle(object->GetCreationContext());
+ return object->GetCreationContext();
}
@@ -5979,7 +5596,7 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
iteration_order =
NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
} else {
- iteration_order = NameDictionary::BuildIterationIndicesArray(dictionary);
+ iteration_order = NameDictionary::IterationIndices(dictionary);
}
int instance_descriptor_length = iteration_order->length();
@@ -5990,10 +5607,16 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
int index = Smi::cast(iteration_order->get(i))->value();
DCHECK(dictionary->IsKey(isolate, dictionary->KeyAt(index)));
- Object* value = dictionary->ValueAt(index);
- PropertyType type = dictionary->DetailsAt(index).type();
- if (type == DATA && !value->IsJSFunction()) {
- number_of_fields += 1;
+ PropertyKind kind = dictionary->DetailsAt(index).kind();
+ if (kind == kData) {
+ if (FLAG_track_constant_fields) {
+ number_of_fields += 1;
+ } else {
+ Object* value = dictionary->ValueAt(index);
+ if (!value->IsJSFunction()) {
+ number_of_fields += 1;
+ }
+ }
}
}
@@ -6057,14 +5680,28 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
Object* value = dictionary->ValueAt(index);
PropertyDetails details = dictionary->DetailsAt(index);
+ DCHECK_EQ(kField, details.location());
+ DCHECK_EQ(kMutable, details.constness());
int enumeration_index = details.dictionary_index();
- PropertyType type = details.type();
- if (value->IsJSFunction()) {
- DataConstantDescriptor d(key, handle(value, isolate),
- details.attributes());
- descriptors->Set(enumeration_index - 1, &d);
- } else if (type == DATA) {
+ Descriptor d;
+ if (details.kind() == kData) {
+ if (!FLAG_track_constant_fields && value->IsJSFunction()) {
+ d = Descriptor::DataConstant(key, handle(value, isolate),
+ details.attributes());
+ } else {
+ d = Descriptor::DataField(
+ key, current_offset, details.attributes(), kDefaultFieldConstness,
+ // TODO(verwaest): value->OptimalRepresentation();
+ Representation::Tagged(), FieldType::Any(isolate));
+ }
+ } else {
+ DCHECK_EQ(kAccessor, details.kind());
+ d = Descriptor::AccessorConstant(key, handle(value, isolate),
+ details.attributes());
+ }
+ details = d.GetDetails();
+ if (details.location() == kField) {
if (current_offset < inobject_props) {
object->InObjectPropertyAtPut(current_offset, value,
UPDATE_WRITE_BARRIER);
@@ -6072,18 +5709,9 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
int offset = current_offset - inobject_props;
fields->set(offset, value);
}
- DataDescriptor d(key, current_offset, details.attributes(),
- // TODO(verwaest): value->OptimalRepresentation();
- Representation::Tagged());
- current_offset += d.GetDetails().field_width_in_words();
- descriptors->Set(enumeration_index - 1, &d);
- } else if (type == ACCESSOR_CONSTANT) {
- AccessorConstantDescriptor d(key, handle(value, isolate),
- details.attributes());
- descriptors->Set(enumeration_index - 1, &d);
- } else {
- UNREACHABLE();
+ current_offset += details.field_width_in_words();
}
+ descriptors->Set(enumeration_index - 1, &d);
}
DCHECK(current_offset == number_of_fields);
@@ -6123,9 +5751,10 @@ void JSObject::ResetElements(Handle<JSObject> object) {
void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
if (dictionary->requires_slow_elements()) return;
dictionary->set_requires_slow_elements();
- // TODO(verwaest): Remove this hack.
if (map()->is_prototype_map()) {
- TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate());
+ // If this object is a prototype (the callee will check), invalidate any
+ // prototype chains involving it.
+ InvalidatePrototypeChains(map());
}
}
@@ -6412,33 +6041,6 @@ Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
return DeleteProperty(&it, language_mode);
}
-
-// ES6 7.1.14
-// 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);
- // 2. ReturnIfAbrupt(key).
- Handle<Object> key;
- if (!maybe_key.ToHandle(&key)) return key;
- // 3. If Type(key) is Symbol, then return key.
- if (key->IsSymbol()) return key;
- // 4. Return ToString(key).
- // Extending spec'ed behavior, we'd be happy to return an element index.
- if (key->IsSmi()) return key;
- if (key->IsHeapNumber()) {
- uint32_t uint_value;
- if (value->ToArrayLength(&uint_value) &&
- uint_value <= static_cast<uint32_t>(Smi::kMaxValue)) {
- return handle(Smi::FromInt(static_cast<int>(uint_value)), isolate);
- }
- }
- return Object::ToString(isolate, key);
-}
-
-
// ES6 19.1.2.4
// static
Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
@@ -6563,12 +6165,15 @@ Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
key, desc, should_throw);
}
+ if (object->IsJSTypedArray()) {
+ return JSTypedArray::DefineOwnProperty(
+ isolate, Handle<JSTypedArray>::cast(object), key, desc, should_throw);
+ }
// TODO(neis): Special case for JSModuleNamespace?
// OrdinaryDefineOwnProperty, by virtue of calling
- // DefineOwnPropertyIgnoreAttributes, can handle arguments (ES6 9.4.4.2)
- // and IntegerIndexedExotics (ES6 9.4.5.3), with one exception:
- // TODO(jkummerow): Setting an indexed accessor on a typed array should throw.
+ // DefineOwnPropertyIgnoreAttributes, can handle arguments
+ // (ES#sec-arguments-exotic-objects-defineownproperty-p-desc).
return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
desc, should_throw);
}
@@ -6970,7 +6575,6 @@ bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) {
return false;
}
-
bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
return PropertyKeyToArrayLength(index_obj, output) && *output != kMaxUInt32;
}
@@ -7300,12 +6904,12 @@ Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy,
if (it.IsFound()) {
DCHECK_EQ(LookupIterator::DATA, it.state());
DCHECK_EQ(DONT_ENUM, it.property_attributes());
- it.WriteDataValue(value);
+ it.WriteDataValue(value, false);
return Just(true);
}
Handle<NameDictionary> dict(proxy->property_dictionary());
- PropertyDetails details(DONT_ENUM, DATA, 0, PropertyCellType::kNoCell);
+ PropertyDetails details(kData, DONT_ENUM, 0, PropertyCellType::kNoCell);
Handle<NameDictionary> result =
NameDictionary::Add(dict, private_name, value, details);
if (!dict.is_identical_to(result)) proxy->set_properties(*result);
@@ -7330,7 +6934,13 @@ namespace {
Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
PropertyDescriptor* desc) {
- if (it->state() == LookupIterator::INTERCEPTOR) {
+ bool has_access = true;
+ if (it->state() == LookupIterator::ACCESS_CHECK) {
+ has_access = it->HasAccess() || JSObject::AllCanRead(it);
+ it->Next();
+ }
+
+ if (has_access && it->state() == LookupIterator::INTERCEPTOR) {
Isolate* isolate = it->isolate();
Handle<InterceptorInfo> interceptor = it->GetInterceptor();
if (!interceptor->descriptor()->IsUndefined(isolate)) {
@@ -7374,6 +6984,7 @@ Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
}
}
}
+ it->Restart();
return Just(false);
}
} // namespace
@@ -7998,7 +7609,7 @@ void ApplyAttributesToDictionary(Isolate* isolate,
PropertyDetails details = dictionary->DetailsAt(i);
int attrs = attributes;
// READ_ONLY is an invalid attribute for JS setters/getters.
- if ((attributes & READ_ONLY) && details.type() == ACCESSOR_CONSTANT) {
+ if ((attributes & READ_ONLY) && details.kind() == kAccessor) {
Object* v = dictionary->ValueAt(i);
if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
@@ -8238,12 +7849,14 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
int limit = copy->map()->NumberOfOwnDescriptors();
for (int i = 0; i < limit; i++) {
PropertyDetails details = descriptors->GetDetails(i);
- if (details.type() != DATA) continue;
+ if (details.location() != kField) continue;
+ DCHECK_EQ(kData, details.kind());
FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
if (object->IsUnboxedDoubleField(index)) {
if (copying) {
- double value = object->RawFastDoublePropertyAt(index);
- copy->RawFastDoublePropertyAtPut(index, value);
+ // Ensure that all bits of the double value are preserved.
+ uint64_t value = object->RawFastDoublePropertyAsBitsAt(index);
+ copy->RawFastDoublePropertyAsBitsAtPut(index, value);
}
} else {
Handle<Object> value(object->RawFastPropertyAt(index), isolate);
@@ -8563,8 +8176,8 @@ bool Map::OnlyHasSimpleProperties() {
// Wrapped string elements aren't explicitly stored in the elements backing
// store, but are loaded indirectly from the underlying string.
return !IsStringWrapperElementsKind(elements_kind()) &&
- instance_type() > LAST_SPECIAL_RECEIVER_TYPE &&
- !has_hidden_prototype() && !is_dictionary_map();
+ !IsSpecialReceiverMap() && !has_hidden_prototype() &&
+ !is_dictionary_map();
}
MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
@@ -8832,7 +8445,9 @@ Object* JSObject::SlowReverseLookup(Object* value) {
DescriptorArray* descs = map()->instance_descriptors();
bool value_is_number = value->IsNumber();
for (int i = 0; i < number_of_own_descriptors; i++) {
- if (descs->GetType(i) == DATA) {
+ PropertyDetails details = descs->GetDetails(i);
+ if (details.location() == kField) {
+ DCHECK_EQ(kData, details.kind());
FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
if (IsUnboxedDoubleField(field_index)) {
if (value_is_number) {
@@ -8852,9 +8467,12 @@ Object* JSObject::SlowReverseLookup(Object* value) {
return descs->GetKey(i);
}
}
- } else if (descs->GetType(i) == DATA_CONSTANT) {
- if (descs->GetConstant(i) == value) {
- return descs->GetKey(i);
+ } else {
+ DCHECK_EQ(kDescriptor, details.location());
+ if (details.kind() == kData) {
+ if (descs->GetValue(i) == value) {
+ return descs->GetKey(i);
+ }
}
}
}
@@ -9000,12 +8618,13 @@ Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size,
Isolate* isolate = map->GetIsolate();
// Strict function maps have Function as a constructor but the
// Function's initial map is a sloppy function map. Same holds for
- // GeneratorFunction and its initial map.
+ // GeneratorFunction / AsyncFunction and its initial map.
Object* constructor = map->GetConstructor();
DCHECK(constructor->IsJSFunction());
DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
*map == *isolate->strict_function_map() ||
- *map == *isolate->strict_generator_function_map());
+ *map == *isolate->generator_function_map() ||
+ *map == *isolate->async_function_map());
#endif
// Initial maps must always own their descriptors and it's descriptor array
// does not contain descriptors that do not belong to the map.
@@ -9161,13 +8780,7 @@ Handle<Map> Map::CopyReplaceDescriptors(
CHECK(maybe_name.ToHandle(&name));
ConnectTransition(map, result, name, simple_flag);
} else {
- int length = descriptors->number_of_descriptors();
- for (int i = 0; i < length; i++) {
- descriptors->SetRepresentation(i, Representation::Tagged());
- if (descriptors->GetDetails(i).type() == DATA) {
- descriptors->SetValue(i, FieldType::Any());
- }
- }
+ descriptors->GeneralizeAllFields();
result->InitializeDescriptors(*descriptors,
LayoutDescriptor::FastPointerLayout());
}
@@ -9449,42 +9062,45 @@ Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
return new_map;
}
-FieldType* DescriptorArray::GetFieldType(int descriptor_number) {
- DCHECK(GetDetails(descriptor_number).location() == kField);
- Object* value = GetValue(descriptor_number);
- if (value->IsWeakCell()) {
- if (WeakCell::cast(value)->cleared()) return FieldType::None();
- value = WeakCell::cast(value)->value();
- }
- return FieldType::cast(value);
-}
-
namespace {
-bool CanHoldValue(DescriptorArray* descriptors, int descriptor, Object* value) {
+bool CanHoldValue(DescriptorArray* descriptors, int descriptor,
+ PropertyConstness constness, Object* value) {
PropertyDetails details = descriptors->GetDetails(descriptor);
- switch (details.type()) {
- case DATA:
- return value->FitsRepresentation(details.representation()) &&
+ if (details.location() == kField) {
+ if (details.kind() == kData) {
+ return IsGeneralizableTo(constness, details.constness()) &&
+ value->FitsRepresentation(details.representation()) &&
descriptors->GetFieldType(descriptor)->NowContains(value);
+ } else {
+ DCHECK_EQ(kAccessor, details.kind());
+ return false;
+ }
- case DATA_CONSTANT:
- DCHECK(descriptors->GetConstant(descriptor) != value ||
+ } else {
+ DCHECK_EQ(kDescriptor, details.location());
+ DCHECK_EQ(kConst, details.constness());
+ if (details.kind() == kData) {
+ DCHECK(!FLAG_track_constant_fields);
+ DCHECK(descriptors->GetValue(descriptor) != value ||
value->FitsRepresentation(details.representation()));
- return descriptors->GetConstant(descriptor) == value;
-
- case ACCESSOR:
- case ACCESSOR_CONSTANT:
+ return descriptors->GetValue(descriptor) == value;
+ } else {
+ DCHECK_EQ(kAccessor, details.kind());
return false;
+ }
}
-
UNREACHABLE();
return false;
}
Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor,
+ PropertyConstness constness,
Handle<Object> value) {
- if (CanHoldValue(map->instance_descriptors(), descriptor, *value)) return map;
+ if (CanHoldValue(map->instance_descriptors(), descriptor, constness,
+ *value)) {
+ return map;
+ }
Isolate* isolate = map->GetIsolate();
PropertyAttributes attributes =
@@ -9492,25 +9108,27 @@ Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor,
Representation representation = value->OptimalRepresentation();
Handle<FieldType> type = value->OptimalType(isolate, representation);
- return Map::ReconfigureProperty(map, descriptor, kData, attributes,
- representation, type, FORCE_FIELD);
+ MapUpdater mu(isolate, map);
+ return mu.ReconfigureToDataField(descriptor, attributes, constness,
+ representation, type);
}
} // namespace
// static
Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
+ PropertyConstness constness,
Handle<Object> value) {
// Dictionaries can store any property value.
DCHECK(!map->is_dictionary_map());
// Update to the newest map before storing the property.
- return UpdateDescriptorForValue(Update(map), descriptor, value);
+ return UpdateDescriptorForValue(Update(map), descriptor, constness, value);
}
-
Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
Handle<Object> value,
PropertyAttributes attributes,
+ PropertyConstness constness,
StoreFromKeyed store_mode) {
RuntimeCallTimerScope stats_scope(
*map, map->is_prototype_map()
@@ -9533,19 +9151,19 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
->GetDetails(descriptor)
.attributes());
- return UpdateDescriptorForValue(transition, descriptor, value);
+ return UpdateDescriptorForValue(transition, descriptor, constness, value);
}
TransitionFlag flag = INSERT_TRANSITION;
MaybeHandle<Map> maybe_map;
- if (value->IsJSFunction()) {
+ if (!FLAG_track_constant_fields && value->IsJSFunction()) {
maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag);
} else if (!map->TooManyFastProperties(store_mode)) {
Isolate* isolate = name->GetIsolate();
Representation representation = value->OptimalRepresentation();
Handle<FieldType> type = value->OptimalType(isolate, representation);
- maybe_map =
- Map::CopyWithField(map, name, type, attributes, representation, flag);
+ maybe_map = Map::CopyWithField(map, name, type, attributes, constness,
+ representation, flag);
}
Handle<Map> result;
@@ -9576,9 +9194,9 @@ Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
if (!map->GetBackPointer()->IsMap()) {
// There is no benefit from reconstructing transition tree for maps without
// back pointers.
- return CopyGeneralizeAllRepresentations(
- map, map->elements_kind(), descriptor, FORCE_FIELD, kind, attributes,
- "GenAll_AttributesMismatchProtoMap");
+ return CopyGeneralizeAllFields(map, map->elements_kind(), descriptor, kind,
+ attributes,
+ "GenAll_AttributesMismatchProtoMap");
}
if (FLAG_trace_generalization) {
@@ -9586,9 +9204,12 @@ Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
}
Isolate* isolate = map->GetIsolate();
- Handle<Map> new_map = ReconfigureProperty(
- map, descriptor, kind, attributes, Representation::None(),
- FieldType::None(isolate), FORCE_FIELD);
+
+ MapUpdater mu(isolate, map);
+ DCHECK_EQ(kData, kind); // Only kData case is supported so far.
+ Handle<Map> new_map = mu.ReconfigureToDataField(
+ descriptor, attributes, kDefaultFieldConstness, Representation::None(),
+ FieldType::None(isolate));
return new_map;
}
@@ -9648,7 +9269,7 @@ Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
return Map::Normalize(map, mode, "AccessorsOverwritingNonLast");
}
PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
- if (old_details.type() != ACCESSOR_CONSTANT) {
+ if (old_details.kind() != kAccessor) {
return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors");
}
@@ -9690,8 +9311,8 @@ Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
pair->SetComponents(*getter, *setter);
TransitionFlag flag = INSERT_TRANSITION;
- AccessorConstantDescriptor new_desc(name, pair, attributes);
- return Map::CopyInsertDescriptor(map, &new_desc, flag);
+ Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
+ return Map::CopyInsertDescriptor(map, &d, flag);
}
@@ -9770,15 +9391,13 @@ Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
if (!key->IsPrivate()) {
int mask = DONT_DELETE | DONT_ENUM;
// READ_ONLY is an invalid attribute for JS setters/getters.
- if (details.type() != ACCESSOR_CONSTANT || !value->IsAccessorPair()) {
+ if (details.kind() != kAccessor || !value->IsAccessorPair()) {
mask |= READ_ONLY;
}
details = details.CopyAddAttributes(
static_cast<PropertyAttributes>(attributes & mask));
}
- Descriptor inner_desc(
- handle(key), handle(value, desc->GetIsolate()), details);
- descriptors->SetDescriptor(i, &inner_desc);
+ descriptors->Set(i, key, value, details);
}
} else {
for (int i = 0; i < size; ++i) {
@@ -9799,7 +9418,8 @@ bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) {
}
PropertyDetails details = GetDetails(i);
PropertyDetails other_details = desc->GetDetails(i);
- if (details.type() != other_details.type() ||
+ if (details.kind() != other_details.kind() ||
+ details.location() != other_details.location() ||
!details.representation().Equals(other_details.representation())) {
return false;
}
@@ -10113,8 +9733,7 @@ Handle<FixedArray> FixedArray::SetAndGrow(Handle<FixedArray> array, int index,
void FixedArray::Shrink(int new_length) {
DCHECK(0 <= new_length && new_length <= length());
if (new_length < length()) {
- GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
- this, length() - new_length);
+ GetHeap()->RightTrimFixedArray(this, length() - new_length);
}
}
@@ -10127,7 +9746,6 @@ void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
}
}
-
#ifdef DEBUG
bool FixedArray::IsEqualTo(FixedArray* other) {
if (length() != other->length()) return false;
@@ -10308,6 +9926,12 @@ Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
return array;
}
+Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) {
+ Handle<ArrayList> result = Handle<ArrayList>::cast(
+ isolate->factory()->NewFixedArray(size + kFirstIndex));
+ result->SetLength(0);
+ return result;
+}
bool ArrayList::IsFull() {
int capacity = length();
@@ -10442,17 +10066,11 @@ void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
}
}
-
void DescriptorArray::CopyFrom(int index, DescriptorArray* src) {
- Object* value = src->GetValue(index);
PropertyDetails details = src->GetDetails(index);
- Descriptor desc(handle(src->GetKey(index)),
- handle(value, src->GetIsolate()),
- details);
- SetDescriptor(index, &desc);
+ Set(index, src->GetKey(index), src->GetValue(index), details);
}
-
void DescriptorArray::Sort() {
// In-place heap sort.
int len = number_of_descriptors();
@@ -10554,34 +10172,12 @@ Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
SharedFunctionInfo* DeoptimizationInputData::GetInlinedFunction(int index) {
if (index == -1) {
- return SharedFunctionInfo::cast(this->SharedFunctionInfo());
+ return SharedFunctionInfo::cast(SharedFunctionInfo());
} else {
return SharedFunctionInfo::cast(LiteralArray()->get(index));
}
}
-const int LiteralsArray::kFeedbackVectorOffset =
- LiteralsArray::OffsetOfElementAt(LiteralsArray::kVectorIndex);
-
-const int LiteralsArray::kOffsetToFirstLiteral =
- LiteralsArray::OffsetOfElementAt(LiteralsArray::kFirstLiteralIndex);
-
-// static
-Handle<LiteralsArray> LiteralsArray::New(Isolate* isolate,
- Handle<TypeFeedbackVector> vector,
- int number_of_literals,
- PretenureFlag pretenure) {
- if (vector->is_empty() && number_of_literals == 0) {
- return Handle<LiteralsArray>::cast(
- isolate->factory()->empty_literals_array());
- }
- Handle<FixedArray> literals = isolate->factory()->NewFixedArray(
- number_of_literals + kFirstLiteralIndex, pretenure);
- Handle<LiteralsArray> casted_literals = Handle<LiteralsArray>::cast(literals);
- casted_literals->set_feedback_vector(*vector);
- return casted_literals;
-}
-
int HandlerTable::LookupRange(int pc_offset, int* data_out,
CatchPrediction* prediction_out) {
int innermost_handler = -1;
@@ -10598,7 +10194,7 @@ int HandlerTable::LookupRange(int pc_offset, int* data_out,
int handler_offset = HandlerOffsetField::decode(handler_field);
CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
int handler_data = Smi::cast(get(i + kRangeDataIndex))->value();
- if (pc_offset > start_offset && pc_offset <= end_offset) {
+ if (pc_offset >= start_offset && pc_offset < end_offset) {
DCHECK_GE(start_offset, innermost_start);
DCHECK_LT(end_offset, innermost_end);
innermost_handler = handler_offset;
@@ -10668,11 +10264,7 @@ Handle<String> String::Trim(Handle<String> string, TrimMode mode) {
return isolate->factory()->NewSubString(string, left, right);
}
-bool String::LooksValid() {
- if (!GetIsolate()->heap()->Contains(this)) return false;
- return true;
-}
-
+bool String::LooksValid() { return GetIsolate()->heap()->Contains(this); }
// static
MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
@@ -10806,8 +10398,7 @@ String::FlatContent String::GetFlatContent() {
}
string = cons->first();
shape = StringShape(string);
- }
- if (shape.representation_tag() == kSlicedStringTag) {
+ } else if (shape.representation_tag() == kSlicedStringTag) {
SlicedString* slice = SlicedString::cast(string);
offset = slice->offset();
string = slice->parent();
@@ -10815,6 +10406,13 @@ String::FlatContent String::GetFlatContent() {
DCHECK(shape.representation_tag() != kConsStringTag &&
shape.representation_tag() != kSlicedStringTag);
}
+ if (shape.representation_tag() == kThinStringTag) {
+ ThinString* thin = ThinString::cast(string);
+ string = thin->actual();
+ shape = StringShape(string);
+ DCHECK(!shape.IsCons());
+ DCHECK(!shape.IsSliced());
+ }
if (shape.encoding_tag() == kOneByteStringTag) {
const uint8_t* start;
if (shape.representation_tag() == kSeqStringTag) {
@@ -10900,6 +10498,7 @@ const uc16* String::GetTwoByteData(unsigned start) {
return slice->parent()->GetTwoByteData(start + slice->offset());
}
case kConsStringTag:
+ case kThinStringTag:
UNREACHABLE();
return NULL;
}
@@ -11166,6 +10765,7 @@ uint16_t ConsString::ConsStringGet(int index) {
return 0;
}
+uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); }
uint16_t SlicedString::SlicedStringGet(int index) {
return parent()->Get(offset() + index);
@@ -11260,6 +10860,10 @@ void String::WriteToFlat(String* src,
WriteToFlat(slice->parent(), sink, from + offset, to + offset);
return;
}
+ case kOneByteStringTag | kThinStringTag:
+ case kTwoByteStringTag | kThinStringTag:
+ source = ThinString::cast(source)->actual();
+ break;
}
}
}
@@ -11481,6 +11085,17 @@ bool String::SlowEquals(String* other) {
if (len != other->length()) return false;
if (len == 0) return true;
+ // Fast check: if at least one ThinString is involved, dereference it/them
+ // and restart.
+ if (this->IsThinString() || other->IsThinString()) {
+ if (other->IsThinString()) other = ThinString::cast(other)->actual();
+ if (this->IsThinString()) {
+ return ThinString::cast(this)->actual()->Equals(other);
+ } else {
+ return this->Equals(other);
+ }
+ }
+
// Fast check: if hash code is computed for both strings
// a fast negative check can be performed.
if (HasHashCode() && other->HasHashCode()) {
@@ -11522,6 +11137,14 @@ bool String::SlowEquals(Handle<String> one, Handle<String> two) {
if (one_length != two->length()) return false;
if (one_length == 0) return true;
+ // Fast check: if at least one ThinString is involved, dereference it/them
+ // and restart.
+ if (one->IsThinString() || two->IsThinString()) {
+ if (one->IsThinString()) one = handle(ThinString::cast(*one)->actual());
+ if (two->IsThinString()) two = handle(ThinString::cast(*two)->actual());
+ return String::Equals(one, two);
+ }
+
// Fast check: if hash code is computed for both strings
// a fast negative check can be performed.
if (one->HasHashCode() && two->HasHashCode()) {
@@ -11630,7 +11253,7 @@ ComparisonResult String::Compare(Handle<String> x, Handle<String> y) {
Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver,
Handle<Object> search, Handle<Object> position) {
- if (receiver->IsNull(isolate) || receiver->IsUndefined(isolate)) {
+ if (receiver->IsNullOrUndefined(isolate)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
isolate->factory()->NewStringFromAsciiChecked(
@@ -11647,11 +11270,9 @@ Object* String::IndexOf(Isolate* isolate, Handle<Object> receiver,
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
Object::ToInteger(isolate, position));
- double index = std::max(position->Number(), 0.0);
- index = std::min(index, static_cast<double>(receiver_string->length()));
-
- return Smi::FromInt(String::IndexOf(isolate, receiver_string, search_string,
- static_cast<uint32_t>(index)));
+ uint32_t index = receiver_string->ToValidIndex(*position);
+ return Smi::FromInt(
+ String::IndexOf(isolate, receiver_string, search_string, index));
}
namespace {
@@ -11833,7 +11454,7 @@ int StringMatchBackwards(Vector<const schar> subject,
Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
Handle<Object> search, Handle<Object> position) {
- if (receiver->IsNull(isolate) || receiver->IsUndefined(isolate)) {
+ if (receiver->IsNullOrUndefined(isolate)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
isolate->factory()->NewStringFromAsciiChecked(
@@ -11857,11 +11478,7 @@ Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
} else {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
Object::ToInteger(isolate, position));
-
- double position_number = std::max(position->Number(), 0.0);
- position_number = std::min(position_number,
- static_cast<double>(receiver_string->length()));
- start_index = static_cast<uint32_t>(position_number);
+ start_index = receiver_string->ToValidIndex(*position);
}
uint32_t pattern_length = search_string->length();
@@ -12006,6 +11623,9 @@ bool String::SlowAsArrayIndex(uint32_t* index) {
Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
+ Heap* heap = string->GetHeap();
+ if (new_length == 0) return heap->isolate()->factory()->empty_string();
+
int new_size, old_size;
int old_length = string->length();
if (old_length <= new_length) return string;
@@ -12025,18 +11645,16 @@ Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
DCHECK_OBJECT_ALIGNED(start_of_string);
DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
- Heap* heap = string->GetHeap();
// Sizes are pointer size aligned, so that we can use filler objects
// that are a multiple of pointer size.
heap->CreateFillerObjectAt(start_of_string + new_size, delta,
ClearRecordedSlots::kNo);
- heap->AdjustLiveBytes(*string, -delta, Heap::CONCURRENT_TO_SWEEPER);
+ heap->AdjustLiveBytes(*string, -delta);
// We are storing the new length using release store after creating a filler
// for the left-over space to avoid races with the sweeper thread.
string->synchronized_set_length(new_length);
- if (new_length == 0) return heap->isolate()->factory()->empty_string();
return string;
}
@@ -12209,7 +11827,9 @@ bool Map::EquivalentToForNormalization(Map* other,
int properties =
mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
- GetInObjectProperties() == properties;
+ GetInObjectProperties() == properties &&
+ JSObject::GetInternalFieldCount(this) ==
+ JSObject::GetInternalFieldCount(other);
}
@@ -12283,60 +11903,33 @@ void JSFunction::AttemptConcurrentOptimization() {
}
// static
-Handle<LiteralsArray> SharedFunctionInfo::FindOrCreateLiterals(
- Handle<SharedFunctionInfo> shared, Handle<Context> native_context) {
- Isolate* isolate = shared->GetIsolate();
- CodeAndLiterals result =
- shared->SearchOptimizedCodeMap(*native_context, BailoutId::None());
- if (result.literals != nullptr) {
- DCHECK(shared->feedback_metadata()->is_empty() ||
- !result.literals->feedback_vector()->is_empty());
- return handle(result.literals, isolate);
- }
-
- Handle<TypeFeedbackVector> feedback_vector =
- TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata()));
- Handle<LiteralsArray> literals =
- LiteralsArray::New(isolate, feedback_vector, shared->num_literals());
- Handle<Code> code;
- if (result.code != nullptr) {
- code = Handle<Code>(result.code, isolate);
- }
- AddToOptimizedCodeMap(shared, native_context, code, literals,
- BailoutId::None());
- return literals;
-}
-
-// static
void SharedFunctionInfo::AddToOptimizedCodeMap(
Handle<SharedFunctionInfo> shared, Handle<Context> native_context,
- MaybeHandle<Code> code, Handle<LiteralsArray> literals,
- BailoutId osr_ast_id) {
+ Handle<Code> code, BailoutId osr_ast_id) {
Isolate* isolate = shared->GetIsolate();
if (isolate->serializer_enabled()) return;
- DCHECK(code.is_null() ||
- code.ToHandleChecked()->kind() == Code::OPTIMIZED_FUNCTION);
+ DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
DCHECK(native_context->IsNativeContext());
- STATIC_ASSERT(kEntryLength == 4);
+ STATIC_ASSERT(kEntryLength == 2);
Handle<FixedArray> new_code_map;
int entry;
+ if (!osr_ast_id.IsNone()) {
+ Context::AddToOptimizedCodeMap(native_context, shared, code, osr_ast_id);
+ return;
+ }
+
+ DCHECK(osr_ast_id.IsNone());
if (shared->OptimizedCodeMapIsCleared()) {
new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED);
entry = kEntriesStart;
} else {
Handle<FixedArray> old_code_map(shared->optimized_code_map(), isolate);
- entry = shared->SearchOptimizedCodeMapEntry(*native_context, osr_ast_id);
+ entry = shared->SearchOptimizedCodeMapEntry(*native_context);
if (entry >= kEntriesStart) {
- // Just set the code and literals of the entry.
- if (!code.is_null()) {
- Handle<WeakCell> code_cell =
- isolate->factory()->NewWeakCell(code.ToHandleChecked());
- old_code_map->set(entry + kCachedCodeOffset, *code_cell);
- }
- Handle<WeakCell> literals_cell =
- isolate->factory()->NewWeakCell(literals);
- old_code_map->set(entry + kLiteralsOffset, *literals_cell);
+ // Just set the code of the entry.
+ Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
+ old_code_map->set(entry + kCachedCodeOffset, *code_cell);
return;
}
@@ -12364,16 +11957,11 @@ void SharedFunctionInfo::AddToOptimizedCodeMap(
}
}
- Handle<WeakCell> code_cell =
- code.is_null() ? isolate->factory()->empty_weak_cell()
- : isolate->factory()->NewWeakCell(code.ToHandleChecked());
- Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals);
+ Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
WeakCell* context_cell = native_context->self_weak_cell();
new_code_map->set(entry + kContextOffset, context_cell);
new_code_map->set(entry + kCachedCodeOffset, *code_cell);
- new_code_map->set(entry + kLiteralsOffset, *literals_cell);
- new_code_map->set(entry + kOsrAstIdOffset, Smi::FromInt(osr_ast_id.ToInt()));
#ifdef DEBUG
for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
@@ -12383,9 +11971,6 @@ void SharedFunctionInfo::AddToOptimizedCodeMap(
DCHECK(cell->cleared() ||
(cell->value()->IsCode() &&
Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION));
- cell = WeakCell::cast(new_code_map->get(i + kLiteralsOffset));
- DCHECK(cell->cleared() || cell->value()->IsFixedArray());
- DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi());
}
#endif
@@ -12405,81 +11990,62 @@ void SharedFunctionInfo::ClearOptimizedCodeMap() {
void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
const char* reason) {
DisallowHeapAllocation no_gc;
- if (OptimizedCodeMapIsCleared()) return;
+ Isolate* isolate = GetIsolate();
+ bool found = false;
- Heap* heap = GetHeap();
- FixedArray* code_map = optimized_code_map();
- int dst = kEntriesStart;
- int length = code_map->length();
- for (int src = kEntriesStart; src < length; src += kEntryLength) {
- DCHECK(WeakCell::cast(code_map->get(src))->cleared() ||
- WeakCell::cast(code_map->get(src))->value()->IsNativeContext());
- if (WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() ==
- optimized_code) {
- BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value());
- if (FLAG_trace_opt) {
- PrintF("[evicting entry from optimizing code map (%s) for ", reason);
- ShortPrint();
- if (osr.IsNone()) {
+ if (!OptimizedCodeMapIsCleared()) {
+ Heap* heap = isolate->heap();
+ FixedArray* code_map = optimized_code_map();
+ int length = code_map->length();
+ for (int src = kEntriesStart; src < length; src += kEntryLength) {
+ DCHECK(WeakCell::cast(code_map->get(src))->cleared() ||
+ WeakCell::cast(code_map->get(src))->value()->IsNativeContext());
+ found = WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() ==
+ optimized_code;
+ if (found) {
+ if (FLAG_trace_opt) {
+ PrintF("[evicting entry from optimizing code map (%s) for ", reason);
+ ShortPrint();
PrintF("]\n");
- } else {
- PrintF(" (osr ast id %d)]\n", osr.ToInt());
}
+ // Just clear the code.
+ code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(),
+ SKIP_WRITE_BARRIER);
}
- if (!osr.IsNone()) {
- // Evict the src entry by not copying it to the dst entry.
- continue;
- }
- // In case of non-OSR entry just clear the code in order to proceed
- // sharing literals.
- code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(),
- SKIP_WRITE_BARRIER);
- }
-
- // Keep the src entry by copying it to the dst entry.
- if (dst != src) {
- code_map->set(dst + kContextOffset, code_map->get(src + kContextOffset));
- code_map->set(dst + kCachedCodeOffset,
- code_map->get(src + kCachedCodeOffset));
- code_map->set(dst + kLiteralsOffset,
- code_map->get(src + kLiteralsOffset));
- code_map->set(dst + kOsrAstIdOffset,
- code_map->get(src + kOsrAstIdOffset));
- }
- dst += kEntryLength;
- }
- if (dst != length) {
- // Always trim even when array is cleared because of heap verifier.
- heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(code_map,
- length - dst);
- if (code_map->length() == kEntriesStart) {
- ClearOptimizedCodeMap();
}
}
-}
-
-void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
- FixedArray* code_map = optimized_code_map();
- DCHECK(shrink_by % kEntryLength == 0);
- DCHECK(shrink_by <= code_map->length() - kEntriesStart);
- // Always trim even when array is cleared because of heap verifier.
- GetHeap()->RightTrimFixedArray<Heap::SEQUENTIAL_TO_SWEEPER>(code_map,
- shrink_by);
- if (code_map->length() == kEntriesStart) {
- ClearOptimizedCodeMap();
+ if (!found) {
+ // We didn't find the code in here. It must be osr'd code.
+ isolate->EvictOSROptimizedCode(optimized_code, reason);
}
}
// static
void JSFunction::EnsureLiterals(Handle<JSFunction> function) {
Handle<SharedFunctionInfo> shared(function->shared());
- Handle<Context> native_context(function->context()->native_context());
- if (function->literals() ==
- function->GetIsolate()->heap()->empty_literals_array()) {
- Handle<LiteralsArray> literals =
- SharedFunctionInfo::FindOrCreateLiterals(shared, native_context);
- function->set_literals(*literals);
+ Isolate* isolate = shared->GetIsolate();
+
+ FeedbackVectorState state = function->GetFeedbackVectorState(isolate);
+ switch (state) {
+ case TOP_LEVEL_SCRIPT_NEEDS_VECTOR: {
+ // A top level script didn't get it's literals installed.
+ Handle<FeedbackVector> feedback_vector =
+ FeedbackVector::New(isolate, shared);
+ Handle<Cell> new_cell =
+ isolate->factory()->NewOneClosureCell(feedback_vector);
+ function->set_feedback_vector_cell(*new_cell);
+ break;
+ }
+ case NEEDS_VECTOR: {
+ Handle<FeedbackVector> feedback_vector =
+ FeedbackVector::New(isolate, shared);
+ function->feedback_vector_cell()->set_value(*feedback_vector);
+ break;
+ }
+ case HAS_VECTOR:
+ // Nothing to do.
+ break;
}
}
@@ -12524,19 +12090,10 @@ void Map::CompleteInobjectSlackTracking() {
static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
DisallowHeapAllocation no_gc;
if (!object->HasFastProperties()) return false;
- Map* map = object->map();
- if (map->is_prototype_map()) return false;
- DescriptorArray* descriptors = map->instance_descriptors();
- for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
- PropertyDetails details = descriptors->GetDetails(i);
- if (details.location() == kDescriptor) continue;
- if (details.representation().IsHeapObject() ||
- details.representation().IsTagged()) {
- FieldIndex index = FieldIndex::ForDescriptor(map, i);
- if (object->RawFastPropertyAt(index)->IsJSFunction()) return true;
- }
- }
- return false;
+ if (object->IsJSGlobalProxy()) return false;
+ if (object->GetIsolate()->bootstrapper()->IsActive()) return false;
+ return !object->map()->is_prototype_map() ||
+ !object->map()->should_be_fast_prototype_map();
}
// static
@@ -12551,8 +12108,10 @@ void JSObject::MakePrototypesFast(Handle<Object> receiver,
if (!current->IsJSObject()) return;
Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
Map* current_map = current_obj->map();
- if (current_map->is_prototype_map() &&
- !current_map->should_be_fast_prototype_map()) {
+ if (current_map->is_prototype_map()) {
+ // If the map is already marked as should be fast, we're done. Its
+ // prototypes will have been marked already as well.
+ if (current_map->should_be_fast_prototype_map()) return;
Handle<Map> map(current_map);
Map::SetShouldBeFastPrototypeMap(map, true, isolate);
JSObject::OptimizeAsPrototype(current_obj, FAST_PROTOTYPE);
@@ -12758,9 +12317,17 @@ void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
// static
Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
Isolate* isolate) {
- Handle<Object> maybe_prototype(
- map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
- if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null();
+ Handle<Object> maybe_prototype;
+ if (map->IsJSGlobalObjectMap()) {
+ DCHECK(map->is_prototype_map());
+ // Global object is prototype of a global proxy and therefore we can
+ // use its validity cell for guarding global object's prototype change.
+ maybe_prototype = isolate->global_object();
+ } else {
+ maybe_prototype =
+ handle(map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
+ if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null();
+ }
Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
// Ensure the prototype is registered with its own prototypes so its cell
// will be invalidated when necessary.
@@ -12997,6 +12564,7 @@ bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
case JS_API_OBJECT_TYPE:
case JS_ARRAY_BUFFER_TYPE:
case JS_ARRAY_TYPE:
+ case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_DATA_VIEW_TYPE:
case JS_DATE_TYPE:
@@ -13038,7 +12606,6 @@ bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
case ODDBALL_TYPE:
case PROPERTY_CELL_TYPE:
case SHARED_FUNCTION_INFO_TYPE:
- case SIMD128_VALUE_TYPE:
case SYMBOL_TYPE:
case WEAK_CELL_TYPE:
@@ -13131,7 +12698,7 @@ MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
// Link initial map and constructor function if the new.target is actually a
// subclass constructor.
- if (IsSubclassConstructor(function->shared()->kind())) {
+ if (IsDerivedConstructor(function->shared()->kind())) {
Handle<Object> prototype(function->instance_prototype(), isolate);
InstanceType instance_type = constructor_initial_map->instance_type();
DCHECK(CanSubclassHaveInobjectProperties(instance_type));
@@ -13281,8 +12848,7 @@ Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
// Check if {function} should hide its source code.
- if (!shared_info->script()->IsScript() ||
- Script::cast(shared_info->script())->hide_source()) {
+ if (!shared_info->IsUserJavaScript()) {
return NativeCodeFunctionSourceString(shared_info);
}
@@ -13304,6 +12870,10 @@ Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
return NativeCodeFunctionSourceString(shared_info);
}
+ if (FLAG_harmony_function_tostring) {
+ return Handle<String>::cast(shared_info->GetSourceCodeHarmony());
+ }
+
IncrementalStringBuilder builder(isolate);
FunctionKind kind = shared_info->kind();
if (!IsArrowFunction(kind)) {
@@ -13355,8 +12925,8 @@ void Script::SetEvalOrigin(Handle<Script> script,
// 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());
+ FrameSummary summary = FrameSummary::GetTop(it.javascript_frame());
+ script->set_eval_from_shared(summary.AsJavaScript().function()->shared());
script->set_eval_from_position(-summary.code_offset());
return;
}
@@ -13409,15 +12979,7 @@ bool Script::GetPositionInfo(Handle<Script> script, int position,
PositionInfo* info, OffsetFlag offset_flag) {
// For wasm, we do not create an artificial line_ends array, but do the
// translation directly.
- if (script->type() == Script::TYPE_WASM) {
- Handle<WasmCompiledModule> compiled_module(
- WasmCompiledModule::cast(script->wasm_compiled_module()));
- DCHECK_LE(0, position);
- return wasm::GetPositionInfo(compiled_module,
- static_cast<uint32_t>(position), info);
- }
-
- InitLineEnds(script);
+ if (script->type() != Script::TYPE_WASM) InitLineEnds(script);
return script->GetPositionInfo(position, info, offset_flag);
}
@@ -13453,6 +13015,16 @@ bool Script::GetPositionInfo(int position, PositionInfo* info,
OffsetFlag offset_flag) const {
DisallowHeapAllocation no_allocation;
+ // For wasm, we do not rely on the line_ends array, but do the translation
+ // directly.
+ if (type() == Script::TYPE_WASM) {
+ Handle<WasmCompiledModule> compiled_module(
+ WasmCompiledModule::cast(wasm_compiled_module()));
+ DCHECK_LE(0, position);
+ return compiled_module->GetPositionInfo(static_cast<uint32_t>(position),
+ info);
+ }
+
if (line_ends()->IsUndefined(GetIsolate())) {
// Slow mode: we do not have line_ends. We have to iterate through source.
if (!GetPositionInfoSlow(this, position, info)) return false;
@@ -13546,15 +13118,11 @@ int Script::GetLineNumber(int code_pos) const {
return info.line;
}
-Handle<Object> Script::GetNameOrSourceURL(Handle<Script> script) {
- Isolate* isolate = script->GetIsolate();
-
+Object* Script::GetNameOrSourceURL() {
+ Isolate* isolate = GetIsolate();
// Keep in sync with ScriptNameOrSourceURL in messages.js.
-
- if (!script->source_url()->IsUndefined(isolate)) {
- return handle(script->source_url(), isolate);
- }
- return handle(script->name(), isolate);
+ if (!source_url()->IsUndefined(isolate)) return source_url();
+ return name();
}
@@ -13583,53 +13151,68 @@ Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
return result;
}
-
MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
- FunctionLiteral* fun) {
- WeakFixedArray::Iterator iterator(shared_function_infos());
- SharedFunctionInfo* shared;
- while ((shared = iterator.Next<SharedFunctionInfo>())) {
- if (fun->function_token_position() == shared->function_token_position() &&
- fun->start_position() == shared->start_position() &&
- fun->end_position() == shared->end_position()) {
- return Handle<SharedFunctionInfo>(shared);
- }
+ Isolate* isolate, const FunctionLiteral* fun) {
+ DCHECK_NE(fun->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
+ DCHECK_LT(fun->function_literal_id(), shared_function_infos()->length());
+ Object* shared = shared_function_infos()->get(fun->function_literal_id());
+ if (shared->IsUndefined(isolate) || WeakCell::cast(shared)->cleared()) {
+ return MaybeHandle<SharedFunctionInfo>();
}
- return MaybeHandle<SharedFunctionInfo>();
+ return handle(SharedFunctionInfo::cast(WeakCell::cast(shared)->value()));
}
-
Script::Iterator::Iterator(Isolate* isolate)
: iterator_(isolate->heap()->script_list()) {}
Script* Script::Iterator::Next() { return iterator_.Next<Script>(); }
+SharedFunctionInfo::ScriptIterator::ScriptIterator(Handle<Script> script)
+ : ScriptIterator(script->GetIsolate(),
+ handle(script->shared_function_infos())) {}
-SharedFunctionInfo::Iterator::Iterator(Isolate* isolate)
- : script_iterator_(isolate),
- sfi_iterator_(isolate->heap()->noscript_shared_function_infos()) {}
+SharedFunctionInfo::ScriptIterator::ScriptIterator(
+ Isolate* isolate, Handle<FixedArray> shared_function_infos)
+ : isolate_(isolate),
+ shared_function_infos_(shared_function_infos),
+ index_(0) {}
+SharedFunctionInfo* SharedFunctionInfo::ScriptIterator::Next() {
+ while (index_ < shared_function_infos_->length()) {
+ Object* raw = shared_function_infos_->get(index_++);
+ if (raw->IsUndefined(isolate_) || WeakCell::cast(raw)->cleared()) continue;
+ return SharedFunctionInfo::cast(WeakCell::cast(raw)->value());
+ }
+ return nullptr;
+}
-bool SharedFunctionInfo::Iterator::NextScript() {
- Script* script = script_iterator_.Next();
- if (script == NULL) return false;
- sfi_iterator_.Reset(script->shared_function_infos());
- return true;
+void SharedFunctionInfo::ScriptIterator::Reset(Handle<Script> script) {
+ shared_function_infos_ = handle(script->shared_function_infos());
+ index_ = 0;
}
+SharedFunctionInfo::GlobalIterator::GlobalIterator(Isolate* isolate)
+ : script_iterator_(isolate),
+ noscript_sfi_iterator_(isolate->heap()->noscript_shared_function_infos()),
+ sfi_iterator_(handle(script_iterator_.Next(), isolate)) {}
-SharedFunctionInfo* SharedFunctionInfo::Iterator::Next() {
- do {
- SharedFunctionInfo* next = sfi_iterator_.Next<SharedFunctionInfo>();
- if (next != NULL) return next;
- } while (NextScript());
- return NULL;
+SharedFunctionInfo* SharedFunctionInfo::GlobalIterator::Next() {
+ SharedFunctionInfo* next = noscript_sfi_iterator_.Next<SharedFunctionInfo>();
+ if (next != nullptr) return next;
+ for (;;) {
+ next = sfi_iterator_.Next();
+ if (next != nullptr) return next;
+ Script* next_script = script_iterator_.Next();
+ if (next_script == nullptr) return nullptr;
+ sfi_iterator_.Reset(handle(next_script));
+ }
}
void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
Handle<Object> script_object) {
+ DCHECK_NE(shared->function_literal_id(), FunctionLiteral::kIdTypeInvalid);
if (shared->script() == *script_object) return;
Isolate* isolate = shared->GetIsolate();
@@ -13637,39 +13220,52 @@ void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
// the shared function info may be temporarily in two lists.
// This is okay because the gc-time processing of these lists can tolerate
// duplicates.
- Handle<Object> list;
if (script_object->IsScript()) {
Handle<Script> script = Handle<Script>::cast(script_object);
- list = handle(script->shared_function_infos(), isolate);
+ Handle<FixedArray> list = handle(script->shared_function_infos(), isolate);
+#ifdef DEBUG
+ DCHECK_LT(shared->function_literal_id(), list->length());
+ if (list->get(shared->function_literal_id())->IsWeakCell() &&
+ !WeakCell::cast(list->get(shared->function_literal_id()))->cleared()) {
+ DCHECK(
+ WeakCell::cast(list->get(shared->function_literal_id()))->value() ==
+ *shared);
+ }
+#endif
+ Handle<WeakCell> cell = isolate->factory()->NewWeakCell(shared);
+ list->set(shared->function_literal_id(), *cell);
} else {
- list = isolate->factory()->noscript_shared_function_infos();
- }
+ Handle<Object> list = isolate->factory()->noscript_shared_function_infos();
#ifdef DEBUG
- if (FLAG_enable_slow_asserts) {
- WeakFixedArray::Iterator iterator(*list);
- SharedFunctionInfo* next;
- while ((next = iterator.Next<SharedFunctionInfo>())) {
- DCHECK_NE(next, *shared);
+ if (FLAG_enable_slow_asserts) {
+ WeakFixedArray::Iterator iterator(*list);
+ SharedFunctionInfo* next;
+ while ((next = iterator.Next<SharedFunctionInfo>())) {
+ DCHECK_NE(next, *shared);
+ }
}
- }
#endif // DEBUG
- list = WeakFixedArray::Add(list, shared);
- if (script_object->IsScript()) {
- Handle<Script> script = Handle<Script>::cast(script_object);
- script->set_shared_function_infos(*list);
- } else {
+ list = WeakFixedArray::Add(list, shared);
+
isolate->heap()->SetRootNoScriptSharedFunctionInfos(*list);
}
- // Remove shared function info from old script's list.
if (shared->script()->IsScript()) {
+ // Remove shared function info from old script's list.
Script* old_script = Script::cast(shared->script());
- if (old_script->shared_function_infos()->IsWeakFixedArray()) {
- WeakFixedArray* list =
- WeakFixedArray::cast(old_script->shared_function_infos());
- list->Remove(shared);
+
+ // Due to liveedit, it might happen that the old_script doesn't know
+ // about the SharedFunctionInfo, so we have to guard against that.
+ Handle<FixedArray> infos(old_script->shared_function_infos(), isolate);
+ if (shared->function_literal_id() < infos->length()) {
+ Object* raw = old_script->shared_function_infos()->get(
+ shared->function_literal_id());
+ if (!raw->IsWeakCell() || WeakCell::cast(raw)->value() == *shared) {
+ old_script->shared_function_infos()->set(
+ shared->function_literal_id(), isolate->heap()->undefined_value());
+ }
}
} else {
// Remove shared function info from root array.
@@ -13688,6 +13284,16 @@ String* SharedFunctionInfo::DebugName() {
return String::cast(n);
}
+bool SharedFunctionInfo::HasNoSideEffect() {
+ if (!computed_has_no_side_effect()) {
+ DisallowHeapAllocation not_handlified;
+ Handle<SharedFunctionInfo> info(this);
+ set_has_no_side_effect(DebugEvaluate::FunctionHasNoSideEffect(info));
+ set_computed_has_no_side_effect(true);
+ }
+ return has_no_side_effect();
+}
+
// The filter is a pattern that matches function names in this way:
// "*" all; the default
// "-" all but the top-level function
@@ -13738,6 +13344,15 @@ Handle<Object> SharedFunctionInfo::GetSourceCode() {
source, start_position(), end_position());
}
+Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony() {
+ Isolate* isolate = GetIsolate();
+ if (!HasSourceCode()) return isolate->factory()->undefined_value();
+ Handle<String> script_source(String::cast(Script::cast(script())->source()));
+ int start_pos = function_token_position();
+ if (start_pos == kNoSourcePosition) start_pos = start_position();
+ return isolate->factory()->NewSubString(script_source, start_pos,
+ end_position());
+}
bool SharedFunctionInfo::IsInlineable() {
// Check that the function has a script associated with it.
@@ -13790,7 +13405,7 @@ void JSFunction::CalculateInstanceSizeForDerivedClass(
JSFunction* func = JSFunction::cast(current);
SharedFunctionInfo* shared = func->shared();
expected_nof_properties += shared->expected_nof_properties();
- if (!IsSubclassConstructor(shared->kind())) {
+ if (!IsDerivedConstructor(shared->kind())) {
break;
}
}
@@ -13933,8 +13548,6 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
shared_info->set_language_mode(lit->language_mode());
shared_info->set_uses_arguments(lit->scope()->arguments() != NULL);
shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
- shared_info->set_is_function(lit->is_function());
- shared_info->set_never_compiled(true);
shared_info->set_kind(lit->kind());
if (!IsConstructable(lit->kind(), lit->language_mode())) {
shared_info->SetConstructStub(
@@ -13942,9 +13555,7 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
}
shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
shared_info->set_asm_function(lit->scope()->asm_function());
- shared_info->set_requires_class_field_init(lit->requires_class_field_init());
- shared_info->set_is_class_field_initializer(
- lit->is_class_field_initializer());
+ shared_info->set_function_literal_id(lit->function_literal_id());
SetExpectedNofPropertiesFromEstimate(shared_info, lit);
}
@@ -13999,19 +13610,15 @@ void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
}
}
-
-int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context,
- BailoutId osr_ast_id) {
+int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context) {
DisallowHeapAllocation no_gc;
DCHECK(native_context->IsNativeContext());
if (!OptimizedCodeMapIsCleared()) {
FixedArray* optimized_code_map = this->optimized_code_map();
int length = optimized_code_map->length();
- Smi* osr_ast_id_smi = Smi::FromInt(osr_ast_id.ToInt());
for (int i = kEntriesStart; i < length; i += kEntryLength) {
if (WeakCell::cast(optimized_code_map->get(i + kContextOffset))
- ->value() == native_context &&
- optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) {
+ ->value() == native_context) {
return i;
}
}
@@ -14031,20 +13638,20 @@ void SharedFunctionInfo::ClearCodeFromOptimizedCodeMap() {
}
}
-CodeAndLiterals SharedFunctionInfo::SearchOptimizedCodeMap(
- Context* native_context, BailoutId osr_ast_id) {
- CodeAndLiterals result = {nullptr, nullptr};
- int entry = SearchOptimizedCodeMapEntry(native_context, osr_ast_id);
+Code* SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context,
+ BailoutId osr_ast_id) {
+ Code* result = nullptr;
+ if (!osr_ast_id.IsNone()) {
+ return native_context->SearchOptimizedCodeMap(this, osr_ast_id);
+ }
+
+ DCHECK(osr_ast_id.IsNone());
+ int entry = SearchOptimizedCodeMapEntry(native_context);
if (entry != kNotFound) {
FixedArray* code_map = optimized_code_map();
DCHECK_LE(entry + kEntryLength, code_map->length());
WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset));
- WeakCell* literals_cell =
- WeakCell::cast(code_map->get(entry + kLiteralsOffset));
-
- result = {cell->cleared() ? nullptr : Code::cast(cell->value()),
- literals_cell->cleared() ? nullptr : LiteralsArray::cast(
- literals_cell->value())};
+ result = cell->cleared() ? nullptr : Code::cast(cell->value());
}
return result;
}
@@ -14289,7 +13896,8 @@ void Code::ClearInlineCaches() {
RelocInfo* info = it.rinfo();
Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
if (target->is_inline_cache_stub()) {
- IC::Clear(this->GetIsolate(), info->pc(), info->host()->constant_pool());
+ ICUtility::Clear(this->GetIsolate(), info->pc(),
+ info->host()->constant_pool());
}
}
}
@@ -14324,11 +13932,10 @@ int AbstractCode::SourceStatementPosition(int offset) {
}
void JSFunction::ClearTypeFeedbackInfo() {
- feedback_vector()->ClearSlots(shared());
-}
-
-void JSFunction::ClearTypeFeedbackInfoAtGCTime() {
- feedback_vector()->ClearSlotsAtGCTime(shared());
+ if (feedback_vector_cell()->value()->IsFeedbackVector()) {
+ FeedbackVector* vector = feedback_vector();
+ vector->ClearSlots(this);
+ }
}
BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
@@ -14353,21 +13960,13 @@ uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) {
return 0;
}
-int Code::LookupRangeInHandlerTable(int code_offset, int* data,
- HandlerTable::CatchPrediction* prediction) {
- DCHECK(!is_optimized_code());
- HandlerTable* table = HandlerTable::cast(handler_table());
- return table->LookupRange(code_offset, data, prediction);
-}
-
void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
- PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge, NO_MARKING_PARITY);
+ PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge);
}
void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
- PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge,
- NO_MARKING_PARITY);
+ PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge);
}
@@ -14401,28 +14000,25 @@ void Code::MakeYoung(Isolate* isolate) {
void Code::PreAge(Isolate* isolate) {
byte* sequence = FindCodeAgeSequence();
if (sequence != NULL) {
- PatchPlatformCodeAge(isolate, sequence, kPreAgedCodeAge, NO_MARKING_PARITY);
+ PatchPlatformCodeAge(isolate, sequence, kPreAgedCodeAge);
}
}
void Code::MarkToBeExecutedOnce(Isolate* isolate) {
byte* sequence = FindCodeAgeSequence();
if (sequence != NULL) {
- PatchPlatformCodeAge(isolate, sequence, kToBeExecutedOnceCodeAge,
- NO_MARKING_PARITY);
+ PatchPlatformCodeAge(isolate, sequence, kToBeExecutedOnceCodeAge);
}
}
-void Code::MakeOlder(MarkingParity current_parity) {
+void Code::MakeOlder() {
byte* sequence = FindCodeAgeSequence();
if (sequence != NULL) {
- Age age;
- MarkingParity code_parity;
Isolate* isolate = GetIsolate();
- GetCodeAgeAndParity(isolate, sequence, &age, &code_parity);
+ Age age = GetCodeAge(isolate, sequence);
Age next_age = NextAge(age);
- if (age != next_age && code_parity != current_parity) {
- PatchPlatformCodeAge(isolate, sequence, next_age, current_parity);
+ if (age != next_age) {
+ PatchPlatformCodeAge(isolate, sequence, next_age);
}
}
}
@@ -14448,77 +14044,47 @@ Code::Age Code::GetAge() {
if (sequence == NULL) {
return kNoAgeCodeAge;
}
- Age age;
- MarkingParity parity;
- GetCodeAgeAndParity(GetIsolate(), sequence, &age, &parity);
- return age;
+ return GetCodeAge(GetIsolate(), sequence);
}
-
-void Code::GetCodeAgeAndParity(Code* code, Age* age,
- MarkingParity* parity) {
+Code::Age Code::GetAgeOfCodeAgeStub(Code* code) {
Isolate* isolate = code->GetIsolate();
Builtins* builtins = isolate->builtins();
- Code* stub = NULL;
-#define HANDLE_CODE_AGE(AGE) \
- stub = *builtins->Make##AGE##CodeYoungAgainEvenMarking(); \
- if (code == stub) { \
- *age = k##AGE##CodeAge; \
- *parity = EVEN_MARKING_PARITY; \
- return; \
- } \
- stub = *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
- if (code == stub) { \
- *age = k##AGE##CodeAge; \
- *parity = ODD_MARKING_PARITY; \
- return; \
+#define HANDLE_CODE_AGE(AGE) \
+ if (code == *builtins->Make##AGE##CodeYoungAgain()) { \
+ return k##AGE##CodeAge; \
}
CODE_AGE_LIST(HANDLE_CODE_AGE)
#undef HANDLE_CODE_AGE
- stub = *builtins->MarkCodeAsExecutedOnce();
- if (code == stub) {
- *age = kNotExecutedCodeAge;
- *parity = NO_MARKING_PARITY;
- return;
+ if (code == *builtins->MarkCodeAsExecutedOnce()) {
+ return kNotExecutedCodeAge;
}
- stub = *builtins->MarkCodeAsExecutedTwice();
- if (code == stub) {
- *age = kExecutedOnceCodeAge;
- *parity = NO_MARKING_PARITY;
- return;
+ if (code == *builtins->MarkCodeAsExecutedTwice()) {
+ return kExecutedOnceCodeAge;
}
- stub = *builtins->MarkCodeAsToBeExecutedOnce();
- if (code == stub) {
- *age = kToBeExecutedOnceCodeAge;
- *parity = NO_MARKING_PARITY;
- return;
+ if (code == *builtins->MarkCodeAsToBeExecutedOnce()) {
+ return kToBeExecutedOnceCodeAge;
}
UNREACHABLE();
+ return kNoAgeCodeAge;
}
-
-Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
+Code* Code::GetCodeAgeStub(Isolate* isolate, Age age) {
Builtins* builtins = isolate->builtins();
switch (age) {
-#define HANDLE_CODE_AGE(AGE) \
- case k##AGE##CodeAge: { \
- Code* stub = parity == EVEN_MARKING_PARITY \
- ? *builtins->Make##AGE##CodeYoungAgainEvenMarking() \
- : *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
- return stub; \
- }
+#define HANDLE_CODE_AGE(AGE) \
+ case k##AGE##CodeAge: { \
+ return *builtins->Make##AGE##CodeYoungAgain(); \
+ }
CODE_AGE_LIST(HANDLE_CODE_AGE)
#undef HANDLE_CODE_AGE
case kNotExecutedCodeAge: {
- DCHECK(parity == NO_MARKING_PARITY);
return *builtins->MarkCodeAsExecutedOnce();
}
case kExecutedOnceCodeAge: {
- DCHECK(parity == NO_MARKING_PARITY);
return *builtins->MarkCodeAsExecutedTwice();
}
case kToBeExecutedOnceCodeAge: {
- DCHECK(parity == NO_MARKING_PARITY);
return *builtins->MarkCodeAsToBeExecutedOnce();
}
default:
@@ -14712,14 +14278,24 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(
break;
}
+ case Translation::CONSTRUCT_STUB_FRAME: {
+ int bailout_id = iterator.Next();
+ int shared_info_id = iterator.Next();
+ Object* shared_info = LiteralArray()->get(shared_info_id);
+ unsigned height = iterator.Next();
+ os << "{bailout_id=" << bailout_id << ", function="
+ << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
+ << ", height=" << height << "}";
+ break;
+ }
+
case Translation::COMPILED_STUB_FRAME: {
Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
os << "{kind=" << stub_kind << "}";
break;
}
- case Translation::ARGUMENTS_ADAPTOR_FRAME:
- case Translation::CONSTRUCT_STUB_FRAME: {
+ case Translation::ARGUMENTS_ADAPTOR_FRAME: {
int shared_info_id = iterator.Next();
Object* shared_info = LiteralArray()->get(shared_info_id);
unsigned height = iterator.Next();
@@ -14906,8 +14482,8 @@ void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
if (!IC::ICUseVector(kind())) {
InlineCacheState ic_state = IC::StateFromCode(this);
os << "ic_state = " << ICState2String(ic_state) << "\n";
+ PrintExtraICState(os, kind(), extra_ic_state());
}
- PrintExtraICState(os, kind(), extra_ic_state());
if (is_compare_ic_stub()) {
DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC);
CompareICStub stub(stub_key(), GetIsolate());
@@ -15122,11 +14698,17 @@ void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) {
from->length());
}
-int BytecodeArray::LookupRangeInHandlerTable(
- int code_offset, int* data, HandlerTable::CatchPrediction* prediction) {
- HandlerTable* table = HandlerTable::cast(handler_table());
- code_offset++; // Point after current bytecode.
- return table->LookupRange(code_offset, data, prediction);
+void BytecodeArray::MakeOlder() {
+ Age age = bytecode_age();
+ if (age < kLastBytecodeAge) {
+ set_bytecode_age(static_cast<Age>(age + 1));
+ }
+ DCHECK_GE(bytecode_age(), kFirstBytecodeAge);
+ DCHECK_LE(bytecode_age(), kLastBytecodeAge);
+}
+
+bool BytecodeArray::IsOld() const {
+ return bytecode_age() >= kIsOldBytecodeAge;
}
// static
@@ -15565,9 +15147,6 @@ Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
// SpiderMonkey behaves this way.
if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true);
- bool dictionary_elements_in_chain =
- object->map()->DictionaryElementsInPrototypeChainOnly();
-
bool all_extensible = object->map()->is_extensible();
Handle<JSObject> real_receiver = object;
if (from_javascript) {
@@ -15633,14 +15212,6 @@ Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
DCHECK(new_map->prototype() == *value);
JSObject::MigrateToMap(real_receiver, new_map);
- if (from_javascript && !dictionary_elements_in_chain &&
- new_map->DictionaryElementsInPrototypeChainOnly()) {
- // If the prototype chain didn't previously have element callbacks, then
- // KeyedStoreICs need to be cleared to ensure any that involve this
- // map go generic.
- TypeFeedbackVector::ClearAllKeyedStoreICs(isolate);
- }
-
heap->ClearInstanceofCache();
DCHECK(size == object->Size());
return Just(true);
@@ -15837,12 +15408,10 @@ Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
ElementsAccessor* accessor = ElementsAccessor::ForKind(to);
accessor->Add(object, index, value, attributes, new_capacity);
- uint32_t new_length = old_length;
- Handle<Object> new_length_handle;
if (object->IsJSArray() && index >= old_length) {
- new_length = index + 1;
- new_length_handle = isolate->factory()->NewNumberFromUint(new_length);
- JSArray::cast(*object)->set_length(*new_length_handle);
+ Handle<Object> new_length =
+ isolate->factory()->NewNumberFromUint(index + 1);
+ JSArray::cast(*object)->set_length(*new_length);
}
return Just(true);
@@ -16147,7 +15716,8 @@ void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT
} else {
os << Brief(k);
}
- os << ": " << Brief(this->ValueAt(i)) << " " << this->DetailsAt(i);
+ os << ": " << Brief(this->ValueAt(i)) << " ";
+ this->DetailsAt(i).PrintAsSlowTo(os);
}
}
}
@@ -16213,118 +15783,6 @@ int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) {
ElementsKindToShiftSize(kind));
}
-void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
- Object* temp = get(i);
- set(i, get(j));
- set(j, temp);
- if (this != numbers) {
- temp = numbers->get(i);
- numbers->set(i, Smi::cast(numbers->get(j)));
- numbers->set(j, Smi::cast(temp));
- }
-}
-
-
-static void InsertionSortPairs(FixedArray* content,
- FixedArray* numbers,
- int len) {
- for (int i = 1; i < len; i++) {
- int j = i;
- while (j > 0 &&
- (NumberToUint32(numbers->get(j - 1)) >
- NumberToUint32(numbers->get(j)))) {
- content->SwapPairs(numbers, j - 1, j);
- j--;
- }
- }
-}
-
-
-void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
- // In-place heap sort.
- DCHECK(content->length() == numbers->length());
-
- // Bottom-up max-heap construction.
- for (int i = 1; i < len; ++i) {
- int child_index = i;
- while (child_index > 0) {
- int parent_index = ((child_index + 1) >> 1) - 1;
- uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
- uint32_t child_value = NumberToUint32(numbers->get(child_index));
- if (parent_value < child_value) {
- content->SwapPairs(numbers, parent_index, child_index);
- } else {
- break;
- }
- child_index = parent_index;
- }
- }
-
- // Extract elements and create sorted array.
- for (int i = len - 1; i > 0; --i) {
- // Put max element at the back of the array.
- content->SwapPairs(numbers, 0, i);
- // Sift down the new top element.
- int parent_index = 0;
- while (true) {
- int child_index = ((parent_index + 1) << 1) - 1;
- if (child_index >= i) break;
- uint32_t child1_value = NumberToUint32(numbers->get(child_index));
- uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
- uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
- if (child_index + 1 >= i || child1_value > child2_value) {
- if (parent_value > child1_value) break;
- content->SwapPairs(numbers, parent_index, child_index);
- parent_index = child_index;
- } else {
- if (parent_value > child2_value) break;
- content->SwapPairs(numbers, parent_index, child_index + 1);
- parent_index = child_index + 1;
- }
- }
- }
-}
-
-
-// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
-void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
- DCHECK(this->length() == numbers->length());
- // For small arrays, simply use insertion sort.
- if (len <= 10) {
- InsertionSortPairs(this, numbers, len);
- return;
- }
- // Check the range of indices.
- uint32_t min_index = NumberToUint32(numbers->get(0));
- uint32_t max_index = min_index;
- uint32_t i;
- for (i = 1; i < len; i++) {
- if (NumberToUint32(numbers->get(i)) < min_index) {
- min_index = NumberToUint32(numbers->get(i));
- } else if (NumberToUint32(numbers->get(i)) > max_index) {
- max_index = NumberToUint32(numbers->get(i));
- }
- }
- if (max_index - min_index + 1 == len) {
- // Indices form a contiguous range, unless there are duplicates.
- // Do an in-place linear time sort assuming distinct numbers, but
- // avoid hanging in case they are not.
- for (i = 0; i < len; i++) {
- uint32_t p;
- uint32_t j = 0;
- // While the current element at i is not at its correct position p,
- // swap the elements at these two positions.
- while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
- j++ < len) {
- SwapPairs(numbers, i, p);
- }
- }
- } else {
- HeapSortPairs(this, numbers, len);
- return;
- }
-}
-
bool JSObject::WasConstructedFromApiFunction() {
auto instance_type = map()->instance_type();
bool is_api_object = instance_type == JS_API_OBJECT_TYPE ||
@@ -16344,94 +15802,6 @@ bool JSObject::WasConstructedFromApiFunction() {
return is_api_object;
}
-MaybeHandle<String> Object::ObjectProtoToString(Isolate* isolate,
- Handle<Object> object) {
- if (*object == isolate->heap()->undefined_value()) {
- return isolate->factory()->undefined_to_string();
- }
- if (*object == isolate->heap()->null_value()) {
- return isolate->factory()->null_to_string();
- }
-
- Handle<JSReceiver> receiver =
- Object::ToObject(isolate, object).ToHandleChecked();
-
- // For proxies, we must check IsArray() before get(toStringTag) to comply
- // with the specification
- Maybe<bool> is_array = Nothing<bool>();
- InstanceType instance_type = receiver->map()->instance_type();
- if (instance_type == JS_PROXY_TYPE) {
- is_array = Object::IsArray(receiver);
- MAYBE_RETURN(is_array, MaybeHandle<String>());
- }
-
- Handle<String> tag;
- Handle<Object> to_string_tag;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, to_string_tag,
- JSReceiver::GetProperty(receiver,
- isolate->factory()->to_string_tag_symbol()),
- String);
- if (to_string_tag->IsString()) {
- tag = Handle<String>::cast(to_string_tag);
- } else {
- switch (instance_type) {
- case JS_API_OBJECT_TYPE:
- case JS_SPECIAL_API_OBJECT_TYPE:
- tag = handle(receiver->class_name(), isolate);
- break;
- case JS_ARGUMENTS_TYPE:
- return isolate->factory()->arguments_to_string();
- case JS_ARRAY_TYPE:
- return isolate->factory()->array_to_string();
- case JS_BOUND_FUNCTION_TYPE:
- case JS_FUNCTION_TYPE:
- return isolate->factory()->function_to_string();
- case JS_ERROR_TYPE:
- return isolate->factory()->error_to_string();
- case JS_DATE_TYPE:
- return isolate->factory()->date_to_string();
- case JS_REGEXP_TYPE:
- return isolate->factory()->regexp_to_string();
- case JS_PROXY_TYPE: {
- if (is_array.FromJust()) {
- return isolate->factory()->array_to_string();
- }
- if (receiver->IsCallable()) {
- return isolate->factory()->function_to_string();
- }
- return isolate->factory()->object_to_string();
- }
- case JS_VALUE_TYPE: {
- Object* value = JSValue::cast(*receiver)->value();
- if (value->IsString()) {
- return isolate->factory()->string_to_string();
- }
- if (value->IsNumber()) {
- return isolate->factory()->number_to_string();
- }
- if (value->IsBoolean()) {
- return isolate->factory()->boolean_to_string();
- }
- if (value->IsSymbol()) {
- return isolate->factory()->object_to_string();
- }
- UNREACHABLE();
- tag = handle(receiver->class_name(), isolate);
- break;
- }
- default:
- return isolate->factory()->object_to_string();
- }
- }
-
- IncrementalStringBuilder builder(isolate);
- builder.AppendCString("[object ");
- builder.AppendString(tag);
- builder.AppendCharacter(']');
- return builder.Finish();
-}
-
const char* Symbol::PrivateSymbolToName() const {
Heap* heap = GetIsolate()->heap();
#define SYMBOL_CHECK_AND_PRINT(name) \
@@ -16460,12 +15830,22 @@ void Symbol::SymbolShortPrint(std::ostream& os) {
// StringSharedKeys are used as keys in the eval cache.
class StringSharedKey : public HashTableKey {
public:
+ // This tuple unambiguously identifies calls to eval() or
+ // CreateDynamicFunction() (such as through the Function() constructor).
+ // * source is the string passed into eval(). For dynamic functions, this is
+ // the effective source for the function, some of which is implicitly
+ // generated.
+ // * shared is the shared function info for the function containing the call
+ // to eval(). for dynamic functions, shared is the native context closure.
+ // * When positive, position is the position in the source where eval is
+ // called. When negative, position is the negation of the position in the
+ // dynamic function's effective source where the ')' ends the parameters.
StringSharedKey(Handle<String> source, Handle<SharedFunctionInfo> shared,
- LanguageMode language_mode, int scope_position)
+ LanguageMode language_mode, int position)
: source_(source),
shared_(shared),
language_mode_(language_mode),
- scope_position_(scope_position) {}
+ position_(position) {}
bool IsMatch(Object* other) override {
DisallowHeapAllocation no_allocation;
@@ -16481,8 +15861,8 @@ class StringSharedKey : public HashTableKey {
DCHECK(is_valid_language_mode(language_unchecked));
LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
if (language_mode != language_mode_) return false;
- int scope_position = Smi::cast(other_array->get(3))->value();
- if (scope_position != scope_position_) return false;
+ int position = Smi::cast(other_array->get(3))->value();
+ if (position != position_) return false;
String* source = String::cast(other_array->get(1));
return source->Equals(*source_);
}
@@ -16490,7 +15870,7 @@ class StringSharedKey : public HashTableKey {
static uint32_t StringSharedHashHelper(String* source,
SharedFunctionInfo* shared,
LanguageMode language_mode,
- int scope_position) {
+ int position) {
uint32_t hash = source->Hash();
if (shared->HasSourceCode()) {
// Instead of using the SharedFunctionInfo pointer in the hash
@@ -16502,14 +15882,14 @@ class StringSharedKey : public HashTableKey {
hash ^= String::cast(script->source())->Hash();
STATIC_ASSERT(LANGUAGE_END == 2);
if (is_strict(language_mode)) hash ^= 0x8000;
- hash += scope_position;
+ hash += position;
}
return hash;
}
uint32_t Hash() override {
return StringSharedHashHelper(*source_, *shared_, language_mode_,
- scope_position_);
+ position_);
}
uint32_t HashForObject(Object* obj) override {
@@ -16523,9 +15903,8 @@ class StringSharedKey : public HashTableKey {
int language_unchecked = Smi::cast(other_array->get(2))->value();
DCHECK(is_valid_language_mode(language_unchecked));
LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
- int scope_position = Smi::cast(other_array->get(3))->value();
- return StringSharedHashHelper(source, shared, language_mode,
- scope_position);
+ int position = Smi::cast(other_array->get(3))->value();
+ return StringSharedHashHelper(source, shared, language_mode, position);
}
@@ -16534,7 +15913,7 @@ class StringSharedKey : public HashTableKey {
array->set(0, *shared_);
array->set(1, *source_);
array->set(2, Smi::FromInt(language_mode_));
- array->set(3, Smi::FromInt(scope_position_));
+ array->set(3, Smi::FromInt(position_));
return array;
}
@@ -16542,9 +15921,22 @@ class StringSharedKey : public HashTableKey {
Handle<String> source_;
Handle<SharedFunctionInfo> shared_;
LanguageMode language_mode_;
- int scope_position_;
+ int position_;
};
+// static
+const char* JSPromise::Status(int status) {
+ switch (status) {
+ case v8::Promise::kFulfilled:
+ return "resolved";
+ case v8::Promise::kPending:
+ return "pending";
+ case v8::Promise::kRejected:
+ return "rejected";
+ }
+ UNREACHABLE();
+ return NULL;
+}
namespace {
@@ -16816,6 +16208,17 @@ class InternalizedStringKey : public HashTableKey {
DCHECK(string_->IsInternalizedString());
return string_;
}
+ if (FLAG_thin_strings) {
+ // External strings get special treatment, to avoid copying their
+ // contents.
+ if (string_->IsExternalOneByteString()) {
+ return isolate->factory()
+ ->InternalizeExternalString<ExternalOneByteString>(string_);
+ } else if (string_->IsExternalTwoByteString()) {
+ return isolate->factory()
+ ->InternalizeExternalString<ExternalTwoByteString>(string_);
+ }
+ }
// Otherwise allocate a new internalized string.
return isolate->factory()->NewInternalizedStringImpl(
string_, string_->length(), string_->hash_field());
@@ -16825,6 +16228,7 @@ class InternalizedStringKey : public HashTableKey {
return String::cast(obj)->Hash();
}
+ private:
Handle<String> string_;
};
@@ -16858,7 +16262,13 @@ Handle<Derived> HashTable<Derived, Shape, Key>::New(
if (capacity > HashTable::kMaxCapacity) {
v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
}
+ return New(isolate, capacity, pretenure);
+}
+template <typename Derived, typename Shape, typename Key>
+Handle<Derived> HashTable<Derived, Shape, Key>::New(Isolate* isolate,
+ int capacity,
+ PretenureFlag pretenure) {
Factory* factory = isolate->factory();
int length = EntryToIndex(capacity);
Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
@@ -16871,7 +16281,6 @@ Handle<Derived> HashTable<Derived, Shape, Key>::New(
return table;
}
-
// Find entry for key otherwise return kNotFound.
template <typename Derived, typename Shape>
int NameDictionaryBase<Derived, Shape>::FindEntry(Handle<Name> key) {
@@ -17145,6 +16554,10 @@ Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::New(
Isolate*, int at_least_space_for, PretenureFlag pretenure,
MinimumCapacity capacity_option);
+template Handle<SeededNumberDictionary>
+Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
+ uint32_t>::NewEmpty(Isolate*, PretenureFlag pretenure);
+
template Handle<UnseededNumberDictionary>
Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
uint32_t>::New(Isolate*, int at_least_space_for,
@@ -17155,6 +16568,10 @@ template Handle<NameDictionary>
Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::New(
Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
+template Handle<NameDictionary>
+Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::NewEmpty(
+ Isolate*, PretenureFlag pretenure);
+
template Handle<GlobalDictionary>
Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::New(
Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
@@ -17220,10 +16637,6 @@ Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::Add(
template Handle<FixedArray> Dictionary<
NameDictionary, NameDictionaryShape,
- Handle<Name> >::BuildIterationIndicesArray(Handle<NameDictionary>);
-
-template Handle<FixedArray> Dictionary<
- NameDictionary, NameDictionaryShape,
Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>);
template Handle<SeededNumberDictionary>
@@ -17278,6 +16691,12 @@ Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CopyEnumKeysTo(
Handle<FixedArray> storage, KeyCollectionMode mode,
KeyAccumulator* accumulator);
+template Handle<FixedArray>
+Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
+ IterationIndices(
+ Handle<
+ Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>>
+ dictionary);
template void
Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
CollectKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
@@ -17285,6 +16704,10 @@ Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
dictionary,
KeyAccumulator* keys);
+template Handle<FixedArray>
+Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::IterationIndices(
+ Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
+ dictionary);
template void
Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CollectKeysTo(
Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
@@ -17321,7 +16744,7 @@ Handle<Object> JSObject::PrepareSlowElementsForSort(
HandleScope scope(isolate);
Handle<Object> value(dict->ValueAt(i), isolate);
PropertyDetails details = dict->DetailsAt(i);
- if (details.type() == ACCESSOR_CONSTANT || details.IsReadOnly()) {
+ if (details.kind() == kAccessor || details.IsReadOnly()) {
// Bail out and do the sorting of undefineds and array holes in JS.
// Also bail out if the element is not supposed to be moved.
return bailout;
@@ -17337,7 +16760,7 @@ Handle<Object> JSObject::PrepareSlowElementsForSort(
return bailout;
} else {
Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
- new_dict, pos, value, details, object->map()->is_prototype_map());
+ new_dict, pos, value, details, object);
DCHECK(result.is_identical_to(new_dict));
USE(result);
pos++;
@@ -17348,7 +16771,7 @@ Handle<Object> JSObject::PrepareSlowElementsForSort(
return bailout;
} else {
Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
- new_dict, key, value, details, object->map()->is_prototype_map());
+ new_dict, key, value, details, object);
DCHECK(result.is_identical_to(new_dict));
USE(result);
}
@@ -17365,7 +16788,7 @@ Handle<Object> JSObject::PrepareSlowElementsForSort(
HandleScope scope(isolate);
Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
new_dict, pos, isolate->factory()->undefined_value(), no_details,
- object->map()->is_prototype_map());
+ object);
DCHECK(result.is_identical_to(new_dict));
USE(result);
pos++;
@@ -17386,7 +16809,7 @@ Handle<Object> JSObject::PrepareSlowElementsForSort(
Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
uint32_t limit) {
Isolate* isolate = object->GetIsolate();
- if (object->HasSloppyArgumentsElements()) {
+ if (object->HasSloppyArgumentsElements() || !object->map()->is_extensible()) {
return handle(Smi::FromInt(-1), isolate);
}
@@ -17503,11 +16926,11 @@ Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
}
result = undefs;
while (undefs < holes) {
- elements->set_undefined(undefs);
+ elements->set_undefined(isolate, undefs);
undefs++;
}
while (holes < limit) {
- elements->set_the_hole(holes);
+ elements->set_the_hole(isolate, holes);
holes++;
}
}
@@ -17515,6 +16938,98 @@ Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
return isolate->factory()->NewNumberFromUint(result);
}
+namespace {
+
+bool CanonicalNumericIndexString(Isolate* isolate, Handle<Object> s,
+ Handle<Object>* index) {
+ DCHECK(s->IsString() || s->IsSmi());
+
+ Handle<Object> result;
+ if (s->IsSmi()) {
+ result = s;
+ } else {
+ result = String::ToNumber(Handle<String>::cast(s));
+ if (!result->IsMinusZero()) {
+ Handle<String> str = Object::ToString(isolate, result).ToHandleChecked();
+ // Avoid treating strings like "2E1" and "20" as the same key.
+ if (!str->SameValue(*s)) return false;
+ }
+ }
+ *index = result;
+ return true;
+}
+
+} // anonymous namespace
+
+// ES#sec-integer-indexed-exotic-objects-defineownproperty-p-desc
+// static
+Maybe<bool> JSTypedArray::DefineOwnProperty(Isolate* isolate,
+ Handle<JSTypedArray> o,
+ Handle<Object> key,
+ PropertyDescriptor* desc,
+ ShouldThrow should_throw) {
+ // 1. Assert: IsPropertyKey(P) is true.
+ DCHECK(key->IsName() || key->IsNumber());
+ // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
+ // 3. If Type(P) is String, then
+ if (key->IsString() || key->IsSmi()) {
+ // 3a. Let numericIndex be ! CanonicalNumericIndexString(P)
+ // 3b. If numericIndex is not undefined, then
+ Handle<Object> numeric_index;
+ if (CanonicalNumericIndexString(isolate, key, &numeric_index)) {
+ // 3b i. If IsInteger(numericIndex) is false, return false.
+ // 3b ii. If numericIndex = -0, return false.
+ // 3b iii. If numericIndex < 0, return false.
+ // FIXME: the standard allows up to 2^53 elements.
+ uint32_t index;
+ if (numeric_index->IsMinusZero() || !numeric_index->ToUint32(&index)) {
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
+ }
+ // 3b iv. Let length be O.[[ArrayLength]].
+ uint32_t length = o->length()->Number();
+ // 3b v. If numericIndex ≥ length, return false.
+ if (index >= length) {
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
+ }
+ // 3b vi. If IsAccessorDescriptor(Desc) is true, return false.
+ if (PropertyDescriptor::IsAccessorDescriptor(desc)) {
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kRedefineDisallowed, key));
+ }
+ // 3b vii. If Desc has a [[Configurable]] field and if
+ // Desc.[[Configurable]] is true, return false.
+ // 3b viii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]]
+ // is false, return false.
+ // 3b ix. If Desc has a [[Writable]] field and if Desc.[[Writable]] is
+ // false, return false.
+ if ((desc->has_configurable() && desc->configurable()) ||
+ (desc->has_enumerable() && !desc->enumerable()) ||
+ (desc->has_writable() && !desc->writable())) {
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kRedefineDisallowed, key));
+ }
+ // 3b x. If Desc has a [[Value]] field, then
+ // 3b x 1. Let value be Desc.[[Value]].
+ // 3b x 2. Return ? IntegerIndexedElementSet(O, numericIndex, value).
+ if (desc->has_value()) {
+ if (!desc->has_configurable()) desc->set_configurable(false);
+ if (!desc->has_enumerable()) desc->set_enumerable(true);
+ if (!desc->has_writable()) desc->set_writable(true);
+ Handle<Object> value = desc->value();
+ RETURN_ON_EXCEPTION_VALUE(isolate,
+ SetOwnElementIgnoreAttributes(
+ o, index, value, desc->ToAttributes()),
+ Nothing<bool>());
+ }
+ // 3b xi. Return true.
+ return Just(true);
+ }
+ }
+ // 4. Return ! OrdinaryDefineOwnProperty(O, P, Desc).
+ return OrdinaryDefineOwnProperty(isolate, o, key, desc, should_throw);
+}
ExternalArrayType JSTypedArray::type() {
switch (elements()->map()->instance_type()) {
@@ -17577,12 +17092,12 @@ Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
if (original_cell_type == PropertyCellType::kInvalidated) {
cell = PropertyCell::InvalidateEntry(dictionary, entry);
}
- PropertyDetails details(NONE, DATA, 0, cell_type);
+ PropertyDetails details(kData, NONE, 0, cell_type);
cell->set_property_details(details);
return cell;
}
cell = isolate->factory()->NewPropertyCell();
- PropertyDetails details(NONE, DATA, 0, cell_type);
+ PropertyDetails details(kData, NONE, 0, cell_type);
dictionary =
GlobalDictionary::Add(dictionary, name, cell, details, entry_out);
// {*entry_out} is initialized inside GlobalDictionary::Add().
@@ -17661,6 +17176,9 @@ MaybeHandle<String> StringTable::InternalizeStringIfExists(
if (string->IsInternalizedString()) {
return string;
}
+ if (string->IsThinString()) {
+ return handle(Handle<ThinString>::cast(string)->actual(), isolate);
+ }
return LookupStringIfExists(isolate, string);
}
@@ -17707,31 +17225,98 @@ void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
isolate->heap()->SetRootStringTable(*table);
}
+namespace {
+
+template <class StringClass>
+void MigrateExternalStringResource(Isolate* isolate, Handle<String> from,
+ Handle<String> to) {
+ Handle<StringClass> cast_from = Handle<StringClass>::cast(from);
+ Handle<StringClass> cast_to = Handle<StringClass>::cast(to);
+ const typename StringClass::Resource* to_resource = cast_to->resource();
+ if (to_resource == nullptr) {
+ // |to| is a just-created internalized copy of |from|. Migrate the resource.
+ cast_to->set_resource(cast_from->resource());
+ // Zap |from|'s resource pointer to reflect the fact that |from| has
+ // relinquished ownership of its resource.
+ cast_from->set_resource(nullptr);
+ } else if (to_resource != cast_from->resource()) {
+ // |to| already existed and has its own resource. Finalize |from|.
+ isolate->heap()->FinalizeExternalString(*from);
+ }
+}
+
+} // namespace
Handle<String> StringTable::LookupString(Isolate* isolate,
Handle<String> string) {
+ if (string->IsThinString()) {
+ DCHECK(Handle<ThinString>::cast(string)->actual()->IsInternalizedString());
+ return handle(Handle<ThinString>::cast(string)->actual(), isolate);
+ }
if (string->IsConsString() && string->IsFlat()) {
- string = String::Flatten(string);
+ string = handle(Handle<ConsString>::cast(string)->first(), isolate);
if (string->IsInternalizedString()) return string;
}
InternalizedStringKey key(string);
Handle<String> result = LookupKey(isolate, &key);
- if (string->IsConsString()) {
- 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());
+ if (FLAG_thin_strings) {
+ if (string->IsExternalString()) {
+ if (result->IsExternalOneByteString()) {
+ MigrateExternalStringResource<ExternalOneByteString>(isolate, string,
+ result);
+ } else if (result->IsExternalTwoByteString()) {
+ MigrateExternalStringResource<ExternalTwoByteString>(isolate, string,
+ result);
+ } else {
+ // If the external string is duped into an existing non-external
+ // internalized string, free its resource (it's about to be rewritten
+ // into a ThinString below).
+ isolate->heap()->FinalizeExternalString(*string);
+ }
+ }
+
+ // The LookupKey() call above tries to internalize the string in-place.
+ // In cases where that wasn't possible (e.g. new-space strings), turn them
+ // into ThinStrings referring to their internalized versions now.
+ if (!string->IsInternalizedString()) {
+ DisallowHeapAllocation no_gc;
+ bool one_byte = result->IsOneByteRepresentation();
+ Handle<Map> map = one_byte
+ ? isolate->factory()->thin_one_byte_string_map()
+ : isolate->factory()->thin_string_map();
+ int old_size = string->Size();
+ DCHECK(old_size >= ThinString::kSize);
+ string->synchronized_set_map(*map);
+ Handle<ThinString> thin = Handle<ThinString>::cast(string);
+ thin->set_actual(*result);
+ Address thin_end = thin->address() + ThinString::kSize;
+ int size_delta = old_size - ThinString::kSize;
+ if (size_delta != 0) {
+ Heap* heap = isolate->heap();
+ heap->CreateFillerObjectAt(thin_end, size_delta,
+ ClearRecordedSlots::kNo);
+ heap->AdjustLiveBytes(*thin, -size_delta);
+ }
+ }
+ } else { // !FLAG_thin_strings
+ if (string->IsConsString()) {
+ 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;
}
@@ -17819,21 +17404,153 @@ Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
return Handle<Object>(get(index + 1), isolate);
}
+namespace {
-Handle<Object> CompilationCacheTable::LookupEval(
- Handle<String> src, Handle<SharedFunctionInfo> outer_info,
- LanguageMode language_mode, int scope_position) {
- Isolate* isolate = GetIsolate();
- // Cache key is the tuple (source, outer shared function info, scope position)
- // to unambiguously identify the context chain the cached eval code assumes.
- StringSharedKey key(src, outer_info, language_mode, scope_position);
+const int kLiteralEntryLength = 2;
+const int kLiteralInitialLength = 2;
+const int kLiteralContextOffset = 0;
+const int kLiteralLiteralsOffset = 1;
+
+int SearchLiteralsMapEntry(CompilationCacheTable* cache, int cache_entry,
+ Context* native_context) {
+ DisallowHeapAllocation no_gc;
+ DCHECK(native_context->IsNativeContext());
+ Object* obj = cache->get(cache_entry);
+
+ if (obj->IsFixedArray()) {
+ FixedArray* literals_map = FixedArray::cast(obj);
+ int length = literals_map->length();
+ for (int i = 0; i < length; i += kLiteralEntryLength) {
+ if (WeakCell::cast(literals_map->get(i + kLiteralContextOffset))
+ ->value() == native_context) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+void AddToLiteralsMap(Handle<CompilationCacheTable> cache, int cache_entry,
+ Handle<Context> native_context, Handle<Cell> literals) {
+ Isolate* isolate = native_context->GetIsolate();
+ DCHECK(native_context->IsNativeContext());
+ STATIC_ASSERT(kLiteralEntryLength == 2);
+ Handle<FixedArray> new_literals_map;
+ int entry;
+
+ Object* obj = cache->get(cache_entry);
+
+ if (!obj->IsFixedArray() || FixedArray::cast(obj)->length() == 0) {
+ new_literals_map =
+ isolate->factory()->NewFixedArray(kLiteralInitialLength, TENURED);
+ entry = 0;
+ } else {
+ Handle<FixedArray> old_literals_map(FixedArray::cast(obj), isolate);
+ entry = SearchLiteralsMapEntry(*cache, cache_entry, *native_context);
+ if (entry >= 0) {
+ // Just set the code of the entry.
+ Handle<WeakCell> literals_cell =
+ isolate->factory()->NewWeakCell(literals);
+ old_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell);
+ return;
+ }
+
+ // Can we reuse an entry?
+ DCHECK(entry < 0);
+ int length = old_literals_map->length();
+ for (int i = 0; i < length; i += kLiteralEntryLength) {
+ if (WeakCell::cast(old_literals_map->get(i + kLiteralContextOffset))
+ ->cleared()) {
+ new_literals_map = old_literals_map;
+ entry = i;
+ break;
+ }
+ }
+
+ if (entry < 0) {
+ // Copy old optimized code map and append one new entry.
+ new_literals_map = isolate->factory()->CopyFixedArrayAndGrow(
+ old_literals_map, kLiteralEntryLength, TENURED);
+ entry = old_literals_map->length();
+ }
+ }
+
+ Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals);
+ WeakCell* context_cell = native_context->self_weak_cell();
+
+ new_literals_map->set(entry + kLiteralContextOffset, context_cell);
+ new_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell);
+
+#ifdef DEBUG
+ for (int i = 0; i < new_literals_map->length(); i += kLiteralEntryLength) {
+ WeakCell* cell =
+ WeakCell::cast(new_literals_map->get(i + kLiteralContextOffset));
+ DCHECK(cell->cleared() || cell->value()->IsNativeContext());
+ cell = WeakCell::cast(new_literals_map->get(i + kLiteralLiteralsOffset));
+ DCHECK(cell->cleared() || (cell->value()->IsCell()));
+ }
+#endif
+
+ Object* old_literals_map = cache->get(cache_entry);
+ if (old_literals_map != *new_literals_map) {
+ cache->set(cache_entry, *new_literals_map);
+ }
+}
+
+Cell* SearchLiteralsMap(CompilationCacheTable* cache, int cache_entry,
+ Context* native_context) {
+ Cell* result = nullptr;
+ int entry = SearchLiteralsMapEntry(cache, cache_entry, native_context);
+ if (entry >= 0) {
+ FixedArray* literals_map = FixedArray::cast(cache->get(cache_entry));
+ DCHECK_LE(entry + kLiteralEntryLength, literals_map->length());
+ WeakCell* cell =
+ WeakCell::cast(literals_map->get(entry + kLiteralLiteralsOffset));
+
+ result = cell->cleared() ? nullptr : Cell::cast(cell->value());
+ }
+ DCHECK(result == nullptr || result->IsCell());
+ return result;
+}
+
+} // namespace
+
+InfoVectorPair CompilationCacheTable::LookupScript(Handle<String> src,
+ Handle<Context> context,
+ LanguageMode language_mode) {
+ InfoVectorPair empty_result;
+ Handle<SharedFunctionInfo> shared(context->closure()->shared());
+ StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
int entry = FindEntry(&key);
- if (entry == kNotFound) return isolate->factory()->undefined_value();
+ if (entry == kNotFound) return empty_result;
int index = EntryToIndex(entry);
- if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
- return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
+ if (!get(index)->IsFixedArray()) return empty_result;
+ Object* obj = get(index + 1);
+ if (obj->IsSharedFunctionInfo()) {
+ Cell* literals =
+ SearchLiteralsMap(this, index + 2, context->native_context());
+ return InfoVectorPair(SharedFunctionInfo::cast(obj), literals);
+ }
+ return empty_result;
}
+InfoVectorPair CompilationCacheTable::LookupEval(
+ Handle<String> src, Handle<SharedFunctionInfo> outer_info,
+ Handle<Context> native_context, LanguageMode language_mode, int position) {
+ InfoVectorPair empty_result;
+ StringSharedKey key(src, outer_info, language_mode, position);
+ int entry = FindEntry(&key);
+ if (entry == kNotFound) return empty_result;
+ int index = EntryToIndex(entry);
+ if (!get(index)->IsFixedArray()) return empty_result;
+ Object* obj = get(EntryToIndex(entry) + 1);
+ if (obj->IsSharedFunctionInfo()) {
+ Cell* literals =
+ SearchLiteralsMap(this, EntryToIndex(entry) + 2, *native_context);
+ return InfoVectorPair(SharedFunctionInfo::cast(obj), literals);
+ }
+ return empty_result;
+}
Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
JSRegExp::Flags flags) {
@@ -17861,20 +17578,41 @@ Handle<CompilationCacheTable> CompilationCacheTable::Put(
return cache;
}
+Handle<CompilationCacheTable> CompilationCacheTable::PutScript(
+ Handle<CompilationCacheTable> cache, Handle<String> src,
+ Handle<Context> context, LanguageMode language_mode,
+ Handle<SharedFunctionInfo> value, Handle<Cell> literals) {
+ Isolate* isolate = cache->GetIsolate();
+ Handle<SharedFunctionInfo> shared(context->closure()->shared());
+ Handle<Context> native_context(context->native_context());
+ StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
+ Handle<Object> k = key.AsHandle(isolate);
+ cache = EnsureCapacity(cache, 1, &key);
+ int entry = cache->FindInsertionEntry(key.Hash());
+ cache->set(EntryToIndex(entry), *k);
+ cache->set(EntryToIndex(entry) + 1, *value);
+ AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context, literals);
+ cache->ElementAdded();
+ return cache;
+}
Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
Handle<CompilationCacheTable> cache, Handle<String> src,
Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
- int scope_position) {
+ Handle<Context> native_context, Handle<Cell> literals, int position) {
Isolate* isolate = cache->GetIsolate();
- StringSharedKey key(src, outer_info, value->language_mode(), scope_position);
+ StringSharedKey key(src, outer_info, value->language_mode(), position);
{
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);
+ // AddToLiteralsMap may allocate a new sub-array to live in the entry,
+ // but it won't change the cache array. Therefore EntryToIndex and
+ // entry remains correct.
+ AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context,
+ literals);
return cache;
}
}
@@ -17924,9 +17662,14 @@ void CompilationCacheTable::Age() {
}
} else if (get(entry_index)->IsFixedArray()) {
SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
- if (info->code()->kind() != Code::FUNCTION || info->code()->IsOld()) {
- NoWriteBarrierSet(this, entry_index, the_hole_value);
- NoWriteBarrierSet(this, value_index, the_hole_value);
+ bool is_old =
+ info->IsInterpreted()
+ ? info->bytecode_array()->IsOld()
+ : info->code()->kind() != Code::FUNCTION || info->code()->IsOld();
+ if (is_old) {
+ for (int i = 0; i < kEntrySize; i++) {
+ NoWriteBarrierSet(this, entry_index + i, the_hole_value);
+ }
ElementRemoved();
}
}
@@ -17941,8 +17684,9 @@ void CompilationCacheTable::Remove(Object* value) {
int entry_index = EntryToIndex(entry);
int value_index = entry_index + 1;
if (get(value_index) == value) {
- NoWriteBarrierSet(this, entry_index, the_hole_value);
- NoWriteBarrierSet(this, value_index, the_hole_value);
+ for (int i = 0; i < kEntrySize; i++) {
+ NoWriteBarrierSet(this, entry_index + i, the_hole_value);
+ }
ElementRemoved();
}
}
@@ -17962,44 +17706,24 @@ Handle<Derived> Dictionary<Derived, Shape, Key>::New(
return dict;
}
-
template <typename Derived, typename Shape, typename Key>
-Handle<FixedArray> Dictionary<Derived, Shape, Key>::BuildIterationIndicesArray(
- Handle<Derived> dictionary) {
- Isolate* isolate = dictionary->GetIsolate();
- Factory* factory = isolate->factory();
- int length = dictionary->NumberOfElements();
-
- Handle<FixedArray> iteration_order = factory->NewFixedArray(length);
- Handle<FixedArray> enumeration_order = factory->NewFixedArray(length);
-
- // Fill both the iteration order array and the enumeration order array
- // with property details.
- int capacity = dictionary->Capacity();
- int pos = 0;
- for (int i = 0; i < capacity; i++) {
- if (dictionary->IsKey(isolate, dictionary->KeyAt(i))) {
- int index = dictionary->DetailsAt(i).dictionary_index();
- iteration_order->set(pos, Smi::FromInt(i));
- enumeration_order->set(pos, Smi::FromInt(index));
- pos++;
- }
- }
- DCHECK(pos == length);
-
- // Sort the arrays wrt. enumeration order.
- iteration_order->SortPairs(*enumeration_order, enumeration_order->length());
- return iteration_order;
+Handle<Derived> Dictionary<Derived, Shape, Key>::NewEmpty(
+ Isolate* isolate, PretenureFlag pretenure) {
+ Handle<Derived> dict = DerivedHashTable::New(isolate, 1, pretenure);
+ // Attempt to add one element to the empty dictionary must cause reallocation.
+ DCHECK(!dict->HasSufficientCapacityToAdd(1));
+ // Initialize the next enumeration index.
+ dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
+ return dict;
}
-
template <typename Derived, typename Shape, typename Key>
Handle<FixedArray>
Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
Handle<Derived> dictionary) {
int length = dictionary->NumberOfElements();
- Handle<FixedArray> iteration_order = BuildIterationIndicesArray(dictionary);
+ Handle<FixedArray> iteration_order = IterationIndices(dictionary);
DCHECK(iteration_order->length() == length);
// Iterate over the dictionary using the enumeration order and update
@@ -18130,15 +17854,15 @@ bool SeededNumberDictionary::HasComplexElements() {
if (!this->IsKey(isolate, k)) continue;
DCHECK(!IsDeleted(i));
PropertyDetails details = this->DetailsAt(i);
- if (details.type() == ACCESSOR_CONSTANT) return true;
+ if (details.kind() == kAccessor) return true;
PropertyAttributes attr = details.attributes();
if (attr & ALL_ATTRIBUTES_MASK) return true;
}
return false;
}
-void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key,
- bool used_as_prototype) {
+void SeededNumberDictionary::UpdateMaxNumberKey(
+ uint32_t key, Handle<JSObject> dictionary_holder) {
DisallowHeapAllocation no_allocation;
// If the dictionary requires slow elements an element has already
// been added at a high index.
@@ -18146,9 +17870,8 @@ void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key,
// Check if this index is high enough that we should require slow
// elements.
if (key > kRequiresSlowElementsLimit) {
- if (used_as_prototype) {
- // TODO(verwaest): Remove this hack.
- TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate());
+ if (!dictionary_holder.is_null()) {
+ dictionary_holder->RequireSlowElements(this);
}
set_requires_slow_elements();
return;
@@ -18161,11 +17884,11 @@ void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key,
}
}
-
Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry(
Handle<SeededNumberDictionary> dictionary, uint32_t key,
- Handle<Object> value, PropertyDetails details, bool used_as_prototype) {
- dictionary->UpdateMaxNumberKey(key, used_as_prototype);
+ Handle<Object> value, PropertyDetails details,
+ Handle<JSObject> dictionary_holder) {
+ dictionary->UpdateMaxNumberKey(key, dictionary_holder);
SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
return Add(dictionary, key, value, details);
}
@@ -18193,8 +17916,8 @@ Handle<UnseededNumberDictionary> UnseededNumberDictionary::DeleteKey(
Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut(
Handle<SeededNumberDictionary> dictionary, uint32_t key,
- Handle<Object> value, bool used_as_prototype) {
- dictionary->UpdateMaxNumberKey(key, used_as_prototype);
+ Handle<Object> value, Handle<JSObject> dictionary_holder) {
+ dictionary->UpdateMaxNumberKey(key, dictionary_holder);
return AtPut(dictionary, key, value);
}
@@ -18206,13 +17929,13 @@ Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut(
return AtPut(dictionary, key, value);
}
-
Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
Handle<SeededNumberDictionary> dictionary, uint32_t key,
- Handle<Object> value, PropertyDetails details, bool used_as_prototype) {
+ Handle<Object> value, PropertyDetails details,
+ Handle<JSObject> dictionary_holder) {
int entry = dictionary->FindEntry(key);
if (entry == kNotFound) {
- return AddNumberEntry(dictionary, key, value, details, used_as_prototype);
+ return AddNumberEntry(dictionary, key, value, details, dictionary_holder);
}
// Preserve enumeration index.
details = details.set_index(dictionary->DetailsAt(entry).dictionary_index());
@@ -18271,6 +17994,7 @@ void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(
Handle<Dictionary<Derived, Shape, Key>> dictionary,
Handle<FixedArray> storage, KeyCollectionMode mode,
KeyAccumulator* accumulator) {
+ DCHECK_IMPLIES(mode != KeyCollectionMode::kOwnOnly, accumulator != nullptr);
Isolate* isolate = dictionary->GetIsolate();
int length = storage->length();
int capacity = dictionary->Capacity();
@@ -18296,7 +18020,7 @@ void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(
storage->set(properties, Smi::FromInt(i));
}
properties++;
- if (properties == length) break;
+ if (mode == KeyCollectionMode::kOwnOnly && properties == length) break;
}
CHECK_EQ(length, properties);
@@ -18313,6 +18037,34 @@ void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(
}
template <typename Derived, typename Shape, typename Key>
+Handle<FixedArray> Dictionary<Derived, Shape, Key>::IterationIndices(
+ Handle<Dictionary<Derived, Shape, Key>> dictionary) {
+ Isolate* isolate = dictionary->GetIsolate();
+ int capacity = dictionary->Capacity();
+ int length = dictionary->NumberOfElements();
+ Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
+ int array_size = 0;
+ {
+ DisallowHeapAllocation no_gc;
+ Dictionary<Derived, Shape, Key>* raw_dict = *dictionary;
+ for (int i = 0; i < capacity; i++) {
+ Object* k = raw_dict->KeyAt(i);
+ if (!raw_dict->IsKey(isolate, k)) continue;
+ if (raw_dict->IsDeleted(i)) continue;
+ array->set(array_size++, Smi::FromInt(i));
+ }
+
+ DCHECK_EQ(array_size, length);
+
+ EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict));
+ Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress());
+ std::sort(start, start + array_size, cmp);
+ }
+ array->Shrink(array_size);
+ return array;
+}
+
+template <typename Derived, typename Shape, typename Key>
void Dictionary<Derived, Shape, Key>::CollectKeysTo(
Handle<Dictionary<Derived, Shape, Key>> dictionary, KeyAccumulator* keys) {
Isolate* isolate = keys->isolate();
@@ -18966,6 +18718,40 @@ bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
return was_present;
}
+Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder,
+ int max_entries) {
+ Isolate* isolate = holder->GetIsolate();
+ Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
+ if (max_entries == 0 || max_entries > table->NumberOfElements()) {
+ max_entries = table->NumberOfElements();
+ }
+ int values_per_entry = holder->IsJSWeakMap() ? 2 : 1;
+ Handle<FixedArray> entries =
+ isolate->factory()->NewFixedArray(max_entries * values_per_entry);
+ // Recompute max_values because GC could have removed elements from the table.
+ if (max_entries > table->NumberOfElements()) {
+ max_entries = table->NumberOfElements();
+ }
+
+ {
+ DisallowHeapAllocation no_gc;
+ int count = 0;
+ for (int i = 0;
+ count / values_per_entry < max_entries && i < table->Capacity(); i++) {
+ Handle<Object> key(table->KeyAt(i), isolate);
+ if (table->IsKey(isolate, *key)) {
+ entries->set(count++, *key);
+ if (values_per_entry > 1) {
+ Object* value = table->Lookup(key);
+ entries->set(count++, value);
+ }
+ }
+ }
+ DCHECK_EQ(max_entries * values_per_entry, count);
+ }
+ return isolate->factory()->NewJSArrayWithElements(entries);
+}
+
// Check if there is a break point at this source position.
bool DebugInfo::HasBreakPoint(int source_position) {
// Get the break point info object for this code offset.
@@ -19052,11 +18838,8 @@ void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int source_position,
DCHECK(index != kNoBreakPointInfo);
// Allocate new BreakPointInfo object and set the break point.
- Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
- isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
- new_break_point_info->set_source_position(source_position);
- new_break_point_info->set_break_point_objects(
- isolate->heap()->undefined_value());
+ Handle<BreakPointInfo> new_break_point_info =
+ isolate->factory()->NewBreakPointInfo(source_position);
BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
debug_info->break_points()->set(index, *new_break_point_info);
}
@@ -19366,27 +19149,6 @@ void JSDate::SetValue(Object* value, bool is_value_nan) {
}
-// static
-MaybeHandle<Object> JSDate::ToPrimitive(Handle<JSReceiver> receiver,
- Handle<Object> hint) {
- Isolate* const isolate = receiver->GetIsolate();
- if (hint->IsString()) {
- Handle<String> hint_string = Handle<String>::cast(hint);
- if (hint_string->Equals(isolate->heap()->number_string())) {
- return JSReceiver::OrdinaryToPrimitive(receiver,
- OrdinaryToPrimitiveHint::kNumber);
- }
- if (hint_string->Equals(isolate->heap()->default_string()) ||
- hint_string->Equals(isolate->heap()->string_string())) {
- return JSReceiver::OrdinaryToPrimitive(receiver,
- OrdinaryToPrimitiveHint::kString);
- }
- }
- THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kInvalidHint, hint),
- Object);
-}
-
-
void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
int days = DateCache::DaysFromTime(local_time_ms);
int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
@@ -19472,6 +19234,11 @@ void JSArrayBuffer::Neuter() {
set_backing_store(NULL);
set_byte_length(Smi::kZero);
set_was_neutered(true);
+ // Invalidate the neutering protector.
+ Isolate* const isolate = GetIsolate();
+ if (isolate->IsArrayBufferNeuteringIntact()) {
+ isolate->InvalidateArrayBufferNeuteringProtector();
+ }
}
@@ -19719,24 +19486,14 @@ void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell,
int JSGeneratorObject::source_position() const {
CHECK(is_suspended());
- AbstractCode* code;
- int code_offset;
- if (function()->shared()->HasBytecodeArray()) {
- // New-style generators.
- DCHECK(!function()->shared()->HasBaselineCode());
- code_offset = Smi::cast(input_or_debug_pos())->value();
- // The stored bytecode offset is relative to a different base than what
- // is used in the source position table, hence the subtraction.
- code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
- code = AbstractCode::cast(function()->shared()->bytecode_array());
- } else {
- // Old-style generators.
- DCHECK(function()->shared()->HasBaselineCode());
- code_offset = continuation();
- CHECK(0 <= code_offset);
- CHECK(code_offset < function()->code()->instruction_size());
- code = AbstractCode::cast(function()->shared()->code());
- }
+ DCHECK(function()->shared()->HasBytecodeArray());
+ DCHECK(!function()->shared()->HasBaselineCode());
+ int code_offset = Smi::cast(input_or_debug_pos())->value();
+ // The stored bytecode offset is relative to a different base than what
+ // is used in the source position table, hence the subtraction.
+ code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
+ AbstractCode* code =
+ AbstractCode::cast(function()->shared()->bytecode_array());
return code->SourcePosition(code_offset);
}