diff options
Diffstat (limited to 'deps/v8/src/objects.cc')
-rw-r--r-- | deps/v8/src/objects.cc | 977 |
1 files changed, 521 insertions, 456 deletions
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index af2e3eccb3..9e80224d93 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -60,6 +60,8 @@ #include "src/objects/frame-array-inl.h" #include "src/objects/hash-table.h" #include "src/objects/map.h" +#include "src/objects/microtask-inl.h" +#include "src/objects/promise-inl.h" #include "src/parsing/preparsed-scope-data.h" #include "src/property-descriptor.h" #include "src/prototype.h" @@ -72,6 +74,7 @@ #include "src/string-stream.h" #include "src/trap-handler/trap-handler.h" #include "src/unicode-cache-inl.h" +#include "src/unicode-decoder.h" #include "src/utils-inl.h" #include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-objects.h" @@ -699,39 +702,6 @@ Handle<String> Object::TypeOf(Isolate* isolate, Handle<Object> object) { // static -MaybeHandle<Object> Object::Multiply(Isolate* isolate, Handle<Object> lhs, - Handle<Object> rhs) { - if (!lhs->IsNumber() || !rhs->IsNumber()) { - ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); - ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); - } - return isolate->factory()->NewNumber(lhs->Number() * rhs->Number()); -} - - -// static -MaybeHandle<Object> Object::Divide(Isolate* isolate, Handle<Object> lhs, - Handle<Object> rhs) { - if (!lhs->IsNumber() || !rhs->IsNumber()) { - ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); - ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); - } - return isolate->factory()->NewNumber(lhs->Number() / rhs->Number()); -} - - -// static -MaybeHandle<Object> Object::Modulus(Isolate* isolate, Handle<Object> lhs, - Handle<Object> rhs) { - if (!lhs->IsNumber() || !rhs->IsNumber()) { - ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); - ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); - } - return isolate->factory()->NewNumber(Modulo(lhs->Number(), rhs->Number())); -} - - -// static MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs, Handle<Object> rhs) { if (lhs->IsNumber() && rhs->IsNumber()) { @@ -757,89 +727,6 @@ MaybeHandle<Object> Object::Add(Isolate* isolate, Handle<Object> lhs, // static -MaybeHandle<Object> Object::Subtract(Isolate* isolate, Handle<Object> lhs, - Handle<Object> rhs) { - if (!lhs->IsNumber() || !rhs->IsNumber()) { - ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); - ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); - } - return isolate->factory()->NewNumber(lhs->Number() - rhs->Number()); -} - - -// static -MaybeHandle<Object> Object::ShiftLeft(Isolate* isolate, Handle<Object> lhs, - Handle<Object> rhs) { - if (!lhs->IsNumber() || !rhs->IsNumber()) { - ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); - ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); - } - return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) - << (NumberToUint32(*rhs) & 0x1F)); -} - - -// static -MaybeHandle<Object> Object::ShiftRight(Isolate* isolate, Handle<Object> lhs, - Handle<Object> rhs) { - if (!lhs->IsNumber() || !rhs->IsNumber()) { - ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); - ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); - } - return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) >> - (NumberToUint32(*rhs) & 0x1F)); -} - - -// static -MaybeHandle<Object> Object::ShiftRightLogical(Isolate* isolate, - Handle<Object> lhs, - Handle<Object> rhs) { - if (!lhs->IsNumber() || !rhs->IsNumber()) { - ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); - ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); - } - return isolate->factory()->NewNumberFromUint(NumberToUint32(*lhs) >> - (NumberToUint32(*rhs) & 0x1F)); -} - - -// static -MaybeHandle<Object> Object::BitwiseAnd(Isolate* isolate, Handle<Object> lhs, - Handle<Object> rhs) { - if (!lhs->IsNumber() || !rhs->IsNumber()) { - ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); - ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); - } - return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) & - NumberToInt32(*rhs)); -} - - -// static -MaybeHandle<Object> Object::BitwiseOr(Isolate* isolate, Handle<Object> lhs, - Handle<Object> rhs) { - if (!lhs->IsNumber() || !rhs->IsNumber()) { - ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); - ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); - } - return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) | - NumberToInt32(*rhs)); -} - - -// static -MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs, - Handle<Object> rhs) { - if (!lhs->IsNumber() || !rhs->IsNumber()) { - ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); - ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); - } - return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) ^ - NumberToInt32(*rhs)); -} - -// static MaybeHandle<Object> Object::OrdinaryHasInstance(Isolate* isolate, Handle<Object> callable, Handle<Object> object) { @@ -1272,7 +1159,7 @@ Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) { // Support calling this method without an active context, but refuse // access to access-checked objects in that case. if (it->isolate()->context() != nullptr && it->HasAccess()) continue; - // Fall through. + V8_FALLTHROUGH; case LookupIterator::JSPROXY: it->NotFound(); return it->isolate()->factory()->undefined_value(); @@ -1313,24 +1200,24 @@ Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo( if (current_info->IsSharedFunctionInfo()) { return handle(SharedFunctionInfo::cast(current_info), isolate); } - Handle<Object> class_name(info->class_name(), isolate); Handle<Name> name; Handle<String> name_string; if (maybe_name.ToHandle(&name) && name->IsString()) { name_string = Handle<String>::cast(name); + } else if (info->class_name()->IsString()) { + name_string = handle(String::cast(info->class_name())); } else { - name_string = class_name->IsString() ? Handle<String>::cast(class_name) - : isolate->factory()->empty_string(); + name_string = isolate->factory()->empty_string(); } Handle<Code> code = BUILTIN_CODE(isolate, HandleApiCall); bool is_constructor; FunctionKind function_kind; - if (!info->remove_prototype()) { - is_constructor = true; - function_kind = kNormalFunction; - } else { + if (info->remove_prototype()) { is_constructor = false; function_kind = kConciseMethod; + } else { + is_constructor = true; + function_kind = kNormalFunction; } Handle<SharedFunctionInfo> result = isolate->factory()->NewSharedFunctionInfo( name_string, code, is_constructor, function_kind); @@ -1339,9 +1226,6 @@ Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo( } result->set_length(info->length()); - if (class_name->IsString()) { - result->set_instance_class_name(String::cast(*class_name)); - } result->set_api_func_data(*info); result->DontAdaptArguments(); DCHECK(result->IsApiFunction()); @@ -2482,7 +2366,7 @@ MaybeHandle<Object> Object::ArraySpeciesConstructor( Handle<Object> default_species = isolate->array_function(); if (original_array->IsJSArray() && Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) && - isolate->IsArraySpeciesLookupChainIntact()) { + isolate->IsSpeciesLookupChainIntact()) { return default_species; } Handle<Object> constructor = isolate->factory()->undefined_value(); @@ -3106,6 +2990,7 @@ VisitorId Map::GetVisitorId(Map* map) { case HASH_TABLE_TYPE: case FIXED_ARRAY_TYPE: case DESCRIPTOR_ARRAY_TYPE: + case SCOPE_INFO_TYPE: return kVisitFixedArray; case FIXED_DOUBLE_ARRAY_TYPE: @@ -3114,6 +2999,9 @@ VisitorId Map::GetVisitorId(Map* map) { case PROPERTY_ARRAY_TYPE: return kVisitPropertyArray; + case FEEDBACK_CELL_TYPE: + return kVisitFeedbackCell; + case FEEDBACK_VECTOR_TYPE: return kVisitFeedbackVector; @@ -3226,6 +3114,8 @@ VisitorId Map::GetVisitorId(Map* map) { case FIXED_INT32_ARRAY_TYPE: case FIXED_FLOAT32_ARRAY_TYPE: case FIXED_UINT8_CLAMPED_ARRAY_TYPE: + case FIXED_BIGUINT64_ARRAY_TYPE: + case FIXED_BIGINT64_ARRAY_TYPE: return kVisitFixedTypedArrayBase; case FIXED_FLOAT64_ARRAY_TYPE: @@ -3401,6 +3291,20 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT case PROPERTY_ARRAY_TYPE: os << "<PropertyArray[" << PropertyArray::cast(this)->length() << "]>"; break; + case FEEDBACK_CELL_TYPE: { + os << "<FeedbackCell["; + if (map() == heap->no_closures_cell_map()) { + os << "no closures"; + } else if (map() == heap->one_closure_cell_map()) { + os << "one closure"; + } else if (map() == heap->many_closures_cell_map()) { + os << "many closures"; + } else { + os << "!!!INVALID MAP!!!"; + } + os << "]>"; + break; + } case FEEDBACK_VECTOR_TYPE: os << "<FeedbackVector[" << FeedbackVector::cast(this)->length() << "]>"; break; @@ -3437,6 +3341,9 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT break; STRUCT_LIST(MAKE_STRUCT_CASE) #undef MAKE_STRUCT_CASE + case SCOPE_INFO_TYPE: + os << "<ScopeInfo[" << ScopeInfo::cast(this)->length() << "]>"; + break; case CODE_TYPE: { Code* code = Code::cast(this); os << "<Code " << Code::Kind2String(code->kind()); @@ -3540,6 +3447,10 @@ void Tuple3::BriefPrintDetails(std::ostream& os) { << Brief(value3()); } +void CallableTask::BriefPrintDetails(std::ostream& os) { + os << " callable=" << Brief(callable()); +} + void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); } @@ -3589,20 +3500,63 @@ void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT (*reinterpret_cast<const byte*>(FIELD_ADDR_CONST(p, offset))) String* JSReceiver::class_name() { - if (IsFunction()) { - return GetHeap()->Function_string(); + if (IsFunction()) return GetHeap()->Function_string(); + if (IsJSArgumentsObject()) return GetHeap()->Arguments_string(); + if (IsJSArray()) return GetHeap()->Array_string(); + if (IsJSArrayBuffer()) { + if (JSArrayBuffer::cast(this)->is_shared()) { + return GetHeap()->SharedArrayBuffer_string(); + } + return GetHeap()->ArrayBuffer_string(); + } + if (IsJSArrayIterator()) return GetHeap()->ArrayIterator_string(); + if (IsJSDate()) return GetHeap()->Date_string(); + if (IsJSError()) return GetHeap()->Error_string(); + if (IsJSGeneratorObject()) return GetHeap()->Generator_string(); + if (IsJSMap()) return GetHeap()->Map_string(); + if (IsJSMapIterator()) return GetHeap()->MapIterator_string(); + if (IsJSProxy()) { + return map()->is_callable() ? GetHeap()->Function_string() + : GetHeap()->Object_string(); + } + if (IsJSRegExp()) return GetHeap()->RegExp_string(); + if (IsJSSet()) return GetHeap()->Set_string(); + if (IsJSSetIterator()) return GetHeap()->SetIterator_string(); + if (IsJSTypedArray()) { +#define SWITCH_KIND(Type, type, TYPE, ctype, size) \ + if (map()->elements_kind() == TYPE##_ELEMENTS) { \ + return GetHeap()->Type##Array_string(); \ + } + TYPED_ARRAYS(SWITCH_KIND) +#undef SWITCH_KIND + } + if (IsJSValue()) { + Object* value = JSValue::cast(this)->value(); + if (value->IsBoolean()) return GetHeap()->Boolean_string(); + if (value->IsString()) return GetHeap()->String_string(); + if (value->IsNumber()) return GetHeap()->Number_string(); + if (value->IsBigInt()) return GetHeap()->BigInt_string(); + if (value->IsSymbol()) return GetHeap()->Symbol_string(); + if (value->IsScript()) return GetHeap()->Script_string(); + UNREACHABLE(); } + if (IsJSWeakMap()) return GetHeap()->WeakMap_string(); + if (IsJSWeakSet()) return GetHeap()->WeakSet_string(); + if (IsJSGlobalProxy()) return GetHeap()->global_string(); + Object* maybe_constructor = map()->GetConstructor(); if (maybe_constructor->IsJSFunction()) { JSFunction* constructor = JSFunction::cast(maybe_constructor); - return String::cast(constructor->shared()->instance_class_name()); - } else if (maybe_constructor->IsFunctionTemplateInfo()) { + if (constructor->shared()->IsApiFunction()) { + maybe_constructor = constructor->shared()->get_api_func_data(); + } + } + + if (maybe_constructor->IsFunctionTemplateInfo()) { FunctionTemplateInfo* info = FunctionTemplateInfo::cast(maybe_constructor); - return info->class_name()->IsString() ? String::cast(info->class_name()) - : GetHeap()->empty_string(); + if (info->class_name()->IsString()) return String::cast(info->class_name()); } - // If the constructor is not present, return "Object". return GetHeap()->Object_string(); } @@ -3612,7 +3566,8 @@ bool HeapObject::CanBeRehashed() const { case HASH_TABLE_TYPE: // TODO(yangguo): actually support rehashing OrderedHash{Map,Set}. return IsNameDictionary() || IsGlobalDictionary() || - IsNumberDictionary() || IsStringTable() || IsWeakHashTable(); + IsNumberDictionary() || IsSimpleNumberDictionary() || + IsStringTable() || IsWeakHashTable(); case DESCRIPTOR_ARRAY_TYPE: return true; case TRANSITION_ARRAY_TYPE: @@ -3634,6 +3589,8 @@ void HeapObject::RehashBasedOnMap() { NameDictionary::cast(this)->Rehash(); } else if (IsNumberDictionary()) { NumberDictionary::cast(this)->Rehash(); + } else if (IsSimpleNumberDictionary()) { + SimpleNumberDictionary::cast(this)->Rehash(); } else if (IsGlobalDictionary()) { GlobalDictionary::cast(this)->Rehash(); } else if (IsStringTable()) { @@ -4885,7 +4842,7 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it, if (it->HolderIsReceiverOrHiddenPrototype()) { return SetDataProperty(it, value); } - // Fall through. + V8_FALLTHROUGH; case LookupIterator::TRANSITION: *found = false; return Nothing<bool>(); @@ -4970,7 +4927,7 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value, return JSObject::SetPropertyWithAccessor(&own_lookup, value, should_throw); } - // Fall through. + V8_FALLTHROUGH; case LookupIterator::INTEGER_INDEXED_EXOTIC: return RedefineIncompatibleProperty(isolate, it->GetName(), value, should_throw); @@ -5054,17 +5011,32 @@ Maybe<bool> Object::RedefineIncompatibleProperty(Isolate* isolate, Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) { - // Proxies are handled elsewhere. Other non-JSObjects cannot have own - // properties. - Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); + DCHECK_IMPLIES(it->GetReceiver()->IsJSProxy(), + it->GetName()->IsPrivateField()); + DCHECK_IMPLIES(!it->IsElement() && it->GetName()->IsPrivateField(), + it->state() == LookupIterator::DATA); + Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); // Store on the holder which may be hidden behind the receiver. DCHECK(it->HolderIsReceiverOrHiddenPrototype()); 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(it->isolate())) { + if (it->IsElement() && receiver->IsJSObject() && + JSObject::cast(*receiver)->HasFixedTypedArrayElements()) { + ElementsKind elements_kind = JSObject::cast(*receiver)->GetElementsKind(); + if (elements_kind == BIGINT64_ELEMENTS || + elements_kind == BIGUINT64_ELEMENTS) { + ASSIGN_RETURN_ON_EXCEPTION_VALUE(it->isolate(), to_assign, + BigInt::FromObject(it->isolate(), value), + Nothing<bool>()); + // We have to recheck the length. However, it can only change if the + // underlying buffer was neutered, so just check that. + if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) { + return Just(true); + // TODO(neis): According to the spec, this should throw a TypeError. + } + } else 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 @@ -5085,7 +5057,7 @@ Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) { #if VERIFY_HEAP if (FLAG_verify_heap) { - receiver->JSObjectVerify(); + receiver->HeapObjectVerify(); } #endif return Just(true); @@ -5096,18 +5068,25 @@ Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value, PropertyAttributes attributes, ShouldThrow should_throw, StoreFromKeyed store_mode) { - if (!it->GetReceiver()->IsJSObject()) { - if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) { - RETURN_FAILURE(it->isolate(), should_throw, - NewTypeError(MessageTemplate::kProxyPrivate)); - } + if (!it->GetReceiver()->IsJSReceiver()) { return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(), value, should_throw); } + // Private symbols should be installed on JSProxy using + // JSProxy::SetPrivateSymbol. + if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate() && + !it->GetName()->IsPrivateField()) { + RETURN_FAILURE(it->isolate(), should_throw, + NewTypeError(MessageTemplate::kProxyPrivate)); + } + DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, it->state()); - Handle<JSObject> receiver = it->GetStoreTarget(); + Handle<JSReceiver> receiver = it->GetStoreTarget<JSReceiver>(); + DCHECK_IMPLIES(receiver->IsJSProxy(), it->GetName()->IsPrivateField()); + DCHECK_IMPLIES(receiver->IsJSProxy(), + it->state() == LookupIterator::NOT_FOUND); // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject) // instead. If the prototype is Null, the proxy is detached. @@ -5141,9 +5120,10 @@ Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value, } } - Maybe<bool> result = JSObject::AddDataElement(receiver, it->index(), value, - attributes, should_throw); - JSObject::ValidateElements(*receiver); + Handle<JSObject> receiver_obj = Handle<JSObject>::cast(receiver); + Maybe<bool> result = JSObject::AddDataElement( + receiver_obj, it->index(), value, attributes, should_throw); + JSObject::ValidateElements(*receiver_obj); return result; } else { it->UpdateProtector(); @@ -5159,7 +5139,7 @@ Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value, #if VERIFY_HEAP if (FLAG_verify_heap) { - receiver->JSObjectVerify(); + receiver->HeapObjectVerify(); } #endif } @@ -7260,7 +7240,6 @@ Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it, return Just(true); } - // TODO(jkummerow): Consider unification with FastAsArrayLength() in // accessors.cc. bool PropertyKeyToArrayLength(Handle<Object> value, uint32_t* length) { @@ -7472,8 +7451,9 @@ Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy, ShouldThrow should_throw) { STACK_CHECK(isolate, Nothing<bool>()); if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) { - return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc, - should_throw); + DCHECK(!Handle<Symbol>::cast(key)->IsPrivateField()); + return JSProxy::SetPrivateSymbol(isolate, proxy, Handle<Symbol>::cast(key), + desc, should_throw); } Handle<String> trap_name = isolate->factory()->defineProperty_string(); // 1. Assert: IsPropertyKey(P) is true. @@ -7576,12 +7556,12 @@ Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy, return Just(true); } - // static -Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy, - Handle<Symbol> private_name, - PropertyDescriptor* desc, - ShouldThrow should_throw) { +Maybe<bool> JSProxy::SetPrivateSymbol(Isolate* isolate, Handle<JSProxy> proxy, + Handle<Symbol> private_name, + PropertyDescriptor* desc, + ShouldThrow should_throw) { + DCHECK(!private_name->IsPrivateField()); // Despite the generic name, this can only add private data properties. if (!PropertyDescriptor::IsDataDescriptor(desc) || desc->ToAttributes() != DONT_ENUM) { @@ -7611,7 +7591,6 @@ Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy, return Just(true); } - // static Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate, Handle<JSReceiver> object, @@ -8791,9 +8770,10 @@ MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries( MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate, Handle<JSReceiver> object, PropertyFilter filter, + bool try_fast_path, bool get_entries) { Handle<FixedArray> values_or_entries; - if (filter == ENUMERABLE_STRINGS) { + if (try_fast_path && filter == ENUMERABLE_STRINGS) { Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries( isolate, object, get_entries, &values_or_entries); if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>(); @@ -8846,13 +8826,17 @@ MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate, } MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object, - PropertyFilter filter) { - return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, false); + PropertyFilter filter, + bool try_fast_path) { + return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, + try_fast_path, false); } MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object, - PropertyFilter filter) { - return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, true); + PropertyFilter filter, + bool try_fast_path) { + return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, + try_fast_path, true); } bool Map::DictionaryElementsInPrototypeChainOnly() { @@ -10027,7 +10011,8 @@ Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map, } Handle<FixedArray> FixedArray::SetAndGrow(Handle<FixedArray> array, int index, - Handle<Object> value) { + Handle<Object> value, + PretenureFlag pretenure) { if (index < array->length()) { array->set(index, *value); return array; @@ -10037,7 +10022,8 @@ Handle<FixedArray> FixedArray::SetAndGrow(Handle<FixedArray> array, int index, capacity = JSObject::NewElementsCapacity(capacity); } while (capacity <= index); Handle<FixedArray> new_array = - array->GetIsolate()->factory()->NewUninitializedFixedArray(capacity); + array->GetIsolate()->factory()->NewUninitializedFixedArray(capacity, + pretenure); array->CopyTo(0, *new_array, 0, array->length()); new_array->FillWithHoles(array->length(), new_array->length()); new_array->set(index, *value); @@ -10493,54 +10479,6 @@ SharedFunctionInfo* DeoptimizationData::GetInlinedFunction(int index) { } } -int HandlerTable::LookupRange(int pc_offset, int* data_out, - CatchPrediction* prediction_out) { - int innermost_handler = -1; -#ifdef DEBUG - // Assuming that ranges are well nested, we don't need to track the innermost - // offsets. This is just to verify that the table is actually well nested. - int innermost_start = std::numeric_limits<int>::min(); - int innermost_end = std::numeric_limits<int>::max(); -#endif - for (int i = 0; i < length(); i += kRangeEntrySize) { - int start_offset = Smi::ToInt(get(i + kRangeStartIndex)); - int end_offset = Smi::ToInt(get(i + kRangeEndIndex)); - int handler_field = Smi::ToInt(get(i + kRangeHandlerIndex)); - int handler_offset = HandlerOffsetField::decode(handler_field); - CatchPrediction prediction = HandlerPredictionField::decode(handler_field); - int handler_data = Smi::ToInt(get(i + kRangeDataIndex)); - if (pc_offset >= start_offset && pc_offset < end_offset) { - DCHECK_GE(start_offset, innermost_start); - DCHECK_LT(end_offset, innermost_end); - innermost_handler = handler_offset; -#ifdef DEBUG - innermost_start = start_offset; - innermost_end = end_offset; -#endif - if (data_out) *data_out = handler_data; - if (prediction_out) *prediction_out = prediction; - } - } - return innermost_handler; -} - - -// TODO(turbofan): Make sure table is sorted and use binary search. -int HandlerTable::LookupReturn(int pc_offset) { - for (int i = 0; i < length(); i += kReturnEntrySize) { - int return_offset = Smi::ToInt(get(i + kReturnOffsetIndex)); - int handler_field = Smi::ToInt(get(i + kReturnHandlerIndex)); - if (pc_offset == return_offset) { - return HandlerOffsetField::decode(handler_field); - } - } - return -1; -} - -Handle<HandlerTable> HandlerTable::Empty(Isolate* isolate) { - return Handle<HandlerTable>::cast(isolate->factory()->empty_fixed_array()); -} - #ifdef DEBUG bool DescriptorArray::IsEqualTo(DescriptorArray* other) { if (length() != other->length()) return false; @@ -10560,7 +10498,7 @@ Handle<String> String::Trim(Handle<String> string, TrimMode mode) { // Perform left trimming if requested. int left = 0; UnicodeCache* unicode_cache = isolate->unicode_cache(); - if (mode == kTrim || mode == kTrimLeft) { + if (mode == kTrim || mode == kTrimStart) { while (left < length && unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) { left++; @@ -10569,7 +10507,7 @@ Handle<String> String::Trim(Handle<String> string, TrimMode mode) { // Perform right trimming if requested. int right = length; - if (mode == kTrim || mode == kTrimRight) { + if (mode == kTrim || mode == kTrimEnd) { while ( right > left && unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) { @@ -11908,24 +11846,15 @@ bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) { str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) { return false; } - int i; - size_t remaining_in_str = static_cast<size_t>(str_len); - const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start()); - for (i = 0; i < slen && remaining_in_str > 0; i++) { - size_t cursor = 0; - uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor); - DCHECK(cursor > 0 && cursor <= remaining_in_str); - if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) { - if (i > slen - 1) return false; - if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false; - if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false; - } else { - if (Get(i) != r) return false; - } - utf8_data += cursor; - remaining_in_str -= cursor; + + int i = 0; + unibrow::Utf8Iterator it = unibrow::Utf8Iterator(str); + while (i < slen && !it.Done()) { + if (Get(i++) != *it) return false; + ++it; } - return (allow_prefix_match || i == slen) && remaining_in_str == 0; + + return (allow_prefix_match || i == slen) && it.Done(); } template <> @@ -12094,37 +12023,31 @@ uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars, *utf16_length_out = vector_length; return HashSequentialString(chars.start(), vector_length, seed); } + // Start with a fake length which won't affect computation. // It will be updated later. StringHasher hasher(String::kMaxArrayIndexSize, seed); - size_t remaining = static_cast<size_t>(vector_length); - const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start()); + DCHECK(hasher.is_array_index_); + + unibrow::Utf8Iterator it = unibrow::Utf8Iterator(chars); int utf16_length = 0; bool is_index = true; - DCHECK(hasher.is_array_index_); - while (remaining > 0) { - size_t consumed = 0; - uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed); - DCHECK(consumed > 0 && consumed <= remaining); - stream += consumed; - remaining -= consumed; - bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode; - utf16_length += is_two_characters ? 2 : 1; - // No need to keep hashing. But we do need to calculate utf16_length. - if (utf16_length > String::kMaxHashCalcLength) continue; - if (is_two_characters) { - uint16_t c1 = unibrow::Utf16::LeadSurrogate(c); - uint16_t c2 = unibrow::Utf16::TrailSurrogate(c); - hasher.AddCharacter(c1); - hasher.AddCharacter(c2); - if (is_index) is_index = hasher.UpdateIndex(c1); - if (is_index) is_index = hasher.UpdateIndex(c2); - } else { - hasher.AddCharacter(c); - if (is_index) is_index = hasher.UpdateIndex(c); - } + + while (utf16_length < String::kMaxHashCalcLength && !it.Done()) { + utf16_length++; + uint16_t c = *it; + ++it; + hasher.AddCharacter(c); + if (is_index) is_index = hasher.UpdateIndex(c); + } + + // Now that hashing is done, we just need to calculate utf16_length + while (!it.Done()) { + ++it; + utf16_length++; } - *utf16_length_out = static_cast<int>(utf16_length); + + *utf16_length_out = utf16_length; // Must set length here so that hash computation is correct. hasher.length_ = utf16_length; return hasher.GetHashField(); @@ -12283,31 +12206,21 @@ void JSFunction::MarkForOptimization(ConcurrencyMode mode) { } // static -void JSFunction::EnsureLiterals(Handle<JSFunction> function) { - Handle<SharedFunctionInfo> shared(function->shared()); - Isolate* isolate = shared->GetIsolate(); - - FeedbackVectorState state = function->GetFeedbackVectorState(isolate); - switch (state) { - case TOP_LEVEL_SCRIPT_NEEDS_VECTOR: { - // A top level script didn't get it's literals installed. - Handle<FeedbackVector> feedback_vector = - FeedbackVector::New(isolate, shared); - Handle<Cell> new_cell = - isolate->factory()->NewOneClosureCell(feedback_vector); - function->set_feedback_vector_cell(*new_cell); - break; - } - case NEEDS_VECTOR: { +void JSFunction::EnsureFeedbackVector(Handle<JSFunction> function) { + Isolate* const isolate = function->GetIsolate(); + if (function->feedback_cell()->value()->IsUndefined(isolate)) { + Handle<SharedFunctionInfo> shared(function->shared(), isolate); + if (!shared->HasAsmWasmData()) { Handle<FeedbackVector> feedback_vector = FeedbackVector::New(isolate, shared); - function->feedback_vector_cell()->set_value(*feedback_vector); - break; + if (function->feedback_cell() == isolate->heap()->many_closures_cell()) { + Handle<FeedbackCell> feedback_cell = + isolate->factory()->NewOneClosureCell(feedback_vector); + function->set_feedback_cell(*feedback_cell); + } else { + function->feedback_cell()->set_value(*feedback_vector); + } } - case HAS_VECTOR: - case NO_VECTOR_NEEDED: - // Nothing to do. - break; } } @@ -12410,9 +12323,7 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object, Object* maybe_constructor = object->map()->GetConstructor(); if (maybe_constructor->IsJSFunction()) { JSFunction* constructor = JSFunction::cast(maybe_constructor); - Isolate* isolate = object->GetIsolate(); - if (!constructor->shared()->IsApiFunction() && - object->class_name() == isolate->heap()->Object_string()) { + if (!constructor->shared()->IsApiFunction()) { Context* context = constructor->context()->native_context(); JSFunction* object_function = context->object_function(); object->map()->SetConstructor(object_function); @@ -13139,9 +13050,6 @@ bool JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name, namespace { -char const kNativeCodeSource[] = "function () { [native code] }"; - - Handle<String> NativeCodeFunctionSourceString( Handle<SharedFunctionInfo> shared_info) { Isolate* const isolate = shared_info->GetIsolate(); @@ -13158,7 +13066,7 @@ Handle<String> NativeCodeFunctionSourceString( // static Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) { Isolate* const isolate = function->GetIsolate(); - return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource); + return isolate->factory()->function_native_code_string(); } @@ -13626,7 +13534,6 @@ bool SharedFunctionInfo::HasBreakInfo() const { if (!HasDebugInfo()) return false; DebugInfo* info = DebugInfo::cast(debug_info()); bool has_break_info = info->HasBreakInfo(); - DCHECK_IMPLIES(has_break_info, HasBytecodeArray()); return has_break_info; } @@ -14020,7 +13927,7 @@ void Code::Relocate(intptr_t delta) { for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) { it.rinfo()->apply(delta); } - Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size()); + Assembler::FlushICache(instruction_start(), instruction_size()); } @@ -14061,18 +13968,18 @@ void Code::CopyFrom(const CodeDesc& desc) { // code object Handle<Object> p = it.rinfo()->target_object_handle(origin); Code* code = Code::cast(*p); - it.rinfo()->set_target_address(GetIsolate(), code->instruction_start(), + it.rinfo()->set_target_address(code->instruction_start(), UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); } else if (RelocInfo::IsRuntimeEntry(mode)) { Address p = it.rinfo()->target_runtime_entry(origin); - it.rinfo()->set_target_runtime_entry( - GetIsolate(), p, UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); + it.rinfo()->set_target_runtime_entry(p, UPDATE_WRITE_BARRIER, + SKIP_ICACHE_FLUSH); } else { intptr_t delta = instruction_start() - desc.buffer; it.rinfo()->apply(delta); } } - Assembler::FlushICache(GetIsolate(), instruction_start(), instruction_size()); + Assembler::FlushICache(instruction_start(), instruction_size()); } @@ -14081,11 +13988,31 @@ SafepointEntry Code::GetSafepointEntry(Address pc) { return table.FindEntry(pc); } +int Code::OffHeapInstructionSize() { + DCHECK(Builtins::IsOffHeapBuiltin(this)); + InstructionStream* stream = + InstructionStream::TryLookupInstructionStream(GetIsolate(), this); + return static_cast<int>(stream->byte_length()); +} + +Address Code::OffHeapInstructionStart() { + DCHECK(Builtins::IsOffHeapBuiltin(this)); + InstructionStream* stream = + InstructionStream::TryLookupInstructionStream(GetIsolate(), this); + return stream->bytes(); +} + +Address Code::OffHeapInstructionEnd() { + DCHECK(Builtins::IsOffHeapBuiltin(this)); + InstructionStream* stream = + InstructionStream::TryLookupInstructionStream(GetIsolate(), this); + return stream->bytes() + stream->byte_length(); +} namespace { template <typename Code> void SetStackFrameCacheCommon(Handle<Code> code, - Handle<NumberDictionary> cache) { + Handle<SimpleNumberDictionary> cache) { Handle<Object> maybe_table(code->source_position_table(), code->GetIsolate()); if (maybe_table->IsSourcePositionTableWithFrameCache()) { Handle<SourcePositionTableWithFrameCache>::cast(maybe_table) @@ -14103,7 +14030,7 @@ void SetStackFrameCacheCommon(Handle<Code> code, // static void AbstractCode::SetStackFrameCache(Handle<AbstractCode> abstract_code, - Handle<NumberDictionary> cache) { + Handle<SimpleNumberDictionary> cache) { if (abstract_code->IsCode()) { SetStackFrameCacheCommon(handle(abstract_code->GetCode()), cache); } else { @@ -14161,7 +14088,7 @@ int AbstractCode::SourceStatementPosition(int offset) { } void JSFunction::ClearTypeFeedbackInfo() { - if (feedback_vector_cell()->value()->IsFeedbackVector()) { + if (feedback_cell()->value()->IsFeedbackVector()) { FeedbackVector* vector = feedback_vector(); Isolate* isolate = GetIsolate(); if (vector->ClearSlots(isolate)) { @@ -14285,30 +14212,6 @@ Code* Code::OptimizedCodeIterator::Next() { return code; } -#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER) - -const char* Code::ICState2String(InlineCacheState state) { - switch (state) { - case UNINITIALIZED: - return "UNINITIALIZED"; - case PREMONOMORPHIC: - return "PREMONOMORPHIC"; - case MONOMORPHIC: - return "MONOMORPHIC"; - case RECOMPUTE_HANDLER: - return "RECOMPUTE_HANDLER"; - case POLYMORPHIC: - return "POLYMORPHIC"; - case MEGAMORPHIC: - return "MEGAMORPHIC"; - case GENERIC: - return "GENERIC"; - } - UNREACHABLE(); -} - -#endif // defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER) - #ifdef ENABLE_DISASSEMBLER namespace { @@ -14537,34 +14440,6 @@ void DeoptimizationData::DeoptimizationDataPrint(std::ostream& os) { // NOLINT } -void HandlerTable::HandlerTableRangePrint(std::ostream& os) { - os << " from to hdlr\n"; - for (int i = 0; i < length(); i += kRangeEntrySize) { - int pc_start = Smi::ToInt(get(i + kRangeStartIndex)); - int pc_end = Smi::ToInt(get(i + kRangeEndIndex)); - int handler_field = Smi::ToInt(get(i + kRangeHandlerIndex)); - int handler_offset = HandlerOffsetField::decode(handler_field); - CatchPrediction prediction = HandlerPredictionField::decode(handler_field); - int data = Smi::ToInt(get(i + kRangeDataIndex)); - os << " (" << std::setw(4) << pc_start << "," << std::setw(4) << pc_end - << ") -> " << std::setw(4) << handler_offset - << " (prediction=" << prediction << ", data=" << data << ")\n"; - } -} - - -void HandlerTable::HandlerTableReturnPrint(std::ostream& os) { - os << " off hdlr (c)\n"; - for (int i = 0; i < length(); i += kReturnEntrySize) { - int pc_offset = Smi::ToInt(get(i + kReturnOffsetIndex)); - int handler_field = Smi::ToInt(get(i + kReturnHandlerIndex)); - int handler_offset = HandlerOffsetField::decode(handler_field); - CatchPrediction prediction = HandlerPredictionField::decode(handler_field); - os << " " << std::setw(4) << pc_offset << " -> " << std::setw(4) - << handler_offset << " (prediction=" << prediction << ")\n"; - } -} - void Code::Disassemble(const char* name, std::ostream& os, void* current_pc) { os << "kind = " << Kind2String(kind()) << "\n"; if (is_stub()) { @@ -14668,10 +14543,11 @@ void Code::Disassemble(const char* name, std::ostream& os, void* current_pc) { os << "\n"; } - if (handler_table()->length() > 0) { - os << "Handler Table (size = " << handler_table()->Size() << ")\n"; + if (handler_table_offset() > 0) { + HandlerTable table(this); + os << "Handler Table (size = " << table.NumberOfReturnEntries() << ")\n"; if (kind() == OPTIMIZED_FUNCTION) { - HandlerTable::cast(handler_table())->HandlerTableReturnPrint(os); + table.HandlerTableReturnPrint(os); } os << "\n"; } @@ -14744,10 +14620,11 @@ void BytecodeArray::Disassemble(std::ostream& os) { } #endif - os << "Handler Table (size = " << handler_table()->Size() << ")\n"; + os << "Handler Table (size = " << handler_table()->length() << ")\n"; #ifdef ENABLE_DISASSEMBLER if (handler_table()->length() > 0) { - HandlerTable::cast(handler_table())->HandlerTableRangePrint(os); + HandlerTable table(this); + table.HandlerTableRangePrint(os); } #endif } @@ -15720,7 +15597,7 @@ int JSObject::GetFastElementsUsage() { : store->length(); case FAST_SLOPPY_ARGUMENTS_ELEMENTS: store = SloppyArgumentsElements::cast(store)->arguments(); - // Fall through. + V8_FALLTHROUGH; case HOLEY_SMI_ELEMENTS: case HOLEY_ELEMENTS: case FAST_STRING_WRAPPER_ELEMENTS: @@ -15938,6 +15815,11 @@ v8::Promise::PromiseState JSPromise::status() const { return static_cast<v8::Promise::PromiseState>(value); } +void JSPromise::set_status(Promise::PromiseState status) { + int value = flags() & ~kStatusMask; + set_flags(value | status); +} + // static const char* JSPromise::Status(v8::Promise::PromiseState status) { switch (status) { @@ -15951,6 +15833,217 @@ const char* JSPromise::Status(v8::Promise::PromiseState status) { UNREACHABLE(); } +// static +Handle<Object> JSPromise::Fulfill(Handle<JSPromise> promise, + Handle<Object> value) { + Isolate* const isolate = promise->GetIsolate(); + + // 1. Assert: The value of promise.[[PromiseState]] is "pending". + DCHECK_EQ(Promise::kPending, promise->status()); + + // 2. Let reactions be promise.[[PromiseFulfillReactions]]. + Handle<Object> reactions(promise->reactions(), isolate); + + // 3. Set promise.[[PromiseResult]] to value. + // 4. Set promise.[[PromiseFulfillReactions]] to undefined. + // 5. Set promise.[[PromiseRejectReactions]] to undefined. + promise->set_reactions_or_result(*value); + + // 6. Set promise.[[PromiseState]] to "fulfilled". + promise->set_status(Promise::kFulfilled); + + // 7. Return TriggerPromiseReactions(reactions, value). + return TriggerPromiseReactions(isolate, reactions, value, + PromiseReaction::kFulfill); +} + +// static +Handle<Object> JSPromise::Reject(Handle<JSPromise> promise, + Handle<Object> reason, bool debug_event) { + Isolate* const isolate = promise->GetIsolate(); + + if (debug_event) isolate->debug()->OnPromiseReject(promise, reason); + isolate->RunPromiseHook(PromiseHookType::kResolve, promise, + isolate->factory()->undefined_value()); + + // 1. Assert: The value of promise.[[PromiseState]] is "pending". + DCHECK_EQ(Promise::kPending, promise->status()); + + // 2. Let reactions be promise.[[PromiseRejectReactions]]. + Handle<Object> reactions(promise->reactions(), isolate); + + // 3. Set promise.[[PromiseResult]] to reason. + // 4. Set promise.[[PromiseFulfillReactions]] to undefined. + // 5. Set promise.[[PromiseRejectReactions]] to undefined. + promise->set_reactions_or_result(*reason); + + // 6. Set promise.[[PromiseState]] to "rejected". + promise->set_status(Promise::kRejected); + + // 7. If promise.[[PromiseIsHandled]] is false, perform + // HostPromiseRejectionTracker(promise, "reject"). + if (!promise->has_handler()) { + isolate->ReportPromiseReject(promise, reason, kPromiseRejectWithNoHandler); + } + + // 8. Return TriggerPromiseReactions(reactions, reason). + return TriggerPromiseReactions(isolate, reactions, reason, + PromiseReaction::kReject); +} + +// static +MaybeHandle<Object> JSPromise::Resolve(Handle<JSPromise> promise, + Handle<Object> resolution) { + Isolate* const isolate = promise->GetIsolate(); + + isolate->RunPromiseHook(PromiseHookType::kResolve, promise, + isolate->factory()->undefined_value()); + + // 6. If SameValue(resolution, promise) is true, then + if (promise.is_identical_to(resolution)) { + // a. Let selfResolutionError be a newly created TypeError object. + Handle<Object> self_resolution_error = isolate->factory()->NewTypeError( + MessageTemplate::kPromiseCyclic, resolution); + // b. Return RejectPromise(promise, selfResolutionError). + return Reject(promise, self_resolution_error); + } + + // 7. If Type(resolution) is not Object, then + if (!resolution->IsJSReceiver()) { + // a. Return FulfillPromise(promise, resolution). + return Fulfill(promise, resolution); + } + + // 8. Let then be Get(resolution, "then"). + MaybeHandle<Object> then; + if (isolate->IsPromiseThenLookupChainIntact( + Handle<JSReceiver>::cast(resolution))) { + // We can skip the "then" lookup on {resolution} if its [[Prototype]] + // is the (initial) Promise.prototype and the Promise#then protector + // is intact, as that guards the lookup path for the "then" property + // on JSPromise instances which have the (initial) %PromisePrototype%. + then = isolate->promise_then(); + } else { + then = JSReceiver::GetProperty(Handle<JSReceiver>::cast(resolution), + isolate->factory()->then_string()); + } + + // 9. If then is an abrupt completion, then + Handle<Object> then_action; + if (!then.ToHandle(&then_action)) { + // a. Return RejectPromise(promise, then.[[Value]]). + Handle<Object> reason(isolate->pending_exception(), isolate); + isolate->clear_pending_exception(); + return Reject(promise, reason, false); + } + + // 10. Let thenAction be then.[[Value]]. + // 11. If IsCallable(thenAction) is false, then + if (!then_action->IsCallable()) { + // a. Return FulfillPromise(promise, resolution). + return Fulfill(promise, resolution); + } + + // 12. Perform EnqueueJob("PromiseJobs", PromiseResolveThenableJob, + // «promise, resolution, thenAction»). + Handle<PromiseResolveThenableJobTask> task = + isolate->factory()->NewPromiseResolveThenableJobTask( + promise, Handle<JSReceiver>::cast(then_action), + Handle<JSReceiver>::cast(resolution), isolate->native_context()); + if (isolate->debug()->is_active() && resolution->IsJSPromise()) { + // Mark the dependency of the new {promise} on the {resolution}. + Object::SetProperty(resolution, + isolate->factory()->promise_handled_by_symbol(), + promise, LanguageMode::kStrict) + .Check(); + } + isolate->EnqueueMicrotask(task); + + // 13. Return undefined. + return isolate->factory()->undefined_value(); +} + +// static +MaybeHandle<JSPromise> JSPromise::From(Handle<HeapObject> object) { + Isolate* const isolate = object->GetIsolate(); + if (object->IsJSPromise()) { + return Handle<JSPromise>::cast(object); + } else if (object->IsPromiseCapability()) { + Handle<PromiseCapability> capability = + Handle<PromiseCapability>::cast(object); + if (capability->promise()->IsJSPromise()) { + return handle(JSPromise::cast(capability->promise()), isolate); + } + } else if (object->IsJSGeneratorObject()) { + Handle<JSGeneratorObject> generator = + Handle<JSGeneratorObject>::cast(object); + Handle<Object> handled_by = JSObject::GetDataProperty( + generator, isolate->factory()->generator_outer_promise_symbol()); + if (handled_by->IsJSPromise()) return Handle<JSPromise>::cast(handled_by); + } + return MaybeHandle<JSPromise>(); +} + +// static +Handle<Object> JSPromise::TriggerPromiseReactions(Isolate* isolate, + Handle<Object> reactions, + Handle<Object> argument, + PromiseReaction::Type type) { + DCHECK(reactions->IsSmi() || reactions->IsPromiseReaction()); + + // We need to reverse the {reactions} here, since we record them + // on the JSPromise in the reverse order. + { + DisallowHeapAllocation no_gc; + Object* current = *reactions; + Object* reversed = Smi::kZero; + while (!current->IsSmi()) { + Object* next = PromiseReaction::cast(current)->next(); + PromiseReaction::cast(current)->set_next(reversed); + reversed = current; + current = next; + } + reactions = handle(reversed, isolate); + } + + // Morph the {reactions} into PromiseReactionJobTasks + // and push them onto the microtask queue. + while (!reactions->IsSmi()) { + Handle<HeapObject> task = Handle<HeapObject>::cast(reactions); + Handle<PromiseReaction> reaction = Handle<PromiseReaction>::cast(task); + reactions = handle(reaction->next(), isolate); + + STATIC_ASSERT(PromiseReaction::kSize == PromiseReactionJobTask::kSize); + if (type == PromiseReaction::kFulfill) { + task->synchronized_set_map( + isolate->heap()->promise_fulfill_reaction_job_task_map()); + Handle<PromiseFulfillReactionJobTask>::cast(task)->set_argument( + *argument); + Handle<PromiseFulfillReactionJobTask>::cast(task)->set_context( + *isolate->native_context()); + STATIC_ASSERT(PromiseReaction::kFulfillHandlerOffset == + PromiseFulfillReactionJobTask::kHandlerOffset); + STATIC_ASSERT(PromiseReaction::kPayloadOffset == + PromiseFulfillReactionJobTask::kPayloadOffset); + } else { + DisallowHeapAllocation no_gc; + HeapObject* handler = reaction->reject_handler(); + task->synchronized_set_map( + isolate->heap()->promise_reject_reaction_job_task_map()); + Handle<PromiseRejectReactionJobTask>::cast(task)->set_argument(*argument); + Handle<PromiseRejectReactionJobTask>::cast(task)->set_context( + *isolate->native_context()); + Handle<PromiseRejectReactionJobTask>::cast(task)->set_handler(handler); + STATIC_ASSERT(PromiseReaction::kPayloadOffset == + PromiseRejectReactionJobTask::kPayloadOffset); + } + + isolate->EnqueueMicrotask(Handle<PromiseReactionJobTask>::cast(task)); + } + + return isolate->factory()->undefined_value(); +} + namespace { JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, bool* success) { @@ -16466,8 +16559,6 @@ template class HashTable<ObjectHashTable, ObjectHashTableShape>; template class HashTable<WeakHashTable, WeakHashTableShape>; -template class HashTable<TemplateMap, TemplateMapShape>; - template class Dictionary<NameDictionary, NameDictionaryShape>; template class Dictionary<GlobalDictionary, GlobalDictionaryShape>; @@ -16478,6 +16569,12 @@ template class EXPORT_TEMPLATE_DEFINE( template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) Dictionary<NumberDictionary, NumberDictionaryShape>; +template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) + HashTable<SimpleNumberDictionary, SimpleNumberDictionaryShape>; + +template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) + Dictionary<SimpleNumberDictionary, SimpleNumberDictionaryShape>; + template Handle<NameDictionary> BaseNameDictionary<NameDictionary, NameDictionaryShape>::New( Isolate*, int n, PretenureFlag pretenure, MinimumCapacity capacity_option); @@ -16490,6 +16587,11 @@ template Handle<NumberDictionary> Dictionary<NumberDictionary, NumberDictionaryShape>::AtPut( Handle<NumberDictionary>, uint32_t, Handle<Object>, PropertyDetails); +template Handle<SimpleNumberDictionary> + Dictionary<SimpleNumberDictionary, SimpleNumberDictionaryShape>::AtPut( + Handle<SimpleNumberDictionary>, uint32_t, Handle<Object>, + PropertyDetails); + template Object* Dictionary< NumberDictionary, NumberDictionaryShape>::SlowReverseLookup(Object* value); @@ -16504,6 +16606,10 @@ template Handle<NumberDictionary> Dictionary<NumberDictionary, NumberDictionaryShape>::DeleteEntry( Handle<NumberDictionary>, int); +template Handle<SimpleNumberDictionary> +Dictionary<SimpleNumberDictionary, SimpleNumberDictionaryShape>::DeleteEntry( + Handle<SimpleNumberDictionary>, int); + template Handle<NameDictionary> HashTable<NameDictionary, NameDictionaryShape>::New(Isolate*, int, PretenureFlag, @@ -16537,6 +16643,11 @@ template Handle<NameDictionary> BaseNameDictionary<NameDictionary, NameDictionaryShape>::EnsureCapacity( Handle<NameDictionary>, int); +template Handle<SimpleNumberDictionary> +Dictionary<SimpleNumberDictionary, SimpleNumberDictionaryShape>::Add( + Handle<SimpleNumberDictionary>, uint32_t, Handle<Object>, PropertyDetails, + int*); + template int Dictionary<GlobalDictionary, GlobalDictionaryShape>::NumberOfEnumerableProperties(); @@ -16692,63 +16803,6 @@ size_t JSTypedArray::element_size() { } } -// static -MaybeHandle<JSTypedArray> JSTypedArray::Create(Isolate* isolate, - Handle<Object> default_ctor, - int argc, Handle<Object>* argv, - const char* method_name) { - // 1. Let newTypedArray be ? Construct(constructor, argumentList). - Handle<Object> new_obj; - ASSIGN_RETURN_ON_EXCEPTION(isolate, new_obj, - Execution::New(isolate, default_ctor, argc, argv), - JSTypedArray); - - // 2. Perform ? ValidateTypedArray(newTypedArray). - Handle<JSTypedArray> new_array; - ASSIGN_RETURN_ON_EXCEPTION( - isolate, new_array, JSTypedArray::Validate(isolate, new_obj, method_name), - JSTypedArray); - - // 3. If argumentList is a List of a single Number, then - // If newTypedArray.[[ArrayLength]] < size, throw a TypeError exception. - DCHECK_IMPLIES(argc == 1, argv[0]->IsSmi()); - if (argc == 1 && new_array->length_value() < argv[0]->Number()) { - const MessageTemplate::Template message = - MessageTemplate::kTypedArrayTooShort; - THROW_NEW_ERROR(isolate, NewTypeError(message), JSTypedArray); - } - - // 4. Return newTypedArray. - return new_array; -} - -// static -MaybeHandle<JSTypedArray> JSTypedArray::SpeciesCreate( - Isolate* isolate, Handle<JSTypedArray> exemplar, int argc, - Handle<Object>* argv, const char* method_name) { - // 1. Assert: exemplar is an Object that has a [[TypedArrayName]] internal - // slot. - DCHECK(exemplar->IsJSTypedArray()); - - // 2. Let defaultConstructor be the intrinsic object listed in column one of - // Table 51 for exemplar.[[TypedArrayName]]. - Handle<JSFunction> default_ctor = - JSTypedArray::DefaultConstructor(isolate, exemplar); - - // 3. Let constructor be ? SpeciesConstructor(exemplar, defaultConstructor). - Handle<Object> ctor = default_ctor; - if (!exemplar->HasJSTypedArrayPrototype(isolate) || - !isolate->IsArraySpeciesLookupChainIntact()) { - ASSIGN_RETURN_ON_EXCEPTION( - isolate, ctor, - Object::SpeciesConstructor(isolate, exemplar, default_ctor), - JSTypedArray); - } - - // 4. Return ? TypedArrayCreate(constructor, argumentList). - return Create(isolate, ctor, argc, argv, method_name); -} - void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global, Handle<Name> name) { // Regardless of whether the property is there or not invalidate @@ -17235,8 +17289,9 @@ int SearchLiteralsMapEntry(CompilationCacheTable* cache, int cache_entry, return -1; } -void AddToLiteralsMap(Handle<CompilationCacheTable> cache, int cache_entry, - Handle<Context> native_context, Handle<Cell> literals) { +void AddToFeedbackCellsMap(Handle<CompilationCacheTable> cache, int cache_entry, + Handle<Context> native_context, + Handle<FeedbackCell> feedback_cell) { Isolate* isolate = native_context->GetIsolate(); DCHECK(native_context->IsNativeContext()); STATIC_ASSERT(kLiteralEntryLength == 2); @@ -17255,7 +17310,7 @@ void AddToLiteralsMap(Handle<CompilationCacheTable> cache, int cache_entry, if (entry >= 0) { // Just set the code of the entry. Handle<WeakCell> literals_cell = - isolate->factory()->NewWeakCell(literals); + isolate->factory()->NewWeakCell(feedback_cell); old_literals_map->set(entry + kLiteralLiteralsOffset, *literals_cell); return; } @@ -17280,7 +17335,8 @@ void AddToLiteralsMap(Handle<CompilationCacheTable> cache, int cache_entry, } } - Handle<WeakCell> literals_cell = isolate->factory()->NewWeakCell(literals); + Handle<WeakCell> literals_cell = + isolate->factory()->NewWeakCell(feedback_cell); WeakCell* context_cell = native_context->self_weak_cell(); new_literals_map->set(entry + kLiteralContextOffset, context_cell); @@ -17292,7 +17348,7 @@ void AddToLiteralsMap(Handle<CompilationCacheTable> cache, int cache_entry, WeakCell::cast(new_literals_map->get(i + kLiteralContextOffset)); DCHECK(cell->cleared() || cell->value()->IsNativeContext()); cell = WeakCell::cast(new_literals_map->get(i + kLiteralLiteralsOffset)); - DCHECK(cell->cleared() || (cell->value()->IsCell())); + DCHECK(cell->cleared() || (cell->value()->IsFeedbackCell())); } #endif @@ -17302,9 +17358,9 @@ void AddToLiteralsMap(Handle<CompilationCacheTable> cache, int cache_entry, } } -Cell* SearchLiteralsMap(CompilationCacheTable* cache, int cache_entry, - Context* native_context) { - Cell* result = nullptr; +FeedbackCell* SearchLiteralsMap(CompilationCacheTable* cache, int cache_entry, + Context* native_context) { + FeedbackCell* result = nullptr; int entry = SearchLiteralsMapEntry(cache, cache_entry, native_context); if (entry >= 0) { FixedArray* literals_map = FixedArray::cast(cache->get(cache_entry)); @@ -17312,37 +17368,33 @@ Cell* SearchLiteralsMap(CompilationCacheTable* cache, int cache_entry, WeakCell* cell = WeakCell::cast(literals_map->get(entry + kLiteralLiteralsOffset)); - result = cell->cleared() ? nullptr : Cell::cast(cell->value()); + result = cell->cleared() ? nullptr : FeedbackCell::cast(cell->value()); } - DCHECK(result == nullptr || result->IsCell()); + DCHECK(result == nullptr || result->IsFeedbackCell()); return result; } } // namespace -InfoVectorPair CompilationCacheTable::LookupScript(Handle<String> src, - Handle<Context> context, - LanguageMode language_mode) { - InfoVectorPair empty_result; +MaybeHandle<SharedFunctionInfo> CompilationCacheTable::LookupScript( + Handle<String> src, Handle<Context> context, LanguageMode language_mode) { Handle<SharedFunctionInfo> shared(context->closure()->shared()); StringSharedKey key(src, shared, language_mode, kNoSourcePosition); int entry = FindEntry(&key); - if (entry == kNotFound) return empty_result; + if (entry == kNotFound) return MaybeHandle<SharedFunctionInfo>(); int index = EntryToIndex(entry); - if (!get(index)->IsFixedArray()) return empty_result; + if (!get(index)->IsFixedArray()) return MaybeHandle<SharedFunctionInfo>(); Object* obj = get(index + 1); if (obj->IsSharedFunctionInfo()) { - Cell* literals = - SearchLiteralsMap(this, index + 2, context->native_context()); - return InfoVectorPair(SharedFunctionInfo::cast(obj), literals); + return handle(SharedFunctionInfo::cast(obj)); } - return empty_result; + return MaybeHandle<SharedFunctionInfo>(); } -InfoVectorPair CompilationCacheTable::LookupEval( +InfoCellPair CompilationCacheTable::LookupEval( Handle<String> src, Handle<SharedFunctionInfo> outer_info, Handle<Context> native_context, LanguageMode language_mode, int position) { - InfoVectorPair empty_result; + InfoCellPair empty_result; StringSharedKey key(src, outer_info, language_mode, position); int entry = FindEntry(&key); if (entry == kNotFound) return empty_result; @@ -17350,9 +17402,9 @@ InfoVectorPair CompilationCacheTable::LookupEval( if (!get(index)->IsFixedArray()) return empty_result; Object* obj = get(EntryToIndex(entry) + 1); if (obj->IsSharedFunctionInfo()) { - Cell* literals = + FeedbackCell* feedback_cell = SearchLiteralsMap(this, EntryToIndex(entry) + 2, *native_context); - return InfoVectorPair(SharedFunctionInfo::cast(obj), literals); + return InfoCellPair(SharedFunctionInfo::cast(obj), feedback_cell); } return empty_result; } @@ -17386,7 +17438,7 @@ Handle<CompilationCacheTable> CompilationCacheTable::Put( Handle<CompilationCacheTable> CompilationCacheTable::PutScript( Handle<CompilationCacheTable> cache, Handle<String> src, Handle<Context> context, LanguageMode language_mode, - Handle<SharedFunctionInfo> value, Handle<Cell> literals) { + Handle<SharedFunctionInfo> value) { Isolate* isolate = cache->GetIsolate(); Handle<SharedFunctionInfo> shared(context->closure()->shared()); Handle<Context> native_context(context->native_context()); @@ -17396,7 +17448,6 @@ Handle<CompilationCacheTable> CompilationCacheTable::PutScript( int entry = cache->FindInsertionEntry(key.Hash()); cache->set(EntryToIndex(entry), *k); cache->set(EntryToIndex(entry) + 1, *value); - AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context, literals); cache->ElementAdded(); return cache; } @@ -17404,7 +17455,8 @@ Handle<CompilationCacheTable> CompilationCacheTable::PutScript( Handle<CompilationCacheTable> CompilationCacheTable::PutEval( Handle<CompilationCacheTable> cache, Handle<String> src, Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value, - Handle<Context> native_context, Handle<Cell> literals, int position) { + Handle<Context> native_context, Handle<FeedbackCell> feedback_cell, + int position) { Isolate* isolate = cache->GetIsolate(); StringSharedKey key(src, outer_info, value->language_mode(), position); { @@ -17413,11 +17465,11 @@ Handle<CompilationCacheTable> CompilationCacheTable::PutEval( if (entry != kNotFound) { cache->set(EntryToIndex(entry), *k); cache->set(EntryToIndex(entry) + 1, *value); - // AddToLiteralsMap may allocate a new sub-array to live in the entry, - // but it won't change the cache array. Therefore EntryToIndex and - // entry remains correct. - AddToLiteralsMap(cache, EntryToIndex(entry) + 2, native_context, - literals); + // AddToFeedbackCellsMap may allocate a new sub-array to live in the + // entry, but it won't change the cache array. Therefore EntryToIndex + // and entry remains correct. + AddToFeedbackCellsMap(cache, EntryToIndex(entry) + 2, native_context, + feedback_cell); return cache; } } @@ -17621,6 +17673,13 @@ Handle<Derived> Dictionary<Derived, Shape>::Add(Handle<Derived> dictionary, return dictionary; } +// static +Handle<SimpleNumberDictionary> SimpleNumberDictionary::Set( + Handle<SimpleNumberDictionary> dictionary, uint32_t key, + Handle<Object> value) { + return AtPut(dictionary, key, value, PropertyDetails::Empty()); +} + bool NumberDictionary::HasComplexElements() { if (!requires_slow_elements()) return false; Isolate* isolate = this->GetIsolate(); @@ -19004,10 +19063,11 @@ void JSArrayBuffer::FreeBackingStore(Isolate* isolate, Allocation allocation) { // actually a buffer we are tracking. isolate->wasm_engine()->allocation_tracker()->ReleaseAddressSpace( allocation.length); + CHECK(FreePages(allocation.allocation_base, allocation.length)); + } else { + isolate->array_buffer_allocator()->Free(allocation.allocation_base, + allocation.length); } - - isolate->array_buffer_allocator()->Free(allocation.allocation_base, - allocation.length, allocation.mode); } void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate, @@ -19105,6 +19165,10 @@ Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer( Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()), isolate); + // This code does not know how to materialize from a buffer with guard + // regions. + DCHECK(!buffer->has_guard_region()); + void* backing_store = isolate->array_buffer_allocator()->AllocateUninitialized( fixed_typed_array->DataSize()); @@ -19139,7 +19203,8 @@ Handle<JSArrayBuffer> JSTypedArray::GetBuffer() { Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()), GetIsolate()); if (array_buffer->was_neutered() || - array_buffer->backing_store() != nullptr) { + array_buffer->backing_store() != nullptr || + array_buffer->has_guard_region()) { return array_buffer; } Handle<JSTypedArray> self(this); @@ -19218,12 +19283,12 @@ PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell, return PropertyCellType::kConstant; case PropertyCellType::kConstant: if (*value == cell->value()) return PropertyCellType::kConstant; - // Fall through. + V8_FALLTHROUGH; case PropertyCellType::kConstantType: if (RemainsConstantType(cell, value)) { return PropertyCellType::kConstantType; } - // Fall through. + V8_FALLTHROUGH; case PropertyCellType::kMutable: return PropertyCellType::kMutable; } @@ -19380,7 +19445,7 @@ ElementsKind JSArrayIterator::ElementsKindForInstanceType(InstanceType type) { DCHECK_LE(type, LAST_ARRAY_ITERATOR_TYPE); } - if (type <= JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE) { + if (type <= JS_BIGINT64_ARRAY_VALUE_ITERATOR_TYPE) { kind = static_cast<ElementsKind>(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + (type - FIRST_ARRAY_VALUE_ITERATOR_TYPE)); |