Revert "Revert "Upgrade to 5.0.71.48"" DO NOT MERGE
This reverts commit f2e3994fa5148cc3d9946666f0b0596290192b0e,
and updates the x64 makefile properly so it doesn't break that
build.
FPIIM-449
Change-Id: Ib83e35bfbae6af627451c926a9650ec57c045605
(cherry picked from commit 109988c7ccb6f3fd1a58574fa3dfb88beaef6632)
diff --git a/src/objects.cc b/src/objects.cc
index d9d8213..f577d5e 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -11,6 +11,7 @@
#include "src/accessors.h"
#include "src/allocation-site-scopes.h"
#include "src/api.h"
+#include "src/api-natives.h"
#include "src/arguments.h"
#include "src/base/bits.h"
#include "src/base/utils/random-number-generator.h"
@@ -24,12 +25,14 @@
#include "src/deoptimizer.h"
#include "src/elements.h"
#include "src/execution.h"
-#include "src/field-index.h"
#include "src/field-index-inl.h"
+#include "src/field-index.h"
+#include "src/field-type.h"
#include "src/full-codegen/full-codegen.h"
#include "src/ic/ic.h"
#include "src/identity-map.h"
#include "src/interpreter/bytecodes.h"
+#include "src/interpreter/source-position-table.h"
#include "src/isolate-inl.h"
#include "src/key-accumulator.h"
#include "src/list.h"
@@ -70,20 +73,19 @@
return os << "UNKNOWN"; // Keep the compiler happy.
}
-
-Handle<HeapType> Object::OptimalType(Isolate* isolate,
- Representation representation) {
- if (representation.IsNone()) return HeapType::None(isolate);
+Handle<FieldType> Object::OptimalType(Isolate* isolate,
+ Representation representation) {
+ if (representation.IsNone()) return FieldType::None(isolate);
if (FLAG_track_field_types) {
if (representation.IsHeapObject() && IsHeapObject()) {
// We can track only JavaScript objects with stable maps.
Handle<Map> map(HeapObject::cast(this)->map(), isolate);
if (map->is_stable() && map->IsJSReceiverMap()) {
- return HeapType::Class(map, isolate);
+ return FieldType::Class(map, isolate);
}
}
}
- return HeapType::Any(isolate);
+ return FieldType::Any(isolate);
}
@@ -98,7 +100,9 @@
int constructor_function_index =
Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex();
if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
- return MaybeHandle<JSReceiver>();
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
+ JSReceiver);
}
constructor = handle(
JSFunction::cast(native_context->get(constructor_function_index)),
@@ -259,14 +263,11 @@
// static
-Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y,
- Strength strength) {
- if (!is_strong(strength)) {
- // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
- if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
- !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
- return Nothing<ComparisonResult>();
- }
+Maybe<ComparisonResult> Object::Compare(Handle<Object> x, Handle<Object> y) {
+ // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4.
+ if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) ||
+ !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) {
+ return Nothing<ComparisonResult>();
}
if (x->IsString() && y->IsString()) {
// ES6 section 7.2.11 Abstract Relational Comparison step 5.
@@ -274,23 +275,8 @@
String::Compare(Handle<String>::cast(x), Handle<String>::cast(y)));
}
// ES6 section 7.2.11 Abstract Relational Comparison step 6.
- if (!is_strong(strength)) {
- if (!Object::ToNumber(x).ToHandle(&x) ||
- !Object::ToNumber(y).ToHandle(&y)) {
- return Nothing<ComparisonResult>();
- }
- } else {
- if (!x->IsNumber()) {
- Isolate* const isolate = Handle<HeapObject>::cast(x)->GetIsolate();
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kStrongImplicitConversion));
- return Nothing<ComparisonResult>();
- } else if (!y->IsNumber()) {
- Isolate* const isolate = Handle<HeapObject>::cast(y)->GetIsolate();
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kStrongImplicitConversion));
- return Nothing<ComparisonResult>();
- }
+ if (!Object::ToNumber(x).ToHandle(&x) || !Object::ToNumber(y).ToHandle(&y)) {
+ return Nothing<ComparisonResult>();
}
return Just(NumberCompare(x->Number(), y->Number()));
}
@@ -410,10 +396,10 @@
// static
Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) {
if (object->IsNumber()) return isolate->factory()->number_string();
- if (object->IsUndefined() || object->IsUndetectableObject()) {
+ if (object->IsOddball()) return handle(Oddball::cast(*object)->type_of());
+ if (object->IsUndetectableObject()) {
return isolate->factory()->undefined_string();
}
- if (object->IsBoolean()) return isolate->factory()->boolean_string();
if (object->IsString()) return isolate->factory()->string_string();
if (object->IsSymbol()) return isolate->factory()->symbol_string();
if (object->IsString()) return isolate->factory()->string_string();
@@ -428,13 +414,8 @@
// static
MaybeHandle<Object> Object::Multiply(Isolate* isolate, Handle<Object> lhs,
- Handle<Object> rhs, Strength strength) {
+ Handle<Object> rhs) {
if (!lhs->IsNumber() || !rhs->IsNumber()) {
- if (is_strong(strength)) {
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kStrongImplicitConversion),
- Object);
- }
ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
}
@@ -444,13 +425,8 @@
// static
MaybeHandle<Object> Object::Divide(Isolate* isolate, Handle<Object> lhs,
- Handle<Object> rhs, Strength strength) {
+ Handle<Object> rhs) {
if (!lhs->IsNumber() || !rhs->IsNumber()) {
- if (is_strong(strength)) {
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kStrongImplicitConversion),
- Object);
- }
ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
}
@@ -460,13 +436,8 @@
// static
MaybeHandle<Object> Object::Modulus(Isolate* isolate, Handle<Object> lhs,
- Handle<Object> rhs, Strength strength) {
+ Handle<Object> rhs) {
if (!lhs->IsNumber() || !rhs->IsNumber()) {
- if (is_strong(strength)) {
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kStrongImplicitConversion),
- Object);
- }
ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
}
@@ -476,16 +447,12 @@
// static
MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs,
- Handle<Object> rhs, Strength strength) {
+ Handle<Object> rhs) {
if (lhs->IsNumber() && rhs->IsNumber()) {
return isolate->factory()->NewNumber(lhs->Number() + rhs->Number());
} else if (lhs->IsString() && rhs->IsString()) {
return isolate->factory()->NewConsString(Handle<String>::cast(lhs),
Handle<String>::cast(rhs));
- } else if (is_strong(strength)) {
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kStrongImplicitConversion),
- Object);
}
ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object);
ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object);
@@ -505,13 +472,8 @@
// static
MaybeHandle<Object> Object::Subtract(Isolate* isolate, Handle<Object> lhs,
- Handle<Object> rhs, Strength strength) {
+ Handle<Object> rhs) {
if (!lhs->IsNumber() || !rhs->IsNumber()) {
- if (is_strong(strength)) {
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kStrongImplicitConversion),
- Object);
- }
ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
}
@@ -521,13 +483,8 @@
// static
MaybeHandle<Object> Object::ShiftLeft(Isolate* isolate, Handle<Object> lhs,
- Handle<Object> rhs, Strength strength) {
+ Handle<Object> rhs) {
if (!lhs->IsNumber() || !rhs->IsNumber()) {
- if (is_strong(strength)) {
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kStrongImplicitConversion),
- Object);
- }
ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
}
@@ -538,13 +495,8 @@
// static
MaybeHandle<Object> Object::ShiftRight(Isolate* isolate, Handle<Object> lhs,
- Handle<Object> rhs, Strength strength) {
+ Handle<Object> rhs) {
if (!lhs->IsNumber() || !rhs->IsNumber()) {
- if (is_strong(strength)) {
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kStrongImplicitConversion),
- Object);
- }
ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
}
@@ -556,14 +508,8 @@
// static
MaybeHandle<Object> Object::ShiftRightLogical(Isolate* isolate,
Handle<Object> lhs,
- Handle<Object> rhs,
- Strength strength) {
+ Handle<Object> rhs) {
if (!lhs->IsNumber() || !rhs->IsNumber()) {
- if (is_strong(strength)) {
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kStrongImplicitConversion),
- Object);
- }
ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
}
@@ -574,13 +520,8 @@
// static
MaybeHandle<Object> Object::BitwiseAnd(Isolate* isolate, Handle<Object> lhs,
- Handle<Object> rhs, Strength strength) {
+ Handle<Object> rhs) {
if (!lhs->IsNumber() || !rhs->IsNumber()) {
- if (is_strong(strength)) {
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kStrongImplicitConversion),
- Object);
- }
ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
}
@@ -591,13 +532,8 @@
// static
MaybeHandle<Object> Object::BitwiseOr(Isolate* isolate, Handle<Object> lhs,
- Handle<Object> rhs, Strength strength) {
+ Handle<Object> rhs) {
if (!lhs->IsNumber() || !rhs->IsNumber()) {
- if (is_strong(strength)) {
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kStrongImplicitConversion),
- Object);
- }
ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
}
@@ -608,13 +544,8 @@
// static
MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs,
- Handle<Object> rhs, Strength strength) {
+ Handle<Object> rhs) {
if (!lhs->IsNumber() || !rhs->IsNumber()) {
- if (is_strong(strength)) {
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kStrongImplicitConversion),
- Object);
- }
ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object);
ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object);
}
@@ -777,8 +708,7 @@
// static
-MaybeHandle<Object> Object::GetProperty(LookupIterator* it,
- LanguageMode language_mode) {
+MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
case LookupIterator::NOT_FOUND:
@@ -786,8 +716,7 @@
UNREACHABLE();
case LookupIterator::JSPROXY:
return JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
- it->GetName(), it->GetReceiver(),
- language_mode);
+ it->GetName(), it->GetReceiver());
case LookupIterator::INTERCEPTOR: {
bool done;
Handle<Object> result;
@@ -801,14 +730,14 @@
if (it->HasAccess()) break;
return JSObject::GetPropertyWithFailedAccessCheck(it);
case LookupIterator::ACCESSOR:
- return GetPropertyWithAccessor(it, language_mode);
+ return GetPropertyWithAccessor(it);
case LookupIterator::INTEGER_INDEXED_EXOTIC:
- return ReadAbsentProperty(it, language_mode);
+ return ReadAbsentProperty(it);
case LookupIterator::DATA:
return it->GetDataValue();
}
}
- return ReadAbsentProperty(it, language_mode);
+ return ReadAbsentProperty(it);
}
@@ -827,8 +756,7 @@
MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
Handle<JSProxy> proxy,
Handle<Name> name,
- Handle<Object> receiver,
- LanguageMode language_mode) {
+ Handle<Object> receiver) {
if (receiver->IsJSGlobalObject()) {
THROW_NEW_ERROR(
isolate,
@@ -861,7 +789,7 @@
// 7.a Return target.[[Get]](P, Receiver).
LookupIterator it =
LookupIterator::PropertyOrElement(isolate, receiver, name, target);
- return Object::GetProperty(&it, language_mode);
+ return Object::GetProperty(&it);
}
// 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
Handle<Object> trap_result;
@@ -934,9 +862,8 @@
it->NotFound();
return it->isolate()->factory()->undefined_value();
case LookupIterator::ACCESSOR:
- // TODO(verwaest): For now this doesn't call into
- // ExecutableAccessorInfo, since clients don't need it. Update once
- // relevant.
+ // TODO(verwaest): For now this doesn't call into AccessorInfo, since
+ // clients don't need it. Update once relevant.
it->NotFound();
return it->isolate()->factory()->undefined_value();
case LookupIterator::INTEGER_INDEXED_EXOTIC:
@@ -1020,9 +947,10 @@
if (recv_type->IsUndefined()) return receiver;
FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type);
// Check the receiver.
- for (PrototypeIterator iter(isolate, receiver,
- PrototypeIterator::START_AT_RECEIVER);
- !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
+ for (PrototypeIterator iter(isolate, JSObject::cast(receiver),
+ PrototypeIterator::START_AT_RECEIVER,
+ PrototypeIterator::END_AT_NON_HIDDEN);
+ !iter.IsAtEnd(); iter.Advance()) {
if (signature->IsTemplateFor(iter.GetCurrent())) return iter.GetCurrent();
}
return isolate->heap()->null_value();
@@ -1058,7 +986,8 @@
Handle<FixedArray> JSObject::EnsureWritableFastElements(
Handle<JSObject> object) {
- DCHECK(object->HasFastSmiOrObjectElements());
+ DCHECK(object->HasFastSmiOrObjectElements() ||
+ object->HasFastStringWrapperElements());
Isolate* isolate = object->GetIsolate();
Handle<FixedArray> elems(FixedArray::cast(object->elements()), isolate);
if (elems->map() != isolate->heap()->fixed_cow_array_map()) return elems;
@@ -1096,7 +1025,7 @@
Object);
// 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
if (trap->IsUndefined()) {
- return Object::GetPrototype(isolate, target);
+ return JSReceiver::GetPrototype(isolate, target);
}
// 7. Let handlerProto be ? Call(trap, handler, «target»).
Handle<Object> argv[] = {target};
@@ -1118,7 +1047,7 @@
// 11. Let targetProto be ? target.[[GetPrototypeOf]]().
Handle<Object> target_proto;
ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
- Object::GetPrototype(isolate, target), Object);
+ JSReceiver::GetPrototype(isolate, target), Object);
// 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
if (!handler_proto->SameValue(*target_proto)) {
THROW_NEW_ERROR(
@@ -1130,9 +1059,7 @@
return handler_proto;
}
-
-MaybeHandle<Object> Object::GetPropertyWithAccessor(
- LookupIterator* it, LanguageMode language_mode) {
+MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
Isolate* isolate = it->isolate();
Handle<Object> structure = it->GetAccessors();
Handle<Object> receiver = it->GetReceiver();
@@ -1145,8 +1072,7 @@
if (structure->IsAccessorInfo()) {
Handle<JSObject> holder = it->GetHolder<JSObject>();
Handle<Name> name = it->GetName();
- Handle<ExecutableAccessorInfo> info =
- Handle<ExecutableAccessorInfo>::cast(structure);
+ Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
if (!info->IsCompatibleReceiver(*receiver)) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
@@ -1159,11 +1085,12 @@
if (call_fun == nullptr) return isolate->factory()->undefined_value();
LOG(isolate, ApiNamedPropertyAccess("load", *holder, *name));
- PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder);
+ PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
+ Object::DONT_THROW);
v8::Local<v8::Value> result = args.Call(call_fun, v8::Utils::ToLocal(name));
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
if (result.IsEmpty()) {
- return ReadAbsentProperty(isolate, receiver, name, language_mode);
+ return ReadAbsentProperty(isolate, receiver, name);
}
Handle<Object> return_value = v8::Utils::OpenHandle(*result);
return_value->VerifyApiCallResultType();
@@ -1173,13 +1100,24 @@
// Regular accessor.
Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
- if (getter->IsCallable()) {
+ if (getter->IsFunctionTemplateInfo()) {
+ auto result = Builtins::InvokeApiFunction(
+ Handle<FunctionTemplateInfo>::cast(getter), receiver, 0, nullptr);
+ if (isolate->has_pending_exception()) {
+ return MaybeHandle<Object>();
+ }
+ Handle<Object> return_value;
+ if (result.ToHandle(&return_value)) {
+ return_value->VerifyApiCallResultType();
+ return handle(*return_value, isolate);
+ }
+ } else if (getter->IsCallable()) {
// TODO(rossberg): nicer would be to cast to some JSCallable here...
return Object::GetPropertyWithDefinedGetter(
receiver, Handle<JSReceiver>::cast(getter));
}
// Getter is not a function.
- return ReadAbsentProperty(isolate, receiver, it->GetName(), language_mode);
+ return ReadAbsentProperty(isolate, receiver, it->GetName());
}
@@ -1192,7 +1130,6 @@
->IsTemplateFor(*map);
}
-
Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
Handle<Object> value,
ShouldThrow should_throw) {
@@ -1205,11 +1142,10 @@
DCHECK(!structure->IsForeign());
// API style callbacks.
- if (structure->IsExecutableAccessorInfo()) {
+ if (structure->IsAccessorInfo()) {
Handle<JSObject> holder = it->GetHolder<JSObject>();
Handle<Name> name = it->GetName();
- Handle<ExecutableAccessorInfo> info =
- Handle<ExecutableAccessorInfo>::cast(structure);
+ Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
if (!info->IsCompatibleReceiver(*receiver)) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kIncompatibleMethodReceiver, name, receiver));
@@ -1218,14 +1154,14 @@
v8::AccessorNameSetterCallback call_fun =
v8::ToCData<v8::AccessorNameSetterCallback>(info->setter());
+ // TODO(verwaest): We should not get here anymore once all AccessorInfos are
+ // marked as special_data_property. They cannot both be writable and not
+ // have a setter.
if (call_fun == nullptr) return Just(true);
- // TODO(verwaest): Shouldn't this case be unreachable (at least in the
- // long run?) Should we have ExecutableAccessorPairs with missing setter
- // that are "writable"? If they aren't writable, shouldn't we have bailed
- // out already earlier?
LOG(isolate, ApiNamedPropertyAccess("store", *holder, *name));
- PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder);
+ PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
+ should_throw);
args.Call(call_fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
return Just(true);
@@ -1233,7 +1169,16 @@
// Regular accessor.
Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
- if (setter->IsCallable()) {
+ if (setter->IsFunctionTemplateInfo()) {
+ Handle<Object> argv[] = {value};
+ auto result =
+ Builtins::InvokeApiFunction(Handle<FunctionTemplateInfo>::cast(setter),
+ receiver, arraysize(argv), argv);
+ if (isolate->has_pending_exception()) {
+ return Nothing<bool>();
+ }
+ return Just(true);
+ } else if (setter->IsCallable()) {
// TODO(rossberg): nicer would be to cast to some JSCallable here...
return SetPropertyWithDefinedSetter(
receiver, Handle<JSReceiver>::cast(setter), value, should_throw);
@@ -1322,7 +1267,7 @@
Handle<JSObject> checked = it->GetHolder<JSObject>();
while (AllCanRead(it)) {
if (it->state() == LookupIterator::ACCESSOR) {
- return GetPropertyWithAccessor(it, SLOPPY);
+ return GetPropertyWithAccessor(it);
}
DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
bool done;
@@ -1350,7 +1295,7 @@
Handle<JSObject> checked = it->GetHolder<JSObject>();
while (AllCanRead(it)) {
if (it->state() == LookupIterator::ACCESSOR) {
- return Just(it->property_details().attributes());
+ return Just(it->property_attributes());
}
DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
auto result = GetPropertyAttributesWithInterceptor(it);
@@ -1436,14 +1381,16 @@
}
}
-
-Maybe<bool> Object::HasInPrototypeChain(Isolate* isolate, Handle<Object> object,
- Handle<Object> proto) {
+Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
+ Handle<JSReceiver> object,
+ Handle<Object> proto) {
PrototypeIterator iter(isolate, object, PrototypeIterator::START_AT_RECEIVER);
while (true) {
if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
if (iter.IsAtEnd()) return Just(false);
- if (iter.IsAtEnd(proto)) return Just(true);
+ if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) {
+ return Just(true);
+ }
}
}
@@ -1544,25 +1491,22 @@
if (IsString() && other->IsString()) {
return String::cast(this)->Equals(String::cast(other));
}
- if (IsSimd128Value() && other->IsSimd128Value()) {
- 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 {
- Simd128Value* a = Simd128Value::cast(this);
- Simd128Value* b = Simd128Value::cast(other);
- return a->map()->instance_type() == b->map()->instance_type() &&
- a->BitwiseEquals(b);
+ 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;
}
@@ -1583,25 +1527,22 @@
if (IsString() && other->IsString()) {
return String::cast(this)->Equals(String::cast(other));
}
- if (IsSimd128Value() && other->IsSimd128Value()) {
- 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 {
- Simd128Value* a = Simd128Value::cast(this);
- Simd128Value* b = Simd128Value::cast(other);
- return a->map()->instance_type() == b->map()->instance_type() &&
- a->BitwiseEquals(b);
+ 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;
}
@@ -1610,8 +1551,14 @@
MaybeHandle<Object> Object::ArraySpeciesConstructor(
Isolate* isolate, Handle<Object> original_array) {
Handle<Context> native_context = isolate->native_context();
+ Handle<Object> default_species = isolate->array_function();
if (!FLAG_harmony_species) {
- return Handle<Object>(native_context->array_function(), isolate);
+ return default_species;
+ }
+ if (original_array->IsJSArray() &&
+ Handle<JSReceiver>::cast(original_array)->map()->new_target_is_base() &&
+ isolate->IsArraySpeciesLookupChainIntact()) {
+ return default_species;
}
Handle<Object> constructor = isolate->factory()->undefined_value();
Maybe<bool> is_array = Object::IsArray(original_array);
@@ -1645,7 +1592,7 @@
}
}
if (constructor->IsUndefined()) {
- return Handle<Object>(native_context->array_function(), isolate);
+ return default_species;
} else {
if (!constructor->IsConstructor()) {
THROW_NEW_ERROR(isolate,
@@ -2104,17 +2051,12 @@
os << "]\n";
}
-
-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,
- HeapType* old_field_type,
- HeapType* new_field_type) {
+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) {
OFStream os(file);
os << "[generalizing]";
Name* name = instance_descriptors()->GetKey(modify_index);
@@ -2128,11 +2070,19 @@
os << "c";
} else {
os << old_representation.Mnemonic() << "{";
- old_field_type->PrintTo(os, HeapType::SEMANTIC_DIM);
+ if (old_field_type.is_null()) {
+ os << Brief(*(old_value.ToHandleChecked()));
+ } else {
+ old_field_type.ToHandleChecked()->PrintTo(os);
+ }
os << "}";
}
os << "->" << new_representation.Mnemonic() << "{";
- new_field_type->PrintTo(os, HeapType::SEMANTIC_DIM);
+ if (new_field_type.is_null()) {
+ os << Brief(*(new_value.ToHandleChecked()));
+ } else {
+ new_field_type.ToHandleChecked()->PrintTo(os);
+ }
os << "} (";
if (strlen(reason) > 0) {
os << reason;
@@ -2569,33 +2519,31 @@
Context* JSReceiver::GetCreationContext() {
- if (IsJSBoundFunction()) {
- return JSBoundFunction::cast(this)->creation_context();
+ JSReceiver* receiver = this;
+ while (receiver->IsJSBoundFunction()) {
+ receiver = JSBoundFunction::cast(receiver)->bound_target_function();
}
- Object* constructor = map()->GetConstructor();
+ Object* constructor = receiver->map()->GetConstructor();
JSFunction* function;
if (constructor->IsJSFunction()) {
function = JSFunction::cast(constructor);
} else {
// Functions have null as a constructor,
// but any JSFunction knows its context immediately.
- CHECK(IsJSFunction());
- function = JSFunction::cast(this);
+ CHECK(receiver->IsJSFunction());
+ function = JSFunction::cast(receiver);
}
return function->context()->native_context();
}
-
-static Handle<Object> WrapType(Handle<HeapType> type) {
- if (type->IsClass()) return Map::WeakCellForMap(type->AsClass()->Map());
+static Handle<Object> WrapType(Handle<FieldType> type) {
+ if (type->IsClass()) return Map::WeakCellForMap(type->AsClass());
return type;
}
-
-MaybeHandle<Map> Map::CopyWithField(Handle<Map> map,
- Handle<Name> name,
- Handle<HeapType> type,
+MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name,
+ Handle<FieldType> type,
PropertyAttributes attributes,
Representation representation,
TransitionFlag flag) {
@@ -2615,7 +2563,7 @@
if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
representation = Representation::Tagged();
- type = HeapType::Any(isolate);
+ type = FieldType::Any(isolate);
}
Handle<Object> wrapped_type(WrapType(type));
@@ -2787,59 +2735,7 @@
}
}
-
-void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
- int expected_additional_properties) {
- if (object->map() == *new_map) return;
- // If this object is a prototype (the callee will check), invalidate any
- // prototype chains involving it.
- InvalidatePrototypeChains(object->map());
- Handle<Map> old_map(object->map());
-
- // If the map was registered with its prototype before, ensure that it
- // registers with its new prototype now. This preserves the invariant that
- // when a map on a prototype chain is registered with its prototype, then
- // all prototypes further up the chain are also registered with their
- // respective prototypes.
- UpdatePrototypeUserRegistration(old_map, new_map, new_map->GetIsolate());
-
- if (object->HasFastProperties()) {
- if (!new_map->is_dictionary_map()) {
- MigrateFastToFast(object, new_map);
- if (old_map->is_prototype_map()) {
- DCHECK(!old_map->is_stable());
- DCHECK(new_map->is_stable());
- // Clear out the old descriptor array to avoid problems to sharing
- // the descriptor array without using an explicit.
- old_map->InitializeDescriptors(
- old_map->GetHeap()->empty_descriptor_array(),
- LayoutDescriptor::FastPointerLayout());
- // Ensure that no transition was inserted for prototype migrations.
- DCHECK_EQ(0, TransitionArray::NumberOfTransitions(
- old_map->raw_transitions()));
- DCHECK(new_map->GetBackPointer()->IsUndefined());
- }
- } else {
- MigrateFastToSlow(object, new_map, expected_additional_properties);
- }
- } else {
- // For slow-to-fast migrations JSObject::MigrateSlowToFast()
- // must be used instead.
- CHECK(new_map->is_dictionary_map());
-
- // Slow-to-slow migration is trivial.
- object->set_map(*new_map);
- }
-
- // Careful: Don't allocate here!
- // For some callers of this method, |object| might be in an inconsistent
- // state now: the new map might have a new elements_kind, but the object's
- // elements pointer hasn't been updated yet. Callers will fix this, but in
- // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
- // When adding code here, add a DisallowHeapAllocation too.
-}
-
-
+namespace {
// To migrate a fast instance to a fast map:
// - First check whether the instance needs to be rewritten. If not, simply
// change the map.
@@ -2855,9 +2751,71 @@
// to temporarily store the inobject properties.
// * If there are properties left in the backing store, install the backing
// store.
-void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
+void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
Isolate* isolate = object->GetIsolate();
Handle<Map> old_map(object->map());
+ // In case of a regular transition.
+ if (new_map->GetBackPointer() == *old_map) {
+ // If the map does not add named properties, simply set the map.
+ if (old_map->NumberOfOwnDescriptors() ==
+ new_map->NumberOfOwnDescriptors()) {
+ object->synchronized_set_map(*new_map);
+ return;
+ }
+
+ PropertyDetails details = new_map->GetLastDescriptorDetails();
+ // Either new_map adds an kDescriptor property, or a kField property for
+ // which there is still space, and which does not require a mutable double
+ // box (an out-of-object double).
+ if (details.location() == kDescriptor ||
+ (old_map->unused_property_fields() > 0 &&
+ ((FLAG_unbox_double_fields && object->properties()->length() == 0) ||
+ !details.representation().IsDouble()))) {
+ object->synchronized_set_map(*new_map);
+ return;
+ }
+
+ // If there is still space in the object, we need to allocate a mutable
+ // double box.
+ if (old_map->unused_property_fields() > 0) {
+ FieldIndex index =
+ FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
+ DCHECK(details.representation().IsDouble());
+ DCHECK(!new_map->IsUnboxedDoubleField(index));
+ Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE);
+ object->RawFastPropertyAtPut(index, *value);
+ object->synchronized_set_map(*new_map);
+ return;
+ }
+
+ // This migration is a transition from a map that has run out of property
+ // space. Extend the backing store.
+ int grow_by = new_map->unused_property_fields() + 1;
+ Handle<FixedArray> old_storage = handle(object->properties(), isolate);
+ Handle<FixedArray> new_storage =
+ isolate->factory()->CopyFixedArrayAndGrow(old_storage, grow_by);
+
+ // Properly initialize newly added property.
+ Handle<Object> value;
+ if (details.representation().IsDouble()) {
+ value = isolate->factory()->NewHeapNumber(0, MUTABLE);
+ } else {
+ value = isolate->factory()->uninitialized_value();
+ }
+ DCHECK_EQ(DATA, details.type());
+ 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);
+
+ // From here on we cannot fail and we shouldn't GC anymore.
+ DisallowHeapAllocation no_allocation;
+
+ // Set the new property value and do the map transition.
+ object->set_properties(*new_storage);
+ object->synchronized_set_map(*new_map);
+ return;
+ }
+
int old_number_of_fields;
int number_of_fields = new_map->NumberOfFields();
int inobject = new_map->GetInObjectProperties();
@@ -2874,53 +2832,6 @@
int total_size = number_of_fields + unused;
int external = total_size - inobject;
- if (number_of_fields != old_number_of_fields &&
- new_map->GetBackPointer() == *old_map) {
- PropertyDetails details = new_map->GetLastDescriptorDetails();
-
- if (old_map->unused_property_fields() > 0) {
- if (details.representation().IsDouble()) {
- FieldIndex index =
- FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
- if (new_map->IsUnboxedDoubleField(index)) {
- object->RawFastDoublePropertyAtPut(index, 0);
- } else {
- Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE);
- object->RawFastPropertyAtPut(index, *value);
- }
- }
- object->synchronized_set_map(*new_map);
- return;
- }
-
- DCHECK(number_of_fields == old_number_of_fields + 1);
- // This migration is a transition from a map that has run out of property
- // space. Therefore it could be done by extending the backing store.
- int grow_by = external - object->properties()->length();
- Handle<FixedArray> old_storage = handle(object->properties(), isolate);
- Handle<FixedArray> new_storage =
- isolate->factory()->CopyFixedArrayAndGrow(old_storage, grow_by);
-
- // Properly initialize newly added property.
- Handle<Object> value;
- if (details.representation().IsDouble()) {
- value = isolate->factory()->NewHeapNumber(0, MUTABLE);
- } else {
- value = isolate->factory()->uninitialized_value();
- }
- DCHECK(details.type() == DATA);
- int target_index = details.field_index() - inobject;
- DCHECK(target_index >= 0); // Must be a backing store index.
- new_storage->set(target_index, *value);
-
- // From here on we cannot fail and we shouldn't GC anymore.
- DisallowHeapAllocation no_allocation;
-
- // Set the new property value and do the map transition.
- object->set_properties(*new_storage);
- object->synchronized_set_map(*new_map);
- return;
- }
Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size);
Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
@@ -2994,6 +2905,8 @@
// From here on we cannot fail and we shouldn't GC anymore.
DisallowHeapAllocation no_allocation;
+ Heap* heap = isolate->heap();
+
// 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);
@@ -3006,12 +2919,16 @@
DCHECK(value->IsMutableHeapNumber());
object->RawFastDoublePropertyAtPut(index,
HeapNumber::cast(value)->value());
+ 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 {
object->RawFastPropertyAtPut(index, value);
}
}
- Heap* heap = isolate->heap();
// If there are properties in the new backing store, trim it to the correct
// size and install the backing store into the object.
@@ -3038,6 +2955,173 @@
object->synchronized_set_map(*new_map);
}
+void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
+ int expected_additional_properties) {
+ // The global object is always normalized.
+ DCHECK(!object->IsJSGlobalObject());
+ // JSGlobalProxy must never be normalized
+ DCHECK(!object->IsJSGlobalProxy());
+
+ Isolate* isolate = object->GetIsolate();
+ HandleScope scope(isolate);
+ Handle<Map> map(object->map());
+
+ // Allocate new content.
+ int real_size = map->NumberOfOwnDescriptors();
+ int property_count = real_size;
+ if (expected_additional_properties > 0) {
+ property_count += expected_additional_properties;
+ } else {
+ property_count += 2; // Make space for two more properties.
+ }
+ Handle<NameDictionary> dictionary =
+ NameDictionary::New(isolate, property_count);
+
+ Handle<DescriptorArray> descs(map->instance_descriptors());
+ 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;
+ if (object->IsUnboxedDoubleField(index)) {
+ double old_value = object->RawFastDoublePropertyAt(index);
+ value = isolate->factory()->NewHeapNumber(old_value);
+ } else {
+ value = handle(object->RawFastPropertyAt(index), isolate);
+ if (details.representation().IsDouble()) {
+ DCHECK(value->IsMutableHeapNumber());
+ Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
+ 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;
+ }
+ }
+ }
+
+ // Copy the next enumeration index from instance descriptor.
+ dictionary->SetNextEnumerationIndex(real_size + 1);
+
+ // From here on we cannot fail and we shouldn't GC anymore.
+ DisallowHeapAllocation 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);
+ heap->AdjustLiveBytes(*object, -instance_size_delta,
+ Heap::CONCURRENT_TO_SWEEPER);
+ }
+
+ // We are storing the new map using release store after creating a filler for
+ // the left-over space to avoid races with the sweeper thread.
+ object->synchronized_set_map(*new_map);
+
+ object->set_properties(*dictionary);
+
+ // Ensure that in-object space of slow-mode object does not contain random
+ // garbage.
+ int inobject_properties = new_map->GetInObjectProperties();
+ for (int i = 0; i < inobject_properties; i++) {
+ FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
+ object->RawFastPropertyAtPut(index, Smi::FromInt(0));
+ }
+
+ isolate->counters()->props_to_dictionary()->Increment();
+
+#ifdef DEBUG
+ if (FLAG_trace_normalization) {
+ OFStream os(stdout);
+ os << "Object properties have been normalized:\n";
+ object->Print(os);
+ }
+#endif
+}
+
+} // namespace
+
+void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
+ int expected_additional_properties) {
+ if (object->map() == *new_map) return;
+ Handle<Map> old_map(object->map());
+ if (old_map->is_prototype_map()) {
+ // If this object is a prototype (the callee will check), invalidate any
+ // prototype chains involving it.
+ InvalidatePrototypeChains(object->map());
+
+ // If the map was registered with its prototype before, ensure that it
+ // registers with its new prototype now. This preserves the invariant that
+ // when a map on a prototype chain is registered with its prototype, then
+ // all prototypes further up the chain are also registered with their
+ // respective prototypes.
+ UpdatePrototypeUserRegistration(old_map, new_map, new_map->GetIsolate());
+ }
+
+ if (old_map->is_dictionary_map()) {
+ // For slow-to-fast migrations JSObject::MigrateSlowToFast()
+ // must be used instead.
+ CHECK(new_map->is_dictionary_map());
+
+ // Slow-to-slow migration is trivial.
+ object->set_map(*new_map);
+ } else if (!new_map->is_dictionary_map()) {
+ MigrateFastToFast(object, new_map);
+ if (old_map->is_prototype_map()) {
+ DCHECK(!old_map->is_stable());
+ DCHECK(new_map->is_stable());
+ // Clear out the old descriptor array to avoid problems to sharing
+ // the descriptor array without using an explicit.
+ old_map->InitializeDescriptors(
+ old_map->GetHeap()->empty_descriptor_array(),
+ LayoutDescriptor::FastPointerLayout());
+ // Ensure that no transition was inserted for prototype migrations.
+ DCHECK_EQ(
+ 0, TransitionArray::NumberOfTransitions(old_map->raw_transitions()));
+ DCHECK(new_map->GetBackPointer()->IsUndefined());
+ }
+ } else {
+ MigrateFastToSlow(object, new_map, expected_additional_properties);
+ }
+
+ // Careful: Don't allocate here!
+ // For some callers of this method, |object| might be in an inconsistent
+ // state now: the new map might have a new elements_kind, but the object's
+ // elements pointer hasn't been updated yet. Callers will fix this, but in
+ // the meantime, (indirectly) calling JSObjectVerify() must be avoided.
+ // When adding code here, add a DisallowHeapAllocation too.
+}
int Map::NumberOfFields() {
DescriptorArray* descriptors = instance_descriptors();
@@ -3061,7 +3145,7 @@
for (int i = 0; i < number_of_own_descriptors; i++) {
descriptors->SetRepresentation(i, Representation::Tagged());
if (descriptors->GetDetails(i).type() == DATA) {
- descriptors->SetValue(i, HeapType::Any());
+ descriptors->SetValue(i, FieldType::Any());
}
}
@@ -3093,16 +3177,18 @@
}
if (FLAG_trace_generalization) {
- HeapType* field_type =
- (details.type() == DATA)
- ? map->instance_descriptors()->GetFieldType(modify_index)
- : NULL;
+ MaybeHandle<FieldType> field_type = FieldType::None(isolate);
+ if (details.type() == DATA) {
+ 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,
details.representation(), Representation::Tagged(), field_type,
- HeapType::Any());
+ MaybeHandle<Object>(), FieldType::Any(isolate),
+ MaybeHandle<Object>());
}
}
return new_map;
@@ -3195,7 +3281,7 @@
if (!details.representation().Equals(next_details.representation())) break;
if (next_details.location() == kField) {
- HeapType* next_field_type = next_descriptors->GetFieldType(i);
+ FieldType* next_field_type = next_descriptors->GetFieldType(i);
if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
break;
}
@@ -3251,42 +3337,41 @@
instance_descriptors()->Replace(descriptor, &d);
}
-
-bool FieldTypeIsCleared(Representation rep, HeapType* type) {
- return type->Is(HeapType::None()) && rep.IsHeapObject();
+bool FieldTypeIsCleared(Representation rep, FieldType* type) {
+ return type->IsNone() && rep.IsHeapObject();
}
// static
-Handle<HeapType> Map::GeneralizeFieldType(Representation rep1,
- Handle<HeapType> type1,
- Representation rep2,
- Handle<HeapType> type2,
- Isolate* isolate) {
+Handle<FieldType> Map::GeneralizeFieldType(Representation rep1,
+ Handle<FieldType> type1,
+ Representation rep2,
+ Handle<FieldType> type2,
+ Isolate* isolate) {
// Cleared field types need special treatment. They represent lost knowledge,
// so we must be conservative, so their generalization with any other type
// is "Any".
if (FieldTypeIsCleared(rep1, *type1) || FieldTypeIsCleared(rep2, *type2)) {
- return HeapType::Any(isolate);
+ return FieldType::Any(isolate);
}
if (type1->NowIs(type2)) return type2;
if (type2->NowIs(type1)) return type1;
- return HeapType::Any(isolate);
+ return FieldType::Any(isolate);
}
// static
void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
Representation new_representation,
- Handle<HeapType> new_field_type) {
+ 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();
- Handle<HeapType> old_field_type(old_descriptors->GetFieldType(modify_index),
- isolate);
+ Handle<FieldType> old_field_type(old_descriptors->GetFieldType(modify_index),
+ isolate);
if (old_representation.Equals(new_representation) &&
!FieldTypeIsCleared(new_representation, *new_field_type) &&
@@ -3320,20 +3405,16 @@
if (FLAG_trace_generalization) {
map->PrintGeneralization(
- stdout, "field type generalization",
- modify_index, map->NumberOfOwnDescriptors(),
- map->NumberOfOwnDescriptors(), false,
- details.representation(), details.representation(),
- *old_field_type, *new_field_type);
+ stdout, "field type generalization", modify_index,
+ map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false,
+ details.representation(), details.representation(), old_field_type,
+ MaybeHandle<Object>(), new_field_type, MaybeHandle<Object>());
}
}
-
-static inline Handle<HeapType> GetFieldType(Isolate* isolate,
- Handle<DescriptorArray> descriptors,
- int descriptor,
- PropertyLocation location,
- Representation representation) {
+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());
@@ -3378,7 +3459,7 @@
PropertyKind new_kind,
PropertyAttributes new_attributes,
Representation new_representation,
- Handle<HeapType> new_field_type,
+ 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);
@@ -3407,8 +3488,9 @@
stdout, "uninitialized field", modify_index,
old_map->NumberOfOwnDescriptors(),
old_map->NumberOfOwnDescriptors(), false, old_representation,
- new_representation, old_descriptors->GetFieldType(modify_index),
- *new_field_type);
+ 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);
@@ -3524,11 +3606,11 @@
PropertyLocation tmp_location = tmp_details.location();
if (tmp_location == kField) {
if (next_kind == kData) {
- Handle<HeapType> next_field_type;
+ Handle<FieldType> next_field_type;
if (modify_index == i) {
next_field_type = new_field_type;
if (!property_kind_reconfiguration) {
- Handle<HeapType> old_field_type =
+ Handle<FieldType> old_field_type =
GetFieldType(isolate, old_descriptors, i,
old_details.location(), tmp_representation);
Representation old_representation = old_details.representation();
@@ -3537,7 +3619,7 @@
next_field_type, isolate);
}
} else {
- Handle<HeapType> old_field_type =
+ Handle<FieldType> old_field_type =
GetFieldType(isolate, old_descriptors, i, old_details.location(),
tmp_representation);
next_field_type = old_field_type;
@@ -3692,17 +3774,17 @@
if (next_location == kField) {
if (next_kind == kData) {
- Handle<HeapType> target_field_type =
+ Handle<FieldType> target_field_type =
GetFieldType(isolate, target_descriptors, i,
target_details.location(), next_representation);
- Handle<HeapType> next_field_type;
+ 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<HeapType> old_field_type =
+ Handle<FieldType> old_field_type =
GetFieldType(isolate, old_descriptors, i,
old_details.location(), next_representation);
next_field_type = GeneralizeFieldType(
@@ -3710,7 +3792,7 @@
next_representation, next_field_type, isolate);
}
} else {
- Handle<HeapType> old_field_type =
+ Handle<FieldType> old_field_type =
GetFieldType(isolate, old_descriptors, i, old_details.location(),
next_representation);
next_field_type = GeneralizeFieldType(
@@ -3769,11 +3851,11 @@
if (next_location == kField) {
if (next_kind == kData) {
- Handle<HeapType> next_field_type;
+ Handle<FieldType> next_field_type;
if (modify_index == i) {
next_field_type = new_field_type;
if (!property_kind_reconfiguration) {
- Handle<HeapType> old_field_type =
+ Handle<FieldType> old_field_type =
GetFieldType(isolate, old_descriptors, i,
old_details.location(), next_representation);
next_field_type = GeneralizeFieldType(
@@ -3781,7 +3863,7 @@
next_representation, next_field_type, isolate);
}
} else {
- Handle<HeapType> old_field_type =
+ Handle<FieldType> old_field_type =
GetFieldType(isolate, old_descriptors, i, old_details.location(),
next_representation);
next_field_type = old_field_type;
@@ -3849,23 +3931,28 @@
if (FLAG_trace_generalization && modify_index >= 0) {
PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
- Handle<HeapType> old_field_type =
- (old_details.type() == DATA)
- ? handle(old_descriptors->GetFieldType(modify_index), isolate)
- : HeapType::Constant(
- handle(old_descriptors->GetValue(modify_index), isolate),
- isolate);
- Handle<HeapType> new_field_type =
- (new_details.type() == DATA)
- ? handle(new_descriptors->GetFieldType(modify_index), isolate)
- : HeapType::Constant(
- handle(new_descriptors->GetValue(modify_index), isolate),
- isolate);
+ 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, *new_field_type);
+ old_field_type, old_value, new_field_type, new_value);
}
Handle<LayoutDescriptor> new_layout_descriptor =
@@ -3891,7 +3978,7 @@
if (details.type() == DATA) {
map = ReconfigureProperty(map, i, kData, details.attributes(),
Representation::Tagged(),
- HeapType::Any(map->GetIsolate()), FORCE_FIELD);
+ FieldType::Any(map->GetIsolate()), FORCE_FIELD);
}
}
return map;
@@ -3940,7 +4027,7 @@
}
switch (new_details.type()) {
case DATA: {
- HeapType* new_type = new_descriptors->GetFieldType(i);
+ 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)) {
@@ -3948,7 +4035,7 @@
}
PropertyType old_property_type = old_details.type();
if (old_property_type == DATA) {
- HeapType* old_type = old_descriptors->GetFieldType(i);
+ FieldType* old_type = old_descriptors->GetFieldType(i);
if (FieldTypeIsCleared(old_details.representation(), old_type) ||
!old_type->NowIs(new_type)) {
return MaybeHandle<Map>();
@@ -3964,8 +4051,8 @@
}
case ACCESSOR: {
#ifdef DEBUG
- HeapType* new_type = new_descriptors->GetFieldType(i);
- DCHECK(HeapType::Any()->Is(new_type));
+ FieldType* new_type = new_descriptors->GetFieldType(i);
+ DCHECK(new_type->IsAny());
#endif
break;
}
@@ -3990,12 +4077,13 @@
Handle<Map> Map::Update(Handle<Map> map) {
if (!map->is_deprecated()) return map;
return ReconfigureProperty(map, -1, kData, NONE, Representation::None(),
- HeapType::None(map->GetIsolate()),
+ FieldType::None(map->GetIsolate()),
ALLOW_IN_DESCRIPTOR);
}
Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
+ ShouldThrow should_throw,
Handle<Object> value) {
Isolate* isolate = it->isolate();
// Make sure that the top context does not change when doing callbacks or
@@ -4009,7 +4097,7 @@
Handle<JSObject> holder = it->GetHolder<JSObject>();
v8::Local<v8::Value> result;
PropertyCallbackArguments args(isolate, interceptor->data(),
- *it->GetReceiver(), *holder);
+ *it->GetReceiver(), *holder, should_throw);
if (it->IsElement()) {
uint32_t index = it->index();
@@ -4062,6 +4150,7 @@
LanguageMode language_mode,
StoreFromKeyed store_mode,
bool* found) {
+ it->UpdateProtector();
ShouldThrow should_throw =
is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
@@ -4090,7 +4179,8 @@
case LookupIterator::INTERCEPTOR:
if (it->HolderIsReceiverOrHiddenPrototype()) {
- Maybe<bool> result = JSObject::SetPropertyWithInterceptor(it, value);
+ Maybe<bool> result =
+ JSObject::SetPropertyWithInterceptor(it, should_throw, value);
if (result.IsNothing() || result.FromJust()) return result;
} else {
Maybe<PropertyAttributes> maybe_attributes =
@@ -4155,16 +4245,12 @@
Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
LanguageMode language_mode,
StoreFromKeyed store_mode) {
- ShouldThrow should_throw =
- is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
- if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) {
- RETURN_FAILURE(it->isolate(), should_throw,
- NewTypeError(MessageTemplate::kProxyPrivate));
- }
bool found = false;
Maybe<bool> result =
SetPropertyInternal(it, value, language_mode, store_mode, &found);
if (found) return result;
+ ShouldThrow should_throw =
+ is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
return AddDataProperty(it, value, NONE, should_throw, store_mode);
}
@@ -4172,13 +4258,7 @@
Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
LanguageMode language_mode,
StoreFromKeyed store_mode) {
- ShouldThrow should_throw =
- is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
Isolate* isolate = it->isolate();
- if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) {
- RETURN_FAILURE(isolate, should_throw,
- NewTypeError(MessageTemplate::kProxyPrivate));
- }
bool found = false;
Maybe<bool> result =
@@ -4188,6 +4268,9 @@
// The property either doesn't exist on the holder or exists there as a data
// property.
+ ShouldThrow should_throw =
+ is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
+
if (!it->GetReceiver()->IsJSReceiver()) {
return WriteToReadOnlyProperty(it, value, should_throw);
}
@@ -4207,14 +4290,21 @@
}
break;
- case LookupIterator::INTEGER_INDEXED_EXOTIC:
case LookupIterator::ACCESSOR:
+ if (own_lookup.GetAccessors()->IsAccessorInfo()) {
+ if (own_lookup.IsReadOnly()) {
+ return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
+ }
+ return JSObject::SetPropertyWithAccessor(&own_lookup, value,
+ should_throw);
+ }
+ // Fall through.
+ case LookupIterator::INTEGER_INDEXED_EXOTIC:
return RedefineIncompatibleProperty(isolate, it->GetName(), value,
should_throw);
case LookupIterator::DATA: {
- PropertyDetails details = own_lookup.property_details();
- if (details.IsReadOnly()) {
+ if (own_lookup.IsReadOnly()) {
return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
}
return SetDataProperty(&own_lookup, value);
@@ -4252,28 +4342,13 @@
store_mode);
}
-
-MaybeHandle<Object> Object::ReadAbsentProperty(LookupIterator* it,
- LanguageMode language_mode) {
- if (is_strong(language_mode)) {
- THROW_NEW_ERROR(it->isolate(),
- NewTypeError(MessageTemplate::kStrongPropertyAccess,
- it->GetName(), it->GetReceiver()),
- Object);
- }
+MaybeHandle<Object> Object::ReadAbsentProperty(LookupIterator* it) {
return it->isolate()->factory()->undefined_value();
}
MaybeHandle<Object> Object::ReadAbsentProperty(Isolate* isolate,
Handle<Object> receiver,
- Handle<Object> name,
- LanguageMode language_mode) {
- if (is_strong(language_mode)) {
- THROW_NEW_ERROR(
- isolate,
- NewTypeError(MessageTemplate::kStrongPropertyAccess, name, receiver),
- Object);
- }
+ Handle<Object> name) {
return isolate->factory()->undefined_value();
}
@@ -4330,8 +4405,7 @@
// Fetch before transforming the object since the encoding may become
// incompatible with what's cached in |it|.
bool is_observed = receiver->map()->is_observed() &&
- (it->IsElement() ||
- !it->isolate()->IsInternallyUsedPropertyName(it->name()));
+ (it->IsElement() || !it->name()->IsPrivate());
MaybeHandle<Object> maybe_old;
if (is_observed) maybe_old = it->GetDataValue();
@@ -4341,13 +4415,6 @@
if (!value->IsNumber() && !value->IsUndefined()) {
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>());
- // ToNumber above might modify the receiver, causing the cached
- // holder_map to mismatch the actual holder->map() after this point.
- // Reload the map to be in consistent state. Other cached state cannot
- // have been invalidated since typed array elements cannot be reconfigured
- // in any way.
- it->ReloadHolderMap();
-
// We have to recheck the length. However, it can only change if the
// underlying buffer was neutered, so just check that.
if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) {
@@ -4427,8 +4494,11 @@
PropertyAttributes attributes,
ShouldThrow should_throw,
StoreFromKeyed store_mode) {
- DCHECK(!it->GetReceiver()->IsJSProxy());
if (!it->GetReceiver()->IsJSObject()) {
+ if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) {
+ RETURN_FAILURE(it->isolate(), should_throw,
+ NewTypeError(MessageTemplate::kProxyPrivate));
+ }
return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(),
value, should_throw);
}
@@ -4443,8 +4513,7 @@
Isolate* isolate = it->isolate();
- if (!receiver->map()->is_extensible() &&
- (it->IsElement() || !isolate->IsInternallyUsedPropertyName(it->name()))) {
+ if (it->ExtendingNonExtensible(receiver)) {
RETURN_FAILURE(
isolate, should_throw,
NewTypeError(MessageTemplate::kObjectNotExtensible, it->GetName()));
@@ -4477,14 +4546,13 @@
} else {
// Migrate to the most up-to-date map that will be able to store |value|
// under it->name() with |attributes|.
- it->PrepareTransitionToDataProperty(value, attributes, store_mode);
+ it->PrepareTransitionToDataProperty(receiver, value, attributes,
+ store_mode);
DCHECK_EQ(LookupIterator::TRANSITION, it->state());
- it->ApplyTransitionToDataProperty();
+ it->ApplyTransitionToDataProperty(receiver);
// TODO(verwaest): Encapsulate dictionary handling better.
if (receiver->map()->is_dictionary_map()) {
- // TODO(verwaest): Probably should ensure this is done beforehand.
- it->InternalizeName();
// TODO(dcarney): just populate TransitionPropertyCell here?
JSObject::AddSlowProperty(receiver, it->name(), value, attributes);
} else {
@@ -4493,8 +4561,7 @@
}
// Send the change record if there are observers.
- if (receiver->map()->is_observed() &&
- !isolate->IsInternallyUsedPropertyName(it->name())) {
+ if (receiver->map()->is_observed() && !it->name()->IsPrivate()) {
RETURN_ON_EXCEPTION_VALUE(isolate, JSObject::EnqueueChangeRecord(
receiver, "add", it->name(),
it->factory()->the_hole_value()),
@@ -5195,8 +5262,7 @@
Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
DCHECK(maybe.IsJust());
DCHECK(!it.IsFound());
- DCHECK(object->map()->is_extensible() ||
- it.isolate()->IsInternallyUsedPropertyName(name));
+ DCHECK(object->map()->is_extensible() || name->IsPrivate());
#endif
CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR,
CERTAINLY_NOT_STORE_FROM_KEYED)
@@ -5204,20 +5270,13 @@
}
-// static
-void ExecutableAccessorInfo::ClearSetter(Handle<ExecutableAccessorInfo> info) {
- Handle<Object> object = v8::FromCData(info->GetIsolate(), nullptr);
- info->set_setter(*object);
-}
-
-
// Reconfigures a property to a data property with attributes, even if it is not
// reconfigurable.
// Requires a LookupIterator that does not look at the prototype chain beyond
// hidden prototypes.
MaybeHandle<Object> JSObject::DefineOwnPropertyIgnoreAttributes(
LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
- ExecutableAccessorInfoHandling handling) {
+ AccessorInfoHandling handling) {
MAYBE_RETURN_NULL(DefineOwnPropertyIgnoreAttributes(
it, value, attributes, THROW_ON_ERROR, handling));
return value;
@@ -5226,11 +5285,11 @@
Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
- ShouldThrow should_throw, ExecutableAccessorInfoHandling handling) {
+ ShouldThrow should_throw, AccessorInfoHandling handling) {
+ it->UpdateProtector();
Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
bool is_observed = object->map()->is_observed() &&
- (it->IsElement() ||
- !it->isolate()->IsInternallyUsedPropertyName(it->name()));
+ (it->IsElement() || !it->name()->IsPrivate());
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
@@ -5257,7 +5316,8 @@
// they throw. Here we should do the same.
case LookupIterator::INTERCEPTOR:
if (handling == DONT_FORCE_FIELD) {
- Maybe<bool> result = JSObject::SetPropertyWithInterceptor(it, value);
+ Maybe<bool> result =
+ JSObject::SetPropertyWithInterceptor(it, should_throw, value);
if (result.IsNothing() || result.FromJust()) return result;
}
break;
@@ -5265,32 +5325,26 @@
case LookupIterator::ACCESSOR: {
Handle<Object> accessors = it->GetAccessors();
- // Special handling for ExecutableAccessorInfo, which behaves like a
- // data property.
- if (accessors->IsExecutableAccessorInfo() &&
- handling == DONT_FORCE_FIELD) {
- PropertyDetails details = it->property_details();
+ // Special handling for AccessorInfo, which behaves like a data
+ // property.
+ if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
+ PropertyAttributes current_attributes = it->property_attributes();
// Ensure the context isn't changed after calling into accessors.
AssertNoContextChange ncc(it->isolate());
- Maybe<bool> result =
- JSObject::SetPropertyWithAccessor(it, value, should_throw);
- if (result.IsNothing() || !result.FromJust()) return result;
-
- if (details.attributes() == attributes) return Just(true);
-
- // Reconfigure the accessor if attributes mismatch.
- Handle<ExecutableAccessorInfo> new_data = Accessors::CloneAccessor(
- it->isolate(), Handle<ExecutableAccessorInfo>::cast(accessors));
- new_data->set_property_attributes(attributes);
- // By clearing the setter we don't have to introduce a lookup to
- // the setter, simply make it unavailable to reflect the
- // attributes.
- if (attributes & READ_ONLY) {
- ExecutableAccessorInfo::ClearSetter(new_data);
+ // Update the attributes before calling the setter. The setter may
+ // later change the shape of the property.
+ if (current_attributes != attributes) {
+ it->TransitionToAccessorPair(accessors, attributes);
}
- it->TransitionToAccessorPair(new_data, attributes);
+ Maybe<bool> result =
+ JSObject::SetPropertyWithAccessor(it, value, should_throw);
+
+ if (current_attributes == attributes || result.IsNothing()) {
+ return result;
+ }
+
} else {
it->ReconfigureDataProperty(value, attributes);
}
@@ -5310,10 +5364,9 @@
should_throw);
case LookupIterator::DATA: {
- PropertyDetails details = it->property_details();
Handle<Object> old_value = it->factory()->the_hole_value();
// Regular property update if the attributes match.
- if (details.attributes() == attributes) {
+ if (it->property_attributes() == attributes) {
return SetDataProperty(it, value);
}
@@ -5347,32 +5400,29 @@
CERTAINLY_NOT_STORE_FROM_KEYED);
}
-
MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
- PropertyAttributes attributes, ExecutableAccessorInfoHandling handling) {
+ PropertyAttributes attributes) {
DCHECK(!value->IsTheHole());
LookupIterator it(object, name, LookupIterator::OWN);
- return DefineOwnPropertyIgnoreAttributes(&it, value, attributes, handling);
+ return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
}
-
MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes(
Handle<JSObject> object, uint32_t index, Handle<Object> value,
- PropertyAttributes attributes, ExecutableAccessorInfoHandling handling) {
+ PropertyAttributes attributes) {
Isolate* isolate = object->GetIsolate();
LookupIterator it(isolate, object, index, LookupIterator::OWN);
- return DefineOwnPropertyIgnoreAttributes(&it, value, attributes, handling);
+ return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
}
-
MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
- PropertyAttributes attributes, ExecutableAccessorInfoHandling handling) {
+ PropertyAttributes attributes) {
Isolate* isolate = object->GetIsolate();
LookupIterator it = LookupIterator::PropertyOrElement(isolate, object, name,
LookupIterator::OWN);
- return DefineOwnPropertyIgnoreAttributes(&it, value, attributes, handling);
+ return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
}
@@ -5391,7 +5441,8 @@
return Just(ABSENT);
}
PropertyCallbackArguments args(isolate, interceptor->data(),
- *it->GetReceiver(), *holder);
+ *it->GetReceiver(), *holder,
+ Object::DONT_THROW);
if (!interceptor->query()->IsUndefined()) {
v8::Local<v8::Integer> result;
if (it->IsElement()) {
@@ -5468,7 +5519,7 @@
return Just(ABSENT);
case LookupIterator::ACCESSOR:
case LookupIterator::DATA:
- return Just(it->property_details().attributes());
+ return Just(it->property_attributes());
}
}
return Just(ABSENT);
@@ -5531,123 +5582,6 @@
}
-void JSObject::MigrateFastToSlow(Handle<JSObject> object,
- Handle<Map> new_map,
- int expected_additional_properties) {
- // The global object is always normalized.
- DCHECK(!object->IsJSGlobalObject());
- // JSGlobalProxy must never be normalized
- DCHECK(!object->IsJSGlobalProxy());
-
- Isolate* isolate = object->GetIsolate();
- HandleScope scope(isolate);
- Handle<Map> map(object->map());
-
- // Allocate new content.
- int real_size = map->NumberOfOwnDescriptors();
- int property_count = real_size;
- if (expected_additional_properties > 0) {
- property_count += expected_additional_properties;
- } else {
- property_count += 2; // Make space for two more properties.
- }
- Handle<NameDictionary> dictionary =
- NameDictionary::New(isolate, property_count);
-
- Handle<DescriptorArray> descs(map->instance_descriptors());
- 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;
- if (object->IsUnboxedDoubleField(index)) {
- double old_value = object->RawFastDoublePropertyAt(index);
- value = isolate->factory()->NewHeapNumber(old_value);
- } else {
- value = handle(object->RawFastPropertyAt(index), isolate);
- if (details.representation().IsDouble()) {
- DCHECK(value->IsMutableHeapNumber());
- Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
- 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;
- }
- }
- }
-
- // Copy the next enumeration index from instance descriptor.
- dictionary->SetNextEnumerationIndex(real_size + 1);
-
- // From here on we cannot fail and we shouldn't GC anymore.
- DisallowHeapAllocation 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);
- heap->AdjustLiveBytes(*object, -instance_size_delta,
- Heap::CONCURRENT_TO_SWEEPER);
- }
-
- // We are storing the new map using release store after creating a filler for
- // the left-over space to avoid races with the sweeper thread.
- object->synchronized_set_map(*new_map);
-
- object->set_properties(*dictionary);
-
- // Ensure that in-object space of slow-mode object does not contain random
- // garbage.
- int inobject_properties = new_map->GetInObjectProperties();
- for (int i = 0; i < inobject_properties; i++) {
- FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
- object->RawFastPropertyAtPut(index, Smi::FromInt(0));
- }
-
- isolate->counters()->props_to_dictionary()->Increment();
-
-#ifdef DEBUG
- if (FLAG_trace_normalization) {
- OFStream os(stdout);
- os << "Object properties have been normalized:\n";
- object->Print(os);
- }
-#endif
-}
-
-
void JSObject::MigrateSlowToFast(Handle<JSObject> object,
int unused_property_fields,
const char* reason) {
@@ -5717,7 +5651,7 @@
// Allocate the instance descriptor.
Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
- isolate, instance_descriptor_length);
+ isolate, instance_descriptor_length, 0, TENURED);
int number_of_allocated_fields =
number_of_fields + unused_property_fields - inobject_props;
@@ -5885,14 +5819,18 @@
DCHECK(object->HasFastSmiOrObjectElements() ||
object->HasFastDoubleElements() ||
- object->HasFastArgumentsElements());
+ object->HasFastArgumentsElements() ||
+ object->HasFastStringWrapperElements());
Handle<SeededNumberDictionary> dictionary =
GetNormalizedElementDictionary(object, elements);
// Switch to using the dictionary as the backing storage for elements.
- ElementsKind target_kind =
- is_arguments ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS : DICTIONARY_ELEMENTS;
+ ElementsKind target_kind = is_arguments
+ ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
+ : object->HasFastStringWrapperElements()
+ ? SLOW_STRING_WRAPPER_ELEMENTS
+ : DICTIONARY_ELEMENTS;
Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
// Set the new map first to satify the elements type assert in set_elements().
JSObject::MigrateToMap(object, new_map);
@@ -5913,7 +5851,9 @@
}
#endif
- DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements());
+ DCHECK(object->HasDictionaryElements() ||
+ object->HasSlowArgumentsElements() ||
+ object->HasSlowStringWrapperElements());
return dictionary;
}
@@ -6076,10 +6016,12 @@
bool JSObject::HasHiddenProperties(Handle<JSObject> object) {
- Handle<Name> hidden = object->GetIsolate()->factory()->hidden_string();
- LookupIterator it(object, hidden, LookupIterator::OWN_SKIP_INTERCEPTOR);
+ Isolate* isolate = object->GetIsolate();
+ Handle<Symbol> hidden = isolate->factory()->hidden_properties_symbol();
+ LookupIterator it(object, hidden);
Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
- // Cannot get an exception since the hidden_string isn't accessible to JS.
+ // Cannot get an exception since the hidden_properties_symbol isn't exposed to
+ // JS.
DCHECK(maybe.IsJust());
return maybe.FromJust() != ABSENT;
}
@@ -6095,7 +6037,8 @@
DescriptorArray* descriptors = this->map()->instance_descriptors();
if (descriptors->number_of_descriptors() > 0) {
int sorted_index = descriptors->GetSortedKeyIndex(0);
- if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() &&
+ if (descriptors->GetKey(sorted_index) ==
+ GetHeap()->hidden_properties_symbol() &&
sorted_index < map()->NumberOfOwnDescriptors()) {
DCHECK(descriptors->GetType(sorted_index) == DATA);
DCHECK(descriptors->GetDetails(sorted_index).representation().
@@ -6110,9 +6053,8 @@
return GetHeap()->undefined_value();
}
} else {
- Isolate* isolate = GetIsolate();
- LookupIterator it(handle(this), isolate->factory()->hidden_string(),
- LookupIterator::OWN_SKIP_INTERCEPTOR);
+ Handle<Symbol> hidden = GetIsolate()->factory()->hidden_properties_symbol();
+ LookupIterator it(handle(this), hidden);
// Access check is always skipped for the hidden string anyways.
return *GetDataProperty(&it);
}
@@ -6141,13 +6083,14 @@
Handle<Object> value) {
DCHECK(!object->IsJSGlobalProxy());
Isolate* isolate = object->GetIsolate();
- Handle<Name> name = isolate->factory()->hidden_string();
+ Handle<Symbol> name = isolate->factory()->hidden_properties_symbol();
SetOwnPropertyIgnoreAttributes(object, name, value, DONT_ENUM).Assert();
return object;
}
-Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it) {
+Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
+ ShouldThrow should_throw) {
Isolate* isolate = it->isolate();
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
@@ -6160,7 +6103,7 @@
Handle<JSObject> holder = it->GetHolder<JSObject>();
PropertyCallbackArguments args(isolate, interceptor->data(),
- *it->GetReceiver(), *holder);
+ *it->GetReceiver(), *holder, should_throw);
v8::Local<v8::Boolean> result;
if (it->IsElement()) {
uint32_t index = it->index();
@@ -6223,6 +6166,8 @@
Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
LanguageMode language_mode) {
+ it->UpdateProtector();
+
Isolate* isolate = it->isolate();
if (it->state() == LookupIterator::JSPROXY) {
@@ -6233,16 +6178,15 @@
if (it->GetReceiver()->IsJSProxy()) {
if (it->state() != LookupIterator::NOT_FOUND) {
DCHECK_EQ(LookupIterator::DATA, it->state());
- DCHECK(it->GetName()->IsPrivate());
+ DCHECK(it->name()->IsPrivate());
it->Delete();
}
return Just(true);
}
Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
- bool is_observed =
- receiver->map()->is_observed() &&
- (it->IsElement() || !isolate->IsInternallyUsedPropertyName(it->name()));
+ bool is_observed = receiver->map()->is_observed() &&
+ (it->IsElement() || !it->name()->IsPrivate());
Handle<Object> old_value = it->factory()->the_hole_value();
@@ -6258,7 +6202,10 @@
RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
return Just(false);
case LookupIterator::INTERCEPTOR: {
- Maybe<bool> result = JSObject::DeletePropertyWithInterceptor(it);
+ ShouldThrow should_throw =
+ is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
+ Maybe<bool> result =
+ JSObject::DeletePropertyWithInterceptor(it, should_throw);
// An exception was thrown in the interceptor. Propagate.
if (isolate->has_pending_exception()) return Nothing<bool>();
// Delete with interceptor succeeded. Return result.
@@ -6413,8 +6360,8 @@
// 5. ReturnIfAbrupt(keys).
Handle<FixedArray> keys;
ASSIGN_RETURN_ON_EXCEPTION(
- isolate, keys,
- JSReceiver::GetKeys(props, JSReceiver::OWN_ONLY, ALL_PROPERTIES), Object);
+ isolate, keys, JSReceiver::GetKeys(props, OWN_ONLY, ALL_PROPERTIES),
+ Object);
// 6. Let descriptors be an empty List.
int capacity = keys->length();
std::vector<PropertyDescriptor> descriptors(capacity);
@@ -6599,8 +6546,8 @@
? desc->value()
: Handle<Object>::cast(isolate->factory()->undefined_value()));
MaybeHandle<Object> result =
- JSObject::DefineOwnPropertyIgnoreAttributes(
- it, value, desc->ToAttributes(), JSObject::DONT_FORCE_FIELD);
+ JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
+ desc->ToAttributes());
if (result.is_null()) return Nothing<bool>();
}
} else {
@@ -6792,8 +6739,8 @@
? current->value()
: Handle<Object>::cast(
isolate->factory()->undefined_value()));
- MaybeHandle<Object> result = JSObject::DefineOwnPropertyIgnoreAttributes(
- it, value, attrs, JSObject::DONT_FORCE_FIELD);
+ MaybeHandle<Object> result =
+ JSObject::DefineOwnPropertyIgnoreAttributes(it, value, attrs);
if (result.is_null()) return Nothing<bool>();
} else {
DCHECK(desc_is_accessor_descriptor ||
@@ -6857,10 +6804,9 @@
return Just(false);
}
- RETURN_ON_EXCEPTION_VALUE(
- it->isolate(),
- DefineOwnPropertyIgnoreAttributes(it, value, NONE, DONT_FORCE_FIELD),
- Nothing<bool>());
+ RETURN_ON_EXCEPTION_VALUE(it->isolate(),
+ DefineOwnPropertyIgnoreAttributes(it, value, NONE),
+ Nothing<bool>());
return Just(true);
}
@@ -7081,7 +7027,7 @@
ShouldThrow should_throw) {
STACK_CHECK(Nothing<bool>());
if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
- return AddPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc,
+ return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc,
should_throw);
}
Handle<String> trap_name = isolate->factory()->defineProperty_string();
@@ -7187,7 +7133,7 @@
// static
-Maybe<bool> JSProxy::AddPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy,
+Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy,
Handle<Symbol> private_name,
PropertyDescriptor* desc,
ShouldThrow should_throw) {
@@ -7207,7 +7153,7 @@
if (it.IsFound()) {
DCHECK_EQ(LookupIterator::DATA, it.state());
- DCHECK_EQ(DONT_ENUM, it.property_details().attributes());
+ DCHECK_EQ(DONT_ENUM, it.property_attributes());
it.WriteDataValue(value);
return Just(true);
}
@@ -7277,9 +7223,9 @@
Handle<AccessorPair> accessors =
Handle<AccessorPair>::cast(it->GetAccessors());
// 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
- desc->set_get(handle(accessors->GetComponent(ACCESSOR_GETTER), isolate));
+ desc->set_get(AccessorPair::GetComponent(accessors, ACCESSOR_GETTER));
// 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
- desc->set_set(handle(accessors->GetComponent(ACCESSOR_SETTER), isolate));
+ desc->set_set(AccessorPair::GetComponent(accessors, ACCESSOR_SETTER));
}
// 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
@@ -7412,9 +7358,7 @@
bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
ElementsKind kind,
Object* object) {
- DCHECK(IsFastObjectElementsKind(kind) ||
- kind == DICTIONARY_ELEMENTS);
- if (IsFastObjectElementsKind(kind)) {
+ if (IsFastObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) {
int length = IsJSArray()
? Smi::cast(JSArray::cast(this)->length())->value()
: elements->length();
@@ -7423,6 +7367,7 @@
if (!element->IsTheHole() && element == object) return true;
}
} else {
+ DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS);
Object* key =
SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
if (!key->IsUndefined()) return true;
@@ -7473,7 +7418,9 @@
break;
case FAST_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
- case DICTIONARY_ELEMENTS: {
+ case DICTIONARY_ELEMENTS:
+ case FAST_STRING_WRAPPER_ELEMENTS:
+ case SLOW_STRING_WRAPPER_ELEMENTS: {
FixedArray* elements = FixedArray::cast(this->elements());
if (ReferencesObjectFromElements(elements, kind, obj)) return true;
break;
@@ -7494,6 +7441,8 @@
if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
break;
}
+ case NO_ELEMENTS:
+ break;
}
// For functions check the context.
@@ -7875,7 +7824,8 @@
Handle<SeededNumberDictionary> new_element_dictionary;
if (!object->HasFixedTypedArrayElements() &&
- !object->HasDictionaryElements()) {
+ !object->HasDictionaryElements() &&
+ !object->HasSlowStringWrapperElements()) {
int length =
object->IsJSArray()
? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
@@ -7902,7 +7852,8 @@
if (transition != NULL) {
Handle<Map> transition_map(transition, isolate);
DCHECK(transition_map->has_dictionary_elements() ||
- transition_map->has_fixed_typed_array_elements());
+ transition_map->has_fixed_typed_array_elements() ||
+ transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
DCHECK(!transition_map->is_extensible());
JSObject::MigrateToMap(object, transition_map);
} else if (TransitionArray::CanHaveMoreTransitions(old_map)) {
@@ -7922,7 +7873,11 @@
Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions");
new_map->set_is_extensible(false);
if (!new_element_dictionary.is_null()) {
- new_map->set_elements_kind(DICTIONARY_ELEMENTS);
+ ElementsKind new_kind =
+ IsStringWrapperElementsKind(old_map->elements_kind())
+ ? SLOW_STRING_WRAPPER_ELEMENTS
+ : DICTIONARY_ELEMENTS;
+ new_map->set_elements_kind(new_kind);
}
JSObject::MigrateToMap(object, new_map);
@@ -7947,7 +7902,8 @@
return Just(true);
}
- DCHECK(object->map()->has_dictionary_elements());
+ DCHECK(object->map()->has_dictionary_elements() ||
+ object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
if (!new_element_dictionary.is_null()) {
object->set_elements(*new_element_dictionary);
}
@@ -7999,8 +7955,9 @@
return Object::WrapForRead(isolate, raw_value, representation);
}
+enum class BoilerplateKind { kNormalBoilerplate, kApiBoilerplate };
-template<class ContextObject>
+template <class ContextObject, BoilerplateKind boilerplate_kind>
class JSObjectWalkVisitor {
public:
JSObjectWalkVisitor(ContextObject* site_context, bool copying,
@@ -8032,10 +7989,9 @@
const JSObject::DeepCopyHints hints_;
};
-
-template <class ContextObject>
-MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
- Handle<JSObject> object) {
+template <class ContextObject, BoilerplateKind boilerplate_kind>
+MaybeHandle<JSObject> JSObjectWalkVisitor<
+ ContextObject, boilerplate_kind>::StructureWalk(Handle<JSObject> object) {
Isolate* isolate = this->isolate();
bool copying = this->copying();
bool shallow = hints_ == JSObject::kObjectIsShallow;
@@ -8055,6 +8011,26 @@
Handle<JSObject> copy;
if (copying) {
+ if (boilerplate_kind == BoilerplateKind::kApiBoilerplate) {
+ if (object->IsJSFunction()) {
+#ifdef DEBUG
+ // Ensure that it is an Api function and template_instantiations_cache
+ // contains an entry for function's FunctionTemplateInfo.
+ JSFunction* function = JSFunction::cast(*object);
+ CHECK(function->shared()->IsApiFunction());
+ FunctionTemplateInfo* data = function->shared()->get_api_func_data();
+ auto serial_number = handle(Smi::cast(data->serial_number()), isolate);
+ CHECK(serial_number->value());
+ auto cache = isolate->template_instantiations_cache();
+ Object* element = cache->Lookup(serial_number);
+ CHECK_EQ(function, element);
+#endif
+ return object;
+ }
+ } else {
+ // JSFunction objects are not allowed to be in normal boilerplates at all.
+ DCHECK(!object->IsJSFunction());
+ }
Handle<AllocationSite> site_to_pass;
if (site_context()->ShouldCreateMemento(object)) {
site_to_pass = site_context()->current();
@@ -8115,7 +8091,7 @@
// an array.
PropertyFilter filter = static_cast<PropertyFilter>(
ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE);
- KeyAccumulator accumulator(isolate, filter);
+ KeyAccumulator accumulator(isolate, OWN_ONLY, filter);
accumulator.NextPrototype();
copy->CollectOwnPropertyNames(&accumulator, filter);
Handle<FixedArray> names = accumulator.GetKeys();
@@ -8139,12 +8115,8 @@
}
// Deep copy own elements.
- // Pixel elements cannot be created using an object literal.
- DCHECK(!copy->HasFixedTypedArrayElements());
switch (kind) {
- case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_ELEMENTS: {
Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
@@ -8156,9 +8128,6 @@
} else {
for (int i = 0; i < elements->length(); i++) {
Handle<Object> value(elements->get(i), isolate);
- DCHECK(value->IsSmi() ||
- value->IsTheHole() ||
- (IsFastObjectElementsKind(copy->GetElementsKind())));
if (value->IsJSObject()) {
Handle<JSObject> result;
ASSIGN_RETURN_ON_EXCEPTION(
@@ -8199,16 +8168,25 @@
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNIMPLEMENTED();
break;
-
+ case FAST_STRING_WRAPPER_ELEMENTS:
+ case SLOW_STRING_WRAPPER_ELEMENTS:
+ UNREACHABLE();
+ break;
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
case TYPE##_ELEMENTS: \
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
+ // Typed elements cannot be created using an object literal.
+ UNREACHABLE();
+ break;
+ case FAST_SMI_ELEMENTS:
+ case FAST_HOLEY_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
+ case NO_ELEMENTS:
// No contained objects, nothing to do.
break;
}
@@ -8221,8 +8199,9 @@
MaybeHandle<JSObject> JSObject::DeepWalk(
Handle<JSObject> object,
AllocationSiteCreationContext* site_context) {
- JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false,
- kNoHints);
+ JSObjectWalkVisitor<AllocationSiteCreationContext,
+ BoilerplateKind::kNormalBoilerplate> v(site_context,
+ false, kNoHints);
MaybeHandle<JSObject> result = v.StructureWalk(object);
Handle<JSObject> for_assert;
DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
@@ -8234,13 +8213,35 @@
Handle<JSObject> object,
AllocationSiteUsageContext* site_context,
DeepCopyHints hints) {
- JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints);
+ JSObjectWalkVisitor<AllocationSiteUsageContext,
+ BoilerplateKind::kNormalBoilerplate> v(site_context, true,
+ hints);
MaybeHandle<JSObject> copy = v.StructureWalk(object);
Handle<JSObject> for_assert;
DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
return copy;
}
+class DummyContextObject : public AllocationSiteContext {
+ public:
+ explicit DummyContextObject(Isolate* isolate)
+ : AllocationSiteContext(isolate) {}
+
+ bool ShouldCreateMemento(Handle<JSObject> object) { return false; }
+ Handle<AllocationSite> EnterNewScope() { return Handle<AllocationSite>(); }
+ void ExitScope(Handle<AllocationSite> site, Handle<JSObject> object) {}
+};
+
+MaybeHandle<JSObject> JSObject::DeepCopyApiBoilerplate(
+ Handle<JSObject> object) {
+ DummyContextObject dummy_context_object(object->GetIsolate());
+ JSObjectWalkVisitor<DummyContextObject, BoilerplateKind::kApiBoilerplate> v(
+ &dummy_context_object, true, kNoHints);
+ MaybeHandle<JSObject> copy = v.StructureWalk(object);
+ Handle<JSObject> for_assert;
+ DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
+ return copy;
+}
// static
MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
@@ -8314,12 +8315,6 @@
// TODO(cbruni/jkummerow): Consider moving this into elements.cc.
bool HasEnumerableElements(JSObject* object) {
- if (object->IsJSValue()) {
- Object* value = JSValue::cast(object)->value();
- if (value->IsString()) {
- if (String::cast(value)->length() > 0) return true;
- }
- }
switch (object->GetElementsKind()) {
case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
@@ -8371,6 +8366,14 @@
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
// We're approximating non-empty arguments objects here.
return true;
+ case FAST_STRING_WRAPPER_ELEMENTS:
+ case SLOW_STRING_WRAPPER_ELEMENTS:
+ if (String::cast(JSValue::cast(object)->value())->length() > 0) {
+ return true;
+ }
+ return object->elements()->length() > 0;
+ case NO_ELEMENTS:
+ return false;
}
UNREACHABLE();
return true;
@@ -8444,22 +8447,27 @@
static Handle<FixedArray> ReduceFixedArrayTo(
Handle<FixedArray> array, int length) {
- DCHECK(array->length() >= length);
+ DCHECK_LE(length, array->length());
if (array->length() == length) return array;
-
- Handle<FixedArray> new_array =
- array->GetIsolate()->factory()->NewFixedArray(length);
- for (int i = 0; i < length; ++i) new_array->set(i, array->get(i));
- return new_array;
+ return array->GetIsolate()->factory()->CopyFixedArrayUpTo(array, length);
}
+bool Map::OnlyHasSimpleProperties() {
+ // Wrapped string elements aren't explicitly stored in the elements backing
+ // store, but are loaded indirectly from the underlying string.
+ return !IsStringWrapperElementsKind(elements_kind()) &&
+ !is_access_check_needed() && !has_named_interceptor() &&
+ !has_indexed_interceptor() && !has_hidden_prototype() &&
+ !is_dictionary_map();
+}
namespace {
Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
- Handle<JSObject> object,
- bool cache_enum_length) {
+ Handle<JSObject> object) {
Handle<Map> map(object->map());
+ bool cache_enum_length = map->OnlyHasSimpleProperties();
+
Handle<DescriptorArray> descs =
Handle<DescriptorArray>(map->instance_descriptors(), isolate);
int own_property_count = map->EnumLength();
@@ -8532,12 +8540,10 @@
} // namespace
-
-Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object,
- bool cache_enum_length) {
+Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object) {
Isolate* isolate = object->GetIsolate();
if (object->HasFastProperties()) {
- return GetFastEnumPropertyKeys(isolate, object, cache_enum_length);
+ return GetFastEnumPropertyKeys(isolate, object);
} else if (object->IsJSGlobalObject()) {
Handle<GlobalDictionary> dictionary(object->global_dictionary());
int length = dictionary->NumberOfEnumElements();
@@ -8583,7 +8589,7 @@
return Just(true);
}
PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
- *object);
+ *object, Object::DONT_THROW);
v8::Local<v8::Object> result;
if (!interceptor->enumerator()->IsUndefined()) {
Callback enum_fun = v8::ToCData<Callback>(interceptor->enumerator());
@@ -8603,8 +8609,8 @@
accumulator->AddElementKeysFromInterceptor(
Handle<JSObject>::cast(v8::Utils::OpenHandle(*result)));
} else {
- accumulator->AddKeys(
- Handle<JSObject>::cast(v8::Utils::OpenHandle(*result)));
+ accumulator->AddKeys(Handle<JSObject>::cast(v8::Utils::OpenHandle(*result)),
+ DO_NOT_CONVERT);
}
return Just(true);
}
@@ -8616,7 +8622,7 @@
Handle<JSReceiver> receiver,
Handle<JSObject> object,
PropertyFilter* filter,
- JSReceiver::KeyCollectionType type,
+ KeyCollectionType type,
KeyAccumulator* accumulator) {
accumulator->NextPrototype();
// Check access rights if required.
@@ -8624,11 +8630,11 @@
!isolate->MayAccess(handle(isolate->context()), object)) {
// The cross-origin spec says that [[Enumerate]] shall return an empty
// iterator when it doesn't have access...
- if (type == JSReceiver::INCLUDE_PROTOS) {
+ if (type == INCLUDE_PROTOS) {
return Just(false);
}
// ...whereas [[OwnPropertyKeys]] shall return whitelisted properties.
- DCHECK(type == JSReceiver::OWN_ONLY);
+ DCHECK_EQ(OWN_ONLY, type);
*filter = static_cast<PropertyFilter>(*filter | ONLY_ALL_CAN_READ);
}
@@ -8641,33 +8647,8 @@
MAYBE_RETURN(success, Nothing<bool>());
if (*filter == ENUMERABLE_STRINGS) {
- // We can cache the computed property keys if access checks are
- // not needed and no interceptors are involved.
- //
- // We do not use the cache if the object has elements and
- // therefore it does not make sense to cache the property names
- // for arguments objects. Arguments objects will always have
- // elements.
- // Wrapped strings have elements, but don't have an elements
- // array or dictionary. So the fast inline test for whether to
- // use the cache says yes, so we should not create a cache.
- Handle<JSFunction> arguments_function(
- JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor()));
- bool has_hidden_prototype = false;
- Object* prototype = object->map()->prototype();
- if (prototype->IsJSObject()) {
- has_hidden_prototype =
- JSObject::cast(prototype)->map()->is_hidden_prototype();
- }
- bool cache_enum_length =
- ((object->map()->GetConstructor() != *arguments_function) &&
- !object->IsJSValue() && !object->IsAccessCheckNeeded() &&
- !object->HasNamedInterceptor() && !object->HasIndexedInterceptor() &&
- !has_hidden_prototype);
- // Compute the property keys and cache them if possible.
- Handle<FixedArray> enum_keys =
- JSObject::GetEnumPropertyKeys(object, cache_enum_length);
- accumulator->AddKeys(enum_keys);
+ Handle<FixedArray> enum_keys = JSObject::GetEnumPropertyKeys(object);
+ accumulator->AddKeys(enum_keys, DO_NOT_CONVERT);
} else {
object->CollectOwnPropertyNames(accumulator, *filter);
}
@@ -8686,28 +8667,22 @@
static Maybe<bool> GetKeys_Internal(Isolate* isolate,
Handle<JSReceiver> receiver,
Handle<JSReceiver> object,
- JSReceiver::KeyCollectionType type,
+ KeyCollectionType type,
PropertyFilter filter,
KeyAccumulator* accumulator) {
- PrototypeIterator::WhereToEnd end = type == JSReceiver::OWN_ONLY
+ PrototypeIterator::WhereToEnd end = type == OWN_ONLY
? PrototypeIterator::END_AT_NON_HIDDEN
: PrototypeIterator::END_AT_NULL;
for (PrototypeIterator iter(isolate, object,
- PrototypeIterator::START_AT_RECEIVER);
- !iter.IsAtEnd(end); iter.Advance()) {
+ PrototypeIterator::START_AT_RECEIVER, end);
+ !iter.IsAtEnd(); iter.Advance()) {
Handle<JSReceiver> current =
PrototypeIterator::GetCurrent<JSReceiver>(iter);
Maybe<bool> result = Just(false); // Dummy initialization.
if (current->IsJSProxy()) {
- if (type == JSReceiver::OWN_ONLY) {
- result = JSProxy::OwnPropertyKeys(isolate, receiver,
- Handle<JSProxy>::cast(current),
- filter, accumulator);
- } else {
- DCHECK(type == JSReceiver::INCLUDE_PROTOS);
- result = JSProxy::Enumerate(
- isolate, receiver, Handle<JSProxy>::cast(current), accumulator);
- }
+ result = JSProxy::OwnPropertyKeys(isolate, receiver,
+ Handle<JSProxy>::cast(current), filter,
+ accumulator);
} else {
DCHECK(current->IsJSObject());
result = GetKeysFromJSObject(isolate, receiver,
@@ -8721,54 +8696,6 @@
}
-// ES6 9.5.11
-// Returns false in case of exception.
-// static
-Maybe<bool> JSProxy::Enumerate(Isolate* isolate, Handle<JSReceiver> receiver,
- Handle<JSProxy> proxy,
- KeyAccumulator* accumulator) {
- STACK_CHECK(Nothing<bool>());
- // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
- Handle<Object> handler(proxy->handler(), isolate);
- // 2. If handler is null, throw a TypeError exception.
- // 3. Assert: Type(handler) is Object.
- if (proxy->IsRevoked()) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kProxyRevoked,
- isolate->factory()->enumerate_string()));
- return Nothing<bool>();
- }
- // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
- Handle<JSReceiver> target(proxy->target(), isolate);
- // 5. Let trap be ? GetMethod(handler, "enumerate").
- Handle<Object> trap;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
- isolate->factory()->enumerate_string()),
- Nothing<bool>());
- // 6. If trap is undefined, then
- if (trap->IsUndefined()) {
- // 6a. Return target.[[Enumerate]]().
- return GetKeys_Internal(isolate, receiver, target, INCLUDE_PROTOS,
- ENUMERABLE_STRINGS, accumulator);
- }
- // The "proxy_enumerate" helper calls the trap (steps 7 - 9), which returns
- // a generator; it then iterates over that generator until it's exhausted
- // and returns an array containing the generated values.
- Handle<Object> trap_result_array;
- Handle<Object> args[] = {trap, handler, target};
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate, trap_result_array,
- Execution::Call(isolate, isolate->proxy_enumerate(),
- isolate->factory()->undefined_value(), arraysize(args),
- args),
- Nothing<bool>());
- accumulator->NextPrototype();
- accumulator->AddKeysFromProxy(Handle<JSObject>::cast(trap_result_array));
- return Just(true);
-}
-
-
// ES6 9.5.12
// Returns |true| on success, |nothing| in case of exception.
// static
@@ -8866,10 +8793,15 @@
const int kPresent = 1;
const int kGone = 0;
IdentityMap<int> unchecked_result_keys(isolate->heap(), &set_zone);
- int unchecked_result_keys_size = trap_result->length();
+ int unchecked_result_keys_size = 0;
for (int i = 0; i < trap_result->length(); ++i) {
DCHECK(trap_result->get(i)->IsUniqueName());
- unchecked_result_keys.Set(trap_result->get(i), kPresent);
+ Object* key = trap_result->get(i);
+ int* entry = unchecked_result_keys.Get(key);
+ if (*entry != kPresent) {
+ *entry = kPresent;
+ unchecked_result_keys_size++;
+ }
}
// 17. Repeat, for each key that is an element of targetNonconfigurableKeys:
for (int i = 0; i < nonconfigurable_keys_length; ++i) {
@@ -8924,7 +8856,7 @@
GetKeysConversion keys_conversion) {
USE(ContainsOnlyValidKeys);
Isolate* isolate = object->GetIsolate();
- KeyAccumulator accumulator(isolate, filter);
+ KeyAccumulator accumulator(isolate, type, filter);
MAYBE_RETURN(
GetKeys_Internal(isolate, object, object, type, filter, &accumulator),
MaybeHandle<FixedArray>());
@@ -8933,6 +8865,64 @@
return keys;
}
+MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
+ Handle<JSReceiver> object,
+ PropertyFilter filter,
+ bool get_entries) {
+ PropertyFilter key_filter =
+ static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
+ KeyAccumulator accumulator(isolate, OWN_ONLY, key_filter);
+ MAYBE_RETURN(GetKeys_Internal(isolate, object, object, OWN_ONLY, key_filter,
+ &accumulator),
+ MaybeHandle<FixedArray>());
+ Handle<FixedArray> keys = accumulator.GetKeys(CONVERT_TO_STRING);
+ DCHECK(ContainsOnlyValidKeys(keys));
+
+ Handle<FixedArray> values_or_entries =
+ isolate->factory()->NewFixedArray(keys->length());
+ int length = 0;
+
+ for (int i = 0; i < keys->length(); ++i) {
+ Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate));
+
+ if (filter & ONLY_ENUMERABLE) {
+ PropertyDescriptor descriptor;
+ Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
+ isolate, object, key, &descriptor);
+ MAYBE_RETURN(did_get_descriptor, MaybeHandle<FixedArray>());
+ if (!did_get_descriptor.FromJust() || !descriptor.enumerable()) continue;
+ }
+
+ Handle<Object> value;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, value, JSReceiver::GetPropertyOrElement(object, key),
+ MaybeHandle<FixedArray>());
+
+ if (get_entries) {
+ Handle<FixedArray> entry_storage =
+ isolate->factory()->NewUninitializedFixedArray(2);
+ entry_storage->set(0, *key);
+ entry_storage->set(1, *value);
+ value = isolate->factory()->NewJSArrayWithElements(entry_storage,
+ FAST_ELEMENTS, 2);
+ }
+
+ values_or_entries->set(length, *value);
+ length++;
+ }
+ if (length < values_or_entries->length()) values_or_entries->Shrink(length);
+ return values_or_entries;
+}
+
+MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object,
+ PropertyFilter filter) {
+ return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, false);
+}
+
+MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
+ PropertyFilter filter) {
+ return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, true);
+}
bool Map::DictionaryElementsInPrototypeChainOnly() {
if (IsDictionaryElementsKind(elements_kind())) {
@@ -9000,7 +8990,7 @@
Handle<Object> old_value = isolate->factory()->the_hole_value();
bool is_observed = object->map()->is_observed() &&
- !isolate->IsInternallyUsedPropertyName(it->GetName());
+ (it->IsElement() || !it->name()->IsPrivate());
bool preexists = false;
if (is_observed) {
CHECK(GetPropertyAttributes(it).IsJust());
@@ -9011,8 +9001,10 @@
}
}
- DCHECK(getter->IsCallable() || getter->IsUndefined() || getter->IsNull());
- DCHECK(setter->IsCallable() || setter->IsUndefined() || setter->IsNull());
+ DCHECK(getter->IsCallable() || getter->IsUndefined() || getter->IsNull() ||
+ getter->IsFunctionTemplateInfo());
+ DCHECK(setter->IsCallable() || setter->IsUndefined() || setter->IsNull() ||
+ getter->IsFunctionTemplateInfo());
// At least one of the accessors needs to be a new value.
DCHECK(!getter->IsNull() || !setter->IsNull());
if (!getter->IsNull()) {
@@ -9111,9 +9103,8 @@
case LookupIterator::ACCESSOR: {
Handle<Object> maybe_pair = it.GetAccessors();
if (maybe_pair->IsAccessorPair()) {
- return handle(
- AccessorPair::cast(*maybe_pair)->GetComponent(component),
- isolate);
+ return AccessorPair::GetComponent(
+ Handle<AccessorPair>::cast(maybe_pair), component);
}
}
}
@@ -9182,8 +9173,6 @@
if (!map->is_dictionary_map()) {
new_bit_field3 = IsUnstable::update(new_bit_field3, false);
}
- new_bit_field3 =
- ConstructionCounter::update(new_bit_field3, kNoSlackTracking);
result->set_bit_field3(new_bit_field3);
return result;
}
@@ -9240,7 +9229,7 @@
new_map = Map::CopyNormalized(fast_map, mode);
if (use_cache) {
cache->Set(fast_map, new_map);
- isolate->counters()->normalized_maps()->Increment();
+ isolate->counters()->maps_normalized()->Increment();
}
#if TRACE_MAPS
if (FLAG_trace_maps) {
@@ -9270,6 +9259,7 @@
result->set_dictionary_map(true);
result->set_migration_target(false);
+ result->set_construction_counter(kNoSlackTracking);
#ifdef VERIFY_HEAP
if (FLAG_verify_heap) result->DictionaryMapVerify();
@@ -9453,7 +9443,7 @@
for (int i = 0; i < length; i++) {
descriptors->SetRepresentation(i, Representation::Tagged());
if (descriptors->GetDetails(i).type() == DATA) {
- descriptors->SetValue(i, HeapType::Any());
+ descriptors->SetValue(i, FieldType::Any());
}
}
result->InitializeDescriptors(*descriptors,
@@ -9760,23 +9750,37 @@
transition_marker, reason, SPECIAL_TRANSITION);
new_map->set_is_extensible(false);
if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
- new_map->set_elements_kind(DICTIONARY_ELEMENTS);
+ ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
+ ? SLOW_STRING_WRAPPER_ELEMENTS
+ : DICTIONARY_ELEMENTS;
+ new_map->set_elements_kind(new_kind);
}
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);
+}
-bool DescriptorArray::CanHoldValue(int descriptor, Object* value) {
- PropertyDetails details = GetDetails(descriptor);
+namespace {
+
+bool CanHoldValue(DescriptorArray* descriptors, int descriptor, Object* value) {
+ PropertyDetails details = descriptors->GetDetails(descriptor);
switch (details.type()) {
case DATA:
return value->FitsRepresentation(details.representation()) &&
- GetFieldType(descriptor)->NowContains(value);
+ descriptors->GetFieldType(descriptor)->NowContains(value);
case DATA_CONSTANT:
- DCHECK(GetConstant(descriptor) != value ||
+ DCHECK(descriptors->GetConstant(descriptor) != value ||
value->FitsRepresentation(details.representation()));
- return GetConstant(descriptor) == value;
+ return descriptors->GetConstant(descriptor) == value;
case ACCESSOR:
case ACCESSOR_CONSTANT:
@@ -9787,28 +9791,29 @@
return false;
}
+Handle<Map> UpdateDescriptorForValue(Handle<Map> map, int descriptor,
+ Handle<Object> value) {
+ if (CanHoldValue(map->instance_descriptors(), descriptor, *value)) return map;
+
+ Isolate* isolate = map->GetIsolate();
+ PropertyAttributes attributes =
+ map->instance_descriptors()->GetDetails(descriptor).attributes();
+ Representation representation = value->OptimalRepresentation();
+ Handle<FieldType> type = value->OptimalType(isolate, representation);
+
+ return Map::ReconfigureProperty(map, descriptor, kData, attributes,
+ representation, type, FORCE_FIELD);
+}
+
+} // namespace
// static
Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
Handle<Object> value) {
// Dictionaries can store any property value.
- if (map->is_dictionary_map()) return map;
-
- // Migrate to the newest map before storing the property.
- map = Update(map);
-
- Handle<DescriptorArray> descriptors(map->instance_descriptors());
-
- if (descriptors->CanHoldValue(descriptor, *value)) return map;
-
- Isolate* isolate = map->GetIsolate();
- PropertyAttributes attributes =
- descriptors->GetDetails(descriptor).attributes();
- Representation representation = value->OptimalRepresentation();
- Handle<HeapType> type = value->OptimalType(isolate, representation);
-
- return ReconfigureProperty(map, descriptor, kData, attributes, representation,
- type, FORCE_FIELD);
+ DCHECK(!map->is_dictionary_map());
+ // Update to the newest map before storing the property.
+ return UpdateDescriptorForValue(Update(map), descriptor, value);
}
@@ -9816,8 +9821,8 @@
Handle<Object> value,
PropertyAttributes attributes,
StoreFromKeyed store_mode) {
- // Dictionary maps can always have additional data properties.
- if (map->is_dictionary_map()) return map;
+ DCHECK(name->IsUniqueName());
+ DCHECK(!map->is_dictionary_map());
// Migrate to the newest map before storing the property.
map = Update(map);
@@ -9832,7 +9837,7 @@
->GetDetails(descriptor)
.attributes());
- return Map::PrepareForDataProperty(transition, descriptor, value);
+ return UpdateDescriptorForValue(transition, descriptor, value);
}
TransitionFlag flag = INSERT_TRANSITION;
@@ -9842,7 +9847,7 @@
} else if (!map->TooManyFastProperties(store_mode)) {
Isolate* isolate = name->GetIsolate();
Representation representation = value->OptimalRepresentation();
- Handle<HeapType> type = value->OptimalType(isolate, representation);
+ Handle<FieldType> type = value->OptimalType(isolate, representation);
maybe_map =
Map::CopyWithField(map, name, type, attributes, representation, flag);
}
@@ -9887,7 +9892,7 @@
Isolate* isolate = map->GetIsolate();
Handle<Map> new_map = ReconfigureProperty(
map, descriptor, kind, attributes, Representation::None(),
- HeapType::None(isolate), FORCE_FIELD);
+ FieldType::None(isolate), FORCE_FIELD);
return new_map;
}
@@ -9897,6 +9902,7 @@
AccessorComponent component,
Handle<Object> accessor,
PropertyAttributes attributes) {
+ DCHECK(name->IsUniqueName());
Isolate* isolate = name->GetIsolate();
// Dictionary maps can always have additional data properties.
@@ -9935,7 +9941,7 @@
Handle<AccessorPair> pair;
DescriptorArray* old_descriptors = map->instance_descriptors();
- int descriptor = old_descriptors->SearchWithCache(*name, *map);
+ int descriptor = old_descriptors->SearchWithCache(isolate, *name, *map);
if (descriptor != DescriptorArray::kNotFound) {
if (descriptor != map->LastAdded()) {
return Map::Normalize(map, mode, "AccessorsOverwritingNonLast");
@@ -9981,9 +9987,6 @@
TransitionFlag flag) {
Handle<DescriptorArray> descriptors(map->instance_descriptors());
- // Ensure the key is unique.
- descriptor->KeyToUniqueName();
-
// Share descriptors only if map owns descriptors and it not an initial map.
if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
!map->GetBackPointer()->IsUndefined() &&
@@ -10012,11 +10015,9 @@
TransitionFlag flag) {
Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
- // Ensure the key is unique.
- descriptor->KeyToUniqueName();
-
// We replace the key if it is already present.
- int index = old_descriptors->SearchWithCache(*descriptor->GetKey(), *map);
+ int index = old_descriptors->SearchWithCache(map->GetIsolate(),
+ *descriptor->GetKey(), *map);
if (index != DescriptorArray::kNotFound) {
return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag);
}
@@ -10099,9 +10100,6 @@
Descriptor* descriptor,
int insertion_index,
TransitionFlag flag) {
- // Ensure the key is unique.
- descriptor->KeyToUniqueName();
-
Handle<Name> key = descriptor->GetKey();
DCHECK(*key == descriptors->GetKey(insertion_index));
@@ -10796,17 +10794,18 @@
return array;
}
-
Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
int number_of_descriptors,
- int slack) {
+ int slack,
+ PretenureFlag pretenure) {
DCHECK(0 <= number_of_descriptors);
Factory* factory = isolate->factory();
// Do not use DescriptorArray::cast on incomplete object.
int size = number_of_descriptors + slack;
if (size == 0) return factory->empty_descriptor_array();
// Allocate the array of keys.
- Handle<FixedArray> result = factory->NewFixedArray(LengthFor(size), TENURED);
+ Handle<FixedArray> result =
+ factory->NewFixedArray(LengthFor(size), pretenure);
result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
result->set(kEnumCacheIndex, Smi::FromInt(0));
@@ -10921,13 +10920,21 @@
return copy;
}
-
-Object* AccessorPair::GetComponent(AccessorComponent component) {
- Object* accessor = get(component);
- return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
+Handle<Object> AccessorPair::GetComponent(Handle<AccessorPair> accessor_pair,
+ AccessorComponent component) {
+ Object* accessor = accessor_pair->get(component);
+ if (accessor->IsFunctionTemplateInfo()) {
+ return ApiNatives::InstantiateFunction(
+ handle(FunctionTemplateInfo::cast(accessor)))
+ .ToHandleChecked();
+ }
+ Isolate* isolate = accessor_pair->GetIsolate();
+ if (accessor->IsTheHole()) {
+ return isolate->factory()->undefined_value();
+ }
+ return handle(accessor, isolate);
}
-
Handle<DeoptimizationInputData> DeoptimizationInputData::New(
Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) {
return Handle<DeoptimizationInputData>::cast(
@@ -10963,23 +10970,31 @@
return casted_literals;
}
-
-int HandlerTable::LookupRange(int pc_offset, int* stack_depth_out,
+int HandlerTable::LookupRange(int pc_offset, int* data_out,
CatchPrediction* prediction_out) {
- int innermost_handler = -1, innermost_start = -1;
+ int innermost_handler = -1;
+#ifdef DEBUG
+ // Assuming that ranges are well nested, we don't need to track the innermost
+ // offsets. This is just to verify that the table is actually well nested.
+ int innermost_start = std::numeric_limits<int>::min();
+ int innermost_end = std::numeric_limits<int>::max();
+#endif
for (int i = 0; i < length(); i += kRangeEntrySize) {
int start_offset = Smi::cast(get(i + kRangeStartIndex))->value();
int end_offset = Smi::cast(get(i + kRangeEndIndex))->value();
int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
int handler_offset = HandlerOffsetField::decode(handler_field);
CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
- int stack_depth = Smi::cast(get(i + kRangeDepthIndex))->value();
+ int handler_data = Smi::cast(get(i + kRangeDataIndex))->value();
if (pc_offset > start_offset && pc_offset <= end_offset) {
- DCHECK_NE(start_offset, innermost_start);
- if (start_offset < innermost_start) continue;
+ DCHECK_GE(start_offset, innermost_start);
+ DCHECK_LT(end_offset, innermost_end);
innermost_handler = handler_offset;
+#ifdef DEBUG
innermost_start = start_offset;
- *stack_depth_out = stack_depth;
+ innermost_end = end_offset;
+#endif
+ if (data_out) *data_out = handler_data;
if (prediction_out) *prediction_out = prediction;
}
}
@@ -12257,7 +12272,8 @@
first->bit_field() == second->bit_field() &&
first->is_extensible() == second->is_extensible() &&
first->is_strong() == second->is_strong() &&
- first->is_hidden_prototype() == second->is_hidden_prototype();
+ first->new_target_is_base() == second->new_target_is_base() &&
+ first->has_hidden_prototype() == second->has_hidden_prototype();
}
} // namespace
@@ -12564,23 +12580,27 @@
map->SetInObjectProperties(map->GetInObjectProperties() - slack);
map->set_unused_property_fields(map->unused_property_fields() - slack);
map->set_instance_size(map->instance_size() - slack * kPointerSize);
+ map->set_construction_counter(Map::kNoSlackTracking);
// Visitor id might depend on the instance size, recalculate it.
map->set_visitor_id(Heap::GetStaticVisitorIdForMap(map));
}
+static void StopSlackTracking(Map* map, void* data) {
+ map->set_construction_counter(Map::kNoSlackTracking);
+}
void Map::CompleteInobjectSlackTracking() {
// Has to be an initial map.
DCHECK(GetBackPointer()->IsUndefined());
- set_construction_counter(kNoSlackTracking);
-
int slack = unused_property_fields();
TransitionArray::TraverseTransitionTree(this, &GetMinInobjectSlack, &slack);
if (slack != 0) {
// Resize the initial map and all maps in its transition tree.
TransitionArray::TraverseTransitionTree(this, &ShrinkInstanceSize, &slack);
+ } else {
+ TransitionArray::TraverseTransitionTree(this, &StopSlackTracking, nullptr);
}
}
@@ -12820,10 +12840,22 @@
// static
void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype,
PrototypeOptimizationMode proto_mode) {
+ bool is_hidden = false;
if (prototype->IsJSObject()) {
Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode);
+
+ Object* maybe_constructor = prototype_jsobj->map()->GetConstructor();
+ if (maybe_constructor->IsJSFunction()) {
+ JSFunction* constructor = JSFunction::cast(maybe_constructor);
+ Object* data = constructor->shared()->function_data();
+ is_hidden = (data->IsFunctionTemplateInfo() &&
+ FunctionTemplateInfo::cast(data)->hidden_prototype()) ||
+ prototype->IsJSGlobalObject();
+ }
}
+ map->set_has_hidden_prototype(is_hidden);
+
WriteBarrierMode wb_mode =
prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER;
map->set_prototype(*prototype, wb_mode);
@@ -12923,7 +12955,8 @@
void JSFunction::SetPrototype(Handle<JSFunction> function,
Handle<Object> value) {
- DCHECK(function->IsConstructor());
+ DCHECK(function->IsConstructor() ||
+ IsGeneratorFunction(function->shared()->kind()));
Handle<Object> construct_prototype = value;
// If the value is not a JSReceiver, store the value in the map's
@@ -13011,7 +13044,6 @@
case JS_MAP_TYPE:
case JS_SET_ITERATOR_TYPE:
case JS_MAP_ITERATOR_TYPE:
- case JS_ITERATOR_RESULT_TYPE:
case JS_WEAK_MAP_TYPE:
case JS_WEAK_SET_TYPE:
case JS_PROMISE_TYPE:
@@ -13155,6 +13187,7 @@
JSFunction::SetInitialMap(function, map, prototype);
map->SetConstructor(*constructor);
+ map->set_construction_counter(Map::kNoSlackTracking);
map->StartInobjectSlackTracking();
return map;
}
@@ -13268,6 +13301,22 @@
return JSFunction::GetName(function);
}
+void JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
+ Handle<String> prefix) {
+ Isolate* isolate = function->GetIsolate();
+ Handle<String> function_name = Name::ToFunctionName(name).ToHandleChecked();
+ if (prefix->length() > 0) {
+ IncrementalStringBuilder builder(isolate);
+ builder.AppendString(prefix);
+ builder.AppendCharacter(' ');
+ builder.AppendString(function_name);
+ function_name = builder.Finish().ToHandleChecked();
+ }
+ JSObject::DefinePropertyOrElementIgnoreAttributes(
+ function, isolate->factory()->name_string(), function_name,
+ static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY))
+ .ToHandleChecked();
+}
namespace {
@@ -13339,7 +13388,7 @@
}
if (shared_info->name_should_print_as_anonymous()) {
builder.AppendCString("anonymous");
- } else {
+ } else if (!shared_info->is_anonymous_expression()) {
builder.AppendString(handle(String::cast(shared_info->name()), isolate));
}
}
@@ -13666,7 +13715,9 @@
for (PrototypeIterator iter(isolate, this,
PrototypeIterator::START_AT_RECEIVER);
!iter.IsAtEnd(); iter.Advance()) {
- JSFunction* func = iter.GetCurrent<JSFunction>();
+ JSReceiver* current = iter.GetCurrent<JSReceiver>();
+ if (!current->IsJSFunction()) break;
+ JSFunction* func = JSFunction::cast(current);
SharedFunctionInfo* shared = func->shared();
expected_nof_properties += shared->expected_nof_properties();
if (!IsSubclassConstructor(shared->kind())) {
@@ -13774,8 +13825,9 @@
shared_info->set_function_token_position(lit->function_token_position());
shared_info->set_start_position(lit->start_position());
shared_info->set_end_position(lit->end_position());
- shared_info->set_is_expression(lit->is_expression());
- shared_info->set_is_anonymous(lit->is_anonymous());
+ shared_info->set_is_declaration(lit->is_declaration());
+ shared_info->set_is_named_expression(lit->is_named_expression());
+ shared_info->set_is_anonymous_expression(lit->is_anonymous_expression());
shared_info->set_inferred_name(*lit->inferred_name());
shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
shared_info->set_allows_lazy_compilation_without_context(
@@ -14064,12 +14116,12 @@
Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
}
-
-// Locate the source position which is closest to the address in the code. This
-// is using the source position information embedded in the relocation info.
+// Locate the source position which is closest to the code offset. This is
+// using the source position information embedded in the relocation info.
// The position returned is relative to the beginning of the script where the
// source for this function is found.
-int Code::SourcePosition(Address pc) {
+int Code::SourcePosition(int code_offset) {
+ Address pc = instruction_start() + code_offset;
int distance = kMaxInt;
int position = RelocInfo::kNoPosition; // Initially no position found.
// Run through all the relocation info to find the best matching source
@@ -14101,10 +14153,10 @@
// Same as Code::SourcePosition above except it only looks for statement
// positions.
-int Code::SourceStatementPosition(Address pc) {
+int Code::SourceStatementPosition(int code_offset) {
// First find the position as close as possible using all position
// information.
- int position = SourcePosition(pc);
+ int position = SourcePosition(code_offset);
// Now find the closest statement position before the position.
int statement_position = 0;
RelocIterator it(this, RelocInfo::kPositionMask);
@@ -14305,6 +14357,15 @@
}
}
+int AbstractCode::SourcePosition(int offset) {
+ return IsBytecodeArray() ? GetBytecodeArray()->SourcePosition(offset)
+ : GetCode()->SourcePosition(offset);
+}
+
+int AbstractCode::SourceStatementPosition(int offset) {
+ return IsBytecodeArray() ? GetBytecodeArray()->SourceStatementPosition(offset)
+ : GetCode()->SourceStatementPosition(offset);
+}
void SharedFunctionInfo::ClearTypeFeedbackInfo() {
feedback_vector()->ClearSlots(this);
@@ -14526,7 +14587,9 @@
for (int i = 0; i < deopt_data->DeoptCount(); i++) {
if (deopt_data->Pc(i)->value() == -1) continue;
Address address = code_start_address + deopt_data->Pc(i)->value();
- if (address == pc) return true;
+ if (address == pc && deopt_data->AstId(i) != BailoutId::None()) {
+ return true;
+ }
}
return false;
}
@@ -14640,11 +14703,6 @@
break;
}
- case Translation::JS_FRAME_FUNCTION: {
- os << "{function}";
- break;
- }
-
case Translation::COMPILED_STUB_FRAME: {
Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
os << "{kind=" << stub_kind << "}";
@@ -14786,10 +14844,10 @@
int handler_field = Smi::cast(get(i + kRangeHandlerIndex))->value();
int handler_offset = HandlerOffsetField::decode(handler_field);
CatchPrediction prediction = HandlerPredictionField::decode(handler_field);
- int depth = Smi::cast(get(i + kRangeDepthIndex))->value();
+ int data = Smi::cast(get(i + kRangeDataIndex))->value();
os << " (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end
<< ") -> " << std::setw(4) << handler_offset
- << " (prediction=" << prediction << ", depth=" << depth << ")\n";
+ << " (prediction=" << prediction << ", data=" << data << ")\n";
}
}
@@ -14997,6 +15055,34 @@
}
#endif // ENABLE_DISASSEMBLER
+int BytecodeArray::SourcePosition(int offset) {
+ int last_position = 0;
+ for (interpreter::SourcePositionTableIterator iterator(this);
+ !iterator.done() && iterator.bytecode_offset() <= offset;
+ iterator.Advance()) {
+ last_position = iterator.source_position();
+ }
+ return last_position;
+}
+
+int BytecodeArray::SourceStatementPosition(int offset) {
+ // First find the position as close as possible using all position
+ // information.
+ int position = SourcePosition(offset);
+ // Now find the closest statement position before the position.
+ int statement_position = 0;
+ interpreter::SourcePositionTableIterator iterator(this);
+ while (!iterator.done()) {
+ if (iterator.is_statement()) {
+ int p = iterator.source_position();
+ if (statement_position < p && p <= position) {
+ statement_position = p;
+ }
+ }
+ iterator.Advance();
+ }
+ return statement_position;
+}
void BytecodeArray::Disassemble(std::ostream& os) {
os << "Parameter count " << parameter_count() << "\n";
@@ -15005,12 +15091,23 @@
const uint8_t* first_bytecode_address = GetFirstBytecodeAddress();
int bytecode_size = 0;
+
+ interpreter::SourcePositionTableIterator source_positions(this);
+
for (int i = 0; i < this->length(); i += bytecode_size) {
const uint8_t* bytecode_start = &first_bytecode_address[i];
interpreter::Bytecode bytecode =
interpreter::Bytecodes::FromByte(bytecode_start[0]);
bytecode_size = interpreter::Bytecodes::Size(bytecode);
+ if (!source_positions.done() && i == source_positions.bytecode_offset()) {
+ os << std::setw(5) << source_positions.source_position();
+ os << (source_positions.is_statement() ? " S> " : " E> ");
+ source_positions.Advance();
+ } else {
+ os << " ";
+ }
+
SNPrintF(buf, "%p", bytecode_start);
os << buf.start() << " : ";
interpreter::Bytecodes::Decode(os, bytecode_start, parameter_count());
@@ -15033,13 +15130,29 @@
SNPrintF(buf, " (%p)", bytecode_start + offset);
os << buf.start();
}
- os << "\n";
+
+ os << std::endl;
}
- os << "Constant pool (size = " << constant_pool()->length() << ")\n";
- constant_pool()->Print();
+ if (constant_pool()->length() > 0) {
+ os << "Constant pool (size = " << constant_pool()->length() << ")\n";
+ constant_pool()->Print();
+ }
+
+#ifdef ENABLE_DISASSEMBLER
+ if (handler_table()->length() > 0) {
+ os << "Handler Table (size = " << handler_table()->Size() << ")\n";
+ HandlerTable::cast(handler_table())->HandlerTableRangePrint(os);
+ }
+#endif
}
+void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) {
+ BytecodeArray* from = this;
+ DCHECK_EQ(from->length(), to->length());
+ CopyBytes(to->GetFirstBytecodeAddress(), from->GetFirstBytecodeAddress(),
+ from->length());
+}
// static
void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
@@ -15527,33 +15640,35 @@
Execution::Call(isolate, trap, handler, arraysize(argv), argv),
Nothing<bool>());
bool bool_trap_result = trap_result->BooleanValue();
- // 9. Let extensibleTarget be ? IsExtensible(target).
+ // 9. If booleanTrapResult is false, return false.
+ if (!bool_trap_result) {
+ RETURN_FAILURE(
+ isolate, should_throw,
+ NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
+ }
+ // 10. Let extensibleTarget be ? IsExtensible(target).
Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
if (is_extensible.IsNothing()) return Nothing<bool>();
- // 10. If extensibleTarget is true, return booleanTrapResult.
+ // 11. If extensibleTarget is true, return true.
if (is_extensible.FromJust()) {
if (bool_trap_result) return Just(true);
RETURN_FAILURE(
isolate, should_throw,
NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
}
- // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
+ // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
Handle<Object> target_proto;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
- Object::GetPrototype(isolate, target),
+ JSReceiver::GetPrototype(isolate, target),
Nothing<bool>());
- // 12. If booleanTrapResult is true and SameValue(V, targetProto) is false,
- // throw a TypeError exception.
+ // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
if (bool_trap_result && !value->SameValue(*target_proto)) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kProxySetPrototypeOfNonExtensible));
return Nothing<bool>();
}
- // 13. Return booleanTrapResult.
- if (bool_trap_result) return Just(true);
- RETURN_FAILURE(
- isolate, should_throw,
- NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
+ // 14. Return true.
+ return Just(true);
}
@@ -15562,11 +15677,21 @@
ShouldThrow should_throw) {
Isolate* isolate = object->GetIsolate();
+ // Setting the prototype of an Array instance invalidates the species
+ // protector
+ // because it could change the constructor property of the instance, which
+ // could change the @@species constructor.
+ if (object->IsJSArray() && isolate->IsArraySpeciesLookupChainIntact()) {
+ isolate->CountUsage(
+ v8::Isolate::UseCounterFeature::kArrayInstanceProtoModified);
+ isolate->InvalidateArraySpeciesProtector();
+ }
+
const bool observed = from_javascript && object->map()->is_observed();
Handle<Object> old_value;
if (observed) {
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, old_value,
- Object::GetPrototype(isolate, object),
+ JSReceiver::GetPrototype(isolate, object),
Nothing<bool>());
}
@@ -15577,7 +15702,7 @@
if (result.FromJust() && observed) {
Handle<Object> new_value;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, new_value,
- Object::GetPrototype(isolate, object),
+ JSReceiver::GetPrototype(isolate, object),
Nothing<bool>());
if (!new_value->SameValue(*old_value)) {
RETURN_ON_EXCEPTION_VALUE(
@@ -15633,8 +15758,10 @@
if (from_javascript) {
// Find the first object in the chain whose prototype object is not
// hidden.
- PrototypeIterator iter(isolate, real_receiver);
- while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
+ PrototypeIterator iter(isolate, real_receiver,
+ PrototypeIterator::START_AT_PROTOTYPE,
+ PrototypeIterator::END_AT_NON_HIDDEN);
+ while (!iter.IsAtEnd()) {
// Casting to JSObject is fine because hidden prototypes are never
// JSProxies.
real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter);
@@ -15663,13 +15790,15 @@
// Before we can set the prototype we need to be sure prototype cycles are
// prevented. It is sufficient to validate that the receiver is not in the
// new prototype chain.
- for (PrototypeIterator iter(isolate, *value,
- PrototypeIterator::START_AT_RECEIVER);
- !iter.IsAtEnd(); iter.Advance()) {
- if (iter.GetCurrent<JSReceiver>() == *object) {
- // Cycle detected.
- RETURN_FAILURE(isolate, should_throw,
- NewTypeError(MessageTemplate::kCyclicProto));
+ if (value->IsJSReceiver()) {
+ for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
+ PrototypeIterator::START_AT_RECEIVER);
+ !iter.IsAtEnd(); iter.Advance()) {
+ if (iter.GetCurrent<JSReceiver>() == *object) {
+ // Cycle detected.
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kCyclicProto));
+ }
}
}
@@ -15767,6 +15896,9 @@
if (object->HasSloppyArgumentsElements()) {
return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
}
+ if (object->HasStringWrapperElements()) {
+ return FAST_STRING_WRAPPER_ELEMENTS;
+ }
DCHECK(object->HasDictionaryElements());
SeededNumberDictionary* dictionary = object->element_dictionary();
ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS;
@@ -15850,6 +15982,8 @@
if (IsSloppyArgumentsElements(kind)) {
elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1));
dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
+ } else if (IsStringWrapperElementsKind(kind)) {
+ dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
}
if (attributes != NONE) {
@@ -16037,7 +16171,8 @@
{
DisallowHeapAllocation no_allocation;
- AllocationMemento* memento = heap->FindAllocationMemento(*object);
+ AllocationMemento* memento =
+ heap->FindAllocationMemento<Heap::kForRuntime>(*object);
if (memento == NULL) return;
// Walk through to the Allocation Site
@@ -16144,13 +16279,16 @@
// Fall through.
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
+ case FAST_STRING_WRAPPER_ELEMENTS:
return FastHoleyElementsUsage(this, FixedArray::cast(store));
case FAST_HOLEY_DOUBLE_ELEMENTS:
if (elements()->length() == 0) return 0;
return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store));
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_STRING_WRAPPER_ELEMENTS:
case DICTIONARY_ELEMENTS:
+ case NO_ELEMENTS:
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
case TYPE##_ELEMENTS: \
@@ -16230,7 +16368,8 @@
Handle<JSObject> holder = it->GetHolder<JSObject>();
v8::Local<v8::Value> result;
PropertyCallbackArguments args(isolate, interceptor->data(),
- *it->GetReceiver(), *holder);
+ *it->GetReceiver(), *holder,
+ Object::DONT_THROW);
if (it->IsElement()) {
uint32_t index = it->index();
@@ -16421,7 +16560,7 @@
}
Name* key = descs->GetKey(i);
if (key->FilterKey(filter)) continue;
- keys->AddKey(key);
+ keys->AddKey(key, DO_NOT_CONVERT);
}
} else if (IsJSGlobalObject()) {
GlobalDictionary::CollectKeysTo(handle(global_dictionary()), keys, filter);
@@ -16450,21 +16589,6 @@
KeyAccumulator* keys,
PropertyFilter filter) {
if (filter & SKIP_STRINGS) return;
- uint32_t string_keys = 0;
-
- // If this is a String wrapper, add the string indices first,
- // as they're guaranteed to precede the elements in numerical order
- // and ascending order is required by ECMA-262, 6th, 9.1.12.
- if (object->IsJSValue()) {
- Object* val = JSValue::cast(*object)->value();
- if (val->IsString() && (filter & ONLY_ALL_CAN_READ) == 0) {
- String* str = String::cast(val);
- string_keys = str->length();
- for (uint32_t i = 0; i < string_keys; i++) {
- keys->AddKey(i);
- }
- }
- }
ElementsAccessor* accessor = object->GetElementsAccessor();
accessor->CollectElementIndices(object, keys, kMaxUInt32, filter, 0);
}
@@ -16493,7 +16617,8 @@
case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_ELEMENTS: {
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_STRING_WRAPPER_ELEMENTS: {
int length = IsJSArray() ?
Smi::cast(JSArray::cast(this)->length())->value() :
FixedArray::cast(elements())->length();
@@ -16542,7 +16667,8 @@
break;
}
- case DICTIONARY_ELEMENTS: {
+ case DICTIONARY_ELEMENTS:
+ case SLOW_STRING_WRAPPER_ELEMENTS: {
if (storage != NULL) {
element_dictionary()->CopyKeysTo(storage, counter, filter,
SeededNumberDictionary::SORTED);
@@ -16592,6 +16718,8 @@
}
break;
}
+ case NO_ELEMENTS:
+ break;
}
DCHECK(!storage || storage->length() == counter);
@@ -16604,8 +16732,8 @@
if (object->IsUndefined()) return isolate->factory()->undefined_to_string();
if (object->IsNull()) return isolate->factory()->null_to_string();
- Handle<JSReceiver> receiver;
- CHECK(Object::ToObject(isolate, object).ToHandle(&receiver));
+ Handle<JSReceiver> receiver =
+ Object::ToObject(isolate, object).ToHandleChecked();
Handle<String> tag;
if (FLAG_harmony_tostring) {
@@ -17221,6 +17349,16 @@
}
}
}
+ // Wipe deleted entries.
+ Heap* heap = GetHeap();
+ Object* the_hole = heap->the_hole_value();
+ Object* undefined = heap->undefined_value();
+ for (uint32_t current = 0; current < capacity; current++) {
+ if (get(EntryToIndex(current)) == the_hole) {
+ set(EntryToIndex(current), undefined);
+ }
+ }
+ SetNumberOfDeletedElements(0);
}
@@ -17550,6 +17688,11 @@
return handle(Smi::FromInt(-1), isolate);
}
+ if (object->HasStringWrapperElements()) {
+ int len = String::cast(Handle<JSValue>::cast(object)->value())->length();
+ return handle(Smi::FromInt(len), isolate);
+ }
+
if (object->HasDictionaryElements()) {
// Convert to fast elements containing only the existing properties.
// Ordering is irrelevant, since we are going to sort anyway.
@@ -18489,7 +18632,7 @@
for (int i = 0; i < array_size; i++) {
int index = Smi::cast(array->get(i))->value();
- keys->AddKey(dictionary->KeyAt(index));
+ keys->AddKey(dictionary->KeyAt(index), DO_NOT_CONVERT);
}
}
@@ -18576,6 +18719,12 @@
return table;
}
+ // Rehash if more than 25% of the entries are deleted entries.
+ // TODO(jochen): Consider to shrink the fixed array in place.
+ if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
+ table->Rehash(isolate->factory()->undefined_value());
+ }
+
// Check whether the hash table should be extended.
table = EnsureCapacity(table, 1, key);
table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
@@ -19040,35 +19189,31 @@
return was_present;
}
-
-// Check if there is a break point at this code position.
-bool DebugInfo::HasBreakPoint(int code_position) {
- // Get the break point info object for this code position.
- Object* break_point_info = GetBreakPointInfo(code_position);
+// Check if there is a break point at this code offset.
+bool DebugInfo::HasBreakPoint(int code_offset) {
+ // Get the break point info object for this code offset.
+ Object* break_point_info = GetBreakPointInfo(code_offset);
// If there is no break point info object or no break points in the break
- // point info object there is no break point at this code position.
+ // point info object there is no break point at this code offset.
if (break_point_info->IsUndefined()) return false;
return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
}
-
-// Get the break point info object for this code position.
-Object* DebugInfo::GetBreakPointInfo(int code_position) {
- // Find the index of the break point info object for this code position.
- int index = GetBreakPointInfoIndex(code_position);
+// Get the break point info object for this code offset.
+Object* DebugInfo::GetBreakPointInfo(int code_offset) {
+ // Find the index of the break point info object for this code offset.
+ int index = GetBreakPointInfoIndex(code_offset);
// Return the break point info object if any.
if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
return BreakPointInfo::cast(break_points()->get(index));
}
-
-// Clear a break point at the specified code position.
-void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
- int code_position,
+// Clear a break point at the specified code offset.
+void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info, int code_offset,
Handle<Object> break_point_object) {
- Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
+ Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_offset),
debug_info->GetIsolate());
if (break_point_info->IsUndefined()) return;
BreakPointInfo::ClearBreakPoint(
@@ -19076,14 +19221,11 @@
break_point_object);
}
-
-void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
- int code_position,
- int source_position,
- int statement_position,
+void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int code_offset,
+ int source_position, int statement_position,
Handle<Object> break_point_object) {
Isolate* isolate = debug_info->GetIsolate();
- Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
+ Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_offset),
isolate);
if (!break_point_info->IsUndefined()) {
BreakPointInfo::SetBreakPoint(
@@ -19092,7 +19234,7 @@
return;
}
- // Adding a new break point for a code position which did not have any
+ // Adding a new break point for a code offset which did not have any
// break points before. Try to find a free slot.
int index = kNoBreakPointInfo;
for (int i = 0; i < debug_info->break_points()->length(); i++) {
@@ -19121,7 +19263,7 @@
// 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_code_position(code_position);
+ new_break_point_info->set_code_offset(code_offset);
new_break_point_info->set_source_position(source_position);
new_break_point_info->set_statement_position(statement_position);
new_break_point_info->set_break_point_objects(
@@ -19130,10 +19272,9 @@
debug_info->break_points()->set(index, *new_break_point_info);
}
-
-// Get the break point objects for a code position.
-Handle<Object> DebugInfo::GetBreakPointObjects(int code_position) {
- Object* break_point_info = GetBreakPointInfo(code_position);
+// Get the break point objects for a code offset.
+Handle<Object> DebugInfo::GetBreakPointObjects(int code_offset) {
+ Object* break_point_info = GetBreakPointInfo(code_offset);
if (break_point_info->IsUndefined()) {
return GetIsolate()->factory()->undefined_value();
}
@@ -19179,13 +19320,13 @@
// Find the index of the break point info object for the specified code
// position.
-int DebugInfo::GetBreakPointInfoIndex(int code_position) {
+int DebugInfo::GetBreakPointInfoIndex(int code_offset) {
if (break_points()->IsUndefined()) return kNoBreakPointInfo;
for (int i = 0; i < break_points()->length(); i++) {
if (!break_points()->get(i)->IsUndefined()) {
BreakPointInfo* break_point_info =
BreakPointInfo::cast(break_points()->get(i));
- if (break_point_info->code_position() == code_position) {
+ if (break_point_info->code_offset() == code_offset) {
return i;
}
}