summaryrefslogtreecommitdiff
path: root/deps/v8/src/objects.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/objects.cc')
-rw-r--r--deps/v8/src/objects.cc4509
1 files changed, 3166 insertions, 1343 deletions
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc
index 7f5ce5a091..ef846d6c42 100644
--- a/deps/v8/src/objects.cc
+++ b/deps/v8/src/objects.cc
@@ -1,4 +1,4 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
+// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -28,6 +28,7 @@
#include "src/field-index-inl.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/isolate-inl.h"
#include "src/key-accumulator.h"
@@ -37,14 +38,17 @@
#include "src/macro-assembler.h"
#include "src/messages.h"
#include "src/objects-inl.h"
+#include "src/objects-body-descriptors-inl.h"
#include "src/profiler/cpu-profiler.h"
#include "src/property-descriptor.h"
#include "src/prototype.h"
+#include "src/regexp/jsregexp.h"
#include "src/safepoint-table.h"
#include "src/string-builder.h"
#include "src/string-search.h"
#include "src/string-stream.h"
#include "src/utils.h"
+#include "src/zone.h"
#ifdef ENABLE_DISASSEMBLER
#include "src/disasm.h"
@@ -54,6 +58,19 @@
namespace v8 {
namespace internal {
+std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
+ switch (instance_type) {
+#define WRITE_TYPE(TYPE) \
+ case TYPE: \
+ return os << #TYPE;
+ INSTANCE_TYPE_LIST(WRITE_TYPE)
+#undef WRITE_TYPE
+ }
+ UNREACHABLE();
+ return os << "UNKNOWN"; // Keep the compiler happy.
+}
+
+
Handle<HeapType> Object::OptimalType(Isolate* isolate,
Representation representation) {
if (representation.IsNone()) return HeapType::None(isolate);
@@ -61,9 +78,7 @@ Handle<HeapType> Object::OptimalType(Isolate* isolate,
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->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE &&
- map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE) {
+ if (map->is_stable() && map->IsJSReceiverMap()) {
return HeapType::Class(map, isolate);
}
}
@@ -608,6 +623,23 @@ MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs,
}
+Maybe<bool> Object::IsArray(Handle<Object> object) {
+ if (object->IsJSArray()) return Just(true);
+ if (object->IsJSProxy()) {
+ Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
+ Isolate* isolate = proxy->GetIsolate();
+ if (proxy->IsRevoked()) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyRevoked,
+ isolate->factory()->NewStringFromAsciiChecked("IsArray")));
+ return Nothing<bool>();
+ }
+ return Object::IsArray(handle(proxy->target(), isolate));
+ }
+ return Just(false);
+}
+
+
bool Object::IsPromise(Handle<Object> object) {
if (!object->IsJSObject()) return false;
auto js_object = Handle<JSObject>::cast(object);
@@ -633,9 +665,8 @@ MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
return isolate->factory()->undefined_value();
}
if (!func->IsCallable()) {
- // TODO(bmeurer): Better error message here?
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kCalledNonCallable, func),
+ THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction,
+ func, name, receiver),
Object);
}
return func;
@@ -643,6 +674,72 @@ MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
// static
+MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
+ Isolate* isolate, Handle<Object> object, ElementTypes element_types) {
+ // 1. ReturnIfAbrupt(object).
+ // 2. (default elementTypes -- not applicable.)
+ // 3. If Type(obj) is not Object, throw a TypeError exception.
+ if (!object->IsJSReceiver()) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kCalledOnNonObject,
+ isolate->factory()->NewStringFromAsciiChecked(
+ "CreateListFromArrayLike")),
+ FixedArray);
+ }
+ // 4. Let len be ? ToLength(? Get(obj, "length")).
+ Handle<Object> raw_length_obj;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, raw_length_obj,
+ JSReceiver::GetProperty(object, isolate->factory()->length_string()),
+ FixedArray);
+ Handle<Object> raw_length_number;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
+ Object::ToLength(isolate, raw_length_obj),
+ FixedArray);
+ uint32_t len;
+ if (!raw_length_number->ToUint32(&len) ||
+ len > static_cast<uint32_t>(FixedArray::kMaxLength)) {
+ THROW_NEW_ERROR(isolate,
+ NewRangeError(MessageTemplate::kInvalidArrayLength),
+ FixedArray);
+ }
+ // 5. Let list be an empty List.
+ Handle<FixedArray> list = isolate->factory()->NewFixedArray(len);
+ // 6. Let index be 0.
+ // 7. Repeat while index < len:
+ for (uint32_t index = 0; index < len; ++index) {
+ // 7a. Let indexName be ToString(index).
+ // 7b. Let next be ? Get(obj, indexName).
+ Handle<Object> next;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, next, Object::GetElement(isolate, object, index), FixedArray);
+ switch (element_types) {
+ case ElementTypes::kAll:
+ // Nothing to do.
+ break;
+ case ElementTypes::kStringAndSymbol: {
+ // 7c. If Type(next) is not an element of elementTypes, throw a
+ // TypeError exception.
+ if (!next->IsName()) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kNotPropertyName, next),
+ FixedArray);
+ }
+ // 7d. Append next as the last element of list.
+ // Internalize on the fly so we can use pointer identity later.
+ next = isolate->factory()->InternalizeName(Handle<Name>::cast(next));
+ break;
+ }
+ }
+ list->set(index, *next);
+ // 7e. Set index to index + 1. (See loop header.)
+ }
+ // 8. Return list.
+ return list;
+}
+
+
+// static
Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
@@ -651,8 +748,8 @@ Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
UNREACHABLE();
case LookupIterator::JSPROXY:
// Call the "has" trap on proxies.
- return JSProxy::HasPropertyWithHandler(it->GetHolder<JSProxy>(),
- it->GetName());
+ return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
+ it->GetName());
case LookupIterator::INTERCEPTOR: {
Maybe<PropertyAttributes> result =
JSObject::GetPropertyAttributesWithInterceptor(it);
@@ -688,8 +785,9 @@ MaybeHandle<Object> Object::GetProperty(LookupIterator* it,
case LookupIterator::TRANSITION:
UNREACHABLE();
case LookupIterator::JSPROXY:
- return JSProxy::GetPropertyWithHandler(
- it->GetHolder<JSProxy>(), it->GetReceiver(), it->GetName());
+ return JSProxy::GetProperty(it->isolate(), it->GetHolder<JSProxy>(),
+ it->GetName(), it->GetReceiver(),
+ language_mode);
case LookupIterator::INTERCEPTOR: {
bool done;
Handle<Object> result;
@@ -714,6 +812,104 @@ MaybeHandle<Object> Object::GetProperty(LookupIterator* it,
}
+#define STACK_CHECK(result_value) \
+ do { \
+ StackLimitCheck stack_check(isolate); \
+ if (stack_check.HasOverflowed()) { \
+ isolate->Throw(*isolate->factory()->NewRangeError( \
+ MessageTemplate::kStackOverflow)); \
+ return result_value; \
+ } \
+ } while (false)
+
+
+// static
+MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
+ Handle<JSProxy> proxy,
+ Handle<Name> name,
+ Handle<Object> receiver,
+ LanguageMode language_mode) {
+ if (receiver->IsJSGlobalObject()) {
+ THROW_NEW_ERROR(
+ isolate,
+ NewTypeError(MessageTemplate::kReadGlobalReferenceThroughProxy, name),
+ Object);
+ }
+
+ DCHECK(!name->IsPrivate());
+ STACK_CHECK(MaybeHandle<Object>());
+ Handle<Name> trap_name = isolate->factory()->get_string();
+ // 1. Assert: IsPropertyKey(P) is true.
+ // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
+ Handle<Object> handler(proxy->handler(), isolate);
+ // 3. If handler is null, throw a TypeError exception.
+ // 4. Assert: Type(handler) is Object.
+ if (proxy->IsRevoked()) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
+ Object);
+ }
+ // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
+ Handle<JSReceiver> target(proxy->target(), isolate);
+ // 6. Let trap be ? GetMethod(handler, "get").
+ Handle<Object> trap;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, trap,
+ Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
+ // 7. If trap is undefined, then
+ if (trap->IsUndefined()) {
+ // 7.a Return target.[[Get]](P, Receiver).
+ LookupIterator it =
+ LookupIterator::PropertyOrElement(isolate, receiver, name, target);
+ return Object::GetProperty(&it, language_mode);
+ }
+ // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»).
+ Handle<Object> trap_result;
+ Handle<Object> args[] = {target, name, receiver};
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, trap_result,
+ Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
+ // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
+ PropertyDescriptor target_desc;
+ Maybe<bool> target_found =
+ JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
+ MAYBE_RETURN_NULL(target_found);
+ // 10. If targetDesc is not undefined, then
+ if (target_found.FromJust()) {
+ // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is
+ // false and targetDesc.[[Writable]] is false, then
+ // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
+ // throw a TypeError exception.
+ bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
+ !target_desc.configurable() &&
+ !target_desc.writable() &&
+ !trap_result->SameValue(*target_desc.value());
+ if (inconsistent) {
+ THROW_NEW_ERROR(
+ isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableData,
+ name, target_desc.value(), trap_result),
+ Object);
+ }
+ // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
+ // is false and targetDesc.[[Get]] is undefined, then
+ // 10.b.i. If trapResult is not undefined, throw a TypeError exception.
+ inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
+ !target_desc.configurable() &&
+ target_desc.get()->IsUndefined() &&
+ !trap_result->IsUndefined();
+ if (inconsistent) {
+ THROW_NEW_ERROR(
+ isolate,
+ NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, name,
+ trap_result),
+ Object);
+ }
+ }
+ // 11. Return trap_result
+ return trap_result;
+}
+
+
Handle<Object> JSReceiver::GetDataProperty(Handle<JSReceiver> object,
Handle<Name> name) {
LookupIterator it(object, name,
@@ -730,7 +926,9 @@ Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
case LookupIterator::TRANSITION:
UNREACHABLE();
case LookupIterator::ACCESS_CHECK:
- if (it->HasAccess()) continue;
+ // Support calling this method without an active context, but refuse
+ // access to access-checked objects in that case.
+ if (it->isolate()->context() != nullptr && it->HasAccess()) continue;
// Fall through.
case LookupIterator::JSPROXY:
it->NotFound();
@@ -831,6 +1029,33 @@ Object* FunctionTemplateInfo::GetCompatibleReceiver(Isolate* isolate,
}
+// static
+MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
+ Handle<JSReceiver> new_target,
+ Handle<AllocationSite> site) {
+ // If called through new, new.target can be:
+ // - a subclass of constructor,
+ // - a proxy wrapper around constructor, or
+ // - the constructor itself.
+ // If called through Reflect.construct, it's guaranteed to be a constructor.
+ Isolate* const isolate = constructor->GetIsolate();
+ DCHECK(constructor->IsConstructor());
+ DCHECK(new_target->IsConstructor());
+ DCHECK(!constructor->has_initial_map() ||
+ constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
+
+ Handle<Map> initial_map;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, initial_map,
+ JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
+ Handle<JSObject> result =
+ isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
+ isolate->counters()->constructed_objects()->Increment();
+ isolate->counters()->constructed_objects_runtime()->Increment();
+ return result;
+}
+
+
Handle<FixedArray> JSObject::EnsureWritableFastElements(
Handle<JSObject> object) {
DCHECK(object->HasFastSmiOrObjectElements());
@@ -845,17 +1070,64 @@ Handle<FixedArray> JSObject::EnsureWritableFastElements(
}
-MaybeHandle<Object> JSProxy::GetPropertyWithHandler(Handle<JSProxy> proxy,
- Handle<Object> receiver,
- Handle<Name> name) {
+// ES6 9.5.1
+// static
+MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
Isolate* isolate = proxy->GetIsolate();
+ Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
- // TODO(rossberg): adjust once there is a story for symbols vs proxies.
- if (name->IsSymbol()) return isolate->factory()->undefined_value();
+ STACK_CHECK(MaybeHandle<Object>());
- Handle<Object> args[] = { receiver, name };
- return CallTrap(
- proxy, "get", isolate->derived_get_trap(), arraysize(args), args);
+ // 1. Let handler be the value of the [[ProxyHandler]] internal slot.
+ // 2. If handler is null, throw a TypeError exception.
+ // 3. Assert: Type(handler) is Object.
+ // 4. Let target be the value of the [[ProxyTarget]] internal slot.
+ if (proxy->IsRevoked()) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
+ Object);
+ }
+ Handle<JSReceiver> target(proxy->target(), isolate);
+ Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
+
+ // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
+ Handle<Object> trap;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
+ Object);
+ // 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
+ if (trap->IsUndefined()) {
+ return Object::GetPrototype(isolate, target);
+ }
+ // 7. Let handlerProto be ? Call(trap, handler, «target»).
+ Handle<Object> argv[] = {target};
+ Handle<Object> handler_proto;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, handler_proto,
+ Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object);
+ // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError.
+ if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull())) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
+ Object);
+ }
+ // 9. Let extensibleTarget be ? IsExtensible(target).
+ Maybe<bool> is_extensible = JSReceiver::IsExtensible(target);
+ MAYBE_RETURN_NULL(is_extensible);
+ // 10. If extensibleTarget is true, return handlerProto.
+ if (is_extensible.FromJust()) return handler_proto;
+ // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
+ Handle<Object> target_proto;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto,
+ Object::GetPrototype(isolate, target), Object);
+ // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError.
+ if (!handler_proto->SameValue(*target_proto)) {
+ THROW_NEW_ERROR(
+ isolate,
+ NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible),
+ Object);
+ }
+ // 13. Return handlerProto.
+ return handler_proto;
}
@@ -992,11 +1264,6 @@ MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
return MaybeHandle<Object>();
}
- Debug* debug = isolate->debug();
- // Handle stepping into a getter if step into is active.
- // TODO(rossberg): should this apply to getters that are function proxies?
- if (debug->is_active()) debug->HandleStepIn(getter, false);
-
return Execution::Call(isolate, getter, receiver, 0, NULL);
}
@@ -1007,11 +1274,6 @@ Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver,
ShouldThrow should_throw) {
Isolate* isolate = setter->GetIsolate();
- Debug* debug = isolate->debug();
- // Handle stepping into a setter if step into is active.
- // TODO(rossberg): should this apply to getters that are function proxies?
- if (debug->is_active()) debug->HandleStepIn(setter, false);
-
Handle<Object> argv[] = { value };
RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver,
arraysize(argv), argv),
@@ -1021,6 +1283,18 @@ Maybe<bool> Object::SetPropertyWithDefinedSetter(Handle<Object> receiver,
// static
+bool Object::IsErrorObject(Isolate* isolate, Handle<Object> object) {
+ if (!object->IsJSObject()) return false;
+ // Use stack_trace_symbol as proxy for [[ErrorData]].
+ Handle<Name> symbol = isolate->factory()->stack_trace_symbol();
+ Maybe<bool> has_stack_trace =
+ JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol);
+ DCHECK(!has_stack_trace.IsNothing());
+ return has_stack_trace.FromJust();
+}
+
+
+// static
bool JSObject::AllCanRead(LookupIterator* it) {
// Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
// which have already been checked.
@@ -1034,6 +1308,9 @@ bool JSObject::AllCanRead(LookupIterator* it) {
}
} else if (it->state() == LookupIterator::INTERCEPTOR) {
if (it->GetInterceptor()->all_can_read()) return true;
+ } else if (it->state() == LookupIterator::JSPROXY) {
+ // Stop lookupiterating. And no, AllCanNotRead.
+ return false;
}
}
return false;
@@ -1089,7 +1366,7 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
// static
bool JSObject::AllCanWrite(LookupIterator* it) {
- for (; it->IsFound(); it->Next()) {
+ for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) {
if (it->state() == LookupIterator::ACCESSOR) {
Handle<Object> accessors = it->GetAccessors();
if (accessors->IsAccessorInfo()) {
@@ -1160,12 +1437,13 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object,
}
-bool Object::HasInPrototypeChain(Isolate* isolate, Object* target) {
- PrototypeIterator iter(isolate, this, PrototypeIterator::START_AT_RECEIVER);
+Maybe<bool> Object::HasInPrototypeChain(Isolate* isolate, Handle<Object> object,
+ Handle<Object> proto) {
+ PrototypeIterator iter(isolate, object, PrototypeIterator::START_AT_RECEIVER);
while (true) {
- iter.AdvanceIgnoringProxies();
- if (iter.IsAtEnd()) return false;
- if (iter.IsAtEnd(target)) return true;
+ if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
+ if (iter.IsAtEnd()) return Just(false);
+ if (iter.IsAtEnd(proto)) return Just(true);
}
}
@@ -1329,6 +1607,56 @@ bool Object::SameValueZero(Object* other) {
}
+MaybeHandle<Object> Object::ArraySpeciesConstructor(
+ Isolate* isolate, Handle<Object> original_array) {
+ Handle<Context> native_context = isolate->native_context();
+ if (!FLAG_harmony_species) {
+ return Handle<Object>(native_context->array_function(), isolate);
+ }
+ Handle<Object> constructor = isolate->factory()->undefined_value();
+ Maybe<bool> is_array = Object::IsArray(original_array);
+ MAYBE_RETURN_NULL(is_array);
+ if (is_array.FromJust()) {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, constructor,
+ Object::GetProperty(original_array,
+ isolate->factory()->constructor_string()),
+ Object);
+ if (constructor->IsConstructor()) {
+ Handle<Context> constructor_context;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, constructor_context,
+ JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
+ Object);
+ if (*constructor_context != *native_context &&
+ *constructor == constructor_context->array_function()) {
+ constructor = isolate->factory()->undefined_value();
+ }
+ }
+ if (constructor->IsJSReceiver()) {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, constructor,
+ Object::GetProperty(constructor,
+ isolate->factory()->species_symbol()),
+ Object);
+ if (constructor->IsNull()) {
+ constructor = isolate->factory()->undefined_value();
+ }
+ }
+ }
+ if (constructor->IsUndefined()) {
+ return Handle<Object>(native_context->array_function(), isolate);
+ } else {
+ if (!constructor->IsConstructor()) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kSpeciesNotConstructor),
+ Object);
+ }
+ return constructor;
+ }
+}
+
+
void Object::ShortPrint(FILE* out) {
OFStream os(out);
os << Brief(this);
@@ -1420,6 +1748,7 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
// Externalizing twice leaks the external resource, so it's
// prohibited by the API.
DCHECK(!this->IsExternalString());
+ DCHECK(!resource->IsCompressible());
#ifdef ENABLE_SLOW_DCHECKS
if (FLAG_enable_slow_asserts) {
// Assert that the resource and the string are equivalent.
@@ -1482,6 +1811,7 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
// Externalizing twice leaks the external resource, so it's
// prohibited by the API.
DCHECK(!this->IsExternalString());
+ DCHECK(!resource->IsCompressible());
#ifdef ENABLE_SLOW_DCHECKS
if (FLAG_enable_slow_asserts) {
// Assert that the resource and the string are equivalent.
@@ -1619,6 +1949,22 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) {
accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
break;
}
+ case JS_BOUND_FUNCTION_TYPE: {
+ JSBoundFunction* bound_function = JSBoundFunction::cast(this);
+ Object* name = bound_function->name();
+ accumulator->Add("<JS BoundFunction");
+ if (name->IsString()) {
+ String* str = String::cast(name);
+ if (str->length() > 0) {
+ accumulator->Add(" ");
+ accumulator->Put(str);
+ }
+ }
+ accumulator->Add(
+ " (BoundTargetFunction %p)>",
+ reinterpret_cast<void*>(bound_function->bound_target_function()));
+ break;
+ }
case JS_WEAK_MAP_TYPE: {
accumulator->Add("<JS WeakMap>");
break;
@@ -1745,9 +2091,7 @@ MaybeHandle<JSFunction> Map::GetConstructorFunction(
void Map::PrintReconfiguration(FILE* file, int modify_index, PropertyKind kind,
PropertyAttributes attributes) {
OFStream os(file);
- os << "[reconfiguring ";
- constructor_name()->PrintOn(file);
- os << "] ";
+ os << "[reconfiguring]";
Name* name = instance_descriptors()->GetKey(modify_index);
if (name->IsString()) {
String::cast(name)->PrintOn(file);
@@ -1772,9 +2116,7 @@ void Map::PrintGeneralization(FILE* file,
HeapType* old_field_type,
HeapType* new_field_type) {
OFStream os(file);
- os << "[generalizing ";
- constructor_name()->PrintOn(file);
- os << "] ";
+ os << "[generalizing]";
Name* name = instance_descriptors()->GetKey(modify_index);
if (name->IsString()) {
String::cast(name)->PrintOn(file);
@@ -1806,9 +2148,7 @@ void Map::PrintGeneralization(FILE* file,
void JSObject::PrintInstanceMigration(FILE* file,
Map* original_map,
Map* new_map) {
- PrintF(file, "[migrating ");
- map()->constructor_name()->PrintOn(file);
- PrintF(file, "] ");
+ PrintF(file, "[migrating]");
DescriptorArray* o = original_map->instance_descriptors();
DescriptorArray* n = new_map->instance_descriptors();
for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
@@ -1877,6 +2217,10 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
case BYTECODE_ARRAY_TYPE:
os << "<BytecodeArray[" << BytecodeArray::cast(this)->length() << "]>";
break;
+ case TRANSITION_ARRAY_TYPE:
+ os << "<TransitionArray[" << TransitionArray::cast(this)->length()
+ << "]>";
+ break;
case FREE_SPACE_TYPE:
os << "<FreeSpace[" << FreeSpace::cast(this)->size() << "]>";
break;
@@ -1961,9 +2305,6 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
case JS_PROXY_TYPE:
os << "<JSProxy>";
break;
- case JS_FUNCTION_PROXY_TYPE:
- os << "<JSFunctionProxy>";
- break;
case FOREIGN_TYPE:
os << "<Foreign>";
break;
@@ -1999,12 +2340,33 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
}
-void HeapObject::Iterate(ObjectVisitor* v) {
- // Handle header
- IteratePointer(v, kMapOffset);
- // Handle object body
+void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
+
+
+void HeapObject::IterateBody(ObjectVisitor* v) {
Map* m = map();
- IterateBody(m->instance_type(), SizeFromMap(m), v);
+ IterateBodyFast<ObjectVisitor>(m->instance_type(), SizeFromMap(m), v);
+}
+
+
+void HeapObject::IterateBody(InstanceType type, int object_size,
+ ObjectVisitor* v) {
+ IterateBodyFast<ObjectVisitor>(type, object_size, v);
+}
+
+
+struct CallIsValidSlot {
+ template <typename BodyDescriptor>
+ static bool apply(HeapObject* obj, int offset, int) {
+ return BodyDescriptor::IsValidSlot(obj, offset);
+ }
+};
+
+
+bool HeapObject::IsValidSlot(int offset) {
+ DCHECK_NE(0, offset);
+ return BodyDescriptorApply<CallIsValidSlot, bool>(map()->instance_type(),
+ this, offset, 0);
}
@@ -2126,7 +2488,7 @@ void Simd128Value::CopyBits(void* destination) const {
String* JSReceiver::class_name() {
- if (IsJSFunction() || IsJSFunctionProxy()) {
+ if (IsFunction()) {
return GetHeap()->Function_string();
}
Object* maybe_constructor = map()->GetConstructor();
@@ -2139,31 +2501,89 @@ String* JSReceiver::class_name() {
}
-String* Map::constructor_name() {
- if (is_prototype_map() && prototype_info()->IsPrototypeInfo()) {
- PrototypeInfo* proto_info = PrototypeInfo::cast(prototype_info());
- if (proto_info->constructor_name()->IsString()) {
- return String::cast(proto_info->constructor_name());
+MaybeHandle<String> JSReceiver::BuiltinStringTag(Handle<JSReceiver> object) {
+ Maybe<bool> is_array = Object::IsArray(object);
+ MAYBE_RETURN(is_array, MaybeHandle<String>());
+ Isolate* const isolate = object->GetIsolate();
+ if (is_array.FromJust()) {
+ return isolate->factory()->Array_string();
+ }
+ // TODO(adamk): According to ES2015, we should return "Function" when
+ // object has a [[Call]] internal method (corresponds to IsCallable).
+ // But this is well cemented in layout tests and might cause webbreakage.
+ // if (object->IsCallable()) {
+ // return isolate->factory()->Function_string();
+ // }
+ // TODO(adamk): class_name() is expensive, replace with instance type
+ // checks where possible.
+ return handle(object->class_name(), isolate);
+}
+
+
+// static
+Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
+ Isolate* isolate = receiver->GetIsolate();
+
+ // If the object was instantiated simply with base == new.target, the
+ // constructor on the map provides the most accurate name.
+ // Don't provide the info for prototypes, since their constructors are
+ // reclaimed and replaced by Object in OptimizeAsPrototype.
+ if (!receiver->IsJSProxy() && receiver->map()->new_target_is_base() &&
+ !receiver->map()->is_prototype_map()) {
+ Object* maybe_constructor = receiver->map()->GetConstructor();
+ if (maybe_constructor->IsJSFunction()) {
+ JSFunction* constructor = JSFunction::cast(maybe_constructor);
+ String* name = String::cast(constructor->shared()->name());
+ if (name->length() == 0) name = constructor->shared()->inferred_name();
+ if (name->length() != 0 &&
+ !name->Equals(isolate->heap()->Object_string())) {
+ return handle(name, isolate);
+ }
}
}
- Object* maybe_constructor = GetConstructor();
+
+ if (FLAG_harmony_tostring) {
+ Handle<Object> maybe_tag = JSReceiver::GetDataProperty(
+ receiver, isolate->factory()->to_string_tag_symbol());
+ if (maybe_tag->IsString()) return Handle<String>::cast(maybe_tag);
+ }
+
+ PrototypeIterator iter(isolate, receiver);
+ if (iter.IsAtEnd()) return handle(receiver->class_name());
+ Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter);
+ LookupIterator it(receiver, isolate->factory()->constructor_string(), start,
+ LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
+ Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
+ Handle<String> result = isolate->factory()->Object_string();
if (maybe_constructor->IsJSFunction()) {
- JSFunction* constructor = JSFunction::cast(maybe_constructor);
+ JSFunction* constructor = JSFunction::cast(*maybe_constructor);
String* name = String::cast(constructor->shared()->name());
- if (name->length() > 0) return name;
- String* inferred_name = constructor->shared()->inferred_name();
- if (inferred_name->length() > 0) return inferred_name;
- Object* proto = prototype();
- if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
+ if (name->length() == 0) name = constructor->shared()->inferred_name();
+ if (name->length() > 0) result = handle(name, isolate);
}
- // TODO(rossberg): what about proxies?
- // If the constructor is not present, return "Object".
- return GetHeap()->Object_string();
+
+ return result.is_identical_to(isolate->factory()->Object_string())
+ ? handle(receiver->class_name())
+ : result;
}
-String* JSReceiver::constructor_name() {
- return map()->constructor_name();
+Context* JSReceiver::GetCreationContext() {
+ if (IsJSBoundFunction()) {
+ return JSBoundFunction::cast(this)->creation_context();
+ }
+ Object* constructor = 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);
+ }
+
+ return function->context()->native_context();
}
@@ -2271,21 +2691,6 @@ void JSObject::AddSlowProperty(Handle<JSObject> object,
}
-Context* JSObject::GetCreationContext() {
- Object* constructor = this->map()->GetConstructor();
- JSFunction* function;
- if (!constructor->IsJSFunction()) {
- // Functions have null as a constructor,
- // but any JSFunction knows its context immediately.
- function = JSFunction::cast(this);
- } else {
- function = JSFunction::cast(constructor);
- }
-
- return function->context()->native_context();
-}
-
-
MaybeHandle<Object> JSObject::EnqueueChangeRecord(Handle<JSObject> object,
const char* type_str,
Handle<Name> name,
@@ -2355,9 +2760,10 @@ bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
}
-static void UpdatePrototypeUserRegistration(Handle<Map> old_map,
- Handle<Map> new_map,
- Isolate* isolate) {
+// static
+void JSObject::UpdatePrototypeUserRegistration(Handle<Map> old_map,
+ Handle<Map> new_map,
+ Isolate* isolate) {
if (!FLAG_track_prototype_users) return;
if (!old_map->is_prototype_map()) return;
DCHECK(new_map->is_prototype_map());
@@ -2724,25 +3130,13 @@ static inline bool EqualImmutableValues(Object* obj1, Object* obj2) {
}
-// Invalidates a transition target at |key|, and installs |new_descriptors| over
-// the current instance_descriptors to ensure proper sharing of descriptor
-// arrays.
-// Returns true if the transition target at given key was deprecated.
-bool Map::DeprecateTarget(PropertyKind kind, Name* key,
- PropertyAttributes attributes,
- DescriptorArray* new_descriptors,
- LayoutDescriptor* new_layout_descriptor) {
- bool transition_target_deprecated = false;
- Map* maybe_transition =
- TransitionArray::SearchTransition(this, kind, key, attributes);
- if (maybe_transition != NULL) {
- maybe_transition->DeprecateTransitionTree();
- transition_target_deprecated = true;
- }
-
+// Installs |new_descriptors| over the current instance_descriptors to ensure
+// proper sharing of descriptor arrays.
+void Map::ReplaceDescriptors(DescriptorArray* new_descriptors,
+ LayoutDescriptor* new_layout_descriptor) {
// Don't overwrite the empty descriptor array or initial map's descriptors.
if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined()) {
- return transition_target_deprecated;
+ return;
}
DescriptorArray* to_replace = instance_descriptors();
@@ -2756,7 +3150,6 @@ bool Map::DeprecateTarget(PropertyKind kind, Name* key,
current = Map::cast(next);
}
set_owns_descriptors(false);
- return transition_target_deprecated;
}
@@ -3422,9 +3815,6 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
int split_nof = split_map->NumberOfOwnDescriptors();
DCHECK_NE(old_nof, split_nof);
- Handle<LayoutDescriptor> new_layout_descriptor =
- LayoutDescriptor::New(split_map, new_descriptors, old_nof);
-
PropertyKind split_kind;
PropertyAttributes split_attributes;
if (modify_index == split_nof) {
@@ -3435,14 +3825,19 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
split_kind = split_prop_details.kind();
split_attributes = split_prop_details.attributes();
}
- bool transition_target_deprecated = split_map->DeprecateTarget(
- split_kind, old_descriptors->GetKey(split_nof), split_attributes,
- *new_descriptors, *new_layout_descriptor);
- // If |transition_target_deprecated| is true then the transition array
- // already contains entry for given descriptor. This means that the transition
+ // Invalidate a transition target at |key|.
+ Map* maybe_transition = TransitionArray::SearchTransition(
+ *split_map, split_kind, old_descriptors->GetKey(split_nof),
+ split_attributes);
+ if (maybe_transition != NULL) {
+ maybe_transition->DeprecateTransitionTree();
+ }
+
+ // If |maybe_transition| is not NULL then the transition array already
+ // contains entry for given descriptor. This means that the transition
// could be inserted regardless of whether transitions array is full or not.
- if (!transition_target_deprecated &&
+ if (maybe_transition == NULL &&
!TransitionArray::CanHaveMoreTransitions(split_map)) {
return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
new_kind, new_attributes,
@@ -3473,13 +3868,16 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
*old_field_type, *new_field_type);
}
- // Add missing transitions.
- Handle<Map> new_map = split_map;
- for (int i = split_nof; i < old_nof; ++i) {
- new_map = CopyInstallDescriptors(new_map, i, new_descriptors,
- new_layout_descriptor);
- }
- new_map->set_owns_descriptors(true);
+ Handle<LayoutDescriptor> new_layout_descriptor =
+ LayoutDescriptor::New(split_map, new_descriptors, old_nof);
+
+ Handle<Map> new_map =
+ AddMissingTransitions(split_map, new_descriptors, new_layout_descriptor);
+
+ // Deprecated part of the transition tree is no longer reachable, so replace
+ // current instance descriptors in the "survived" part of the tree with
+ // the new descriptors to maintain descriptors sharing invariant.
+ split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor);
return new_map;
}
@@ -3622,6 +4020,7 @@ Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
result = args.Call(setter, index, v8::Utils::ToLocal(value));
} else {
Handle<Name> name = it->name();
+ DCHECK(!name->IsPrivate());
if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
return Just(false);
@@ -3643,6 +4042,8 @@ Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
result_internal->VerifyApiCallResultType();
#endif
return Just(true);
+ // TODO(neis): In the future, we may want to actually return the interceptor's
+ // result, which then should be a boolean.
}
@@ -3684,21 +4085,8 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
should_throw);
case LookupIterator::JSPROXY:
- if (it->HolderIsReceiverOrHiddenPrototype()) {
- return JSProxy::SetPropertyWithHandler(
- it->GetHolder<JSProxy>(), it->GetReceiver(), it->GetName(), value,
- should_throw);
- } else {
- // TODO(verwaest): Use the MaybeHandle to indicate result.
- bool has_result = false;
- Maybe<bool> maybe_result =
- JSProxy::SetPropertyViaPrototypesWithHandler(
- it->GetHolder<JSProxy>(), it->GetReceiver(), it->GetName(),
- value, should_throw, &has_result);
- if (has_result) return maybe_result;
- done = true;
- }
- break;
+ return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
+ value, it->GetReceiver(), language_mode);
case LookupIterator::INTERCEPTOR:
if (it->HolderIsReceiverOrHiddenPrototype()) {
@@ -3767,12 +4155,16 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
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);
}
@@ -3782,6 +4174,11 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
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 =
@@ -3794,12 +4191,12 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
if (!it->GetReceiver()->IsJSReceiver()) {
return WriteToReadOnlyProperty(it, value, should_throw);
}
+ Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
LookupIterator::Configuration c = LookupIterator::OWN;
LookupIterator own_lookup =
- it->IsElement()
- ? LookupIterator(it->isolate(), it->GetReceiver(), it->index(), c)
- : LookupIterator(it->GetReceiver(), it->name(), c);
+ it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
+ : LookupIterator(receiver, it->name(), c);
for (; own_lookup.IsFound(); own_lookup.Next()) {
switch (own_lookup.state()) {
@@ -3811,7 +4208,8 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
break;
case LookupIterator::INTEGER_INDEXED_EXOTIC:
- return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value,
+ case LookupIterator::ACCESSOR:
+ return RedefineIncompatibleProperty(isolate, it->GetName(), value,
should_throw);
case LookupIterator::DATA: {
@@ -3822,18 +4220,26 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
return SetDataProperty(&own_lookup, value);
}
- case LookupIterator::ACCESSOR: {
- return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value,
- should_throw);
- }
-
case LookupIterator::INTERCEPTOR:
case LookupIterator::JSPROXY: {
- bool found = false;
- Maybe<bool> result = SetPropertyInternal(
- &own_lookup, value, language_mode, store_mode, &found);
- if (found) return result;
- break;
+ PropertyDescriptor desc;
+ Maybe<bool> owned =
+ JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
+ MAYBE_RETURN(owned, Nothing<bool>());
+ if (!owned.FromJust()) {
+ return JSReceiver::CreateDataProperty(&own_lookup, value,
+ should_throw);
+ }
+ if (PropertyDescriptor::IsAccessorDescriptor(&desc) ||
+ !desc.writable()) {
+ return RedefineIncompatibleProperty(isolate, it->GetName(), value,
+ should_throw);
+ }
+
+ PropertyDescriptor value_desc;
+ value_desc.set_value(value);
+ return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
+ &value_desc, should_throw);
}
case LookupIterator::NOT_FOUND:
@@ -3913,8 +4319,8 @@ Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate,
Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
- // Proxies are handled on the WithHandler path. Other non-JSObjects cannot
- // have own properties.
+ // Proxies are handled elsewhere. Other non-JSObjects cannot have own
+ // properties.
Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
// Store on the holder which may be hidden behind the receiver.
@@ -4372,19 +4778,16 @@ Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, to_kind);
return handle(native_context->fast_aliased_arguments_map());
}
- } else {
- Object* maybe_array_maps = map->is_strong()
- ? native_context->js_array_strong_maps()
- : native_context->js_array_maps();
+ } else if (IsFastElementsKind(from_kind) && IsFastElementsKind(to_kind)) {
// Reuse map transitions for JSArrays.
- if (maybe_array_maps->IsFixedArray()) {
- DisallowHeapAllocation no_gc;
- FixedArray* array_maps = FixedArray::cast(maybe_array_maps);
- if (array_maps->get(from_kind) == *map) {
- Object* maybe_transitioned_map = array_maps->get(to_kind);
- if (maybe_transitioned_map->IsMap()) {
- return handle(Map::cast(maybe_transitioned_map));
- }
+ DisallowHeapAllocation no_gc;
+ Strength strength = map->is_strong() ? Strength::STRONG : Strength::WEAK;
+ if (native_context->get(Context::ArrayMapIndex(from_kind, strength)) ==
+ *map) {
+ Object* maybe_transitioned_map =
+ native_context->get(Context::ArrayMapIndex(to_kind, strength));
+ if (maybe_transitioned_map->IsMap()) {
+ return handle(Map::cast(maybe_transitioned_map), isolate);
}
}
}
@@ -4433,281 +4836,291 @@ Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
}
-Maybe<bool> JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy,
- Handle<Name> name) {
+void JSProxy::Revoke(Handle<JSProxy> proxy) {
Isolate* isolate = proxy->GetIsolate();
+ if (!proxy->IsRevoked()) proxy->set_handler(isolate->heap()->null_value());
+ DCHECK(proxy->IsRevoked());
+}
- // TODO(rossberg): adjust once there is a story for symbols vs proxies.
- if (name->IsSymbol()) return Just(false);
- Handle<Object> args[] = { name };
- Handle<Object> result;
+Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
+ Handle<Name> name) {
+ DCHECK(!name->IsPrivate());
+ STACK_CHECK(Nothing<bool>());
+ // 1. (Assert)
+ // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
+ Handle<Object> handler(proxy->handler(), isolate);
+ // 3. If handler is null, throw a TypeError exception.
+ // 4. Assert: Type(handler) is Object.
+ if (proxy->IsRevoked()) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
+ return Nothing<bool>();
+ }
+ // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
+ Handle<JSReceiver> target(proxy->target(), isolate);
+ // 6. Let trap be ? GetMethod(handler, "has").
+ Handle<Object> trap;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate, result, CallTrap(proxy, "has", isolate->derived_has_trap(),
- arraysize(args), args),
+ isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
+ isolate->factory()->has_string()),
Nothing<bool>());
-
- return Just(result->BooleanValue());
+ // 7. If trap is undefined, then
+ if (trap->IsUndefined()) {
+ // 7a. Return target.[[HasProperty]](P).
+ return JSReceiver::HasProperty(target, name);
+ }
+ // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
+ Handle<Object> trap_result_obj;
+ Handle<Object> args[] = {target, name};
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap_result_obj,
+ Execution::Call(isolate, trap, handler, arraysize(args), args),
+ Nothing<bool>());
+ bool boolean_trap_result = trap_result_obj->BooleanValue();
+ // 9. If booleanTrapResult is false, then:
+ if (!boolean_trap_result) {
+ // 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
+ PropertyDescriptor target_desc;
+ Maybe<bool> target_found = JSReceiver::GetOwnPropertyDescriptor(
+ isolate, target, name, &target_desc);
+ MAYBE_RETURN(target_found, Nothing<bool>());
+ // 9b. If targetDesc is not undefined, then:
+ if (target_found.FromJust()) {
+ // 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
+ // exception.
+ if (!target_desc.configurable()) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyHasNonConfigurable, name));
+ return Nothing<bool>();
+ }
+ // 9b ii. Let extensibleTarget be ? IsExtensible(target).
+ Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
+ MAYBE_RETURN(extensible_target, Nothing<bool>());
+ // 9b iii. If extensibleTarget is false, throw a TypeError exception.
+ if (!extensible_target.FromJust()) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyHasNonExtensible, name));
+ return Nothing<bool>();
+ }
+ }
+ }
+ // 10. Return booleanTrapResult.
+ return Just(boolean_trap_result);
}
-Maybe<bool> JSProxy::SetPropertyWithHandler(Handle<JSProxy> proxy,
- Handle<Object> receiver,
- Handle<Name> name,
- Handle<Object> value,
- ShouldThrow should_throw) {
+Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
+ Handle<Object> value, Handle<Object> receiver,
+ LanguageMode language_mode) {
+ DCHECK(!name->IsPrivate());
Isolate* isolate = proxy->GetIsolate();
+ STACK_CHECK(Nothing<bool>());
+ Factory* factory = isolate->factory();
+ Handle<String> trap_name = factory->set_string();
+ ShouldThrow should_throw =
+ is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
- // TODO(rossberg): adjust once there is a story for symbols vs proxies.
- if (name->IsSymbol()) return Just(true);
+ if (proxy->IsRevoked()) {
+ isolate->Throw(
+ *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
+ return Nothing<bool>();
+ }
+ Handle<JSReceiver> target(proxy->target(), isolate);
+ Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
- Handle<Object> args[] = { receiver, name, value };
- RETURN_ON_EXCEPTION_VALUE(isolate,
- CallTrap(proxy, "set", isolate->derived_set_trap(),
- arraysize(args), args),
- Nothing<bool>());
+ Handle<Object> trap;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
+ if (trap->IsUndefined()) {
+ LookupIterator it =
+ LookupIterator::PropertyOrElement(isolate, receiver, name, target);
+ return Object::SetSuperProperty(&it, value, language_mode,
+ Object::MAY_BE_STORE_FROM_KEYED);
+ }
+ Handle<Object> trap_result;
+ Handle<Object> args[] = {target, name, value, receiver};
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap_result,
+ Execution::Call(isolate, trap, handler, arraysize(args), args),
+ Nothing<bool>());
+ if (!trap_result->BooleanValue()) {
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
+ trap_name, name));
+ }
+
+ // Enforce the invariant.
+ PropertyDescriptor target_desc;
+ Maybe<bool> owned =
+ JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
+ MAYBE_RETURN(owned, Nothing<bool>());
+ if (owned.FromJust()) {
+ bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
+ !target_desc.configurable() &&
+ !target_desc.writable() &&
+ !value->SameValue(*target_desc.value());
+ if (inconsistent) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxySetFrozenData, name));
+ return Nothing<bool>();
+ }
+ inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
+ !target_desc.configurable() &&
+ target_desc.set()->IsUndefined();
+ if (inconsistent) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxySetFrozenAccessor, name));
+ return Nothing<bool>();
+ }
+ }
return Just(true);
- // TODO(neis): This needs to be made spec-conformant by looking at the
- // trap's result.
}
-Maybe<bool> JSProxy::SetPropertyViaPrototypesWithHandler(
- Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name,
- Handle<Object> value, ShouldThrow should_throw, bool* done) {
+Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
+ Handle<Name> name,
+ LanguageMode language_mode) {
+ DCHECK(!name->IsPrivate());
+ ShouldThrow should_throw =
+ is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
Isolate* isolate = proxy->GetIsolate();
- Handle<Object> handler(proxy->handler(), isolate); // Trap might morph proxy.
+ STACK_CHECK(Nothing<bool>());
+ Factory* factory = isolate->factory();
+ Handle<String> trap_name = factory->deleteProperty_string();
- // TODO(rossberg): adjust once there is a story for symbols vs proxies.
- if (name->IsSymbol()) {
- *done = false; // Return value will be ignored.
+ if (proxy->IsRevoked()) {
+ isolate->Throw(
+ *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
return Nothing<bool>();
}
+ Handle<JSReceiver> target(proxy->target(), isolate);
+ Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
- *done = true; // except where redefined...
- Handle<Object> args[] = { name };
- Handle<Object> result;
+ Handle<Object> trap;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate, result, CallTrap(proxy, "getPropertyDescriptor",
- Handle<Object>(), arraysize(args), args),
- Nothing<bool>());
-
- if (result->IsUndefined()) {
- *done = false; // Return value will be ignored.
- return Nothing<bool>();
+ isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
+ if (trap->IsUndefined()) {
+ return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
}
- // Emulate [[GetProperty]] semantics for proxies.
- Handle<Object> argv[] = { result };
- Handle<Object> desc;
+ Handle<Object> trap_result;
+ Handle<Object> args[] = {target, name};
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate, desc,
- Execution::Call(isolate, isolate->to_complete_property_descriptor(),
- result, arraysize(argv), argv),
+ isolate, trap_result,
+ Execution::Call(isolate, trap, handler, arraysize(args), args),
Nothing<bool>());
-
- // [[GetProperty]] requires to check that all properties are configurable.
- Handle<String> configurable_name =
- isolate->factory()->InternalizeOneByteString(
- STATIC_CHAR_VECTOR("configurable_"));
- Handle<Object> configurable =
- Object::GetProperty(desc, configurable_name).ToHandleChecked();
- DCHECK(configurable->IsBoolean());
- if (configurable->IsFalse()) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kProxyPropNotConfigurable, handler, name,
- isolate->factory()->NewStringFromAsciiChecked(
- "getPropertyDescriptor")));
+ if (!trap_result->BooleanValue()) {
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
+ trap_name, name));
+ }
+
+ // Enforce the invariant.
+ PropertyDescriptor target_desc;
+ Maybe<bool> owned =
+ JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
+ MAYBE_RETURN(owned, Nothing<bool>());
+ if (owned.FromJust() && !target_desc.configurable()) {
+ isolate->Throw(*factory->NewTypeError(
+ MessageTemplate::kProxyDeletePropertyNonConfigurable, name));
return Nothing<bool>();
}
- DCHECK(configurable->IsTrue());
-
- // Check for DataDescriptor.
- Handle<String> hasWritable_name =
- isolate->factory()->InternalizeOneByteString(
- STATIC_CHAR_VECTOR("hasWritable_"));
- Handle<Object> hasWritable =
- Object::GetProperty(desc, hasWritable_name).ToHandleChecked();
- DCHECK(hasWritable->IsBoolean());
- if (hasWritable->IsTrue()) {
- Handle<String> writable_name = isolate->factory()->InternalizeOneByteString(
- STATIC_CHAR_VECTOR("writable_"));
- Handle<Object> writable =
- Object::GetProperty(desc, writable_name).ToHandleChecked();
- DCHECK(writable->IsBoolean());
- *done = writable->IsFalse();
- if (!*done) return Nothing<bool>(); // Return value will be ignored.
- return WriteToReadOnlyProperty(isolate, receiver, name, value,
- should_throw);
- }
-
- // We have an AccessorDescriptor.
- Handle<String> set_name =
- isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("set_"));
- Handle<Object> setter = Object::GetProperty(desc, set_name).ToHandleChecked();
- if (!setter->IsUndefined()) {
- // TODO(rossberg): nicer would be to cast to some JSCallable here...
- return SetPropertyWithDefinedSetter(
- receiver, Handle<JSReceiver>::cast(setter), value, should_throw);
- }
-
- RETURN_FAILURE(
- isolate, should_throw,
- NewTypeError(MessageTemplate::kNoSetterInCallback, name, proxy));
+ return Just(true);
}
-MaybeHandle<Object> JSProxy::DeletePropertyWithHandler(
- Handle<JSProxy> proxy, Handle<Name> name, LanguageMode language_mode) {
- Isolate* isolate = proxy->GetIsolate();
+// static
+MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
+ Handle<Object> handler) {
+ if (!target->IsJSReceiver()) {
+ THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
+ JSProxy);
+ }
+ if (target->IsJSProxy() && JSProxy::cast(*target)->IsRevoked()) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
+ JSProxy);
+ }
+ if (!handler->IsJSReceiver()) {
+ THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyNonObject),
+ JSProxy);
+ }
+ if (handler->IsJSProxy() && JSProxy::cast(*handler)->IsRevoked()) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kProxyHandlerOrTargetRevoked),
+ JSProxy);
+ }
+ return isolate->factory()->NewJSProxy(Handle<JSReceiver>::cast(target),
+ Handle<JSReceiver>::cast(handler));
+}
- // TODO(rossberg): adjust once there is a story for symbols vs proxies.
- if (name->IsSymbol()) return isolate->factory()->false_value();
- Handle<Object> args[] = { name };
- Handle<Object> result;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, result,
- CallTrap(proxy,
- "delete",
- Handle<Object>(),
- arraysize(args),
- args),
- Object);
-
- bool result_bool = result->BooleanValue();
- if (is_strict(language_mode) && !result_bool) {
- Handle<Object> handler(proxy->handler(), isolate);
- THROW_NEW_ERROR(
- isolate,
- NewTypeError(MessageTemplate::kProxyHandlerDeleteFailed, handler),
- Object);
+// static
+MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
+ DCHECK(proxy->map()->is_constructor());
+ if (proxy->IsRevoked()) {
+ THROW_NEW_ERROR(proxy->GetIsolate(),
+ NewTypeError(MessageTemplate::kProxyRevoked), Context);
}
- return isolate->factory()->ToBoolean(result_bool);
+ Handle<JSReceiver> target(JSReceiver::cast(proxy->target()));
+ return JSReceiver::GetFunctionRealm(target);
}
-Maybe<PropertyAttributes> JSProxy::GetPropertyAttributesWithHandler(
- Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name) {
- Isolate* isolate = proxy->GetIsolate();
- HandleScope scope(isolate);
+// static
+MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
+ Handle<JSBoundFunction> function) {
+ DCHECK(function->map()->is_constructor());
+ return JSReceiver::GetFunctionRealm(
+ handle(function->bound_target_function()));
+}
- // TODO(rossberg): adjust once there is a story for symbols vs proxies.
- if (name->IsSymbol()) return Just(ABSENT);
- Handle<Object> args[] = { name };
- Handle<Object> result;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate, result, proxy->CallTrap(proxy, "getPropertyDescriptor",
- Handle<Object>(), arraysize(args), args),
- Nothing<PropertyAttributes>());
+// static
+Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
+ DCHECK(function->map()->is_constructor());
+ return handle(function->context()->native_context());
+}
- if (result->IsUndefined()) return Just(ABSENT);
- Handle<Object> argv[] = { result };
- Handle<Object> desc;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate, desc,
- Execution::Call(isolate, isolate->to_complete_property_descriptor(),
- result, arraysize(argv), argv),
- Nothing<PropertyAttributes>());
-
- // Convert result to PropertyAttributes.
- Handle<String> enum_n = isolate->factory()->InternalizeOneByteString(
- STATIC_CHAR_VECTOR("enumerable_"));
- Handle<Object> enumerable;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, enumerable,
- Object::GetProperty(desc, enum_n),
- Nothing<PropertyAttributes>());
- Handle<String> conf_n = isolate->factory()->InternalizeOneByteString(
- STATIC_CHAR_VECTOR("configurable_"));
- Handle<Object> configurable;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, configurable,
- Object::GetProperty(desc, conf_n),
- Nothing<PropertyAttributes>());
- Handle<String> writ_n = isolate->factory()->InternalizeOneByteString(
- STATIC_CHAR_VECTOR("writable_"));
- Handle<Object> writable;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, writable,
- Object::GetProperty(desc, writ_n),
- Nothing<PropertyAttributes>());
- if (!writable->BooleanValue()) {
- Handle<String> set_n = isolate->factory()->InternalizeOneByteString(
- STATIC_CHAR_VECTOR("set_"));
- Handle<Object> setter;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, setter,
- Object::GetProperty(desc, set_n),
- Nothing<PropertyAttributes>());
- writable = isolate->factory()->ToBoolean(!setter->IsUndefined());
- }
-
- if (configurable->IsFalse()) {
- Handle<Object> handler(proxy->handler(), isolate);
- Handle<String> trap = isolate->factory()->InternalizeOneByteString(
- STATIC_CHAR_VECTOR("getPropertyDescriptor"));
- Handle<Object> error = isolate->factory()->NewTypeError(
- MessageTemplate::kProxyPropNotConfigurable, handler, name, trap);
- isolate->Throw(*error);
- return Nothing<PropertyAttributes>();
- }
-
- int attributes = NONE;
- if (!enumerable->BooleanValue()) attributes |= DONT_ENUM;
- if (!configurable->BooleanValue()) attributes |= DONT_DELETE;
- if (!writable->BooleanValue()) attributes |= READ_ONLY;
- return Just(static_cast<PropertyAttributes>(attributes));
-}
-
-
-void JSProxy::Fix(Handle<JSProxy> proxy) {
- Isolate* isolate = proxy->GetIsolate();
+// static
+MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
+ DCHECK(object->map()->is_constructor());
+ DCHECK(!object->IsJSFunction());
+ return handle(object->GetCreationContext());
+}
- // Save identity hash.
- Handle<Object> hash(proxy->GetIdentityHash(), isolate);
- if (proxy->IsJSFunctionProxy()) {
- isolate->factory()->BecomeJSFunction(proxy);
- // Code will be set on the JavaScript side.
- } else {
- isolate->factory()->BecomeJSObject(proxy);
+// static
+MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
+ if (receiver->IsJSProxy()) {
+ return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
}
- DCHECK(proxy->IsJSObject());
- // Inherit identity, if it was present.
- if (hash->IsSmi()) {
- JSObject::SetIdentityHash(Handle<JSObject>::cast(proxy),
- Handle<Smi>::cast(hash));
+ if (receiver->IsJSFunction()) {
+ return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
}
-}
+ if (receiver->IsJSBoundFunction()) {
+ return JSBoundFunction::GetFunctionRealm(
+ Handle<JSBoundFunction>::cast(receiver));
+ }
-MaybeHandle<Object> JSProxy::CallTrap(Handle<JSProxy> proxy,
- const char* name,
- Handle<Object> derived,
- int argc,
- Handle<Object> argv[]) {
- Isolate* isolate = proxy->GetIsolate();
- Handle<Object> handler(proxy->handler(), isolate);
+ return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
+}
- Handle<String> trap_name = isolate->factory()->InternalizeUtf8String(name);
- Handle<Object> trap;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, trap,
- Object::GetPropertyOrElement(handler, trap_name),
- Object);
- if (trap->IsUndefined()) {
- if (derived.is_null()) {
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kProxyHandlerTrapMissing,
- handler, trap_name),
- Object);
- }
- trap = Handle<Object>(derived);
- }
-
- return Execution::Call(isolate, trap, handler, argc, argv);
+Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
+ Isolate* isolate = it->isolate();
+ HandleScope scope(isolate);
+ PropertyDescriptor desc;
+ Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
+ isolate, it->GetHolder<JSProxy>(), it->GetName(), &desc);
+ MAYBE_RETURN(found, Nothing<PropertyAttributes>());
+ if (!found.FromJust()) return Just(ABSENT);
+ return Just(desc.ToAttributes());
}
@@ -4963,28 +5376,6 @@ MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
}
-Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
- Handle<Object> value) {
- DCHECK(it->GetReceiver()->IsJSObject());
- Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(it);
- if (maybe.IsNothing()) return Nothing<bool>();
-
- if (it->IsFound()) {
- if (!it->IsConfigurable()) return Just(false);
- } else {
- if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver())))
- return Just(false);
- }
-
- RETURN_ON_EXCEPTION_VALUE(
- it->isolate(),
- DefineOwnPropertyIgnoreAttributes(it, value, NONE, DONT_FORCE_FIELD),
- Nothing<bool>());
-
- return Just(true);
-}
-
-
Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
LookupIterator* it) {
Isolate* isolate = it->isolate();
@@ -5012,6 +5403,7 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
result = args.Call(query, index);
} else {
Handle<Name> name = it->name();
+ DCHECK(!name->IsPrivate());
v8::GenericNamedPropertyQueryCallback query =
v8::ToCData<v8::GenericNamedPropertyQueryCallback>(
interceptor->query());
@@ -5037,7 +5429,7 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
result = args.Call(getter, index);
} else {
Handle<Name> name = it->name();
-
+ DCHECK(!name->IsPrivate());
v8::GenericNamedPropertyGetterCallback getter =
v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
interceptor->getter());
@@ -5061,8 +5453,7 @@ Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
case LookupIterator::TRANSITION:
UNREACHABLE();
case LookupIterator::JSPROXY:
- return JSProxy::GetPropertyAttributesWithHandler(
- it->GetHolder<JSProxy>(), it->GetReceiver(), it->GetName());
+ return JSProxy::GetPropertyAttributes(it);
case LookupIterator::INTERCEPTOR: {
Maybe<PropertyAttributes> result =
JSObject::GetPropertyAttributesWithInterceptor(it);
@@ -5451,7 +5842,7 @@ void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
dictionary->set_requires_slow_elements();
// TODO(verwaest): Remove this hack.
if (map()->is_prototype_map()) {
- GetHeap()->ClearAllKeyedStoreICs();
+ TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate());
}
}
@@ -5582,7 +5973,6 @@ Handle<Smi> JSObject::GetOrCreateIdentityHash(Handle<JSObject> object) {
if (object->IsJSGlobalProxy()) {
return GetOrCreateIdentityHashHelper(Handle<JSGlobalProxy>::cast(object));
}
-
Isolate* isolate = object->GetIsolate();
Handle<Object> maybe_hash(object->GetIdentityHash(), isolate);
@@ -5757,8 +6147,7 @@ Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object,
}
-MaybeHandle<Object> JSObject::DeletePropertyWithInterceptor(
- LookupIterator* it) {
+Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it) {
Isolate* isolate = it->isolate();
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
@@ -5766,7 +6155,7 @@ MaybeHandle<Object> JSObject::DeletePropertyWithInterceptor(
DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
Handle<InterceptorInfo> interceptor(it->GetInterceptor());
- if (interceptor->deleter()->IsUndefined()) return MaybeHandle<Object>();
+ if (interceptor->deleter()->IsUndefined()) return Nothing<bool>();
Handle<JSObject> holder = it->GetHolder<JSObject>();
@@ -5781,9 +6170,10 @@ MaybeHandle<Object> JSObject::DeletePropertyWithInterceptor(
ApiIndexedPropertyAccess("interceptor-indexed-delete", *holder, index));
result = args.Call(deleter, index);
} else if (it->name()->IsSymbol() && !interceptor->can_intercept_symbols()) {
- return MaybeHandle<Object>();
+ return Nothing<bool>();
} else {
Handle<Name> name = it->name();
+ DCHECK(!name->IsPrivate());
v8::GenericNamedPropertyDeleterCallback deleter =
v8::ToCData<v8::GenericNamedPropertyDeleterCallback>(
interceptor->deleter());
@@ -5792,25 +6182,26 @@ MaybeHandle<Object> JSObject::DeletePropertyWithInterceptor(
result = args.Call(deleter, v8::Utils::ToLocal(name));
}
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
- if (result.IsEmpty()) return MaybeHandle<Object>();
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
+ if (result.IsEmpty()) return Nothing<bool>();
DCHECK(result->IsBoolean());
Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
result_internal->VerifyApiCallResultType();
// Rebox CustomArguments::kReturnValueOffset before returning.
- return handle(*result_internal, isolate);
+ return Just(result_internal->BooleanValue());
}
-void JSObject::DeleteNormalizedProperty(Handle<JSObject> object,
- Handle<Name> name, int entry) {
+void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
+ Handle<Name> name, int entry) {
DCHECK(!object->HasFastProperties());
Isolate* isolate = object->GetIsolate();
if (object->IsJSGlobalObject()) {
// If we have a global object, invalidate the cell and swap in a new one.
- Handle<GlobalDictionary> dictionary(object->global_dictionary());
+ Handle<GlobalDictionary> dictionary(
+ JSObject::cast(*object)->global_dictionary());
DCHECK_NE(GlobalDictionary::kNotFound, entry);
auto cell = PropertyCell::InvalidateEntry(dictionary, entry);
@@ -5830,15 +6221,23 @@ void JSObject::DeleteNormalizedProperty(Handle<JSObject> object,
}
-// ECMA-262, 3rd, 8.6.2.5
-MaybeHandle<Object> JSReceiver::DeleteProperty(LookupIterator* it,
- LanguageMode language_mode) {
+Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
+ LanguageMode language_mode) {
Isolate* isolate = it->isolate();
+
if (it->state() == LookupIterator::JSPROXY) {
- return JSProxy::DeletePropertyWithHandler(it->GetHolder<JSProxy>(),
- it->GetName(), language_mode);
+ return JSProxy::DeletePropertyOrElement(it->GetHolder<JSProxy>(),
+ it->GetName(), language_mode);
}
+ if (it->GetReceiver()->IsJSProxy()) {
+ if (it->state() != LookupIterator::NOT_FOUND) {
+ DCHECK_EQ(LookupIterator::DATA, it->state());
+ DCHECK(it->GetName()->IsPrivate());
+ it->Delete();
+ }
+ return Just(true);
+ }
Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
bool is_observed =
@@ -5856,19 +6255,20 @@ MaybeHandle<Object> JSReceiver::DeleteProperty(LookupIterator* it,
case LookupIterator::ACCESS_CHECK:
if (it->HasAccess()) break;
isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
- return it->factory()->false_value();
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
+ return Just(false);
case LookupIterator::INTERCEPTOR: {
- MaybeHandle<Object> maybe_result =
- JSObject::DeletePropertyWithInterceptor(it);
- // Delete with interceptor succeeded. Return result.
- if (!maybe_result.is_null()) return maybe_result;
+ Maybe<bool> result = JSObject::DeletePropertyWithInterceptor(it);
// An exception was thrown in the interceptor. Propagate.
- if (isolate->has_pending_exception()) return maybe_result;
+ if (isolate->has_pending_exception()) return Nothing<bool>();
+ // Delete with interceptor succeeded. Return result.
+ // TODO(neis): In strict mode, we should probably throw if the
+ // interceptor returns false.
+ if (result.IsJust()) return result;
break;
}
case LookupIterator::INTEGER_INDEXED_EXOTIC:
- return it->factory()->true_value();
+ return Just(true);
case LookupIterator::DATA:
if (is_observed) {
old_value = it->GetDataValue();
@@ -5882,49 +6282,50 @@ MaybeHandle<Object> JSReceiver::DeleteProperty(LookupIterator* it,
receiver->map()->is_strong()
? MessageTemplate::kStrongDeleteProperty
: MessageTemplate::kStrictDeleteProperty;
- THROW_NEW_ERROR(
- isolate, NewTypeError(templ, it->GetName(), receiver), Object);
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ templ, it->GetName(), receiver));
+ return Nothing<bool>();
}
- return it->factory()->false_value();
+ return Just(false);
}
it->Delete();
if (is_observed) {
- RETURN_ON_EXCEPTION(isolate,
- JSObject::EnqueueChangeRecord(
- receiver, "delete", it->GetName(), old_value),
- Object);
+ RETURN_ON_EXCEPTION_VALUE(
+ isolate, JSObject::EnqueueChangeRecord(receiver, "delete",
+ it->GetName(), old_value),
+ Nothing<bool>());
}
- return it->factory()->true_value();
+ return Just(true);
}
}
}
- return it->factory()->true_value();
+ return Just(true);
}
-MaybeHandle<Object> JSReceiver::DeleteElement(Handle<JSReceiver> object,
- uint32_t index,
- LanguageMode language_mode) {
+Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
+ LanguageMode language_mode) {
LookupIterator it(object->GetIsolate(), object, index,
LookupIterator::HIDDEN);
return DeleteProperty(&it, language_mode);
}
-MaybeHandle<Object> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
- Handle<Name> name,
- LanguageMode language_mode) {
+Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
+ Handle<Name> name,
+ LanguageMode language_mode) {
LookupIterator it(object, name, LookupIterator::HIDDEN);
return DeleteProperty(&it, language_mode);
}
-MaybeHandle<Object> JSReceiver::DeletePropertyOrElement(
- Handle<JSReceiver> object, Handle<Name> name, LanguageMode language_mode) {
+Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
+ Handle<Name> name,
+ LanguageMode language_mode) {
LookupIterator it = LookupIterator::PropertyOrElement(
name->GetIsolate(), object, name, LookupIterator::HIDDEN);
return DeleteProperty(&it, language_mode);
@@ -5961,8 +6362,7 @@ Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
Handle<Object> key,
Handle<Object> attributes) {
// 1. If Type(O) is not Object, throw a TypeError exception.
- // TODO(jkummerow): Implement Proxy support, change to "IsSpecObject".
- if (!object->IsJSObject()) {
+ if (!object->IsJSReceiver()) {
Handle<String> fun_name =
isolate->factory()->InternalizeUtf8String("Object.defineProperty");
THROW_NEW_ERROR_RETURN_FAILURE(
@@ -5978,11 +6378,11 @@ Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
return isolate->heap()->exception();
}
// 6. Let success be DefinePropertyOrThrow(O,key, desc).
- bool success = DefineOwnProperty(isolate, Handle<JSObject>::cast(object), key,
- &desc, THROW_ON_ERROR);
+ Maybe<bool> success = DefineOwnProperty(
+ isolate, Handle<JSReceiver>::cast(object), key, &desc, THROW_ON_ERROR);
// 7. ReturnIfAbrupt(success).
- if (isolate->has_pending_exception()) return isolate->heap()->exception();
- CHECK(success == true);
+ MAYBE_RETURN(success, isolate->heap()->exception());
+ CHECK(success.FromJust());
// 8. Return O.
return *object;
}
@@ -5990,32 +6390,35 @@ Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
// ES6 19.1.2.3.1
// static
-Object* JSReceiver::DefineProperties(Isolate* isolate, Handle<Object> object,
- Handle<Object> properties) {
+MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
+ Handle<Object> object,
+ Handle<Object> properties) {
// 1. If Type(O) is not Object, throw a TypeError exception.
- // TODO(jkummerow): Implement Proxy support, change to "IsSpecObject".
- if (!object->IsJSObject()) {
+ if (!object->IsJSReceiver()) {
Handle<String> fun_name =
isolate->factory()->InternalizeUtf8String("Object.defineProperties");
- THROW_NEW_ERROR_RETURN_FAILURE(
- isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
+ Object);
}
// 2. Let props be ToObject(Properties).
// 3. ReturnIfAbrupt(props).
Handle<JSReceiver> props;
if (!Object::ToObject(isolate, properties).ToHandle(&props)) {
- THROW_NEW_ERROR_RETURN_FAILURE(
- isolate, NewTypeError(MessageTemplate::kUndefinedOrNullToObject));
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
+ Object);
}
// 4. Let keys be props.[[OwnPropertyKeys]]().
// 5. ReturnIfAbrupt(keys).
Handle<FixedArray> keys;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ ASSIGN_RETURN_ON_EXCEPTION(
isolate, keys,
- JSReceiver::GetKeys(props, JSReceiver::OWN_ONLY, INCLUDE_SYMBOLS));
+ JSReceiver::GetKeys(props, JSReceiver::OWN_ONLY, ALL_PROPERTIES), Object);
// 6. Let descriptors be an empty List.
int capacity = keys->length();
std::vector<PropertyDescriptor> descriptors(capacity);
+ size_t descriptors_index = 0;
// 7. Repeat for each element nextKey of keys in List order,
for (int i = 0; i < keys->length(); ++i) {
Handle<Object> next_key(keys->get(i), isolate);
@@ -6025,58 +6428,60 @@ Object* JSReceiver::DefineProperties(Isolate* isolate, Handle<Object> object,
LookupIterator it = LookupIterator::PropertyOrElement(
isolate, props, next_key, &success, LookupIterator::HIDDEN);
DCHECK(success);
- // TODO(jkummerow): Support JSProxies. Make sure we call the correct
- // getOwnPropertyDescriptor trap, and convert the result object to a
- // PropertyDescriptor.
- Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(&it);
- if (!maybe.IsJust()) return isolate->heap()->exception();
+ Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
+ if (!maybe.IsJust()) return MaybeHandle<Object>();
PropertyAttributes attrs = maybe.FromJust();
// 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
if (attrs == ABSENT) continue;
- // GetKeys() only returns enumerable keys.
- DCHECK((attrs & DONT_ENUM) == 0);
+ if (attrs & DONT_ENUM) continue;
// 7c i. Let descObj be Get(props, nextKey).
// 7c ii. ReturnIfAbrupt(descObj).
Handle<Object> desc_obj;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, desc_obj,
- JSObject::GetProperty(&it));
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
+ Object);
// 7c iii. Let desc be ToPropertyDescriptor(descObj).
- success = PropertyDescriptor::ToPropertyDescriptor(isolate, desc_obj,
- &descriptors[i]);
+ success = PropertyDescriptor::ToPropertyDescriptor(
+ isolate, desc_obj, &descriptors[descriptors_index]);
// 7c iv. ReturnIfAbrupt(desc).
- if (!success) return isolate->heap()->exception();
+ if (!success) return MaybeHandle<Object>();
// 7c v. Append the pair (a two element List) consisting of nextKey and
// desc to the end of descriptors.
- descriptors[i].set_name(next_key);
+ descriptors[descriptors_index].set_name(next_key);
+ descriptors_index++;
}
// 8. For each pair from descriptors in list order,
- for (size_t i = 0; i < descriptors.size(); ++i) {
+ for (size_t i = 0; i < descriptors_index; ++i) {
PropertyDescriptor* desc = &descriptors[i];
// 8a. Let P be the first element of pair.
// 8b. Let desc be the second element of pair.
// 8c. Let status be DefinePropertyOrThrow(O, P, desc).
- bool status = DefineOwnProperty(isolate, Handle<JSObject>::cast(object),
- desc->name(), desc, THROW_ON_ERROR);
+ Maybe<bool> status =
+ DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
+ desc->name(), desc, THROW_ON_ERROR);
// 8d. ReturnIfAbrupt(status).
- if (isolate->has_pending_exception()) return isolate->heap()->exception();
- CHECK(status == true);
+ if (!status.IsJust()) return MaybeHandle<Object>();
+ CHECK(status.FromJust());
}
// 9. Return o.
- return *object;
+ return object;
}
// static
-bool JSReceiver::DefineOwnProperty(Isolate* isolate, Handle<JSReceiver> object,
- Handle<Object> key, PropertyDescriptor* desc,
- ShouldThrow should_throw) {
+Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
+ Handle<JSReceiver> object,
+ Handle<Object> key,
+ PropertyDescriptor* desc,
+ ShouldThrow should_throw) {
if (object->IsJSArray()) {
return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object),
key, desc, should_throw);
}
+ if (object->IsJSProxy()) {
+ return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object),
+ key, desc, should_throw);
+ }
// TODO(jkummerow): Support Modules (ES6 9.4.6.6)
- // TODO(jkummerow): Support Proxies (ES6 9.5.6)
- if (!object->IsJSObject()) return true;
// OrdinaryDefineOwnProperty, by virtue of calling
// DefineOwnPropertyIgnoreAttributes, can handle arguments (ES6 9.4.4.2)
@@ -6088,11 +6493,11 @@ bool JSReceiver::DefineOwnProperty(Isolate* isolate, Handle<JSReceiver> object,
// static
-bool JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
- Handle<JSObject> object,
- Handle<Object> key,
- PropertyDescriptor* desc,
- ShouldThrow should_throw) {
+Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
+ Handle<JSObject> object,
+ Handle<Object> key,
+ PropertyDescriptor* desc,
+ ShouldThrow should_throw) {
bool success = false;
DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
LookupIterator it = LookupIterator::PropertyOrElement(
@@ -6103,8 +6508,8 @@ bool JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
if (it.state() == LookupIterator::ACCESS_CHECK) {
if (!it.HasAccess()) {
isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
- RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, false);
- return false;
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
+ return Just(true);
}
it.Next();
}
@@ -6115,18 +6520,15 @@ bool JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
// ES6 9.1.6.1
// static
-bool JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
- PropertyDescriptor* desc,
- ShouldThrow should_throw) {
+Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
+ PropertyDescriptor* desc,
+ ShouldThrow should_throw) {
Isolate* isolate = it->isolate();
- // == OrdinaryDefineOwnProperty (O, P, Desc) ==
// 1. Let current be O.[[GetOwnProperty]](P).
// 2. ReturnIfAbrupt(current).
PropertyDescriptor current;
- if (!GetOwnPropertyDescriptor(it, &current) &&
- isolate->has_pending_exception()) {
- return false;
- }
+ MAYBE_RETURN(GetOwnPropertyDescriptor(it, &current), Nothing<bool>());
+
// TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
// the iterator every time. Currently, the reasons why we need it are:
// - handle interceptors correctly
@@ -6136,22 +6538,47 @@ bool JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
bool extensible = JSObject::IsExtensible(object);
+ return ValidateAndApplyPropertyDescriptor(isolate, it, extensible, desc,
+ &current, should_throw);
+}
+
+
+// ES6 9.1.6.2
+// static
+Maybe<bool> JSReceiver::IsCompatiblePropertyDescriptor(
+ Isolate* isolate, bool extensible, PropertyDescriptor* desc,
+ PropertyDescriptor* current, Handle<Name> property_name,
+ ShouldThrow should_throw) {
+ // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined,
+ // Extensible, Desc, Current).
+ return ValidateAndApplyPropertyDescriptor(
+ isolate, NULL, extensible, desc, current, should_throw, property_name);
+}
+
+
+// ES6 9.1.6.3
+// static
+Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
+ Isolate* isolate, LookupIterator* it, bool extensible,
+ PropertyDescriptor* desc, PropertyDescriptor* current,
+ ShouldThrow should_throw, Handle<Name> property_name) {
+ // We either need a LookupIterator, or a property name.
+ DCHECK((it == NULL) != property_name.is_null());
+ Handle<JSObject> object;
+ if (it != NULL) object = Handle<JSObject>::cast(it->GetReceiver());
bool desc_is_data_descriptor = PropertyDescriptor::IsDataDescriptor(desc);
bool desc_is_accessor_descriptor =
PropertyDescriptor::IsAccessorDescriptor(desc);
bool desc_is_generic_descriptor =
PropertyDescriptor::IsGenericDescriptor(desc);
-
- // == ValidateAndApplyPropertyDescriptor (O, P, extensible, Desc, current) ==
+ // 1. (Assert)
// 2. If current is undefined, then
- if (current.is_empty()) {
+ if (current->is_empty()) {
// 2a. If extensible is false, return false.
if (!extensible) {
- if (should_throw == THROW_ON_ERROR) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kDefineDisallowed, it->GetName()));
- }
- return false;
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kDefineDisallowed,
+ it != NULL ? it->GetName() : property_name));
}
// 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
// (This is equivalent to !IsAccessorDescriptor(desc).)
@@ -6163,7 +6590,7 @@ bool JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
// [[Configurable]] attribute values are described by Desc. If the value
// of an attribute field of Desc is absent, the attribute of the newly
// created property is set to its default value.
- if (!object->IsUndefined()) {
+ if (it != NULL) {
if (!desc->has_writable()) desc->set_writable(false);
if (!desc->has_enumerable()) desc->set_enumerable(false);
if (!desc->has_configurable()) desc->set_configurable(false);
@@ -6174,7 +6601,7 @@ bool JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
MaybeHandle<Object> result =
JSObject::DefineOwnPropertyIgnoreAttributes(
it, value, desc->ToAttributes(), JSObject::DONT_FORCE_FIELD);
- if (result.is_null()) return false;
+ if (result.is_null()) return Nothing<bool>();
}
} else {
// 2d. Else Desc must be an accessor Property Descriptor,
@@ -6184,7 +6611,7 @@ bool JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
// [[Configurable]] attribute values are described by Desc. If the value
// of an attribute field of Desc is absent, the attribute of the newly
// created property is set to its default value.
- if (!object->IsUndefined()) {
+ if (it != NULL) {
if (!desc->has_enumerable()) desc->set_enumerable(false);
if (!desc->has_configurable()) desc->set_configurable(false);
Handle<Object> getter(
@@ -6197,53 +6624,50 @@ bool JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
: Handle<Object>::cast(isolate->factory()->null_value()));
MaybeHandle<Object> result =
JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
- if (result.is_null()) return false;
+ if (result.is_null()) return Nothing<bool>();
}
}
// 2e. Return true.
- return true;
+ return Just(true);
}
// 3. Return true, if every field in Desc is absent.
// 4. Return true, if every field in Desc also occurs in current and the
// value of every field in Desc is the same value as the corresponding field
// in current when compared using the SameValue algorithm.
- if ((!desc->has_enumerable() || desc->enumerable() == current.enumerable()) &&
+ if ((!desc->has_enumerable() ||
+ desc->enumerable() == current->enumerable()) &&
(!desc->has_configurable() ||
- desc->configurable() == current.configurable()) &&
+ desc->configurable() == current->configurable()) &&
(!desc->has_value() ||
- (current.has_value() && current.value()->SameValue(*desc->value()))) &&
+ (current->has_value() && current->value()->SameValue(*desc->value()))) &&
(!desc->has_writable() ||
- (current.has_writable() && current.writable() == desc->writable())) &&
+ (current->has_writable() && current->writable() == desc->writable())) &&
(!desc->has_get() ||
- (current.has_get() && current.get()->SameValue(*desc->get()))) &&
+ (current->has_get() && current->get()->SameValue(*desc->get()))) &&
(!desc->has_set() ||
- (current.has_set() && current.set()->SameValue(*desc->set())))) {
- return true;
+ (current->has_set() && current->set()->SameValue(*desc->set())))) {
+ return Just(true);
}
// 5. If the [[Configurable]] field of current is false, then
- if (!current.configurable()) {
+ if (!current->configurable()) {
// 5a. Return false, if the [[Configurable]] field of Desc is true.
if (desc->has_configurable() && desc->configurable()) {
- if (should_throw == THROW_ON_ERROR) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kRedefineDisallowed, it->GetName()));
- }
- return false;
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kRedefineDisallowed,
+ it != NULL ? it->GetName() : property_name));
}
// 5b. Return false, if the [[Enumerable]] field of Desc is present and the
// [[Enumerable]] fields of current and Desc are the Boolean negation of
// each other.
- if (desc->has_enumerable() && desc->enumerable() != current.enumerable()) {
- if (should_throw == THROW_ON_ERROR) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kRedefineDisallowed, it->GetName()));
- }
- return false;
+ if (desc->has_enumerable() && desc->enumerable() != current->enumerable()) {
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kRedefineDisallowed,
+ it != NULL ? it->GetName() : property_name));
}
}
bool current_is_data_descriptor =
- PropertyDescriptor::IsDataDescriptor(&current);
+ PropertyDescriptor::IsDataDescriptor(current);
// 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
if (desc_is_generic_descriptor) {
// Nothing to see here.
@@ -6252,12 +6676,10 @@ bool JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
// different results, then:
} else if (current_is_data_descriptor != desc_is_data_descriptor) {
// 7a. Return false, if the [[Configurable]] field of current is false.
- if (!current.configurable()) {
- if (should_throw == THROW_ON_ERROR) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kRedefineDisallowed, it->GetName()));
- }
- return false;
+ if (!current->configurable()) {
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kRedefineDisallowed,
+ it != NULL ? it->GetName() : property_name));
}
// 7b. If IsDataDescriptor(current) is true, then:
if (current_is_data_descriptor) {
@@ -6280,70 +6702,63 @@ bool JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
// true, then:
} else if (current_is_data_descriptor && desc_is_data_descriptor) {
// 8a. If the [[Configurable]] field of current is false, then:
- if (!current.configurable()) {
+ if (!current->configurable()) {
// [Strong mode] Disallow changing writable -> readonly for
// non-configurable properties.
- if (current.writable() && desc->has_writable() && !desc->writable() &&
- object->map()->is_strong()) {
- if (should_throw == THROW_ON_ERROR) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kStrongRedefineDisallowed, object,
- it->GetName()));
- }
- return false;
+ if (it != NULL && current->writable() && desc->has_writable() &&
+ !desc->writable() && object->map()->is_strong()) {
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kStrongRedefineDisallowed,
+ object, it->GetName()));
}
// 8a i. Return false, if the [[Writable]] field of current is false and
// the [[Writable]] field of Desc is true.
- if (!current.writable() && desc->has_writable() && desc->writable()) {
- if (should_throw == THROW_ON_ERROR) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kRedefineDisallowed, it->GetName()));
- }
- return false;
+ if (!current->writable() && desc->has_writable() && desc->writable()) {
+ RETURN_FAILURE(
+ isolate, should_throw,
+ NewTypeError(MessageTemplate::kRedefineDisallowed,
+ it != NULL ? it->GetName() : property_name));
}
// 8a ii. If the [[Writable]] field of current is false, then:
- if (!current.writable()) {
+ if (!current->writable()) {
// 8a ii 1. Return false, if the [[Value]] field of Desc is present and
// SameValue(Desc.[[Value]], current.[[Value]]) is false.
- if (desc->has_value() && !desc->value()->SameValue(*current.value())) {
- if (should_throw == THROW_ON_ERROR) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kRedefineDisallowed, it->GetName()));
- }
- return false;
+ if (desc->has_value() && !desc->value()->SameValue(*current->value())) {
+ RETURN_FAILURE(
+ isolate, should_throw,
+ NewTypeError(MessageTemplate::kRedefineDisallowed,
+ it != NULL ? it->GetName() : property_name));
}
}
}
} else {
// 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc)
// are both true,
- DCHECK(PropertyDescriptor::IsAccessorDescriptor(&current) &&
+ DCHECK(PropertyDescriptor::IsAccessorDescriptor(current) &&
desc_is_accessor_descriptor);
// 9a. If the [[Configurable]] field of current is false, then:
- if (!current.configurable()) {
+ if (!current->configurable()) {
// 9a i. Return false, if the [[Set]] field of Desc is present and
// SameValue(Desc.[[Set]], current.[[Set]]) is false.
- if (desc->has_set() && !desc->set()->SameValue(*current.set())) {
- if (should_throw == THROW_ON_ERROR) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kRedefineDisallowed, it->GetName()));
- }
- return false;
+ if (desc->has_set() && !desc->set()->SameValue(*current->set())) {
+ RETURN_FAILURE(
+ isolate, should_throw,
+ NewTypeError(MessageTemplate::kRedefineDisallowed,
+ it != NULL ? it->GetName() : property_name));
}
// 9a ii. Return false, if the [[Get]] field of Desc is present and
// SameValue(Desc.[[Get]], current.[[Get]]) is false.
- if (desc->has_get() && !desc->get()->SameValue(*current.get())) {
- if (should_throw == THROW_ON_ERROR) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kRedefineDisallowed, it->GetName()));
- }
- return false;
+ if (desc->has_get() && !desc->get()->SameValue(*current->get())) {
+ RETURN_FAILURE(
+ isolate, should_throw,
+ NewTypeError(MessageTemplate::kRedefineDisallowed,
+ it != NULL ? it->GetName() : property_name));
}
}
}
// 10. If O is not undefined, then:
- if (!object->IsUndefined()) {
+ if (it != NULL) {
// 10a. For each field of Desc that is present, set the corresponding
// attribute of the property named P of object O to the value of the field.
PropertyAttributes attrs = NONE;
@@ -6353,14 +6768,14 @@ bool JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
attrs | (desc->enumerable() ? NONE : DONT_ENUM));
} else {
attrs = static_cast<PropertyAttributes>(
- attrs | (current.enumerable() ? NONE : DONT_ENUM));
+ attrs | (current->enumerable() ? NONE : DONT_ENUM));
}
if (desc->has_configurable()) {
attrs = static_cast<PropertyAttributes>(
attrs | (desc->configurable() ? NONE : DONT_DELETE));
} else {
attrs = static_cast<PropertyAttributes>(
- attrs | (current.configurable() ? NONE : DONT_DELETE));
+ attrs | (current->configurable() ? NONE : DONT_DELETE));
}
if (desc_is_data_descriptor ||
(desc_is_generic_descriptor && current_is_data_descriptor)) {
@@ -6369,41 +6784,85 @@ bool JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
attrs | (desc->writable() ? NONE : READ_ONLY));
} else {
attrs = static_cast<PropertyAttributes>(
- attrs | (current.writable() ? NONE : READ_ONLY));
+ attrs | (current->writable() ? NONE : READ_ONLY));
}
Handle<Object> value(
desc->has_value() ? desc->value()
- : current.has_value()
- ? current.value()
+ : current->has_value()
+ ? current->value()
: Handle<Object>::cast(
isolate->factory()->undefined_value()));
MaybeHandle<Object> result = JSObject::DefineOwnPropertyIgnoreAttributes(
it, value, attrs, JSObject::DONT_FORCE_FIELD);
- if (result.is_null()) return false;
+ if (result.is_null()) return Nothing<bool>();
} else {
DCHECK(desc_is_accessor_descriptor ||
(desc_is_generic_descriptor &&
- PropertyDescriptor::IsAccessorDescriptor(&current)));
+ PropertyDescriptor::IsAccessorDescriptor(current)));
Handle<Object> getter(
desc->has_get()
? desc->get()
- : current.has_get()
- ? current.get()
+ : current->has_get()
+ ? current->get()
: Handle<Object>::cast(isolate->factory()->null_value()));
Handle<Object> setter(
desc->has_set()
? desc->set()
- : current.has_set()
- ? current.set()
+ : current->has_set()
+ ? current->set()
: Handle<Object>::cast(isolate->factory()->null_value()));
MaybeHandle<Object> result =
JSObject::DefineAccessor(it, getter, setter, attrs);
- if (result.is_null()) return false;
+ if (result.is_null()) return Nothing<bool>();
}
}
// 11. Return true.
- return true;
+ return Just(true);
+}
+
+
+// static
+Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it,
+ Handle<Object> value,
+ ShouldThrow should_throw) {
+ DCHECK(!it->check_prototype_chain());
+ Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
+ Isolate* isolate = receiver->GetIsolate();
+
+ if (receiver->IsJSObject()) {
+ return JSObject::CreateDataProperty(it, value); // Shortcut.
+ }
+
+ PropertyDescriptor new_desc;
+ new_desc.set_value(value);
+ new_desc.set_writable(true);
+ new_desc.set_enumerable(true);
+ new_desc.set_configurable(true);
+
+ return JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(),
+ &new_desc, should_throw);
+}
+
+
+Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
+ Handle<Object> value) {
+ DCHECK(it->GetReceiver()->IsJSObject());
+ MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
+
+ if (it->IsFound()) {
+ if (!it->IsConfigurable()) return Just(false);
+ } else {
+ if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver())))
+ return Just(false);
+ }
+
+ RETURN_ON_EXCEPTION_VALUE(
+ it->isolate(),
+ DefineOwnPropertyIgnoreAttributes(it, value, NONE, DONT_FORCE_FIELD),
+ Nothing<bool>());
+
+ return Just(true);
}
@@ -6424,9 +6883,10 @@ bool PropertyKeyToArrayIndex(Handle<Object> index_obj, uint32_t* output) {
// ES6 9.4.2.1
// static
-bool JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
- Handle<Object> name, PropertyDescriptor* desc,
- ShouldThrow should_throw) {
+Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
+ Handle<Object> name,
+ PropertyDescriptor* desc,
+ ShouldThrow should_throw) {
// 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.)
// 2. If P is "length", then:
// TODO(jkummerow): Check if we need slow string comparison.
@@ -6439,10 +6899,10 @@ bool JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
if (PropertyKeyToArrayIndex(name, &index)) {
// 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
PropertyDescriptor old_len_desc;
- bool success = GetOwnPropertyDescriptor(
+ Maybe<bool> success = GetOwnPropertyDescriptor(
isolate, o, isolate->factory()->length_string(), &old_len_desc);
// 3b. (Assert)
- DCHECK(success);
+ DCHECK(success.FromJust());
USE(success);
// 3c. Let oldLen be oldLenDesc.[[Value]].
uint32_t old_len = 0;
@@ -6454,30 +6914,31 @@ bool JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o,
// return false.
if (index >= old_len && old_len_desc.has_writable() &&
!old_len_desc.writable()) {
- if (should_throw == THROW_ON_ERROR) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kDefineDisallowed, name));
- }
- return false;
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kDefineDisallowed, name));
}
// 3g. Let succeeded be OrdinaryDefineOwnProperty(A, P, Desc).
- bool succeeded =
+ Maybe<bool> succeeded =
OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw);
- // 3h. (Assert)
+ // 3h. Assert: succeeded is not an abrupt completion.
+ // In our case, if should_throw == THROW_ON_ERROR, it can be!
// 3i. If succeeded is false, return false.
- if (!succeeded) return false;
+ if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded;
// 3j. If index >= oldLen, then:
if (index >= old_len) {
// 3j i. Set oldLenDesc.[[Value]] to index + 1.
old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1));
// 3j ii. Let succeeded be
// OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
- OrdinaryDefineOwnProperty(isolate, o, isolate->factory()->length_string(),
- &old_len_desc, should_throw);
- // 3j iii. (Assert)
+ succeeded = OrdinaryDefineOwnProperty(isolate, o,
+ isolate->factory()->length_string(),
+ &old_len_desc, should_throw);
+ // 3j iii. Assert: succeeded is true.
+ DCHECK(succeeded.FromJust());
+ USE(succeeded);
}
// 3k. Return true.
- return true;
+ return Just(true);
}
// 4. Return OrdinaryDefineOwnProperty(A, P, Desc).
@@ -6524,9 +6985,9 @@ bool JSArray::AnythingToArrayLength(Isolate* isolate,
// ES6 9.4.2.4
// static
-bool JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
- PropertyDescriptor* desc,
- ShouldThrow should_throw) {
+Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
+ PropertyDescriptor* desc,
+ ShouldThrow should_throw) {
// 1. If the [[Value]] field of Desc is absent, then
if (!desc->has_value()) {
// 1a. Return OrdinaryDefineOwnProperty(A, "length", Desc).
@@ -6539,20 +7000,17 @@ bool JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
// 3. - 7. Convert Desc.[[Value]] to newLen.
uint32_t new_len = 0;
if (!AnythingToArrayLength(isolate, desc->value(), &new_len)) {
- if (should_throw == THROW_ON_ERROR && !isolate->has_pending_exception()) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kCannotConvertToPrimitive));
- }
- return false;
+ DCHECK(isolate->has_pending_exception());
+ return Nothing<bool>();
}
// 8. Set newLenDesc.[[Value]] to newLen.
// (Done below, if needed.)
// 9. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
PropertyDescriptor old_len_desc;
- bool success = GetOwnPropertyDescriptor(
+ Maybe<bool> success = GetOwnPropertyDescriptor(
isolate, a, isolate->factory()->length_string(), &old_len_desc);
// 10. (Assert)
- DCHECK(success);
+ DCHECK(success.FromJust());
USE(success);
// 11. Let oldLen be oldLenDesc.[[Value]].
uint32_t old_len = 0;
@@ -6568,11 +7026,9 @@ bool JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
}
// 13. If oldLenDesc.[[Writable]] is false, return false.
if (!old_len_desc.writable()) {
- if (should_throw == THROW_ON_ERROR)
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kRedefineDisallowed,
- isolate->factory()->length_string()));
- return false;
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kRedefineDisallowed,
+ isolate->factory()->length_string()));
}
// 14. If newLenDesc.[[Writable]] is absent or has the value true,
// let newWritable be true.
@@ -6590,33 +7046,186 @@ bool JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
// Most of steps 16 through 19 is implemented by JSArray::SetLength.
if (JSArray::ObservableSetLength(a, new_len).is_null()) {
DCHECK(isolate->has_pending_exception());
- return false;
+ return Nothing<bool>();
}
// Steps 19d-ii, 20.
if (!new_writable) {
PropertyDescriptor readonly;
readonly.set_writable(false);
- OrdinaryDefineOwnProperty(isolate, a, isolate->factory()->length_string(),
- &readonly, should_throw);
+ Maybe<bool> success = OrdinaryDefineOwnProperty(
+ isolate, a, isolate->factory()->length_string(), &readonly,
+ should_throw);
+ DCHECK(success.FromJust());
+ USE(success);
}
uint32_t actual_new_len = 0;
CHECK(a->length()->ToArrayLength(&actual_new_len));
// Steps 19d-v, 21. Return false if there were non-deletable elements.
- success = actual_new_len == new_len;
- if (!success && should_throw == THROW_ON_ERROR) {
+ bool result = actual_new_len == new_len;
+ if (!result) {
+ RETURN_FAILURE(
+ isolate, should_throw,
+ NewTypeError(MessageTemplate::kStrictDeleteProperty,
+ isolate->factory()->NewNumberFromUint(actual_new_len - 1),
+ a));
+ }
+ return Just(result);
+}
+
+
+// ES6 9.5.6
+// static
+Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
+ Handle<Object> key,
+ PropertyDescriptor* desc,
+ ShouldThrow should_throw) {
+ STACK_CHECK(Nothing<bool>());
+ if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
+ return AddPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc,
+ should_throw);
+ }
+ Handle<String> trap_name = isolate->factory()->defineProperty_string();
+ // 1. Assert: IsPropertyKey(P) is true.
+ DCHECK(key->IsName() || key->IsNumber());
+ // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
+ Handle<Object> handler(proxy->handler(), isolate);
+ // 3. If handler is null, throw a TypeError exception.
+ // 4. Assert: Type(handler) is Object.
+ if (proxy->IsRevoked()) {
isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kStrictDeleteProperty,
- isolate->factory()->NewNumberFromUint(actual_new_len - 1), a));
+ MessageTemplate::kProxyRevoked, trap_name));
+ return Nothing<bool>();
}
- return success;
+ // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
+ Handle<JSReceiver> target(proxy->target(), isolate);
+ // 6. Let trap be ? GetMethod(handler, "defineProperty").
+ Handle<Object> trap;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap,
+ Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
+ Nothing<bool>());
+ // 7. If trap is undefined, then:
+ if (trap->IsUndefined()) {
+ // 7a. Return target.[[DefineOwnProperty]](P, Desc).
+ return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
+ should_throw);
+ }
+ // 8. Let descObj be FromPropertyDescriptor(Desc).
+ Handle<Object> desc_obj = desc->ToObject(isolate);
+ // 9. Let booleanTrapResult be
+ // ToBoolean(? Call(trap, handler, «target, P, descObj»)).
+ Handle<Name> property_name =
+ key->IsName()
+ ? Handle<Name>::cast(key)
+ : Handle<Name>::cast(isolate->factory()->NumberToString(key));
+ // Do not leak private property names.
+ DCHECK(!property_name->IsPrivate());
+ Handle<Object> trap_result_obj;
+ Handle<Object> args[] = {target, property_name, desc_obj};
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap_result_obj,
+ Execution::Call(isolate, trap, handler, arraysize(args), args),
+ Nothing<bool>());
+ // 10. If booleanTrapResult is false, return false.
+ if (!trap_result_obj->BooleanValue()) {
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor,
+ trap_name, property_name));
+ }
+ // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
+ PropertyDescriptor target_desc;
+ Maybe<bool> target_found =
+ JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc);
+ MAYBE_RETURN(target_found, Nothing<bool>());
+ // 12. Let extensibleTarget be ? IsExtensible(target).
+ Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
+ MAYBE_RETURN(maybe_extensible, Nothing<bool>());
+ bool extensible_target = maybe_extensible.FromJust();
+ // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]]
+ // is false, then:
+ // 13a. Let settingConfigFalse be true.
+ // 14. Else let settingConfigFalse be false.
+ bool setting_config_false = desc->has_configurable() && !desc->configurable();
+ // 15. If targetDesc is undefined, then
+ if (!target_found.FromJust()) {
+ // 15a. If extensibleTarget is false, throw a TypeError exception.
+ if (!extensible_target) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyDefinePropertyNonExtensible, property_name));
+ return Nothing<bool>();
+ }
+ // 15b. If settingConfigFalse is true, throw a TypeError exception.
+ if (setting_config_false) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
+ return Nothing<bool>();
+ }
+ } else {
+ // 16. Else targetDesc is not undefined,
+ // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc,
+ // targetDesc) is false, throw a TypeError exception.
+ Maybe<bool> valid =
+ IsCompatiblePropertyDescriptor(isolate, extensible_target, desc,
+ &target_desc, property_name, DONT_THROW);
+ MAYBE_RETURN(valid, Nothing<bool>());
+ if (!valid.FromJust()) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyDefinePropertyIncompatible, property_name));
+ return Nothing<bool>();
+ }
+ // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is
+ // true, throw a TypeError exception.
+ if (setting_config_false && target_desc.configurable()) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name));
+ return Nothing<bool>();
+ }
+ }
+ // 17. Return true.
+ return Just(true);
}
// static
-bool JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
- Handle<JSReceiver> object,
- Handle<Object> key,
- PropertyDescriptor* desc) {
+Maybe<bool> JSProxy::AddPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy,
+ Handle<Symbol> private_name,
+ PropertyDescriptor* desc,
+ ShouldThrow should_throw) {
+ // Despite the generic name, this can only add private data properties.
+ if (!PropertyDescriptor::IsDataDescriptor(desc) ||
+ desc->ToAttributes() != DONT_ENUM) {
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kProxyPrivate));
+ }
+ DCHECK(proxy->map()->is_dictionary_map());
+ Handle<Object> value =
+ desc->has_value()
+ ? desc->value()
+ : Handle<Object>::cast(isolate->factory()->undefined_value());
+
+ LookupIterator it(proxy, private_name);
+
+ if (it.IsFound()) {
+ DCHECK_EQ(LookupIterator::DATA, it.state());
+ DCHECK_EQ(DONT_ENUM, it.property_details().attributes());
+ it.WriteDataValue(value);
+ return Just(true);
+ }
+
+ Handle<NameDictionary> dict(proxy->property_dictionary());
+ PropertyDetails details(DONT_ENUM, DATA, 0, PropertyCellType::kNoCell);
+ Handle<NameDictionary> result =
+ NameDictionary::Add(dict, private_name, value, details);
+ if (!dict.is_identical_to(result)) proxy->set_properties(*result);
+ return Just(true);
+}
+
+
+// static
+Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
+ Handle<JSReceiver> object,
+ Handle<Object> key,
+ PropertyDescriptor* desc) {
bool success = false;
DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
LookupIterator it = LookupIterator::PropertyOrElement(
@@ -6626,25 +7235,25 @@ bool JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
}
-// TODO(jkummerow): Any chance to unify this with
-// "MaybeHandle<Object> GetOwnProperty()" in runtime-object.cc?
-
-// TODO(jkummerow/verwaest): Proxy support: call getOwnPropertyDescriptor trap
-// and convert the result (if it's an object) with ToPropertyDescriptor.
-
// ES6 9.1.5.1
-// Returns true on success; false if there was an exception or no property.
+// Returns true on success, false if the property didn't exist, nothing if
+// an exception was thrown.
// static
-bool JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
- PropertyDescriptor* desc) {
+Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
+ PropertyDescriptor* desc) {
Isolate* isolate = it->isolate();
+ // "Virtual" dispatch.
+ if (it->IsFound() && it->GetHolder<JSReceiver>()->IsJSProxy()) {
+ return JSProxy::GetOwnPropertyDescriptor(isolate, it->GetHolder<JSProxy>(),
+ it->GetName(), desc);
+ }
+
// 1. (Assert)
// 2. If O does not have an own property with key P, return undefined.
Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
-
- if (!maybe.IsJust()) return false;
+ MAYBE_RETURN(maybe, Nothing<bool>());
PropertyAttributes attrs = maybe.FromJust();
- if (attrs == ABSENT) return false;
+ if (attrs == ABSENT) return Just(false);
DCHECK(!isolate->has_pending_exception());
// 3. Let D be a newly created Property Descriptor with no fields.
@@ -6658,7 +7267,7 @@ bool JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
Handle<Object> value;
if (!JSObject::GetProperty(it).ToHandle(&value)) {
DCHECK(isolate->has_pending_exception());
- return false;
+ return Nothing<bool>();
}
desc->set_value(value);
// 5b. Set D.[[Writable]] to the value of X's [[Writable]] attribute
@@ -6680,7 +7289,123 @@ bool JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
// 9. Return D.
DCHECK(PropertyDescriptor::IsAccessorDescriptor(desc) !=
PropertyDescriptor::IsDataDescriptor(desc));
- return true;
+ return Just(true);
+}
+
+
+// ES6 9.5.5
+// static
+Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
+ Handle<JSProxy> proxy,
+ Handle<Name> name,
+ PropertyDescriptor* desc) {
+ DCHECK(!name->IsPrivate());
+ STACK_CHECK(Nothing<bool>());
+
+ Handle<String> trap_name =
+ isolate->factory()->getOwnPropertyDescriptor_string();
+ // 1. (Assert)
+ // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
+ Handle<Object> handler(proxy->handler(), isolate);
+ // 3. If handler is null, throw a TypeError exception.
+ // 4. Assert: Type(handler) is Object.
+ if (proxy->IsRevoked()) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyRevoked, trap_name));
+ return Nothing<bool>();
+ }
+ // 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
+ Handle<JSReceiver> target(proxy->target(), isolate);
+ // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
+ Handle<Object> trap;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap,
+ Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
+ Nothing<bool>());
+ // 7. If trap is undefined, then
+ if (trap->IsUndefined()) {
+ // 7a. Return target.[[GetOwnProperty]](P).
+ return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
+ }
+ // 8. Let trapResultObj be ? Call(trap, handler, «target, P»).
+ Handle<Object> trap_result_obj;
+ Handle<Object> args[] = {target, name};
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap_result_obj,
+ Execution::Call(isolate, trap, handler, arraysize(args), args),
+ Nothing<bool>());
+ // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
+ // TypeError exception.
+ if (!trap_result_obj->IsJSReceiver() && !trap_result_obj->IsUndefined()) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
+ return Nothing<bool>();
+ }
+ // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
+ PropertyDescriptor target_desc;
+ Maybe<bool> found =
+ JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
+ MAYBE_RETURN(found, Nothing<bool>());
+ // 11. If trapResultObj is undefined, then
+ if (trap_result_obj->IsUndefined()) {
+ // 11a. If targetDesc is undefined, return undefined.
+ if (!found.FromJust()) return Just(false);
+ // 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
+ // exception.
+ if (!target_desc.configurable()) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyGetOwnPropertyDescriptorUndefined, name));
+ return Nothing<bool>();
+ }
+ // 11c. Let extensibleTarget be ? IsExtensible(target).
+ Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
+ MAYBE_RETURN(extensible_target, Nothing<bool>());
+ // 11d. (Assert)
+ // 11e. If extensibleTarget is false, throw a TypeError exception.
+ if (!extensible_target.FromJust()) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyGetOwnPropertyDescriptorNonExtensible, name));
+ return Nothing<bool>();
+ }
+ // 11f. Return undefined.
+ return Just(false);
+ }
+ // 12. Let extensibleTarget be ? IsExtensible(target).
+ Maybe<bool> extensible_target = JSReceiver::IsExtensible(target);
+ MAYBE_RETURN(extensible_target, Nothing<bool>());
+ // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
+ if (!PropertyDescriptor::ToPropertyDescriptor(isolate, trap_result_obj,
+ desc)) {
+ DCHECK(isolate->has_pending_exception());
+ return Nothing<bool>();
+ }
+ // 14. Call CompletePropertyDescriptor(resultDesc).
+ PropertyDescriptor::CompletePropertyDescriptor(isolate, desc);
+ // 15. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget,
+ // resultDesc, targetDesc).
+ Maybe<bool> valid =
+ IsCompatiblePropertyDescriptor(isolate, extensible_target.FromJust(),
+ desc, &target_desc, name, DONT_THROW);
+ MAYBE_RETURN(valid, Nothing<bool>());
+ // 16. If valid is false, throw a TypeError exception.
+ if (!valid.FromJust()) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyGetOwnPropertyDescriptorIncompatible, name));
+ return Nothing<bool>();
+ }
+ // 17. If resultDesc.[[Configurable]] is false, then
+ if (!desc->configurable()) {
+ // 17a. If targetDesc is undefined or targetDesc.[[Configurable]] is true:
+ if (target_desc.is_empty() || target_desc.configurable()) {
+ // 17a i. Throw a TypeError exception.
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyGetOwnPropertyDescriptorNonConfigurable,
+ name));
+ return Nothing<bool>();
+ }
+ }
+ // 18. Return resultDesc.
+ return Just(true);
}
@@ -6819,15 +7544,162 @@ bool JSObject::ReferencesObject(Object* obj) {
}
+Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
+ IntegrityLevel level,
+ ShouldThrow should_throw) {
+ DCHECK(level == SEALED || level == FROZEN);
+
+ if (receiver->IsJSObject()) {
+ Handle<JSObject> object = Handle<JSObject>::cast(receiver);
+ if (!object->HasSloppyArgumentsElements() &&
+ !object->map()->is_observed() &&
+ (!object->map()->is_strong() || level == SEALED)) { // Fast path.
+ if (level == SEALED) {
+ return JSObject::PreventExtensionsWithTransition<SEALED>(object,
+ should_throw);
+ } else {
+ return JSObject::PreventExtensionsWithTransition<FROZEN>(object,
+ should_throw);
+ }
+ }
+ }
+
+ Isolate* isolate = receiver->GetIsolate();
+
+ MAYBE_RETURN(JSReceiver::PreventExtensions(receiver, should_throw),
+ Nothing<bool>());
+
+ Handle<FixedArray> keys;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, keys, JSReceiver::OwnPropertyKeys(receiver), Nothing<bool>());
+
+ PropertyDescriptor no_conf;
+ no_conf.set_configurable(false);
+
+ PropertyDescriptor no_conf_no_write;
+ no_conf_no_write.set_configurable(false);
+ no_conf_no_write.set_writable(false);
+
+ if (level == SEALED) {
+ for (int i = 0; i < keys->length(); ++i) {
+ Handle<Object> key(keys->get(i), isolate);
+ MAYBE_RETURN(
+ DefineOwnProperty(isolate, receiver, key, &no_conf, THROW_ON_ERROR),
+ Nothing<bool>());
+ }
+ return Just(true);
+ }
+
+ for (int i = 0; i < keys->length(); ++i) {
+ Handle<Object> key(keys->get(i), isolate);
+ PropertyDescriptor current_desc;
+ Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
+ isolate, receiver, key, &current_desc);
+ MAYBE_RETURN(owned, Nothing<bool>());
+ if (owned.FromJust()) {
+ PropertyDescriptor desc =
+ PropertyDescriptor::IsAccessorDescriptor(&current_desc)
+ ? no_conf
+ : no_conf_no_write;
+ MAYBE_RETURN(
+ DefineOwnProperty(isolate, receiver, key, &desc, THROW_ON_ERROR),
+ Nothing<bool>());
+ }
+ }
+ return Just(true);
+}
+
+
+Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> object,
+ IntegrityLevel level) {
+ DCHECK(level == SEALED || level == FROZEN);
+ Isolate* isolate = object->GetIsolate();
+
+ Maybe<bool> extensible = JSReceiver::IsExtensible(object);
+ MAYBE_RETURN(extensible, Nothing<bool>());
+ if (extensible.FromJust()) return Just(false);
+
+ Handle<FixedArray> keys;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, keys, JSReceiver::OwnPropertyKeys(object), Nothing<bool>());
+
+ for (int i = 0; i < keys->length(); ++i) {
+ Handle<Object> key(keys->get(i), isolate);
+ PropertyDescriptor current_desc;
+ Maybe<bool> owned = JSReceiver::GetOwnPropertyDescriptor(
+ isolate, object, key, &current_desc);
+ MAYBE_RETURN(owned, Nothing<bool>());
+ if (owned.FromJust()) {
+ if (current_desc.configurable()) return Just(false);
+ if (level == FROZEN &&
+ PropertyDescriptor::IsDataDescriptor(&current_desc) &&
+ current_desc.writable()) {
+ return Just(false);
+ }
+ }
+ }
+ return Just(true);
+}
+
+
Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
ShouldThrow should_throw) {
- if (!object->IsJSObject()) return Just(false);
- // TODO(neis): Deal with proxies.
+ if (object->IsJSProxy()) {
+ return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
+ should_throw);
+ }
+ DCHECK(object->IsJSObject());
return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
should_throw);
}
+Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
+ ShouldThrow should_throw) {
+ Isolate* isolate = proxy->GetIsolate();
+ STACK_CHECK(Nothing<bool>());
+ Factory* factory = isolate->factory();
+ Handle<String> trap_name = factory->preventExtensions_string();
+
+ if (proxy->IsRevoked()) {
+ isolate->Throw(
+ *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
+ return Nothing<bool>();
+ }
+ Handle<JSReceiver> target(proxy->target(), isolate);
+ Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
+
+ Handle<Object> trap;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
+ if (trap->IsUndefined()) {
+ return JSReceiver::PreventExtensions(target, should_throw);
+ }
+
+ Handle<Object> trap_result;
+ Handle<Object> args[] = {target};
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap_result,
+ Execution::Call(isolate, trap, handler, arraysize(args), args),
+ Nothing<bool>());
+ if (!trap_result->BooleanValue()) {
+ RETURN_FAILURE(
+ isolate, should_throw,
+ NewTypeError(MessageTemplate::kProxyTrapReturnedFalsish, trap_name));
+ }
+
+ // Enforce the invariant.
+ Maybe<bool> target_result = JSReceiver::IsExtensible(target);
+ MAYBE_RETURN(target_result, Nothing<bool>());
+ if (target_result.FromJust()) {
+ isolate->Throw(*factory->NewTypeError(
+ MessageTemplate::kProxyPreventExtensionsExtensible));
+ return Nothing<bool>();
+ }
+ return Just(true);
+}
+
+
Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
ShouldThrow should_throw) {
Isolate* isolate = object->GetIsolate();
@@ -6840,7 +7712,6 @@ Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
!isolate->MayAccess(handle(isolate->context()), object)) {
isolate->ReportFailedAccessCheck(object);
RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
- UNREACHABLE();
RETURN_FAILURE(isolate, should_throw,
NewTypeError(MessageTemplate::kNoAccess));
}
@@ -6885,6 +7756,55 @@ Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
}
+Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
+ if (object->IsJSProxy()) {
+ return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
+ }
+ return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
+}
+
+
+Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
+ Isolate* isolate = proxy->GetIsolate();
+ STACK_CHECK(Nothing<bool>());
+ Factory* factory = isolate->factory();
+ Handle<String> trap_name = factory->isExtensible_string();
+
+ if (proxy->IsRevoked()) {
+ isolate->Throw(
+ *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
+ return Nothing<bool>();
+ }
+ Handle<JSReceiver> target(proxy->target(), isolate);
+ Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
+
+ Handle<Object> trap;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
+ if (trap->IsUndefined()) {
+ return JSReceiver::IsExtensible(target);
+ }
+
+ Handle<Object> trap_result;
+ Handle<Object> args[] = {target};
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap_result,
+ Execution::Call(isolate, trap, handler, arraysize(args), args),
+ Nothing<bool>());
+
+ // Enforce the invariant.
+ Maybe<bool> target_result = JSReceiver::IsExtensible(target);
+ MAYBE_RETURN(target_result, Nothing<bool>());
+ if (target_result.FromJust() != trap_result->BooleanValue()) {
+ isolate->Throw(
+ *factory->NewTypeError(MessageTemplate::kProxyIsExtensibleInconsistent,
+ factory->ToBoolean(target_result.FromJust())));
+ return Nothing<bool>();
+ }
+ return target_result;
+}
+
+
bool JSObject::IsExtensible(Handle<JSObject> object) {
Isolate* isolate = object->GetIsolate();
if (object->IsAccessCheckNeeded() &&
@@ -6939,7 +7859,6 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
!isolate->MayAccess(handle(isolate->context()), object)) {
isolate->ReportFailedAccessCheck(object);
RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
- UNREACHABLE();
RETURN_FAILURE(isolate, should_throw,
NewTypeError(MessageTemplate::kNoAccess));
}
@@ -7046,20 +7965,6 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
}
-MaybeHandle<Object> JSObject::Freeze(Handle<JSObject> object) {
- MAYBE_RETURN_NULL(
- PreventExtensionsWithTransition<FROZEN>(object, THROW_ON_ERROR));
- return object;
-}
-
-
-MaybeHandle<Object> JSObject::Seal(Handle<JSObject> object) {
- MAYBE_RETURN_NULL(
- PreventExtensionsWithTransition<SEALED>(object, THROW_ON_ERROR));
- return object;
-}
-
-
void JSObject::SetObserved(Handle<JSObject> object) {
DCHECK(!object->IsJSGlobalProxy());
DCHECK(!object->IsJSGlobalObject());
@@ -7205,22 +8110,20 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
}
}
} else {
- Handle<FixedArray> names =
- isolate->factory()->NewFixedArray(copy->NumberOfOwnProperties());
- copy->GetOwnPropertyNames(*names, 0);
+ // Only deep copy fields from the object literal expression.
+ // In particular, don't try to copy the length attribute of
+ // an array.
+ PropertyFilter filter = static_cast<PropertyFilter>(
+ ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE);
+ KeyAccumulator accumulator(isolate, filter);
+ accumulator.NextPrototype();
+ copy->CollectOwnPropertyNames(&accumulator, filter);
+ Handle<FixedArray> names = accumulator.GetKeys();
for (int i = 0; i < names->length(); i++) {
- DCHECK(names->get(i)->IsString());
- Handle<String> key_string(String::cast(names->get(i)));
- Maybe<PropertyAttributes> maybe =
- JSReceiver::GetOwnPropertyAttributes(copy, key_string);
- DCHECK(maybe.IsJust());
- PropertyAttributes attributes = maybe.FromJust();
- // Only deep copy fields from the object literal expression.
- // In particular, don't try to copy the length attribute of
- // an array.
- if (attributes != NONE) continue;
+ DCHECK(names->get(i)->IsName());
+ Handle<Name> name(Name::cast(names->get(i)));
Handle<Object> value =
- Object::GetProperty(copy, key_string).ToHandleChecked();
+ Object::GetProperty(copy, name).ToHandleChecked();
if (value->IsJSObject()) {
Handle<JSObject> result;
ASSIGN_RETURN_ON_EXCEPTION(
@@ -7229,7 +8132,7 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
JSObject);
if (copying) {
// Creating object copy for literals. No strict mode needed.
- JSObject::SetProperty(copy, key_string, result, SLOPPY).Assert();
+ JSObject::SetProperty(copy, name, result, SLOPPY).Assert();
}
}
}
@@ -7409,6 +8312,71 @@ MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
}
+// 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:
+ case FAST_DOUBLE_ELEMENTS: {
+ int length = object->IsJSArray()
+ ? Smi::cast(JSArray::cast(object)->length())->value()
+ : object->elements()->length();
+ return length > 0;
+ }
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_HOLEY_ELEMENTS: {
+ FixedArray* elements = FixedArray::cast(object->elements());
+ int length = object->IsJSArray()
+ ? Smi::cast(JSArray::cast(object)->length())->value()
+ : elements->length();
+ for (int i = 0; i < length; i++) {
+ if (!elements->is_the_hole(i)) return true;
+ }
+ return false;
+ }
+ case FAST_HOLEY_DOUBLE_ELEMENTS: {
+ int length = object->IsJSArray()
+ ? Smi::cast(JSArray::cast(object)->length())->value()
+ : object->elements()->length();
+ // Zero-length arrays would use the empty FixedArray...
+ if (length == 0) return false;
+ // ...so only cast to FixedDoubleArray otherwise.
+ FixedDoubleArray* elements = FixedDoubleArray::cast(object->elements());
+ for (int i = 0; i < length; i++) {
+ if (!elements->is_the_hole(i)) return true;
+ }
+ return false;
+ }
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case TYPE##_ELEMENTS:
+
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+ {
+ int length = object->elements()->length();
+ return length > 0;
+ }
+ case DICTIONARY_ELEMENTS: {
+ SeededNumberDictionary* elements =
+ SeededNumberDictionary::cast(object->elements());
+ return elements->NumberOfElementsFilterAttributes(ONLY_ENUMERABLE) > 0;
+ }
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
+ // We're approximating non-empty arguments objects here.
+ return true;
+ }
+ UNREACHABLE();
+ return true;
+}
+
+
// Tests for the fast common case for property enumeration:
// - This object and all prototypes has an enum cache (which means that
// it is no proxy, has no interceptors and needs no access checks).
@@ -7425,7 +8393,7 @@ bool JSReceiver::IsSimpleEnum() {
if (current->IsAccessCheckNeeded()) return false;
DCHECK(!current->HasNamedInterceptor());
DCHECK(!current->HasIndexedInterceptor());
- if (current->NumberOfEnumElements() > 0) return false;
+ if (HasEnumerableElements(current)) return false;
if (current != this && enum_length != 0) return false;
}
return true;
@@ -7433,7 +8401,7 @@ bool JSReceiver::IsSimpleEnum() {
int Map::NumberOfDescribedProperties(DescriptorFlag which,
- PropertyAttributes filter) {
+ PropertyFilter filter) {
int result = 0;
DescriptorArray* descs = instance_descriptors();
int limit = which == ALL_DESCRIPTORS
@@ -7498,14 +8466,14 @@ Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
// If the enum length of the given map is set to kInvalidEnumCache, this
// means that the map itself has never used the present enum cache. The
// first step to using the cache is to set the enum length of the map by
- // counting the number of own descriptors that are not DONT_ENUM or
- // SYMBOLIC.
+ // counting the number of own descriptors that are ENUMERABLE_STRINGS.
if (own_property_count == kInvalidEnumCacheSentinel) {
own_property_count =
- map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_SHOW);
+ map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS);
} else {
- DCHECK(own_property_count ==
- map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_SHOW));
+ DCHECK(
+ own_property_count ==
+ map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS));
}
if (descs->HasEnumCache()) {
@@ -7592,103 +8560,368 @@ Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object,
}
-MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
- KeyCollectionType type,
- KeyFilter filter,
- GetKeysConversion getConversion) {
- USE(ContainsOnlyValidKeys);
- Isolate* isolate = object->GetIsolate();
- KeyAccumulator accumulator(isolate, filter);
- Handle<JSFunction> arguments_function(
- JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor()));
- PrototypeIterator::WhereToEnd end = type == OWN_ONLY
+enum IndexedOrNamed { kIndexed, kNamed };
+
+
+// Returns |true| on success, |nothing| on exception.
+template <class Callback, IndexedOrNamed type>
+static Maybe<bool> GetKeysFromInterceptor(Isolate* isolate,
+ Handle<JSReceiver> receiver,
+ Handle<JSObject> object,
+ PropertyFilter filter,
+ KeyAccumulator* accumulator) {
+ if (type == kIndexed) {
+ if (!object->HasIndexedInterceptor()) return Just(true);
+ } else {
+ if (!object->HasNamedInterceptor()) return Just(true);
+ }
+ Handle<InterceptorInfo> interceptor(type == kIndexed
+ ? object->GetIndexedInterceptor()
+ : object->GetNamedInterceptor(),
+ isolate);
+ if ((filter & ONLY_ALL_CAN_READ) && !interceptor->all_can_read()) {
+ return Just(true);
+ }
+ PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
+ *object);
+ v8::Local<v8::Object> result;
+ if (!interceptor->enumerator()->IsUndefined()) {
+ Callback enum_fun = v8::ToCData<Callback>(interceptor->enumerator());
+ const char* log_tag = type == kIndexed ? "interceptor-indexed-enum"
+ : "interceptor-named-enum";
+ LOG(isolate, ApiObjectAccess(log_tag, *object));
+ result = args.Call(enum_fun);
+ }
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
+ if (result.IsEmpty()) return Just(true);
+ DCHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
+ (v8::Utils::OpenHandle(*result)->IsJSObject() &&
+ Handle<JSObject>::cast(v8::Utils::OpenHandle(*result))
+ ->HasSloppyArgumentsElements()));
+ // The accumulator takes care of string/symbol filtering.
+ if (type == kIndexed) {
+ accumulator->AddElementKeysFromInterceptor(
+ Handle<JSObject>::cast(v8::Utils::OpenHandle(*result)));
+ } else {
+ accumulator->AddKeys(
+ Handle<JSObject>::cast(v8::Utils::OpenHandle(*result)));
+ }
+ return Just(true);
+}
+
+
+// Returns |true| on success, |false| if prototype walking should be stopped,
+// |nothing| if an exception was thrown.
+static Maybe<bool> GetKeysFromJSObject(Isolate* isolate,
+ Handle<JSReceiver> receiver,
+ Handle<JSObject> object,
+ PropertyFilter* filter,
+ JSReceiver::KeyCollectionType type,
+ KeyAccumulator* accumulator) {
+ accumulator->NextPrototype();
+ // Check access rights if required.
+ if (object->IsAccessCheckNeeded() &&
+ !isolate->MayAccess(handle(isolate->context()), object)) {
+ // The cross-origin spec says that [[Enumerate]] shall return an empty
+ // iterator when it doesn't have access...
+ if (type == JSReceiver::INCLUDE_PROTOS) {
+ return Just(false);
+ }
+ // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties.
+ DCHECK(type == JSReceiver::OWN_ONLY);
+ *filter = static_cast<PropertyFilter>(*filter | ONLY_ALL_CAN_READ);
+ }
+
+ JSObject::CollectOwnElementKeys(object, accumulator, *filter);
+
+ // Add the element keys from the interceptor.
+ Maybe<bool> success =
+ GetKeysFromInterceptor<v8::IndexedPropertyEnumeratorCallback, kIndexed>(
+ isolate, receiver, object, *filter, accumulator);
+ MAYBE_RETURN(success, Nothing<bool>());
+
+ if (*filter == ENUMERABLE_STRINGS) {
+ // 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 cache_enum_length =
+ ((object->map()->GetConstructor() != *arguments_function) &&
+ !object->IsJSValue() && !object->IsAccessCheckNeeded() &&
+ !object->HasNamedInterceptor() && !object->HasIndexedInterceptor());
+ // Compute the property keys and cache them if possible.
+ Handle<FixedArray> enum_keys =
+ JSObject::GetEnumPropertyKeys(object, cache_enum_length);
+ accumulator->AddKeys(enum_keys);
+ } else {
+ object->CollectOwnPropertyNames(accumulator, *filter);
+ }
+
+ // Add the property keys from the interceptor.
+ success = GetKeysFromInterceptor<v8::GenericNamedPropertyEnumeratorCallback,
+ kNamed>(isolate, receiver, object, *filter,
+ accumulator);
+ MAYBE_RETURN(success, Nothing<bool>());
+ return Just(true);
+}
+
+
+// Helper function for JSReceiver::GetKeys() below. Can be called recursively.
+// Returns |true| or |nothing|.
+static Maybe<bool> GetKeys_Internal(Isolate* isolate,
+ Handle<JSReceiver> receiver,
+ Handle<JSReceiver> object,
+ JSReceiver::KeyCollectionType type,
+ PropertyFilter filter,
+ KeyAccumulator* accumulator) {
+ PrototypeIterator::WhereToEnd end = type == JSReceiver::OWN_ONLY
? PrototypeIterator::END_AT_NON_HIDDEN
: PrototypeIterator::END_AT_NULL;
- // Only collect keys if access is permitted.
for (PrototypeIterator iter(isolate, object,
PrototypeIterator::START_AT_RECEIVER);
!iter.IsAtEnd(end); iter.Advance()) {
- accumulator.NextPrototype();
- if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
- Handle<JSProxy> proxy = PrototypeIterator::GetCurrent<JSProxy>(iter);
- Handle<Object> args[] = { proxy };
- Handle<Object> names;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, names,
- Execution::Call(isolate,
- isolate->proxy_enumerate(),
- object,
- arraysize(args),
- args),
- FixedArray);
- accumulator.AddKeysFromProxy(Handle<JSObject>::cast(names));
- break;
- }
-
- Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
-
- // Check access rights if required.
- if (current->IsAccessCheckNeeded() &&
- !isolate->MayAccess(handle(isolate->context()), current)) {
- if (iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
- isolate->ReportFailedAccessCheck(current);
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray);
+ 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);
}
- break;
+ } else {
+ DCHECK(current->IsJSObject());
+ result = GetKeysFromJSObject(isolate, receiver,
+ Handle<JSObject>::cast(current), &filter,
+ type, accumulator);
}
+ MAYBE_RETURN(result, Nothing<bool>());
+ if (!result.FromJust()) break; // |false| means "stop iterating".
+ }
+ return Just(true);
+}
- JSObject::CollectOwnElementKeys(current, &accumulator,
- static_cast<PropertyAttributes>(DONT_ENUM));
- // Add the element keys from the interceptor.
- if (current->HasIndexedInterceptor()) {
- Handle<JSObject> result;
- if (JSObject::GetKeysForIndexedInterceptor(current, object)
- .ToHandle(&result)) {
- accumulator.AddElementKeysFromInterceptor(result);
- }
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray);
- }
+// 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);
+}
- if (filter == SKIP_SYMBOLS) {
- // 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.
- bool cache_enum_length =
- ((current->map()->GetConstructor() != *arguments_function) &&
- !current->IsJSValue() && !current->IsAccessCheckNeeded() &&
- !current->HasNamedInterceptor() &&
- !current->HasIndexedInterceptor());
- // Compute the property keys and cache them if possible.
- Handle<FixedArray> enum_keys =
- JSObject::GetEnumPropertyKeys(current, cache_enum_length);
- accumulator.AddKeys(enum_keys);
+
+// ES6 9.5.12
+// Returns |true| on success, |nothing| in case of exception.
+// static
+Maybe<bool> JSProxy::OwnPropertyKeys(Isolate* isolate,
+ Handle<JSReceiver> receiver,
+ Handle<JSProxy> proxy,
+ PropertyFilter filter,
+ KeyAccumulator* accumulator) {
+ STACK_CHECK(Nothing<bool>());
+ // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
+ Handle<Object> handler(proxy->handler(), isolate);
+ // 2. If handler is null, throw a TypeError exception.
+ // 3. Assert: Type(handler) is Object.
+ if (proxy->IsRevoked()) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyRevoked, isolate->factory()->ownKeys_string()));
+ return Nothing<bool>();
+ }
+ // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
+ Handle<JSReceiver> target(proxy->target(), isolate);
+ // 5. Let trap be ? GetMethod(handler, "ownKeys").
+ Handle<Object> trap;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
+ isolate->factory()->ownKeys_string()),
+ Nothing<bool>());
+ // 6. If trap is undefined, then
+ if (trap->IsUndefined()) {
+ // 6a. Return target.[[OwnPropertyKeys]]().
+ return GetKeys_Internal(isolate, receiver, target, OWN_ONLY, filter,
+ accumulator);
+ }
+ // 7. Let trapResultArray be Call(trap, handler, «target»).
+ Handle<Object> trap_result_array;
+ Handle<Object> args[] = {target};
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap_result_array,
+ Execution::Call(isolate, trap, handler, arraysize(args), args),
+ Nothing<bool>());
+ // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray,
+ // «String, Symbol»).
+ Handle<FixedArray> trap_result;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap_result,
+ Object::CreateListFromArrayLike(isolate, trap_result_array,
+ ElementTypes::kStringAndSymbol),
+ Nothing<bool>());
+ // 9. Let extensibleTarget be ? IsExtensible(target).
+ Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
+ MAYBE_RETURN(maybe_extensible, Nothing<bool>());
+ bool extensible_target = maybe_extensible.FromJust();
+ // 10. Let targetKeys be ? target.[[OwnPropertyKeys]]().
+ Handle<FixedArray> target_keys;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_keys,
+ JSReceiver::OwnPropertyKeys(target),
+ Nothing<bool>());
+ // 11. (Assert)
+ // 12. Let targetConfigurableKeys be an empty List.
+ // To save memory, we're re-using target_keys and will modify it in-place.
+ Handle<FixedArray> target_configurable_keys = target_keys;
+ // 13. Let targetNonconfigurableKeys be an empty List.
+ Handle<FixedArray> target_nonconfigurable_keys =
+ isolate->factory()->NewFixedArray(target_keys->length());
+ int nonconfigurable_keys_length = 0;
+ // 14. Repeat, for each element key of targetKeys:
+ for (int i = 0; i < target_keys->length(); ++i) {
+ // 14a. Let desc be ? target.[[GetOwnProperty]](key).
+ PropertyDescriptor desc;
+ Maybe<bool> found = JSReceiver::GetOwnPropertyDescriptor(
+ isolate, target, handle(target_keys->get(i), isolate), &desc);
+ MAYBE_RETURN(found, Nothing<bool>());
+ // 14b. If desc is not undefined and desc.[[Configurable]] is false, then
+ if (found.FromJust() && !desc.configurable()) {
+ // 14b i. Append key as an element of targetNonconfigurableKeys.
+ target_nonconfigurable_keys->set(nonconfigurable_keys_length,
+ target_keys->get(i));
+ nonconfigurable_keys_length++;
+ // The key was moved, null it out in the original list.
+ target_keys->set(i, Smi::FromInt(0));
} else {
- DCHECK(filter == INCLUDE_SYMBOLS);
- PropertyAttributes attr_filter =
- static_cast<PropertyAttributes>(DONT_ENUM | PRIVATE_SYMBOL);
- current->CollectOwnPropertyNames(&accumulator, attr_filter);
- }
-
- // Add the property keys from the interceptor.
- if (current->HasNamedInterceptor()) {
- Handle<JSObject> result;
- if (JSObject::GetKeysForNamedInterceptor(current, object)
- .ToHandle(&result)) {
- accumulator.AddKeys(result);
- }
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray);
+ // 14c. Else,
+ // 14c i. Append key as an element of targetConfigurableKeys.
+ // (No-op, just keep it in |target_keys|.)
+ }
+ }
+ accumulator->NextPrototype(); // Prepare for accumulating keys.
+ // 15. If extensibleTarget is true and targetNonconfigurableKeys is empty,
+ // then:
+ if (extensible_target && nonconfigurable_keys_length == 0) {
+ // 15a. Return trapResult.
+ return accumulator->AddKeysFromProxy(proxy, trap_result);
+ }
+ // 16. Let uncheckedResultKeys be a new List which is a copy of trapResult.
+ Zone set_zone;
+ 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();
+ for (int i = 0; i < trap_result->length(); ++i) {
+ DCHECK(trap_result->get(i)->IsUniqueName());
+ unchecked_result_keys.Set(trap_result->get(i), kPresent);
+ }
+ // 17. Repeat, for each key that is an element of targetNonconfigurableKeys:
+ for (int i = 0; i < nonconfigurable_keys_length; ++i) {
+ Object* key = target_nonconfigurable_keys->get(i);
+ // 17a. If key is not an element of uncheckedResultKeys, throw a
+ // TypeError exception.
+ int* found = unchecked_result_keys.Find(key);
+ if (found == nullptr || *found == kGone) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate)));
+ return Nothing<bool>();
+ }
+ // 17b. Remove key from uncheckedResultKeys.
+ *found = kGone;
+ unchecked_result_keys_size--;
+ }
+ // 18. If extensibleTarget is true, return trapResult.
+ if (extensible_target) {
+ return accumulator->AddKeysFromProxy(proxy, trap_result);
+ }
+ // 19. Repeat, for each key that is an element of targetConfigurableKeys:
+ for (int i = 0; i < target_configurable_keys->length(); ++i) {
+ Object* key = target_configurable_keys->get(i);
+ if (key->IsSmi()) continue; // Zapped entry, was nonconfigurable.
+ // 19a. If key is not an element of uncheckedResultKeys, throw a
+ // TypeError exception.
+ int* found = unchecked_result_keys.Find(key);
+ if (found == nullptr || *found == kGone) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate)));
+ return Nothing<bool>();
}
+ // 19b. Remove key from uncheckedResultKeys.
+ *found = kGone;
+ unchecked_result_keys_size--;
}
+ // 20. If uncheckedResultKeys is not empty, throw a TypeError exception.
+ if (unchecked_result_keys_size != 0) {
+ DCHECK_GT(unchecked_result_keys_size, 0);
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyOwnKeysNonExtensible));
+ return Nothing<bool>();
+ }
+ // 21. Return trapResult.
+ return accumulator->AddKeysFromProxy(proxy, trap_result);
+}
+
- Handle<FixedArray> keys = accumulator.GetKeys(getConversion);
+MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
+ KeyCollectionType type,
+ PropertyFilter filter,
+ GetKeysConversion keys_conversion) {
+ USE(ContainsOnlyValidKeys);
+ Isolate* isolate = object->GetIsolate();
+ KeyAccumulator accumulator(isolate, filter);
+ MAYBE_RETURN(
+ GetKeys_Internal(isolate, object, object, type, filter, &accumulator),
+ MaybeHandle<FixedArray>());
+ Handle<FixedArray> keys = accumulator.GetKeys(keys_conversion);
DCHECK(ContainsOnlyValidKeys(keys));
return keys;
}
@@ -7942,7 +9175,8 @@ Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) {
if (!map->is_dictionary_map()) {
new_bit_field3 = IsUnstable::update(new_bit_field3, false);
}
- new_bit_field3 = Counter::update(new_bit_field3, kRetainingCounterStart);
+ new_bit_field3 =
+ ConstructionCounter::update(new_bit_field3, kNoSlackTracking);
result->set_bit_field3(new_bit_field3);
return result;
}
@@ -8042,9 +9276,17 @@ Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size,
int in_object_properties,
int unused_property_fields) {
#ifdef DEBUG
+ Isolate* isolate = map->GetIsolate();
+ // Strict and strong function maps have Function as a constructor but the
+ // Function's initial map is a sloppy function map. Same holds for
+ // GeneratorFunction and its initial map.
Object* constructor = map->GetConstructor();
DCHECK(constructor->IsJSFunction());
- DCHECK_EQ(*map, JSFunction::cast(constructor)->initial_map());
+ DCHECK(*map == JSFunction::cast(constructor)->initial_map() ||
+ *map == *isolate->strict_function_map() ||
+ *map == *isolate->strong_function_map() ||
+ *map == *isolate->strict_generator_function_map() ||
+ *map == *isolate->strong_generator_function_map());
#endif
// Initial maps must always own their descriptors and it's descriptor array
// does not contain descriptors that do not belong to the map.
@@ -8077,9 +9319,10 @@ Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
Handle<Map> result = RawCopy(map, map->instance_size());
// Please note instance_type and instance_size are set when allocated.
- result->SetInObjectProperties(map->GetInObjectProperties());
- result->set_unused_property_fields(map->unused_property_fields());
-
+ if (map->IsJSObjectMap()) {
+ result->SetInObjectProperties(map->GetInObjectProperties());
+ result->set_unused_property_fields(map->unused_property_fields());
+ }
result->ClearCodeCache(map->GetHeap());
map->NotifyLeafMapLayoutChange();
return result;
@@ -8228,48 +9471,85 @@ Handle<Map> Map::CopyReplaceDescriptors(
}
-// Since this method is used to rewrite an existing transition tree, it can
-// always insert transitions without checking.
-Handle<Map> Map::CopyInstallDescriptors(
- Handle<Map> map, int new_descriptor, Handle<DescriptorArray> descriptors,
+// Creates transition tree starting from |split_map| and adding all descriptors
+// starting from descriptor with index |split_map|.NumberOfOwnDescriptors().
+// The way how it is done is tricky because of GC and special descriptors
+// marking logic.
+Handle<Map> Map::AddMissingTransitions(
+ Handle<Map> split_map, Handle<DescriptorArray> descriptors,
Handle<LayoutDescriptor> full_layout_descriptor) {
DCHECK(descriptors->IsSortedNoDuplicates());
+ int split_nof = split_map->NumberOfOwnDescriptors();
+ int nof_descriptors = descriptors->number_of_descriptors();
+ DCHECK_LT(split_nof, nof_descriptors);
+
+ // Start with creating last map which will own full descriptors array.
+ // This is necessary to guarantee that GC will mark the whole descriptor
+ // array if any of the allocations happening below fail.
+ // Number of unused properties is temporarily incorrect and the layout
+ // descriptor could unnecessarily be in slow mode but we will fix after
+ // all the other intermediate maps are created.
+ Handle<Map> last_map = CopyDropDescriptors(split_map);
+ last_map->InitializeDescriptors(*descriptors, *full_layout_descriptor);
+ last_map->set_unused_property_fields(0);
+
+ // During creation of intermediate maps we violate descriptors sharing
+ // invariant since the last map is not yet connected to the transition tree
+ // we create here. But it is safe because GC never trims map's descriptors
+ // if there are no dead transitions from that map and this is exactly the
+ // case for all the intermediate maps we create here.
+ Handle<Map> map = split_map;
+ for (int i = split_nof; i < nof_descriptors - 1; ++i) {
+ Handle<Map> new_map = CopyDropDescriptors(map);
+ InstallDescriptors(map, new_map, i, descriptors, full_layout_descriptor);
+ map = new_map;
+ }
+ map->NotifyLeafMapLayoutChange();
+ InstallDescriptors(map, last_map, nof_descriptors - 1, descriptors,
+ full_layout_descriptor);
+ return last_map;
+}
- Handle<Map> result = CopyDropDescriptors(map);
- result->set_instance_descriptors(*descriptors);
- result->SetNumberOfOwnDescriptors(new_descriptor + 1);
+// Since this method is used to rewrite an existing transition tree, it can
+// always insert transitions without checking.
+void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child,
+ int new_descriptor,
+ Handle<DescriptorArray> descriptors,
+ Handle<LayoutDescriptor> full_layout_descriptor) {
+ DCHECK(descriptors->IsSortedNoDuplicates());
- int unused_property_fields = map->unused_property_fields();
+ child->set_instance_descriptors(*descriptors);
+ child->SetNumberOfOwnDescriptors(new_descriptor + 1);
+
+ int unused_property_fields = parent->unused_property_fields();
PropertyDetails details = descriptors->GetDetails(new_descriptor);
if (details.location() == kField) {
- unused_property_fields = map->unused_property_fields() - 1;
+ unused_property_fields = parent->unused_property_fields() - 1;
if (unused_property_fields < 0) {
unused_property_fields += JSObject::kFieldsAdded;
}
}
- result->set_unused_property_fields(unused_property_fields);
+ child->set_unused_property_fields(unused_property_fields);
if (FLAG_unbox_double_fields) {
Handle<LayoutDescriptor> layout_descriptor =
- LayoutDescriptor::AppendIfFastOrUseFull(map, details,
+ LayoutDescriptor::AppendIfFastOrUseFull(parent, details,
full_layout_descriptor);
- result->set_layout_descriptor(*layout_descriptor);
+ child->set_layout_descriptor(*layout_descriptor);
#ifdef VERIFY_HEAP
// TODO(ishell): remove these checks from VERIFY_HEAP mode.
if (FLAG_verify_heap) {
- CHECK(result->layout_descriptor()->IsConsistentWithMap(*result));
+ CHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
}
#else
- SLOW_DCHECK(result->layout_descriptor()->IsConsistentWithMap(*result));
+ SLOW_DCHECK(child->layout_descriptor()->IsConsistentWithMap(*child));
#endif
- result->set_visitor_id(Heap::GetStaticVisitorIdForMap(*result));
+ child->set_visitor_id(Heap::GetStaticVisitorIdForMap(*child));
}
Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
- ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
-
- return result;
+ ConnectTransition(parent, child, name, SIMPLE_PROPERTY_TRANSITION);
}
@@ -8308,6 +9588,58 @@ Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
}
+Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map,
+ LanguageMode language_mode, FunctionKind kind) {
+ DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
+ // Initial map for sloppy mode function is stored in the function
+ // constructor. Initial maps for strict and strong modes are cached as
+ // special transitions using |strict_function_transition_symbol| and
+ // |strong_function_transition_symbol| respectively as a key.
+ if (language_mode == SLOPPY) return initial_map;
+ Isolate* isolate = initial_map->GetIsolate();
+ Factory* factory = isolate->factory();
+ Handle<Symbol> transition_symbol;
+
+ int map_index = Context::FunctionMapIndex(language_mode, kind);
+ Handle<Map> function_map(
+ Map::cast(isolate->native_context()->get(map_index)));
+
+ STATIC_ASSERT(LANGUAGE_END == 3);
+ switch (language_mode) {
+ case STRICT:
+ transition_symbol = factory->strict_function_transition_symbol();
+ break;
+ case STRONG:
+ transition_symbol = factory->strong_function_transition_symbol();
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ Map* maybe_transition =
+ TransitionArray::SearchSpecial(*initial_map, *transition_symbol);
+ if (maybe_transition != NULL) {
+ return handle(maybe_transition, isolate);
+ }
+ initial_map->NotifyLeafMapLayoutChange();
+
+ // Create new map taking descriptors from the |function_map| and all
+ // the other details from the |initial_map|.
+ Handle<Map> map =
+ Map::CopyInitialMap(function_map, initial_map->instance_size(),
+ initial_map->GetInObjectProperties(),
+ initial_map->unused_property_fields());
+ map->SetConstructor(initial_map->GetConstructor());
+ map->set_prototype(initial_map->prototype());
+
+ if (TransitionArray::CanHaveMoreTransitions(initial_map)) {
+ Map::ConnectTransition(initial_map, map, transition_symbol,
+ SPECIAL_TRANSITION);
+ }
+ return map;
+}
+
+
Handle<Map> Map::CopyForObserved(Handle<Map> map) {
DCHECK(!map->is_observed());
@@ -8427,25 +9759,6 @@ Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
}
-Handle<Map> Map::FixProxy(Handle<Map> map, InstanceType type, int size) {
- DCHECK(type == JS_OBJECT_TYPE || type == JS_FUNCTION_TYPE);
- DCHECK(map->IsJSProxyMap());
-
- Isolate* isolate = map->GetIsolate();
-
- // Allocate fresh map.
- // TODO(rossberg): Once we optimize proxies, cache these maps.
- Handle<Map> new_map = isolate->factory()->NewMap(type, size);
-
- Handle<Object> prototype(map->prototype(), isolate);
- Map::SetPrototype(new_map, prototype);
-
- map->NotifyLeafMapLayoutChange();
-
- return new_map;
-}
-
-
bool DescriptorArray::CanHoldValue(int descriptor, Object* value) {
PropertyDetails details = GetDetails(descriptor);
switch (details.type()) {
@@ -8726,7 +10039,6 @@ Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
Handle<DescriptorArray> descriptors =
DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
- DescriptorArray::WhitenessWitness witness(*descriptors);
if (attributes != NONE) {
for (int i = 0; i < size; ++i) {
@@ -8734,7 +10046,7 @@ Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
Name* key = desc->GetKey(i);
PropertyDetails details = desc->GetDetails(i);
// Bulk attribute changes never affect private properties.
- if (!key->IsSymbol() || !Symbol::cast(key)->is_private()) {
+ if (!key->IsPrivate()) {
int mask = DONT_DELETE | DONT_ENUM;
// READ_ONLY is an invalid attribute for JS setters/getters.
if (details.type() != ACCESSOR_CONSTANT || !value->IsAccessorPair()) {
@@ -8745,11 +10057,11 @@ Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
}
Descriptor inner_desc(
handle(key), handle(value, desc->GetIsolate()), details);
- descriptors->Set(i, &inner_desc, witness);
+ descriptors->SetDescriptor(i, &inner_desc);
}
} else {
for (int i = 0; i < size; ++i) {
- descriptors->CopyFrom(i, *desc, witness);
+ descriptors->CopyFrom(i, *desc);
}
}
@@ -8759,6 +10071,22 @@ Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
}
+bool DescriptorArray::IsEqualUpTo(DescriptorArray* desc, int nof_descriptors) {
+ for (int i = 0; i < nof_descriptors; i++) {
+ if (GetKey(i) != desc->GetKey(i) || GetValue(i) != desc->GetValue(i)) {
+ return false;
+ }
+ PropertyDetails details = GetDetails(i);
+ PropertyDetails other_details = desc->GetDetails(i);
+ if (details.type() != other_details.type() ||
+ !details.representation().Equals(other_details.representation())) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
Handle<DescriptorArray> descriptors,
Descriptor* descriptor,
@@ -9440,6 +10768,12 @@ Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
}
+bool ArrayList::IsFull() {
+ int capacity = length();
+ return kFirstIndex + Length() == capacity;
+}
+
+
Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
int capacity = array->length();
bool empty = (capacity == 0);
@@ -9465,7 +10799,7 @@ Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
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));
+ Handle<FixedArray> result = factory->NewFixedArray(LengthFor(size), TENURED);
result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
result->set(kEnumCacheIndex, Smi::FromInt(0));
@@ -9508,21 +10842,16 @@ void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
}
-void DescriptorArray::CopyFrom(int index, DescriptorArray* src,
- const WhitenessWitness& witness) {
+void DescriptorArray::CopyFrom(int index, DescriptorArray* src) {
Object* value = src->GetValue(index);
PropertyDetails details = src->GetDetails(index);
Descriptor desc(handle(src->GetKey(index)),
handle(value, src->GetIsolate()),
details);
- Set(index, &desc, witness);
+ SetDescriptor(index, &desc);
}
-// We need the whiteness witness since sort will reshuffle the entries in the
-// descriptor array. If the descriptor array were to be black, the shuffling
-// would move a slot that was already recorded as pointing into an evacuation
-// candidate. This would result in missing updates upon evacuation.
void DescriptorArray::Sort() {
// In-place heap sort.
int len = number_of_descriptors();
@@ -9628,47 +10957,6 @@ Handle<LiteralsArray> LiteralsArray::New(Isolate* isolate,
}
-// static
-Handle<BindingsArray> BindingsArray::New(Isolate* isolate,
- Handle<TypeFeedbackVector> vector,
- Handle<JSReceiver> bound_function,
- Handle<Object> bound_this,
- int number_of_bindings) {
- Handle<FixedArray> bindings = isolate->factory()->NewFixedArray(
- number_of_bindings + kFirstBindingIndex);
- Handle<BindingsArray> casted_bindings = Handle<BindingsArray>::cast(bindings);
- casted_bindings->set_feedback_vector(*vector);
- casted_bindings->set_bound_function(*bound_function);
- casted_bindings->set_bound_this(*bound_this);
- return casted_bindings;
-}
-
-
-// static
-Handle<JSArray> BindingsArray::CreateBoundArguments(
- Handle<BindingsArray> bindings) {
- int bound_argument_count = bindings->bindings_count();
- Factory* factory = bindings->GetIsolate()->factory();
- Handle<FixedArray> arguments = factory->NewFixedArray(bound_argument_count);
- bindings->CopyTo(kFirstBindingIndex, *arguments, 0, bound_argument_count);
- return factory->NewJSArrayWithElements(arguments);
-}
-
-
-// static
-Handle<JSArray> BindingsArray::CreateRuntimeBindings(
- Handle<BindingsArray> bindings) {
- Factory* factory = bindings->GetIsolate()->factory();
- // A runtime bindings array consists of
- // [bound function, bound this, [arg0, arg1, ...]].
- Handle<FixedArray> runtime_bindings =
- factory->NewFixedArray(2 + bindings->bindings_count());
- bindings->CopyTo(kBoundFunctionIndex, *runtime_bindings, 0,
- 2 + bindings->bindings_count());
- return factory->NewJSArrayWithElements(runtime_bindings);
-}
-
-
int HandlerTable::LookupRange(int pc_offset, int* stack_depth_out,
CatchPrediction* prediction_out) {
int innermost_handler = -1, innermost_start = -1;
@@ -10336,8 +11624,10 @@ static void CalculateLineEndsImpl(Isolate* isolate,
if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) {
line_ends->Add(src_len - 1);
- } else if (include_ending_line) {
- // Even if the last line misses a line end, it is counted.
+ }
+ if (include_ending_line) {
+ // Include one character beyond the end of script. The rewriter uses that
+ // position for the implicit return statement.
line_ends->Add(src_len);
}
}
@@ -10933,12 +12223,6 @@ void String::PrintOn(FILE* file) {
}
-inline static uint32_t ObjectAddressForHashing(Object* object) {
- uint32_t value = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object));
- return value & MemoryChunk::kAlignmentMask;
-}
-
-
int Map::Hash() {
// For performance reasons we only hash the 3 most variable fields of a map:
// constructor, prototype and bit_field2. For predictability reasons we
@@ -10973,7 +12257,15 @@ bool CheckEquivalent(Map* first, Map* second) {
bool Map::EquivalentToForTransition(Map* other) {
- return CheckEquivalent(this, other);
+ if (!CheckEquivalent(this, other)) return false;
+ if (instance_type() == JS_FUNCTION_TYPE) {
+ // JSFunctions require more checks to ensure that sloppy function is
+ // not equvalent to strict function.
+ int nof = Min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors());
+ return instance_descriptors()->IsEqualUpTo(other->instance_descriptors(),
+ nof);
+ }
+ return true;
}
@@ -11054,14 +12346,19 @@ void SharedFunctionInfo::AddSharedCodeToOptimizedCodeMap(
Isolate* isolate = shared->GetIsolate();
if (isolate->serializer_enabled()) return;
DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
- Handle<Object> value(shared->optimized_code_map(), isolate);
- if (value->IsSmi()) return; // Empty code maps are unsupported.
- Handle<FixedArray> code_map = Handle<FixedArray>::cast(value);
- code_map->set(kSharedCodeIndex, *code);
+ // Empty code maps are unsupported.
+ if (!shared->OptimizedCodeMapIsCleared()) {
+ Handle<WeakCell> cell = isolate->factory()->NewWeakCell(code);
+ // A collection may have occured and cleared the optimized code map in the
+ // allocation above.
+ if (!shared->OptimizedCodeMapIsCleared()) {
+ shared->optimized_code_map()->set(kSharedCodeIndex, *cell);
+ }
+ }
}
-void SharedFunctionInfo::AddToOptimizedCodeMap(
+void SharedFunctionInfo::AddToOptimizedCodeMapInternal(
Handle<SharedFunctionInfo> shared, Handle<Context> native_context,
Handle<HeapObject> code, Handle<LiteralsArray> literals,
BailoutId osr_ast_id) {
@@ -11074,86 +12371,110 @@ void SharedFunctionInfo::AddToOptimizedCodeMap(
DCHECK(native_context->IsNativeContext());
STATIC_ASSERT(kEntryLength == 4);
Handle<FixedArray> new_code_map;
- Handle<Object> value(shared->optimized_code_map(), isolate);
int entry;
- if (value->IsSmi()) {
- // No optimized code map.
- DCHECK_EQ(0, Smi::cast(*value)->value());
+
+ if (shared->OptimizedCodeMapIsCleared()) {
new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED);
+ new_code_map->set(kSharedCodeIndex, *isolate->factory()->empty_weak_cell(),
+ SKIP_WRITE_BARRIER);
entry = kEntriesStart;
} else {
- Handle<FixedArray> old_code_map = Handle<FixedArray>::cast(value);
+ Handle<FixedArray> old_code_map(shared->optimized_code_map(), isolate);
entry = shared->SearchOptimizedCodeMapEntry(*native_context, osr_ast_id);
if (entry > kSharedCodeIndex) {
- // Found an existing context-specific entry, it must not contain any code.
- DCHECK_EQ(isolate->heap()->undefined_value(),
- old_code_map->get(entry + kCachedCodeOffset));
+ // Found an existing context-specific entry. If the user provided valid
+ // code, it must not contain any code.
+ DCHECK(code->IsUndefined() ||
+ WeakCell::cast(old_code_map->get(entry + kCachedCodeOffset))
+ ->cleared());
+
// Just set the code and literals to the entry.
- old_code_map->set(entry + kCachedCodeOffset, *code);
- old_code_map->set(entry + kLiteralsOffset, *literals);
+ if (!code->IsUndefined()) {
+ Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
+ old_code_map->set(entry + kCachedCodeOffset, *code_cell);
+ }
+ Handle<WeakCell> literals_cell =
+ isolate->factory()->NewWeakCell(literals);
+ old_code_map->set(entry + kLiteralsOffset, *literals_cell);
return;
}
- // Copy old optimized code map and append one new entry.
- new_code_map = isolate->factory()->CopyFixedArrayAndGrow(
- old_code_map, kEntryLength, TENURED);
- // TODO(mstarzinger): Temporary workaround. The allocation above might have
- // flushed the optimized code map and the copy we created is full of holes.
- // For now we just give up on adding the entry and pretend it got flushed.
- if (shared->optimized_code_map()->IsSmi()) return;
- entry = old_code_map->length();
+ // Can we reuse an entry?
+ DCHECK(entry < kEntriesStart);
+ int length = old_code_map->length();
+ for (int i = kEntriesStart; i < length; i += kEntryLength) {
+ if (WeakCell::cast(old_code_map->get(i + kContextOffset))->cleared()) {
+ new_code_map = old_code_map;
+ entry = i;
+ break;
+ }
+ }
+
+ if (entry < kEntriesStart) {
+ // Copy old optimized code map and append one new entry.
+ new_code_map = isolate->factory()->CopyFixedArrayAndGrow(
+ old_code_map, kEntryLength, TENURED);
+ // TODO(mstarzinger): Temporary workaround. The allocation above might
+ // have flushed the optimized code map and the copy we created is full of
+ // holes. For now we just give up on adding the entry and pretend it got
+ // flushed.
+ if (shared->OptimizedCodeMapIsCleared()) return;
+ entry = old_code_map->length();
+ }
}
- new_code_map->set(entry + kContextOffset, *native_context);
- new_code_map->set(entry + kCachedCodeOffset, *code);
- new_code_map->set(entry + kLiteralsOffset, *literals);
+
+ Handle<WeakCell> code_cell = code->IsUndefined()
+ ? isolate->factory()->empty_weak_cell()
+ : isolate->factory()->NewWeakCell(code);
+ Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals);
+ WeakCell* context_cell = native_context->self_weak_cell();
+
+ new_code_map->set(entry + kContextOffset, context_cell);
+ new_code_map->set(entry + kCachedCodeOffset, *code_cell);
+ new_code_map->set(entry + kLiteralsOffset, *literals_cell);
new_code_map->set(entry + kOsrAstIdOffset, Smi::FromInt(osr_ast_id.ToInt()));
#ifdef DEBUG
for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
- DCHECK(new_code_map->get(i + kContextOffset)->IsNativeContext());
- Object* code = new_code_map->get(i + kCachedCodeOffset);
- if (code != isolate->heap()->undefined_value()) {
- DCHECK(code->IsCode());
- DCHECK(Code::cast(code)->kind() == Code::OPTIMIZED_FUNCTION);
- }
- DCHECK(new_code_map->get(i + kLiteralsOffset)->IsFixedArray());
+ WeakCell* cell = WeakCell::cast(new_code_map->get(i + kContextOffset));
+ DCHECK(cell->cleared() || cell->value()->IsNativeContext());
+ cell = WeakCell::cast(new_code_map->get(i + kCachedCodeOffset));
+ DCHECK(cell->cleared() ||
+ (cell->value()->IsCode() &&
+ Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION));
+ cell = WeakCell::cast(new_code_map->get(i + kLiteralsOffset));
+ DCHECK(cell->cleared() || cell->value()->IsFixedArray());
DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi());
}
#endif
- // Zap any old optimized code map.
- if (!shared->optimized_code_map()->IsSmi()) {
- FixedArray* old_code_map = FixedArray::cast(shared->optimized_code_map());
- old_code_map->FillWithHoles(0, old_code_map->length());
+ FixedArray* old_code_map = shared->optimized_code_map();
+ if (old_code_map != *new_code_map) {
+ shared->set_optimized_code_map(*new_code_map);
}
-
- shared->set_optimized_code_map(*new_code_map);
}
void SharedFunctionInfo::ClearOptimizedCodeMap() {
- // Zap any old optimized code map.
- if (!optimized_code_map()->IsSmi()) {
- FixedArray* old_code_map = FixedArray::cast(optimized_code_map());
- old_code_map->FillWithHoles(0, old_code_map->length());
- }
-
- set_optimized_code_map(Smi::FromInt(0));
+ FixedArray* cleared_map = GetHeap()->cleared_optimized_code_map();
+ set_optimized_code_map(cleared_map, SKIP_WRITE_BARRIER);
}
void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
const char* reason) {
DisallowHeapAllocation no_gc;
- if (optimized_code_map()->IsSmi()) return;
+ if (OptimizedCodeMapIsCleared()) return;
Heap* heap = GetHeap();
- FixedArray* code_map = FixedArray::cast(optimized_code_map());
+ FixedArray* code_map = optimized_code_map();
int dst = kEntriesStart;
int length = code_map->length();
for (int src = kEntriesStart; src < length; src += kEntryLength) {
- DCHECK(code_map->get(src)->IsNativeContext());
- if (code_map->get(src + kCachedCodeOffset) == optimized_code) {
+ DCHECK(WeakCell::cast(code_map->get(src))->cleared() ||
+ WeakCell::cast(code_map->get(src))->value()->IsNativeContext());
+ if (WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() ==
+ optimized_code) {
BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value());
if (FLAG_trace_opt) {
PrintF("[evicting entry from optimizing code map (%s) for ", reason);
@@ -11170,7 +12491,8 @@ void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
}
// In case of non-OSR entry just clear the code in order to proceed
// sharing literals.
- code_map->set_undefined(src + kCachedCodeOffset);
+ code_map->set(src + kCachedCodeOffset, heap->empty_weak_cell(),
+ SKIP_WRITE_BARRIER);
}
// Keep the src entry by copying it to the dst entry.
@@ -11185,9 +12507,11 @@ void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
}
dst += kEntryLength;
}
- if (code_map->get(kSharedCodeIndex) == optimized_code) {
+ if (WeakCell::cast(code_map->get(kSharedCodeIndex))->value() ==
+ optimized_code) {
// Evict context-independent code as well.
- code_map->set_undefined(kSharedCodeIndex);
+ code_map->set(kSharedCodeIndex, heap->empty_weak_cell(),
+ SKIP_WRITE_BARRIER);
if (FLAG_trace_opt) {
PrintF("[evicting entry from optimizing code map (%s) for ", reason);
ShortPrint();
@@ -11199,7 +12523,7 @@ void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(code_map,
length - dst);
if (code_map->length() == kEntriesStart &&
- code_map->get(kSharedCodeIndex)->IsUndefined()) {
+ WeakCell::cast(code_map->get(kSharedCodeIndex))->cleared()) {
ClearOptimizedCodeMap();
}
}
@@ -11207,14 +12531,14 @@ void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
- FixedArray* code_map = FixedArray::cast(optimized_code_map());
+ FixedArray* code_map = optimized_code_map();
DCHECK(shrink_by % kEntryLength == 0);
DCHECK(shrink_by <= code_map->length() - kEntriesStart);
// Always trim even when array is cleared because of heap verifier.
GetHeap()->RightTrimFixedArray<Heap::SEQUENTIAL_TO_SWEEPER>(code_map,
shrink_by);
if (code_map->length() == kEntriesStart &&
- code_map->get(kSharedCodeIndex)->IsUndefined()) {
+ WeakCell::cast(code_map->get(kSharedCodeIndex))->cleared()) {
ClearOptimizedCodeMap();
}
}
@@ -11239,18 +12563,11 @@ static void ShrinkInstanceSize(Map* map, void* data) {
}
-void JSFunction::CompleteInobjectSlackTracking() {
- DCHECK(has_initial_map());
- initial_map()->CompleteInobjectSlackTracking();
-}
-
-
void Map::CompleteInobjectSlackTracking() {
// Has to be an initial map.
DCHECK(GetBackPointer()->IsUndefined());
- DCHECK_GE(counter(), kSlackTrackingCounterEnd - 1);
- set_counter(kRetainingCounterStart);
+ set_construction_counter(kNoSlackTracking);
int slack = unused_property_fields();
TransitionArray::TraverseTransitionTree(this, &GetMinInobjectSlack, &slack);
@@ -11284,7 +12601,6 @@ static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
PrototypeOptimizationMode mode) {
if (object->IsJSGlobalObject()) return;
- if (object->IsJSGlobalProxy()) return;
if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) {
// First normalize to ensure all JSFunctions are DATA_CONSTANT.
JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
@@ -11310,13 +12626,9 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
Isolate* isolate = object->GetIsolate();
if (!constructor->shared()->IsApiFunction() &&
object->class_name() == isolate->heap()->Object_string()) {
- Handle<String> constructor_name(object->constructor_name(), isolate);
Context* context = constructor->context()->native_context();
JSFunction* object_function = context->object_function();
object->map()->SetConstructor(object_function);
- Handle<PrototypeInfo> proto_info =
- Map::GetOrCreatePrototypeInfo(object, isolate);
- proto_info->set_constructor_name(*constructor_name);
}
}
}
@@ -11346,7 +12658,6 @@ void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
break;
}
Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
- if (maybe_proto->IsJSGlobalProxy()) continue;
// Proxies on the prototype chain are not supported. They make it
// impossible to make any assumptions about the prototype chain anyway.
if (maybe_proto->IsJSProxy()) return;
@@ -11381,17 +12692,18 @@ bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
DCHECK(user->is_prototype_map());
// If it doesn't have a PrototypeInfo, it was never registered.
if (!user->prototype_info()->IsPrototypeInfo()) return false;
- // If it doesn't have a prototype, it can't be registered.
- if (!user->prototype()->IsJSObject()) return false;
+ // If it had no prototype before, see if it had users that might expect
+ // registration.
+ if (!user->prototype()->IsJSObject()) {
+ Object* users =
+ PrototypeInfo::cast(user->prototype_info())->prototype_users();
+ return users->IsWeakFixedArray();
+ }
Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
Handle<PrototypeInfo> user_info =
Map::GetOrCreatePrototypeInfo(user, isolate);
int slot = user_info->registry_slot();
if (slot == PrototypeInfo::UNREGISTERED) return false;
- if (prototype->IsJSGlobalProxy()) {
- PrototypeIterator iter(isolate, prototype);
- prototype = PrototypeIterator::GetCurrent<JSObject>(iter);
- }
DCHECK(prototype->map()->is_prototype_map());
Object* maybe_proto_info = prototype->map()->prototype_info();
// User knows its registry slot, prototype info and user registry must exist.
@@ -11440,10 +12752,6 @@ static void InvalidatePrototypeChainsInternal(Map* map) {
void JSObject::InvalidatePrototypeChains(Map* map) {
if (!FLAG_eliminate_prototype_chain_checks) return;
DisallowHeapAllocation no_gc;
- if (map->IsJSGlobalProxyMap()) {
- PrototypeIterator iter(map);
- map = iter.GetCurrent<JSObject>()->map();
- }
InvalidatePrototypeChainsInternal(map);
}
@@ -11480,10 +12788,6 @@ Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
Handle<Object> maybe_prototype(map->prototype(), isolate);
if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null();
Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
- if (prototype->IsJSGlobalProxy()) {
- PrototypeIterator iter(isolate, prototype);
- prototype = PrototypeIterator::GetCurrent<JSObject>(iter);
- }
// Ensure the prototype is registered with its own prototypes so its cell
// will be invalidated when necessary.
JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate),
@@ -11523,33 +12827,26 @@ Handle<Object> CacheInitialJSArrayMaps(
Handle<Context> native_context, Handle<Map> initial_map) {
// Replace all of the cached initial array maps in the native context with
// the appropriate transitioned elements kind maps.
- Factory* factory = native_context->GetIsolate()->factory();
- Handle<FixedArray> maps = factory->NewFixedArrayWithHoles(
- kElementsKindCount, TENURED);
-
+ Strength strength =
+ initial_map->is_strong() ? Strength::STRONG : Strength::WEAK;
Handle<Map> current_map = initial_map;
ElementsKind kind = current_map->elements_kind();
- DCHECK(kind == GetInitialFastElementsKind());
- maps->set(kind, *current_map);
+ DCHECK_EQ(GetInitialFastElementsKind(), kind);
+ native_context->set(Context::ArrayMapIndex(kind, strength), *current_map);
for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
i < kFastElementsKindCount; ++i) {
Handle<Map> new_map;
ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
- Map* maybe_elements_transition = current_map->ElementsTransitionMap();
- if (maybe_elements_transition != NULL) {
+ if (Map* maybe_elements_transition = current_map->ElementsTransitionMap()) {
new_map = handle(maybe_elements_transition);
- DCHECK(new_map->elements_kind() == next_kind);
} else {
new_map = Map::CopyAsElementsKind(
current_map, next_kind, INSERT_TRANSITION);
}
- maps->set(next_kind, *new_map);
+ DCHECK_EQ(next_kind, new_map->elements_kind());
+ native_context->set(Context::ArrayMapIndex(next_kind, strength), *new_map);
current_map = new_map;
}
- if (initial_map->is_strong())
- native_context->set_js_array_strong_maps(*maps);
- else
- native_context->set_js_array_maps(*maps);
return initial_map;
}
@@ -11567,9 +12864,7 @@ void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
// copy containing the new prototype. Also complete any in-object
// slack tracking that is in progress at this point because it is
// still tracking the old copy.
- if (function->IsInobjectSlackTrackingInProgress()) {
- function->CompleteInobjectSlackTracking();
- }
+ function->CompleteInobjectSlackTrackingIfActive();
Handle<Map> initial_map(function->initial_map(), isolate);
@@ -11689,10 +12984,85 @@ void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
}
+#ifdef DEBUG
+namespace {
+
+bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
+ switch (instance_type) {
+ case JS_OBJECT_TYPE:
+ case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
+ case JS_GENERATOR_OBJECT_TYPE:
+ case JS_MODULE_TYPE:
+ case JS_VALUE_TYPE:
+ case JS_DATE_TYPE:
+ case JS_ARRAY_TYPE:
+ case JS_MESSAGE_OBJECT_TYPE:
+ case JS_ARRAY_BUFFER_TYPE:
+ case JS_TYPED_ARRAY_TYPE:
+ case JS_DATA_VIEW_TYPE:
+ case JS_SET_TYPE:
+ 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:
+ case JS_REGEXP_TYPE:
+ case JS_FUNCTION_TYPE:
+ return true;
+
+ case JS_BOUND_FUNCTION_TYPE:
+ case JS_PROXY_TYPE:
+ case JS_GLOBAL_PROXY_TYPE:
+ case JS_GLOBAL_OBJECT_TYPE:
+ case FIXED_ARRAY_TYPE:
+ case FIXED_DOUBLE_ARRAY_TYPE:
+ case ODDBALL_TYPE:
+ case FOREIGN_TYPE:
+ case MAP_TYPE:
+ case CODE_TYPE:
+ case CELL_TYPE:
+ case PROPERTY_CELL_TYPE:
+ case WEAK_CELL_TYPE:
+ case SYMBOL_TYPE:
+ case BYTECODE_ARRAY_TYPE:
+ case HEAP_NUMBER_TYPE:
+ case MUTABLE_HEAP_NUMBER_TYPE:
+ case SIMD128_VALUE_TYPE:
+ case FILLER_TYPE:
+ case BYTE_ARRAY_TYPE:
+ case FREE_SPACE_TYPE:
+ case SHARED_FUNCTION_INFO_TYPE:
+
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case FIXED_##TYPE##_ARRAY_TYPE:
+#undef TYPED_ARRAY_CASE
+
+#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
+ STRUCT_LIST(MAKE_STRUCT_CASE)
+#undef MAKE_STRUCT_CASE
+ // We must not end up here for these instance types at all.
+ UNREACHABLE();
+ // Fall through.
+ default:
+ return false;
+ }
+}
+
+} // namespace
+#endif
+
+
void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
+ DCHECK(function->IsConstructor() || function->shared()->is_generator());
if (function->has_initial_map()) return;
Isolate* isolate = function->GetIsolate();
+ // The constructor should be compiled for the optimization hints to be
+ // available.
+ Compiler::Compile(function, CLEAR_EXCEPTION);
+
// First create a new map with the size and number of in-object properties
// suggested by the function.
InstanceType instance_type;
@@ -11725,78 +13095,109 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
// Finally link initial map and constructor function.
DCHECK(prototype->IsJSReceiver());
JSFunction::SetInitialMap(function, map, prototype);
-
- if (!function->shared()->is_generator()) {
- function->StartInobjectSlackTracking();
- }
+ map->StartInobjectSlackTracking();
}
-Handle<Map> JSFunction::EnsureDerivedHasInitialMap(
- Handle<JSFunction> original_constructor, Handle<JSFunction> constructor) {
- DCHECK(constructor->has_initial_map());
- Isolate* isolate = constructor->GetIsolate();
- Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
- if (*original_constructor == *constructor) return constructor_initial_map;
- if (original_constructor->has_initial_map()) {
- // Check that |original_constructor|'s initial map still in sync with
- // the |constructor|, otherwise we must create a new initial map for
- // |original_constructor|.
- if (original_constructor->initial_map()->GetConstructor() == *constructor) {
- return handle(original_constructor->initial_map(), isolate);
- }
- }
-
- // First create a new map with the size and number of in-object properties
- // suggested by the function.
- DCHECK(!original_constructor->shared()->is_generator());
- DCHECK(!constructor->shared()->is_generator());
+// static
+MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
+ Handle<JSFunction> constructor,
+ Handle<JSReceiver> new_target) {
+ EnsureHasInitialMap(constructor);
- // Fetch or allocate prototype.
+ Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
+ if (*new_target == *constructor) return constructor_initial_map;
+
+ // Fast case, new.target is a subclass of constructor. The map is cacheable
+ // (and may already have been cached). new.target.prototype is guaranteed to
+ // be a JSReceiver.
+ if (new_target->IsJSFunction()) {
+ Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
+
+ // Check that |function|'s initial map still in sync with the |constructor|,
+ // otherwise we must create a new initial map for |function|.
+ if (function->has_initial_map() &&
+ function->initial_map()->GetConstructor() == *constructor) {
+ return handle(function->initial_map(), isolate);
+ }
+
+ // Create a new map with the size and number of in-object properties
+ // suggested by |function|.
+
+ // Link initial map and constructor function if the new.target is actually a
+ // subclass constructor.
+ if (IsSubclassConstructor(function->shared()->kind())) {
+ Handle<Object> prototype(function->instance_prototype(), isolate);
+ InstanceType instance_type = constructor_initial_map->instance_type();
+ DCHECK(CanSubclassHaveInobjectProperties(instance_type));
+ int internal_fields =
+ JSObject::GetInternalFieldCount(*constructor_initial_map);
+ int pre_allocated = constructor_initial_map->GetInObjectProperties() -
+ constructor_initial_map->unused_property_fields();
+ int instance_size;
+ int in_object_properties;
+ function->CalculateInstanceSizeForDerivedClass(
+ instance_type, internal_fields, &instance_size,
+ &in_object_properties);
+
+ int unused_property_fields = in_object_properties - pre_allocated;
+ Handle<Map> map =
+ Map::CopyInitialMap(constructor_initial_map, instance_size,
+ in_object_properties, unused_property_fields);
+ map->set_new_target_is_base(false);
+
+ JSFunction::SetInitialMap(function, map, prototype);
+ map->SetConstructor(*constructor);
+ map->StartInobjectSlackTracking();
+ return map;
+ }
+ }
+
+ // Slow path, new.target is either a proxy or can't cache the map.
+ // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
+ // fall back to the intrinsicDefaultProto.
Handle<Object> prototype;
- if (original_constructor->has_instance_prototype()) {
- prototype = handle(original_constructor->instance_prototype(), isolate);
+ if (new_target->IsJSFunction()) {
+ Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
+ // Make sure the new.target.prototype is cached.
+ EnsureHasInitialMap(function);
+ prototype = handle(function->prototype(), isolate);
} else {
- prototype = isolate->factory()->NewFunctionPrototype(original_constructor);
- }
-
- // Finally link initial map and constructor function if the original
- // constructor is actually a subclass constructor.
- if (IsSubclassConstructor(original_constructor->shared()->kind())) {
-// TODO(ishell): v8:4531, allow ES6 built-ins subclasses to have
-// in-object properties.
-#if 0
- InstanceType instance_type = constructor_initial_map->instance_type();
- int internal_fields =
- JSObject::GetInternalFieldCount(*constructor_initial_map);
- int pre_allocated = constructor_initial_map->GetInObjectProperties() -
- constructor_initial_map->unused_property_fields();
- int instance_size;
- int in_object_properties;
- original_constructor->CalculateInstanceSizeForDerivedClass(
- instance_type, internal_fields, &instance_size, &in_object_properties);
-
- int unused_property_fields = in_object_properties - pre_allocated;
- Handle<Map> map =
- Map::CopyInitialMap(constructor_initial_map, instance_size,
- in_object_properties, unused_property_fields);
-#endif
- Handle<Map> map = Map::CopyInitialMap(constructor_initial_map);
-
- JSFunction::SetInitialMap(original_constructor, map, prototype);
- map->SetConstructor(*constructor);
- original_constructor->StartInobjectSlackTracking();
- return map;
-
- } else {
- Handle<Map> map = Map::CopyInitialMap(constructor_initial_map);
- DCHECK(prototype->IsJSReceiver());
- if (map->prototype() != *prototype) {
- Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
- }
- map->SetConstructor(*constructor);
- return map;
+ Handle<String> prototype_string = isolate->factory()->prototype_string();
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, prototype,
+ JSReceiver::GetProperty(new_target, prototype_string), Map);
+ // The above prototype lookup might change the constructor and its
+ // prototype, hence we have to reload the initial map.
+ EnsureHasInitialMap(constructor);
+ constructor_initial_map = handle(constructor->initial_map(), isolate);
+ }
+
+ // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
+ // correct realm. Rather than directly fetching the .prototype, we fetch the
+ // constructor that points to the .prototype. This relies on
+ // constructor.prototype being FROZEN for those constructors.
+ if (!prototype->IsJSReceiver()) {
+ Handle<Context> context;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
+ JSReceiver::GetFunctionRealm(new_target), Map);
+ DCHECK(context->IsNativeContext());
+ Handle<Object> maybe_index = JSReceiver::GetDataProperty(
+ constructor, isolate->factory()->native_context_index_symbol());
+ int index = maybe_index->IsSmi() ? Smi::cast(*maybe_index)->value()
+ : Context::OBJECT_FUNCTION_INDEX;
+ Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)));
+ prototype = handle(realm_constructor->prototype(), isolate);
+ }
+
+ Handle<Map> map = Map::CopyInitialMap(constructor_initial_map);
+ map->set_new_target_is_base(false);
+ DCHECK(prototype->IsJSReceiver());
+ if (map->prototype() != *prototype) {
+ Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
}
+ map->SetConstructor(*constructor);
+ return map;
}
@@ -11843,7 +13244,7 @@ bool JSFunction::PassesFilter(const char* raw_filter) {
}
-Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
+Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
Isolate* isolate = function->GetIsolate();
Handle<Object> name =
JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
@@ -11852,6 +13253,94 @@ Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
}
+Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
+ Isolate* isolate = function->GetIsolate();
+ Handle<Object> name = JSReceiver::GetDataProperty(
+ function, isolate->factory()->display_name_string());
+ if (name->IsString()) return Handle<String>::cast(name);
+ return JSFunction::GetName(function);
+}
+
+
+namespace {
+
+char const kNativeCodeSource[] = "function () { [native code] }";
+
+
+Handle<String> NativeCodeFunctionSourceString(
+ Handle<SharedFunctionInfo> shared_info) {
+ Isolate* const isolate = shared_info->GetIsolate();
+ if (shared_info->name()->IsString()) {
+ IncrementalStringBuilder builder(isolate);
+ builder.AppendCString("function ");
+ builder.AppendString(handle(String::cast(shared_info->name()), isolate));
+ builder.AppendCString("() { [native code] }");
+ return builder.Finish().ToHandleChecked();
+ }
+ return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
+}
+
+} // namespace
+
+
+// static
+Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
+ Isolate* const isolate = function->GetIsolate();
+ return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
+}
+
+
+// static
+Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
+ Isolate* const isolate = function->GetIsolate();
+ Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
+
+ // Check if {function} should hide its source code.
+ if (!shared_info->script()->IsScript() ||
+ Script::cast(shared_info->script())->hide_source()) {
+ return NativeCodeFunctionSourceString(shared_info);
+ }
+
+ // Check if we should print {function} as a class.
+ Handle<Object> class_start_position = JSReceiver::GetDataProperty(
+ function, isolate->factory()->class_start_position_symbol());
+ if (class_start_position->IsSmi()) {
+ Handle<Object> class_end_position = JSReceiver::GetDataProperty(
+ function, isolate->factory()->class_end_position_symbol());
+ Handle<String> script_source(
+ String::cast(Script::cast(shared_info->script())->source()), isolate);
+ return isolate->factory()->NewSubString(
+ script_source, Handle<Smi>::cast(class_start_position)->value(),
+ Handle<Smi>::cast(class_end_position)->value());
+ }
+
+ // Check if we have source code for the {function}.
+ if (!shared_info->HasSourceCode()) {
+ return NativeCodeFunctionSourceString(shared_info);
+ }
+
+ IncrementalStringBuilder builder(isolate);
+ if (!shared_info->is_arrow()) {
+ if (shared_info->is_concise_method()) {
+ if (shared_info->is_generator()) builder.AppendCharacter('*');
+ } else {
+ if (shared_info->is_generator()) {
+ builder.AppendCString("function* ");
+ } else {
+ builder.AppendCString("function ");
+ }
+ }
+ if (shared_info->name_should_print_as_anonymous()) {
+ builder.AppendCString("anonymous");
+ } else {
+ builder.AppendString(handle(String::cast(shared_info->name()), isolate));
+ }
+ }
+ builder.AppendString(Handle<String>::cast(shared_info->GetSourceCode()));
+ return builder.Finish().ToHandleChecked();
+}
+
+
void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
const char* to_string, Handle<Object> to_number,
const char* type_of, byte kind) {
@@ -12295,6 +13784,10 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
shared_info->set_dont_crankshaft(lit->flags() &
AstProperties::kDontCrankshaft);
shared_info->set_kind(lit->kind());
+ if (!IsConstructable(lit->kind(), lit->language_mode())) {
+ shared_info->set_construct_stub(
+ *shared_info->GetIsolate()->builtins()->ConstructedNonConstructable());
+ }
shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
shared_info->set_asm_function(lit->scope()->asm_function());
}
@@ -12311,18 +13804,16 @@ bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
}
-void JSFunction::StartInobjectSlackTracking() {
- DCHECK(has_initial_map() && !IsInobjectSlackTrackingInProgress());
-
- Map* map = initial_map();
+void Map::StartInobjectSlackTracking() {
+ DCHECK(!IsInobjectSlackTrackingInProgress());
// No tracking during the snapshot construction phase.
Isolate* isolate = GetIsolate();
if (isolate->serializer_enabled()) return;
- if (map->unused_property_fields() == 0) return;
+ if (unused_property_fields() == 0) return;
- map->set_counter(Map::kSlackTrackingCounterStart);
+ set_construction_counter(Map::kSlackTrackingCounterStart);
}
@@ -12349,18 +13840,19 @@ int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context,
BailoutId osr_ast_id) {
DisallowHeapAllocation no_gc;
DCHECK(native_context->IsNativeContext());
- Object* value = optimized_code_map();
- if (!value->IsSmi()) {
- FixedArray* optimized_code_map = FixedArray::cast(value);
+ if (!OptimizedCodeMapIsCleared()) {
+ FixedArray* optimized_code_map = this->optimized_code_map();
int length = optimized_code_map->length();
Smi* osr_ast_id_smi = Smi::FromInt(osr_ast_id.ToInt());
for (int i = kEntriesStart; i < length; i += kEntryLength) {
- if (optimized_code_map->get(i + kContextOffset) == native_context &&
+ if (WeakCell::cast(optimized_code_map->get(i + kContextOffset))
+ ->value() == native_context &&
optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) {
return i;
}
}
- Object* shared_code = optimized_code_map->get(kSharedCodeIndex);
+ Object* shared_code =
+ WeakCell::cast(optimized_code_map->get(kSharedCodeIndex))->value();
if (shared_code->IsCode() && osr_ast_id.IsNone()) {
return kSharedCodeIndex;
}
@@ -12374,18 +13866,27 @@ CodeAndLiterals SharedFunctionInfo::SearchOptimizedCodeMap(
CodeAndLiterals result = {nullptr, nullptr};
int entry = SearchOptimizedCodeMapEntry(native_context, osr_ast_id);
if (entry != kNotFound) {
- FixedArray* code_map = FixedArray::cast(optimized_code_map());
+ FixedArray* code_map = optimized_code_map();
if (entry == kSharedCodeIndex) {
- result = {Code::cast(code_map->get(kSharedCodeIndex)), nullptr};
-
+ // We know the weak cell isn't cleared because we made sure of it in
+ // SearchOptimizedCodeMapEntry and performed no allocations since that
+ // call.
+ result = {
+ Code::cast(WeakCell::cast(code_map->get(kSharedCodeIndex))->value()),
+ nullptr};
} else {
DCHECK_LE(entry + kEntryLength, code_map->length());
- Object* code = code_map->get(entry + kCachedCodeOffset);
- result = {code->IsUndefined() ? nullptr : Code::cast(code),
- LiteralsArray::cast(code_map->get(entry + kLiteralsOffset))};
+ WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset));
+ WeakCell* literals_cell =
+ WeakCell::cast(code_map->get(entry + kLiteralsOffset));
+
+ result = {cell->cleared() ? nullptr : Code::cast(cell->value()),
+ literals_cell->cleared()
+ ? nullptr
+ : LiteralsArray::cast(literals_cell->value())};
}
}
- if (FLAG_trace_opt && !optimized_code_map()->IsSmi() &&
+ if (FLAG_trace_opt && !OptimizedCodeMapIsCleared() &&
result.code == nullptr) {
PrintF("[didn't find optimized code in optimized code map for ");
ShortPrint();
@@ -12784,7 +14285,6 @@ void Code::ClearInlineCaches(Code::Kind kind) {
void Code::ClearInlineCaches(Code::Kind* kind) {
int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
- RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
for (RelocIterator it(this, mask); !it.done(); it.next()) {
RelocInfo* info = it.rinfo();
@@ -13122,6 +14622,17 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(
break;
}
+ case Translation::INTERPRETED_FRAME: {
+ int bytecode_offset = iterator.Next();
+ int shared_info_id = iterator.Next();
+ unsigned height = iterator.Next();
+ Object* shared_info = LiteralArray()->get(shared_info_id);
+ os << "{bytecode_offset=" << bytecode_offset << ", function="
+ << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
+ << ", height=" << height << "}";
+ break;
+ }
+
case Translation::JS_FRAME_FUNCTION: {
os << "{function}";
break;
@@ -13217,8 +14728,10 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(
}
case Translation::LITERAL: {
- unsigned literal_index = iterator.Next();
- os << "{literal_id=" << literal_index << "}";
+ int literal_index = iterator.Next();
+ Object* literal_value = LiteralArray()->get(literal_index);
+ os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
+ << ")}";
break;
}
@@ -13494,15 +15007,24 @@ void BytecodeArray::Disassemble(std::ostream& os) {
SNPrintF(buf, "%p", bytecode_start);
os << buf.start() << " : ";
interpreter::Bytecodes::Decode(os, bytecode_start, parameter_count());
- if (interpreter::Bytecodes::IsJump(bytecode)) {
- int offset = static_cast<int8_t>(bytecode_start[1]);
+
+ if (interpreter::Bytecodes::IsJumpConstantWide(bytecode)) {
+ DCHECK_EQ(bytecode_size, 3);
+ int index = static_cast<int>(ReadUnalignedUInt16(bytecode_start + 1));
+ int offset = Smi::cast(constant_pool()->get(index))->value();
SNPrintF(buf, " (%p)", bytecode_start + offset);
os << buf.start();
} else if (interpreter::Bytecodes::IsJumpConstant(bytecode)) {
+ DCHECK_EQ(bytecode_size, 2);
int index = static_cast<int>(bytecode_start[1]);
int offset = Smi::cast(constant_pool()->get(index))->value();
SNPrintF(buf, " (%p)", bytecode_start + offset);
os << buf.start();
+ } else if (interpreter::Bytecodes::IsJump(bytecode)) {
+ DCHECK_EQ(bytecode_size, 2);
+ int offset = static_cast<int8_t>(bytecode_start[1]);
+ SNPrintF(buf, " (%p)", bytecode_start + offset);
+ os << buf.start();
}
os << "\n";
}
@@ -13566,8 +15088,7 @@ MaybeHandle<Object> JSArray::ObservableSetLength(Handle<JSArray> array,
uint32_t old_length = 0;
CHECK(old_length_handle->ToArrayLength(&old_length));
- static const PropertyAttributes kNoAttrFilter = NONE;
- int num_elements = array->NumberOfOwnElements(kNoAttrFilter);
+ int num_elements = array->NumberOfOwnElements(ALL_PROPERTIES);
if (num_elements > 0) {
if (old_length == static_cast<uint32_t>(num_elements)) {
// Simple case for arrays without holes.
@@ -13579,7 +15100,7 @@ MaybeHandle<Object> JSArray::ObservableSetLength(Handle<JSArray> array,
// TODO(rafaelw): For fast, sparse arrays, we can avoid iterating over
// the to-be-removed indices twice.
Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements);
- array->GetOwnElementKeys(*keys, kNoAttrFilter);
+ array->GetOwnElementKeys(*keys, ALL_PROPERTIES);
while (num_elements-- > 0) {
uint32_t index = NumberToUint32(keys->get(num_elements));
if (index < new_length) break;
@@ -13649,20 +15170,6 @@ void Map::AddDependentCode(Handle<Map> map,
}
-DependentCode::GroupStartIndexes::GroupStartIndexes(DependentCode* entries) {
- Recompute(entries);
-}
-
-
-void DependentCode::GroupStartIndexes::Recompute(DependentCode* entries) {
- start_indexes_[0] = 0;
- for (int g = 1; g <= kGroupCount; g++) {
- int count = entries->number_of_entries(static_cast<DependencyGroup>(g - 1));
- start_indexes_[g] = start_indexes_[g - 1] + count;
- }
-}
-
-
Handle<DependentCode> DependentCode::InsertCompilationDependencies(
Handle<DependentCode> entries, DependencyGroup group,
Handle<Foreign> info) {
@@ -13680,44 +15187,54 @@ Handle<DependentCode> DependentCode::InsertWeakCode(
Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
DependencyGroup group,
Handle<Object> object) {
- GroupStartIndexes starts(*entries);
- int start = starts.at(group);
- int end = starts.at(group + 1);
- int number_of_entries = starts.number_of_entries();
+ if (entries->length() == 0 || entries->group() > group) {
+ // There is no such group.
+ return DependentCode::New(group, object, entries);
+ }
+ if (entries->group() < group) {
+ // The group comes later in the list.
+ Handle<DependentCode> old_next(entries->next_link());
+ Handle<DependentCode> new_next = Insert(old_next, group, object);
+ if (!old_next.is_identical_to(new_next)) {
+ entries->set_next_link(*new_next);
+ }
+ return entries;
+ }
+ DCHECK_EQ(group, entries->group());
+ int count = entries->count();
// Check for existing entry to avoid duplicates.
- for (int i = start; i < end; i++) {
+ for (int i = 0; i < count; i++) {
if (entries->object_at(i) == *object) return entries;
}
- if (entries->length() < kCodesStartIndex + number_of_entries + 1) {
+ if (entries->length() < kCodesStartIndex + count + 1) {
entries = EnsureSpace(entries);
- // The number of codes can change after Compact and GC.
- starts.Recompute(*entries);
- start = starts.at(group);
- end = starts.at(group + 1);
+ // Count could have changed, reload it.
+ count = entries->count();
}
-
- entries->ExtendGroup(group);
- entries->set_object_at(end, *object);
- entries->set_number_of_entries(group, end + 1 - start);
+ entries->set_object_at(count, *object);
+ entries->set_count(count + 1);
return entries;
}
+Handle<DependentCode> DependentCode::New(DependencyGroup group,
+ Handle<Object> object,
+ Handle<DependentCode> next) {
+ Isolate* isolate = next->GetIsolate();
+ Handle<DependentCode> result = Handle<DependentCode>::cast(
+ isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED));
+ result->set_next_link(*next);
+ result->set_flags(GroupField::encode(group) | CountField::encode(1));
+ result->set_object_at(0, *object);
+ return result;
+}
+
+
Handle<DependentCode> DependentCode::EnsureSpace(
Handle<DependentCode> entries) {
- Isolate* isolate = entries->GetIsolate();
- if (entries->length() == 0) {
- entries = Handle<DependentCode>::cast(
- isolate->factory()->NewFixedArray(kCodesStartIndex + 1, TENURED));
- for (int g = 0; g < kGroupCount; g++) {
- entries->set_number_of_entries(static_cast<DependencyGroup>(g), 0);
- }
- return entries;
- }
if (entries->Compact()) return entries;
- GroupStartIndexes starts(*entries);
- int capacity =
- kCodesStartIndex + DependentCode::Grow(starts.number_of_entries());
+ Isolate* isolate = entries->GetIsolate();
+ int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
int grow_by = capacity - entries->length();
return Handle<DependentCode>::cast(
isolate->factory()->CopyFixedArrayAndGrow(entries, grow_by, TENURED));
@@ -13725,46 +15242,47 @@ Handle<DependentCode> DependentCode::EnsureSpace(
bool DependentCode::Compact() {
- GroupStartIndexes starts(this);
- int n = 0;
- for (int g = 0; g < kGroupCount; g++) {
- int start = starts.at(g);
- int end = starts.at(g + 1);
- int count = 0;
- DCHECK(start >= n);
- for (int i = start; i < end; i++) {
- Object* obj = object_at(i);
- if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) {
- if (i != n + count) {
- copy(i, n + count);
- }
- count++;
+ int old_count = count();
+ int new_count = 0;
+ for (int i = 0; i < old_count; i++) {
+ Object* obj = object_at(i);
+ if (!obj->IsWeakCell() || !WeakCell::cast(obj)->cleared()) {
+ if (i != new_count) {
+ copy(i, new_count);
}
+ new_count++;
}
- if (count != end - start) {
- set_number_of_entries(static_cast<DependencyGroup>(g), count);
- }
- n += count;
}
- return n < starts.number_of_entries();
+ set_count(new_count);
+ for (int i = new_count; i < old_count; i++) {
+ clear_at(i);
+ }
+ return new_count < old_count;
}
void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
WeakCell* code_cell) {
+ if (this->length() == 0 || this->group() > group) {
+ // There is no such group.
+ return;
+ }
+ if (this->group() < group) {
+ // The group comes later in the list.
+ next_link()->UpdateToFinishedCode(group, info, code_cell);
+ return;
+ }
+ DCHECK_EQ(group, this->group());
DisallowHeapAllocation no_gc;
- GroupStartIndexes starts(this);
- int start = starts.at(group);
- int end = starts.at(group + 1);
- for (int i = start; i < end; i++) {
+ int count = this->count();
+ for (int i = 0; i < count; i++) {
if (object_at(i) == info) {
set_object_at(i, code_cell);
break;
}
}
-
#ifdef DEBUG
- for (int i = start; i < end; i++) {
+ for (int i = 0; i < count; i++) {
DCHECK(object_at(i) != info);
}
#endif
@@ -13773,34 +15291,36 @@ void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
void DependentCode::RemoveCompilationDependencies(
DependentCode::DependencyGroup group, Foreign* info) {
+ if (this->length() == 0 || this->group() > group) {
+ // There is no such group.
+ return;
+ }
+ if (this->group() < group) {
+ // The group comes later in the list.
+ next_link()->RemoveCompilationDependencies(group, info);
+ return;
+ }
+ DCHECK_EQ(group, this->group());
DisallowHeapAllocation no_allocation;
- GroupStartIndexes starts(this);
- int start = starts.at(group);
- int end = starts.at(group + 1);
+ int old_count = count();
// Find compilation info wrapper.
int info_pos = -1;
- for (int i = start; i < end; i++) {
+ for (int i = 0; i < old_count; i++) {
if (object_at(i) == info) {
info_pos = i;
break;
}
}
if (info_pos == -1) return; // Not found.
- int gap = info_pos;
- // Use the last of each group to fill the gap in the previous group.
- for (int i = group; i < kGroupCount; i++) {
- int last_of_group = starts.at(i + 1) - 1;
- DCHECK(last_of_group >= gap);
- if (last_of_group == gap) continue;
- copy(last_of_group, gap);
- gap = last_of_group;
- }
- DCHECK(gap == starts.number_of_entries() - 1);
- clear_at(gap); // Clear last gap.
- set_number_of_entries(group, end - start - 1);
+ // Use the last code to fill the gap.
+ if (info_pos < old_count - 1) {
+ copy(old_count - 1, info_pos);
+ }
+ clear_at(old_count - 1);
+ set_count(old_count - 1);
#ifdef DEBUG
- for (int i = start; i < end - 1; i++) {
+ for (int i = 0; i < old_count - 1; i++) {
DCHECK(object_at(i) != info);
}
#endif
@@ -13808,30 +15328,55 @@ void DependentCode::RemoveCompilationDependencies(
bool DependentCode::Contains(DependencyGroup group, WeakCell* code_cell) {
- GroupStartIndexes starts(this);
- int start = starts.at(group);
- int end = starts.at(group + 1);
- for (int i = start; i < end; i++) {
+ if (this->length() == 0 || this->group() > group) {
+ // There is no such group.
+ return false;
+ }
+ if (this->group() < group) {
+ // The group comes later in the list.
+ return next_link()->Contains(group, code_cell);
+ }
+ DCHECK_EQ(group, this->group());
+ int count = this->count();
+ for (int i = 0; i < count; i++) {
if (object_at(i) == code_cell) return true;
}
return false;
}
+bool DependentCode::IsEmpty(DependencyGroup group) {
+ if (this->length() == 0 || this->group() > group) {
+ // There is no such group.
+ return true;
+ }
+ if (this->group() < group) {
+ // The group comes later in the list.
+ return next_link()->IsEmpty(group);
+ }
+ DCHECK_EQ(group, this->group());
+ return count() == 0;
+}
+
+
bool DependentCode::MarkCodeForDeoptimization(
Isolate* isolate,
DependentCode::DependencyGroup group) {
+ if (this->length() == 0 || this->group() > group) {
+ // There is no such group.
+ return false;
+ }
+ if (this->group() < group) {
+ // The group comes later in the list.
+ return next_link()->MarkCodeForDeoptimization(isolate, group);
+ }
+ DCHECK_EQ(group, this->group());
DisallowHeapAllocation no_allocation_scope;
- DependentCode::GroupStartIndexes starts(this);
- int start = starts.at(group);
- int end = starts.at(group + 1);
- int code_entries = starts.number_of_entries();
- if (start == end) return false;
-
// Mark all the code that needs to be deoptimized.
bool marked = false;
bool invalidate_embedded_objects = group == kWeakCodeGroup;
- for (int i = start; i < end; i++) {
+ int count = this->count();
+ for (int i = 0; i < count; i++) {
Object* obj = object_at(i);
if (obj->IsWeakCell()) {
WeakCell* cell = WeakCell::cast(obj);
@@ -13852,16 +15397,10 @@ bool DependentCode::MarkCodeForDeoptimization(
info->Abort();
}
}
- // Compact the array by moving all subsequent groups to fill in the new holes.
- for (int src = end, dst = start; src < code_entries; src++, dst++) {
- copy(src, dst);
- }
- // Now the holes are at the end of the array, zap them for heap-verifier.
- int removed = end - start;
- for (int i = code_entries - removed; i < code_entries; i++) {
+ for (int i = 0; i < count; i++) {
clear_at(i);
}
- set_number_of_entries(group, 0);
+ set_count(0);
return marked;
}
@@ -13932,13 +15471,85 @@ Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
Maybe<bool> JSReceiver::SetPrototype(Handle<JSReceiver> object,
Handle<Object> value, bool from_javascript,
ShouldThrow should_throw) {
- if (!object->IsJSObject()) return Just(false);
- // TODO(neis): Deal with proxies.
+ if (object->IsJSProxy()) {
+ return JSProxy::SetPrototype(Handle<JSProxy>::cast(object), value,
+ from_javascript, should_throw);
+ }
return JSObject::SetPrototype(Handle<JSObject>::cast(object), value,
from_javascript, should_throw);
}
+// ES6: 9.5.2 [[SetPrototypeOf]] (V)
+// static
+Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
+ bool from_javascript,
+ ShouldThrow should_throw) {
+ Isolate* isolate = proxy->GetIsolate();
+ STACK_CHECK(Nothing<bool>());
+ Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
+ // 1. Assert: Either Type(V) is Object or Type(V) is Null.
+ DCHECK(value->IsJSReceiver() || value->IsNull());
+ // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
+ Handle<Object> handler(proxy->handler(), isolate);
+ // 3. If handler is null, throw a TypeError exception.
+ // 4. Assert: Type(handler) is Object.
+ if (proxy->IsRevoked()) {
+ isolate->Throw(*isolate->factory()->NewTypeError(
+ MessageTemplate::kProxyRevoked, trap_name));
+ return Nothing<bool>();
+ }
+ // 5. Let target be the value of the [[ProxyTarget]] internal slot.
+ Handle<JSReceiver> target(proxy->target(), isolate);
+ // 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
+ Handle<Object> trap;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap,
+ Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
+ Nothing<bool>());
+ // 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
+ if (trap->IsUndefined()) {
+ return JSReceiver::SetPrototype(target, value, from_javascript,
+ should_throw);
+ }
+ // 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, V»)).
+ Handle<Object> argv[] = {target, value};
+ Handle<Object> trap_result;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, trap_result,
+ Execution::Call(isolate, trap, handler, arraysize(argv), argv),
+ Nothing<bool>());
+ bool bool_trap_result = trap_result->BooleanValue();
+ // 9. 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.
+ 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]]().
+ Handle<Object> target_proto;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_proto,
+ Object::GetPrototype(isolate, target),
+ Nothing<bool>());
+ // 12. If booleanTrapResult is true and 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));
+}
+
+
Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
Handle<Object> value, bool from_javascript,
ShouldThrow should_throw) {
@@ -13947,7 +15558,9 @@ Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
const bool observed = from_javascript && object->map()->is_observed();
Handle<Object> old_value;
if (observed) {
- old_value = Object::GetPrototype(isolate, object);
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, old_value,
+ Object::GetPrototype(isolate, object),
+ Nothing<bool>());
}
Maybe<bool> result =
@@ -13955,7 +15568,10 @@ Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
MAYBE_RETURN(result, Nothing<bool>());
if (result.FromJust() && observed) {
- Handle<Object> new_value = Object::GetPrototype(isolate, object);
+ Handle<Object> new_value;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, new_value,
+ Object::GetPrototype(isolate, object),
+ Nothing<bool>());
if (!new_value->SameValue(*old_value)) {
RETURN_ON_EXCEPTION_VALUE(
isolate, JSObject::EnqueueChangeRecord(
@@ -13984,7 +15600,8 @@ Maybe<bool> JSObject::SetPrototypeUnobserved(Handle<JSObject> object,
!isolate->MayAccess(handle(isolate->context()), object)) {
isolate->ReportFailedAccessCheck(object);
RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
- UNREACHABLE();
+ RETURN_FAILURE(isolate, should_throw,
+ NewTypeError(MessageTemplate::kNoAccess));
}
} else {
DCHECK(!object->IsAccessCheckNeeded());
@@ -14064,7 +15681,7 @@ Maybe<bool> JSObject::SetPrototypeUnobserved(Handle<JSObject> object,
// If the prototype chain didn't previously have element callbacks, then
// KeyedStoreICs need to be cleared to ensure any that involve this
// map go generic.
- object->GetHeap()->ClearAllKeyedStoreICs();
+ TypeFeedbackVector::ClearAllKeyedStoreICs(isolate);
}
heap->ClearInstanceofCache();
@@ -14513,8 +16130,8 @@ int JSObject::GetFastElementsUsage() {
case FAST_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_ELEMENTS:
- // Only JSArray have packed elements.
- return Smi::cast(JSArray::cast(this)->length())->value();
+ return IsJSArray() ? Smi::cast(JSArray::cast(this)->length())->value()
+ : store->length();
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
store = FixedArray::cast(FixedArray::cast(store)->get(1));
// Fall through.
@@ -14589,16 +16206,6 @@ InterceptorInfo* JSObject::GetNamedInterceptor() {
}
-InterceptorInfo* JSObject::GetIndexedInterceptor() {
- DCHECK(map()->has_indexed_interceptor());
- JSFunction* constructor = JSFunction::cast(map()->GetConstructor());
- DCHECK(constructor->shared()->IsApiFunction());
- Object* result =
- constructor->shared()->get_api_func_data()->indexed_property_handler();
- return InterceptorInfo::cast(result);
-}
-
-
MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
bool* done) {
*done = false;
@@ -14627,6 +16234,7 @@ MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
result = args.Call(getter, index);
} else {
Handle<Name> name = it->name();
+ DCHECK(!name->IsPrivate());
if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
return isolate->factory()->undefined_value();
@@ -14650,52 +16258,6 @@ MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
}
-// Compute the property keys from the interceptor.
-MaybeHandle<JSObject> JSObject::GetKeysForNamedInterceptor(
- Handle<JSObject> object, Handle<JSReceiver> receiver) {
- Isolate* isolate = receiver->GetIsolate();
- Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
- PropertyCallbackArguments
- args(isolate, interceptor->data(), *receiver, *object);
- v8::Local<v8::Object> result;
- if (!interceptor->enumerator()->IsUndefined()) {
- v8::GenericNamedPropertyEnumeratorCallback enum_fun =
- v8::ToCData<v8::GenericNamedPropertyEnumeratorCallback>(
- interceptor->enumerator());
- LOG(isolate, ApiObjectAccess("interceptor-named-enum", *object));
- result = args.Call(enum_fun);
- }
- if (result.IsEmpty()) return MaybeHandle<JSObject>();
- DCHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
- v8::Utils::OpenHandle(*result)->HasSloppyArgumentsElements());
- // Rebox before returning.
- return handle(*v8::Utils::OpenHandle(*result), isolate);
-}
-
-
-// Compute the element keys from the interceptor.
-MaybeHandle<JSObject> JSObject::GetKeysForIndexedInterceptor(
- Handle<JSObject> object, Handle<JSReceiver> receiver) {
- Isolate* isolate = receiver->GetIsolate();
- Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
- PropertyCallbackArguments
- args(isolate, interceptor->data(), *receiver, *object);
- v8::Local<v8::Object> result;
- if (!interceptor->enumerator()->IsUndefined()) {
- v8::IndexedPropertyEnumeratorCallback enum_fun =
- v8::ToCData<v8::IndexedPropertyEnumeratorCallback>(
- interceptor->enumerator());
- LOG(isolate, ApiObjectAccess("interceptor-indexed-enum", *object));
- result = args.Call(enum_fun);
- }
- if (result.IsEmpty()) return MaybeHandle<JSObject>();
- DCHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
- v8::Utils::OpenHandle(*result)->HasSloppyArgumentsElements());
- // Rebox before returning.
- return handle(*v8::Utils::OpenHandle(*result), isolate);
-}
-
-
Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
Handle<Name> name) {
LookupIterator it = LookupIterator::PropertyOrElement(
@@ -14723,25 +16285,6 @@ Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
}
-int JSObject::NumberOfOwnProperties(PropertyAttributes filter) {
- if (HasFastProperties()) {
- Map* map = this->map();
- if (filter == NONE) return map->NumberOfOwnDescriptors();
- if (filter == DONT_SHOW) {
- // The cached enum length was computed with filter == DONT_SHOW, so
- // that's the only filter for which it's valid to retrieve it.
- int result = map->EnumLength();
- if (result != kInvalidEnumCacheSentinel) return result;
- }
- return map->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter);
- } else if (IsJSGlobalObject()) {
- return global_dictionary()->NumberOfElementsFilterAttributes(filter);
- } else {
- return property_dictionary()->NumberOfElementsFilterAttributes(filter);
- }
-}
-
-
void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
Object* temp = get(i);
set(i, get(j));
@@ -14855,55 +16398,33 @@ void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
}
-// Fill in the names of own properties into the supplied storage. The main
-// purpose of this function is to provide reflection information for the object
-// mirrors.
-int JSObject::GetOwnPropertyNames(FixedArray* storage, int index,
- PropertyAttributes filter) {
- DCHECK(storage->length() >= (NumberOfOwnProperties(filter) - index));
+void JSObject::CollectOwnPropertyNames(KeyAccumulator* keys,
+ PropertyFilter filter) {
if (HasFastProperties()) {
- int start_index = index;
- int real_size = map()->NumberOfOwnDescriptors();
- DescriptorArray* descs = map()->instance_descriptors();
- for (int i = 0; i < real_size; i++) {
- if ((descs->GetDetails(i).attributes() & filter) == 0 &&
- !descs->GetKey(i)->FilterKey(filter)) {
- storage->set(index++, descs->GetKey(i));
- }
- }
- return index - start_index;
- } else if (IsJSGlobalObject()) {
- return global_dictionary()->CopyKeysTo(storage, index, filter,
- GlobalDictionary::UNSORTED);
- } else {
- return property_dictionary()->CopyKeysTo(storage, index, filter,
- NameDictionary::UNSORTED);
- }
-}
-
-
-int JSObject::CollectOwnPropertyNames(KeyAccumulator* keys,
- PropertyAttributes filter) {
- if (HasFastProperties()) {
- int nof_keys = keys->length();
int real_size = map()->NumberOfOwnDescriptors();
Handle<DescriptorArray> descs(map()->instance_descriptors());
for (int i = 0; i < real_size; i++) {
- if ((descs->GetDetails(i).attributes() & filter) != 0) continue;
+ PropertyDetails details = descs->GetDetails(i);
+ if ((details.attributes() & filter) != 0) continue;
+ if (filter & ONLY_ALL_CAN_READ) {
+ if (details.kind() != kAccessor) continue;
+ Object* accessors = descs->GetValue(i);
+ if (!accessors->IsAccessorInfo()) continue;
+ if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
+ }
Name* key = descs->GetKey(i);
if (key->FilterKey(filter)) continue;
keys->AddKey(key);
}
- return nof_keys - keys->length();
} else if (IsJSGlobalObject()) {
- return global_dictionary()->CollectKeysTo(keys, filter);
+ GlobalDictionary::CollectKeysTo(handle(global_dictionary()), keys, filter);
} else {
- return property_dictionary()->CollectKeysTo(keys, filter);
+ NameDictionary::CollectKeysTo(handle(property_dictionary()), keys, filter);
}
}
-int JSObject::NumberOfOwnElements(PropertyAttributes filter) {
+int JSObject::NumberOfOwnElements(PropertyFilter filter) {
// Fast case for objects with no elements.
if (!IsJSValue() && HasFastElements()) {
uint32_t length =
@@ -14918,14 +16439,10 @@ int JSObject::NumberOfOwnElements(PropertyAttributes filter) {
}
-int JSObject::NumberOfEnumElements() {
- return NumberOfOwnElements(static_cast<PropertyAttributes>(DONT_ENUM));
-}
-
-
void JSObject::CollectOwnElementKeys(Handle<JSObject> object,
KeyAccumulator* keys,
- PropertyAttributes filter) {
+ PropertyFilter filter) {
+ if (filter & SKIP_STRINGS) return;
uint32_t string_keys = 0;
// If this is a String wrapper, add the string indices first,
@@ -14933,7 +16450,7 @@ void JSObject::CollectOwnElementKeys(Handle<JSObject> object,
// and ascending order is required by ECMA-262, 6th, 9.1.12.
if (object->IsJSValue()) {
Object* val = JSValue::cast(*object)->value();
- if (val->IsString()) {
+ 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++) {
@@ -14946,8 +16463,7 @@ void JSObject::CollectOwnElementKeys(Handle<JSObject> object,
}
-int JSObject::GetOwnElementKeys(FixedArray* storage,
- PropertyAttributes filter) {
+int JSObject::GetOwnElementKeys(FixedArray* storage, PropertyFilter filter) {
int counter = 0;
// If this is a String wrapper, add the string indices first,
@@ -15076,6 +16592,39 @@ int JSObject::GetOwnElementKeys(FixedArray* storage,
}
+MaybeHandle<String> Object::ObjectProtoToString(Isolate* isolate,
+ Handle<Object> object) {
+ 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<String> tag;
+ if (FLAG_harmony_tostring) {
+ Handle<Object> to_string_tag;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, to_string_tag,
+ GetProperty(receiver, isolate->factory()->to_string_tag_symbol()),
+ String);
+ if (to_string_tag->IsString()) {
+ tag = Handle<String>::cast(to_string_tag);
+ }
+ }
+
+ if (tag.is_null()) {
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, tag,
+ JSReceiver::BuiltinStringTag(receiver), String);
+ }
+
+ IncrementalStringBuilder builder(isolate);
+ builder.AppendCString("[object ");
+ builder.AppendString(tag);
+ builder.AppendCharacter(']');
+ return builder.Finish();
+}
+
+
const char* Symbol::PrivateSymbolToName() const {
Heap* heap = GetIsolate()->heap();
#define SYMBOL_CHECK_AND_PRINT(name) \
@@ -15191,12 +16740,197 @@ class StringSharedKey : public HashTableKey {
};
+namespace {
+
+JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) {
+ JSRegExp::Flags value = JSRegExp::kNone;
+ int length = flags->length();
+ // A longer flags string cannot be valid.
+ if (length > 5) return JSRegExp::Flags(0);
+ for (int i = 0; i < length; i++) {
+ JSRegExp::Flag flag = JSRegExp::kNone;
+ switch (flags->Get(i)) {
+ case 'g':
+ flag = JSRegExp::kGlobal;
+ break;
+ case 'i':
+ flag = JSRegExp::kIgnoreCase;
+ break;
+ case 'm':
+ flag = JSRegExp::kMultiline;
+ break;
+ case 'u':
+ if (!FLAG_harmony_unicode_regexps) return JSRegExp::Flags(0);
+ flag = JSRegExp::kUnicode;
+ break;
+ case 'y':
+ if (!FLAG_harmony_regexps) return JSRegExp::Flags(0);
+ flag = JSRegExp::kSticky;
+ break;
+ default:
+ return JSRegExp::Flags(0);
+ }
+ // Duplicate flag.
+ if (value & flag) return JSRegExp::Flags(0);
+ value |= flag;
+ }
+ *success = true;
+ return value;
+}
+
+} // namespace
+
+
+// static
+MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, Flags flags) {
+ Isolate* isolate = pattern->GetIsolate();
+ Handle<JSFunction> constructor = isolate->regexp_function();
+ Handle<JSRegExp> regexp =
+ Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor));
+
+ return JSRegExp::Initialize(regexp, pattern, flags);
+}
+
+
+// static
+MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern,
+ Handle<String> flags_string) {
+ Isolate* isolate = pattern->GetIsolate();
+ bool success = false;
+ Flags flags = RegExpFlagsFromString(flags_string, &success);
+ if (!success) {
+ THROW_NEW_ERROR(
+ isolate,
+ NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
+ JSRegExp);
+ }
+ return New(pattern, flags);
+}
+
+
+// static
+Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
+ Isolate* const isolate = regexp->GetIsolate();
+ return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
+}
+
+
+template <typename Char>
+inline int CountRequiredEscapes(Handle<String> source) {
+ DisallowHeapAllocation no_gc;
+ int escapes = 0;
+ Vector<const Char> src = source->GetCharVector<Char>();
+ for (int i = 0; i < src.length(); i++) {
+ if (src[i] == '/' && (i == 0 || src[i - 1] != '\\')) escapes++;
+ }
+ return escapes;
+}
+
+
+template <typename Char, typename StringType>
+inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
+ Handle<StringType> result) {
+ DisallowHeapAllocation no_gc;
+ Vector<const Char> src = source->GetCharVector<Char>();
+ Vector<Char> dst(result->GetChars(), result->length());
+ int s = 0;
+ int d = 0;
+ while (s < src.length()) {
+ if (src[s] == '/' && (s == 0 || src[s - 1] != '\\')) dst[d++] = '\\';
+ dst[d++] = src[s++];
+ }
+ DCHECK_EQ(result->length(), d);
+ return result;
+}
+
+
+MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
+ Handle<String> source) {
+ String::Flatten(source);
+ if (source->length() == 0) return isolate->factory()->query_colon_string();
+ bool one_byte = source->IsOneByteRepresentationUnderneath();
+ int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
+ : CountRequiredEscapes<uc16>(source);
+ if (escapes == 0) return source;
+ int length = source->length() + escapes;
+ if (one_byte) {
+ Handle<SeqOneByteString> result;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
+ isolate->factory()->NewRawOneByteString(length),
+ String);
+ return WriteEscapedRegExpSource<uint8_t>(source, result);
+ } else {
+ Handle<SeqTwoByteString> result;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
+ isolate->factory()->NewRawTwoByteString(length),
+ String);
+ return WriteEscapedRegExpSource<uc16>(source, result);
+ }
+}
+
+
+// static
+MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
+ Handle<String> source,
+ Handle<String> flags_string) {
+ Isolate* isolate = source->GetIsolate();
+ bool success = false;
+ Flags flags = RegExpFlagsFromString(flags_string, &success);
+ if (!success) {
+ THROW_NEW_ERROR(
+ isolate,
+ NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string),
+ JSRegExp);
+ }
+ return Initialize(regexp, source, flags);
+}
+
+
+// static
+MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
+ Handle<String> source, Flags flags) {
+ Isolate* isolate = regexp->GetIsolate();
+ Factory* factory = isolate->factory();
+ // If source is the empty string we set it to "(?:)" instead as
+ // suggested by ECMA-262, 5th, section 15.10.4.1.
+ if (source->length() == 0) source = factory->query_colon_string();
+
+ Handle<String> escaped_source;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
+ EscapeRegExpSource(isolate, source), JSRegExp);
+
+ regexp->set_source(*escaped_source);
+ regexp->set_flags(Smi::FromInt(flags));
+
+ Map* map = regexp->map();
+ Object* constructor = map->GetConstructor();
+ if (constructor->IsJSFunction() &&
+ JSFunction::cast(constructor)->initial_map() == map) {
+ // If we still have the original map, set in-object properties directly.
+ regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
+ Smi::FromInt(0), SKIP_WRITE_BARRIER);
+ } else {
+ // Map has changed, so use generic, but slower, method.
+ PropertyAttributes writable =
+ static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
+ JSObject::SetOwnPropertyIgnoreAttributes(
+ regexp, factory->last_index_string(),
+ Handle<Smi>(Smi::FromInt(0), isolate), writable)
+ .Check();
+ }
+
+ RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags),
+ JSRegExp);
+
+ return regexp;
+}
+
+
// RegExpKey carries the source and flags of a regular expression as key.
class RegExpKey : public HashTableKey {
public:
RegExpKey(Handle<String> string, JSRegExp::Flags flags)
- : string_(string),
- flags_(Smi::FromInt(flags.value())) { }
+ : string_(string), flags_(Smi::FromInt(flags)) {}
// Rather than storing the key in the hash table, a pointer to the
// stored value is stored where the key should be. IsMatch then
@@ -15298,15 +17032,14 @@ class InternalizedStringKey : public HashTableKey {
template<typename Derived, typename Shape, typename Key>
void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) {
- IteratePointers(v, 0, kElementsStartOffset);
+ BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v);
}
template<typename Derived, typename Shape, typename Key>
void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) {
- IteratePointers(v,
- kElementsStartOffset,
- kHeaderSize + length() * kPointerSize);
+ BodyDescriptorBase::IteratePointers(this, kElementsStartOffset,
+ kHeaderSize + length() * kPointerSize, v);
}
@@ -15493,14 +17226,8 @@ Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity(
Isolate* isolate = table->GetIsolate();
int capacity = table->Capacity();
int nof = table->NumberOfElements() + n;
- int nod = table->NumberOfDeletedElements();
- // Return if:
- // 50% is still free after adding n elements and
- // at most 50% of the free elements are deleted elements.
- if (nod <= (capacity - nof) >> 1) {
- int needed_free = nof >> 1;
- if (nof + needed_free <= capacity) return table;
- }
+
+ if (table->HasSufficientCapacity(n)) return table;
const int kMinCapacityForPretenure = 256;
bool should_pretenure = pretenure == TENURED ||
@@ -15517,6 +17244,22 @@ Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity(
}
+template <typename Derived, typename Shape, typename Key>
+bool HashTable<Derived, Shape, Key>::HasSufficientCapacity(int n) {
+ int capacity = Capacity();
+ int nof = NumberOfElements() + n;
+ int nod = NumberOfDeletedElements();
+ // Return true if:
+ // 50% is still free after adding n elements and
+ // at most 50% of the free elements are deleted elements.
+ if (nod <= (capacity - nof) >> 1) {
+ int needed_free = nof >> 1;
+ if (nof + needed_free <= capacity) return true;
+ }
+ return false;
+}
+
+
template<typename Derived, typename Shape, typename Key>
Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table,
Key key) {
@@ -15683,6 +17426,9 @@ template Handle<UnseededNumberDictionary>
Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t);
+template void Dictionary<NameDictionary, NameDictionaryShape,
+ Handle<Name> >::SetRequiresCopyOnCapacityChange();
+
template Handle<NameDictionary>
Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>);
@@ -16411,7 +18157,17 @@ Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
}
-template<typename Derived, typename Shape, typename Key>
+template <typename Derived, typename Shape, typename Key>
+void Dictionary<Derived, Shape, Key>::SetRequiresCopyOnCapacityChange() {
+ DCHECK_EQ(0, DerivedHashTable::NumberOfElements());
+ DCHECK_EQ(0, DerivedHashTable::NumberOfDeletedElements());
+ // Make sure that HashTable::EnsureCapacity will create a copy.
+ DerivedHashTable::SetNumberOfDeletedElements(DerivedHashTable::Capacity());
+ DCHECK(!DerivedHashTable::HasSufficientCapacity(1));
+}
+
+
+template <typename Derived, typename Shape, typename Key>
Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity(
Handle<Derived> dictionary, int n, Key key) {
// Check whether there are enough enumeration indices to add n elements.
@@ -16515,7 +18271,7 @@ void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key,
if (key > kRequiresSlowElementsLimit) {
if (used_as_prototype) {
// TODO(verwaest): Remove this hack.
- GetHeap()->ClearAllKeyedStoreICs();
+ TypeFeedbackVector::ClearAllKeyedStoreICs(GetIsolate());
}
set_requires_slow_elements();
return;
@@ -16594,7 +18350,7 @@ Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
template <typename Derived, typename Shape, typename Key>
int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
- PropertyAttributes filter) {
+ PropertyFilter filter) {
int capacity = this->Capacity();
int result = 0;
for (int i = 0; i < capacity; i++) {
@@ -16615,12 +18371,12 @@ bool Dictionary<Derived, Shape, Key>::HasComplexElements() {
int capacity = this->Capacity();
for (int i = 0; i < capacity; i++) {
Object* k = this->KeyAt(i);
- if (this->IsKey(k) && !k->FilterKey(NONE)) {
+ if (this->IsKey(k) && !k->FilterKey(ALL_PROPERTIES)) {
if (this->IsDeleted(i)) continue;
PropertyDetails details = this->DetailsAt(i);
if (details.type() == ACCESSOR_CONSTANT) return true;
PropertyAttributes attr = details.attributes();
- if (attr & (READ_ONLY | DONT_DELETE | DONT_ENUM)) return true;
+ if (attr & ALL_ATTRIBUTES_MASK) return true;
}
}
return false;
@@ -16667,7 +18423,7 @@ void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(FixedArray* storage) {
template <typename Derived, typename Shape, typename Key>
int Dictionary<Derived, Shape, Key>::CopyKeysTo(
- FixedArray* storage, int index, PropertyAttributes filter,
+ FixedArray* storage, int index, PropertyFilter filter,
typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
int start_index = index;
@@ -16690,20 +18446,44 @@ int Dictionary<Derived, Shape, Key>::CopyKeysTo(
template <typename Derived, typename Shape, typename Key>
-int Dictionary<Derived, Shape, Key>::CollectKeysTo(KeyAccumulator* keys,
- PropertyAttributes filter) {
- int capacity = this->Capacity();
- int keyLength = keys->length();
- for (int i = 0; i < capacity; i++) {
- Object* k = this->KeyAt(i);
- if (!this->IsKey(k) || k->FilterKey(filter)) continue;
- if (this->IsDeleted(i)) continue;
- PropertyDetails details = this->DetailsAt(i);
- PropertyAttributes attr = details.attributes();
- if ((attr & filter) != 0) continue;
- keys->AddKey(k);
+void Dictionary<Derived, Shape, Key>::CollectKeysTo(
+ Handle<Dictionary<Derived, Shape, Key> > dictionary, KeyAccumulator* keys,
+ PropertyFilter filter) {
+ int capacity = dictionary->Capacity();
+ Handle<FixedArray> array =
+ keys->isolate()->factory()->NewFixedArray(dictionary->NumberOfElements());
+ int array_size = 0;
+
+ {
+ DisallowHeapAllocation no_gc;
+ Dictionary<Derived, Shape, Key>* raw_dict = *dictionary;
+ for (int i = 0; i < capacity; i++) {
+ Object* k = raw_dict->KeyAt(i);
+ if (!raw_dict->IsKey(k) || k->FilterKey(filter)) continue;
+ if (raw_dict->IsDeleted(i)) continue;
+ PropertyDetails details = raw_dict->DetailsAt(i);
+ if ((details.attributes() & filter) != 0) continue;
+ if (filter & ONLY_ALL_CAN_READ) {
+ if (details.kind() != kAccessor) continue;
+ Object* accessors = raw_dict->ValueAt(i);
+ if (accessors->IsPropertyCell()) {
+ accessors = PropertyCell::cast(accessors)->value();
+ }
+ if (!accessors->IsAccessorInfo()) continue;
+ if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
+ }
+ array->set(array_size++, Smi::FromInt(i));
+ }
+
+ EnumIndexComparator<Derived> cmp(static_cast<Derived*>(raw_dict));
+ Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress());
+ std::sort(start, start + array_size, cmp);
+ }
+
+ for (int i = 0; i < array_size; i++) {
+ int index = Smi::cast(array->get(i))->value();
+ keys->AddKey(dictionary->KeyAt(index));
}
- return keyLength - keys->length();
}
@@ -17510,6 +19290,39 @@ int BreakPointInfo::GetBreakPointCount() {
}
+// static
+MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
+ Handle<JSReceiver> new_target, double tv) {
+ Isolate* const isolate = constructor->GetIsolate();
+ Handle<JSObject> result;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
+ JSObject::New(constructor, new_target), JSDate);
+ if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
+ tv = DoubleToInteger(tv) + 0.0;
+ } else {
+ tv = std::numeric_limits<double>::quiet_NaN();
+ }
+ Handle<Object> value = isolate->factory()->NewNumber(tv);
+ Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
+ return Handle<JSDate>::cast(result);
+}
+
+
+// static
+double JSDate::CurrentTimeValue(Isolate* isolate) {
+ if (FLAG_log_timer_events || FLAG_prof_cpp) LOG(isolate, CurrentTimeEvent());
+
+ // According to ECMA-262, section 15.9.1, page 117, the precision of
+ // the number in a Date object representing a particular instant in
+ // time is milliseconds. Therefore, we floor the result of getting
+ // the OS time.
+ return Floor(FLAG_verify_predictable
+ ? isolate->heap()->MonotonicallyIncreasingTimeInMs()
+ : base::OS::TimeCurrentMillis());
+}
+
+
+// static
Object* JSDate::GetField(Object* object, Smi* index) {
return JSDate::cast(object)->DoGetField(
static_cast<FieldIndex>(index->value()));
@@ -17602,6 +19415,16 @@ Object* JSDate::GetUTCField(FieldIndex index,
}
+// static
+Handle<Object> JSDate::SetValue(Handle<JSDate> date, double v) {
+ Isolate* const isolate = date->GetIsolate();
+ Handle<Object> value = isolate->factory()->NewNumber(v);
+ bool value_is_nan = std::isnan(v);
+ date->SetValue(*value, value_is_nan);
+ return value;
+}
+
+
void JSDate::SetValue(Object* value, bool is_value_nan) {
set_value(value);
if (is_value_nan) {