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.cc808
1 files changed, 736 insertions, 72 deletions
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc
index 00721c2d1b..44271db9fb 100644
--- a/deps/v8/src/objects.cc
+++ b/deps/v8/src/objects.cc
@@ -8,6 +8,8 @@
#include <iomanip>
#include <memory>
#include <sstream>
+#include <unordered_map>
+#include <unordered_set>
#include "src/objects-inl.h"
@@ -60,7 +62,7 @@
#include "src/string-stream.h"
#include "src/utils.h"
#include "src/wasm/wasm-module.h"
-#include "src/zone.h"
+#include "src/zone/zone.h"
#ifdef ENABLE_DISASSEMBLER
#include "src/disasm.h"
@@ -995,12 +997,12 @@ MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
case LookupIterator::ACCESSOR:
return GetPropertyWithAccessor(it);
case LookupIterator::INTEGER_INDEXED_EXOTIC:
- return ReadAbsentProperty(it);
+ return it->isolate()->factory()->undefined_value();
case LookupIterator::DATA:
return it->GetDataValue();
}
}
- return ReadAbsentProperty(it);
+ return it->isolate()->factory()->undefined_value();
}
@@ -1349,7 +1351,7 @@ MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
Object::DONT_THROW);
Handle<Object> result = args.Call(call_fun, name);
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
- if (result.is_null()) return ReadAbsentProperty(isolate, receiver, name);
+ if (result.is_null()) return isolate->factory()->undefined_value();
// Rebox handle before return.
return handle(*result, isolate);
}
@@ -1366,7 +1368,7 @@ MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
receiver, Handle<JSReceiver>::cast(getter));
}
// Getter is not a function.
- return ReadAbsentProperty(isolate, receiver, it->GetName());
+ return isolate->factory()->undefined_value();
}
// static
@@ -1677,6 +1679,71 @@ Maybe<bool> SetPropertyWithInterceptorInternal(
return Just(result);
}
+Maybe<bool> DefinePropertyWithInterceptorInternal(
+ LookupIterator* it, Handle<InterceptorInfo> interceptor,
+ Object::ShouldThrow should_throw, PropertyDescriptor& desc) {
+ Isolate* isolate = it->isolate();
+ // Make sure that the top context does not change when doing callbacks or
+ // interceptor calls.
+ AssertNoContextChange ncc(isolate);
+
+ if (interceptor->definer()->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);
+
+ std::unique_ptr<v8::PropertyDescriptor> descriptor(
+ new v8::PropertyDescriptor());
+ if (PropertyDescriptor::IsAccessorDescriptor(&desc)) {
+ descriptor.reset(new v8::PropertyDescriptor(
+ v8::Utils::ToLocal(desc.get()), v8::Utils::ToLocal(desc.set())));
+ } else if (PropertyDescriptor::IsDataDescriptor(&desc)) {
+ if (desc.has_writable()) {
+ descriptor.reset(new v8::PropertyDescriptor(
+ v8::Utils::ToLocal(desc.value()), desc.writable()));
+ } else {
+ descriptor.reset(
+ new v8::PropertyDescriptor(v8::Utils::ToLocal(desc.value())));
+ }
+ }
+ if (desc.has_enumerable()) {
+ descriptor->set_enumerable(desc.enumerable());
+ }
+ if (desc.has_configurable()) {
+ descriptor->set_configurable(desc.configurable());
+ }
+
+ if (it->IsElement()) {
+ uint32_t index = it->index();
+ v8::IndexedPropertyDefinerCallback definer =
+ v8::ToCData<v8::IndexedPropertyDefinerCallback>(interceptor->definer());
+ result = !args.Call(definer, index, *descriptor).is_null();
+ } else {
+ Handle<Name> name = it->name();
+ DCHECK(!name->IsPrivate());
+
+ if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
+ return Just(false);
+ }
+
+ v8::GenericNamedPropertyDefinerCallback definer =
+ v8::ToCData<v8::GenericNamedPropertyDefinerCallback>(
+ interceptor->definer());
+ result = !args.Call(definer, name, *descriptor).is_null();
+ }
+
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>());
+ return Just(result);
+}
+
} // namespace
MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
@@ -2415,10 +2482,6 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) {
accumulator->Add("<JS Generator>");
break;
}
- case JS_MODULE_TYPE: {
- accumulator->Add("<JS Module>");
- break;
- }
// All other JSObjects are rather similar to each other (JSObject,
// JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue).
default: {
@@ -3449,9 +3512,16 @@ void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
// Ensure that in-object space of slow-mode object does not contain random
// garbage.
int inobject_properties = new_map->GetInObjectProperties();
- for (int i = 0; i < inobject_properties; i++) {
- FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
- object->RawFastPropertyAtPut(index, Smi::FromInt(0));
+ if (inobject_properties) {
+ Heap* heap = isolate->heap();
+ heap->ClearRecordedSlotRange(
+ object->address() + map->GetInObjectPropertyOffset(0),
+ object->address() + new_instance_size);
+
+ for (int i = 0; i < inobject_properties; i++) {
+ FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
+ object->RawFastPropertyAtPut(index, Smi::FromInt(0));
+ }
}
isolate->counters()->props_to_dictionary()->Increment();
@@ -4576,13 +4646,6 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
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"
@@ -4761,17 +4824,6 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
return AddDataProperty(&own_lookup, value, NONE, should_throw, store_mode);
}
-MaybeHandle<Object> Object::ReadAbsentProperty(LookupIterator* it) {
- return it->isolate()->factory()->undefined_value();
-}
-
-MaybeHandle<Object> Object::ReadAbsentProperty(Isolate* isolate,
- Handle<Object> receiver,
- Handle<Object> name) {
- return isolate->factory()->undefined_value();
-}
-
-
Maybe<bool> Object::CannotCreateProperty(Isolate* isolate,
Handle<Object> receiver,
Handle<Object> name,
@@ -6542,6 +6594,34 @@ Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
it.Next();
}
+ // Handle interceptor
+ if (it.state() == 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 = DefinePropertyWithInterceptorInternal(
+ &it, it.GetInterceptor(), should_throw, *desc);
+ if (result.IsNothing() || result.FromJust()) {
+ return result;
+ }
+ // Interceptor modified the store target but failed to set the
+ // property.
+ if (!store_target_map.is_null() &&
+ *store_target_map != it.GetStoreTarget()->map()) {
+ it.isolate()->PushStackTraceAndDie(
+ 0xabababaa, v8::ToCData<void*>(it.GetInterceptor()->definer()),
+ nullptr, 0xabababab);
+ }
+ Utils::ApiCheck(store_target_map.is_null() ||
+ *store_target_map == it.GetStoreTarget()->map(),
+ it.IsElement() ? "v8::IndexedPropertyDefinerCallback"
+ : "v8::NamedPropertyDefinerCallback",
+ "Interceptor silently changed store target.");
+ }
+ }
+
return OrdinaryDefineOwnProperty(&it, desc, should_throw);
}
@@ -7261,6 +7341,57 @@ Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
return GetOwnPropertyDescriptor(&it, desc);
}
+namespace {
+
+Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
+ PropertyDescriptor* desc) {
+ if (it->state() == LookupIterator::INTERCEPTOR) {
+ Isolate* isolate = it->isolate();
+ Handle<InterceptorInfo> interceptor = it->GetInterceptor();
+ if (!interceptor->descriptor()->IsUndefined(isolate)) {
+ Handle<Object> result;
+ Handle<JSObject> holder = it->GetHolder<JSObject>();
+
+ 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, Object::DONT_THROW);
+ if (it->IsElement()) {
+ uint32_t index = it->index();
+ v8::IndexedPropertyDescriptorCallback descriptorCallback =
+ v8::ToCData<v8::IndexedPropertyDescriptorCallback>(
+ interceptor->descriptor());
+
+ result = args.Call(descriptorCallback, index);
+ } else {
+ Handle<Name> name = it->name();
+ DCHECK(!name->IsPrivate());
+ v8::GenericNamedPropertyDescriptorCallback descriptorCallback =
+ v8::ToCData<v8::GenericNamedPropertyDescriptorCallback>(
+ interceptor->descriptor());
+ result = args.Call(descriptorCallback, name);
+ }
+ if (!result.is_null()) {
+ // Request successfully intercepted, try to set the property
+ // descriptor.
+ Utils::ApiCheck(
+ PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc),
+ it->IsElement() ? "v8::IndexedPropertyDescriptorCallback"
+ : "v8::NamedPropertyDescriptorCallback",
+ "Invalid property descriptor.");
+
+ return Just(true);
+ }
+ }
+ }
+ return Just(false);
+}
+} // namespace
// ES6 9.1.5.1
// Returns true on success, false if the property didn't exist, nothing if
@@ -7275,6 +7406,13 @@ Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
it->GetName(), desc);
}
+ Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc);
+ MAYBE_RETURN(intercepted, Nothing<bool>());
+ if (intercepted.FromJust()) {
+ return Just(true);
+ }
+
+ // Request was not intercepted, continue as normal.
// 1. (Assert)
// 2. If O does not have an own property with key P, return undefined.
Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
@@ -9367,12 +9505,6 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
*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());
@@ -9459,12 +9591,6 @@ Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
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));
@@ -10177,22 +10303,76 @@ bool ArrayList::IsFull() {
return kFirstIndex + Length() == capacity;
}
+namespace {
-Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
+Handle<FixedArray> EnsureSpaceInFixedArray(Handle<FixedArray> array,
+ int length) {
int capacity = array->length();
- bool empty = (capacity == 0);
- if (capacity < kFirstIndex + length) {
+ if (capacity < length) {
Isolate* isolate = array->GetIsolate();
- int new_capacity = kFirstIndex + length;
+ int new_capacity = length;
new_capacity = new_capacity + Max(new_capacity / 2, 2);
int grow_by = new_capacity - capacity;
array = Handle<ArrayList>::cast(
isolate->factory()->CopyFixedArrayAndGrow(array, grow_by));
- if (empty) array->SetLength(0);
}
return array;
}
+} // namespace
+
+Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
+ const bool empty = (array->length() == 0);
+ auto ret = Handle<ArrayList>::cast(
+ EnsureSpaceInFixedArray(array, kFirstIndex + length));
+ if (empty) ret->SetLength(0);
+ return ret;
+}
+
+// static
+Handle<FrameArray> FrameArray::AppendJSFrame(Handle<FrameArray> in,
+ Handle<Object> receiver,
+ Handle<JSFunction> function,
+ Handle<AbstractCode> code,
+ int offset, int flags) {
+ const int frame_count = in->FrameCount();
+ const int new_length = LengthFor(frame_count + 1);
+ Handle<FrameArray> array = EnsureSpace(in, new_length);
+ array->SetReceiver(frame_count, *receiver);
+ array->SetFunction(frame_count, *function);
+ array->SetCode(frame_count, *code);
+ array->SetOffset(frame_count, Smi::FromInt(offset));
+ array->SetFlags(frame_count, Smi::FromInt(flags));
+ array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
+ return array;
+}
+
+// static
+Handle<FrameArray> FrameArray::AppendWasmFrame(Handle<FrameArray> in,
+ Handle<Object> wasm_object,
+ int wasm_function_index,
+ Handle<AbstractCode> code,
+ int offset, int flags) {
+ const int frame_count = in->FrameCount();
+ const int new_length = LengthFor(frame_count + 1);
+ Handle<FrameArray> array = EnsureSpace(in, new_length);
+ array->SetWasmObject(frame_count, *wasm_object);
+ array->SetWasmFunctionIndex(frame_count, Smi::FromInt(wasm_function_index));
+ array->SetCode(frame_count, *code);
+ array->SetOffset(frame_count, Smi::FromInt(offset));
+ array->SetFlags(frame_count, Smi::FromInt(flags));
+ array->set(kFrameCountIndex, Smi::FromInt(frame_count + 1));
+ return array;
+}
+
+void FrameArray::ShrinkToFit() { Shrink(LengthFor(FrameCount())); }
+
+// static
+Handle<FrameArray> FrameArray::EnsureSpace(Handle<FrameArray> array,
+ int length) {
+ return Handle<FrameArray>::cast(EnsureSpaceInFixedArray(array, length));
+}
+
Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
int number_of_descriptors,
int slack,
@@ -10919,7 +11099,7 @@ String* ConsStringIterator::NextLeaf(bool* blew_stack) {
if ((type & kStringRepresentationMask) != kConsStringTag) {
AdjustMaximumDepth();
int length = string->length();
- DCHECK(length != 0);
+ if (length == 0) break; // Skip empty left-hand sides of ConsStrings.
consumed_ += length;
return string;
}
@@ -11461,6 +11641,118 @@ int String::IndexOf(Isolate* isolate, Handle<String> sub, Handle<String> pat,
return SearchString(isolate, seq_sub.ToUC16Vector(), pat_vector, start_index);
}
+namespace { // for String.Prototype.lastIndexOf
+
+template <typename schar, typename pchar>
+int StringMatchBackwards(Vector<const schar> subject,
+ Vector<const pchar> pattern, int idx) {
+ int pattern_length = pattern.length();
+ DCHECK(pattern_length >= 1);
+ DCHECK(idx + pattern_length <= subject.length());
+
+ if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
+ for (int i = 0; i < pattern_length; i++) {
+ uc16 c = pattern[i];
+ if (c > String::kMaxOneByteCharCode) {
+ return -1;
+ }
+ }
+ }
+
+ pchar pattern_first_char = pattern[0];
+ for (int i = idx; i >= 0; i--) {
+ if (subject[i] != pattern_first_char) continue;
+ int j = 1;
+ while (j < pattern_length) {
+ if (pattern[j] != subject[i + j]) {
+ break;
+ }
+ j++;
+ }
+ if (j == pattern_length) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+} // namespace
+
+Object* String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
+ Handle<Object> search, Handle<Object> position) {
+ if (receiver->IsNull(isolate) || receiver->IsUndefined(isolate)) {
+ THROW_NEW_ERROR_RETURN_FAILURE(
+ isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
+ isolate->factory()->NewStringFromAsciiChecked(
+ "String.prototype.lastIndexOf")));
+ }
+ Handle<String> receiver_string;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_string,
+ Object::ToString(isolate, receiver));
+
+ Handle<String> search_string;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
+ Object::ToString(isolate, search));
+
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
+ Object::ToNumber(position));
+
+ uint32_t start_index;
+
+ if (position->IsNaN()) {
+ start_index = receiver_string->length();
+ } else {
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
+ Object::ToInteger(isolate, position));
+
+ double position_number = std::max(position->Number(), 0.0);
+ position_number = std::min(position_number,
+ static_cast<double>(receiver_string->length()));
+ start_index = static_cast<uint32_t>(position_number);
+ }
+
+ uint32_t pattern_length = search_string->length();
+ uint32_t receiver_length = receiver_string->length();
+
+ if (start_index + pattern_length > receiver_length) {
+ start_index = receiver_length - pattern_length;
+ }
+
+ if (pattern_length == 0) {
+ return Smi::FromInt(start_index);
+ }
+
+ receiver_string = String::Flatten(receiver_string);
+ search_string = String::Flatten(search_string);
+
+ int last_index = -1;
+ DisallowHeapAllocation no_gc; // ensure vectors stay valid
+
+ String::FlatContent receiver_content = receiver_string->GetFlatContent();
+ String::FlatContent search_content = search_string->GetFlatContent();
+
+ if (search_content.IsOneByte()) {
+ Vector<const uint8_t> pat_vector = search_content.ToOneByteVector();
+ if (receiver_content.IsOneByte()) {
+ last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
+ pat_vector, start_index);
+ } else {
+ last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
+ pat_vector, start_index);
+ }
+ } else {
+ Vector<const uc16> pat_vector = search_content.ToUC16Vector();
+ if (receiver_content.IsOneByte()) {
+ last_index = StringMatchBackwards(receiver_content.ToOneByteVector(),
+ pat_vector, start_index);
+ } else {
+ last_index = StringMatchBackwards(receiver_content.ToUC16Vector(),
+ pat_vector, start_index);
+ }
+ }
+ return Smi::FromInt(last_index);
+}
+
bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
int slen = length();
// Can't check exact length equality, but we can check bounds.
@@ -12361,8 +12653,6 @@ Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
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()) {
@@ -12562,7 +12852,6 @@ bool CanSubclassHaveInobjectProperties(InstanceType instance_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:
@@ -12620,7 +12909,8 @@ bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
- DCHECK(function->IsConstructor() || function->shared()->is_resumable());
+ DCHECK(function->IsConstructor() ||
+ IsResumableFunction(function->shared()->kind()));
if (function->has_initial_map()) return;
Isolate* isolate = function->GetIsolate();
@@ -12631,7 +12921,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_resumable()) {
+ if (IsResumableFunction(function->shared()->kind())) {
instance_type = JS_GENERATOR_OBJECT_TYPE;
} else {
instance_type = JS_OBJECT_TYPE;
@@ -12862,17 +13152,18 @@ 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()) {
+ FunctionKind kind = shared_info->kind();
+ if (!IsArrowFunction(kind)) {
+ if (IsConciseMethod(kind)) {
+ if (IsGeneratorFunction(kind)) {
builder.AppendCharacter('*');
- } else if (shared_info->is_async()) {
+ } else if (IsAsyncFunction(kind)) {
builder.AppendCString("async ");
}
} else {
- if (shared_info->is_generator()) {
+ if (IsGeneratorFunction(kind)) {
builder.AppendCString("function* ");
- } else if (shared_info->is_async()) {
+ } else if (IsAsyncFunction(kind)) {
builder.AppendCString("async function ");
} else {
builder.AppendCString("function ");
@@ -13455,9 +13746,9 @@ void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
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());
+ // When adding fields here, make sure DeclarationScope::AnalyzePartially is
+ // updated accordingly.
+ shared_info->set_length(lit->scope()->arity());
shared_info->set_internal_formal_parameter_count(lit->parameter_count());
shared_info->set_function_token_position(lit->function_token_position());
shared_info->set_start_position(lit->start_position());
@@ -13481,6 +13772,9 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
}
shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
shared_info->set_asm_function(lit->scope()->asm_function());
+ shared_info->set_requires_class_field_init(lit->requires_class_field_init());
+ shared_info->set_is_class_field_initializer(
+ lit->is_class_field_initializer());
SetExpectedNofPropertiesFromEstimate(shared_info, lit);
}
@@ -15433,10 +15727,11 @@ bool AllocationSite::IsNestedSite() {
return false;
}
-
-void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
+template <AllocationSiteUpdateMode update_or_check>
+bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
ElementsKind to_kind) {
Isolate* isolate = site->GetIsolate();
+ bool result = false;
if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) {
Handle<JSArray> transition_info =
@@ -15452,6 +15747,9 @@ void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
uint32_t length = 0;
CHECK(transition_info->length()->ToArrayLength(&length));
if (length <= kMaximumArrayBytesToPretransition) {
+ if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) {
+ return true;
+ }
if (FLAG_trace_track_allocation_sites) {
bool is_nested = site->IsNestedSite();
PrintF(
@@ -15464,6 +15762,7 @@ void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
JSObject::TransitionElementsKind(transition_info, to_kind);
site->dependent_code()->DeoptimizeDependentCodeGroup(
isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
+ result = true;
}
}
} else {
@@ -15473,6 +15772,7 @@ void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
to_kind = GetHoleyElementsKind(to_kind);
}
if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
+ if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true;
if (FLAG_trace_track_allocation_sites) {
PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
reinterpret_cast<void*>(*site),
@@ -15482,8 +15782,10 @@ void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
site->SetElementsKind(to_kind);
site->dependent_code()->DeoptimizeDependentCodeGroup(
isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
+ result = true;
}
}
+ return result;
}
@@ -15499,13 +15801,13 @@ const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
return NULL;
}
-
-void JSObject::UpdateAllocationSite(Handle<JSObject> object,
+template <AllocationSiteUpdateMode update_or_check>
+bool JSObject::UpdateAllocationSite(Handle<JSObject> object,
ElementsKind to_kind) {
- if (!object->IsJSArray()) return;
+ if (!object->IsJSArray()) return false;
Heap* heap = object->GetHeap();
- if (!heap->InNewSpace(*object)) return;
+ if (!heap->InNewSpace(*object)) return false;
Handle<AllocationSite> site;
{
@@ -15513,14 +15815,21 @@ void JSObject::UpdateAllocationSite(Handle<JSObject> object,
AllocationMemento* memento =
heap->FindAllocationMemento<Heap::kForRuntime>(*object);
- if (memento == NULL) return;
+ if (memento == NULL) return false;
// Walk through to the Allocation Site
site = handle(memento->GetAllocationSite());
}
- AllocationSite::DigestTransitionFeedback(site, to_kind);
+ return AllocationSite::DigestTransitionFeedback<update_or_check>(site,
+ to_kind);
}
+template bool
+JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
+ Handle<JSObject> object, ElementsKind to_kind);
+
+template bool JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kUpdate>(
+ Handle<JSObject> object, ElementsKind to_kind);
void JSObject::TransitionElementsKind(Handle<JSObject> object,
ElementsKind to_kind) {
@@ -15729,7 +16038,7 @@ Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
}
int FixedArrayBase::GetMaxLengthForNewSpaceAllocation(ElementsKind kind) {
- return ((Page::kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >>
+ return ((kMaxRegularHeapObjectSize - FixedArrayBase::kHeaderSize) >>
ElementsKindToShiftSize(kind));
}
@@ -17984,7 +18293,8 @@ Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
if (capacity > ObjectHashTable::kMaxCapacity) {
for (size_t i = 0; i < 2; ++i) {
isolate->heap()->CollectAllGarbage(
- Heap::kFinalizeIncrementalMarkingMask, "full object hash table");
+ Heap::kFinalizeIncrementalMarkingMask,
+ GarbageCollectionReason::kFullHashtable);
}
table->Rehash(isolate->factory()->undefined_value());
}
@@ -19281,5 +19591,359 @@ bool JSReceiver::HasProxyInPrototype(Isolate* isolate) {
return false;
}
+namespace {
+
+template <typename T>
+struct HandleValueHash {
+ V8_INLINE size_t operator()(Handle<T> handle) const { return handle->Hash(); }
+};
+
+struct ModuleHandleEqual {
+ V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const {
+ return *lhs == *rhs;
+ }
+};
+
+struct StringHandleEqual {
+ V8_INLINE bool operator()(Handle<String> lhs, Handle<String> rhs) const {
+ return lhs->Equals(*rhs);
+ }
+};
+
+class UnorderedStringSet
+ : public std::unordered_set<Handle<String>, HandleValueHash<String>,
+ StringHandleEqual,
+ zone_allocator<Handle<String>>> {
+ public:
+ explicit UnorderedStringSet(Zone* zone)
+ : std::unordered_set<Handle<String>, HandleValueHash<String>,
+ StringHandleEqual, zone_allocator<Handle<String>>>(
+ 2 /* bucket count */, HandleValueHash<String>(),
+ StringHandleEqual(), zone_allocator<Handle<String>>(zone)) {}
+};
+
+} // anonymous namespace
+
+class Module::ResolveSet
+ : public std::unordered_map<
+ Handle<Module>, UnorderedStringSet*, HandleValueHash<Module>,
+ ModuleHandleEqual, zone_allocator<std::pair<const Handle<Module>,
+ UnorderedStringSet*>>> {
+ public:
+ explicit ResolveSet(Zone* zone)
+ : std::unordered_map<Handle<Module>, UnorderedStringSet*,
+ HandleValueHash<Module>, ModuleHandleEqual,
+ zone_allocator<std::pair<const Handle<Module>,
+ UnorderedStringSet*>>>(
+ 2 /* bucket count */, HandleValueHash<Module>(),
+ ModuleHandleEqual(),
+ zone_allocator<
+ std::pair<const Handle<Module>, UnorderedStringSet*>>(zone)),
+ zone_(zone) {}
+
+ Zone* zone() const { return zone_; }
+
+ private:
+ Zone* zone_;
+};
+
+void Module::CreateIndirectExport(Handle<Module> module, Handle<String> name,
+ Handle<ModuleInfoEntry> entry) {
+ Isolate* isolate = module->GetIsolate();
+ Handle<ObjectHashTable> exports(module->exports(), isolate);
+ DCHECK(exports->Lookup(name)->IsTheHole(isolate));
+ exports = ObjectHashTable::Put(exports, name, entry);
+ module->set_exports(*exports);
+}
+
+void Module::CreateExport(Handle<Module> module, Handle<FixedArray> names) {
+ DCHECK_LT(0, names->length());
+ Isolate* isolate = module->GetIsolate();
+ Handle<Cell> cell =
+ isolate->factory()->NewCell(isolate->factory()->undefined_value());
+ Handle<ObjectHashTable> exports(module->exports(), isolate);
+ for (int i = 0, n = names->length(); i < n; ++i) {
+ Handle<String> name(String::cast(names->get(i)), isolate);
+ DCHECK(exports->Lookup(name)->IsTheHole(isolate));
+ exports = ObjectHashTable::Put(exports, name, cell);
+ }
+ module->set_exports(*exports);
+}
+
+void Module::StoreExport(Handle<Module> module, Handle<String> name,
+ Handle<Object> value) {
+ Handle<Cell> cell(Cell::cast(module->exports()->Lookup(name)));
+ cell->set_value(*value);
+}
+
+Handle<Object> Module::LoadExport(Handle<Module> module, Handle<String> name) {
+ Isolate* isolate = module->GetIsolate();
+ Handle<Object> object(module->exports()->Lookup(name), isolate);
+
+ // TODO(neis): Namespace imports are not yet implemented. Trying to use this
+ // feature may crash here.
+ if (!object->IsCell()) UNIMPLEMENTED();
+
+ return handle(Handle<Cell>::cast(object)->value(), isolate);
+}
+
+Handle<Object> Module::LoadImport(Handle<Module> module, Handle<String> name,
+ int module_request) {
+ Isolate* isolate = module->GetIsolate();
+ Handle<Module> requested_module(
+ Module::cast(module->requested_modules()->get(module_request)), isolate);
+ return Module::LoadExport(requested_module, name);
+}
+
+MaybeHandle<Cell> Module::ResolveImport(Handle<Module> module,
+ Handle<String> name, int module_request,
+ bool must_resolve,
+ Module::ResolveSet* resolve_set) {
+ Isolate* isolate = module->GetIsolate();
+ Handle<Module> requested_module(
+ Module::cast(module->requested_modules()->get(module_request)), isolate);
+ return Module::ResolveExport(requested_module, name, must_resolve,
+ resolve_set);
+}
+
+MaybeHandle<Cell> Module::ResolveExport(Handle<Module> module,
+ Handle<String> name, bool must_resolve,
+ Module::ResolveSet* resolve_set) {
+ Isolate* isolate = module->GetIsolate();
+ Handle<Object> object(module->exports()->Lookup(name), isolate);
+ if (object->IsCell()) {
+ // Already resolved (e.g. because it's a local export).
+ return Handle<Cell>::cast(object);
+ }
+
+ // Check for cycle before recursing.
+ {
+ // Attempt insertion with a null string set.
+ auto result = resolve_set->insert({module, nullptr});
+ UnorderedStringSet*& name_set = result.first->second;
+ if (result.second) {
+ // |module| wasn't in the map previously, so allocate a new name set.
+ Zone* zone = resolve_set->zone();
+ name_set =
+ new (zone->New(sizeof(UnorderedStringSet))) UnorderedStringSet(zone);
+ } else if (name_set->count(name)) {
+ // Cycle detected.
+ if (must_resolve) {
+ THROW_NEW_ERROR(
+ isolate,
+ NewSyntaxError(MessageTemplate::kCyclicModuleDependency, name),
+ Cell);
+ }
+ return MaybeHandle<Cell>();
+ }
+ name_set->insert(name);
+ }
+
+ if (object->IsModuleInfoEntry()) {
+ // Not yet resolved indirect export.
+ Handle<ModuleInfoEntry> entry = Handle<ModuleInfoEntry>::cast(object);
+ int module_request = Smi::cast(entry->module_request())->value();
+ Handle<String> import_name(String::cast(entry->import_name()), isolate);
+
+ Handle<Cell> cell;
+ if (!ResolveImport(module, import_name, module_request, true, resolve_set)
+ .ToHandle(&cell)) {
+ DCHECK(isolate->has_pending_exception());
+ return MaybeHandle<Cell>();
+ }
+
+ // The export table may have changed but the entry in question should be
+ // unchanged.
+ Handle<ObjectHashTable> exports(module->exports(), isolate);
+ DCHECK(exports->Lookup(name)->IsModuleInfoEntry());
+
+ exports = ObjectHashTable::Put(exports, name, cell);
+ module->set_exports(*exports);
+ return cell;
+ }
+
+ DCHECK(object->IsTheHole(isolate));
+ return Module::ResolveExportUsingStarExports(module, name, must_resolve,
+ resolve_set);
+}
+
+MaybeHandle<Cell> Module::ResolveExportUsingStarExports(
+ Handle<Module> module, Handle<String> name, bool must_resolve,
+ Module::ResolveSet* resolve_set) {
+ Isolate* isolate = module->GetIsolate();
+ if (!name->Equals(isolate->heap()->default_string())) {
+ // Go through all star exports looking for the given name. If multiple star
+ // exports provide the name, make sure they all map it to the same cell.
+ Handle<Cell> unique_cell;
+ Handle<FixedArray> special_exports(module->info()->special_exports(),
+ isolate);
+ for (int i = 0, n = special_exports->length(); i < n; ++i) {
+ i::Handle<i::ModuleInfoEntry> entry(
+ i::ModuleInfoEntry::cast(special_exports->get(i)), isolate);
+ if (!entry->export_name()->IsUndefined(isolate)) {
+ continue; // Indirect export.
+ }
+ int module_request = Smi::cast(entry->module_request())->value();
+
+ Handle<Cell> cell;
+ if (ResolveImport(module, name, module_request, false, resolve_set)
+ .ToHandle(&cell)) {
+ if (unique_cell.is_null()) unique_cell = cell;
+ if (*unique_cell != *cell) {
+ THROW_NEW_ERROR(
+ isolate, NewSyntaxError(MessageTemplate::kAmbiguousExport, name),
+ Cell);
+ }
+ } else if (isolate->has_pending_exception()) {
+ return MaybeHandle<Cell>();
+ }
+ }
+
+ if (!unique_cell.is_null()) {
+ // Found a unique star export for this name.
+ Handle<ObjectHashTable> exports(module->exports(), isolate);
+ DCHECK(exports->Lookup(name)->IsTheHole(isolate));
+ exports = ObjectHashTable::Put(exports, name, unique_cell);
+ module->set_exports(*exports);
+ return unique_cell;
+ }
+ }
+
+ // Unresolvable.
+ if (must_resolve) {
+ THROW_NEW_ERROR(isolate,
+ NewSyntaxError(MessageTemplate::kUnresolvableExport, name),
+ Cell);
+ }
+ return MaybeHandle<Cell>();
+}
+
+bool Module::Instantiate(Handle<Module> module, v8::Local<v8::Context> context,
+ v8::Module::ResolveCallback callback,
+ v8::Local<v8::Value> callback_data) {
+ // Already instantiated.
+ if (module->code()->IsJSFunction()) return true;
+
+ Isolate* isolate = module->GetIsolate();
+ Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(module->code()),
+ isolate);
+ Handle<JSFunction> function =
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(
+ shared,
+ handle(Utils::OpenHandle(*context)->native_context(), isolate));
+ module->set_code(*function);
+
+ Handle<ModuleInfo> module_info(shared->scope_info()->ModuleDescriptorInfo(),
+ isolate);
+
+ // Set up local exports.
+ Handle<FixedArray> regular_exports(module_info->regular_exports(), isolate);
+ for (int i = 0, n = regular_exports->length(); i < n; i += 2) {
+ Handle<FixedArray> export_names(
+ FixedArray::cast(regular_exports->get(i + 1)), isolate);
+ CreateExport(module, export_names);
+ }
+
+ // Partially set up indirect exports.
+ // For each indirect export, we create the appropriate slot in the export
+ // table and store its ModuleInfoEntry there. When we later find the correct
+ // Cell in the module that actually provides the value, we replace the
+ // ModuleInfoEntry by that Cell (see ResolveExport).
+ Handle<FixedArray> special_exports(module_info->special_exports(), isolate);
+ for (int i = 0, n = special_exports->length(); i < n; ++i) {
+ Handle<ModuleInfoEntry> entry(
+ ModuleInfoEntry::cast(special_exports->get(i)), isolate);
+ Handle<Object> export_name(entry->export_name(), isolate);
+ if (export_name->IsUndefined(isolate)) continue; // Star export.
+ CreateIndirectExport(module, Handle<String>::cast(export_name), entry);
+ }
+
+ Handle<FixedArray> module_requests(module_info->module_requests(), isolate);
+ for (int i = 0, length = module_requests->length(); i < length; ++i) {
+ Handle<String> specifier(String::cast(module_requests->get(i)), isolate);
+ v8::Local<v8::Module> api_requested_module;
+ // TODO(adamk): Revisit these failure cases once d8 knows how to
+ // persist a module_map across multiple top-level module loads, as
+ // the current module is left in a "half-instantiated" state.
+ if (!callback(context, v8::Utils::ToLocal(specifier),
+ v8::Utils::ToLocal(module), callback_data)
+ .ToLocal(&api_requested_module)) {
+ // TODO(adamk): Give this a better error message. But this is a
+ // misuse of the API anyway.
+ isolate->ThrowIllegalOperation();
+ return false;
+ }
+ Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module);
+ module->requested_modules()->set(i, *requested_module);
+ if (!Instantiate(requested_module, context, callback, callback_data)) {
+ return false;
+ }
+ }
+
+ Zone zone(isolate->allocator());
+
+ // Resolve imports.
+ Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate);
+ for (int i = 0, n = regular_imports->length(); i < n; ++i) {
+ Handle<ModuleInfoEntry> entry(
+ ModuleInfoEntry::cast(regular_imports->get(i)), isolate);
+ Handle<String> name(String::cast(entry->import_name()), isolate);
+ int module_request = Smi::cast(entry->module_request())->value();
+ ResolveSet resolve_set(&zone);
+ if (ResolveImport(module, name, module_request, true, &resolve_set)
+ .is_null()) {
+ return false;
+ }
+ }
+
+ // Resolve indirect exports.
+ for (int i = 0, n = special_exports->length(); i < n; ++i) {
+ Handle<ModuleInfoEntry> entry(
+ ModuleInfoEntry::cast(special_exports->get(i)), isolate);
+ Handle<Object> name(entry->export_name(), isolate);
+ if (name->IsUndefined(isolate)) continue; // Star export.
+ ResolveSet resolve_set(&zone);
+ if (ResolveExport(module, Handle<String>::cast(name), true, &resolve_set)
+ .is_null()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+MaybeHandle<Object> Module::Evaluate(Handle<Module> module) {
+ DCHECK(module->code()->IsJSFunction()); // Instantiated.
+
+ Isolate* isolate = module->GetIsolate();
+
+ // Each module can only be evaluated once.
+ if (module->evaluated()) return isolate->factory()->undefined_value();
+ module->set_evaluated(true);
+
+ // Initialization.
+ Handle<JSFunction> function(JSFunction::cast(module->code()), isolate);
+ DCHECK_EQ(MODULE_SCOPE, function->shared()->scope_info()->scope_type());
+ Handle<Object> receiver = isolate->factory()->undefined_value();
+ Handle<Object> argv[] = {module};
+ Handle<Object> generator;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, generator,
+ Execution::Call(isolate, function, receiver, arraysize(argv), argv),
+ Object);
+
+ // Recursion.
+ Handle<FixedArray> requested_modules(module->requested_modules(), isolate);
+ for (int i = 0, length = requested_modules->length(); i < length; ++i) {
+ Handle<Module> import(Module::cast(requested_modules->get(i)), isolate);
+ RETURN_ON_EXCEPTION(isolate, Evaluate(import), Object);
+ }
+
+ // Evaluation of module body.
+ Handle<JSFunction> resume(
+ isolate->native_context()->generator_next_internal(), isolate);
+ return Execution::Call(isolate, resume, generator, 0, nullptr);
+}
+
} // namespace internal
} // namespace v8