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.cc5231
1 files changed, 2299 insertions, 2932 deletions
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc
index 51993f3f32..00721c2d1b 100644
--- a/deps/v8/src/objects.cc
+++ b/deps/v8/src/objects.cc
@@ -6,15 +6,16 @@
#include <cmath>
#include <iomanip>
+#include <memory>
#include <sstream>
#include "src/objects-inl.h"
#include "src/accessors.h"
#include "src/allocation-site-scopes.h"
-#include "src/api.h"
-#include "src/api-arguments.h"
+#include "src/api-arguments-inl.h"
#include "src/api-natives.h"
+#include "src/api.h"
#include "src/base/bits.h"
#include "src/base/utils/random-number-generator.h"
#include "src/bootstrapper.h"
@@ -22,6 +23,8 @@
#include "src/codegen.h"
#include "src/compilation-dependencies.h"
#include "src/compiler.h"
+#include "src/counters-inl.h"
+#include "src/counters.h"
#include "src/date.h"
#include "src/debug/debug.h"
#include "src/deoptimizer.h"
@@ -30,12 +33,14 @@
#include "src/field-index-inl.h"
#include "src/field-index.h"
#include "src/field-type.h"
+#include "src/frames-inl.h"
#include "src/full-codegen/full-codegen.h"
+#include "src/globals.h"
#include "src/ic/ic.h"
#include "src/identity-map.h"
#include "src/interpreter/bytecode-array-iterator.h"
+#include "src/interpreter/bytecode-decoder.h"
#include "src/interpreter/interpreter.h"
-#include "src/interpreter/source-position-table.h"
#include "src/isolate-inl.h"
#include "src/keys.h"
#include "src/list.h"
@@ -44,20 +49,23 @@
#include "src/macro-assembler.h"
#include "src/messages.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/snapshot/code-serializer.h"
+#include "src/source-position-table.h"
#include "src/string-builder.h"
#include "src/string-search.h"
#include "src/string-stream.h"
#include "src/utils.h"
+#include "src/wasm/wasm-module.h"
#include "src/zone.h"
#ifdef ENABLE_DISASSEMBLER
#include "src/disasm.h"
#include "src/disassembler.h"
+#include "src/eh-frame.h"
#endif
namespace v8 {
@@ -121,8 +129,8 @@ MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate,
Handle<Object> object) {
if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
if (*object == isolate->heap()->null_value() ||
- *object == isolate->heap()->undefined_value()) {
- return handle(isolate->global_proxy(), isolate);
+ object->IsUndefined(isolate)) {
+ return isolate->global_proxy();
}
return Object::ToObject(isolate, object);
}
@@ -213,6 +221,155 @@ MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) {
}
}
+namespace {
+
+bool IsErrorObject(Isolate* isolate, Handle<Object> object) {
+ if (!object->IsJSReceiver()) return false;
+ Handle<Symbol> symbol = isolate->factory()->stack_trace_symbol();
+ return JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), symbol)
+ .FromMaybe(false);
+}
+
+Handle<String> AsStringOrEmpty(Isolate* isolate, Handle<Object> object) {
+ return object->IsString() ? Handle<String>::cast(object)
+ : isolate->factory()->empty_string();
+}
+
+Handle<String> NoSideEffectsErrorToString(Isolate* isolate,
+ Handle<Object> input) {
+ Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
+
+ Handle<Name> name_key = isolate->factory()->name_string();
+ Handle<Object> name = JSReceiver::GetDataProperty(receiver, name_key);
+ Handle<String> name_str = AsStringOrEmpty(isolate, name);
+
+ Handle<Name> msg_key = isolate->factory()->message_string();
+ Handle<Object> msg = JSReceiver::GetDataProperty(receiver, msg_key);
+ Handle<String> msg_str = AsStringOrEmpty(isolate, msg);
+
+ if (name_str->length() == 0) return msg_str;
+ if (msg_str->length() == 0) return name_str;
+
+ IncrementalStringBuilder builder(isolate);
+ builder.AppendString(name_str);
+ builder.AppendCString(": ");
+ builder.AppendString(msg_str);
+
+ return builder.Finish().ToHandleChecked();
+}
+
+} // namespace
+
+// static
+Handle<String> Object::NoSideEffectsToString(Isolate* isolate,
+ Handle<Object> input) {
+ DisallowJavascriptExecution no_js(isolate);
+
+ if (input->IsString() || input->IsNumber() || input->IsOddball() ||
+ input->IsSimd128Value()) {
+ return Object::ToString(isolate, input).ToHandleChecked();
+ } else if (input->IsFunction()) {
+ // -- F u n c t i o n
+ Handle<String> fun_str;
+ if (input->IsJSBoundFunction()) {
+ fun_str = JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(input));
+ } else {
+ DCHECK(input->IsJSFunction());
+ fun_str = JSFunction::ToString(Handle<JSFunction>::cast(input));
+ }
+
+ if (fun_str->length() > 128) {
+ IncrementalStringBuilder builder(isolate);
+ builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111));
+ builder.AppendCString("...<omitted>...");
+ builder.AppendString(isolate->factory()->NewSubString(
+ fun_str, fun_str->length() - 2, fun_str->length()));
+
+ return builder.Finish().ToHandleChecked();
+ }
+ return fun_str;
+ } else if (input->IsSymbol()) {
+ // -- S y m b o l
+ Handle<Symbol> symbol = Handle<Symbol>::cast(input);
+
+ IncrementalStringBuilder builder(isolate);
+ builder.AppendCString("Symbol(");
+ if (symbol->name()->IsString()) {
+ builder.AppendString(handle(String::cast(symbol->name()), isolate));
+ }
+ builder.AppendCharacter(')');
+
+ return builder.Finish().ToHandleChecked();
+ } else if (input->IsJSReceiver()) {
+ // -- J S R e c e i v e r
+ Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(input);
+ Handle<Object> to_string = JSReceiver::GetDataProperty(
+ receiver, isolate->factory()->toString_string());
+
+ if (IsErrorObject(isolate, input) ||
+ *to_string == *isolate->error_to_string()) {
+ // When internally formatting error objects, use a side-effects-free
+ // version of Error.prototype.toString independent of the actually
+ // installed toString method.
+ return NoSideEffectsErrorToString(isolate, input);
+ } else if (*to_string == *isolate->object_to_string()) {
+ Handle<Object> ctor = JSReceiver::GetDataProperty(
+ receiver, isolate->factory()->constructor_string());
+ if (ctor->IsFunction()) {
+ Handle<String> ctor_name;
+ if (ctor->IsJSBoundFunction()) {
+ ctor_name = JSBoundFunction::GetName(
+ isolate, Handle<JSBoundFunction>::cast(ctor))
+ .ToHandleChecked();
+ } else if (ctor->IsJSFunction()) {
+ Handle<Object> ctor_name_obj =
+ JSFunction::GetName(isolate, Handle<JSFunction>::cast(ctor));
+ ctor_name = AsStringOrEmpty(isolate, ctor_name_obj);
+ }
+
+ if (ctor_name->length() != 0) {
+ IncrementalStringBuilder builder(isolate);
+ builder.AppendCString("#<");
+ builder.AppendString(ctor_name);
+ builder.AppendCString(">");
+
+ return builder.Finish().ToHandleChecked();
+ }
+ }
+ }
+ }
+
+ // At this point, input is either none of the above or a JSReceiver.
+
+ Handle<JSReceiver> receiver;
+ if (input->IsJSReceiver()) {
+ receiver = Handle<JSReceiver>::cast(input);
+ } else {
+ // This is the only case where Object::ToObject throws.
+ DCHECK(!input->IsSmi());
+ int constructor_function_index =
+ Handle<HeapObject>::cast(input)->map()->GetConstructorFunctionIndex();
+ if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
+ return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]");
+ }
+
+ receiver = Object::ToObject(isolate, input, isolate->native_context())
+ .ToHandleChecked();
+ }
+
+ Handle<String> builtin_tag = handle(receiver->class_name(), isolate);
+ Handle<Object> tag_obj = JSReceiver::GetDataProperty(
+ receiver, isolate->factory()->to_string_tag_symbol());
+ Handle<String> tag =
+ tag_obj->IsString() ? Handle<String>::cast(tag_obj) : builtin_tag;
+
+ IncrementalStringBuilder builder(isolate);
+ builder.AppendCString("[object ");
+ builder.AppendString(tag);
+ builder.AppendCString("]");
+
+ return builder.Finish().ToHandleChecked();
+}
// static
MaybeHandle<Object> Object::ToLength(Isolate* isolate, Handle<Object> input) {
@@ -226,11 +383,25 @@ MaybeHandle<Object> Object::ToLength(Isolate* isolate, Handle<Object> input) {
return isolate->factory()->NewNumber(len);
}
+// static
+MaybeHandle<Object> Object::ToIndex(Isolate* isolate, Handle<Object> input,
+ MessageTemplate::Template error_index) {
+ if (input->IsUndefined(isolate)) return isolate->factory()->NewNumber(0.0);
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object);
+ double len = DoubleToInteger(input->Number()) + 0.0;
+ auto js_len = isolate->factory()->NewNumber(len);
+ if (len < 0.0 || len > kMaxSafeInteger) {
+ THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object);
+ }
+ return js_len;
+}
bool Object::BooleanValue() {
- if (IsBoolean()) return IsTrue();
if (IsSmi()) return Smi::cast(this)->value() != 0;
- if (IsUndefined() || IsNull()) return false;
+ DCHECK(IsHeapObject());
+ Isolate* isolate = HeapObject::cast(this)->GetIsolate();
+ if (IsBoolean()) return IsTrue(isolate);
+ if (IsUndefined(isolate) || IsNull(isolate)) return false;
if (IsUndetectable()) return false; // Undetectable object is false.
if (IsString()) return String::cast(this)->length() != 0;
if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
@@ -568,6 +739,86 @@ MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs,
NumberToInt32(*rhs));
}
+// static
+MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate,
+ Handle<Object> callable,
+ Handle<Object> object) {
+ // The {callable} must have a [[Call]] internal method.
+ if (!callable->IsCallable()) return isolate->factory()->false_value();
+
+ // Check if {callable} is a bound function, and if so retrieve its
+ // [[BoundTargetFunction]] and use that instead of {callable}.
+ if (callable->IsJSBoundFunction()) {
+ Handle<Object> bound_callable(
+ Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
+ isolate);
+ return Object::InstanceOf(isolate, object, bound_callable);
+ }
+
+ // If {object} is not a receiver, return false.
+ if (!object->IsJSReceiver()) return isolate->factory()->false_value();
+
+ // Get the "prototype" of {callable}; raise an error if it's not a receiver.
+ Handle<Object> prototype;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, prototype,
+ Object::GetProperty(callable, isolate->factory()->prototype_string()),
+ Object);
+ if (!prototype->IsJSReceiver()) {
+ THROW_NEW_ERROR(
+ isolate,
+ NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype),
+ Object);
+ }
+
+ // Return whether or not {prototype} is in the prototype chain of {object}.
+ Maybe<bool> result = JSReceiver::HasInPrototypeChain(
+ isolate, Handle<JSReceiver>::cast(object), prototype);
+ if (result.IsNothing()) return MaybeHandle<Object>();
+ return isolate->factory()->ToBoolean(result.FromJust());
+}
+
+// static
+MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object,
+ Handle<Object> callable) {
+ // The {callable} must be a receiver.
+ if (!callable->IsJSReceiver()) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck),
+ Object);
+ }
+
+ // Lookup the @@hasInstance method on {callable}.
+ Handle<Object> inst_of_handler;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, inst_of_handler,
+ JSReceiver::GetMethod(Handle<JSReceiver>::cast(callable),
+ isolate->factory()->has_instance_symbol()),
+ Object);
+ if (!inst_of_handler->IsUndefined(isolate)) {
+ // Call the {inst_of_handler} on the {callable}.
+ Handle<Object> result;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, result,
+ Execution::Call(isolate, inst_of_handler, callable, 1, &object),
+ Object);
+ return isolate->factory()->ToBoolean(result->BooleanValue());
+ }
+
+ // The {callable} must have a [[Call]] internal method.
+ if (!callable->IsCallable()) {
+ THROW_NEW_ERROR(
+ isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck),
+ Object);
+ }
+
+ // Fall back to OrdinaryHasInstance with {callable} and {object}.
+ Handle<Object> result;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, result,
+ JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object);
+ return result;
+}
Maybe<bool> Object::IsArray(Handle<Object> object) {
if (object->IsJSArray()) return Just(true);
@@ -586,20 +837,6 @@ Maybe<bool> Object::IsArray(Handle<Object> object) {
}
-bool Object::IsPromise(Handle<Object> object) {
- if (!object->IsJSObject()) return false;
- auto js_object = Handle<JSObject>::cast(object);
- // Promises can't have access checks.
- if (js_object->map()->is_access_check_needed()) return false;
- auto isolate = js_object->GetIsolate();
- // TODO(dcarney): this should just be read from the symbol registry so as not
- // to be context dependent.
- auto key = isolate->factory()->promise_status_symbol();
- // Shouldn't be possible to throw here.
- return JSObject::HasRealNamedProperty(js_object, key).FromJust();
-}
-
-
// static
MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
Handle<Name> name) {
@@ -607,7 +844,7 @@ MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
Isolate* isolate = receiver->GetIsolate();
ASSIGN_RETURN_ON_EXCEPTION(isolate, func,
JSReceiver::GetProperty(receiver, name), Object);
- if (func->IsNull() || func->IsUndefined()) {
+ if (func->IsNull(isolate) || func->IsUndefined(isolate)) {
return isolate->factory()->undefined_value();
}
if (!func->IsCallable()) {
@@ -634,14 +871,9 @@ MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
}
// 4. Let len be ? ToLength(? Get(obj, "length")).
Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
- Handle<Object> raw_length_obj;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, raw_length_obj,
- JSReceiver::GetProperty(receiver, isolate->factory()->length_string()),
- FixedArray);
Handle<Object> raw_length_number;
ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number,
- Object::ToLength(isolate, raw_length_obj),
+ Object::GetLengthFromArrayLike(isolate, receiver),
FixedArray);
uint32_t len;
if (!raw_length_number->ToUint32(&len) ||
@@ -688,6 +920,16 @@ MaybeHandle<FixedArray> Object::CreateListFromArrayLike(
// static
+MaybeHandle<Object> Object::GetLengthFromArrayLike(Isolate* isolate,
+ Handle<Object> object) {
+ Handle<Object> val;
+ Handle<Object> key = isolate->factory()->length_string();
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, val, Runtime::GetObjectProperty(isolate, object, key), Object);
+ return Object::ToLength(isolate, val);
+}
+
+// static
Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
@@ -762,17 +1004,6 @@ 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,
@@ -788,7 +1019,7 @@ MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
}
DCHECK(!name->IsPrivate());
- STACK_CHECK(MaybeHandle<Object>());
+ STACK_CHECK(isolate, MaybeHandle<Object>());
Handle<Name> trap_name = isolate->factory()->get_string();
// 1. Assert: IsPropertyKey(P) is true.
// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
@@ -808,7 +1039,7 @@ MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
isolate, trap,
Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), Object);
// 7. If trap is undefined, then
- if (trap->IsUndefined()) {
+ if (trap->IsUndefined(isolate)) {
// 7.a Return target.[[Get]](P, Receiver).
LookupIterator it =
LookupIterator::PropertyOrElement(isolate, receiver, name, target);
@@ -848,8 +1079,8 @@ MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
// 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();
+ target_desc.get()->IsUndefined(isolate) &&
+ !trap_result->IsUndefined(isolate);
if (inconsistent) {
THROW_NEW_ERROR(
isolate,
@@ -908,12 +1139,40 @@ bool Object::ToInt32(int32_t* value) {
return false;
}
+Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
+ Isolate* isolate, Handle<FunctionTemplateInfo> info) {
+ Object* current_info = info->shared_function_info();
+ if (current_info->IsSharedFunctionInfo()) {
+ return handle(SharedFunctionInfo::cast(current_info), isolate);
+ }
-bool FunctionTemplateInfo::IsTemplateFor(Object* object) {
- if (!object->IsHeapObject()) return false;
- return IsTemplateFor(HeapObject::cast(object)->map());
-}
+ Handle<Object> class_name(info->class_name(), isolate);
+ Handle<String> name = class_name->IsString()
+ ? Handle<String>::cast(class_name)
+ : isolate->factory()->empty_string();
+ Handle<Code> code;
+ if (info->call_code()->IsCallHandlerInfo() &&
+ CallHandlerInfo::cast(info->call_code())->fast_handler()->IsCode()) {
+ code = isolate->builtins()->HandleFastApiCall();
+ } else {
+ code = isolate->builtins()->HandleApiCall();
+ }
+ bool is_constructor = !info->remove_prototype();
+ Handle<SharedFunctionInfo> result =
+ isolate->factory()->NewSharedFunctionInfo(name, code, is_constructor);
+ if (is_constructor) {
+ result->SetConstructStub(*isolate->builtins()->JSConstructStubApi());
+ }
+
+ result->set_length(info->length());
+ if (class_name->IsString()) result->set_instance_class_name(*class_name);
+ result->set_api_func_data(*info);
+ result->DontAdaptArguments();
+ DCHECK(result->IsApiFunction());
+ info->set_shared_function_info(*result);
+ return result;
+}
bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
// There is a constraint on the object; check.
@@ -934,25 +1193,25 @@ bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
}
-// TODO(dcarney): CallOptimization duplicates this logic, merge.
-Object* FunctionTemplateInfo::GetCompatibleReceiver(Isolate* isolate,
- Object* receiver) {
- // API calls are only supported with JSObject receivers.
- if (!receiver->IsJSObject()) return isolate->heap()->null_value();
- Object* recv_type = this->signature();
- // No signature, return holder.
- if (recv_type->IsUndefined()) return receiver;
- FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type);
- // Check the receiver.
- for (PrototypeIterator iter(isolate, JSObject::cast(receiver),
- PrototypeIterator::START_AT_RECEIVER,
- PrototypeIterator::END_AT_NON_HIDDEN);
- !iter.IsAtEnd(); iter.Advance()) {
- if (signature->IsTemplateFor(iter.GetCurrent())) return iter.GetCurrent();
- }
- return isolate->heap()->null_value();
+// static
+Handle<TemplateList> TemplateList::New(Isolate* isolate, int size) {
+ Handle<FixedArray> list =
+ isolate->factory()->NewFixedArray(kLengthIndex + size);
+ list->set(kLengthIndex, Smi::FromInt(0));
+ return Handle<TemplateList>::cast(list);
}
+// static
+Handle<TemplateList> TemplateList::Add(Isolate* isolate,
+ Handle<TemplateList> list,
+ Handle<i::Object> value) {
+ STATIC_ASSERT(kFirstElementIndex == 1);
+ int index = list->length() + 1;
+ Handle<i::FixedArray> fixed_array = Handle<FixedArray>::cast(list);
+ fixed_array = FixedArray::SetAndGrow(fixed_array, index, value);
+ fixed_array->set(kLengthIndex, Smi::FromInt(index));
+ return Handle<TemplateList>::cast(fixed_array);
+}
// static
MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
@@ -1001,7 +1260,7 @@ MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
Isolate* isolate = proxy->GetIsolate();
Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
- STACK_CHECK(MaybeHandle<Object>());
+ STACK_CHECK(isolate, MaybeHandle<Object>());
// 1. Let handler be the value of the [[ProxyHandler]] internal slot.
// 2. If handler is null, throw a TypeError exception.
@@ -1020,7 +1279,7 @@ MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
Object);
// 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
- if (trap->IsUndefined()) {
+ if (trap->IsUndefined(isolate)) {
return JSReceiver::GetPrototype(isolate, target);
}
// 7. Let handlerProto be ? Call(trap, handler, «target»).
@@ -1030,7 +1289,7 @@ MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
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())) {
+ if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull(isolate))) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid),
Object);
@@ -1098,16 +1357,9 @@ MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
// Regular accessor.
Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate);
if (getter->IsFunctionTemplateInfo()) {
- auto result = Builtins::InvokeApiFunction(
- Handle<FunctionTemplateInfo>::cast(getter), receiver, 0, nullptr);
- if (isolate->has_pending_exception()) {
- return MaybeHandle<Object>();
- }
- Handle<Object> return_value;
- if (result.ToHandle(&return_value)) {
- return_value->VerifyApiCallResultType();
- return handle(*return_value, isolate);
- }
+ return Builtins::InvokeApiFunction(
+ isolate, false, Handle<FunctionTemplateInfo>::cast(getter), receiver, 0,
+ nullptr, isolate->factory()->undefined_value());
} else if (getter->IsCallable()) {
// TODO(rossberg): nicer would be to cast to some JSCallable here...
return Object::GetPropertyWithDefinedGetter(
@@ -1117,6 +1369,20 @@ MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
return ReadAbsentProperty(isolate, receiver, it->GetName());
}
+// static
+Address AccessorInfo::redirect(Isolate* isolate, Address address,
+ AccessorComponent component) {
+ ApiFunction fun(address);
+ DCHECK_EQ(ACCESSOR_GETTER, component);
+ ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
+ return ExternalReference(&fun, type, isolate).address();
+}
+
+Address AccessorInfo::redirected_getter() const {
+ Address accessor = v8::ToCData<Address>(getter());
+ if (accessor == nullptr) return nullptr;
+ return redirect(GetIsolate(), accessor, ACCESSOR_GETTER);
+}
bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate,
Handle<AccessorInfo> info,
@@ -1173,12 +1439,12 @@ Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
if (setter->IsFunctionTemplateInfo()) {
Handle<Object> argv[] = {value};
- auto result =
- Builtins::InvokeApiFunction(Handle<FunctionTemplateInfo>::cast(setter),
- receiver, arraysize(argv), argv);
- if (isolate->has_pending_exception()) {
- return Nothing<bool>();
- }
+ RETURN_ON_EXCEPTION_VALUE(
+ isolate, Builtins::InvokeApiFunction(
+ isolate, false, Handle<FunctionTemplateInfo>::cast(setter),
+ receiver, arraysize(argv), argv,
+ isolate->factory()->undefined_value()),
+ Nothing<bool>());
return Just(true);
} else if (setter->IsCallable()) {
// TODO(rossberg): nicer would be to cast to some JSCallable here...
@@ -1230,18 +1496,6 @@ 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.
@@ -1263,19 +1517,191 @@ bool JSObject::AllCanRead(LookupIterator* it) {
return false;
}
+namespace {
+
+MaybeHandle<Object> GetPropertyWithInterceptorInternal(
+ LookupIterator* it, Handle<InterceptorInfo> interceptor, bool* done) {
+ *done = false;
+ Isolate* isolate = it->isolate();
+ // Make sure that the top context does not change when doing callbacks or
+ // interceptor calls.
+ AssertNoContextChange ncc(isolate);
+
+ if (interceptor->getter()->IsUndefined(isolate)) {
+ return isolate->factory()->undefined_value();
+ }
+
+ Handle<JSObject> holder = it->GetHolder<JSObject>();
+ Handle<Object> result;
+ Handle<Object> receiver = it->GetReceiver();
+ if (!receiver->IsJSReceiver()) {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
+ }
+ PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
+ *holder, Object::DONT_THROW);
+
+ if (it->IsElement()) {
+ uint32_t index = it->index();
+ v8::IndexedPropertyGetterCallback getter =
+ v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
+ 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();
+ }
+
+ v8::GenericNamedPropertyGetterCallback getter =
+ v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
+ interceptor->getter());
+ result = args.Call(getter, name);
+ }
+
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
+ if (result.is_null()) return isolate->factory()->undefined_value();
+ *done = true;
+ // Rebox handle before return
+ return handle(*result, isolate);
+}
+
+Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
+ LookupIterator* it, Handle<InterceptorInfo> interceptor) {
+ Isolate* isolate = it->isolate();
+ // Make sure that the top context does not change when doing
+ // callbacks or interceptor calls.
+ AssertNoContextChange ncc(isolate);
+ HandleScope scope(isolate);
+
+ Handle<JSObject> holder = it->GetHolder<JSObject>();
+ if (!it->IsElement() && it->name()->IsSymbol() &&
+ !interceptor->can_intercept_symbols()) {
+ return Just(ABSENT);
+ }
+ Handle<Object> receiver = it->GetReceiver();
+ if (!receiver->IsJSReceiver()) {
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
+ Object::ConvertReceiver(isolate, receiver),
+ Nothing<PropertyAttributes>());
+ }
+ PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
+ *holder, Object::DONT_THROW);
+ if (!interceptor->query()->IsUndefined(isolate)) {
+ Handle<Object> result;
+ if (it->IsElement()) {
+ uint32_t index = it->index();
+ v8::IndexedPropertyQueryCallback query =
+ v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
+ result = args.Call(query, index);
+ } else {
+ Handle<Name> name = it->name();
+ DCHECK(!name->IsPrivate());
+ v8::GenericNamedPropertyQueryCallback query =
+ v8::ToCData<v8::GenericNamedPropertyQueryCallback>(
+ interceptor->query());
+ result = args.Call(query, name);
+ }
+ if (!result.is_null()) {
+ int32_t value;
+ CHECK(result->ToInt32(&value));
+ return Just(static_cast<PropertyAttributes>(value));
+ }
+ } else if (!interceptor->getter()->IsUndefined(isolate)) {
+ // TODO(verwaest): Use GetPropertyWithInterceptor?
+ Handle<Object> result;
+ if (it->IsElement()) {
+ uint32_t index = it->index();
+ v8::IndexedPropertyGetterCallback getter =
+ v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
+ result = args.Call(getter, index);
+ } else {
+ Handle<Name> name = it->name();
+ DCHECK(!name->IsPrivate());
+ v8::GenericNamedPropertyGetterCallback getter =
+ v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
+ interceptor->getter());
+ result = args.Call(getter, name);
+ }
+ if (!result.is_null()) return Just(DONT_ENUM);
+ }
+
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
+ return Just(ABSENT);
+}
+
+Maybe<bool> SetPropertyWithInterceptorInternal(
+ LookupIterator* it, Handle<InterceptorInfo> interceptor,
+ Object::ShouldThrow should_throw, Handle<Object> value) {
+ Isolate* isolate = it->isolate();
+ // Make sure that the top context does not change when doing callbacks or
+ // interceptor calls.
+ AssertNoContextChange ncc(isolate);
+
+ if (interceptor->setter()->IsUndefined(isolate)) return Just(false);
+
+ Handle<JSObject> holder = it->GetHolder<JSObject>();
+ bool result;
+ Handle<Object> receiver = it->GetReceiver();
+ if (!receiver->IsJSReceiver()) {
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
+ Object::ConvertReceiver(isolate, receiver),
+ Nothing<bool>());
+ }
+ PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
+ *holder, should_throw);
+
+ if (it->IsElement()) {
+ uint32_t index = it->index();
+ v8::IndexedPropertySetterCallback setter =
+ v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
+ // TODO(neis): In the future, we may want to actually return the
+ // interceptor's result, which then should be a boolean.
+ result = !args.Call(setter, index, value).is_null();
+ } else {
+ Handle<Name> name = it->name();
+ DCHECK(!name->IsPrivate());
+
+ if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
+ return Just(false);
+ }
+
+ v8::GenericNamedPropertySetterCallback setter =
+ v8::ToCData<v8::GenericNamedPropertySetterCallback>(
+ interceptor->setter());
+ result = !args.Call(setter, name, value).is_null();
+ }
+
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
+ return Just(result);
+}
+
+} // namespace
MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
LookupIterator* it) {
+ Isolate* isolate = it->isolate();
Handle<JSObject> checked = it->GetHolder<JSObject>();
- while (AllCanRead(it)) {
- if (it->state() == LookupIterator::ACCESSOR) {
- return GetPropertyWithAccessor(it);
+ Handle<InterceptorInfo> interceptor =
+ it->GetInterceptorForFailedAccessCheck();
+ if (interceptor.is_null()) {
+ while (AllCanRead(it)) {
+ if (it->state() == LookupIterator::ACCESSOR) {
+ return GetPropertyWithAccessor(it);
+ }
+ DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
+ bool done;
+ Handle<Object> result;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
+ GetPropertyWithInterceptor(it, &done), Object);
+ if (done) return result;
}
- DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
+ } else {
+ MaybeHandle<Object> result;
bool done;
- Handle<Object> result;
- ASSIGN_RETURN_ON_EXCEPTION(it->isolate(), result,
- GetPropertyWithInterceptor(it, &done), Object);
+ result = GetPropertyWithInterceptorInternal(it, interceptor, &done);
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
if (done) return result;
}
@@ -1286,27 +1712,36 @@ MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
return it->factory()->undefined_value();
}
- it->isolate()->ReportFailedAccessCheck(checked);
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
+ isolate->ReportFailedAccessCheck(checked);
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
return it->factory()->undefined_value();
}
Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
LookupIterator* it) {
+ Isolate* isolate = it->isolate();
Handle<JSObject> checked = it->GetHolder<JSObject>();
- while (AllCanRead(it)) {
- if (it->state() == LookupIterator::ACCESSOR) {
- return Just(it->property_attributes());
+ Handle<InterceptorInfo> interceptor =
+ it->GetInterceptorForFailedAccessCheck();
+ if (interceptor.is_null()) {
+ while (AllCanRead(it)) {
+ if (it->state() == LookupIterator::ACCESSOR) {
+ return Just(it->property_attributes());
+ }
+ DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
+ auto result = GetPropertyAttributesWithInterceptor(it);
+ if (isolate->has_scheduled_exception()) break;
+ if (result.IsJust() && result.FromJust() != ABSENT) return result;
}
- DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
- auto result = GetPropertyAttributesWithInterceptor(it);
- if (it->isolate()->has_scheduled_exception()) break;
- if (result.IsJust() && result.FromJust() != ABSENT) return result;
+ } else {
+ Maybe<PropertyAttributes> result =
+ GetPropertyAttributesWithInterceptorInternal(it, interceptor);
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
+ if (result.FromMaybe(ABSENT) != ABSENT) return result;
}
- it->isolate()->ReportFailedAccessCheck(checked);
- RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(),
- Nothing<PropertyAttributes>());
+ isolate->ReportFailedAccessCheck(checked);
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
return Just(ABSENT);
}
@@ -1327,13 +1762,23 @@ bool JSObject::AllCanWrite(LookupIterator* it) {
Maybe<bool> JSObject::SetPropertyWithFailedAccessCheck(
LookupIterator* it, Handle<Object> value, ShouldThrow should_throw) {
+ Isolate* isolate = it->isolate();
Handle<JSObject> checked = it->GetHolder<JSObject>();
- if (AllCanWrite(it)) {
- return SetPropertyWithAccessor(it, value, should_throw);
+ Handle<InterceptorInfo> interceptor =
+ it->GetInterceptorForFailedAccessCheck();
+ if (interceptor.is_null()) {
+ if (AllCanWrite(it)) {
+ return SetPropertyWithAccessor(it, value, should_throw);
+ }
+ } else {
+ Maybe<bool> result = SetPropertyWithInterceptorInternal(
+ it, interceptor, should_throw, value);
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
+ if (result.IsJust()) return result;
}
- it->isolate()->ReportFailedAccessCheck(checked);
- RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
+ isolate->ReportFailedAccessCheck(checked);
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
return Just(true);
}
@@ -1349,44 +1794,47 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object,
}
if (object->IsJSGlobalObject()) {
- Handle<GlobalDictionary> property_dictionary(object->global_dictionary());
+ Handle<GlobalDictionary> dictionary(object->global_dictionary());
- int entry = property_dictionary->FindEntry(name);
+ int entry = dictionary->FindEntry(name);
if (entry == GlobalDictionary::kNotFound) {
- auto cell = object->GetIsolate()->factory()->NewPropertyCell();
+ Isolate* isolate = object->GetIsolate();
+ auto cell = isolate->factory()->NewPropertyCell();
cell->set_value(*value);
- auto cell_type = value->IsUndefined() ? PropertyCellType::kUndefined
- : PropertyCellType::kConstant;
+ auto cell_type = value->IsUndefined(isolate)
+ ? PropertyCellType::kUndefined
+ : PropertyCellType::kConstant;
details = details.set_cell_type(cell_type);
value = cell;
- property_dictionary =
- GlobalDictionary::Add(property_dictionary, name, value, details);
- object->set_properties(*property_dictionary);
+ dictionary = GlobalDictionary::Add(dictionary, name, value, details);
+ object->set_properties(*dictionary);
} else {
- PropertyCell::UpdateCell(property_dictionary, entry, value, details);
+ Handle<PropertyCell> cell =
+ PropertyCell::PrepareForValue(dictionary, entry, value, details);
+ cell->set_value(*value);
}
} else {
- Handle<NameDictionary> property_dictionary(object->property_dictionary());
+ Handle<NameDictionary> dictionary(object->property_dictionary());
- int entry = property_dictionary->FindEntry(name);
+ int entry = dictionary->FindEntry(name);
if (entry == NameDictionary::kNotFound) {
- property_dictionary =
- NameDictionary::Add(property_dictionary, name, value, details);
- object->set_properties(*property_dictionary);
+ dictionary = NameDictionary::Add(dictionary, name, value, details);
+ object->set_properties(*dictionary);
} else {
- PropertyDetails original_details = property_dictionary->DetailsAt(entry);
+ PropertyDetails original_details = dictionary->DetailsAt(entry);
int enumeration_index = original_details.dictionary_index();
DCHECK(enumeration_index > 0);
details = details.set_index(enumeration_index);
- property_dictionary->SetEntry(entry, name, value, details);
+ dictionary->SetEntry(entry, name, value, details);
}
}
}
+// static
Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
Handle<JSReceiver> object,
Handle<Object> proto) {
- PrototypeIterator iter(isolate, object, PrototypeIterator::START_AT_RECEIVER);
+ PrototypeIterator iter(isolate, object, kStartAtReceiver);
while (true) {
if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
if (iter.IsAtEnd()) return Just(false);
@@ -1396,7 +1844,6 @@ Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
}
}
-
Map* Object::GetRootMap(Isolate* isolate) {
DisallowHeapAllocation no_alloc;
if (IsSmi()) {
@@ -1421,28 +1868,21 @@ Map* Object::GetRootMap(Isolate* isolate) {
return isolate->heap()->null_value()->map();
}
+namespace {
-Object* Object::GetHash() {
- Object* hash = GetSimpleHash();
- if (hash->IsSmi()) return hash;
-
- DisallowHeapAllocation no_gc;
- DCHECK(IsJSReceiver());
- JSReceiver* receiver = JSReceiver::cast(this);
- Isolate* isolate = receiver->GetIsolate();
- return *JSReceiver::GetIdentityHash(isolate, handle(receiver, isolate));
-}
-
-
-Object* Object::GetSimpleHash() {
+// Returns a non-SMI for JSObjects, but returns the hash code for simple
+// objects. This avoids a double lookup in the cases where we know we will
+// add the hash to the JSObject if it does not already exist.
+Object* GetSimpleHash(Object* object) {
// The object is either a Smi, a HeapNumber, a name, an odd-ball,
// a SIMD value type, a real JS object, or a Harmony proxy.
- if (IsSmi()) {
- uint32_t hash = ComputeIntegerHash(Smi::cast(this)->value(), kZeroHashSeed);
+ if (object->IsSmi()) {
+ uint32_t hash =
+ ComputeIntegerHash(Smi::cast(object)->value(), kZeroHashSeed);
return Smi::FromInt(hash & Smi::kMaxValue);
}
- if (IsHeapNumber()) {
- double num = HeapNumber::cast(this)->value();
+ if (object->IsHeapNumber()) {
+ double num = HeapNumber::cast(object)->value();
if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue);
if (i::IsMinusZero(num)) num = 0;
if (IsSmiDouble(num)) {
@@ -1451,30 +1891,43 @@ Object* Object::GetSimpleHash() {
uint32_t hash = ComputeLongHash(double_to_uint64(num));
return Smi::FromInt(hash & Smi::kMaxValue);
}
- if (IsName()) {
- uint32_t hash = Name::cast(this)->Hash();
+ if (object->IsName()) {
+ uint32_t hash = Name::cast(object)->Hash();
return Smi::FromInt(hash);
}
- if (IsOddball()) {
- uint32_t hash = Oddball::cast(this)->to_string()->Hash();
+ if (object->IsOddball()) {
+ uint32_t hash = Oddball::cast(object)->to_string()->Hash();
return Smi::FromInt(hash);
}
- if (IsSimd128Value()) {
- uint32_t hash = Simd128Value::cast(this)->Hash();
+ if (object->IsSimd128Value()) {
+ uint32_t hash = Simd128Value::cast(object)->Hash();
return Smi::FromInt(hash & Smi::kMaxValue);
}
+ DCHECK(object->IsJSReceiver());
+ // Simply return the receiver as it is guaranteed to not be a SMI.
+ return object;
+}
+
+} // namespace
+
+Object* Object::GetHash() {
+ Object* hash = GetSimpleHash(this);
+ if (hash->IsSmi()) return hash;
+
+ DisallowHeapAllocation no_gc;
DCHECK(IsJSReceiver());
JSReceiver* receiver = JSReceiver::cast(this);
- return receiver->GetHeap()->undefined_value();
+ Isolate* isolate = receiver->GetIsolate();
+ return JSReceiver::GetIdentityHash(isolate, handle(receiver, isolate));
}
-
-Handle<Smi> Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) {
- Handle<Object> hash(object->GetSimpleHash(), isolate);
- if (hash->IsSmi()) return Handle<Smi>::cast(hash);
+Smi* Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) {
+ Object* hash = GetSimpleHash(*object);
+ if (hash->IsSmi()) return Smi::cast(hash);
DCHECK(object->IsJSReceiver());
- return JSReceiver::GetOrCreateIdentityHash(Handle<JSReceiver>::cast(object));
+ return JSReceiver::GetOrCreateIdentityHash(isolate,
+ Handle<JSReceiver>::cast(object));
}
@@ -1555,11 +2008,7 @@ bool Object::SameValueZero(Object* other) {
MaybeHandle<Object> Object::ArraySpeciesConstructor(
Isolate* isolate, Handle<Object> original_array) {
- Handle<Context> native_context = isolate->native_context();
Handle<Object> default_species = isolate->array_function();
- if (!FLAG_harmony_species) {
- return default_species;
- }
if (original_array->IsJSArray() &&
Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
isolate->IsArraySpeciesLookupChainIntact()) {
@@ -1580,7 +2029,7 @@ MaybeHandle<Object> Object::ArraySpeciesConstructor(
isolate, constructor_context,
JSReceiver::GetFunctionRealm(Handle<JSReceiver>::cast(constructor)),
Object);
- if (*constructor_context != *native_context &&
+ if (*constructor_context != *isolate->native_context() &&
*constructor == constructor_context->array_function()) {
constructor = isolate->factory()->undefined_value();
}
@@ -1591,12 +2040,12 @@ MaybeHandle<Object> Object::ArraySpeciesConstructor(
JSReceiver::GetProperty(Handle<JSReceiver>::cast(constructor),
isolate->factory()->species_symbol()),
Object);
- if (constructor->IsNull()) {
+ if (constructor->IsNull(isolate)) {
constructor = isolate->factory()->undefined_value();
}
}
}
- if (constructor->IsUndefined()) {
+ if (constructor->IsUndefined(isolate)) {
return default_species;
} else {
if (!constructor->IsConstructor()) {
@@ -1718,6 +2167,7 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
Heap* heap = GetHeap();
bool is_one_byte = this->IsOneByteRepresentation();
bool is_internalized = this->IsInternalizedString();
+ bool has_pointers = this->IsConsString() || this->IsSlicedString();
// Morph the string to an external string by replacing the map and
// reinitializing the fields. This won't work if the space the existing
@@ -1746,6 +2196,9 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
int new_size = this->SizeFromMap(new_map);
heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
ClearRecordedSlots::kNo);
+ if (has_pointers) {
+ heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
+ }
// We are storing the new map using release store after creating a filler for
// the left-over space to avoid races with the sweeper thread.
@@ -1786,6 +2239,7 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
if (size < ExternalString::kShortSize) return false;
Heap* heap = GetHeap();
bool is_internalized = this->IsInternalizedString();
+ bool has_pointers = this->IsConsString() || this->IsSlicedString();
// Morph the string to an external string by replacing the map and
// reinitializing the fields. This won't work if the space the existing
@@ -1808,6 +2262,9 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
int new_size = this->SizeFromMap(new_map);
heap->CreateFillerObjectAt(this->address() + new_size, size - new_size,
ClearRecordedSlots::kNo);
+ if (has_pointers) {
+ heap->ClearRecordedSlotRange(this->address(), this->address() + new_size);
+ }
// We are storing the new map using release store after creating a filler for
// the left-over space to avoid races with the sweeper thread.
@@ -1821,8 +2278,7 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
return true;
}
-
-void String::StringShortPrint(StringStream* accumulator) {
+void String::StringShortPrint(StringStream* accumulator, bool show_details) {
int len = length();
if (len > kMaxShortPrintLength) {
accumulator->Add("<Very long string[%u]>", len);
@@ -1851,15 +2307,15 @@ void String::StringShortPrint(StringStream* accumulator) {
}
stream.Reset(this);
if (one_byte) {
- accumulator->Add("<String[%u]: ", length());
+ if (show_details) accumulator->Add("<String[%u]: ", length());
for (int i = 0; i < len; i++) {
accumulator->Put(static_cast<char>(stream.GetNext()));
}
- accumulator->Put('>');
+ if (show_details) accumulator->Put('>');
} else {
// Backslash indicates that the string contains control
// characters and that backslashes are therefore escaped.
- accumulator->Add("<String[%u]\\: ", length());
+ if (show_details) accumulator->Add("<String[%u]\\: ", length());
for (int i = 0; i < len; i++) {
uint16_t c = stream.GetNext();
if (c == '\n') {
@@ -1879,7 +2335,7 @@ void String::StringShortPrint(StringStream* accumulator) {
accumulator->Put('.');
accumulator->Put('.');
}
- accumulator->Put('>');
+ if (show_details) accumulator->Put('>');
}
return;
}
@@ -1897,23 +2353,15 @@ void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT
void JSObject::JSObjectShortPrint(StringStream* accumulator) {
switch (map()->instance_type()) {
case JS_ARRAY_TYPE: {
- double length = JSArray::cast(this)->length()->IsUndefined()
- ? 0
- : JSArray::cast(this)->length()->Number();
+ double length = JSArray::cast(this)->length()->IsUndefined(GetIsolate())
+ ? 0
+ : JSArray::cast(this)->length()->Number();
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()));
@@ -1946,6 +2394,18 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) {
if (!printed) {
accumulator->Add("<JS Function");
}
+ if (FLAG_trace_file_names) {
+ Object* source_name =
+ Script::cast(function->shared()->script())->name();
+ if (source_name->IsString()) {
+ String* str = String::cast(source_name);
+ if (str->length() > 0) {
+ accumulator->Add(" <");
+ accumulator->Put(str);
+ accumulator->Add(">");
+ }
+ }
+ }
accumulator->Add(" (SharedFunctionInfo %p)",
reinterpret_cast<void*>(function->shared()));
accumulator->Put('>');
@@ -2131,6 +2591,7 @@ void JSObject::PrintInstanceMigration(FILE* file,
void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
Heap* heap = GetHeap();
+ Isolate* isolate = heap->isolate();
if (!heap->Contains(this)) {
os << "!!!INVALID POINTER!!!";
return;
@@ -2192,8 +2653,7 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
case SHARED_FUNCTION_INFO_TYPE: {
SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
- base::SmartArrayPointer<char> debug_name =
- shared->DebugName()->ToCString();
+ std::unique_ptr<char[]> debug_name = shared->DebugName()->ToCString();
if (debug_name[0] != 0) {
os << "<SharedFunctionInfo " << debug_name.get() << ">";
} else {
@@ -2216,18 +2676,20 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
break;
}
case ODDBALL_TYPE: {
- if (IsUndefined()) {
+ if (IsUndefined(isolate)) {
os << "<undefined>";
- } else if (IsTheHole()) {
+ } else if (IsTheHole(isolate)) {
os << "<the hole>";
- } else if (IsNull()) {
+ } else if (IsNull(isolate)) {
os << "<null>";
- } else if (IsTrue()) {
+ } else if (IsTrue(isolate)) {
os << "<true>";
- } else if (IsFalse()) {
+ } else if (IsFalse(isolate)) {
os << "<false>";
} else {
- os << "<Odd Oddball>";
+ os << "<Odd Oddball: ";
+ os << Oddball::cast(this)->to_string()->ToCString().get();
+ os << ">";
}
break;
}
@@ -2458,25 +2920,6 @@ String* JSReceiver::class_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();
@@ -2600,68 +3043,6 @@ MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
}
-
-void JSObject::AddSlowProperty(Handle<JSObject> object,
- Handle<Name> name,
- Handle<Object> value,
- PropertyAttributes attributes) {
- DCHECK(!object->HasFastProperties());
- Isolate* isolate = object->GetIsolate();
- if (object->IsJSGlobalObject()) {
- Handle<GlobalDictionary> dict(object->global_dictionary());
- PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
- int entry = dict->FindEntry(name);
- // If there's a cell there, just invalidate and set the property.
- if (entry != GlobalDictionary::kNotFound) {
- PropertyCell::UpdateCell(dict, entry, value, details);
- // TODO(ishell): move this to UpdateCell.
- // Need to adjust the details.
- int index = dict->NextEnumerationIndex();
- dict->SetNextEnumerationIndex(index + 1);
- PropertyCell* cell = PropertyCell::cast(dict->ValueAt(entry));
- details = cell->property_details().set_index(index);
- cell->set_property_details(details);
-
- } else {
- auto cell = isolate->factory()->NewPropertyCell();
- cell->set_value(*value);
- auto cell_type = value->IsUndefined() ? PropertyCellType::kUndefined
- : PropertyCellType::kConstant;
- details = details.set_cell_type(cell_type);
- value = cell;
-
- Handle<GlobalDictionary> result =
- GlobalDictionary::Add(dict, name, value, details);
- if (*dict != *result) object->set_properties(*result);
- }
- } else {
- Handle<NameDictionary> dict(object->property_dictionary());
- PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
- Handle<NameDictionary> result =
- NameDictionary::Add(dict, name, value, details);
- if (*dict != *result) object->set_properties(*result);
- }
-}
-
-
-MaybeHandle<Object> JSObject::EnqueueChangeRecord(Handle<JSObject> object,
- const char* type_str,
- Handle<Name> name,
- Handle<Object> old_value) {
- DCHECK(!object->IsJSGlobalProxy());
- DCHECK(!object->IsJSGlobalObject());
- Isolate* isolate = object->GetIsolate();
- HandleScope scope(isolate);
- Handle<String> type = isolate->factory()->InternalizeUtf8String(type_str);
- Handle<Object> args[] = { type, object, name, old_value };
- int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4;
-
- return Execution::Call(isolate,
- Handle<JSFunction>(isolate->observers_notify_change()),
- isolate->factory()->undefined_value(), argc, args);
-}
-
-
const char* Representation::Mnemonic() const {
switch (kind_) {
case kNone: return "v";
@@ -2727,7 +3108,6 @@ bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
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());
bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
@@ -3124,7 +3504,7 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
// Ensure that no transition was inserted for prototype migrations.
DCHECK_EQ(
0, TransitionArray::NumberOfTransitions(old_map->raw_transitions()));
- DCHECK(new_map->GetBackPointer()->IsUndefined());
+ DCHECK(new_map->GetBackPointer()->IsUndefined(new_map->GetIsolate()));
}
} else {
MigrateFastToSlow(object, new_map, expected_additional_properties);
@@ -3138,6 +3518,15 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
// When adding code here, add a DisallowHeapAllocation too.
}
+void JSObject::ForceSetPrototype(Handle<JSObject> object,
+ Handle<Object> proto) {
+ // object.__proto__ = proto;
+ Handle<Map> old_map = Handle<Map>(object->map());
+ Handle<Map> new_map = Map::Copy(old_map, "ForceSetPrototype");
+ Map::SetPrototype(new_map, proto, FAST_PROTOTYPE);
+ JSObject::MigrateToMap(object, new_map);
+}
+
int Map::NumberOfFields() {
DescriptorArray* descriptors = instance_descriptors();
int result = 0;
@@ -3236,17 +3625,18 @@ static inline bool EqualImmutableValues(Object* obj1, Object* obj2) {
// proper sharing of descriptor arrays.
void Map::ReplaceDescriptors(DescriptorArray* new_descriptors,
LayoutDescriptor* new_layout_descriptor) {
+ Isolate* isolate = GetIsolate();
// Don't overwrite the empty descriptor array or initial map's descriptors.
- if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined()) {
+ if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined(isolate)) {
return;
}
DescriptorArray* to_replace = instance_descriptors();
- GetHeap()->incremental_marking()->IterateBlackObject(to_replace);
+ isolate->heap()->incremental_marking()->IterateBlackObject(to_replace);
Map* current = this;
while (current->instance_descriptors() == to_replace) {
Object* next = current->GetBackPointer();
- if (next->IsUndefined()) break; // Stop overwriting at initial map.
+ if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
current->SetEnumLength(kInvalidEnumCacheSentinel);
current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
current = Map::cast(next);
@@ -3257,9 +3647,10 @@ void Map::ReplaceDescriptors(DescriptorArray* new_descriptors,
Map* Map::FindRootMap() {
Map* result = this;
+ Isolate* isolate = GetIsolate();
while (true) {
Object* back = result->GetBackPointer();
- if (back->IsUndefined()) {
+ if (back->IsUndefined(isolate)) {
// Initial map always owns descriptors and doesn't have unused entries
// in the descriptor array.
DCHECK(result->owns_descriptors());
@@ -3317,9 +3708,10 @@ Map* Map::FindFieldOwner(int descriptor) {
DisallowHeapAllocation no_allocation;
DCHECK_EQ(DATA, instance_descriptors()->GetDetails(descriptor).type());
Map* result = this;
+ Isolate* isolate = GetIsolate();
while (true) {
Object* back = result->GetBackPointer();
- if (back->IsUndefined()) break;
+ if (back->IsUndefined(isolate)) break;
Map* parent = Map::cast(back);
if (parent->NumberOfOwnDescriptors() <= descriptor) break;
result = parent;
@@ -4125,56 +4517,14 @@ Handle<Map> Map::Update(Handle<Map> map) {
ALLOW_IN_DESCRIPTOR);
}
-
Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
ShouldThrow should_throw,
Handle<Object> value) {
- Isolate* isolate = it->isolate();
- // Make sure that the top context does not change when doing callbacks or
- // interceptor calls.
- AssertNoContextChange ncc(isolate);
-
DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
- Handle<InterceptorInfo> interceptor(it->GetInterceptor());
- if (interceptor->setter()->IsUndefined()) return Just(false);
-
- Handle<JSObject> holder = it->GetHolder<JSObject>();
- bool result;
- Handle<Object> receiver = it->GetReceiver();
- if (!receiver->IsJSReceiver()) {
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
- Object::ConvertReceiver(isolate, receiver),
- Nothing<bool>());
- }
- PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
- *holder, should_throw);
-
- if (it->IsElement()) {
- uint32_t index = it->index();
- v8::IndexedPropertySetterCallback setter =
- v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
- // TODO(neis): In the future, we may want to actually return the
- // interceptor's result, which then should be a boolean.
- result = !args.Call(setter, index, value).is_null();
- } else {
- Handle<Name> name = it->name();
- DCHECK(!name->IsPrivate());
-
- if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
- return Just(false);
- }
-
- v8::GenericNamedPropertySetterCallback setter =
- v8::ToCData<v8::GenericNamedPropertySetterCallback>(
- interceptor->setter());
- result = !args.Call(setter, name, value).is_null();
- }
-
- RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
- return Just(result);
+ return SetPropertyWithInterceptorInternal(it, it->GetInterceptor(),
+ should_throw, value);
}
-
MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
Handle<Name> name, Handle<Object> value,
LanguageMode language_mode,
@@ -4190,6 +4540,7 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
LanguageMode language_mode,
StoreFromKeyed store_mode,
bool* found) {
+ it->UpdateProtector();
DCHECK(it->IsFound());
ShouldThrow should_throw =
is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
@@ -4214,23 +4565,49 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(),
value, it->GetReceiver(), language_mode);
- case LookupIterator::INTERCEPTOR:
+ case LookupIterator::INTERCEPTOR: {
+ Handle<Map> store_target_map;
+ if (it->GetReceiver()->IsJSObject()) {
+ store_target_map = handle(it->GetStoreTarget()->map(), it->isolate());
+ }
if (it->HolderIsReceiverOrHiddenPrototype()) {
Maybe<bool> result =
JSObject::SetPropertyWithInterceptor(it, should_throw, value);
if (result.IsNothing() || result.FromJust()) return result;
+ // Interceptor modified the store target but failed to set the
+ // property.
+ // TODO(jochen): Remove after we've identified the faulty interceptor.
+ if (!store_target_map.is_null() &&
+ *store_target_map != it->GetStoreTarget()->map()) {
+ it->isolate()->PushStackTraceAndDie(
+ 0xabababaa, v8::ToCData<void*>(it->GetInterceptor()->setter()),
+ nullptr, 0xabababab);
+ }
+ Utils::ApiCheck(store_target_map.is_null() ||
+ *store_target_map == it->GetStoreTarget()->map(),
+ it->IsElement() ? "v8::IndexedPropertySetterCallback"
+ : "v8::NamedPropertySetterCallback",
+ "Interceptor silently changed store target.");
} else {
Maybe<PropertyAttributes> maybe_attributes =
JSObject::GetPropertyAttributesWithInterceptor(it);
if (!maybe_attributes.IsJust()) return Nothing<bool>();
- if (maybe_attributes.FromJust() == ABSENT) break;
if ((maybe_attributes.FromJust() & READ_ONLY) != 0) {
return WriteToReadOnlyProperty(it, value, should_throw);
}
+ // Interceptor modified the store target but failed to set the
+ // property.
+ Utils::ApiCheck(store_target_map.is_null() ||
+ *store_target_map == it->GetStoreTarget()->map(),
+ it->IsElement() ? "v8::IndexedPropertySetterCallback"
+ : "v8::NamedPropertySetterCallback",
+ "Interceptor silently changed store target.");
+ if (maybe_attributes.FromJust() == ABSENT) break;
*found = false;
return Nothing<bool>();
}
break;
+ }
case LookupIterator::ACCESSOR: {
if (it->IsReadOnly()) {
@@ -4272,7 +4649,6 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
Maybe<bool> Object::SetProperty(LookupIterator* it, Handle<Object> value,
LanguageMode language_mode,
StoreFromKeyed store_mode) {
- it->UpdateProtector();
if (it->IsFound()) {
bool found = true;
Maybe<bool> result =
@@ -4300,7 +4676,6 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
StoreFromKeyed store_mode) {
Isolate* isolate = it->isolate();
- it->UpdateProtector();
if (it->IsFound()) {
bool found = true;
Maybe<bool> result =
@@ -4308,6 +4683,8 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
if (found) return result;
}
+ it->UpdateProtector();
+
// The property either doesn't exist on the holder or exists there as a data
// property.
@@ -4319,7 +4696,7 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
}
Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
- LookupIterator::Configuration c = LookupIterator::HIDDEN;
+ LookupIterator::Configuration c = LookupIterator::OWN;
LookupIterator own_lookup =
it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
: LookupIterator(receiver, it->name(), c);
@@ -4443,18 +4820,10 @@ Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
// Store on the holder which may be hidden behind the receiver.
DCHECK(it->HolderIsReceiverOrHiddenPrototype());
- // Old value for the observation change record.
- // Fetch before transforming the object since the encoding may become
- // incompatible with what's cached in |it|.
- bool is_observed = receiver->map()->is_observed() &&
- (it->IsElement() || !it->name()->IsPrivate());
- MaybeHandle<Object> maybe_old;
- if (is_observed) maybe_old = it->GetDataValue();
-
Handle<Object> to_assign = value;
// Convert the incoming value to a number for storing into typed arrays.
if (it->IsElement() && receiver->HasFixedTypedArrayElements()) {
- if (!value->IsNumber() && !value->IsUndefined()) {
+ if (!value->IsNumber() && !value->IsUndefined(it->isolate())) {
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>());
// We have to recheck the length. However, it can only change if the
@@ -4473,15 +4842,6 @@ Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
// Write the property value.
it->WriteDataValue(to_assign);
- // Send the change record if there are observers.
- if (is_observed && !value->SameValue(*maybe_old.ToHandleChecked())) {
- RETURN_ON_EXCEPTION_VALUE(
- it->isolate(),
- JSObject::EnqueueChangeRecord(receiver, "update", it->GetName(),
- maybe_old.ToHandleChecked()),
- Nothing<bool>());
- }
-
#if VERIFY_HEAP
if (FLAG_verify_heap) {
receiver->JSObjectVerify();
@@ -4491,47 +4851,6 @@ Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
}
-MUST_USE_RESULT static MaybeHandle<Object> BeginPerformSplice(
- Handle<JSArray> object) {
- Isolate* isolate = object->GetIsolate();
- HandleScope scope(isolate);
- Handle<Object> args[] = {object};
-
- return Execution::Call(
- isolate, Handle<JSFunction>(isolate->observers_begin_perform_splice()),
- isolate->factory()->undefined_value(), arraysize(args), args);
-}
-
-
-MUST_USE_RESULT static MaybeHandle<Object> EndPerformSplice(
- Handle<JSArray> object) {
- Isolate* isolate = object->GetIsolate();
- HandleScope scope(isolate);
- Handle<Object> args[] = {object};
-
- return Execution::Call(
- isolate, Handle<JSFunction>(isolate->observers_end_perform_splice()),
- isolate->factory()->undefined_value(), arraysize(args), args);
-}
-
-
-MUST_USE_RESULT static MaybeHandle<Object> EnqueueSpliceRecord(
- Handle<JSArray> object, uint32_t index, Handle<JSArray> deleted,
- uint32_t add_count) {
- Isolate* isolate = object->GetIsolate();
- HandleScope scope(isolate);
- Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index);
- Handle<Object> add_count_object =
- isolate->factory()->NewNumberFromUint(add_count);
-
- Handle<Object> args[] = {object, index_object, deleted, add_count_object};
-
- return Execution::Call(
- isolate, Handle<JSFunction>(isolate->observers_enqueue_splice()),
- isolate->factory()->undefined_value(), arraysize(args), args);
-}
-
-
Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
PropertyAttributes attributes,
ShouldThrow should_throw,
@@ -4586,6 +4905,7 @@ Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
JSObject::ValidateElements(receiver);
return result;
} else {
+ it->UpdateProtector();
// Migrate to the most up-to-date map that will be able to store |value|
// under it->name() with |attributes|.
it->PrepareTransitionToDataProperty(receiver, value, attributes,
@@ -4593,22 +4913,9 @@ Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
DCHECK_EQ(LookupIterator::TRANSITION, it->state());
it->ApplyTransitionToDataProperty(receiver);
- // TODO(verwaest): Encapsulate dictionary handling better.
- if (receiver->map()->is_dictionary_map()) {
- // TODO(dcarney): just populate TransitionPropertyCell here?
- JSObject::AddSlowProperty(receiver, it->name(), value, attributes);
- } else {
- // Write the property value.
- it->WriteDataValue(value);
- }
+ // Write the property value.
+ it->WriteDataValue(value);
- // Send the change record if there are observers.
- if (receiver->map()->is_observed() && !it->name()->IsPrivate()) {
- RETURN_ON_EXCEPTION_VALUE(isolate, JSObject::EnqueueChangeRecord(
- receiver, "add", it->name(),
- it->factory()->the_hole_value()),
- Nothing<bool>());
- }
#if VERIFY_HEAP
if (FLAG_verify_heap) {
receiver->JSObjectVerify();
@@ -4649,22 +4956,22 @@ void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
new_descriptors->CopyEnumCacheFrom(*descriptors);
}
+ Isolate* isolate = map->GetIsolate();
// Replace descriptors by new_descriptors in all maps that share it.
- map->GetHeap()->incremental_marking()->IterateBlackObject(*descriptors);
+ isolate->heap()->incremental_marking()->IterateBlackObject(*descriptors);
Map* current = *map;
while (current->instance_descriptors() == *descriptors) {
Object* next = current->GetBackPointer();
- if (next->IsUndefined()) break; // Stop overwriting at initial map.
+ if (next->IsUndefined(isolate)) break; // Stop overwriting at initial map.
current->UpdateDescriptors(*new_descriptors, layout_descriptor);
current = Map::cast(next);
}
map->UpdateDescriptors(*new_descriptors, layout_descriptor);
}
-
-template<class T>
-static int AppendUniqueCallbacks(NeanderArray* callbacks,
+template <class T>
+static int AppendUniqueCallbacks(Handle<TemplateList> callbacks,
Handle<typename T::Array> array,
int valid_descriptors) {
int nof_callbacks = callbacks->length();
@@ -4743,9 +5050,9 @@ void Map::AppendCallbackDescriptors(Handle<Map> map,
Handle<Object> descriptors) {
int nof = map->NumberOfOwnDescriptors();
Handle<DescriptorArray> array(map->instance_descriptors());
- NeanderArray callbacks(descriptors);
- DCHECK(array->NumberOfSlackDescriptors() >= callbacks.length());
- nof = AppendUniqueCallbacks<DescriptorArrayAppender>(&callbacks, array, nof);
+ Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
+ DCHECK_GE(array->NumberOfSlackDescriptors(), callbacks->length());
+ nof = AppendUniqueCallbacks<DescriptorArrayAppender>(callbacks, array, nof);
map->SetNumberOfOwnDescriptors(nof);
}
@@ -4753,10 +5060,9 @@ void Map::AppendCallbackDescriptors(Handle<Map> map,
int AccessorInfo::AppendUnique(Handle<Object> descriptors,
Handle<FixedArray> array,
int valid_descriptors) {
- NeanderArray callbacks(descriptors);
- DCHECK(array->length() >= callbacks.length() + valid_descriptors);
- return AppendUniqueCallbacks<FixedArrayAppender>(&callbacks,
- array,
+ Handle<TemplateList> callbacks = Handle<TemplateList>::cast(descriptors);
+ DCHECK_GE(array->length(), callbacks->length() + valid_descriptors);
+ return AppendUniqueCallbacks<FixedArrayAppender>(callbacks, array,
valid_descriptors);
}
@@ -4915,7 +5221,7 @@ Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
}
}
- DCHECK(!map->IsUndefined());
+ DCHECK(!map->IsUndefined(isolate));
// Check if we can go back in the elements kind transition chain.
if (IsHoleyElementsKind(from_kind) &&
to_kind == GetPackedElementsKind(from_kind) &&
@@ -4969,7 +5275,7 @@ void JSProxy::Revoke(Handle<JSProxy> proxy) {
Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
Handle<Name> name) {
DCHECK(!name->IsPrivate());
- STACK_CHECK(Nothing<bool>());
+ STACK_CHECK(isolate, Nothing<bool>());
// 1. (Assert)
// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
Handle<Object> handler(proxy->handler(), isolate);
@@ -4989,7 +5295,7 @@ Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
isolate->factory()->has_string()),
Nothing<bool>());
// 7. If trap is undefined, then
- if (trap->IsUndefined()) {
+ if (trap->IsUndefined(isolate)) {
// 7a. Return target.[[HasProperty]](P).
return JSReceiver::HasProperty(target, name);
}
@@ -5038,7 +5344,7 @@ Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
LanguageMode language_mode) {
DCHECK(!name->IsPrivate());
Isolate* isolate = proxy->GetIsolate();
- STACK_CHECK(Nothing<bool>());
+ STACK_CHECK(isolate, Nothing<bool>());
Factory* factory = isolate->factory();
Handle<String> trap_name = factory->set_string();
ShouldThrow should_throw =
@@ -5055,7 +5361,7 @@ Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
Handle<Object> trap;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
- if (trap->IsUndefined()) {
+ if (trap->IsUndefined(isolate)) {
LookupIterator it =
LookupIterator::PropertyOrElement(isolate, receiver, name, target);
return Object::SetSuperProperty(&it, value, language_mode,
@@ -5091,7 +5397,7 @@ Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
}
inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
!target_desc.configurable() &&
- target_desc.set()->IsUndefined();
+ target_desc.set()->IsUndefined(isolate);
if (inconsistent) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kProxySetFrozenAccessor, name));
@@ -5109,7 +5415,7 @@ Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
ShouldThrow should_throw =
is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
Isolate* isolate = proxy->GetIsolate();
- STACK_CHECK(Nothing<bool>());
+ STACK_CHECK(isolate, Nothing<bool>());
Factory* factory = isolate->factory();
Handle<String> trap_name = factory->deleteProperty_string();
@@ -5124,7 +5430,7 @@ Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
Handle<Object> trap;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
- if (trap->IsUndefined()) {
+ if (trap->IsUndefined(isolate)) {
return JSReceiver::DeletePropertyOrElement(target, name, language_mode);
}
@@ -5200,6 +5506,44 @@ MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
handle(function->bound_target_function()));
}
+// static
+MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
+ Handle<JSBoundFunction> function) {
+ Handle<String> prefix = isolate->factory()->bound__string();
+ if (!function->bound_target_function()->IsJSFunction()) return prefix;
+ Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
+ isolate);
+ Handle<Object> target_name = JSFunction::GetName(isolate, target);
+ if (!target_name->IsString()) return prefix;
+ Factory* factory = isolate->factory();
+ return factory->NewConsString(prefix, Handle<String>::cast(target_name));
+}
+
+// static
+Handle<Object> JSFunction::GetName(Isolate* isolate,
+ Handle<JSFunction> function) {
+ if (function->shared()->name_should_print_as_anonymous()) {
+ return isolate->factory()->anonymous_string();
+ }
+ return handle(function->shared()->name(), isolate);
+}
+
+// static
+MaybeHandle<Smi> JSFunction::GetLength(Isolate* isolate,
+ Handle<JSFunction> function) {
+ int length = 0;
+ if (function->shared()->is_compiled()) {
+ length = function->shared()->length();
+ } else {
+ // If the function isn't compiled yet, the length is not computed
+ // correctly yet. Compile it now and return the right length.
+ if (Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
+ length = function->shared()->length();
+ }
+ if (isolate->has_pending_exception()) return MaybeHandle<Smi>();
+ }
+ return handle(Smi::FromInt(length), isolate);
+}
// static
Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
@@ -5342,8 +5686,6 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
ShouldThrow should_throw, AccessorInfoHandling handling) {
it->UpdateProtector();
Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
- bool is_observed = object->map()->is_observed() &&
- (it->IsElement() || !it->name()->IsPrivate());
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
@@ -5403,14 +5745,6 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
it->ReconfigureDataProperty(value, attributes);
}
- if (is_observed) {
- RETURN_ON_EXCEPTION_VALUE(
- it->isolate(),
- EnqueueChangeRecord(object, "reconfigure", it->GetName(),
- it->factory()->the_hole_value()),
- Nothing<bool>());
- }
-
return Just(true);
}
case LookupIterator::INTEGER_INDEXED_EXOTIC:
@@ -5431,20 +5765,8 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
}
// Reconfigure the data property if the attributes mismatch.
- Handle<Object> old_value = it->factory()->the_hole_value();
- if (is_observed) old_value = it->GetDataValue();
-
it->ReconfigureDataProperty(value, attributes);
- if (is_observed) {
- if (old_value->SameValue(*value)) {
- old_value = it->factory()->the_hole_value();
- }
- RETURN_ON_EXCEPTION_VALUE(
- it->isolate(), EnqueueChangeRecord(object, "reconfigure",
- it->GetName(), old_value),
- Nothing<bool>());
- }
return Just(true);
}
}
@@ -5457,7 +5779,7 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
PropertyAttributes attributes) {
- DCHECK(!value->IsTheHole());
+ DCHECK(!value->IsTheHole(object->GetIsolate()));
LookupIterator it(object, name, object, LookupIterator::OWN);
return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
}
@@ -5479,73 +5801,11 @@ MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes(
return DefineOwnPropertyIgnoreAttributes(&it, value, attributes);
}
-
Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
LookupIterator* it) {
- Isolate* isolate = it->isolate();
- // Make sure that the top context does not change when doing
- // callbacks or interceptor calls.
- AssertNoContextChange ncc(isolate);
- HandleScope scope(isolate);
-
- Handle<JSObject> holder = it->GetHolder<JSObject>();
- Handle<InterceptorInfo> interceptor(it->GetInterceptor());
- if (!it->IsElement() && it->name()->IsSymbol() &&
- !interceptor->can_intercept_symbols()) {
- return Just(ABSENT);
- }
- Handle<Object> receiver = it->GetReceiver();
- if (!receiver->IsJSReceiver()) {
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
- Object::ConvertReceiver(isolate, receiver),
- Nothing<PropertyAttributes>());
- }
- PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
- *holder, Object::DONT_THROW);
- if (!interceptor->query()->IsUndefined()) {
- Handle<Object> result;
- if (it->IsElement()) {
- uint32_t index = it->index();
- v8::IndexedPropertyQueryCallback query =
- v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
- result = args.Call(query, index);
- } else {
- Handle<Name> name = it->name();
- DCHECK(!name->IsPrivate());
- v8::GenericNamedPropertyQueryCallback query =
- v8::ToCData<v8::GenericNamedPropertyQueryCallback>(
- interceptor->query());
- result = args.Call(query, name);
- }
- if (!result.is_null()) {
- int32_t value;
- CHECK(result->ToInt32(&value));
- return Just(static_cast<PropertyAttributes>(value));
- }
- } else if (!interceptor->getter()->IsUndefined()) {
- // TODO(verwaest): Use GetPropertyWithInterceptor?
- Handle<Object> result;
- if (it->IsElement()) {
- uint32_t index = it->index();
- v8::IndexedPropertyGetterCallback getter =
- v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
- result = args.Call(getter, index);
- } else {
- Handle<Name> name = it->name();
- DCHECK(!name->IsPrivate());
- v8::GenericNamedPropertyGetterCallback getter =
- v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
- interceptor->getter());
- result = args.Call(getter, name);
- }
- if (!result.is_null()) return Just(DONT_ENUM);
- }
-
- RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>());
- return Just(ABSENT);
+ return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor());
}
-
Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
LookupIterator* it) {
for (; it->IsFound(); it->Next()) {
@@ -5660,7 +5920,7 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
// Compute the length of the instance descriptor.
for (int i = 0; i < instance_descriptor_length; i++) {
int index = Smi::cast(iteration_order->get(i))->value();
- DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
+ DCHECK(dictionary->IsKey(isolate, dictionary->KeyAt(index)));
Object* value = dictionary->ValueAt(index);
PropertyType type = dictionary->DetailsAt(index).type();
@@ -5876,216 +6136,56 @@ static Smi* GenerateIdentityHash(Isolate* isolate) {
return Smi::FromInt(hash_value);
}
+template <typename ProxyType>
+static Smi* GetOrCreateIdentityHashHelper(Isolate* isolate,
+ Handle<ProxyType> proxy) {
+ Object* maybe_hash = proxy->hash();
+ if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash);
-template<typename ProxyType>
-static Handle<Smi> GetOrCreateIdentityHashHelper(Handle<ProxyType> proxy) {
- Isolate* isolate = proxy->GetIsolate();
-
- Handle<Object> maybe_hash(proxy->hash(), isolate);
- if (maybe_hash->IsSmi()) return Handle<Smi>::cast(maybe_hash);
-
- Handle<Smi> hash(GenerateIdentityHash(isolate), isolate);
- proxy->set_hash(*hash);
+ Smi* hash = GenerateIdentityHash(isolate);
+ proxy->set_hash(hash);
return hash;
}
// static
-Handle<Object> JSObject::GetIdentityHash(Isolate* isolate,
- Handle<JSObject> object) {
+Object* JSObject::GetIdentityHash(Isolate* isolate, Handle<JSObject> object) {
if (object->IsJSGlobalProxy()) {
- return handle(JSGlobalProxy::cast(*object)->hash(), isolate);
+ return JSGlobalProxy::cast(*object)->hash();
}
Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
- return JSReceiver::GetDataProperty(object, hash_code_symbol);
+ return *JSReceiver::GetDataProperty(object, hash_code_symbol);
}
// static
-Handle<Smi> JSObject::GetOrCreateIdentityHash(Handle<JSObject> object) {
+Smi* JSObject::GetOrCreateIdentityHash(Isolate* isolate,
+ Handle<JSObject> object) {
if (object->IsJSGlobalProxy()) {
- return GetOrCreateIdentityHashHelper(Handle<JSGlobalProxy>::cast(object));
+ return GetOrCreateIdentityHashHelper(isolate,
+ Handle<JSGlobalProxy>::cast(object));
}
- Isolate* isolate = object->GetIsolate();
Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
LookupIterator it(object, hash_code_symbol, object, LookupIterator::OWN);
if (it.IsFound()) {
DCHECK_EQ(LookupIterator::DATA, it.state());
- Handle<Object> maybe_hash = it.GetDataValue();
- if (maybe_hash->IsSmi()) return Handle<Smi>::cast(maybe_hash);
+ Object* maybe_hash = *it.GetDataValue();
+ if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash);
}
- Handle<Smi> hash(GenerateIdentityHash(isolate), isolate);
- CHECK(AddDataProperty(&it, hash, NONE, THROW_ON_ERROR,
+ Smi* hash = GenerateIdentityHash(isolate);
+ CHECK(AddDataProperty(&it, handle(hash, isolate), NONE, THROW_ON_ERROR,
CERTAINLY_NOT_STORE_FROM_KEYED)
.IsJust());
return hash;
}
// static
-Handle<Object> JSProxy::GetIdentityHash(Isolate* isolate,
- Handle<JSProxy> proxy) {
- return handle(proxy->hash(), isolate);
+Object* JSProxy::GetIdentityHash(Handle<JSProxy> proxy) {
+ return proxy->hash();
}
-
-Handle<Smi> JSProxy::GetOrCreateIdentityHash(Handle<JSProxy> proxy) {
- return GetOrCreateIdentityHashHelper(proxy);
-}
-
-
-Object* JSObject::GetHiddenProperty(Handle<Name> key) {
- DisallowHeapAllocation no_gc;
- DCHECK(key->IsUniqueName());
- if (IsJSGlobalProxy()) {
- // For a proxy, use the prototype as target object.
- PrototypeIterator iter(GetIsolate(), this);
- // If the proxy is detached, return undefined.
- if (iter.IsAtEnd()) return GetHeap()->the_hole_value();
- DCHECK(iter.GetCurrent()->IsJSGlobalObject());
- return iter.GetCurrent<JSObject>()->GetHiddenProperty(key);
- }
- DCHECK(!IsJSGlobalProxy());
- Object* inline_value = GetHiddenPropertiesHashTable();
-
- if (inline_value->IsUndefined()) return GetHeap()->the_hole_value();
-
- ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value);
- Object* entry = hashtable->Lookup(key);
- return entry;
-}
-
-
-Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> object,
- Handle<Name> key,
- Handle<Object> value) {
- Isolate* isolate = object->GetIsolate();
-
- DCHECK(key->IsUniqueName());
- if (object->IsJSGlobalProxy()) {
- // For a proxy, use the prototype as target object.
- PrototypeIterator iter(isolate, object);
- // If the proxy is detached, return undefined.
- if (iter.IsAtEnd()) return isolate->factory()->undefined_value();
- DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
- return SetHiddenProperty(PrototypeIterator::GetCurrent<JSObject>(iter), key,
- value);
- }
- DCHECK(!object->IsJSGlobalProxy());
-
- Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
-
- Handle<ObjectHashTable> hashtable =
- GetOrCreateHiddenPropertiesHashtable(object);
-
- // If it was found, check if the key is already in the dictionary.
- Handle<ObjectHashTable> new_table = ObjectHashTable::Put(hashtable, key,
- value);
- if (*new_table != *hashtable) {
- // If adding the key expanded the dictionary (i.e., Add returned a new
- // dictionary), store it back to the object.
- SetHiddenPropertiesHashTable(object, new_table);
- }
-
- // Return this to mark success.
- return object;
-}
-
-
-void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) {
- Isolate* isolate = object->GetIsolate();
- DCHECK(key->IsUniqueName());
-
- if (object->IsJSGlobalProxy()) {
- PrototypeIterator iter(isolate, object);
- if (iter.IsAtEnd()) return;
- DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
- return DeleteHiddenProperty(PrototypeIterator::GetCurrent<JSObject>(iter),
- key);
- }
-
- Object* inline_value = object->GetHiddenPropertiesHashTable();
-
- if (inline_value->IsUndefined()) return;
-
- Handle<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value));
- bool was_present = false;
- ObjectHashTable::Remove(hashtable, key, &was_present);
-}
-
-
-bool JSObject::HasHiddenProperties(Handle<JSObject> object) {
- Isolate* isolate = object->GetIsolate();
- Handle<Symbol> hidden = isolate->factory()->hidden_properties_symbol();
- LookupIterator it(object, hidden, object);
- Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
- // Cannot get an exception since the hidden_properties_symbol isn't exposed to
- // JS.
- DCHECK(maybe.IsJust());
- return maybe.FromJust() != ABSENT;
-}
-
-
-Object* JSObject::GetHiddenPropertiesHashTable() {
- DCHECK(!IsJSGlobalProxy());
- if (HasFastProperties()) {
- // If the object has fast properties, check whether the first slot
- // in the descriptor array matches the hidden string. Since the
- // hidden strings hash code is zero (and no other name has hash
- // code zero) it will always occupy the first entry if present.
- DescriptorArray* descriptors = this->map()->instance_descriptors();
- if (descriptors->number_of_descriptors() > 0) {
- int sorted_index = descriptors->GetSortedKeyIndex(0);
- if (descriptors->GetKey(sorted_index) ==
- GetHeap()->hidden_properties_symbol() &&
- sorted_index < map()->NumberOfOwnDescriptors()) {
- DCHECK(descriptors->GetType(sorted_index) == DATA);
- DCHECK(descriptors->GetDetails(sorted_index).representation().
- IsCompatibleForLoad(Representation::Tagged()));
- FieldIndex index = FieldIndex::ForDescriptor(this->map(),
- sorted_index);
- return this->RawFastPropertyAt(index);
- } else {
- return GetHeap()->undefined_value();
- }
- } else {
- return GetHeap()->undefined_value();
- }
- } else {
- Isolate* isolate = GetIsolate();
- Handle<Symbol> hidden = isolate->factory()->hidden_properties_symbol();
- Handle<JSObject> receiver(this, isolate);
- LookupIterator it(receiver, hidden, receiver);
- // Access check is always skipped for the hidden string anyways.
- return *GetDataProperty(&it);
- }
-}
-
-Handle<ObjectHashTable> JSObject::GetOrCreateHiddenPropertiesHashtable(
- Handle<JSObject> object) {
- Isolate* isolate = object->GetIsolate();
-
- static const int kInitialCapacity = 4;
- Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
- if (inline_value->IsHashTable()) {
- return Handle<ObjectHashTable>::cast(inline_value);
- }
-
- Handle<ObjectHashTable> hashtable = ObjectHashTable::New(
- isolate, kInitialCapacity, USE_CUSTOM_MINIMUM_CAPACITY);
-
- DCHECK(inline_value->IsUndefined());
- SetHiddenPropertiesHashTable(object, hashtable);
- return hashtable;
-}
-
-
-Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object,
- Handle<Object> value) {
- DCHECK(!object->IsJSGlobalProxy());
- Isolate* isolate = object->GetIsolate();
- Handle<Symbol> name = isolate->factory()->hidden_properties_symbol();
- SetOwnPropertyIgnoreAttributes(object, name, value, DONT_ENUM).Assert();
- return object;
+Smi* JSProxy::GetOrCreateIdentityHash(Isolate* isolate, Handle<JSProxy> proxy) {
+ return GetOrCreateIdentityHashHelper(isolate, proxy);
}
@@ -6098,7 +6198,7 @@ Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
Handle<InterceptorInfo> interceptor(it->GetInterceptor());
- if (interceptor->deleter()->IsUndefined()) return Nothing<bool>();
+ if (interceptor->deleter()->IsUndefined(isolate)) return Nothing<bool>();
Handle<JSObject> holder = it->GetHolder<JSObject>();
Handle<Object> receiver = it->GetReceiver();
@@ -6132,7 +6232,7 @@ Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
DCHECK(result->IsBoolean());
// Rebox CustomArguments::kReturnValueOffset before returning.
- return Just(result->IsTrue());
+ return Just(result->IsTrue(isolate));
}
@@ -6149,9 +6249,8 @@ void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
auto cell = PropertyCell::InvalidateEntry(dictionary, entry);
cell->set_value(isolate->heap()->the_hole_value());
- // TODO(ishell): InvalidateForDelete
cell->set_property_details(
- cell->property_details().set_cell_type(PropertyCellType::kInvalidated));
+ PropertyDetails::Empty(PropertyCellType::kUninitialized));
} else {
Handle<NameDictionary> dictionary(object->property_dictionary());
DCHECK_NE(NameDictionary::kNotFound, entry);
@@ -6185,11 +6284,6 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
}
Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
- bool is_observed = receiver->map()->is_observed() &&
- (it->IsElement() || !it->name()->IsPrivate());
-
- Handle<Object> old_value = it->factory()->the_hole_value();
-
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
case LookupIterator::JSPROXY:
@@ -6217,10 +6311,6 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
case LookupIterator::INTEGER_INDEXED_EXOTIC:
return Just(true);
case LookupIterator::DATA:
- if (is_observed) {
- old_value = it->GetDataValue();
- }
- // Fall through.
case LookupIterator::ACCESSOR: {
if (!it->IsConfigurable()) {
// Fail if the property is not configurable.
@@ -6235,13 +6325,6 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
it->Delete();
- if (is_observed) {
- RETURN_ON_EXCEPTION_VALUE(
- isolate, JSObject::EnqueueChangeRecord(receiver, "delete",
- it->GetName(), old_value),
- Nothing<bool>());
- }
-
return Just(true);
}
}
@@ -6254,7 +6337,7 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
LanguageMode language_mode) {
LookupIterator it(object->GetIsolate(), object, index, object,
- LookupIterator::HIDDEN);
+ LookupIterator::OWN);
return DeleteProperty(&it, language_mode);
}
@@ -6262,7 +6345,7 @@ Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index,
Maybe<bool> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
Handle<Name> name,
LanguageMode language_mode) {
- LookupIterator it(object, name, object, LookupIterator::HIDDEN);
+ LookupIterator it(object, name, object, LookupIterator::OWN);
return DeleteProperty(&it, language_mode);
}
@@ -6271,13 +6354,15 @@ Maybe<bool> JSReceiver::DeletePropertyOrElement(Handle<JSReceiver> object,
Handle<Name> name,
LanguageMode language_mode) {
LookupIterator it = LookupIterator::PropertyOrElement(
- name->GetIsolate(), object, name, object, LookupIterator::HIDDEN);
+ name->GetIsolate(), object, name, object, LookupIterator::OWN);
return DeleteProperty(&it, language_mode);
}
// ES6 7.1.14
-MaybeHandle<Object> ToPropertyKey(Isolate* isolate, Handle<Object> value) {
+// static
+MaybeHandle<Object> Object::ToPropertyKey(Isolate* isolate,
+ Handle<Object> value) {
// 1. Let key be ToPrimitive(argument, hint String).
MaybeHandle<Object> maybe_key =
Object::ToPrimitive(value, ToPrimitiveHint::kString);
@@ -6348,16 +6433,15 @@ MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
// 2. Let props be ToObject(Properties).
// 3. ReturnIfAbrupt(props).
Handle<JSReceiver> props;
- if (!Object::ToObject(isolate, properties).ToHandle(&props)) {
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
- Object);
- }
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, props,
+ Object::ToObject(isolate, properties), Object);
+
// 4. Let keys be props.[[OwnPropertyKeys]]().
// 5. ReturnIfAbrupt(keys).
Handle<FixedArray> keys;
ASSIGN_RETURN_ON_EXCEPTION(
- isolate, keys, JSReceiver::GetKeys(props, OWN_ONLY, ALL_PROPERTIES),
+ isolate, keys, KeyAccumulator::GetKeys(props, KeyCollectionMode::kOwnOnly,
+ ALL_PROPERTIES),
Object);
// 6. Let descriptors be an empty List.
int capacity = keys->length();
@@ -6370,7 +6454,7 @@ MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
// 7b. ReturnIfAbrupt(propDesc).
bool success = false;
LookupIterator it = LookupIterator::PropertyOrElement(
- isolate, props, next_key, &success, LookupIterator::HIDDEN);
+ isolate, props, next_key, &success, LookupIterator::OWN);
DCHECK(success);
Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
if (!maybe.IsJust()) return MaybeHandle<Object>();
@@ -6445,7 +6529,7 @@ Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
bool success = false;
DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
LookupIterator it = LookupIterator::PropertyOrElement(
- isolate, object, key, &success, LookupIterator::HIDDEN);
+ isolate, object, key, &success, LookupIterator::OWN);
DCHECK(success); // ...so creating a LookupIterator can't fail.
// Deal with access checks first.
@@ -6990,10 +7074,7 @@ Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a,
// (Not needed.)
}
// Most of steps 16 through 19 is implemented by JSArray::SetLength.
- if (JSArray::ObservableSetLength(a, new_len).is_null()) {
- DCHECK(isolate->has_pending_exception());
- return Nothing<bool>();
- }
+ JSArray::SetLength(a, new_len);
// Steps 19d-ii, 20.
if (!new_writable) {
PropertyDescriptor readonly;
@@ -7025,7 +7106,7 @@ Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
Handle<Object> key,
PropertyDescriptor* desc,
ShouldThrow should_throw) {
- STACK_CHECK(Nothing<bool>());
+ STACK_CHECK(isolate, Nothing<bool>());
if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) {
return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc,
should_throw);
@@ -7051,7 +7132,7 @@ Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
Nothing<bool>());
// 7. If trap is undefined, then:
- if (trap->IsUndefined()) {
+ if (trap->IsUndefined(isolate)) {
// 7a. Return target.[[DefineOwnProperty]](P, Desc).
return JSReceiver::DefineOwnProperty(isolate, target, key, desc,
should_throw);
@@ -7175,7 +7256,7 @@ Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
bool success = false;
DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey...
LookupIterator it = LookupIterator::PropertyOrElement(
- isolate, object, key, &success, LookupIterator::HIDDEN);
+ isolate, object, key, &success, LookupIterator::OWN);
DCHECK(success); // ...so creating a LookupIterator can't fail.
return GetOwnPropertyDescriptor(&it, desc);
}
@@ -7246,7 +7327,7 @@ Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
Handle<Name> name,
PropertyDescriptor* desc) {
DCHECK(!name->IsPrivate());
- STACK_CHECK(Nothing<bool>());
+ STACK_CHECK(isolate, Nothing<bool>());
Handle<String> trap_name =
isolate->factory()->getOwnPropertyDescriptor_string();
@@ -7269,7 +7350,7 @@ Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
Nothing<bool>());
// 7. If trap is undefined, then
- if (trap->IsUndefined()) {
+ if (trap->IsUndefined(isolate)) {
// 7a. Return target.[[GetOwnProperty]](P).
return JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, desc);
}
@@ -7282,7 +7363,8 @@ Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
Nothing<bool>());
// 9. If Type(trapResultObj) is neither Object nor Undefined, throw a
// TypeError exception.
- if (!trap_result_obj->IsJSReceiver() && !trap_result_obj->IsUndefined()) {
+ if (!trap_result_obj->IsJSReceiver() &&
+ !trap_result_obj->IsUndefined(isolate)) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kProxyGetOwnPropertyDescriptorInvalid, name));
return Nothing<bool>();
@@ -7293,7 +7375,7 @@ Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
MAYBE_RETURN(found, Nothing<bool>());
// 11. If trapResultObj is undefined, then
- if (trap_result_obj->IsUndefined()) {
+ if (trap_result_obj->IsUndefined(isolate)) {
// 11a. If targetDesc is undefined, return undefined.
if (!found.FromJust()) return Just(false);
// 11b. If targetDesc.[[Configurable]] is false, throw a TypeError
@@ -7358,19 +7440,20 @@ Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
ElementsKind kind,
Object* object) {
+ Isolate* isolate = elements->GetIsolate();
if (IsFastObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) {
int length = IsJSArray()
? Smi::cast(JSArray::cast(this)->length())->value()
: elements->length();
for (int i = 0; i < length; ++i) {
Object* element = elements->get(i);
- if (!element->IsTheHole() && element == object) return true;
+ if (!element->IsTheHole(isolate) && element == object) return true;
}
} else {
DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS);
Object* key =
SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
- if (!key->IsUndefined()) return true;
+ if (!key->IsUndefined(isolate)) return true;
}
return false;
}
@@ -7394,7 +7477,7 @@ bool JSObject::ReferencesObject(Object* obj) {
// Check if the object is among the named properties.
Object* key = SlowReverseLookup(obj);
- if (!key->IsUndefined()) {
+ if (!key->IsUndefined(heap->isolate())) {
return true;
}
@@ -7432,7 +7515,7 @@ bool JSObject::ReferencesObject(Object* obj) {
int length = parameter_map->length();
for (int i = 2; i < length; ++i) {
Object* value = parameter_map->get(i);
- if (!value->IsTheHole() && value == obj) return true;
+ if (!value->IsTheHole(heap->isolate()) && value == obj) return true;
}
// Check the arguments.
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
@@ -7500,8 +7583,7 @@ Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
if (receiver->IsJSObject()) {
Handle<JSObject> object = Handle<JSObject>::cast(receiver);
- if (!object->HasSloppyArgumentsElements() &&
- !object->map()->is_observed()) { // Fast path.
+ if (!object->HasSloppyArgumentsElements()) { // Fast path.
if (level == SEALED) {
return JSObject::PreventExtensionsWithTransition<SEALED>(object,
should_throw);
@@ -7605,7 +7687,7 @@ Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
ShouldThrow should_throw) {
Isolate* isolate = proxy->GetIsolate();
- STACK_CHECK(Nothing<bool>());
+ STACK_CHECK(isolate, Nothing<bool>());
Factory* factory = isolate->factory();
Handle<String> trap_name = factory->preventExtensions_string();
@@ -7620,7 +7702,7 @@ Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
Handle<Object> trap;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
- if (trap->IsUndefined()) {
+ if (trap->IsUndefined(isolate)) {
return JSReceiver::PreventExtensions(target, should_throw);
}
@@ -7652,7 +7734,7 @@ Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
ShouldThrow should_throw) {
Isolate* isolate = object->GetIsolate();
- if (!object->HasSloppyArgumentsElements() && !object->map()->is_observed()) {
+ if (!object->HasSloppyArgumentsElements()) {
return PreventExtensionsWithTransition<NONE>(object, should_throw);
}
@@ -7693,13 +7775,6 @@ Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object,
JSObject::MigrateToMap(object, new_map);
DCHECK(!object->map()->is_extensible());
- if (object->map()->is_observed()) {
- RETURN_ON_EXCEPTION_VALUE(
- isolate,
- EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
- isolate->factory()->the_hole_value()),
- Nothing<bool>());
- }
return Just(true);
}
@@ -7714,7 +7789,7 @@ Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
Isolate* isolate = proxy->GetIsolate();
- STACK_CHECK(Nothing<bool>());
+ STACK_CHECK(isolate, Nothing<bool>());
Factory* factory = isolate->factory();
Handle<String> trap_name = factory->isExtensible_string();
@@ -7729,7 +7804,7 @@ Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
Handle<Object> trap;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
- if (trap->IsUndefined()) {
+ if (trap->IsUndefined(isolate)) {
return JSReceiver::IsExtensible(target);
}
@@ -7773,9 +7848,10 @@ template <typename Dictionary>
static void ApplyAttributesToDictionary(Dictionary* dictionary,
const PropertyAttributes attributes) {
int capacity = dictionary->Capacity();
+ Isolate* isolate = dictionary->GetIsolate();
for (int i = 0; i < capacity; i++) {
Object* k = dictionary->KeyAt(i);
- if (dictionary->IsKey(k) &&
+ if (dictionary->IsKey(isolate, k) &&
!(k->IsSymbol() && Symbol::cast(k)->is_private())) {
PropertyDetails details = dictionary->DetailsAt(i);
int attrs = attributes;
@@ -7800,7 +7876,6 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
// Sealing/freezing sloppy arguments should be handled elsewhere.
DCHECK(!object->HasSloppyArgumentsElements());
- DCHECK(!object->map()->is_observed());
Isolate* isolate = object->GetIsolate();
if (object->IsAccessCheckNeeded() &&
@@ -7919,28 +7994,6 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
}
-void JSObject::SetObserved(Handle<JSObject> object) {
- DCHECK(!object->IsJSGlobalProxy());
- DCHECK(!object->IsJSGlobalObject());
- Isolate* isolate = object->GetIsolate();
- Handle<Map> new_map;
- Handle<Map> old_map(object->map(), isolate);
- DCHECK(!old_map->is_observed());
- Map* transition = TransitionArray::SearchSpecial(
- *old_map, isolate->heap()->observed_symbol());
- if (transition != NULL) {
- new_map = handle(transition, isolate);
- DCHECK(new_map->is_observed());
- } else if (TransitionArray::CanHaveMoreTransitions(old_map)) {
- new_map = Map::CopyForObserved(old_map);
- } else {
- new_map = Map::Copy(old_map, "SlowObserved");
- new_map->set_is_observed();
- }
- JSObject::MigrateToMap(object, new_map);
-}
-
-
Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
Representation representation,
FieldIndex index) {
@@ -8069,9 +8122,8 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
// an array.
PropertyFilter filter = static_cast<PropertyFilter>(
ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE);
- KeyAccumulator accumulator(isolate, OWN_ONLY, filter);
- accumulator.NextPrototype();
- copy->CollectOwnPropertyNames(&accumulator, filter);
+ KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly, filter);
+ accumulator.CollectOwnPropertyNames(copy, copy);
Handle<FixedArray> names = accumulator.GetKeys();
for (int i = 0; i < names->length(); i++) {
DCHECK(names->get(i)->IsName());
@@ -8126,7 +8178,7 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
int capacity = element_dictionary->Capacity();
for (int i = 0; i < capacity; i++) {
Object* k = element_dictionary->KeyAt(i);
- if (element_dictionary->IsKey(k)) {
+ if (element_dictionary->IsKey(isolate, k)) {
Handle<Object> value(element_dictionary->ValueAt(i), isolate);
if (value->IsJSObject()) {
Handle<JSObject> result;
@@ -8205,19 +8257,9 @@ MaybeHandle<Object> JSReceiver::ToPrimitive(Handle<JSReceiver> receiver,
ASSIGN_RETURN_ON_EXCEPTION(
isolate, exotic_to_prim,
GetMethod(receiver, isolate->factory()->to_primitive_symbol()), Object);
- if (!exotic_to_prim->IsUndefined()) {
- Handle<Object> hint_string;
- switch (hint) {
- case ToPrimitiveHint::kDefault:
- hint_string = isolate->factory()->default_string();
- break;
- case ToPrimitiveHint::kNumber:
- hint_string = isolate->factory()->number_string();
- break;
- case ToPrimitiveHint::kString:
- hint_string = isolate->factory()->string_string();
- break;
- }
+ if (!exotic_to_prim->IsUndefined(isolate)) {
+ Handle<Object> hint_string =
+ isolate->factory()->ToPrimitiveHintString(hint);
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result,
@@ -8335,28 +8377,6 @@ bool JSObject::HasEnumerableElements() {
return true;
}
-// Tests for the fast common case for property enumeration:
-// - This object and all prototypes has an enum cache (which means that
-// it is no proxy, has no interceptors and needs no access checks).
-// - This object has no elements.
-// - No prototype has enumerable properties/elements.
-bool JSReceiver::IsSimpleEnum() {
- for (PrototypeIterator iter(GetIsolate(), this,
- PrototypeIterator::START_AT_RECEIVER);
- !iter.IsAtEnd(); iter.Advance()) {
- if (!iter.GetCurrent()->IsJSObject()) return false;
- JSObject* current = iter.GetCurrent<JSObject>();
- int enum_length = current->map()->EnumLength();
- if (enum_length == kInvalidEnumCacheSentinel) return false;
- if (current->IsAccessCheckNeeded()) return false;
- DCHECK(!current->HasNamedInterceptor());
- DCHECK(!current->HasIndexedInterceptor());
- if (current->HasEnumerableElements()) return false;
- if (current != this && enum_length != 0) return false;
- }
- return true;
-}
-
int Map::NumberOfDescribedProperties(DescriptorFlag which,
PropertyFilter filter) {
@@ -8390,447 +8410,14 @@ int Map::NextFreePropertyIndex() {
}
-static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
- int len = array->length();
- for (int i = 0; i < len; i++) {
- Object* e = array->get(i);
- if (!(e->IsName() || e->IsNumber())) return false;
- }
- return true;
-}
-
-
-static Handle<FixedArray> ReduceFixedArrayTo(
- Handle<FixedArray> array, int length) {
- DCHECK_LE(length, array->length());
- if (array->length() == length) return array;
- return array->GetIsolate()->factory()->CopyFixedArrayUpTo(array, length);
-}
-
bool Map::OnlyHasSimpleProperties() {
// Wrapped string elements aren't explicitly stored in the elements backing
// store, but are loaded indirectly from the underlying string.
return !IsStringWrapperElementsKind(elements_kind()) &&
- (instance_type() > LAST_SPECIAL_RECEIVER_TYPE &&
- instance_type() != JS_GLOBAL_PROXY_TYPE) &&
+ instance_type() > LAST_SPECIAL_RECEIVER_TYPE &&
!has_hidden_prototype() && !is_dictionary_map();
}
-// static
-Handle<FixedArray> JSObject::GetFastEnumPropertyKeys(Isolate* isolate,
- Handle<JSObject> object) {
- Handle<Map> map(object->map());
- bool cache_enum_length = map->OnlyHasSimpleProperties();
-
- Handle<DescriptorArray> descs =
- Handle<DescriptorArray>(map->instance_descriptors(), isolate);
- int own_property_count = map->EnumLength();
- // If the enum length of the given map is set to kInvalidEnumCache, this
- // means that the map itself has never used the present enum cache. The
- // first step to using the cache is to set the enum length of the map by
- // counting the number of own descriptors that are ENUMERABLE_STRINGS.
- if (own_property_count == kInvalidEnumCacheSentinel) {
- own_property_count =
- map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS);
- } else {
- DCHECK(
- own_property_count ==
- map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS));
- }
-
- if (descs->HasEnumCache()) {
- Handle<FixedArray> keys(descs->GetEnumCache(), isolate);
- // In case the number of properties required in the enum are actually
- // present, we can reuse the enum cache. Otherwise, this means that the
- // enum cache was generated for a previous (smaller) version of the
- // Descriptor Array. In that case we regenerate the enum cache.
- if (own_property_count <= keys->length()) {
- isolate->counters()->enum_cache_hits()->Increment();
- if (cache_enum_length) map->SetEnumLength(own_property_count);
- return ReduceFixedArrayTo(keys, own_property_count);
- }
- }
-
- if (descs->IsEmpty()) {
- isolate->counters()->enum_cache_hits()->Increment();
- if (cache_enum_length) map->SetEnumLength(0);
- return isolate->factory()->empty_fixed_array();
- }
-
- isolate->counters()->enum_cache_misses()->Increment();
-
- Handle<FixedArray> storage =
- isolate->factory()->NewFixedArray(own_property_count);
- Handle<FixedArray> indices =
- isolate->factory()->NewFixedArray(own_property_count);
-
- int size = map->NumberOfOwnDescriptors();
- int index = 0;
-
- for (int i = 0; i < size; i++) {
- PropertyDetails details = descs->GetDetails(i);
- if (details.IsDontEnum()) continue;
- Object* key = descs->GetKey(i);
- if (key->IsSymbol()) continue;
- storage->set(index, key);
- if (!indices.is_null()) {
- if (details.type() != DATA) {
- indices = Handle<FixedArray>();
- } else {
- FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
- int load_by_field_index = field_index.GetLoadByFieldIndex();
- indices->set(index, Smi::FromInt(load_by_field_index));
- }
- }
- index++;
- }
- DCHECK(index == storage->length());
-
- DescriptorArray::SetEnumCache(descs, isolate, storage, indices);
- if (cache_enum_length) {
- map->SetEnumLength(own_property_count);
- }
- return storage;
-}
-
-
-Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object) {
- Isolate* isolate = object->GetIsolate();
- if (object->HasFastProperties()) {
- return GetFastEnumPropertyKeys(isolate, object);
- } else if (object->IsJSGlobalObject()) {
- Handle<GlobalDictionary> dictionary(object->global_dictionary());
- int length = dictionary->NumberOfEnumElements();
- if (length == 0) {
- return isolate->factory()->empty_fixed_array();
- }
- Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
- dictionary->CopyEnumKeysTo(*storage);
- return storage;
- } else {
- Handle<NameDictionary> dictionary(object->property_dictionary());
- int length = dictionary->NumberOfEnumElements();
- if (length == 0) {
- return isolate->factory()->empty_fixed_array();
- }
- Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
- dictionary->CopyEnumKeysTo(*storage);
- return storage;
- }
-}
-
-
-enum IndexedOrNamed { kIndexed, kNamed };
-
-
-// Returns |true| on success, |nothing| on exception.
-template <class Callback, IndexedOrNamed type>
-static Maybe<bool> GetKeysFromInterceptor(Isolate* isolate,
- Handle<JSReceiver> receiver,
- Handle<JSObject> object,
- PropertyFilter filter,
- KeyAccumulator* accumulator) {
- if (type == kIndexed) {
- if (!object->HasIndexedInterceptor()) return Just(true);
- } else {
- if (!object->HasNamedInterceptor()) return Just(true);
- }
- Handle<InterceptorInfo> interceptor(type == kIndexed
- ? object->GetIndexedInterceptor()
- : object->GetNamedInterceptor(),
- isolate);
- if ((filter & ONLY_ALL_CAN_READ) && !interceptor->all_can_read()) {
- return Just(true);
- }
- PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
- *object, Object::DONT_THROW);
- Handle<JSObject> result;
- if (!interceptor->enumerator()->IsUndefined()) {
- Callback enum_fun = v8::ToCData<Callback>(interceptor->enumerator());
- const char* log_tag = type == kIndexed ? "interceptor-indexed-enum"
- : "interceptor-named-enum";
- LOG(isolate, ApiObjectAccess(log_tag, *object));
- result = args.Call(enum_fun);
- }
- RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
- if (result.is_null()) return Just(true);
- DCHECK(result->IsJSArray() || result->HasSloppyArgumentsElements());
- // The accumulator takes care of string/symbol filtering.
- if (type == kIndexed) {
- accumulator->AddElementKeysFromInterceptor(result);
- } else {
- accumulator->AddKeys(result, DO_NOT_CONVERT);
- }
- return Just(true);
-}
-
-
-// Returns |true| on success, |false| if prototype walking should be stopped,
-// |nothing| if an exception was thrown.
-static Maybe<bool> GetKeysFromJSObject(Isolate* isolate,
- Handle<JSReceiver> receiver,
- Handle<JSObject> object,
- PropertyFilter* filter,
- KeyCollectionType type,
- KeyAccumulator* accumulator) {
- accumulator->NextPrototype();
- // Check access rights if required.
- if (object->IsAccessCheckNeeded() &&
- !isolate->MayAccess(handle(isolate->context()), object)) {
- // The cross-origin spec says that [[Enumerate]] shall return an empty
- // iterator when it doesn't have access...
- if (type == INCLUDE_PROTOS) {
- return Just(false);
- }
- // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties.
- DCHECK_EQ(OWN_ONLY, type);
- *filter = static_cast<PropertyFilter>(*filter | ONLY_ALL_CAN_READ);
- }
-
- JSObject::CollectOwnElementKeys(object, accumulator, *filter);
-
- // Add the element keys from the interceptor.
- Maybe<bool> success =
- GetKeysFromInterceptor<v8::IndexedPropertyEnumeratorCallback, kIndexed>(
- isolate, receiver, object, *filter, accumulator);
- MAYBE_RETURN(success, Nothing<bool>());
-
- if (*filter == ENUMERABLE_STRINGS) {
- Handle<FixedArray> enum_keys = JSObject::GetEnumPropertyKeys(object);
- accumulator->AddKeys(enum_keys, DO_NOT_CONVERT);
- } else {
- object->CollectOwnPropertyNames(accumulator, *filter);
- }
-
- // Add the property keys from the interceptor.
- success = GetKeysFromInterceptor<v8::GenericNamedPropertyEnumeratorCallback,
- kNamed>(isolate, receiver, object, *filter,
- accumulator);
- MAYBE_RETURN(success, Nothing<bool>());
- return Just(true);
-}
-
-
-// Helper function for JSReceiver::GetKeys() below. Can be called recursively.
-// Returns |true| or |nothing|.
-static Maybe<bool> GetKeys_Internal(Isolate* isolate,
- Handle<JSReceiver> receiver,
- Handle<JSReceiver> object,
- KeyCollectionType type,
- PropertyFilter filter,
- KeyAccumulator* accumulator) {
- // Proxies have no hidden prototype and we should not trigger the
- // [[GetPrototypeOf]] trap on the last iteration when using
- // AdvanceFollowingProxies.
- if (type == OWN_ONLY && object->IsJSProxy()) {
- MAYBE_RETURN(JSProxy::OwnPropertyKeys(isolate, receiver,
- Handle<JSProxy>::cast(object), filter,
- accumulator),
- Nothing<bool>());
- return Just(true);
- }
-
- PrototypeIterator::WhereToEnd end = type == OWN_ONLY
- ? PrototypeIterator::END_AT_NON_HIDDEN
- : PrototypeIterator::END_AT_NULL;
- for (PrototypeIterator iter(isolate, object,
- PrototypeIterator::START_AT_RECEIVER, end);
- !iter.IsAtEnd();) {
- Handle<JSReceiver> current =
- PrototypeIterator::GetCurrent<JSReceiver>(iter);
- Maybe<bool> result = Just(false); // Dummy initialization.
- if (current->IsJSProxy()) {
- result = JSProxy::OwnPropertyKeys(isolate, receiver,
- Handle<JSProxy>::cast(current), filter,
- accumulator);
- } else {
- DCHECK(current->IsJSObject());
- result = GetKeysFromJSObject(isolate, receiver,
- Handle<JSObject>::cast(current), &filter,
- type, accumulator);
- }
- MAYBE_RETURN(result, Nothing<bool>());
- if (!result.FromJust()) break; // |false| means "stop iterating".
- // Iterate through proxies but ignore access checks for the ALL_CAN_READ
- // case on API objects for OWN_ONLY keys handlede in GgetKeysFromJSObject.
- if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) {
- return Nothing<bool>();
- }
- }
- return Just(true);
-}
-
-
-// ES6 9.5.12
-// Returns |true| on success, |nothing| in case of exception.
-// static
-Maybe<bool> JSProxy::OwnPropertyKeys(Isolate* isolate,
- Handle<JSReceiver> receiver,
- Handle<JSProxy> proxy,
- PropertyFilter filter,
- KeyAccumulator* accumulator) {
- STACK_CHECK(Nothing<bool>());
- // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
- Handle<Object> handler(proxy->handler(), isolate);
- // 2. If handler is null, throw a TypeError exception.
- // 3. Assert: Type(handler) is Object.
- if (proxy->IsRevoked()) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kProxyRevoked, isolate->factory()->ownKeys_string()));
- return Nothing<bool>();
- }
- // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
- Handle<JSReceiver> target(proxy->target(), isolate);
- // 5. Let trap be ? GetMethod(handler, "ownKeys").
- Handle<Object> trap;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
- isolate->factory()->ownKeys_string()),
- Nothing<bool>());
- // 6. If trap is undefined, then
- if (trap->IsUndefined()) {
- // 6a. Return target.[[OwnPropertyKeys]]().
- return GetKeys_Internal(isolate, receiver, target, OWN_ONLY, filter,
- accumulator);
- }
- // 7. Let trapResultArray be Call(trap, handler, «target»).
- Handle<Object> trap_result_array;
- Handle<Object> args[] = {target};
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate, trap_result_array,
- Execution::Call(isolate, trap, handler, arraysize(args), args),
- Nothing<bool>());
- // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray,
- // «String, Symbol»).
- Handle<FixedArray> trap_result;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate, trap_result,
- Object::CreateListFromArrayLike(isolate, trap_result_array,
- ElementTypes::kStringAndSymbol),
- Nothing<bool>());
- // 9. Let extensibleTarget be ? IsExtensible(target).
- Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
- MAYBE_RETURN(maybe_extensible, Nothing<bool>());
- bool extensible_target = maybe_extensible.FromJust();
- // 10. Let targetKeys be ? target.[[OwnPropertyKeys]]().
- Handle<FixedArray> target_keys;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_keys,
- JSReceiver::OwnPropertyKeys(target),
- Nothing<bool>());
- // 11. (Assert)
- // 12. Let targetConfigurableKeys be an empty List.
- // To save memory, we're re-using target_keys and will modify it in-place.
- Handle<FixedArray> target_configurable_keys = target_keys;
- // 13. Let targetNonconfigurableKeys be an empty List.
- Handle<FixedArray> target_nonconfigurable_keys =
- isolate->factory()->NewFixedArray(target_keys->length());
- int nonconfigurable_keys_length = 0;
- // 14. Repeat, for each element key of targetKeys:
- for (int i = 0; i < target_keys->length(); ++i) {
- // 14a. Let desc be ? target.[[GetOwnProperty]](key).
- PropertyDescriptor desc;
- Maybe<bool> found = JSReceiver::GetOwnPropertyDescriptor(
- isolate, target, handle(target_keys->get(i), isolate), &desc);
- MAYBE_RETURN(found, Nothing<bool>());
- // 14b. If desc is not undefined and desc.[[Configurable]] is false, then
- if (found.FromJust() && !desc.configurable()) {
- // 14b i. Append key as an element of targetNonconfigurableKeys.
- target_nonconfigurable_keys->set(nonconfigurable_keys_length,
- target_keys->get(i));
- nonconfigurable_keys_length++;
- // The key was moved, null it out in the original list.
- target_keys->set(i, Smi::FromInt(0));
- } else {
- // 14c. Else,
- // 14c i. Append key as an element of targetConfigurableKeys.
- // (No-op, just keep it in |target_keys|.)
- }
- }
- accumulator->NextPrototype(); // Prepare for accumulating keys.
- // 15. If extensibleTarget is true and targetNonconfigurableKeys is empty,
- // then:
- if (extensible_target && nonconfigurable_keys_length == 0) {
- // 15a. Return trapResult.
- return accumulator->AddKeysFromProxy(proxy, trap_result);
- }
- // 16. Let uncheckedResultKeys be a new List which is a copy of trapResult.
- Zone set_zone(isolate->allocator());
- const int kPresent = 1;
- const int kGone = 0;
- IdentityMap<int> unchecked_result_keys(isolate->heap(), &set_zone);
- int unchecked_result_keys_size = 0;
- for (int i = 0; i < trap_result->length(); ++i) {
- DCHECK(trap_result->get(i)->IsUniqueName());
- Object* key = trap_result->get(i);
- int* entry = unchecked_result_keys.Get(key);
- if (*entry != kPresent) {
- *entry = kPresent;
- unchecked_result_keys_size++;
- }
- }
- // 17. Repeat, for each key that is an element of targetNonconfigurableKeys:
- for (int i = 0; i < nonconfigurable_keys_length; ++i) {
- Object* key = target_nonconfigurable_keys->get(i);
- // 17a. If key is not an element of uncheckedResultKeys, throw a
- // TypeError exception.
- int* found = unchecked_result_keys.Find(key);
- if (found == nullptr || *found == kGone) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate)));
- return Nothing<bool>();
- }
- // 17b. Remove key from uncheckedResultKeys.
- *found = kGone;
- unchecked_result_keys_size--;
- }
- // 18. If extensibleTarget is true, return trapResult.
- if (extensible_target) {
- return accumulator->AddKeysFromProxy(proxy, trap_result);
- }
- // 19. Repeat, for each key that is an element of targetConfigurableKeys:
- for (int i = 0; i < target_configurable_keys->length(); ++i) {
- Object* key = target_configurable_keys->get(i);
- if (key->IsSmi()) continue; // Zapped entry, was nonconfigurable.
- // 19a. If key is not an element of uncheckedResultKeys, throw a
- // TypeError exception.
- int* found = unchecked_result_keys.Find(key);
- if (found == nullptr || *found == kGone) {
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate)));
- return Nothing<bool>();
- }
- // 19b. Remove key from uncheckedResultKeys.
- *found = kGone;
- unchecked_result_keys_size--;
- }
- // 20. If uncheckedResultKeys is not empty, throw a TypeError exception.
- if (unchecked_result_keys_size != 0) {
- DCHECK_GT(unchecked_result_keys_size, 0);
- isolate->Throw(*isolate->factory()->NewTypeError(
- MessageTemplate::kProxyOwnKeysNonExtensible));
- return Nothing<bool>();
- }
- // 21. Return trapResult.
- return accumulator->AddKeysFromProxy(proxy, trap_result);
-}
-
-MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
- KeyCollectionType type,
- PropertyFilter filter,
- GetKeysConversion keys_conversion,
- bool filter_proxy_keys) {
- USE(ContainsOnlyValidKeys);
- Isolate* isolate = object->GetIsolate();
- KeyAccumulator accumulator(isolate, type, filter);
- accumulator.set_filter_proxy_keys(filter_proxy_keys);
- MAYBE_RETURN(
- GetKeys_Internal(isolate, object, object, type, filter, &accumulator),
- MaybeHandle<FixedArray>());
- Handle<FixedArray> keys = accumulator.GetKeys(keys_conversion);
- DCHECK(ContainsOnlyValidKeys(keys));
- return keys;
-}
-
MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
Isolate* isolate, Handle<JSReceiver> receiver, bool get_entries,
Handle<FixedArray>* result) {
@@ -8921,12 +8508,13 @@ MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
PropertyFilter key_filter =
static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
- KeyAccumulator accumulator(isolate, OWN_ONLY, key_filter);
- MAYBE_RETURN(GetKeys_Internal(isolate, object, object, OWN_ONLY, key_filter,
- &accumulator),
- MaybeHandle<FixedArray>());
- Handle<FixedArray> keys = accumulator.GetKeys(CONVERT_TO_STRING);
- DCHECK(ContainsOnlyValidKeys(keys));
+
+ Handle<FixedArray> keys;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, keys,
+ KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, key_filter,
+ GetKeysConversion::kConvertToString),
+ MaybeHandle<FixedArray>());
values_or_entries = isolate->factory()->NewFixedArray(keys->length());
int length = 0;
@@ -9011,7 +8599,7 @@ MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
Isolate* isolate = object->GetIsolate();
LookupIterator it = LookupIterator::PropertyOrElement(
- isolate, object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
+ isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
return DefineAccessor(&it, getter, setter, attributes);
}
@@ -9039,40 +8627,11 @@ MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
return it->factory()->undefined_value();
}
- Handle<Object> old_value = isolate->factory()->the_hole_value();
- bool is_observed = object->map()->is_observed() &&
- (it->IsElement() || !it->name()->IsPrivate());
- bool preexists = false;
- if (is_observed) {
- CHECK(GetPropertyAttributes(it).IsJust());
- preexists = it->IsFound();
- if (preexists && (it->state() == LookupIterator::DATA ||
- it->GetAccessors()->IsAccessorInfo())) {
- old_value = Object::GetProperty(it).ToHandleChecked();
- }
- }
-
- DCHECK(getter->IsCallable() || getter->IsUndefined() || getter->IsNull() ||
- getter->IsFunctionTemplateInfo());
- DCHECK(setter->IsCallable() || setter->IsUndefined() || setter->IsNull() ||
- getter->IsFunctionTemplateInfo());
- // At least one of the accessors needs to be a new value.
- DCHECK(!getter->IsNull() || !setter->IsNull());
- if (!getter->IsNull()) {
- it->TransitionToAccessorProperty(ACCESSOR_GETTER, getter, attributes);
- }
- if (!setter->IsNull()) {
- it->TransitionToAccessorProperty(ACCESSOR_SETTER, setter, attributes);
- }
-
- if (is_observed) {
- // Make sure the top context isn't changed.
- AssertNoContextChange ncc(isolate);
- const char* type = preexists ? "reconfigure" : "add";
- RETURN_ON_EXCEPTION(
- isolate, EnqueueChangeRecord(object, type, it->GetName(), old_value),
- Object);
- }
+ DCHECK(getter->IsCallable() || getter->IsUndefined(isolate) ||
+ getter->IsNull(isolate) || getter->IsFunctionTemplateInfo());
+ DCHECK(setter->IsCallable() || setter->IsUndefined(isolate) ||
+ setter->IsNull(isolate) || setter->IsFunctionTemplateInfo());
+ it->TransitionToAccessorProperty(getter, setter, attributes);
return isolate->factory()->undefined_value();
}
@@ -9084,7 +8643,7 @@ MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
Handle<Name> name(Name::cast(info->name()), isolate);
LookupIterator it = LookupIterator::PropertyOrElement(
- isolate, object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
+ isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
// Duplicate ACCESS_CHECK outside of GetPropertyAttributes for the case that
// the FailedAccessCheckCallbackFunction doesn't throw an exception.
@@ -9118,53 +8677,6 @@ MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
return object;
}
-
-MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
- Handle<Name> name,
- AccessorComponent component) {
- Isolate* isolate = object->GetIsolate();
-
- // Make sure that the top context does not change when doing callbacks or
- // interceptor calls.
- AssertNoContextChange ncc(isolate);
-
- LookupIterator it = LookupIterator::PropertyOrElement(
- isolate, object, name, LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
-
- for (; it.IsFound(); it.Next()) {
- switch (it.state()) {
- case LookupIterator::INTERCEPTOR:
- case LookupIterator::NOT_FOUND:
- case LookupIterator::TRANSITION:
- UNREACHABLE();
-
- case LookupIterator::ACCESS_CHECK:
- if (it.HasAccess()) continue;
- isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
- return isolate->factory()->undefined_value();
-
- case LookupIterator::JSPROXY:
- return isolate->factory()->undefined_value();
-
- case LookupIterator::INTEGER_INDEXED_EXOTIC:
- return isolate->factory()->undefined_value();
- case LookupIterator::DATA:
- continue;
- case LookupIterator::ACCESSOR: {
- Handle<Object> maybe_pair = it.GetAccessors();
- if (maybe_pair->IsAccessorPair()) {
- return AccessorPair::GetComponent(
- Handle<AccessorPair>::cast(maybe_pair), component);
- }
- }
- }
- }
-
- return isolate->factory()->undefined_value();
-}
-
-
Object* JSObject::SlowReverseLookup(Object* value) {
if (HasFastProperties()) {
int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
@@ -9236,7 +8748,8 @@ Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
Isolate* isolate = fast_map->GetIsolate();
Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
isolate);
- bool use_cache = !fast_map->is_prototype_map() && !maybe_cache->IsUndefined();
+ bool use_cache =
+ !fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate);
Handle<NormalizedMapCache> cache;
if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
@@ -9319,6 +8832,17 @@ Handle<Map> Map::CopyNormalized(Handle<Map> map,
return result;
}
+// Return an immutable prototype exotic object version of the input map.
+// Never even try to cache it in the transition tree, as it is intended
+// for the global object and its prototype chain, and excluding it saves
+// memory on the map transition tree.
+
+// static
+Handle<Map> Map::TransitionToImmutableProto(Handle<Map> map) {
+ Handle<Map> new_map = Map::Copy(map, "ImmutablePrototype");
+ new_map->set_immutable_proto(true);
+ return new_map;
+}
Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size,
int in_object_properties,
@@ -9447,7 +8971,7 @@ void Map::TraceAllTransitions(Map* map) {
void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
Handle<Name> name, SimpleTransitionFlag flag) {
- if (!parent->GetBackPointer()->IsUndefined()) {
+ if (!parent->GetBackPointer()->IsUndefined(parent->GetIsolate())) {
parent->set_owns_descriptors(false);
} else {
// |parent| is initial map and it must keep the ownership, there must be no
@@ -9646,22 +9170,15 @@ Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map,
// using |strict_function_transition_symbol| 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;
- default:
- UNREACHABLE();
- break;
- }
+ STATIC_ASSERT(LANGUAGE_END == 2);
+ DCHECK_EQ(STRICT, language_mode);
+ Handle<Symbol> transition_symbol =
+ isolate->factory()->strict_function_transition_symbol();
Map* maybe_transition =
TransitionArray::SearchSpecial(*initial_map, *transition_symbol);
if (maybe_transition != NULL) {
@@ -9686,30 +9203,6 @@ Handle<Map> Map::AsLanguageMode(Handle<Map> initial_map,
}
-Handle<Map> Map::CopyForObserved(Handle<Map> map) {
- DCHECK(!map->is_observed());
-
- Isolate* isolate = map->GetIsolate();
-
- bool insert_transition =
- TransitionArray::CanHaveMoreTransitions(map) && !map->is_prototype_map();
-
- if (insert_transition) {
- Handle<Map> new_map = CopyForTransition(map, "CopyForObserved");
- new_map->set_is_observed();
-
- Handle<Name> name = isolate->factory()->observed_symbol();
- ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
- return new_map;
- }
-
- // Create a new free-floating map only if we are not allowed to store it.
- Handle<Map> new_map = Map::Copy(map, "CopyForObserved");
- new_map->set_is_observed();
- return new_map;
-}
-
-
Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) {
DCHECK(!map->is_prototype_map());
Handle<Map> new_map = CopyDropDescriptors(map);
@@ -9870,6 +9363,17 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
Handle<Object> value,
PropertyAttributes attributes,
StoreFromKeyed store_mode) {
+ RuntimeCallTimerScope stats_scope(
+ *map, map->is_prototype_map()
+ ? &RuntimeCallStats::PrototypeMap_TransitionToDataProperty
+ : &RuntimeCallStats::Map_TransitionToDataProperty);
+ TRACE_EVENT_RUNTIME_CALL_STATS_TRACING_SCOPED(
+ map->GetIsolate(),
+ (map->is_prototype_map()
+ ? &tracing::TraceEventStatsTable::
+ PrototypeMap_TransitionToDataProperty
+ : &tracing::TraceEventStatsTable::Map_TransitionToDataProperty))
+
DCHECK(name->IsUniqueName());
DCHECK(!map->is_dictionary_map());
@@ -9945,13 +9449,26 @@ Handle<Map> Map::ReconfigureExistingProperty(Handle<Map> map, int descriptor,
return new_map;
}
-Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
+Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
Handle<Name> name, int descriptor,
- AccessorComponent component,
- Handle<Object> accessor,
+ Handle<Object> getter,
+ Handle<Object> setter,
PropertyAttributes attributes) {
+ RuntimeCallTimerScope stats_scope(
+ isolate,
+ map->is_prototype_map()
+ ? &RuntimeCallStats::PrototypeMap_TransitionToAccessorProperty
+ : &RuntimeCallStats::Map_TransitionToAccessorProperty);
+ TRACE_EVENT_RUNTIME_CALL_STATS_TRACING_SCOPED(
+ isolate,
+ (map->is_prototype_map()
+ ? &tracing::TraceEventStatsTable::
+ PrototypeMap_TransitionToAccessorProperty
+ : &tracing::TraceEventStatsTable::Map_TransitionToAccessorProperty));
+
+ // At least one of the accessors needs to be a new value.
+ DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate));
DCHECK(name->IsUniqueName());
- Isolate* isolate = name->GetIsolate();
// Dictionary maps can always have additional data properties.
if (map->is_dictionary_map()) return map;
@@ -9980,7 +9497,7 @@ Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
}
Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
- if (pair->get(component) != *accessor) {
+ if (!pair->Equals(*getter, *setter)) {
return Map::Normalize(map, mode, "TransitionToDifferentAccessor");
}
@@ -10007,10 +9524,21 @@ Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
return Map::Normalize(map, mode, "AccessorsOverwritingNonPair");
}
- Object* current = Handle<AccessorPair>::cast(maybe_pair)->get(component);
- if (current == *accessor) return map;
+ Handle<AccessorPair> current_pair = Handle<AccessorPair>::cast(maybe_pair);
+ if (current_pair->Equals(*getter, *setter)) return map;
- if (!current->IsTheHole()) {
+ bool overwriting_accessor = false;
+ if (!getter->IsNull(isolate) &&
+ !current_pair->get(ACCESSOR_GETTER)->IsNull(isolate) &&
+ current_pair->get(ACCESSOR_GETTER) != *getter) {
+ overwriting_accessor = true;
+ }
+ if (!setter->IsNull(isolate) &&
+ !current_pair->get(ACCESSOR_SETTER)->IsNull(isolate) &&
+ current_pair->get(ACCESSOR_SETTER) != *setter) {
+ overwriting_accessor = true;
+ }
+ if (overwriting_accessor) {
return Map::Normalize(map, mode, "AccessorsOverwritingAccessors");
}
@@ -10022,7 +9550,8 @@ Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
pair = isolate->factory()->NewAccessorPair();
}
- pair->set(component, *accessor);
+ pair->SetComponents(*getter, *setter);
+
TransitionFlag flag = INSERT_TRANSITION;
AccessorConstantDescriptor new_desc(name, pair, attributes);
return Map::CopyInsertDescriptor(map, &new_desc, flag);
@@ -10036,7 +9565,7 @@ Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
// Share descriptors only if map owns descriptors and it not an initial map.
if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
- !map->GetBackPointer()->IsUndefined() &&
+ !map->GetBackPointer()->IsUndefined(map->GetIsolate()) &&
TransitionArray::CanHaveMoreTransitions(map)) {
return ShareDescriptor(map, descriptors, descriptor);
}
@@ -10166,222 +9695,186 @@ Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
simple_flag);
}
-
-void Map::UpdateCodeCache(Handle<Map> map,
- Handle<Name> name,
- Handle<Code> code) {
- Isolate* isolate = map->GetIsolate();
- HandleScope scope(isolate);
- // Allocate the code cache if not present.
- if (map->code_cache()->IsFixedArray()) {
- Handle<Object> result = isolate->factory()->NewCodeCache();
- map->set_code_cache(*result);
+// Helper class to manage a Map's code cache. The layout depends on the number
+// of entries; this is worthwhile because most code caches are very small,
+// but some are huge (thousands of entries).
+// For zero entries, the EmptyFixedArray is used.
+// For one entry, we use a 2-element FixedArray containing [name, code].
+// For 2..100 entries, we use a FixedArray with linear lookups, the layout is:
+// [0] - number of slots that are currently in use
+// [1] - first name
+// [2] - first code
+// [3] - second name
+// [4] - second code
+// etc.
+// For more than 128 entries, we use a CodeCacheHashTable.
+class CodeCache : public AllStatic {
+ public:
+ // Returns the new cache, to be stored on the map.
+ static Handle<FixedArray> Put(Isolate* isolate, Handle<FixedArray> cache,
+ Handle<Name> name, Handle<Code> code) {
+ int length = cache->length();
+ if (length == 0) return PutFirstElement(isolate, name, code);
+ if (length == kEntrySize) {
+ return PutSecondElement(isolate, cache, name, code);
+ }
+ if (length <= kLinearMaxSize) {
+ Handle<FixedArray> result = PutLinearElement(isolate, cache, name, code);
+ if (!result.is_null()) return result;
+ // Fall through if linear storage is getting too large.
+ }
+ return PutHashTableElement(isolate, cache, name, code);
+ }
+
+ static Code* Lookup(FixedArray* cache, Name* name, Code::Flags flags) {
+ int length = cache->length();
+ if (length == 0) return nullptr;
+ if (length == kEntrySize) return OneElementLookup(cache, name, flags);
+ if (!cache->IsCodeCacheHashTable()) {
+ return LinearLookup(cache, name, flags);
+ } else {
+ return CodeCacheHashTable::cast(cache)->Lookup(name, flags);
+ }
}
- // Update the code cache.
- Handle<CodeCache> code_cache(CodeCache::cast(map->code_cache()), isolate);
- CodeCache::Update(code_cache, name, code);
-}
-
+ private:
+ static const int kNameIndex = 0;
+ static const int kCodeIndex = 1;
+ static const int kEntrySize = 2;
-Object* Map::FindInCodeCache(Name* name, Code::Flags flags) {
- // Do a lookup if a code cache exists.
- if (!code_cache()->IsFixedArray()) {
- return CodeCache::cast(code_cache())->Lookup(name, flags);
- } else {
- return GetHeap()->undefined_value();
- }
-}
+ static const int kLinearUsageIndex = 0;
+ static const int kLinearReservedSlots = 1;
+ static const int kLinearInitialCapacity = 2;
+ static const int kLinearMaxSize = 257; // == LinearSizeFor(128);
+ static const int kHashTableInitialCapacity = 200; // Number of entries.
-int Map::IndexInCodeCache(Object* name, Code* code) {
- // Get the internal index if a code cache exists.
- if (!code_cache()->IsFixedArray()) {
- return CodeCache::cast(code_cache())->GetIndex(name, code);
+ static int LinearSizeFor(int entries) {
+ return kLinearReservedSlots + kEntrySize * entries;
}
- return -1;
-}
-
-
-void Map::RemoveFromCodeCache(Name* name, Code* code, int index) {
- // No GC is supposed to happen between a call to IndexInCodeCache and
- // RemoveFromCodeCache so the code cache must be there.
- DCHECK(!code_cache()->IsFixedArray());
- CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
-}
-
-void CodeCache::Update(
- Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
- // The number of monomorphic stubs for normal load/store/call IC's can grow to
- // a large number and therefore they need to go into a hash table. They are
- // used to load global properties from cells.
- if (code->type() == Code::NORMAL) {
- // Make sure that a hash table is allocated for the normal load code cache.
- if (code_cache->normal_type_cache()->IsUndefined()) {
- Handle<Object> result =
- CodeCacheHashTable::New(code_cache->GetIsolate(),
- CodeCacheHashTable::kInitialSize);
- code_cache->set_normal_type_cache(*result);
- }
- UpdateNormalTypeCache(code_cache, name, code);
- } else {
- DCHECK(code_cache->default_cache()->IsFixedArray());
- UpdateDefaultCache(code_cache, name, code);
+ static int LinearNewSize(int old_size) {
+ int old_entries = (old_size - kLinearReservedSlots) / kEntrySize;
+ return LinearSizeFor(old_entries * 2);
}
-}
-
-void CodeCache::UpdateDefaultCache(
- Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
- Isolate* isolate = code_cache->GetIsolate();
- // When updating the default code cache we disregard the type encoded in the
- // flags. This allows call constant stubs to overwrite call field
- // stubs, etc.
- Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
-
- // First check whether we can update existing code cache without
- // extending it.
- Handle<FixedArray> cache = handle(code_cache->default_cache());
- int length = cache->length();
- {
- DisallowHeapAllocation no_alloc;
- int deleted_index = -1;
- Object* null = isolate->heap()->null_value();
- Object* undefined = isolate->heap()->undefined_value();
- DCHECK(name->IsUniqueName());
- for (int i = 0; i < length; i += kCodeCacheEntrySize) {
- Object* key = cache->get(i);
- if (key == null) {
- if (deleted_index < 0) deleted_index = i;
- continue;
- }
- if (key == undefined) {
- if (deleted_index >= 0) i = deleted_index;
- cache->set(i + kCodeCacheEntryNameOffset, *name);
- cache->set(i + kCodeCacheEntryCodeOffset, *code);
- return;
- }
- DCHECK(key->IsUniqueName());
- if (*name == key) {
- Code::Flags found =
- Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
- if (Code::RemoveTypeFromFlags(found) == flags) {
- cache->set(i + kCodeCacheEntryCodeOffset, *code);
- return;
- }
- }
- }
+ static Code* OneElementLookup(FixedArray* cache, Name* name,
+ Code::Flags flags) {
+ DCHECK_EQ(cache->length(), kEntrySize);
+ if (cache->get(kNameIndex) != name) return nullptr;
+ Code* maybe_code = Code::cast(cache->get(kCodeIndex));
+ if (maybe_code->flags() != flags) return nullptr;
+ return maybe_code;
+ }
- // Reached the end of the code cache. If there were deleted
- // elements, reuse the space for the first of them.
- if (deleted_index >= 0) {
- cache->set(deleted_index + kCodeCacheEntryNameOffset, *name);
- cache->set(deleted_index + kCodeCacheEntryCodeOffset, *code);
- return;
+ static Code* LinearLookup(FixedArray* cache, Name* name, Code::Flags flags) {
+ DCHECK_GE(cache->length(), kEntrySize);
+ DCHECK(!cache->IsCodeCacheHashTable());
+ int usage = GetLinearUsage(cache);
+ for (int i = kLinearReservedSlots; i < usage; i += kEntrySize) {
+ if (cache->get(i + kNameIndex) != name) continue;
+ Code* code = Code::cast(cache->get(i + kCodeIndex));
+ if (code->flags() == flags) return code;
}
+ return nullptr;
}
- // Extend the code cache with some new entries (at least one). Must be a
- // multiple of the entry size.
- int new_length = length + (length >> 1) + kCodeCacheEntrySize;
- new_length = new_length - new_length % kCodeCacheEntrySize;
- DCHECK((new_length % kCodeCacheEntrySize) == 0);
- cache = isolate->factory()->CopyFixedArrayAndGrow(cache, new_length - length);
-
- // Add the (name, code) pair to the new cache.
- cache->set(length + kCodeCacheEntryNameOffset, *name);
- cache->set(length + kCodeCacheEntryCodeOffset, *code);
- code_cache->set_default_cache(*cache);
-}
-
-
-void CodeCache::UpdateNormalTypeCache(
- Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
- // Adding a new entry can cause a new cache to be allocated.
- Handle<CodeCacheHashTable> cache(
- CodeCacheHashTable::cast(code_cache->normal_type_cache()));
- Handle<Object> new_cache = CodeCacheHashTable::Put(cache, name, code);
- code_cache->set_normal_type_cache(*new_cache);
-}
-
-
-Object* CodeCache::Lookup(Name* name, Code::Flags flags) {
- Object* result = LookupDefaultCache(name, Code::RemoveTypeFromFlags(flags));
- if (result->IsCode()) {
- if (Code::cast(result)->flags() == flags) return result;
- return GetHeap()->undefined_value();
+ static Handle<FixedArray> PutFirstElement(Isolate* isolate, Handle<Name> name,
+ Handle<Code> code) {
+ Handle<FixedArray> cache = isolate->factory()->NewFixedArray(kEntrySize);
+ cache->set(kNameIndex, *name);
+ cache->set(kCodeIndex, *code);
+ return cache;
}
- return LookupNormalTypeCache(name, flags);
-}
-
-Object* CodeCache::LookupDefaultCache(Name* name, Code::Flags flags) {
- FixedArray* cache = default_cache();
- Heap* heap = GetHeap();
- Object* null = heap->null_value();
- Object* undefined = heap->undefined_value();
- int length = cache->length();
- DCHECK(name->IsUniqueName());
- for (int i = 0; i < length; i += kCodeCacheEntrySize) {
- Object* key = cache->get(i + kCodeCacheEntryNameOffset);
- // Skip deleted elements.
- if (key == null) continue;
- if (key == undefined) return key;
- DCHECK(key->IsUniqueName());
- if (name == key) {
- Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
- if (Code::RemoveTypeFromFlags(code->flags()) == flags) {
- return code;
+ static Handle<FixedArray> PutSecondElement(Isolate* isolate,
+ Handle<FixedArray> cache,
+ Handle<Name> name,
+ Handle<Code> code) {
+ DCHECK_EQ(cache->length(), kEntrySize);
+ Handle<FixedArray> new_cache = isolate->factory()->NewFixedArray(
+ LinearSizeFor(kLinearInitialCapacity));
+ new_cache->set(kLinearReservedSlots + kNameIndex, cache->get(kNameIndex));
+ new_cache->set(kLinearReservedSlots + kCodeIndex, cache->get(kCodeIndex));
+ new_cache->set(LinearSizeFor(1) + kNameIndex, *name);
+ new_cache->set(LinearSizeFor(1) + kCodeIndex, *code);
+ new_cache->set(kLinearUsageIndex, Smi::FromInt(LinearSizeFor(2)));
+ return new_cache;
+ }
+
+ static Handle<FixedArray> PutLinearElement(Isolate* isolate,
+ Handle<FixedArray> cache,
+ Handle<Name> name,
+ Handle<Code> code) {
+ int length = cache->length();
+ int usage = GetLinearUsage(*cache);
+ DCHECK_LE(usage, length);
+ // Check if we need to grow.
+ if (usage == length) {
+ int new_length = LinearNewSize(length);
+ if (new_length > kLinearMaxSize) return Handle<FixedArray>::null();
+ Handle<FixedArray> new_cache =
+ isolate->factory()->NewFixedArray(new_length);
+ for (int i = kLinearReservedSlots; i < length; i++) {
+ new_cache->set(i, cache->get(i));
}
+ cache = new_cache;
}
+ // Store new entry.
+ DCHECK_GE(cache->length(), usage + kEntrySize);
+ cache->set(usage + kNameIndex, *name);
+ cache->set(usage + kCodeIndex, *code);
+ cache->set(kLinearUsageIndex, Smi::FromInt(usage + kEntrySize));
+ return cache;
}
- return GetHeap()->undefined_value();
-}
-
-Object* CodeCache::LookupNormalTypeCache(Name* name, Code::Flags flags) {
- if (!normal_type_cache()->IsUndefined()) {
- CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
- return cache->Lookup(name, flags);
- } else {
- return GetHeap()->undefined_value();
+ static Handle<FixedArray> PutHashTableElement(Isolate* isolate,
+ Handle<FixedArray> cache,
+ Handle<Name> name,
+ Handle<Code> code) {
+ // Check if we need to transition from linear to hash table storage.
+ if (!cache->IsCodeCacheHashTable()) {
+ // Check that the initial hash table capacity is large enough.
+ DCHECK_EQ(kLinearMaxSize, LinearSizeFor(128));
+ STATIC_ASSERT(kHashTableInitialCapacity > 128);
+
+ int length = cache->length();
+ // Only migrate from linear storage when it's full.
+ DCHECK_EQ(length, GetLinearUsage(*cache));
+ DCHECK_EQ(length, kLinearMaxSize);
+ Handle<CodeCacheHashTable> table =
+ CodeCacheHashTable::New(isolate, kHashTableInitialCapacity);
+ HandleScope scope(isolate);
+ for (int i = kLinearReservedSlots; i < length; i += kEntrySize) {
+ Handle<Name> old_name(Name::cast(cache->get(i + kNameIndex)), isolate);
+ Handle<Code> old_code(Code::cast(cache->get(i + kCodeIndex)), isolate);
+ CodeCacheHashTable::Put(table, old_name, old_code);
+ }
+ cache = table;
+ }
+ // Store new entry.
+ DCHECK(cache->IsCodeCacheHashTable());
+ return CodeCacheHashTable::Put(Handle<CodeCacheHashTable>::cast(cache),
+ name, code);
}
-}
-
-int CodeCache::GetIndex(Object* name, Code* code) {
- if (code->type() == Code::NORMAL) {
- if (normal_type_cache()->IsUndefined()) return -1;
- CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
- return cache->GetIndex(Name::cast(name), code->flags());
+ static inline int GetLinearUsage(FixedArray* linear_cache) {
+ DCHECK_GT(linear_cache->length(), kEntrySize);
+ return Smi::cast(linear_cache->get(kLinearUsageIndex))->value();
}
+};
- FixedArray* array = default_cache();
- int len = array->length();
- for (int i = 0; i < len; i += kCodeCacheEntrySize) {
- if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
- }
- return -1;
+void Map::UpdateCodeCache(Handle<Map> map,
+ Handle<Name> name,
+ Handle<Code> code) {
+ Isolate* isolate = map->GetIsolate();
+ Handle<FixedArray> cache(map->code_cache(), isolate);
+ Handle<FixedArray> new_cache = CodeCache::Put(isolate, cache, name, code);
+ map->set_code_cache(*new_cache);
}
-
-void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
- if (code->type() == Code::NORMAL) {
- DCHECK(!normal_type_cache()->IsUndefined());
- CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
- DCHECK(cache->GetIndex(Name::cast(name), code->flags()) == index);
- cache->RemoveByIndex(index);
- } else {
- FixedArray* array = default_cache();
- DCHECK(array->length() >= index && array->get(index)->IsCode());
- // Use null instead of undefined for deleted elements to distinguish
- // deleted elements from unused elements. This distinction is used
- // when looking up in the cache and when updating the cache.
- DCHECK_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
- array->set_null(index - 1); // Name.
- array->set_null(index); // Code.
- }
+Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) {
+ return CodeCache::Lookup(code_cache(), name, flags);
}
@@ -10392,20 +9885,23 @@ void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
class CodeCacheHashTableKey : public HashTableKey {
public:
CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
- : name_(name), flags_(flags), code_() { }
+ : name_(name), flags_(flags), code_() {
+ DCHECK(name_->IsUniqueName());
+ }
CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
- : name_(name), flags_(code->flags()), code_(code) { }
+ : name_(name), flags_(code->flags()), code_(code) {
+ DCHECK(name_->IsUniqueName());
+ }
bool IsMatch(Object* other) override {
- if (!other->IsFixedArray()) return false;
+ DCHECK(other->IsFixedArray());
FixedArray* pair = FixedArray::cast(other);
Name* name = Name::cast(pair->get(0));
Code::Flags flags = Code::cast(pair->get(1))->flags();
- if (flags != flags_) {
- return false;
- }
- return name_->Equals(name);
+ if (flags != flags_) return false;
+ DCHECK(name->IsUniqueName());
+ return *name_ == name;
}
static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
@@ -10437,15 +9933,6 @@ class CodeCacheHashTableKey : public HashTableKey {
};
-Object* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
- DisallowHeapAllocation no_alloc;
- CodeCacheHashTableKey key(handle(name), flags);
- int entry = FindEntry(&key);
- if (entry == kNotFound) return GetHeap()->undefined_value();
- return get(EntryToIndex(entry) + 1);
-}
-
-
Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) {
CodeCacheHashTableKey key(name, code);
@@ -10456,179 +9943,36 @@ Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
Handle<Object> k = key.AsHandle(cache->GetIsolate());
new_cache->set(EntryToIndex(entry), *k);
- new_cache->set(EntryToIndex(entry) + 1, *code);
new_cache->ElementAdded();
return new_cache;
}
-
-int CodeCacheHashTable::GetIndex(Name* name, Code::Flags flags) {
+Code* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
DisallowHeapAllocation no_alloc;
CodeCacheHashTableKey key(handle(name), flags);
int entry = FindEntry(&key);
- return (entry == kNotFound) ? -1 : entry;
+ if (entry == kNotFound) return nullptr;
+ return Code::cast(FixedArray::cast(get(EntryToIndex(entry)))->get(1));
}
-
-void CodeCacheHashTable::RemoveByIndex(int index) {
- DCHECK(index >= 0);
- Heap* heap = GetHeap();
- set(EntryToIndex(index), heap->the_hole_value());
- set(EntryToIndex(index) + 1, heap->the_hole_value());
- ElementRemoved();
-}
-
-
-void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> code_cache,
- MapHandleList* maps,
- Code::Flags flags,
- Handle<Code> code) {
- Isolate* isolate = code_cache->GetIsolate();
- if (code_cache->cache()->IsUndefined()) {
- Handle<PolymorphicCodeCacheHashTable> result =
- PolymorphicCodeCacheHashTable::New(
- isolate,
- PolymorphicCodeCacheHashTable::kInitialSize);
- code_cache->set_cache(*result);
- } else {
- // This entry shouldn't be contained in the cache yet.
- DCHECK(PolymorphicCodeCacheHashTable::cast(code_cache->cache())
- ->Lookup(maps, flags)->IsUndefined());
- }
- Handle<PolymorphicCodeCacheHashTable> hash_table =
- handle(PolymorphicCodeCacheHashTable::cast(code_cache->cache()));
- Handle<PolymorphicCodeCacheHashTable> new_cache =
- PolymorphicCodeCacheHashTable::Put(hash_table, maps, flags, code);
- code_cache->set_cache(*new_cache);
-}
-
-
-Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
- Code::Flags flags) {
- if (!cache()->IsUndefined()) {
- PolymorphicCodeCacheHashTable* hash_table =
- PolymorphicCodeCacheHashTable::cast(cache());
- return Handle<Object>(hash_table->Lookup(maps, flags), GetIsolate());
- } else {
- return GetIsolate()->factory()->undefined_value();
- }
-}
-
-
-// Despite their name, object of this class are not stored in the actual
-// hash table; instead they're temporarily used for lookups. It is therefore
-// safe to have a weak (non-owning) pointer to a MapList as a member field.
-class PolymorphicCodeCacheHashTableKey : public HashTableKey {
- public:
- // Callers must ensure that |maps| outlives the newly constructed object.
- PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
- : maps_(maps),
- code_flags_(code_flags) {}
-
- bool IsMatch(Object* other) override {
- MapHandleList other_maps(kDefaultListAllocationSize);
- int other_flags;
- FromObject(other, &other_flags, &other_maps);
- if (code_flags_ != other_flags) return false;
- if (maps_->length() != other_maps.length()) return false;
- // Compare just the hashes first because it's faster.
- int this_hash = MapsHashHelper(maps_, code_flags_);
- int other_hash = MapsHashHelper(&other_maps, other_flags);
- if (this_hash != other_hash) return false;
-
- // Full comparison: for each map in maps_, look for an equivalent map in
- // other_maps. This implementation is slow, but probably good enough for
- // now because the lists are short (<= 4 elements currently).
- for (int i = 0; i < maps_->length(); ++i) {
- bool match_found = false;
- for (int j = 0; j < other_maps.length(); ++j) {
- if (*(maps_->at(i)) == *(other_maps.at(j))) {
- match_found = true;
- break;
- }
- }
- if (!match_found) return false;
- }
- return true;
- }
-
- static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
- uint32_t hash = code_flags;
- for (int i = 0; i < maps->length(); ++i) {
- hash ^= maps->at(i)->Hash();
- }
- return hash;
- }
-
- uint32_t Hash() override { return MapsHashHelper(maps_, code_flags_); }
-
- uint32_t HashForObject(Object* obj) override {
- MapHandleList other_maps(kDefaultListAllocationSize);
- int other_flags;
- FromObject(obj, &other_flags, &other_maps);
- return MapsHashHelper(&other_maps, other_flags);
- }
-
- MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
- // The maps in |maps_| must be copied to a newly allocated FixedArray,
- // both because the referenced MapList is short-lived, and because C++
- // objects can't be stored in the heap anyway.
- Handle<FixedArray> list =
- isolate->factory()->NewUninitializedFixedArray(maps_->length() + 1);
- list->set(0, Smi::FromInt(code_flags_));
- for (int i = 0; i < maps_->length(); ++i) {
- list->set(i + 1, *maps_->at(i));
- }
- return list;
- }
-
- private:
- static MapHandleList* FromObject(Object* obj,
- int* code_flags,
- MapHandleList* maps) {
- FixedArray* list = FixedArray::cast(obj);
- maps->Rewind(0);
- *code_flags = Smi::cast(list->get(0))->value();
- for (int i = 1; i < list->length(); ++i) {
- maps->Add(Handle<Map>(Map::cast(list->get(i))));
- }
- return maps;
+Handle<FixedArray> FixedArray::SetAndGrow(Handle<FixedArray> array, int index,
+ Handle<Object> value) {
+ if (index < array->length()) {
+ array->set(index, *value);
+ return array;
}
-
- MapHandleList* maps_; // weak.
- int code_flags_;
- static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
-};
-
-
-Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
- int code_kind) {
- DisallowHeapAllocation no_alloc;
- PolymorphicCodeCacheHashTableKey key(maps, code_kind);
- int entry = FindEntry(&key);
- if (entry == kNotFound) return GetHeap()->undefined_value();
- return get(EntryToIndex(entry) + 1);
-}
-
-
-Handle<PolymorphicCodeCacheHashTable> PolymorphicCodeCacheHashTable::Put(
- Handle<PolymorphicCodeCacheHashTable> hash_table,
- MapHandleList* maps,
- int code_kind,
- Handle<Code> code) {
- PolymorphicCodeCacheHashTableKey key(maps, code_kind);
- Handle<PolymorphicCodeCacheHashTable> cache =
- EnsureCapacity(hash_table, 1, &key);
- int entry = cache->FindInsertionEntry(key.Hash());
-
- Handle<Object> obj = key.AsHandle(hash_table->GetIsolate());
- cache->set(EntryToIndex(entry), *obj);
- cache->set(EntryToIndex(entry) + 1, *code);
- cache->ElementAdded();
- return cache;
+ int capacity = array->length();
+ do {
+ capacity = JSObject::NewElementsCapacity(capacity);
+ } while (capacity <= index);
+ Handle<FixedArray> new_array =
+ array->GetIsolate()->factory()->NewUninitializedFixedArray(capacity);
+ array->CopyTo(0, *new_array, 0, array->length());
+ new_array->FillWithHoles(array->length(), new_array->length());
+ new_array->set(index, *value);
+ return new_array;
}
-
void FixedArray::Shrink(int new_length) {
DCHECK(0 <= new_length && new_length <= length());
if (new_length < length()) {
@@ -10984,7 +10328,7 @@ Handle<Object> AccessorPair::GetComponent(Handle<AccessorPair> accessor_pair,
.ToHandleChecked();
}
Isolate* isolate = accessor_pair->GetIsolate();
- if (accessor->IsTheHole()) {
+ if (accessor->IsNull(isolate)) {
return isolate->factory()->undefined_value();
}
return handle(accessor, isolate);
@@ -11012,12 +10356,21 @@ Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
return Handle<DeoptimizationOutputData>::cast(result);
}
+const int LiteralsArray::kFeedbackVectorOffset =
+ LiteralsArray::OffsetOfElementAt(LiteralsArray::kVectorIndex);
+
+const int LiteralsArray::kOffsetToFirstLiteral =
+ LiteralsArray::OffsetOfElementAt(LiteralsArray::kFirstLiteralIndex);
// static
Handle<LiteralsArray> LiteralsArray::New(Isolate* isolate,
Handle<TypeFeedbackVector> vector,
int number_of_literals,
PretenureFlag pretenure) {
+ if (vector->is_empty() && number_of_literals == 0) {
+ return Handle<LiteralsArray>::cast(
+ isolate->factory()->empty_literals_array());
+ }
Handle<FixedArray> literals = isolate->factory()->NewFixedArray(
number_of_literals + kFirstLiteralIndex, pretenure);
Handle<LiteralsArray> casted_literals = Handle<LiteralsArray>::cast(literals);
@@ -11058,14 +10411,11 @@ int HandlerTable::LookupRange(int pc_offset, int* data_out,
// TODO(turbofan): Make sure table is sorted and use binary search.
-int HandlerTable::LookupReturn(int pc_offset, CatchPrediction* prediction_out) {
+int HandlerTable::LookupReturn(int pc_offset) {
for (int i = 0; i < length(); i += kReturnEntrySize) {
int return_offset = Smi::cast(get(i + kReturnOffsetIndex))->value();
int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value();
if (pc_offset == return_offset) {
- if (prediction_out) {
- *prediction_out = HandlerPredictionField::decode(handler_field);
- }
return HandlerOffsetField::decode(handler_field);
}
}
@@ -11085,6 +10435,34 @@ bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
}
#endif
+// static
+Handle<String> String::Trim(Handle<String> string, TrimMode mode) {
+ Isolate* const isolate = string->GetIsolate();
+ string = String::Flatten(string);
+ int const length = string->length();
+
+ // Perform left trimming if requested.
+ int left = 0;
+ UnicodeCache* unicode_cache = isolate->unicode_cache();
+ if (mode == kTrim || mode == kTrimLeft) {
+ while (left < length &&
+ unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) {
+ left++;
+ }
+ }
+
+ // Perform right trimming if requested.
+ int right = length;
+ if (mode == kTrim || mode == kTrimRight) {
+ while (
+ right > left &&
+ unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) {
+ right--;
+ }
+ }
+
+ return isolate->factory()->NewSubString(string, left, right);
+}
bool String::LooksValid() {
if (!GetIsolate()->heap()->Contains(this)) return false;
@@ -11098,7 +10476,9 @@ MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
// ES6 section 9.2.11 SetFunctionName, step 4.
Isolate* const isolate = name->GetIsolate();
Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
- if (description->IsUndefined()) return isolate->factory()->empty_string();
+ if (description->IsUndefined(isolate)) {
+ return isolate->factory()->empty_string();
+ }
IncrementalStringBuilder builder(isolate);
builder.AppendCharacter('[');
builder.AppendString(Handle<String>::cast(description));
@@ -11106,6 +10486,19 @@ MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
return builder.Finish();
}
+// static
+MaybeHandle<String> Name::ToFunctionName(Handle<Name> name,
+ Handle<String> prefix) {
+ Handle<String> name_string;
+ Isolate* const isolate = name->GetIsolate();
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, name_string, ToFunctionName(name),
+ String);
+ IncrementalStringBuilder builder(isolate);
+ builder.AppendString(prefix);
+ builder.AppendCharacter(' ');
+ builder.AppendString(name_string);
+ return builder.Finish();
+}
namespace {
@@ -11238,13 +10631,12 @@ String::FlatContent String::GetFlatContent() {
}
}
-
-base::SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
- RobustnessFlag robust_flag,
- int offset, int length,
- int* length_return) {
+std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
+ RobustnessFlag robust_flag,
+ int offset, int length,
+ int* length_return) {
if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
- return base::SmartArrayPointer<char>(NULL);
+ return std::unique_ptr<char[]>();
}
// Negative length means the to the end of the string.
if (length < 0) length = kMaxInt - offset;
@@ -11281,13 +10673,12 @@ base::SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
last = character;
}
result[utf8_byte_position] = 0;
- return base::SmartArrayPointer<char>(result);
+ return std::unique_ptr<char[]>(result);
}
-
-base::SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
- RobustnessFlag robust_flag,
- int* length_return) {
+std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
+ RobustnessFlag robust_flag,
+ int* length_return) {
return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
}
@@ -11313,25 +10704,6 @@ const uc16* String::GetTwoByteData(unsigned start) {
}
-base::SmartArrayPointer<uc16> String::ToWideCString(
- RobustnessFlag robust_flag) {
- if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
- return base::SmartArrayPointer<uc16>();
- }
- StringCharacterStream stream(this);
-
- uc16* result = NewArray<uc16>(length() + 1);
-
- int i = 0;
- while (stream.HasMore()) {
- uint16_t character = stream.GetNext();
- result[i++] = character;
- }
- result[i] = 0;
- return base::SmartArrayPointer<uc16>(result);
-}
-
-
const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
return reinterpret_cast<uc16*>(
reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
@@ -12052,6 +11424,42 @@ ComparisonResult String::Compare(Handle<String> x, Handle<String> y) {
return result;
}
+int String::IndexOf(Isolate* isolate, Handle<String> sub, Handle<String> pat,
+ int start_index) {
+ DCHECK(0 <= start_index);
+ DCHECK(start_index <= sub->length());
+
+ int pattern_length = pat->length();
+ if (pattern_length == 0) return start_index;
+
+ int subject_length = sub->length();
+ if (start_index + pattern_length > subject_length) return -1;
+
+ sub = String::Flatten(sub);
+ pat = String::Flatten(pat);
+
+ DisallowHeapAllocation no_gc; // ensure vectors stay valid
+ // Extract flattened substrings of cons strings before getting encoding.
+ String::FlatContent seq_sub = sub->GetFlatContent();
+ String::FlatContent seq_pat = pat->GetFlatContent();
+
+ // dispatch on type of strings
+ if (seq_pat.IsOneByte()) {
+ Vector<const uint8_t> pat_vector = seq_pat.ToOneByteVector();
+ if (seq_sub.IsOneByte()) {
+ return SearchString(isolate, seq_sub.ToOneByteVector(), pat_vector,
+ start_index);
+ }
+ return SearchString(isolate, seq_sub.ToUC16Vector(), pat_vector,
+ start_index);
+ }
+ Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
+ if (seq_sub.IsOneByte()) {
+ return SearchString(isolate, seq_sub.ToOneByteVector(), pat_vector,
+ start_index);
+ }
+ return SearchString(isolate, seq_sub.ToUC16Vector(), pat_vector, start_index);
+}
bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
int slen = length();
@@ -12200,8 +11608,8 @@ uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
value |= length << String::ArrayIndexLengthBits::kShift;
DCHECK((value & String::kIsNotArrayIndexMask) == 0);
- DCHECK((length > String::kMaxCachedArrayIndexLength) ||
- (value & String::kContainsCachedArrayIndexMask) == 0);
+ DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength,
+ (value & String::kContainsCachedArrayIndexMask) == 0);
return value;
}
@@ -12377,15 +11785,18 @@ bool JSFunction::Inlines(SharedFunctionInfo* candidate) {
return false;
}
+void JSFunction::MarkForBaseline() {
+ Isolate* isolate = GetIsolate();
+ set_code_no_write_barrier(
+ isolate->builtins()->builtin(Builtins::kCompileBaseline));
+ // No write barrier required, since the builtin is part of the root set.
+}
void JSFunction::MarkForOptimization() {
Isolate* isolate = GetIsolate();
- // Do not optimize if function contains break points.
- if (shared()->HasDebugInfo()) return;
DCHECK(!IsOptimized());
DCHECK(shared()->allows_lazy_compilation() ||
!shared()->optimization_disabled());
- DCHECK(!shared()->HasDebugInfo());
set_code_no_write_barrier(
isolate->builtins()->builtin(Builtins::kCompileOptimized));
// No write barrier required, since the builtin is part of the root set.
@@ -12414,6 +11825,30 @@ void JSFunction::AttemptConcurrentOptimization() {
// No write barrier required, since the builtin is part of the root set.
}
+// static
+Handle<LiteralsArray> SharedFunctionInfo::FindOrCreateLiterals(
+ Handle<SharedFunctionInfo> shared, Handle<Context> native_context) {
+ Isolate* isolate = shared->GetIsolate();
+ CodeAndLiterals result =
+ shared->SearchOptimizedCodeMap(*native_context, BailoutId::None());
+ if (result.literals != nullptr) {
+ DCHECK(shared->feedback_metadata()->is_empty() ||
+ !result.literals->feedback_vector()->is_empty());
+ return handle(result.literals, isolate);
+ }
+
+ Handle<TypeFeedbackVector> feedback_vector =
+ TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata()));
+ Handle<LiteralsArray> literals =
+ LiteralsArray::New(isolate, feedback_vector, shared->num_literals());
+ Handle<Code> code;
+ if (result.code != nullptr) {
+ code = Handle<Code>(result.code, isolate);
+ }
+ AddToOptimizedCodeMap(shared, native_context, code, literals,
+ BailoutId::None());
+ return literals;
+}
void SharedFunctionInfo::AddSharedCodeToOptimizedCodeMap(
Handle<SharedFunctionInfo> shared, Handle<Code> code) {
@@ -12610,6 +12045,17 @@ void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
}
}
+// static
+void JSFunction::EnsureLiterals(Handle<JSFunction> function) {
+ Handle<SharedFunctionInfo> shared(function->shared());
+ Handle<Context> native_context(function->context()->native_context());
+ if (function->literals() ==
+ function->GetIsolate()->heap()->empty_literals_array()) {
+ Handle<LiteralsArray> literals =
+ SharedFunctionInfo::FindOrCreateLiterals(shared, native_context);
+ function->set_literals(*literals);
+ }
+}
static void GetMinInobjectSlack(Map* map, void* data) {
int slack = map->unused_property_fields();
@@ -12636,7 +12082,7 @@ static void StopSlackTracking(Map* map, void* data) {
void Map::CompleteInobjectSlackTracking() {
// Has to be an initial map.
- DCHECK(GetBackPointer()->IsUndefined());
+ DCHECK(GetBackPointer()->IsUndefined(GetIsolate()));
int slack = unused_property_fields();
TransitionArray::TraverseTransitionTree(this, &GetMinInobjectSlack, &slack);
@@ -12667,6 +12113,26 @@ static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
return false;
}
+// static
+void JSObject::MakePrototypesFast(Handle<Object> receiver,
+ WhereToStart where_to_start,
+ Isolate* isolate) {
+ if (!receiver->IsJSReceiver()) return;
+ for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver),
+ where_to_start);
+ !iter.IsAtEnd(); iter.Advance()) {
+ Handle<Object> current = PrototypeIterator::GetCurrent(iter);
+ if (!current->IsJSObject()) return;
+ Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
+ Map* current_map = current_obj->map();
+ if (current_map->is_prototype_map() &&
+ !current_map->should_be_fast_prototype_map()) {
+ Handle<Map> map(current_map);
+ Map::SetShouldBeFastPrototypeMap(map, true, isolate);
+ JSObject::OptimizeAsPrototype(current_obj, FAST_PROTOTYPE);
+ }
+ }
+}
// static
void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
@@ -12678,10 +12144,12 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
"NormalizeAsPrototype");
}
Handle<Map> previous_map(object->map());
- if (!object->HasFastProperties()) {
- JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
- }
- if (!object->map()->is_prototype_map()) {
+ if (object->map()->is_prototype_map()) {
+ if (object->map()->should_be_fast_prototype_map() &&
+ !object->HasFastProperties()) {
+ JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
+ }
+ } else {
if (object->map() == *previous_map) {
Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
JSObject::MigrateToMap(object, new_map);
@@ -12709,13 +12177,13 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
// static
void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
if (!object->map()->is_prototype_map()) return;
+ if (!object->map()->should_be_fast_prototype_map()) return;
OptimizeAsPrototype(object, FAST_PROTOTYPE);
}
// static
void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
- DCHECK(FLAG_track_prototype_users);
// Contract: In line with InvalidatePrototypeChains()'s requirements,
// leaf maps don't need to register as users, only prototypes do.
DCHECK(user->is_prototype_map());
@@ -12821,7 +12289,6 @@ static void InvalidatePrototypeChainsInternal(Map* map) {
// static
void JSObject::InvalidatePrototypeChains(Map* map) {
- if (!FLAG_eliminate_prototype_chain_checks) return;
DisallowHeapAllocation no_gc;
InvalidatePrototypeChainsInternal(map);
}
@@ -12852,6 +12319,15 @@ Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
return proto_info;
}
+// static
+void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
+ Isolate* isolate) {
+ if (value == false && !map->prototype_info()->IsPrototypeInfo()) {
+ // "False" is the implicit default value, so there's nothing to do.
+ return;
+ }
+ GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value);
+}
// static
Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
@@ -12884,6 +12360,10 @@ Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
// static
void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype,
PrototypeOptimizationMode proto_mode) {
+ RuntimeCallTimerScope stats_scope(*map, &RuntimeCallStats::Map_SetPrototype);
+ TRACE_EVENT_RUNTIME_CALL_STATS_TRACING_SCOPED(
+ map->GetIsolate(), &tracing::TraceEventStatsTable::Map_SetPrototype);
+
bool is_hidden = false;
if (prototype->IsJSObject()) {
Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
@@ -12900,8 +12380,9 @@ void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype,
}
map->set_has_hidden_prototype(is_hidden);
- WriteBarrierMode wb_mode =
- prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER;
+ WriteBarrierMode wb_mode = prototype->IsNull(map->GetIsolate())
+ ? SKIP_WRITE_BARRIER
+ : UPDATE_WRITE_BARRIER;
map->set_prototype(*prototype, wb_mode);
}
@@ -13009,8 +12490,13 @@ void JSFunction::SetPrototype(Handle<JSFunction> function,
new_map->SetConstructor(*value);
new_map->set_non_instance_prototype(true);
Isolate* isolate = new_map->GetIsolate();
+
construct_prototype = handle(
- function->context()->native_context()->initial_object_prototype(),
+ IsGeneratorFunction(function->shared()->kind())
+ ? function->context()
+ ->native_context()
+ ->initial_generator_prototype()
+ : function->context()->native_context()->initial_object_prototype(),
isolate);
} else {
function->map()->set_non_instance_prototype(false);
@@ -13065,50 +12551,54 @@ 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_API_OBJECT_TYPE:
case JS_ARRAY_BUFFER_TYPE:
- case JS_TYPED_ARRAY_TYPE:
+ case JS_ARRAY_TYPE:
+ case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_DATA_VIEW_TYPE:
- case JS_SET_TYPE:
+ case JS_DATE_TYPE:
+ case JS_FUNCTION_TYPE:
+ case JS_GENERATOR_OBJECT_TYPE:
+ case JS_MAP_ITERATOR_TYPE:
case JS_MAP_TYPE:
+ case JS_MESSAGE_OBJECT_TYPE:
+ case JS_MODULE_TYPE:
+ case JS_OBJECT_TYPE:
+ case JS_ERROR_TYPE:
+ case JS_ARGUMENTS_TYPE:
+ case JS_PROMISE_TYPE:
+ case JS_REGEXP_TYPE:
case JS_SET_ITERATOR_TYPE:
- case JS_MAP_ITERATOR_TYPE:
+ case JS_SET_TYPE:
+ case JS_SPECIAL_API_OBJECT_TYPE:
+ case JS_TYPED_ARRAY_TYPE:
+ case JS_VALUE_TYPE:
case JS_WEAK_MAP_TYPE:
case JS_WEAK_SET_TYPE:
- 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 BYTECODE_ARRAY_TYPE:
+ case BYTE_ARRAY_TYPE:
+ case CELL_TYPE:
+ case CODE_TYPE:
+ case FILLER_TYPE:
case FIXED_ARRAY_TYPE:
case FIXED_DOUBLE_ARRAY_TYPE:
- case ODDBALL_TYPE:
case FOREIGN_TYPE:
- case MAP_TYPE:
- case CODE_TYPE:
- case CELL_TYPE:
- case PROPERTY_CELL_TYPE:
- case WEAK_CELL_TYPE:
- case SYMBOL_TYPE:
- case BYTECODE_ARRAY_TYPE:
+ case FREE_SPACE_TYPE:
case HEAP_NUMBER_TYPE:
+ case JS_BOUND_FUNCTION_TYPE:
+ case JS_GLOBAL_OBJECT_TYPE:
+ case JS_GLOBAL_PROXY_TYPE:
+ case JS_PROXY_TYPE:
+ case MAP_TYPE:
case MUTABLE_HEAP_NUMBER_TYPE:
- case SIMD128_VALUE_TYPE:
- case FILLER_TYPE:
- case BYTE_ARRAY_TYPE:
- case FREE_SPACE_TYPE:
+ case ODDBALL_TYPE:
+ case PROPERTY_CELL_TYPE:
case SHARED_FUNCTION_INFO_TYPE:
+ case SIMD128_VALUE_TYPE:
+ case SYMBOL_TYPE:
+ case WEAK_CELL_TYPE:
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
case FIXED_##TYPE##_ARRAY_TYPE:
@@ -13130,7 +12620,7 @@ bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
- DCHECK(function->IsConstructor() || function->shared()->is_generator());
+ DCHECK(function->IsConstructor() || function->shared()->is_resumable());
if (function->has_initial_map()) return;
Isolate* isolate = function->GetIsolate();
@@ -13141,7 +12631,7 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
// First create a new map with the size and number of in-object properties
// suggested by the function.
InstanceType instance_type;
- if (function->shared()->is_generator()) {
+ if (function->shared()->is_resumable()) {
instance_type = JS_GENERATOR_OBJECT_TYPE;
} else {
instance_type = JS_OBJECT_TYPE;
@@ -13275,7 +12765,7 @@ MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
void JSFunction::PrintName(FILE* out) {
- base::SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
+ std::unique_ptr<char[]> name = shared()->DebugName()->ToCString();
PrintF(out, "%s", name.get());
}
@@ -13341,18 +12831,6 @@ Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
}
-// static
-MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
- Handle<JSBoundFunction> function) {
- Handle<String> prefix = isolate->factory()->bound__string();
- if (!function->bound_target_function()->IsJSFunction()) return prefix;
- Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
- isolate);
- Handle<Object> target_name = JSFunction::GetName(target);
- if (!target_name->IsString()) return prefix;
- Factory* factory = isolate->factory();
- return factory->NewConsString(prefix, Handle<String>::cast(target_name));
-}
// static
Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
@@ -13386,10 +12864,16 @@ Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
IncrementalStringBuilder builder(isolate);
if (!shared_info->is_arrow()) {
if (shared_info->is_concise_method()) {
- if (shared_info->is_generator()) builder.AppendCharacter('*');
+ if (shared_info->is_generator()) {
+ builder.AppendCharacter('*');
+ } else if (shared_info->is_async()) {
+ builder.AppendCString("async ");
+ }
} else {
if (shared_info->is_generator()) {
builder.AppendCString("function* ");
+ } else if (shared_info->is_async()) {
+ builder.AppendCString("async function ");
} else {
builder.AppendCString("function ");
}
@@ -13406,26 +12890,64 @@ Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
void Oddball::Initialize(Isolate* isolate, Handle<Oddball> oddball,
const char* to_string, Handle<Object> to_number,
- bool to_boolean, const char* type_of, byte kind) {
+ const char* type_of, byte kind) {
Handle<String> internalized_to_string =
isolate->factory()->InternalizeUtf8String(to_string);
Handle<String> internalized_type_of =
isolate->factory()->InternalizeUtf8String(type_of);
- oddball->set_to_boolean(isolate->heap()->ToBoolean(to_boolean));
+ oddball->set_to_number_raw(to_number->Number());
oddball->set_to_number(*to_number);
oddball->set_to_string(*internalized_to_string);
oddball->set_type_of(*internalized_type_of);
oddball->set_kind(kind);
}
+void Script::SetEvalOrigin(Handle<Script> script,
+ Handle<SharedFunctionInfo> outer_info,
+ int eval_position) {
+ if (eval_position == kNoSourcePosition) {
+ // If the position is missing, attempt to get the code offset from the
+ // current activation. Do not translate the code offset into source
+ // position, but store it as negative value for lazy translation.
+ StackTraceFrameIterator it(script->GetIsolate());
+ if (!it.done() && it.is_javascript()) {
+ FrameSummary summary = FrameSummary::GetFirst(it.javascript_frame());
+ script->set_eval_from_shared(summary.function()->shared());
+ script->set_eval_from_position(-summary.code_offset());
+ return;
+ }
+ eval_position = 0;
+ }
+ script->set_eval_from_shared(*outer_info);
+ script->set_eval_from_position(eval_position);
+}
-void Script::InitLineEnds(Handle<Script> script) {
- if (!script->line_ends()->IsUndefined()) return;
+int Script::GetEvalPosition() {
+ DisallowHeapAllocation no_gc;
+ DCHECK(compilation_type() == Script::COMPILATION_TYPE_EVAL);
+ int position = eval_from_position();
+ if (position < 0) {
+ // Due to laziness, the position may not have been translated from code
+ // offset yet, which would be encoded as negative integer. In that case,
+ // translate and set the position.
+ if (eval_from_shared()->IsUndefined(GetIsolate())) {
+ position = 0;
+ } else {
+ SharedFunctionInfo* shared = SharedFunctionInfo::cast(eval_from_shared());
+ position = shared->abstract_code()->SourcePosition(-position);
+ }
+ DCHECK(position >= 0);
+ set_eval_from_position(position);
+ }
+ return position;
+}
+void Script::InitLineEnds(Handle<Script> script) {
Isolate* isolate = script->GetIsolate();
+ if (!script->line_ends()->IsUndefined(isolate)) return;
if (!script->source()->IsString()) {
- DCHECK(script->source()->IsUndefined());
+ DCHECK(script->source()->IsUndefined(isolate));
Handle<FixedArray> empty = isolate->factory()->NewFixedArray(0);
script->set_line_ends(*empty);
DCHECK(script->line_ends()->IsFixedArray());
@@ -13444,42 +12966,94 @@ void Script::InitLineEnds(Handle<Script> script) {
DCHECK(script->line_ends()->IsFixedArray());
}
-
-int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
- int line_number = GetLineNumber(script, code_pos);
- if (line_number == -1) return -1;
+#define SMI_VALUE(x) (Smi::cast(x)->value())
+bool Script::GetPositionInfo(int position, PositionInfo* info,
+ OffsetFlag offset_flag) {
+ Handle<Script> script(this);
+ InitLineEnds(script);
DisallowHeapAllocation no_allocation;
- FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
- line_number = line_number - script->line_offset();
- if (line_number == 0) return code_pos + script->column_offset();
- int prev_line_end_pos =
- Smi::cast(line_ends_array->get(line_number - 1))->value();
- return code_pos - (prev_line_end_pos + 1);
-}
+ DCHECK(script->line_ends()->IsFixedArray());
+ FixedArray* ends = FixedArray::cast(script->line_ends());
-int Script::GetLineNumberWithArray(int code_pos) {
- DisallowHeapAllocation no_allocation;
- DCHECK(line_ends()->IsFixedArray());
- FixedArray* line_ends_array = FixedArray::cast(line_ends());
- int line_ends_len = line_ends_array->length();
- if (line_ends_len == 0) return -1;
+ const int ends_len = ends->length();
+ if (ends_len == 0) return false;
- if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) {
- return line_offset();
+ // Return early on invalid positions. Negative positions behave as if 0 was
+ // passed, and positions beyond the end of the script return as failure.
+ if (position < 0) {
+ position = 0;
+ } else if (position > SMI_VALUE(ends->get(ends_len - 1))) {
+ return false;
}
- int left = 0;
- int right = line_ends_len;
- while (int half = (right - left) / 2) {
- if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) {
- right -= half;
- } else {
- left += half;
+ // Determine line number by doing a binary search on the line ends array.
+ if (SMI_VALUE(ends->get(0)) >= position) {
+ info->line = 0;
+ info->line_start = 0;
+ info->column = position;
+ } else {
+ int left = 0;
+ int right = ends_len - 1;
+
+ while (right > 0) {
+ DCHECK_LE(left, right);
+ const int mid = (left + right) / 2;
+ if (position > SMI_VALUE(ends->get(mid))) {
+ left = mid + 1;
+ } else if (position <= SMI_VALUE(ends->get(mid - 1))) {
+ right = mid - 1;
+ } else {
+ info->line = mid;
+ break;
+ }
}
+ DCHECK(SMI_VALUE(ends->get(info->line)) >= position &&
+ SMI_VALUE(ends->get(info->line - 1)) < position);
+ info->line_start = SMI_VALUE(ends->get(info->line - 1)) + 1;
+ info->column = position - info->line_start;
}
- return right + line_offset();
+
+ // Line end is position of the linebreak character.
+ info->line_end = SMI_VALUE(ends->get(info->line));
+ if (info->line_end > 0) {
+ DCHECK(script->source()->IsString());
+ Handle<String> src(String::cast(script->source()));
+ if (src->length() >= info->line_end &&
+ src->Get(info->line_end - 1) == '\r') {
+ info->line_end--;
+ }
+ }
+
+ // Add offsets if requested.
+ if (offset_flag == WITH_OFFSET) {
+ if (info->line == 0) {
+ info->column += script->column_offset();
+ }
+ info->line += script->line_offset();
+ }
+
+ return true;
+}
+#undef SMI_VALUE
+
+int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
+ PositionInfo info;
+ if (!script->GetPositionInfo(code_pos, &info, WITH_OFFSET)) {
+ return -1;
+ }
+
+ return info.column;
+}
+
+int Script::GetLineNumberWithArray(int code_pos) {
+ PositionInfo info;
+ if (!GetPositionInfo(code_pos, &info, WITH_OFFSET)) {
+ return -1;
+ }
+
+ return info.line;
}
@@ -13491,7 +13065,9 @@ int Script::GetLineNumber(Handle<Script> script, int code_pos) {
int Script::GetLineNumber(int code_pos) {
DisallowHeapAllocation no_allocation;
- if (!line_ends()->IsUndefined()) return GetLineNumberWithArray(code_pos);
+ if (!line_ends()->IsUndefined(GetIsolate())) {
+ return GetLineNumberWithArray(code_pos);
+ }
// Slow mode: we do not have line_ends. We have to iterate through source.
if (!source()->IsString()) return -1;
@@ -13509,28 +13085,19 @@ int Script::GetLineNumber(int code_pos) {
Handle<Object> Script::GetNameOrSourceURL(Handle<Script> script) {
Isolate* isolate = script->GetIsolate();
- Handle<String> name_or_source_url_key =
- isolate->factory()->InternalizeOneByteString(
- STATIC_CHAR_VECTOR("nameOrSourceURL"));
- Handle<JSObject> script_wrapper = Script::GetWrapper(script);
- Handle<Object> property =
- JSReceiver::GetProperty(script_wrapper, name_or_source_url_key)
- .ToHandleChecked();
- DCHECK(property->IsJSFunction());
- Handle<Object> result;
- // Do not check against pending exception, since this function may be called
- // when an exception has already been pending.
- if (!Execution::TryCall(isolate, property, script_wrapper, 0, NULL)
- .ToHandle(&result)) {
- return isolate->factory()->undefined_value();
+
+ // Keep in sync with ScriptNameOrSourceURL in messages.js.
+
+ if (!script->source_url()->IsUndefined(isolate)) {
+ return handle(script->source_url(), isolate);
}
- return result;
+ return handle(script->name(), isolate);
}
Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
Isolate* isolate = script->GetIsolate();
- if (!script->wrapper()->IsUndefined()) {
+ if (!script->wrapper()->IsUndefined(isolate)) {
DCHECK(script->wrapper()->IsWeakCell());
Handle<WeakCell> cell(WeakCell::cast(script->wrapper()));
if (!cell->cleared()) {
@@ -13560,7 +13127,8 @@ MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
SharedFunctionInfo* shared;
while ((shared = iterator.Next<SharedFunctionInfo>())) {
if (fun->function_token_position() == shared->function_token_position() &&
- fun->start_position() == shared->start_position()) {
+ fun->start_position() == shared->start_position() &&
+ fun->end_position() == shared->end_position()) {
return Handle<SharedFunctionInfo>(shared);
}
}
@@ -13694,8 +13262,9 @@ bool SharedFunctionInfo::PassesFilter(const char* raw_filter) {
}
bool SharedFunctionInfo::HasSourceCode() const {
- return !script()->IsUndefined() &&
- !reinterpret_cast<Script*>(script())->source()->IsUndefined();
+ Isolate* isolate = GetIsolate();
+ return !script()->IsUndefined(isolate) &&
+ !reinterpret_cast<Script*>(script())->source()->IsUndefined(isolate);
}
@@ -13751,9 +13320,8 @@ void JSFunction::CalculateInstanceSizeForDerivedClass(
int* instance_size, int* in_object_properties) {
Isolate* isolate = GetIsolate();
int expected_nof_properties = 0;
- for (PrototypeIterator iter(isolate, this,
- PrototypeIterator::START_AT_RECEIVER);
- !iter.IsAtEnd(); iter.Advance()) {
+ for (PrototypeIterator iter(isolate, this, kStartAtReceiver); !iter.IsAtEnd();
+ iter.Advance()) {
JSReceiver* current = iter.GetCurrent<JSReceiver>();
if (!current->IsJSFunction()) break;
JSFunction* func = JSFunction::cast(current);
@@ -13858,9 +13426,37 @@ void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
}
}
+namespace {
+
+// Sets the expected number of properties based on estimate from parser.
+void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
+ FunctionLiteral* literal) {
+ int estimate = literal->expected_property_count();
+
+ // If no properties are added in the constructor, they are more likely
+ // to be added later.
+ if (estimate == 0) estimate = 2;
+
+ // TODO(yangguo): check whether those heuristics are still up-to-date.
+ // We do not shrink objects that go into a snapshot (yet), so we adjust
+ // the estimate conservatively.
+ if (shared->GetIsolate()->serializer_enabled()) {
+ estimate += 2;
+ } else {
+ // Inobject slack tracking will reclaim redundant inobject space later,
+ // so we can afford to adjust the estimate generously.
+ estimate += 8;
+ }
+
+ shared->set_expected_nof_properties(estimate);
+}
+
+} // namespace
void SharedFunctionInfo::InitFromFunctionLiteral(
Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) {
+ // When adding fields here, make sure Scope::AnalyzePartially is updated
+ // accordingly.
shared_info->set_length(lit->scope()->default_function_length());
shared_info->set_internal_formal_parameter_count(lit->parameter_count());
shared_info->set_function_token_position(lit->function_token_position());
@@ -13876,20 +13472,16 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
shared_info->set_language_mode(lit->language_mode());
shared_info->set_uses_arguments(lit->scope()->arguments() != NULL);
shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
- shared_info->set_ast_node_count(lit->ast_node_count());
shared_info->set_is_function(lit->is_function());
- if (lit->dont_optimize_reason() != kNoReason) {
- shared_info->DisableOptimization(lit->dont_optimize_reason());
- }
- shared_info->set_dont_crankshaft(lit->flags() &
- AstProperties::kDontCrankshaft);
+ shared_info->set_never_compiled(true);
shared_info->set_kind(lit->kind());
if (!IsConstructable(lit->kind(), lit->language_mode())) {
- shared_info->set_construct_stub(
+ shared_info->SetConstructStub(
*shared_info->GetIsolate()->builtins()->ConstructedNonConstructable());
}
shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
shared_info->set_asm_function(lit->scope()->asm_function());
+ SetExpectedNofPropertiesFromEstimate(shared_info, lit);
}
@@ -13903,6 +13495,10 @@ bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
return true; // Return true if there was no DCHECK.
}
+void SharedFunctionInfo::SetConstructStub(Code* code) {
+ if (code->kind() == Code::BUILTIN) code->set_is_construct_stub(true);
+ set_construct_stub(code);
+}
void Map::StartInobjectSlackTracking() {
DCHECK(!IsInobjectSlackTrackingInProgress());
@@ -13919,14 +13515,18 @@ void Map::StartInobjectSlackTracking() {
void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
code()->ClearInlineCaches();
- // If we clear ICs, we need to clear the type feedback vector too, since
- // CallICs are synced with a feedback vector slot.
- ClearTypeFeedbackInfo();
set_ic_age(new_ic_age);
if (code()->kind() == Code::FUNCTION) {
code()->set_profiler_ticks(0);
- if (optimization_disabled() &&
- opt_count() >= FLAG_max_opt_count) {
+ if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) {
+ // Re-enable optimizations if they were disabled due to opt_count limit.
+ set_optimization_disabled(false);
+ }
+ set_opt_count(0);
+ set_deopt_count(0);
+ } else if (code()->is_interpreter_trampoline_builtin()) {
+ set_profiler_ticks(0);
+ if (optimization_disabled() && opt_count() >= FLAG_max_opt_count) {
// Re-enable optimizations if they were disabled due to opt_count limit.
set_optimization_disabled(false);
}
@@ -13960,6 +13560,19 @@ int SharedFunctionInfo::SearchOptimizedCodeMapEntry(Context* native_context,
return -1;
}
+void SharedFunctionInfo::ClearCodeFromOptimizedCodeMap() {
+ if (!OptimizedCodeMapIsCleared()) {
+ FixedArray* optimized_code_map = this->optimized_code_map();
+ int length = optimized_code_map->length();
+ WeakCell* empty_weak_cell = GetHeap()->empty_weak_cell();
+ for (int i = kEntriesStart; i < length; i += kEntryLength) {
+ optimized_code_map->set(i + kCachedCodeOffset, empty_weak_cell,
+ SKIP_WRITE_BARRIER);
+ }
+ optimized_code_map->set(kSharedCodeIndex, empty_weak_cell,
+ SKIP_WRITE_BARRIER);
+ }
+}
CodeAndLiterals SharedFunctionInfo::SearchOptimizedCodeMap(
Context* native_context, BailoutId osr_ast_id) {
@@ -13986,12 +13599,6 @@ CodeAndLiterals SharedFunctionInfo::SearchOptimizedCodeMap(
: LiteralsArray::cast(literals_cell->value())};
}
}
- if (FLAG_trace_opt && !OptimizedCodeMapIsCleared() &&
- result.code == nullptr) {
- PrintF("[didn't find optimized code in optimized code map for ");
- ShortPrint();
- PrintF("]\n");
- }
return result;
}
@@ -14014,63 +13621,66 @@ const char* const VisitorSynchronization::kTagNames[
void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
- Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
- Object* old_target = target;
- VisitPointer(&target);
- CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
+ Object* old_pointer = Code::GetCodeFromTargetAddress(rinfo->target_address());
+ Object* new_pointer = old_pointer;
+ VisitPointer(&new_pointer);
+ DCHECK_EQ(old_pointer, new_pointer);
}
void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) {
DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
- Object* stub = rinfo->code_age_stub();
- if (stub) {
- VisitPointer(&stub);
+ Object* old_pointer = rinfo->code_age_stub();
+ Object* new_pointer = old_pointer;
+ if (old_pointer != nullptr) {
+ VisitPointer(&new_pointer);
+ DCHECK_EQ(old_pointer, new_pointer);
}
}
void ObjectVisitor::VisitCodeEntry(Address entry_address) {
- Object* code = Code::GetObjectFromEntryAddress(entry_address);
- Object* old_code = code;
- VisitPointer(&code);
- if (code != old_code) {
- Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
- }
+ Object* old_pointer = Code::GetObjectFromEntryAddress(entry_address);
+ Object* new_pointer = old_pointer;
+ VisitPointer(&new_pointer);
+ DCHECK_EQ(old_pointer, new_pointer);
}
void ObjectVisitor::VisitCell(RelocInfo* rinfo) {
DCHECK(rinfo->rmode() == RelocInfo::CELL);
- Object* cell = rinfo->target_cell();
- Object* old_cell = cell;
- VisitPointer(&cell);
- if (cell != old_cell) {
- rinfo->set_target_cell(reinterpret_cast<Cell*>(cell));
- }
+ Object* old_pointer = rinfo->target_cell();
+ Object* new_pointer = old_pointer;
+ VisitPointer(&new_pointer);
+ DCHECK_EQ(old_pointer, new_pointer);
}
void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
rinfo->IsPatchedDebugBreakSlotSequence());
- Object* target = Code::GetCodeFromTargetAddress(rinfo->debug_call_address());
- Object* old_target = target;
- VisitPointer(&target);
- CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
+ Object* old_pointer =
+ Code::GetCodeFromTargetAddress(rinfo->debug_call_address());
+ Object* new_pointer = old_pointer;
+ VisitPointer(&new_pointer);
+ DCHECK_EQ(old_pointer, new_pointer);
}
void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
- Object* p = rinfo->target_object();
- VisitPointer(&p);
+ Object* old_pointer = rinfo->target_object();
+ Object* new_pointer = old_pointer;
+ VisitPointer(&new_pointer);
+ DCHECK_EQ(old_pointer, new_pointer);
}
void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
- Address p = rinfo->target_external_reference();
- VisitExternalReference(&p);
+ Address old_reference = rinfo->target_external_reference();
+ Address new_reference = old_reference;
+ VisitExternalReference(&new_reference);
+ DCHECK_EQ(old_reference, new_reference);
}
@@ -14109,6 +13719,14 @@ void Code::CopyFrom(const CodeDesc& desc) {
CopyBytes(instruction_start(), desc.buffer,
static_cast<size_t>(desc.instr_size));
+ // copy unwinding info, if any
+ if (desc.unwinding_info) {
+ DCHECK_GT(desc.unwinding_info_size, 0);
+ set_unwinding_info_size(desc.unwinding_info_size);
+ CopyBytes(unwinding_info_start(), desc.unwinding_info,
+ static_cast<size_t>(desc.unwinding_info_size));
+ }
+
// copy reloc info
CopyBytes(relocation_start(),
desc.buffer + desc.buffer_size - desc.reloc_size,
@@ -14156,64 +13774,6 @@ void Code::CopyFrom(const CodeDesc& desc) {
Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size());
}
-// Locate the source position which is closest to the code offset. This is
-// using the source position information embedded in the relocation info.
-// The position returned is relative to the beginning of the script where the
-// source for this function is found.
-int Code::SourcePosition(int code_offset) {
- Address pc = instruction_start() + code_offset;
- int distance = kMaxInt;
- int position = RelocInfo::kNoPosition; // Initially no position found.
- // Run through all the relocation info to find the best matching source
- // position. All the code needs to be considered as the sequence of the
- // instructions in the code does not necessarily follow the same order as the
- // source.
- RelocIterator it(this, RelocInfo::kPositionMask);
- while (!it.done()) {
- // Only look at positions after the current pc.
- if (it.rinfo()->pc() < pc) {
- // Get position and distance.
-
- int dist = static_cast<int>(pc - it.rinfo()->pc());
- int pos = static_cast<int>(it.rinfo()->data());
- // If this position is closer than the current candidate or if it has the
- // same distance as the current candidate and the position is higher then
- // this position is the new candidate.
- if ((dist < distance) ||
- (dist == distance && pos > position)) {
- position = pos;
- distance = dist;
- }
- }
- it.next();
- }
- DCHECK(kind() == FUNCTION || (is_optimized_code() && is_turbofanned()) ||
- is_wasm_code() || position == RelocInfo::kNoPosition);
- return position;
-}
-
-
-// Same as Code::SourcePosition above except it only looks for statement
-// positions.
-int Code::SourceStatementPosition(int code_offset) {
- // First find the position as close as possible using all position
- // information.
- int position = SourcePosition(code_offset);
- // Now find the closest statement position before the position.
- int statement_position = 0;
- RelocIterator it(this, RelocInfo::kPositionMask);
- while (!it.done()) {
- if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
- int p = static_cast<int>(it.rinfo()->data());
- if (statement_position < p && p <= position) {
- statement_position = p;
- }
- }
- it.next();
- }
- return statement_position;
-}
-
SafepointEntry Code::GetSafepointEntry(Address pc) {
SafepointTable table(this);
@@ -14275,150 +13835,55 @@ void Code::FindAndReplace(const FindAndReplacePattern& pattern) {
}
-void Code::FindAllMaps(MapHandleList* maps) {
- DCHECK(is_inline_cache_stub());
- DisallowHeapAllocation no_allocation;
- int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- for (RelocIterator it(this, mask); !it.done(); it.next()) {
- RelocInfo* info = it.rinfo();
- Object* object = info->target_object();
- if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
- if (object->IsMap()) maps->Add(handle(Map::cast(object)));
- }
-}
-
-
-Code* Code::FindFirstHandler() {
- DCHECK(is_inline_cache_stub());
- DisallowHeapAllocation no_allocation;
- int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
- RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- bool skip_next_handler = false;
- for (RelocIterator it(this, mask); !it.done(); it.next()) {
- RelocInfo* info = it.rinfo();
- if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
- Object* obj = info->target_object();
- skip_next_handler |= obj->IsWeakCell() && WeakCell::cast(obj)->cleared();
- } else {
- Code* code = Code::GetCodeFromTargetAddress(info->target_address());
- if (code->kind() == Code::HANDLER) {
- if (!skip_next_handler) return code;
- skip_next_handler = false;
- }
- }
- }
- return NULL;
-}
-
-
-bool Code::FindHandlers(CodeHandleList* code_list, int length) {
- DCHECK(is_inline_cache_stub());
- DisallowHeapAllocation no_allocation;
- int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
- RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- bool skip_next_handler = false;
- int i = 0;
- for (RelocIterator it(this, mask); !it.done(); it.next()) {
- if (i == length) return true;
- RelocInfo* info = it.rinfo();
- if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
- Object* obj = info->target_object();
- skip_next_handler |= obj->IsWeakCell() && WeakCell::cast(obj)->cleared();
- } else {
- Code* code = Code::GetCodeFromTargetAddress(info->target_address());
- // IC stubs with handlers never contain non-handler code objects before
- // handler targets.
- if (code->kind() != Code::HANDLER) break;
- if (!skip_next_handler) {
- code_list->Add(Handle<Code>(code));
- i++;
- }
- skip_next_handler = false;
- }
- }
- return i == length;
-}
-
-
-MaybeHandle<Code> Code::FindHandlerForMap(Map* map) {
- DCHECK(is_inline_cache_stub());
- int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
- RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- bool return_next = false;
- for (RelocIterator it(this, mask); !it.done(); it.next()) {
- RelocInfo* info = it.rinfo();
- if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
- Object* object = info->target_object();
- if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
- if (object == map) return_next = true;
- } else if (return_next) {
- Code* code = Code::GetCodeFromTargetAddress(info->target_address());
- DCHECK(code->kind() == Code::HANDLER);
- return handle(code);
- }
- }
- return MaybeHandle<Code>();
-}
-
-
-Name* Code::FindFirstName() {
- DCHECK(is_inline_cache_stub());
- DisallowHeapAllocation no_allocation;
- int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- for (RelocIterator it(this, mask); !it.done(); it.next()) {
- RelocInfo* info = it.rinfo();
- Object* object = info->target_object();
- if (object->IsName()) return Name::cast(object);
- }
- return NULL;
-}
-
-
void Code::ClearInlineCaches() {
- ClearInlineCaches(NULL);
-}
-
-
-void Code::ClearInlineCaches(Code::Kind kind) {
- ClearInlineCaches(&kind);
-}
-
-
-void Code::ClearInlineCaches(Code::Kind* kind) {
int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
for (RelocIterator it(this, mask); !it.done(); it.next()) {
RelocInfo* info = it.rinfo();
Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
if (target->is_inline_cache_stub()) {
- if (kind == NULL || *kind == target->kind()) {
- IC::Clear(this->GetIsolate(), info->pc(),
- info->host()->constant_pool());
- }
+ IC::Clear(this->GetIsolate(), info->pc(), info->host()->constant_pool());
}
}
}
int AbstractCode::SourcePosition(int offset) {
- return IsBytecodeArray() ? GetBytecodeArray()->SourcePosition(offset)
- : GetCode()->SourcePosition(offset);
+ int position = 0;
+ // Subtract one because the current PC is one instruction after the call site.
+ if (IsCode()) offset--;
+ for (SourcePositionTableIterator iterator(source_position_table());
+ !iterator.done() && iterator.code_offset() <= offset;
+ iterator.Advance()) {
+ position = iterator.source_position();
+ }
+ return position;
}
int AbstractCode::SourceStatementPosition(int offset) {
- return IsBytecodeArray() ? GetBytecodeArray()->SourceStatementPosition(offset)
- : GetCode()->SourceStatementPosition(offset);
+ // First find the closest position.
+ int position = SourcePosition(offset);
+ // Now find the closest statement position before the position.
+ int statement_position = 0;
+ for (SourcePositionTableIterator it(source_position_table()); !it.done();
+ it.Advance()) {
+ if (it.is_statement()) {
+ int p = it.source_position();
+ if (statement_position < p && p <= position) {
+ statement_position = p;
+ }
+ }
+ }
+ return statement_position;
}
-void SharedFunctionInfo::ClearTypeFeedbackInfo() {
- feedback_vector()->ClearSlots(this);
+void JSFunction::ClearTypeFeedbackInfo() {
+ feedback_vector()->ClearSlots(shared());
}
-
-void SharedFunctionInfo::ClearTypeFeedbackInfoAtGCTime() {
- feedback_vector()->ClearSlotsAtGCTime(this);
+void JSFunction::ClearTypeFeedbackInfoAtGCTime() {
+ feedback_vector()->ClearSlotsAtGCTime(shared());
}
-
BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
DisallowHeapAllocation no_gc;
DCHECK(kind() == FUNCTION);
@@ -14441,6 +13906,12 @@ uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) {
return 0;
}
+int Code::LookupRangeInHandlerTable(int code_offset, int* data,
+ HandlerTable::CatchPrediction* prediction) {
+ DCHECK(!is_optimized_code());
+ HandlerTable* table = HandlerTable::cast(handler_table());
+ return table->LookupRange(code_offset, data, prediction);
+}
void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge, NO_MARKING_PARITY);
@@ -14614,14 +14085,14 @@ Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
void Code::PrintDeoptLocation(FILE* out, Address pc) {
Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc);
class SourcePosition pos = info.position;
- if (info.deopt_reason != Deoptimizer::kNoReason || !pos.IsUnknown()) {
+ if (info.deopt_reason != DeoptimizeReason::kNoReason || !pos.IsUnknown()) {
if (FLAG_hydrogen_track_positions) {
PrintF(out, " ;;; deoptimize at %d_%d: %s\n",
pos.inlining_id(), pos.position(),
- Deoptimizer::GetDeoptReason(info.deopt_reason));
+ DeoptimizeReasonToString(info.deopt_reason));
} else {
PrintF(out, " ;;; deoptimize at %d: %s\n", pos.raw(),
- Deoptimizer::GetDeoptReason(info.deopt_reason));
+ DeoptimizeReasonToString(info.deopt_reason));
}
}
}
@@ -14654,6 +14125,14 @@ const char* Code::Kind2String(Kind kind) {
return NULL;
}
+// Identify kind of code.
+const char* AbstractCode::Kind2String(Kind kind) {
+ if (kind < AbstractCode::INTERPRETED_FUNCTION)
+ return Code::Kind2String((Code::Kind)kind);
+ if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION";
+ UNREACHABLE();
+ return NULL;
+}
Handle<WeakCell> Code::WeakCellFor(Handle<Code> code) {
DCHECK(code->kind() == OPTIMIZED_FUNCTION);
@@ -14677,7 +14156,6 @@ WeakCell* Code::CachedWeakCell() {
return NULL;
}
-
#ifdef ENABLE_DISASSEMBLER
void DeoptimizationInputData::DeoptimizationInputDataPrint(
@@ -14811,9 +14289,20 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(
break;
}
+ case Translation::FLOAT_REGISTER: {
+ int reg_code = iterator.Next();
+ os << "{input="
+ << RegisterConfiguration::Crankshaft()->GetFloatRegisterName(
+ reg_code)
+ << "}";
+ break;
+ }
+
case Translation::DOUBLE_REGISTER: {
int reg_code = iterator.Next();
- os << "{input=" << DoubleRegister::from_code(reg_code).ToString()
+ os << "{input="
+ << RegisterConfiguration::Crankshaft()->GetDoubleRegisterName(
+ reg_code)
<< "}";
break;
}
@@ -14842,6 +14331,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(
break;
}
+ case Translation::FLOAT_STACK_SLOT:
case Translation::DOUBLE_STACK_SLOT: {
int input_slot_index = iterator.Next();
os << "{input=" << input_slot_index << "}";
@@ -14886,8 +14376,9 @@ void DeoptimizationOutputData::DeoptimizationOutputDataPrint(
int pc_and_state = this->PcAndState(i)->value();
os << std::setw(6) << this->AstId(i).ToInt() << " " << std::setw(8)
<< FullCodeGenerator::PcField::decode(pc_and_state) << " "
- << FullCodeGenerator::State2String(
- FullCodeGenerator::StateField::decode(pc_and_state)) << "\n";
+ << Deoptimizer::BailoutStateToString(
+ FullCodeGenerator::BailoutStateField::decode(pc_and_state))
+ << "\n";
}
}
@@ -14926,28 +14417,17 @@ const char* Code::ICState2String(InlineCacheState state) {
case UNINITIALIZED: return "UNINITIALIZED";
case PREMONOMORPHIC: return "PREMONOMORPHIC";
case MONOMORPHIC: return "MONOMORPHIC";
- case PROTOTYPE_FAILURE:
- return "PROTOTYPE_FAILURE";
+ case RECOMPUTE_HANDLER:
+ return "RECOMPUTE_HANDLER";
case POLYMORPHIC: return "POLYMORPHIC";
case MEGAMORPHIC: return "MEGAMORPHIC";
case GENERIC: return "GENERIC";
- case DEBUG_STUB: return "DEBUG_STUB";
}
UNREACHABLE();
return NULL;
}
-const char* Code::StubType2String(StubType type) {
- switch (type) {
- case NORMAL: return "NORMAL";
- case FAST: return "FAST";
- }
- UNREACHABLE(); // keep the compiler happy
- return NULL;
-}
-
-
void Code::PrintExtraICState(std::ostream& os, // NOLINT
Kind kind, ExtraICState extra) {
os << "extra_ic_state = ";
@@ -14967,11 +14447,11 @@ void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
os << "major_key = " << (n == NULL ? "null" : n) << "\n";
}
if (is_inline_cache_stub()) {
- os << "ic_state = " << ICState2String(ic_state()) << "\n";
- PrintExtraICState(os, kind(), extra_ic_state());
- if (ic_state() == MONOMORPHIC) {
- os << "type = " << StubType2String(type()) << "\n";
+ if (!IC::ICUseVector(kind())) {
+ InlineCacheState ic_state = IC::StateFromCode(this);
+ os << "ic_state = " << ICState2String(ic_state) << "\n";
}
+ PrintExtraICState(os, kind(), extra_ic_state());
if (is_compare_ic_stub()) {
DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC);
CompareICStub stub(stub_key(), GetIsolate());
@@ -15038,6 +14518,17 @@ void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
}
os << "\n";
+ SourcePositionTableIterator it(source_position_table());
+ if (!it.done()) {
+ os << "Source positions:\n pc offset position\n";
+ for (; !it.done(); it.Advance()) {
+ os << std::setw(10) << it.code_offset() << std::setw(10)
+ << it.source_position() << (it.is_statement() ? " statement" : "")
+ << "\n";
+ }
+ os << "\n";
+ }
+
if (kind() == FUNCTION) {
DeoptimizationOutputData* data =
DeoptimizationOutputData::cast(this->deoptimization_data());
@@ -15090,7 +14581,7 @@ void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
os << "\n";
}
#ifdef OBJECT_PRINT
- if (!type_feedback_info()->IsUndefined()) {
+ if (!type_feedback_info()->IsUndefined(GetIsolate())) {
TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(os);
os << "\n";
}
@@ -15112,52 +14603,29 @@ void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
it.rinfo()->Print(GetIsolate(), os);
}
os << "\n";
-}
-#endif // ENABLE_DISASSEMBLER
-int BytecodeArray::SourcePosition(int offset) {
- int last_position = 0;
- for (interpreter::SourcePositionTableIterator iterator(
- source_position_table());
- !iterator.done() && iterator.bytecode_offset() <= offset;
- iterator.Advance()) {
- last_position = iterator.source_position();
+ if (has_unwinding_info()) {
+ os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n";
+ EhFrameDisassembler eh_frame_disassembler(unwinding_info_start(),
+ unwinding_info_end());
+ eh_frame_disassembler.DisassembleToStream(os);
+ os << "\n";
}
- return last_position;
}
+#endif // ENABLE_DISASSEMBLER
-int BytecodeArray::SourceStatementPosition(int offset) {
- // First find the position as close as possible using all position
- // information.
- int position = SourcePosition(offset);
- // Now find the closest statement position before the position.
- int statement_position = 0;
- interpreter::SourcePositionTableIterator iterator(source_position_table());
- while (!iterator.done()) {
- if (iterator.is_statement()) {
- int p = iterator.source_position();
- if (statement_position < p && p <= position) {
- statement_position = p;
- }
- }
- iterator.Advance();
- }
- return statement_position;
-}
void BytecodeArray::Disassemble(std::ostream& os) {
os << "Parameter count " << parameter_count() << "\n";
os << "Frame size " << frame_size() << "\n";
- Vector<char> buf = Vector<char>::New(50);
const uint8_t* base_address = GetFirstBytecodeAddress();
- interpreter::SourcePositionTableIterator source_positions(
- source_position_table());
+ SourcePositionTableIterator source_positions(source_position_table());
interpreter::BytecodeArrayIterator iterator(handle(this));
while (!iterator.done()) {
if (!source_positions.done() &&
- iterator.current_offset() == source_positions.bytecode_offset()) {
+ iterator.current_offset() == source_positions.code_offset()) {
os << std::setw(5) << source_positions.source_position();
os << (source_positions.is_statement() ? " S> " : " E> ");
source_positions.Advance();
@@ -15165,12 +14633,14 @@ void BytecodeArray::Disassemble(std::ostream& os) {
os << " ";
}
const uint8_t* current_address = base_address + iterator.current_offset();
- SNPrintF(buf, "%p", current_address);
- os << buf.start() << " : ";
- interpreter::Bytecodes::Decode(os, current_address, parameter_count());
+ os << reinterpret_cast<const void*>(current_address) << " @ "
+ << std::setw(4) << iterator.current_offset() << " : ";
+ interpreter::BytecodeDecoder::Decode(os, current_address,
+ parameter_count());
if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) {
- SNPrintF(buf, " (%p)", base_address + iterator.GetJumpTargetOffset());
- os << buf.start();
+ const void* jump_target = base_address + iterator.GetJumpTargetOffset();
+ os << " (" << jump_target << " @ " << iterator.GetJumpTargetOffset()
+ << ")";
}
os << std::endl;
iterator.Advance();
@@ -15196,6 +14666,13 @@ void BytecodeArray::CopyBytecodesTo(BytecodeArray* to) {
from->length());
}
+int BytecodeArray::LookupRangeInHandlerTable(
+ int code_offset, int* data, HandlerTable::CatchPrediction* prediction) {
+ HandlerTable* table = HandlerTable::cast(handler_table());
+ code_offset++; // Point after current bytecode.
+ return table->LookupRange(code_offset, data, prediction);
+}
+
// static
void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
DCHECK(capacity >= 0);
@@ -15203,29 +14680,6 @@ void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
}
-
-// Returns false if the passed-in index is marked non-configurable, which will
-// cause the truncation operation to halt, and thus no further old values need
-// be collected.
-static bool GetOldValue(Isolate* isolate,
- Handle<JSObject> object,
- uint32_t index,
- List<Handle<Object> >* old_values,
- List<uint32_t>* indices) {
- LookupIterator it(isolate, object, index, object, LookupIterator::HIDDEN);
- CHECK(JSReceiver::GetPropertyAttributes(&it).IsJust());
- DCHECK(it.IsFound());
- if (!it.IsConfigurable()) return false;
- Handle<Object> value =
- it.state() == LookupIterator::ACCESSOR
- ? Handle<Object>::cast(isolate->factory()->the_hole_value())
- : JSReceiver::GetDataProperty(&it);
- old_values->Add(value);
- indices->Add(index);
- return true;
-}
-
-
void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
// We should never end in here with a pixel or external array.
DCHECK(array->AllowsSetLength());
@@ -15236,91 +14690,6 @@ void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) {
}
-MaybeHandle<Object> JSArray::ObservableSetLength(Handle<JSArray> array,
- uint32_t new_length) {
- if (!array->map()->is_observed()) {
- SetLength(array, new_length);
- return array;
- }
-
- Isolate* isolate = array->GetIsolate();
- List<uint32_t> indices;
- List<Handle<Object> > old_values;
- Handle<Object> old_length_handle(array->length(), isolate);
- uint32_t old_length = 0;
- CHECK(old_length_handle->ToArrayLength(&old_length));
-
- int num_elements = array->NumberOfOwnElements(ALL_PROPERTIES);
- if (num_elements > 0) {
- if (old_length == static_cast<uint32_t>(num_elements)) {
- // Simple case for arrays without holes.
- for (uint32_t i = old_length - 1; i + 1 > new_length; --i) {
- if (!GetOldValue(isolate, array, i, &old_values, &indices)) break;
- }
- } else {
- // For sparse arrays, only iterate over existing elements.
- // TODO(rafaelw): For fast, sparse arrays, we can avoid iterating over
- // the to-be-removed indices twice.
- Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements);
- array->GetOwnElementKeys(*keys, ALL_PROPERTIES);
- while (num_elements-- > 0) {
- uint32_t index = NumberToUint32(keys->get(num_elements));
- if (index < new_length) break;
- if (!GetOldValue(isolate, array, index, &old_values, &indices)) break;
- }
- }
- }
-
- SetLength(array, new_length);
-
- CHECK(array->length()->ToArrayLength(&new_length));
- if (old_length == new_length) return array;
-
- RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object);
-
- for (int i = 0; i < indices.length(); ++i) {
- // For deletions where the property was an accessor, old_values[i]
- // will be the hole, which instructs EnqueueChangeRecord to elide
- // the "oldValue" property.
- RETURN_ON_EXCEPTION(
- isolate,
- JSObject::EnqueueChangeRecord(
- array, "delete", isolate->factory()->Uint32ToString(indices[i]),
- old_values[i]),
- Object);
- }
-
- RETURN_ON_EXCEPTION(isolate,
- JSObject::EnqueueChangeRecord(
- array, "update", isolate->factory()->length_string(),
- old_length_handle),
- Object);
-
- RETURN_ON_EXCEPTION(isolate, EndPerformSplice(array), Object);
-
- uint32_t index = Min(old_length, new_length);
- uint32_t add_count = new_length > old_length ? new_length - old_length : 0;
- uint32_t delete_count = new_length < old_length ? old_length - new_length : 0;
- Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
- if (delete_count > 0) {
- for (int i = indices.length() - 1; i >= 0; i--) {
- // Skip deletions where the property was an accessor, leaving holes
- // in the array of old values.
- if (old_values[i]->IsTheHole()) continue;
- JSObject::AddDataElement(deleted, indices[i] - index, old_values[i], NONE)
- .Assert();
- }
-
- JSArray::SetLength(deleted, delete_count);
- }
-
- RETURN_ON_EXCEPTION(
- isolate, EnqueueSpliceRecord(array, index, deleted, add_count), Object);
-
- return array;
-}
-
-
// static
void Map::AddDependentCode(Handle<Map> map,
DependentCode::DependencyGroup group,
@@ -15648,10 +15017,10 @@ Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
bool from_javascript,
ShouldThrow should_throw) {
Isolate* isolate = proxy->GetIsolate();
- STACK_CHECK(Nothing<bool>());
+ STACK_CHECK(isolate, Nothing<bool>());
Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
// 1. Assert: Either Type(V) is Object or Type(V) is Null.
- DCHECK(value->IsJSReceiver() || value->IsNull());
+ DCHECK(value->IsJSReceiver() || value->IsNull(isolate));
// 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.
@@ -15670,7 +15039,7 @@ Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
Nothing<bool>());
// 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
- if (trap->IsUndefined()) {
+ if (trap->IsUndefined(isolate)) {
return JSReceiver::SetPrototype(target, value, from_javascript,
should_throw);
}
@@ -15719,46 +15088,10 @@ Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
ShouldThrow should_throw) {
Isolate* isolate = object->GetIsolate();
- const bool observed = from_javascript && object->map()->is_observed();
- Handle<Object> old_value;
- if (observed) {
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, old_value,
- JSReceiver::GetPrototype(isolate, object),
- Nothing<bool>());
- }
-
- Maybe<bool> result =
- SetPrototypeUnobserved(object, value, from_javascript, should_throw);
- MAYBE_RETURN(result, Nothing<bool>());
-
- if (result.FromJust() && observed) {
- Handle<Object> new_value;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, new_value,
- JSReceiver::GetPrototype(isolate, object),
- Nothing<bool>());
- if (!new_value->SameValue(*old_value)) {
- RETURN_ON_EXCEPTION_VALUE(
- isolate, JSObject::EnqueueChangeRecord(
- object, "setPrototype",
- isolate->factory()->proto_string(), old_value),
- Nothing<bool>());
- }
- }
-
- return result;
-}
-
-
-Maybe<bool> JSObject::SetPrototypeUnobserved(Handle<JSObject> object,
- Handle<Object> value,
- bool from_javascript,
- ShouldThrow should_throw) {
#ifdef DEBUG
int size = object->Size();
#endif
- Isolate* isolate = object->GetIsolate();
-
if (from_javascript) {
if (object->IsAccessCheckNeeded() &&
!isolate->MayAccess(handle(isolate->context()), object)) {
@@ -15774,7 +15107,7 @@ Maybe<bool> JSObject::SetPrototypeUnobserved(Handle<JSObject> object,
Heap* heap = isolate->heap();
// Silently ignore the change if value is not a JSObject or null.
// SpiderMonkey behaves this way.
- if (!value->IsJSReceiver() && !value->IsNull()) return Just(true);
+ if (!value->IsJSReceiver() && !value->IsNull(isolate)) return Just(true);
bool dictionary_elements_in_chain =
object->map()->DictionaryElementsInPrototypeChainOnly();
@@ -15784,8 +15117,7 @@ Maybe<bool> JSObject::SetPrototypeUnobserved(Handle<JSObject> object,
if (from_javascript) {
// Find the first object in the chain whose prototype object is not
// hidden.
- PrototypeIterator iter(isolate, real_receiver,
- PrototypeIterator::START_AT_PROTOTYPE,
+ PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype,
PrototypeIterator::END_AT_NON_HIDDEN);
while (!iter.IsAtEnd()) {
// Casting to JSObject is fine because hidden prototypes are never
@@ -15800,6 +15132,13 @@ Maybe<bool> JSObject::SetPrototypeUnobserved(Handle<JSObject> object,
// Nothing to do if prototype is already set.
if (map->prototype() == *value) return Just(true);
+ bool immutable_proto = object->map()->is_immutable_proto();
+ if (immutable_proto) {
+ RETURN_FAILURE(
+ isolate, should_throw,
+ NewTypeError(MessageTemplate::kImmutablePrototypeSet, object));
+ }
+
// From 8.6.2 Object Internal Methods
// ...
// In addition, if [[Extensible]] is false the value of the [[Class]] and
@@ -15818,7 +15157,7 @@ Maybe<bool> JSObject::SetPrototypeUnobserved(Handle<JSObject> object,
// new prototype chain.
if (value->IsJSReceiver()) {
for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
- PrototypeIterator::START_AT_RECEIVER);
+ kStartAtReceiver);
!iter.IsAtEnd(); iter.Advance()) {
if (iter.GetCurrent<JSReceiver>() == *object) {
// Cycle detected.
@@ -15851,6 +15190,17 @@ Maybe<bool> JSObject::SetPrototypeUnobserved(Handle<JSObject> object,
return Just(true);
}
+// static
+void JSObject::SetImmutableProto(Handle<JSObject> object) {
+ DCHECK(!object->IsAccessCheckNeeded()); // Never called from JS
+ Handle<Map> map(object->map());
+
+ // Nothing to do if prototype is already set.
+ if (map->is_immutable_proto()) return;
+
+ Handle<Map> new_map = Map::TransitionToImmutableProto(map);
+ object->set_map(*new_map);
+}
void JSObject::EnsureCanContainElements(Handle<JSObject> object,
Arguments* args,
@@ -15994,12 +15344,8 @@ Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
uint32_t old_length = 0;
uint32_t new_capacity = 0;
- Handle<Object> old_length_handle;
if (object->IsJSArray()) {
CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length));
- if (object->map()->is_observed()) {
- old_length_handle = handle(JSArray::cast(*object)->length(), isolate);
- }
}
ElementsKind kind = object->GetElementsKind();
@@ -16043,38 +15389,6 @@ Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
JSArray::cast(*object)->set_length(*new_length_handle);
}
- if (!old_length_handle.is_null() && new_length != old_length) {
- // |old_length_handle| is kept null above unless the object is observed.
- DCHECK(object->map()->is_observed());
- Handle<JSArray> array = Handle<JSArray>::cast(object);
- Handle<String> name = isolate->factory()->Uint32ToString(index);
-
- RETURN_ON_EXCEPTION_VALUE(isolate, BeginPerformSplice(array),
- Nothing<bool>());
- RETURN_ON_EXCEPTION_VALUE(
- isolate, EnqueueChangeRecord(array, "add", name,
- isolate->factory()->the_hole_value()),
- Nothing<bool>());
- RETURN_ON_EXCEPTION_VALUE(
- isolate, EnqueueChangeRecord(array, "update",
- isolate->factory()->length_string(),
- old_length_handle),
- Nothing<bool>());
- RETURN_ON_EXCEPTION_VALUE(isolate, EndPerformSplice(array),
- Nothing<bool>());
- Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
- RETURN_ON_EXCEPTION_VALUE(isolate,
- EnqueueSpliceRecord(array, old_length, deleted,
- new_length - old_length),
- Nothing<bool>());
- } else if (object->map()->is_observed()) {
- Handle<String> name = isolate->factory()->Uint32ToString(index);
- RETURN_ON_EXCEPTION_VALUE(
- isolate, EnqueueChangeRecord(object, "add", name,
- isolate->factory()->the_hole_value()),
- Nothing<bool>());
- }
-
return Just(true);
}
@@ -16342,10 +15656,11 @@ int JSObject::GetFastElementsUsage() {
#ifdef OBJECT_PRINT
template <typename Derived, typename Shape, typename Key>
void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT
+ Isolate* isolate = this->GetIsolate();
int capacity = this->Capacity();
for (int i = 0; i < capacity; i++) {
Object* k = this->KeyAt(i);
- if (this->IsKey(k)) {
+ if (this->IsKey(isolate, k)) {
os << "\n ";
if (k->IsString()) {
String::cast(k)->StringPrint(os);
@@ -16356,18 +15671,24 @@ void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT
}
}
}
+template <typename Derived, typename Shape, typename Key>
+void Dictionary<Derived, Shape, Key>::Print() {
+ OFStream os(stdout);
+ Print(os);
+}
#endif
template<typename Derived, typename Shape, typename Key>
void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) {
+ Isolate* isolate = this->GetIsolate();
int pos = 0;
int capacity = this->Capacity();
DisallowHeapAllocation no_gc;
WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
for (int i = 0; i < capacity; i++) {
Object* k = this->KeyAt(i);
- if (this->IsKey(k)) {
+ if (this->IsKey(isolate, k)) {
elements->set(pos++, this->ValueAt(i), mode);
}
}
@@ -16377,55 +15698,10 @@ void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) {
MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
bool* done) {
- *done = false;
- Isolate* isolate = it->isolate();
- // Make sure that the top context does not change when doing callbacks or
- // interceptor calls.
- AssertNoContextChange ncc(isolate);
-
DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
- Handle<InterceptorInfo> interceptor = it->GetInterceptor();
- if (interceptor->getter()->IsUndefined()) {
- return isolate->factory()->undefined_value();
- }
-
- Handle<JSObject> holder = it->GetHolder<JSObject>();
- Handle<Object> result;
- Handle<Object> receiver = it->GetReceiver();
- if (!receiver->IsJSReceiver()) {
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
- }
- PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
- *holder, Object::DONT_THROW);
-
- if (it->IsElement()) {
- uint32_t index = it->index();
- v8::IndexedPropertyGetterCallback getter =
- v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
- 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();
- }
-
- v8::GenericNamedPropertyGetterCallback getter =
- v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
- interceptor->getter());
- result = args.Call(getter, name);
- }
-
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
- if (result.is_null()) return isolate->factory()->undefined_value();
- *done = true;
- // Rebox handle before return
- return handle(*result, isolate);
+ return GetPropertyWithInterceptorInternal(it, it->GetInterceptor(), done);
}
-
Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
Handle<Name> name) {
LookupIterator it = LookupIterator::PropertyOrElement(
@@ -16452,6 +15728,10 @@ Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
: Nothing<bool>();
}
+int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) {
+ return ((Page::kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >>
+ ElementsKindToShiftSize(kind));
+}
void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
Object* temp = get(i);
@@ -16565,196 +15845,46 @@ void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
}
}
-void JSObject::CollectOwnPropertyNames(KeyAccumulator* keys,
- PropertyFilter filter) {
- if (HasFastProperties()) {
- int real_size = map()->NumberOfOwnDescriptors();
- Handle<DescriptorArray> descs(map()->instance_descriptors());
- for (int i = 0; i < real_size; i++) {
- PropertyDetails details = descs->GetDetails(i);
- if ((details.attributes() & filter) != 0) continue;
- if (filter & ONLY_ALL_CAN_READ) {
- if (details.kind() != kAccessor) continue;
- Object* accessors = descs->GetValue(i);
- if (!accessors->IsAccessorInfo()) continue;
- if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
- }
- Name* key = descs->GetKey(i);
- if (key->FilterKey(filter)) continue;
- keys->AddKey(key, DO_NOT_CONVERT);
- }
- } else if (IsJSGlobalObject()) {
- GlobalDictionary::CollectKeysTo(handle(global_dictionary()), keys, filter);
- } else {
- NameDictionary::CollectKeysTo(handle(property_dictionary()), keys, filter);
- }
-}
-
-
-int JSObject::NumberOfOwnElements(PropertyFilter filter) {
- // Fast case for objects with no elements.
- if (!IsJSValue() && HasFastElements()) {
- uint32_t length =
- IsJSArray()
- ? static_cast<uint32_t>(
- Smi::cast(JSArray::cast(this)->length())->value())
- : static_cast<uint32_t>(FixedArrayBase::cast(elements())->length());
- if (length == 0) return 0;
- }
- // Compute the number of enumerable elements.
- return GetOwnElementKeys(NULL, filter);
-}
-
-void JSObject::CollectOwnElementKeys(Handle<JSObject> object,
- KeyAccumulator* keys,
- PropertyFilter filter) {
- if (filter & SKIP_STRINGS) return;
- ElementsAccessor* accessor = object->GetElementsAccessor();
- accessor->CollectElementIndices(object, keys, kMaxUInt32, filter, 0);
-}
-
-
-int JSObject::GetOwnElementKeys(FixedArray* storage, PropertyFilter filter) {
- int counter = 0;
-
- // If this is a String wrapper, add the string indices first,
- // as they're guaranteed to precede the elements in numerical order
- // and ascending order is required by ECMA-262, 6th, 9.1.12.
- if (IsJSValue()) {
- Object* val = JSValue::cast(this)->value();
- if (val->IsString()) {
- String* str = String::cast(val);
- if (storage) {
- for (int i = 0; i < str->length(); i++) {
- storage->set(counter + i, Smi::FromInt(i));
- }
- }
- counter += str->length();
- }
- }
-
- switch (GetElementsKind()) {
- case FAST_SMI_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_ELEMENTS:
- case FAST_STRING_WRAPPER_ELEMENTS: {
- int length = IsJSArray() ?
- Smi::cast(JSArray::cast(this)->length())->value() :
- FixedArray::cast(elements())->length();
- for (int i = 0; i < length; i++) {
- if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
- if (storage != NULL) {
- storage->set(counter, Smi::FromInt(i));
- }
- counter++;
- }
- }
- DCHECK(!storage || storage->length() >= counter);
- break;
- }
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS: {
- int length = IsJSArray() ?
- Smi::cast(JSArray::cast(this)->length())->value() :
- FixedArrayBase::cast(elements())->length();
- for (int i = 0; i < length; i++) {
- if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
- if (storage != NULL) {
- storage->set(counter, Smi::FromInt(i));
- }
- counter++;
- }
- }
- DCHECK(!storage || storage->length() >= counter);
- break;
- }
-
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case TYPE##_ELEMENTS: \
-
- TYPED_ARRAYS(TYPED_ARRAY_CASE)
-#undef TYPED_ARRAY_CASE
- {
- int length = FixedArrayBase::cast(elements())->length();
- while (counter < length) {
- if (storage != NULL) {
- storage->set(counter, Smi::FromInt(counter));
- }
- counter++;
- }
- DCHECK(!storage || storage->length() >= counter);
- break;
- }
-
- case DICTIONARY_ELEMENTS:
- case SLOW_STRING_WRAPPER_ELEMENTS: {
- if (storage != NULL) {
- element_dictionary()->CopyKeysTo(storage, counter, filter,
- SeededNumberDictionary::SORTED);
- }
- counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
- break;
- }
- case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
- case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
- FixedArray* parameter_map = FixedArray::cast(elements());
- int mapped_length = parameter_map->length() - 2;
- FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
- if (arguments->IsDictionary()) {
- // Copy the keys from arguments first, because Dictionary::CopyKeysTo
- // will insert in storage starting at index 0.
- SeededNumberDictionary* dictionary =
- SeededNumberDictionary::cast(arguments);
- if (storage != NULL) {
- dictionary->CopyKeysTo(storage, counter, filter,
- SeededNumberDictionary::UNSORTED);
- }
- counter += dictionary->NumberOfElementsFilterAttributes(filter);
- for (int i = 0; i < mapped_length; ++i) {
- if (!parameter_map->get(i + 2)->IsTheHole()) {
- if (storage != NULL) storage->set(counter, Smi::FromInt(i));
- ++counter;
- }
- }
- if (storage != NULL) storage->SortPairs(storage, counter);
-
- } else {
- int backing_length = arguments->length();
- int i = 0;
- for (; i < mapped_length; ++i) {
- if (!parameter_map->get(i + 2)->IsTheHole()) {
- if (storage != NULL) storage->set(counter, Smi::FromInt(i));
- ++counter;
- } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
- if (storage != NULL) storage->set(counter, Smi::FromInt(i));
- ++counter;
- }
- }
- for (; i < backing_length; ++i) {
- if (storage != NULL) storage->set(counter, Smi::FromInt(i));
- ++counter;
- }
- }
- break;
+bool JSObject::WasConstructedFromApiFunction() {
+ auto instance_type = map()->instance_type();
+ bool is_api_object = instance_type == JS_API_OBJECT_TYPE ||
+ instance_type == JS_SPECIAL_API_OBJECT_TYPE;
+#ifdef ENABLE_SLOW_DCHECKS
+ if (FLAG_enable_slow_asserts) {
+ Object* maybe_constructor = map()->GetConstructor();
+ if (!maybe_constructor->IsJSFunction()) return false;
+ JSFunction* constructor = JSFunction::cast(maybe_constructor);
+ if (constructor->shared()->IsApiFunction()) {
+ DCHECK(is_api_object);
+ } else {
+ DCHECK(!is_api_object);
}
- case NO_ELEMENTS:
- break;
}
-
- DCHECK(!storage || storage->length() == counter);
- return counter;
+#endif
+ return is_api_object;
}
-
MaybeHandle<String> Object::ObjectProtoToString(Isolate* isolate,
Handle<Object> object) {
- if (object->IsUndefined()) return isolate->factory()->undefined_to_string();
- if (object->IsNull()) return isolate->factory()->null_to_string();
+ if (*object == isolate->heap()->undefined_value()) {
+ return isolate->factory()->undefined_to_string();
+ }
+ if (*object == isolate->heap()->null_value()) {
+ return isolate->factory()->null_to_string();
+ }
Handle<JSReceiver> receiver =
Object::ToObject(isolate, object).ToHandleChecked();
+ // For proxies, we must check IsArray() before get(toStringTag) to comply
+ // with the specification
+ Maybe<bool> is_array = Nothing<bool>();
+ InstanceType instance_type = receiver->map()->instance_type();
+ if (instance_type == JS_PROXY_TYPE) {
+ is_array = Object::IsArray(receiver);
+ MAYBE_RETURN(is_array, MaybeHandle<String>());
+ }
+
Handle<String> tag;
Handle<Object> to_string_tag;
ASSIGN_RETURN_ON_EXCEPTION(
@@ -16764,11 +15894,55 @@ MaybeHandle<String> Object::ObjectProtoToString(Isolate* isolate,
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);
+ } else {
+ switch (instance_type) {
+ case JS_API_OBJECT_TYPE:
+ case JS_SPECIAL_API_OBJECT_TYPE:
+ tag = handle(receiver->class_name(), isolate);
+ break;
+ case JS_ARGUMENTS_TYPE:
+ return isolate->factory()->arguments_to_string();
+ case JS_ARRAY_TYPE:
+ return isolate->factory()->array_to_string();
+ case JS_BOUND_FUNCTION_TYPE:
+ case JS_FUNCTION_TYPE:
+ return isolate->factory()->function_to_string();
+ case JS_ERROR_TYPE:
+ return isolate->factory()->error_to_string();
+ case JS_DATE_TYPE:
+ return isolate->factory()->date_to_string();
+ case JS_REGEXP_TYPE:
+ return isolate->factory()->regexp_to_string();
+ case JS_PROXY_TYPE: {
+ if (is_array.FromJust()) {
+ return isolate->factory()->array_to_string();
+ }
+ if (receiver->IsCallable()) {
+ return isolate->factory()->function_to_string();
+ }
+ return isolate->factory()->object_to_string();
+ }
+ case JS_VALUE_TYPE: {
+ Object* value = JSValue::cast(*receiver)->value();
+ if (value->IsString()) {
+ return isolate->factory()->string_to_string();
+ }
+ if (value->IsNumber()) {
+ return isolate->factory()->number_to_string();
+ }
+ if (value->IsBoolean()) {
+ return isolate->factory()->boolean_to_string();
+ }
+ if (value->IsSymbol()) {
+ return isolate->factory()->object_to_string();
+ }
+ UNREACHABLE();
+ tag = handle(receiver->class_name(), isolate);
+ break;
+ }
+ default:
+ return isolate->factory()->object_to_string();
+ }
}
IncrementalStringBuilder builder(isolate);
@@ -16778,7 +15952,6 @@ MaybeHandle<String> Object::ObjectProtoToString(Isolate* isolate,
return builder.Finish();
}
-
const char* Symbol::PrivateSymbolToName() const {
Heap* heap = GetIsolate()->heap();
#define SYMBOL_CHECK_AND_PRINT(name) \
@@ -16790,12 +15963,12 @@ const char* Symbol::PrivateSymbolToName() const {
void Symbol::SymbolShortPrint(std::ostream& os) {
- os << "<Symbol: " << Hash();
- if (!name()->IsUndefined()) {
+ os << "<Symbol:";
+ if (!name()->IsUndefined(GetIsolate())) {
os << " ";
HeapStringAllocator allocator;
StringStream accumulator(&allocator);
- String::cast(name())->StringShortPrint(&accumulator);
+ String::cast(name())->StringShortPrint(&accumulator, false);
os << accumulator.ToCString().get();
} else {
os << " (" << PrivateSymbolToName() << ")";
@@ -16847,7 +16020,7 @@ class StringSharedKey : public HashTableKey {
// collection.
Script* script(Script::cast(shared->script()));
hash ^= String::cast(script->source())->Hash();
- STATIC_ASSERT(LANGUAGE_END == 3);
+ STATIC_ASSERT(LANGUAGE_END == 2);
if (is_strict(language_mode)) hash ^= 0x8000;
hash += scope_position;
}
@@ -16913,7 +16086,6 @@ JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) {
flag = JSRegExp::kMultiline;
break;
case 'u':
- if (!FLAG_harmony_unicode_regexps) return JSRegExp::Flags(0);
flag = JSRegExp::kUnicode;
break;
case 'y':
@@ -16945,22 +16117,6 @@ MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, Flags 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));
@@ -16973,7 +16129,13 @@ inline int CountRequiredEscapes(Handle<String> source) {
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++;
+ if (src[i] == '\\') {
+ // Escape. Skip next character;
+ i++;
+ } else if (src[i] == '/') {
+ // Not escaped forward-slash needs escape.
+ escapes++;
+ }
}
return escapes;
}
@@ -16988,7 +16150,14 @@ inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
int s = 0;
int d = 0;
while (s < src.length()) {
- if (src[s] == '/' && (s == 0 || src[s - 1] != '\\')) dst[d++] = '\\';
+ if (src[s] == '\\') {
+ // Escape. Copy this and next character.
+ dst[d++] = src[s++];
+ if (s == src.length()) break;
+ } else if (src[s] == '/') {
+ // Not escaped forward-slash needs escape.
+ dst[d++] = '\\';
+ }
dst[d++] = src[s++];
}
DCHECK_EQ(result->length(), d);
@@ -17051,6 +16220,9 @@ MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source,
EscapeRegExpSource(isolate, source), JSRegExp);
+ RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags),
+ JSRegExp);
+
regexp->set_source(*escaped_source);
regexp->set_flags(Smi::FromInt(flags));
@@ -17063,17 +16235,13 @@ MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
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,
+ JSReceiver::SetProperty(regexp, factory->last_index_string(),
+ Handle<Smi>(Smi::FromInt(0), isolate), STRICT),
+ JSRegExp);
}
- RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags),
- JSRegExp);
-
return regexp;
}
@@ -17214,7 +16382,7 @@ Handle<Derived> HashTable<Derived, Shape, Key>::New(
Factory* factory = isolate->factory();
int length = EntryToIndex(capacity);
Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
- array->set_map_no_write_barrier(*factory->hash_table_map());
+ array->set_map_no_write_barrier(Shape::GetMap(isolate));
Handle<Derived> table = Handle<Derived>::cast(array);
table->SetNumberOfElements(0);
@@ -17244,21 +16412,12 @@ int NameDictionaryBase<Derived, Shape>::FindEntry(Handle<Name> key) {
uint32_t capacity = this->Capacity();
uint32_t entry = Derived::FirstProbe(key->Hash(), capacity);
uint32_t count = 1;
-
+ Isolate* isolate = this->GetIsolate();
while (true) {
- int index = Derived::EntryToIndex(entry);
- Object* element = this->get(index);
- if (element->IsUndefined()) break; // Empty entry.
+ Object* element = this->KeyAt(entry);
+ if (element->IsUndefined(isolate)) break; // Empty entry.
if (*key == element) return entry;
- if (!element->IsUniqueName() &&
- !element->IsTheHole() &&
- Name::cast(element)->Equals(*key)) {
- // Replace a key that is a non-internalized string by the equivalent
- // internalized string for faster further lookups.
- this->set(index, *key);
- return entry;
- }
- DCHECK(element->IsTheHole() || !Name::cast(element)->Equals(*key));
+ DCHECK(element->IsTheHole(isolate) || element->IsUniqueName());
entry = Derived::NextProbe(entry, count++, capacity);
}
return Derived::kNotFound;
@@ -17283,10 +16442,13 @@ void HashTable<Derived, Shape, Key>::Rehash(
// Rehash the elements.
int capacity = this->Capacity();
+ Heap* heap = new_table->GetHeap();
+ Object* the_hole = heap->the_hole_value();
+ Object* undefined = heap->undefined_value();
for (int i = 0; i < capacity; i++) {
uint32_t from_index = EntryToIndex(i);
Object* k = this->get(from_index);
- if (IsKey(k)) {
+ if (k != the_hole && k != undefined) {
uint32_t hash = this->HashForObject(key, k);
uint32_t insertion_index =
EntryToIndex(new_table->FindInsertionEntry(hash));
@@ -17340,6 +16502,7 @@ template<typename Derived, typename Shape, typename Key>
void HashTable<Derived, Shape, Key>::Rehash(Key key) {
DisallowHeapAllocation no_gc;
WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
+ Isolate* isolate = GetIsolate();
uint32_t capacity = Capacity();
bool done = false;
for (int probe = 1; !done; probe++) {
@@ -17347,11 +16510,11 @@ void HashTable<Derived, Shape, Key>::Rehash(Key key) {
// are placed correctly. Other elements might need to be moved.
done = true;
for (uint32_t current = 0; current < capacity; current++) {
- Object* current_key = get(EntryToIndex(current));
- if (IsKey(current_key)) {
+ Object* current_key = KeyAt(current);
+ if (IsKey(isolate, current_key)) {
uint32_t target = EntryForProbe(key, current_key, probe, current);
if (current == target) continue;
- Object* target_key = get(EntryToIndex(target));
+ Object* target_key = KeyAt(target);
if (!IsKey(target_key) ||
EntryForProbe(key, target_key, probe, target) != target) {
// Put the current element into the correct position.
@@ -17367,12 +16530,11 @@ void HashTable<Derived, Shape, Key>::Rehash(Key key) {
}
}
// Wipe deleted entries.
- Heap* heap = GetHeap();
- Object* the_hole = heap->the_hole_value();
- Object* undefined = heap->undefined_value();
+ Object* the_hole = isolate->heap()->the_hole_value();
+ Object* undefined = isolate->heap()->undefined_value();
for (uint32_t current = 0; current < capacity; current++) {
- if (get(EntryToIndex(current)) == the_hole) {
- set(EntryToIndex(current), undefined);
+ if (KeyAt(current) == the_hole) {
+ set(EntryToIndex(current) + Derived::kEntryKeyIndex, undefined);
}
}
SetNumberOfDeletedElements(0);
@@ -17460,9 +16622,10 @@ uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) {
uint32_t entry = FirstProbe(hash, capacity);
uint32_t count = 1;
// EnsureCapacity will guarantee the hash table is never full.
+ Isolate* isolate = GetIsolate();
while (true) {
Object* element = KeyAt(entry);
- if (element->IsUndefined() || element->IsTheHole()) break;
+ if (!IsKey(isolate, element)) break;
entry = NextProbe(entry, count++, capacity);
}
return entry;
@@ -17498,20 +16661,23 @@ template class Dictionary<UnseededNumberDictionary,
uint32_t>;
template Handle<SeededNumberDictionary>
-Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
- New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
+Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::New(
+ Isolate*, int at_least_space_for, PretenureFlag pretenure,
+ MinimumCapacity capacity_option);
template Handle<UnseededNumberDictionary>
-Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
- New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
+Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
+ uint32_t>::New(Isolate*, int at_least_space_for,
+ PretenureFlag pretenure,
+ MinimumCapacity capacity_option);
template Handle<NameDictionary>
-Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
- New(Isolate*, int n, PretenureFlag pretenure);
+Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::New(
+ Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
template Handle<GlobalDictionary>
-Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name> >::New(
- Isolate*, int n, PretenureFlag pretenure);
+Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::New(
+ Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option);
template Handle<SeededNumberDictionary>
Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
@@ -17545,6 +16711,11 @@ template Handle<NameDictionary>
HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
New(Isolate*, int, MinimumCapacity, PretenureFlag);
+template Handle<ObjectHashSet> HashTable<ObjectHashSet, ObjectHashSetShape,
+ Handle<Object>>::New(Isolate*, int n,
+ MinimumCapacity,
+ PretenureFlag);
+
template Handle<NameDictionary>
HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
Shrink(Handle<NameDictionary>, Handle<Name>);
@@ -17558,13 +16729,14 @@ template Handle<UnseededNumberDictionary>
uint32_t>::Shrink(Handle<UnseededNumberDictionary>, uint32_t);
template Handle<NameDictionary>
-Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::Add(
- Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails);
+Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::Add(
+ Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
+ int*);
template Handle<GlobalDictionary>
- Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name> >::Add(
- Handle<GlobalDictionary>, Handle<Name>, Handle<Object>,
- PropertyDetails);
+Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::Add(
+ Handle<GlobalDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
+ int*);
template Handle<FixedArray> Dictionary<
NameDictionary, NameDictionaryShape,
@@ -17575,18 +16747,14 @@ template Handle<FixedArray> Dictionary<
Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>);
template Handle<SeededNumberDictionary>
-Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
- Add(Handle<SeededNumberDictionary>,
- uint32_t,
- Handle<Object>,
- PropertyDetails);
+Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::Add(
+ Handle<SeededNumberDictionary>, uint32_t, Handle<Object>, PropertyDetails,
+ int*);
template Handle<UnseededNumberDictionary>
-Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
- Add(Handle<UnseededNumberDictionary>,
- uint32_t,
- Handle<Object>,
- PropertyDetails);
+Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
+ uint32_t>::Add(Handle<UnseededNumberDictionary>, uint32_t,
+ Handle<Object>, PropertyDetails, int*);
template Handle<SeededNumberDictionary>
Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
@@ -17609,6 +16777,39 @@ template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape,
template int NameDictionaryBase<NameDictionary, NameDictionaryShape>::FindEntry(
Handle<Name>);
+template int Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
+ NumberOfElementsFilterAttributes(PropertyFilter filter);
+
+template int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::
+ NumberOfElementsFilterAttributes(PropertyFilter filter);
+
+template void
+Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
+ CopyEnumKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
+ Handle<Name>>>
+ dictionary,
+ Handle<FixedArray> storage, KeyCollectionMode mode,
+ KeyAccumulator* accumulator);
+
+template void
+Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CopyEnumKeysTo(
+ Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
+ dictionary,
+ Handle<FixedArray> storage, KeyCollectionMode mode,
+ KeyAccumulator* accumulator);
+
+template void
+Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::
+ CollectKeysTo(Handle<Dictionary<GlobalDictionary, GlobalDictionaryShape,
+ Handle<Name>>>
+ dictionary,
+ KeyAccumulator* keys);
+
+template void
+Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::CollectKeysTo(
+ Handle<Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>>
+ dictionary,
+ KeyAccumulator* keys);
Handle<Object> JSObject::PrepareSlowElementsForSort(
Handle<JSObject> object, uint32_t limit) {
@@ -17630,7 +16831,7 @@ Handle<Object> JSObject::PrepareSlowElementsForSort(
DisallowHeapAllocation no_gc;
for (int i = 0; i < capacity; i++) {
Object* k = dict->KeyAt(i);
- if (!dict->IsKey(k)) continue;
+ if (!dict->IsKey(isolate, k)) continue;
DCHECK(k->IsNumber());
DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0);
@@ -17648,7 +16849,7 @@ Handle<Object> JSObject::PrepareSlowElementsForSort(
uint32_t key = NumberToUint32(k);
if (key < limit) {
- if (value->IsUndefined()) {
+ if (value->IsUndefined(isolate)) {
undefs++;
} else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
// Adding an entry with the key beyond smi-range requires
@@ -17705,8 +16906,7 @@ Handle<Object> JSObject::PrepareSlowElementsForSort(
Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
uint32_t limit) {
Isolate* isolate = object->GetIsolate();
- if (object->HasSloppyArgumentsElements() ||
- object->map()->is_observed()) {
+ if (object->HasSloppyArgumentsElements()) {
return handle(Smi::FromInt(-1), isolate);
}
@@ -17799,10 +16999,10 @@ Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
// number of stores of non-undefined, non-the-hole values.
for (unsigned int i = 0; i < undefs; i++) {
Object* current = elements->get(i);
- if (current->IsTheHole()) {
+ if (current->IsTheHole(isolate)) {
holes--;
undefs--;
- } else if (current->IsUndefined()) {
+ } else if (current->IsUndefined(isolate)) {
undefs--;
} else {
continue;
@@ -17810,10 +17010,10 @@ Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
// Position i needs to be filled.
while (undefs > i) {
current = elements->get(undefs);
- if (current->IsTheHole()) {
+ if (current->IsTheHole(isolate)) {
holes--;
undefs--;
- } else if (current->IsUndefined()) {
+ } else if (current->IsUndefined(isolate)) {
undefs--;
} else {
elements->set(i, current, write_barrier);
@@ -17877,29 +17077,35 @@ void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
PropertyCell::InvalidateEntry(dictionary, entry);
}
-
-// TODO(ishell): rename to EnsureEmptyPropertyCell or something.
-Handle<PropertyCell> JSGlobalObject::EnsurePropertyCell(
- Handle<JSGlobalObject> global, Handle<Name> name) {
+Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
+ Handle<JSGlobalObject> global, Handle<Name> name,
+ PropertyCellType cell_type, int* entry_out) {
+ Isolate* isolate = global->GetIsolate();
DCHECK(!global->HasFastProperties());
- auto dictionary = handle(global->global_dictionary());
+ Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate);
int entry = dictionary->FindEntry(name);
Handle<PropertyCell> cell;
if (entry != GlobalDictionary::kNotFound) {
+ if (entry_out) *entry_out = entry;
// This call should be idempotent.
DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
cell = handle(PropertyCell::cast(dictionary->ValueAt(entry)));
- DCHECK(cell->property_details().cell_type() ==
- PropertyCellType::kUninitialized ||
- cell->property_details().cell_type() ==
- PropertyCellType::kInvalidated);
- DCHECK(cell->value()->IsTheHole());
+ PropertyCellType original_cell_type = cell->property_details().cell_type();
+ DCHECK(original_cell_type == PropertyCellType::kInvalidated ||
+ original_cell_type == PropertyCellType::kUninitialized);
+ DCHECK(cell->value()->IsTheHole(isolate));
+ if (original_cell_type == PropertyCellType::kInvalidated) {
+ cell = PropertyCell::InvalidateEntry(dictionary, entry);
+ }
+ PropertyDetails details(NONE, DATA, 0, cell_type);
+ cell->set_property_details(details);
return cell;
}
- Isolate* isolate = global->GetIsolate();
cell = isolate->factory()->NewPropertyCell();
- PropertyDetails details(NONE, DATA, 0, PropertyCellType::kUninitialized);
- dictionary = GlobalDictionary::Add(dictionary, name, cell, details);
+ PropertyDetails details(NONE, DATA, 0, cell_type);
+ dictionary =
+ GlobalDictionary::Add(dictionary, name, cell, details, entry_out);
+ // {*entry_out} is initialized inside GlobalDictionary::Add().
global->set_properties(*dictionary);
return cell;
}
@@ -18036,6 +17242,16 @@ Handle<String> StringTable::LookupString(Isolate* isolate,
Handle<ConsString> cons = Handle<ConsString>::cast(string);
cons->set_first(*result);
cons->set_second(isolate->heap()->empty_string());
+ } else if (string->IsSlicedString()) {
+ STATIC_ASSERT(ConsString::kSize == SlicedString::kSize);
+ DisallowHeapAllocation no_gc;
+ bool one_byte = result->IsOneByteRepresentation();
+ Handle<Map> map = one_byte ? isolate->factory()->cons_one_byte_string_map()
+ : isolate->factory()->cons_string_map();
+ string->set_map(*map);
+ Handle<ConsString> cons = Handle<ConsString>::cast(string);
+ cons->set_first(*result);
+ cons->set_second(isolate->heap()->empty_string());
}
return result;
}
@@ -18096,12 +17312,26 @@ bool StringSet::Has(Handle<String> name) {
return FindEntry(*name) != kNotFound;
}
+Handle<ObjectHashSet> ObjectHashSet::Add(Handle<ObjectHashSet> set,
+ Handle<Object> key) {
+ Isolate* isolate = set->GetIsolate();
+ int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
+
+ if (!set->Has(isolate, key, hash)) {
+ set = EnsureCapacity(set, 1, key);
+ int entry = set->FindInsertionEntry(hash);
+ set->set(EntryToIndex(entry), *key);
+ set->ElementAdded();
+ }
+ return set;
+}
+
Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
Handle<Context> context,
LanguageMode language_mode) {
Isolate* isolate = GetIsolate();
Handle<SharedFunctionInfo> shared(context->closure()->shared());
- StringSharedKey key(src, shared, language_mode, RelocInfo::kNoPosition);
+ StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
int entry = FindEntry(&key);
if (entry == kNotFound) return isolate->factory()->undefined_value();
int index = EntryToIndex(entry);
@@ -18141,24 +17371,12 @@ Handle<CompilationCacheTable> CompilationCacheTable::Put(
Handle<Context> context, LanguageMode language_mode, Handle<Object> value) {
Isolate* isolate = cache->GetIsolate();
Handle<SharedFunctionInfo> shared(context->closure()->shared());
- StringSharedKey key(src, shared, language_mode, RelocInfo::kNoPosition);
- {
- Handle<Object> k = key.AsHandle(isolate);
- DisallowHeapAllocation no_allocation_scope;
- int entry = cache->FindEntry(&key);
- if (entry != kNotFound) {
- cache->set(EntryToIndex(entry), *k);
- cache->set(EntryToIndex(entry) + 1, *value);
- return cache;
- }
- }
-
+ StringSharedKey key(src, shared, language_mode, kNoSourcePosition);
+ Handle<Object> k = key.AsHandle(isolate);
cache = EnsureCapacity(cache, 1, &key);
int entry = cache->FindInsertionEntry(key.Hash());
- Handle<Object> k =
- isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
cache->set(EntryToIndex(entry), *k);
- cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
+ cache->set(EntryToIndex(entry) + 1, *value);
cache->ElementAdded();
return cache;
}
@@ -18251,17 +17469,13 @@ void CompilationCacheTable::Remove(Object* value) {
return;
}
-
-template<typename Derived, typename Shape, typename Key>
+template <typename Derived, typename Shape, typename Key>
Handle<Derived> Dictionary<Derived, Shape, Key>::New(
- Isolate* isolate,
- int at_least_space_for,
- PretenureFlag pretenure) {
+ Isolate* isolate, int at_least_space_for, PretenureFlag pretenure,
+ MinimumCapacity capacity_option) {
DCHECK(0 <= at_least_space_for);
- Handle<Derived> dict = DerivedHashTable::New(isolate,
- at_least_space_for,
- USE_DEFAULT_MINIMUM_CAPACITY,
- pretenure);
+ Handle<Derived> dict = DerivedHashTable::New(isolate, at_least_space_for,
+ capacity_option, pretenure);
// Initialize the next enumeration index.
dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
@@ -18272,7 +17486,8 @@ Handle<Derived> Dictionary<Derived, Shape, Key>::New(
template <typename Derived, typename Shape, typename Key>
Handle<FixedArray> Dictionary<Derived, Shape, Key>::BuildIterationIndicesArray(
Handle<Derived> dictionary) {
- Factory* factory = dictionary->GetIsolate()->factory();
+ Isolate* isolate = dictionary->GetIsolate();
+ Factory* factory = isolate->factory();
int length = dictionary->NumberOfElements();
Handle<FixedArray> iteration_order = factory->NewFixedArray(length);
@@ -18283,7 +17498,7 @@ Handle<FixedArray> Dictionary<Derived, Shape, Key>::BuildIterationIndicesArray(
int capacity = dictionary->Capacity();
int pos = 0;
for (int i = 0; i < capacity; i++) {
- if (dictionary->IsKey(dictionary->KeyAt(i))) {
+ if (dictionary->IsKey(isolate, dictionary->KeyAt(i))) {
int index = dictionary->DetailsAt(i).dictionary_index();
iteration_order->set(pos, Smi::FromInt(i));
enumeration_order->set(pos, Smi::FromInt(index));
@@ -18385,31 +17600,28 @@ Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
return dictionary;
}
-
-template<typename Derived, typename Shape, typename Key>
-Handle<Derived> Dictionary<Derived, Shape, Key>::Add(
- Handle<Derived> dictionary,
- Key key,
- Handle<Object> value,
- PropertyDetails details) {
+template <typename Derived, typename Shape, typename Key>
+Handle<Derived> Dictionary<Derived, Shape, Key>::Add(Handle<Derived> dictionary,
+ Key key,
+ Handle<Object> value,
+ PropertyDetails details,
+ int* entry_out) {
// Valdate key is absent.
SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound));
// Check whether the dictionary should be extended.
dictionary = EnsureCapacity(dictionary, 1, key);
- AddEntry(dictionary, key, value, details, dictionary->Hash(key));
+ int entry = AddEntry(dictionary, key, value, details, dictionary->Hash(key));
+ if (entry_out) *entry_out = entry;
return dictionary;
}
-
-// Add a key, value pair to the dictionary.
-template<typename Derived, typename Shape, typename Key>
-void Dictionary<Derived, Shape, Key>::AddEntry(
- Handle<Derived> dictionary,
- Key key,
- Handle<Object> value,
- PropertyDetails details,
- uint32_t hash) {
+// Add a key, value pair to the dictionary. Returns entry value.
+template <typename Derived, typename Shape, typename Key>
+int Dictionary<Derived, Shape, Key>::AddEntry(Handle<Derived> dictionary,
+ Key key, Handle<Object> value,
+ PropertyDetails details,
+ uint32_t hash) {
// Compute the key object.
Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key);
@@ -18426,20 +17638,21 @@ void Dictionary<Derived, Shape, Key>::AddEntry(
DCHECK((dictionary->KeyAt(entry)->IsNumber() ||
dictionary->KeyAt(entry)->IsName()));
dictionary->ElementAdded();
+ return entry;
}
bool SeededNumberDictionary::HasComplexElements() {
if (!requires_slow_elements()) return false;
+ Isolate* isolate = this->GetIsolate();
int capacity = this->Capacity();
for (int i = 0; i < capacity; i++) {
Object* k = this->KeyAt(i);
- if (this->IsKey(k)) {
- DCHECK(!IsDeleted(i));
- PropertyDetails details = this->DetailsAt(i);
- if (details.type() == ACCESSOR_CONSTANT) return true;
- PropertyAttributes attr = details.attributes();
- if (attr & ALL_ATTRIBUTES_MASK) return true;
- }
+ if (!this->IsKey(isolate, k)) continue;
+ DCHECK(!IsDeleted(i));
+ PropertyDetails details = this->DetailsAt(i);
+ if (details.type() == ACCESSOR_CONSTANT) return true;
+ PropertyAttributes attr = details.attributes();
+ if (attr & ALL_ATTRIBUTES_MASK) return true;
}
return false;
}
@@ -18486,6 +17699,17 @@ Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
return Add(dictionary, key, value, PropertyDetails::Empty());
}
+Handle<UnseededNumberDictionary> UnseededNumberDictionary::DeleteKey(
+ Handle<UnseededNumberDictionary> dictionary, uint32_t key) {
+ int entry = dictionary->FindEntry(key);
+ if (entry == kNotFound) return dictionary;
+
+ Factory* factory = dictionary->GetIsolate()->factory();
+ dictionary->SetEntry(entry, factory->the_hole_value(),
+ factory->the_hole_value());
+ dictionary->ElementRemoved();
+ return dictionary->Shrink(dictionary, key);
+}
Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut(
Handle<SeededNumberDictionary> dictionary, uint32_t key,
@@ -18535,11 +17759,12 @@ Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
template <typename Derived, typename Shape, typename Key>
int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
PropertyFilter filter) {
+ Isolate* isolate = this->GetIsolate();
int capacity = this->Capacity();
int result = 0;
for (int i = 0; i < capacity; i++) {
Object* k = this->KeyAt(i);
- if (this->IsKey(k) && !k->FilterKey(filter)) {
+ if (this->IsKey(isolate, k) && !k->FilterKey(filter)) {
if (this->IsDeleted(i)) continue;
PropertyDetails details = this->DetailsAt(i);
PropertyAttributes attr = details.attributes();
@@ -18561,74 +17786,73 @@ struct EnumIndexComparator {
Dictionary* dict;
};
-
template <typename Derived, typename Shape, typename Key>
-void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(FixedArray* storage) {
+void Dictionary<Derived, Shape, Key>::CopyEnumKeysTo(
+ Handle<Dictionary<Derived, Shape, Key>> dictionary,
+ Handle<FixedArray> storage, KeyCollectionMode mode,
+ KeyAccumulator* accumulator) {
+ Isolate* isolate = dictionary->GetIsolate();
int length = storage->length();
- int capacity = this->Capacity();
+ int capacity = dictionary->Capacity();
int properties = 0;
for (int i = 0; i < capacity; i++) {
- Object* k = this->KeyAt(i);
- if (this->IsKey(k) && !k->IsSymbol()) {
- PropertyDetails details = this->DetailsAt(i);
- if (details.IsDontEnum() || this->IsDeleted(i)) continue;
+ Object* key = dictionary->KeyAt(i);
+ bool is_shadowing_key = false;
+ if (!dictionary->IsKey(isolate, key)) continue;
+ if (key->IsSymbol()) continue;
+ PropertyDetails details = dictionary->DetailsAt(i);
+ if (details.IsDontEnum()) {
+ if (mode == KeyCollectionMode::kIncludePrototypes) {
+ is_shadowing_key = true;
+ } else {
+ continue;
+ }
+ }
+ if (dictionary->IsDeleted(i)) continue;
+ if (is_shadowing_key) {
+ accumulator->AddShadowingKey(key);
+ continue;
+ } else {
storage->set(properties, Smi::FromInt(i));
- properties++;
- if (properties == length) break;
}
+ properties++;
+ if (properties == length) break;
}
+
CHECK_EQ(length, properties);
- EnumIndexComparator<Derived> cmp(static_cast<Derived*>(this));
+ DisallowHeapAllocation no_gc;
+ Dictionary<Derived, Shape, Key>* raw_dictionary = *dictionary;
+ FixedArray* raw_storage = *storage;
+ EnumIndexComparator<Derived> cmp(static_cast<Derived*>(*dictionary));
Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress());
std::sort(start, start + length, cmp);
for (int i = 0; i < length; i++) {
- int index = Smi::cast(storage->get(i))->value();
- storage->set(i, this->KeyAt(index));
- }
-}
-
-
-template <typename Derived, typename Shape, typename Key>
-int Dictionary<Derived, Shape, Key>::CopyKeysTo(
- FixedArray* storage, int index, PropertyFilter filter,
- typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
- DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
- int start_index = index;
- int capacity = this->Capacity();
- for (int i = 0; i < capacity; i++) {
- Object* k = this->KeyAt(i);
- if (!this->IsKey(k) || k->FilterKey(filter)) continue;
- if (this->IsDeleted(i)) continue;
- PropertyDetails details = this->DetailsAt(i);
- PropertyAttributes attr = details.attributes();
- if ((attr & filter) != 0) continue;
- storage->set(index++, k);
- }
- if (sort_mode == Dictionary::SORTED) {
- storage->SortPairs(storage, index);
+ int index = Smi::cast(raw_storage->get(i))->value();
+ raw_storage->set(i, raw_dictionary->KeyAt(index));
}
- DCHECK(storage->length() >= index);
- return index - start_index;
}
template <typename Derived, typename Shape, typename Key>
void Dictionary<Derived, Shape, Key>::CollectKeysTo(
- Handle<Dictionary<Derived, Shape, Key> > dictionary, KeyAccumulator* keys,
- PropertyFilter filter) {
+ Handle<Dictionary<Derived, Shape, Key>> dictionary, KeyAccumulator* keys) {
+ Isolate* isolate = keys->isolate();
int capacity = dictionary->Capacity();
Handle<FixedArray> array =
- keys->isolate()->factory()->NewFixedArray(dictionary->NumberOfElements());
+ isolate->factory()->NewFixedArray(dictionary->NumberOfElements());
int array_size = 0;
-
+ PropertyFilter filter = keys->filter();
{
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->IsKey(isolate, k) || k->FilterKey(filter)) continue;
if (raw_dict->IsDeleted(i)) continue;
PropertyDetails details = raw_dict->DetailsAt(i);
- if ((details.attributes() & filter) != 0) continue;
+ if ((details.attributes() & filter) != 0) {
+ keys->AddShadowingKey(k);
+ continue;
+ }
if (filter & ONLY_ALL_CAN_READ) {
if (details.kind() != kAccessor) continue;
Object* accessors = raw_dict->ValueAt(i);
@@ -18646,9 +17870,23 @@ void Dictionary<Derived, Shape, Key>::CollectKeysTo(
std::sort(start, start + array_size, cmp);
}
+ bool has_seen_symbol = false;
for (int i = 0; i < array_size; i++) {
int index = Smi::cast(array->get(i))->value();
- keys->AddKey(dictionary->KeyAt(index), DO_NOT_CONVERT);
+ Object* key = dictionary->KeyAt(index);
+ if (key->IsSymbol()) {
+ has_seen_symbol = true;
+ continue;
+ }
+ keys->AddKey(key, DO_NOT_CONVERT);
+ }
+ if (has_seen_symbol) {
+ for (int i = 0; i < array_size; i++) {
+ int index = Smi::cast(array->get(i))->value();
+ Object* key = dictionary->KeyAt(index);
+ if (!key->IsSymbol()) continue;
+ keys->AddKey(key, DO_NOT_CONVERT);
+ }
}
}
@@ -18656,27 +17894,26 @@ void Dictionary<Derived, Shape, Key>::CollectKeysTo(
// Backwards lookup (slow).
template<typename Derived, typename Shape, typename Key>
Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) {
+ Isolate* isolate = this->GetIsolate();
int capacity = this->Capacity();
for (int i = 0; i < capacity; i++) {
Object* k = this->KeyAt(i);
- if (this->IsKey(k)) {
- Object* e = this->ValueAt(i);
- // TODO(dcarney): this should be templatized.
- if (e->IsPropertyCell()) {
- e = PropertyCell::cast(e)->value();
- }
- if (e == value) return k;
+ if (!this->IsKey(isolate, k)) continue;
+ Object* e = this->ValueAt(i);
+ // TODO(dcarney): this should be templatized.
+ if (e->IsPropertyCell()) {
+ e = PropertyCell::cast(e)->value();
}
+ if (e == value) return k;
}
- Heap* heap = Dictionary::GetHeap();
- return heap->undefined_value();
+ return isolate->heap()->undefined_value();
}
Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key,
int32_t hash) {
DisallowHeapAllocation no_gc;
- DCHECK(IsKey(*key));
+ DCHECK(IsKey(isolate, *key));
int entry = FindEntry(isolate, key, hash);
if (entry == kNotFound) return isolate->heap()->the_hole_value();
@@ -18686,13 +17923,13 @@ Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key,
Object* ObjectHashTable::Lookup(Handle<Object> key) {
DisallowHeapAllocation no_gc;
- DCHECK(IsKey(*key));
Isolate* isolate = GetIsolate();
+ DCHECK(IsKey(isolate, *key));
// If the object does not have an identity hash, it was never used as a key.
Object* hash = key->GetHash();
- if (hash->IsUndefined()) {
+ if (hash->IsUndefined(isolate)) {
return isolate->heap()->the_hole_value();
}
return Lookup(isolate, key, Smi::cast(hash)->value());
@@ -18707,10 +17944,10 @@ Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) {
Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
Handle<Object> key,
Handle<Object> value) {
- DCHECK(table->IsKey(*key));
- DCHECK(!value->IsTheHole());
-
Isolate* isolate = table->GetIsolate();
+ DCHECK(table->IsKey(isolate, *key));
+ DCHECK(!value->IsTheHole(isolate));
+
// Make sure the key object has an identity hash code.
int32_t hash = Object::GetOrCreateHash(isolate, key)->value();
@@ -18722,10 +17959,9 @@ Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
Handle<Object> key,
Handle<Object> value,
int32_t hash) {
- DCHECK(table->IsKey(*key));
- DCHECK(!value->IsTheHole());
-
Isolate* isolate = table->GetIsolate();
+ DCHECK(table->IsKey(isolate, *key));
+ DCHECK(!value->IsTheHole(isolate));
int entry = table->FindEntry(isolate, key, hash);
@@ -18735,7 +17971,7 @@ Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
return table;
}
- // Rehash if more than 25% of the entries are deleted entries.
+ // Rehash if more than 33% of the entries are deleted entries.
// TODO(jochen): Consider to shrink the fixed array in place.
if ((table->NumberOfDeletedElements() << 1) > table->NumberOfElements()) {
table->Rehash(isolate->factory()->undefined_value());
@@ -18764,10 +18000,10 @@ Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
Handle<Object> key,
bool* was_present) {
- DCHECK(table->IsKey(*key));
+ DCHECK(table->IsKey(table->GetIsolate(), *key));
Object* hash = key->GetHash();
- if (hash->IsUndefined()) {
+ if (hash->IsUndefined(table->GetIsolate())) {
*was_present = false;
return table;
}
@@ -18780,9 +18016,10 @@ Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
Handle<Object> key,
bool* was_present,
int32_t hash) {
- DCHECK(table->IsKey(*key));
+ Isolate* isolate = table->GetIsolate();
+ DCHECK(table->IsKey(isolate, *key));
- int entry = table->FindEntry(table->GetIsolate(), key, hash);
+ int entry = table->FindEntry(isolate, key, hash);
if (entry == kNotFound) {
*was_present = false;
return table;
@@ -18810,9 +18047,10 @@ void ObjectHashTable::RemoveEntry(int entry) {
Object* WeakHashTable::Lookup(Handle<HeapObject> key) {
DisallowHeapAllocation no_gc;
- DCHECK(IsKey(*key));
+ Isolate* isolate = GetIsolate();
+ DCHECK(IsKey(isolate, *key));
int entry = FindEntry(key);
- if (entry == kNotFound) return GetHeap()->the_hole_value();
+ if (entry == kNotFound) return isolate->heap()->the_hole_value();
return get(EntryToValueIndex(entry));
}
@@ -18820,7 +18058,8 @@ Object* WeakHashTable::Lookup(Handle<HeapObject> key) {
Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
Handle<HeapObject> key,
Handle<HeapObject> value) {
- DCHECK(table->IsKey(*key));
+ Isolate* isolate = key->GetIsolate();
+ DCHECK(table->IsKey(isolate, *key));
int entry = table->FindEntry(key);
// Key is already in table, just overwrite value.
if (entry != kNotFound) {
@@ -18828,7 +18067,7 @@ Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
return table;
}
- Handle<WeakCell> key_cell = key->GetIsolate()->factory()->NewWeakCell(key);
+ Handle<WeakCell> key_cell = isolate->factory()->NewWeakCell(key);
// Check whether the hash table should be extended.
table = EnsureCapacity(table, 1, key, TENURED);
@@ -18922,11 +18161,14 @@ Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Clear(
template <class Derived, class Iterator, int entrysize>
bool OrderedHashTable<Derived, Iterator, entrysize>::HasKey(
Handle<Derived> table, Handle<Object> key) {
- int entry = table->KeyToFirstEntry(*key);
+ DisallowHeapAllocation no_gc;
+ Isolate* isolate = table->GetIsolate();
+ Object* raw_key = *key;
+ int entry = table->KeyToFirstEntry(isolate, raw_key);
// Walk the chain in the bucket to find the key.
while (entry != kNotFound) {
Object* candidate_key = table->KeyAt(entry);
- if (candidate_key->SameValueZero(*key)) return true;
+ if (candidate_key->SameValueZero(raw_key)) return true;
entry = table->NextChainEntry(entry);
}
return false;
@@ -18961,25 +18203,46 @@ Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
return table;
}
+Handle<FixedArray> OrderedHashSet::ConvertToKeysArray(
+ Handle<OrderedHashSet> table, GetKeysConversion convert) {
+ Isolate* isolate = table->GetIsolate();
+ int length = table->NumberOfElements();
+ int nof_buckets = table->NumberOfBuckets();
+ // Convert the dictionary to a linear list.
+ Handle<FixedArray> result = Handle<FixedArray>::cast(table);
+ // From this point on table is no longer a valid OrderedHashSet.
+ result->set_map(isolate->heap()->fixed_array_map());
+ for (int i = 0; i < length; i++) {
+ int index = kHashTableStartIndex + nof_buckets + (i * kEntrySize);
+ Object* key = table->get(index);
+ if (convert == GetKeysConversion::kConvertToString && key->IsNumber()) {
+ key = *isolate->factory()->NumberToString(handle(key, isolate));
+ }
+ result->set(i, key);
+ }
+ result->Shrink(length);
+ return result;
+}
template<class Derived, class Iterator, int entrysize>
Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash(
Handle<Derived> table, int new_capacity) {
+ Isolate* isolate = table->GetIsolate();
DCHECK(!table->IsObsolete());
Handle<Derived> new_table =
- Allocate(table->GetIsolate(),
- new_capacity,
- table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
+ Allocate(isolate, new_capacity,
+ isolate->heap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
int nof = table->NumberOfElements();
int nod = table->NumberOfDeletedElements();
int new_buckets = new_table->NumberOfBuckets();
int new_entry = 0;
int removed_holes_index = 0;
+ DisallowHeapAllocation no_gc;
for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
Object* key = table->KeyAt(old_entry);
- if (key->IsTheHole()) {
+ if (key->IsTheHole(isolate)) {
table->SetRemovedIndexAt(removed_holes_index++, old_entry);
continue;
}
@@ -19083,7 +18346,8 @@ void OrderedHashTableIterator<Derived, TableType>::Transition() {
template<class Derived, class TableType>
bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
DisallowHeapAllocation no_allocation;
- if (this->table()->IsUndefined()) return false;
+ Isolate* isolate = this->GetIsolate();
+ if (this->table()->IsUndefined(isolate)) return false;
Transition();
@@ -19091,7 +18355,7 @@ bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
int index = Smi::cast(this->index())->value();
int used_capacity = table->UsedCapacity();
- while (index < used_capacity && table->KeyAt(index)->IsTheHole()) {
+ while (index < used_capacity && table->KeyAt(index)->IsTheHole(isolate)) {
index++;
}
@@ -19099,7 +18363,7 @@ bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
if (index < used_capacity) return true;
- set_table(GetHeap()->undefined_value());
+ set_table(isolate->heap()->undefined_value());
return false;
}
@@ -19218,45 +18482,58 @@ bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
return was_present;
}
-// Check if there is a break point at this code offset.
-bool DebugInfo::HasBreakPoint(int code_offset) {
+// Check if there is a break point at this source position.
+bool DebugInfo::HasBreakPoint(int source_position) {
// Get the break point info object for this code offset.
- Object* break_point_info = GetBreakPointInfo(code_offset);
+ Object* break_point_info = GetBreakPointInfo(source_position);
// If there is no break point info object or no break points in the break
// point info object there is no break point at this code offset.
- if (break_point_info->IsUndefined()) return false;
+ if (break_point_info->IsUndefined(GetIsolate())) return false;
return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
}
-// Get the break point info object for this code offset.
-Object* DebugInfo::GetBreakPointInfo(int code_offset) {
- // Find the index of the break point info object for this code offset.
- int index = GetBreakPointInfoIndex(code_offset);
-
- // Return the break point info object if any.
- if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
- return BreakPointInfo::cast(break_points()->get(index));
+// Get the break point info object for this source position.
+Object* DebugInfo::GetBreakPointInfo(int source_position) {
+ Isolate* isolate = GetIsolate();
+ if (!break_points()->IsUndefined(isolate)) {
+ for (int i = 0; i < break_points()->length(); i++) {
+ if (!break_points()->get(i)->IsUndefined(isolate)) {
+ BreakPointInfo* break_point_info =
+ BreakPointInfo::cast(break_points()->get(i));
+ if (break_point_info->source_position() == source_position) {
+ return break_point_info;
+ }
+ }
+ }
+ }
+ return isolate->heap()->undefined_value();
}
-// Clear a break point at the specified code offset.
-void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info, int code_offset,
+bool DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
Handle<Object> break_point_object) {
- Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_offset),
- debug_info->GetIsolate());
- if (break_point_info->IsUndefined()) return;
- BreakPointInfo::ClearBreakPoint(
- Handle<BreakPointInfo>::cast(break_point_info),
- break_point_object);
+ Isolate* isolate = debug_info->GetIsolate();
+ if (debug_info->break_points()->IsUndefined(isolate)) return false;
+
+ for (int i = 0; i < debug_info->break_points()->length(); i++) {
+ if (debug_info->break_points()->get(i)->IsUndefined(isolate)) continue;
+ Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
+ BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
+ if (BreakPointInfo::HasBreakPointObject(break_point_info,
+ break_point_object)) {
+ BreakPointInfo::ClearBreakPoint(break_point_info, break_point_object);
+ return true;
+ }
+ }
+ return false;
}
-void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int code_offset,
- int source_position, int statement_position,
+void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int source_position,
Handle<Object> break_point_object) {
Isolate* isolate = debug_info->GetIsolate();
- Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_offset),
- isolate);
- if (!break_point_info->IsUndefined()) {
+ Handle<Object> break_point_info(
+ debug_info->GetBreakPointInfo(source_position), isolate);
+ if (!break_point_info->IsUndefined(isolate)) {
BreakPointInfo::SetBreakPoint(
Handle<BreakPointInfo>::cast(break_point_info),
break_point_object);
@@ -19265,17 +18542,18 @@ void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int code_offset,
// Adding a new break point for a code offset which did not have any
// break points before. Try to find a free slot.
+ static const int kNoBreakPointInfo = -1;
int index = kNoBreakPointInfo;
for (int i = 0; i < debug_info->break_points()->length(); i++) {
- if (debug_info->break_points()->get(i)->IsUndefined()) {
+ if (debug_info->break_points()->get(i)->IsUndefined(isolate)) {
index = i;
break;
}
}
if (index == kNoBreakPointInfo) {
// No free slot - extend break point info array.
- Handle<FixedArray> old_break_points =
- Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
+ Handle<FixedArray> old_break_points = Handle<FixedArray>(
+ FixedArray::cast(debug_info->break_points()), isolate);
Handle<FixedArray> new_break_points =
isolate->factory()->NewFixedArray(
old_break_points->length() +
@@ -19292,33 +18570,32 @@ void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int code_offset,
// Allocate new BreakPointInfo object and set the break point.
Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
- new_break_point_info->set_code_offset(code_offset);
new_break_point_info->set_source_position(source_position);
- new_break_point_info->set_statement_position(statement_position);
new_break_point_info->set_break_point_objects(
isolate->heap()->undefined_value());
BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
debug_info->break_points()->set(index, *new_break_point_info);
}
-// Get the break point objects for a code offset.
-Handle<Object> DebugInfo::GetBreakPointObjects(int code_offset) {
- Object* break_point_info = GetBreakPointInfo(code_offset);
- if (break_point_info->IsUndefined()) {
- return GetIsolate()->factory()->undefined_value();
+// Get the break point objects for a source position.
+Handle<Object> DebugInfo::GetBreakPointObjects(int source_position) {
+ Object* break_point_info = GetBreakPointInfo(source_position);
+ Isolate* isolate = GetIsolate();
+ if (break_point_info->IsUndefined(isolate)) {
+ return isolate->factory()->undefined_value();
}
return Handle<Object>(
- BreakPointInfo::cast(break_point_info)->break_point_objects(),
- GetIsolate());
+ BreakPointInfo::cast(break_point_info)->break_point_objects(), isolate);
}
// Get the total number of break points.
int DebugInfo::GetBreakPointCount() {
- if (break_points()->IsUndefined()) return 0;
+ Isolate* isolate = GetIsolate();
+ if (break_points()->IsUndefined(isolate)) return 0;
int count = 0;
for (int i = 0; i < break_points()->length(); i++) {
- if (!break_points()->get(i)->IsUndefined()) {
+ if (!break_points()->get(i)->IsUndefined(isolate)) {
BreakPointInfo* break_point_info =
BreakPointInfo::cast(break_points()->get(i));
count += break_point_info->GetBreakPointCount();
@@ -19331,9 +18608,9 @@ int DebugInfo::GetBreakPointCount() {
Handle<Object> DebugInfo::FindBreakPointInfo(
Handle<DebugInfo> debug_info, Handle<Object> break_point_object) {
Isolate* isolate = debug_info->GetIsolate();
- if (!debug_info->break_points()->IsUndefined()) {
+ if (!debug_info->break_points()->IsUndefined(isolate)) {
for (int i = 0; i < debug_info->break_points()->length(); i++) {
- if (!debug_info->break_points()->get(i)->IsUndefined()) {
+ if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) {
Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
if (BreakPointInfo::HasBreakPointObject(break_point_info,
@@ -19346,30 +18623,12 @@ Handle<Object> DebugInfo::FindBreakPointInfo(
return isolate->factory()->undefined_value();
}
-
-// Find the index of the break point info object for the specified code
-// position.
-int DebugInfo::GetBreakPointInfoIndex(int code_offset) {
- if (break_points()->IsUndefined()) return kNoBreakPointInfo;
- for (int i = 0; i < break_points()->length(); i++) {
- if (!break_points()->get(i)->IsUndefined()) {
- BreakPointInfo* break_point_info =
- BreakPointInfo::cast(break_points()->get(i));
- if (break_point_info->code_offset() == code_offset) {
- return i;
- }
- }
- }
- return kNoBreakPointInfo;
-}
-
-
// Remove the specified break point object.
void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
Handle<Object> break_point_object) {
Isolate* isolate = break_point_info->GetIsolate();
// If there are no break points just ignore.
- if (break_point_info->break_point_objects()->IsUndefined()) return;
+ if (break_point_info->break_point_objects()->IsUndefined(isolate)) return;
// If there is a single break point clear it if it is the same.
if (!break_point_info->break_point_objects()->IsFixedArray()) {
if (break_point_info->break_point_objects() == *break_point_object) {
@@ -19405,7 +18664,7 @@ void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
Isolate* isolate = break_point_info->GetIsolate();
// If there was no break point objects before just set it.
- if (break_point_info->break_point_objects()->IsUndefined()) {
+ if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
break_point_info->set_break_point_objects(*break_point_object);
return;
}
@@ -19440,7 +18699,10 @@ bool BreakPointInfo::HasBreakPointObject(
Handle<BreakPointInfo> break_point_info,
Handle<Object> break_point_object) {
// No break point.
- if (break_point_info->break_point_objects()->IsUndefined()) return false;
+ Isolate* isolate = break_point_info->GetIsolate();
+ if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
+ return false;
+ }
// Single break point.
if (!break_point_info->break_point_objects()->IsFixedArray()) {
return break_point_info->break_point_objects() == *break_point_object;
@@ -19459,7 +18721,7 @@ bool BreakPointInfo::HasBreakPointObject(
// Get the number of break points.
int BreakPointInfo::GetBreakPointCount() {
// No break point.
- if (break_point_objects()->IsUndefined()) return 0;
+ if (break_point_objects()->IsUndefined(GetIsolate())) return 0;
// Single break point.
if (!break_point_objects()->IsFixedArray()) return 1;
// Multiple break points.
@@ -19660,6 +18922,62 @@ void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
}
+namespace {
+
+Script* ScriptFromJSValue(Object* in) {
+ DCHECK(in->IsJSValue());
+ JSValue* jsvalue = JSValue::cast(in);
+ DCHECK(jsvalue->value()->IsScript());
+ return Script::cast(jsvalue->value());
+}
+
+} // namespace
+
+int JSMessageObject::GetLineNumber() const {
+ if (start_position() == -1) return Message::kNoLineNumberInfo;
+
+ Handle<Script> the_script = handle(ScriptFromJSValue(script()));
+
+ Script::PositionInfo info;
+ const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
+ if (!the_script->GetPositionInfo(start_position(), &info, offset_flag)) {
+ return Message::kNoLineNumberInfo;
+ }
+
+ return info.line + 1;
+}
+
+int JSMessageObject::GetColumnNumber() const {
+ if (start_position() == -1) return -1;
+
+ Handle<Script> the_script = handle(ScriptFromJSValue(script()));
+
+ Script::PositionInfo info;
+ const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
+ if (!the_script->GetPositionInfo(start_position(), &info, offset_flag)) {
+ return -1;
+ }
+
+ return info.column; // Note: No '+1' in contrast to GetLineNumber.
+}
+
+Handle<String> JSMessageObject::GetSourceLine() const {
+ Handle<Script> the_script = handle(ScriptFromJSValue(script()));
+
+ Isolate* isolate = the_script->GetIsolate();
+ if (the_script->type() == Script::TYPE_WASM) {
+ return isolate->factory()->empty_string();
+ }
+
+ Script::PositionInfo info;
+ const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
+ if (!the_script->GetPositionInfo(start_position(), &info, offset_flag)) {
+ return isolate->factory()->empty_string();
+ }
+
+ Handle<String> src = handle(String::cast(the_script->source()), isolate);
+ return isolate->factory()->NewSubString(src, info.line_start, info.line_end);
+}
void JSArrayBuffer::Neuter() {
CHECK(is_neuterable());
@@ -19776,20 +19094,19 @@ Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
return MaterializeArrayBuffer(self);
}
-
Handle<PropertyCell> PropertyCell::InvalidateEntry(
Handle<GlobalDictionary> dictionary, int entry) {
Isolate* isolate = dictionary->GetIsolate();
// Swap with a copy.
DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
- auto new_cell = isolate->factory()->NewPropertyCell();
+ Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell();
new_cell->set_value(cell->value());
dictionary->ValueAtPut(entry, *new_cell);
- bool is_the_hole = cell->value()->IsTheHole();
+ bool is_the_hole = cell->value()->IsTheHole(isolate);
// Cell is officially mutable henceforth.
PropertyDetails details = cell->property_details();
- details = details.set_cell_type(is_the_hole ? PropertyCellType::kInvalidated
+ details = details.set_cell_type(is_the_hole ? PropertyCellType::kUninitialized
: PropertyCellType::kMutable);
new_cell->set_property_details(details);
// Old cell is ready for invalidation.
@@ -19830,12 +19147,13 @@ PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell,
Handle<Object> value,
PropertyDetails details) {
PropertyCellType type = details.cell_type();
- DCHECK(!value->IsTheHole());
- if (cell->value()->IsTheHole()) {
+ Isolate* isolate = cell->GetIsolate();
+ DCHECK(!value->IsTheHole(isolate));
+ if (cell->value()->IsTheHole(isolate)) {
switch (type) {
// Only allow a cell to transition once into constant state.
case PropertyCellType::kUninitialized:
- if (value->IsUndefined()) return PropertyCellType::kUndefined;
+ if (value->IsUndefined(isolate)) return PropertyCellType::kUndefined;
return PropertyCellType::kConstant;
case PropertyCellType::kInvalidated:
return PropertyCellType::kMutable;
@@ -19862,10 +19180,11 @@ PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell,
return PropertyCellType::kMutable;
}
-
-void PropertyCell::UpdateCell(Handle<GlobalDictionary> dictionary, int entry,
- Handle<Object> value, PropertyDetails details) {
- DCHECK(!value->IsTheHole());
+Handle<PropertyCell> PropertyCell::PrepareForValue(
+ Handle<GlobalDictionary> dictionary, int entry, Handle<Object> value,
+ PropertyDetails details) {
+ Isolate* isolate = dictionary->GetIsolate();
+ DCHECK(!value->IsTheHole(isolate));
DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
const PropertyDetails original_details = cell->property_details();
@@ -19876,11 +19195,9 @@ void PropertyCell::UpdateCell(Handle<GlobalDictionary> dictionary, int entry,
PropertyCellType old_type = original_details.cell_type();
// Preserve the enumeration index unless the property was deleted or never
// initialized.
- if (cell->value()->IsTheHole()) {
+ if (cell->value()->IsTheHole(isolate)) {
index = dictionary->NextEnumerationIndex();
dictionary->SetNextEnumerationIndex(index + 1);
- // Negative lookup cells must be invalidated.
- invalidate = true;
}
DCHECK(index > 0);
details = details.set_index(index);
@@ -19888,18 +19205,17 @@ void PropertyCell::UpdateCell(Handle<GlobalDictionary> dictionary, int entry,
PropertyCellType new_type = UpdatedType(cell, value, original_details);
if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry);
- // Install new property details and cell value.
+ // Install new property details.
details = details.set_cell_type(new_type);
cell->set_property_details(details);
- cell->set_value(*value);
// Deopt when transitioning from a constant type.
if (!invalidate && (old_type != new_type ||
original_details.IsReadOnly() != details.IsReadOnly())) {
- Isolate* isolate = dictionary->GetIsolate();
cell->dependent_code()->DeoptimizeDependentCodeGroup(
isolate, DependentCode::kPropertyCellChangedGroup);
}
+ return cell;
}
@@ -19914,5 +19230,56 @@ void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell,
}
}
+int JSGeneratorObject::source_position() const {
+ CHECK(is_suspended());
+ AbstractCode* code;
+ int code_offset;
+ if (function()->shared()->HasBytecodeArray()) {
+ // New-style generators.
+ DCHECK(!function()->shared()->HasBaselineCode());
+ code_offset = Smi::cast(input_or_debug_pos())->value();
+ // The stored bytecode offset is relative to a different base than what
+ // is used in the source position table, hence the subtraction.
+ code_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
+ code = AbstractCode::cast(function()->shared()->bytecode_array());
+ } else {
+ // Old-style generators.
+ DCHECK(function()->shared()->HasBaselineCode());
+ code_offset = continuation();
+ CHECK(0 <= code_offset);
+ CHECK(code_offset < function()->code()->instruction_size());
+ code = AbstractCode::cast(function()->shared()->code());
+ }
+ return code->SourcePosition(code_offset);
+}
+
+// static
+AccessCheckInfo* AccessCheckInfo::Get(Isolate* isolate,
+ Handle<JSObject> receiver) {
+ DisallowHeapAllocation no_gc;
+ DCHECK(receiver->map()->is_access_check_needed());
+ Object* maybe_constructor = receiver->map()->GetConstructor();
+ // Might happen for a detached context.
+ if (!maybe_constructor->IsJSFunction()) return nullptr;
+ JSFunction* constructor = JSFunction::cast(maybe_constructor);
+ // Might happen for the debug context.
+ if (!constructor->shared()->IsApiFunction()) return nullptr;
+
+ Object* data_obj =
+ constructor->shared()->get_api_func_data()->access_check_info();
+ if (data_obj->IsUndefined(isolate)) return nullptr;
+
+ return AccessCheckInfo::cast(data_obj);
+}
+
+bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
+ for (PrototypeIterator iter(isolate, this, kStartAtReceiver,
+ PrototypeIterator::END_AT_NULL);
+ !iter.IsAtEnd(); iter.AdvanceIgnoringProxies()) {
+ if (iter.GetCurrent<Object>()->IsJSProxy()) return true;
+ }
+ return false;
+}
+
} // namespace internal
} // namespace v8