diff options
author | Michaël Zasso <targos@protonmail.com> | 2017-10-18 15:03:02 -0700 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2017-10-18 17:01:41 -0700 |
commit | 3d1b3df9486c0e7708065257f7311902f6b7b366 (patch) | |
tree | cb051bdeaead11e06dcd97725783e0f113afb1bf /deps/v8/src/objects | |
parent | e2cddbb8ccdb7b3c4a40c8acc630f68703bc77b5 (diff) | |
download | android-node-v8-3d1b3df9486c0e7708065257f7311902f6b7b366.tar.gz android-node-v8-3d1b3df9486c0e7708065257f7311902f6b7b366.tar.bz2 android-node-v8-3d1b3df9486c0e7708065257f7311902f6b7b366.zip |
deps: update V8 to 6.2.414.32
PR-URL: https://github.com/nodejs/node/pull/15362
Reviewed-By: Myles Borins <myles.borins@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'deps/v8/src/objects')
26 files changed, 1833 insertions, 478 deletions
diff --git a/deps/v8/src/objects/arguments-inl.h b/deps/v8/src/objects/arguments-inl.h index 32f5359e4b..48ff8daec4 100644 --- a/deps/v8/src/objects/arguments-inl.h +++ b/deps/v8/src/objects/arguments-inl.h @@ -15,12 +15,8 @@ namespace internal { CAST_ACCESSOR(AliasedArgumentsEntry) CAST_ACCESSOR(JSArgumentsObject) -CAST_ACCESSOR(JSSloppyArgumentsObject) CAST_ACCESSOR(SloppyArgumentsElements) -ACCESSORS(JSArgumentsObject, length, Object, kLengthOffset); -ACCESSORS(JSSloppyArgumentsObject, callee, Object, kCalleeOffset); - SMI_ACCESSORS(AliasedArgumentsEntry, aliased_context_slot, kAliasedContextSlot) TYPE_CHECKER(JSArgumentsObject, JS_ARGUMENTS_TYPE) diff --git a/deps/v8/src/objects/arguments.h b/deps/v8/src/objects/arguments.h index 61c1a9cb41..64c34df993 100644 --- a/deps/v8/src/objects/arguments.h +++ b/deps/v8/src/objects/arguments.h @@ -14,16 +14,17 @@ namespace v8 { namespace internal { // Common superclass for JSSloppyArgumentsObject and JSStrictArgumentsObject. +// Note that the instance type {JS_ARGUMENTS_TYPE} does _not_ guarantee the +// below layout, the in-object properties might have transitioned to dictionary +// mode already. Only use the below layout with the specific initial maps. class JSArgumentsObject : public JSObject { public: // Offsets of object fields. static const int kLengthOffset = JSObject::kHeaderSize; - static const int kHeaderSize = kLengthOffset + kPointerSize; + static const int kSize = kLengthOffset + kPointerSize; // Indices of in-object properties. static const int kLengthIndex = 0; - DECL_ACCESSORS(length, Object) - DECL_VERIFIER(JSArgumentsObject) DECL_CAST(JSArgumentsObject) @@ -36,16 +37,11 @@ class JSArgumentsObject : public JSObject { class JSSloppyArgumentsObject : public JSArgumentsObject { public: // Offsets of object fields. - static const int kCalleeOffset = JSArgumentsObject::kHeaderSize; + static const int kCalleeOffset = JSArgumentsObject::kSize; static const int kSize = kCalleeOffset + kPointerSize; // Indices of in-object properties. static const int kCalleeIndex = kLengthIndex + 1; - DECL_ACCESSORS(callee, Object) - - DECL_VERIFIER(JSSloppyArgumentsObject) - DECL_CAST(JSSloppyArgumentsObject) - private: DISALLOW_IMPLICIT_CONSTRUCTORS(JSSloppyArgumentsObject); }; @@ -55,9 +51,7 @@ class JSSloppyArgumentsObject : public JSArgumentsObject { class JSStrictArgumentsObject : public JSArgumentsObject { public: // Offsets of object fields. - static const int kSize = JSArgumentsObject::kHeaderSize; - - DECL_CAST(JSStrictArgumentsObject) + static const int kSize = JSArgumentsObject::kSize; private: DISALLOW_IMPLICIT_CONSTRUCTORS(JSStrictArgumentsObject); @@ -100,7 +94,7 @@ class SloppyArgumentsElements : public FixedArray { DECL_CAST(SloppyArgumentsElements) #ifdef VERIFY_HEAP - void SloppyArgumentsElementsVerify(JSSloppyArgumentsObject* holder); + void SloppyArgumentsElementsVerify(JSObject* holder); #endif private: diff --git a/deps/v8/src/objects/debug-objects-inl.h b/deps/v8/src/objects/debug-objects-inl.h index 1a117f15bd..002ac5215d 100644 --- a/deps/v8/src/objects/debug-objects-inl.h +++ b/deps/v8/src/objects/debug-objects-inl.h @@ -18,6 +18,7 @@ namespace internal { CAST_ACCESSOR(BreakPointInfo) CAST_ACCESSOR(DebugInfo) CAST_ACCESSOR(CoverageInfo) +CAST_ACCESSOR(BreakPoint) SMI_ACCESSORS(DebugInfo, flags, kFlagsOffset) ACCESSORS(DebugInfo, shared, SharedFunctionInfo, kSharedFunctionInfoOffset) @@ -29,17 +30,13 @@ ACCESSORS(DebugInfo, coverage_info, Object, kCoverageInfoOffset) SMI_ACCESSORS(BreakPointInfo, source_position, kSourcePositionOffset) ACCESSORS(BreakPointInfo, break_point_objects, Object, kBreakPointObjectsOffset) +SMI_ACCESSORS(BreakPoint, id, kIdOffset) +ACCESSORS(BreakPoint, condition, String, kConditionOffset) + bool DebugInfo::HasDebugBytecodeArray() { return debug_bytecode_array()->IsBytecodeArray(); } -bool DebugInfo::HasDebugCode() { - Code* code = shared()->code(); - bool has = code->kind() == Code::FUNCTION; - DCHECK(!has || code->has_debug_break_slots()); - return has; -} - BytecodeArray* DebugInfo::OriginalBytecodeArray() { DCHECK(HasDebugBytecodeArray()); return shared()->bytecode_array(); @@ -50,11 +47,6 @@ BytecodeArray* DebugInfo::DebugBytecodeArray() { return BytecodeArray::cast(debug_bytecode_array()); } -Code* DebugInfo::DebugCode() { - DCHECK(HasDebugCode()); - return shared()->code(); -} - } // namespace internal } // namespace v8 diff --git a/deps/v8/src/objects/debug-objects.cc b/deps/v8/src/objects/debug-objects.cc index f686c99639..59e9b20a09 100644 --- a/deps/v8/src/objects/debug-objects.cc +++ b/deps/v8/src/objects/debug-objects.cc @@ -12,13 +12,18 @@ bool DebugInfo::IsEmpty() const { return flags() == kNone; } bool DebugInfo::HasBreakInfo() const { return (flags() & kHasBreakInfo) != 0; } +bool DebugInfo::IsPreparedForBreakpoints() const { + DCHECK(HasBreakInfo()); + return (flags() & kPreparedForBreakpoints) != 0; +} + bool DebugInfo::ClearBreakInfo() { Isolate* isolate = GetIsolate(); set_debug_bytecode_array(isolate->heap()->undefined_value()); set_break_points(isolate->heap()->empty_fixed_array()); - int new_flags = flags() & ~kHasBreakInfo; + int new_flags = flags() & ~kHasBreakInfo & ~kPreparedForBreakpoints; set_flags(new_flags); return new_flags == kNone; @@ -171,16 +176,28 @@ bool DebugInfo::HasCoverageInfo() const { bool DebugInfo::ClearCoverageInfo() { DCHECK(FLAG_block_coverage); - DCHECK(HasCoverageInfo()); - Isolate* isolate = GetIsolate(); + if (HasCoverageInfo()) { + Isolate* isolate = GetIsolate(); - set_coverage_info(isolate->heap()->undefined_value()); + set_coverage_info(isolate->heap()->undefined_value()); - int new_flags = flags() & ~kHasCoverageInfo; - set_flags(new_flags); + int new_flags = flags() & ~kHasCoverageInfo; + set_flags(new_flags); + } + return flags() == kNone; +} - return new_flags == kNone; +namespace { +bool IsEqual(Object* break_point1, Object* break_point2) { + // TODO(kozyatinskiy): remove non-BreakPoint logic once the JS debug API has + // been removed. + if (break_point1->IsBreakPoint() != break_point2->IsBreakPoint()) + return false; + if (!break_point1->IsBreakPoint()) return break_point1 == break_point2; + return BreakPoint::cast(break_point1)->id() == + BreakPoint::cast(break_point2)->id(); } +} // namespace // Remove the specified break point object. void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info, @@ -190,7 +207,7 @@ void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info, if (break_point_info->break_point_objects()->IsUndefined(isolate)) return; // If there is a single break point clear it if it is the same. if (!break_point_info->break_point_objects()->IsFixedArray()) { - if (break_point_info->break_point_objects() == *break_point_object) { + if (IsEqual(break_point_info->break_point_objects(), *break_point_object)) { break_point_info->set_break_point_objects( isolate->heap()->undefined_value()); } @@ -204,7 +221,7 @@ void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info, isolate->factory()->NewFixedArray(old_array->length() - 1); int found_count = 0; for (int i = 0; i < old_array->length(); i++) { - if (old_array->get(i) == *break_point_object) { + if (IsEqual(old_array->get(i), *break_point_object)) { DCHECK(found_count == 0); found_count++; } else { @@ -242,7 +259,7 @@ void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info, isolate->factory()->NewFixedArray(old_array->length() + 1); for (int i = 0; i < old_array->length(); i++) { // If the break point was there before just ignore. - if (old_array->get(i) == *break_point_object) return; + if (IsEqual(old_array->get(i), *break_point_object)) return; new_array->set(i, old_array->get(i)); } // Add the new break point. @@ -260,12 +277,13 @@ bool BreakPointInfo::HasBreakPointObject( } // Single break point. if (!break_point_info->break_point_objects()->IsFixedArray()) { - return break_point_info->break_point_objects() == *break_point_object; + return IsEqual(break_point_info->break_point_objects(), + *break_point_object); } // Multiple break points. FixedArray* array = FixedArray::cast(break_point_info->break_point_objects()); for (int i = 0; i < array->length(); i++) { - if (array->get(i) == *break_point_object) { + if (IsEqual(array->get(i), *break_point_object)) { return true; } } @@ -333,5 +351,25 @@ void CoverageInfo::ResetBlockCount(int slot_index) { set(slot_start + kSlotBlockCountIndex, Smi::kZero); } +void CoverageInfo::Print(String* function_name) { + DCHECK(FLAG_trace_block_coverage); + DisallowHeapAllocation no_gc; + + OFStream os(stdout); + os << "Coverage info ("; + if (function_name->length() > 0) { + auto function_name_cstr = function_name->ToCString(); + os << function_name_cstr.get(); + } else { + os << "{anonymous}"; + } + os << "):" << std::endl; + + for (int i = 0; i < SlotCount(); i++) { + os << "{" << StartSourcePosition(i) << "," << EndSourcePosition(i) << "}" + << std::endl; + } +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/objects/debug-objects.h b/deps/v8/src/objects/debug-objects.h index 1c874fc77d..e75043f8d2 100644 --- a/deps/v8/src/objects/debug-objects.h +++ b/deps/v8/src/objects/debug-objects.h @@ -20,7 +20,8 @@ class DebugInfo : public Struct { enum Flag { kNone = 0, kHasBreakInfo = 1 << 0, - kHasCoverageInfo = 1 << 1, + kPreparedForBreakpoints = 1 << 1, + kHasCoverageInfo = 2 << 1, }; typedef base::Flags<Flag> Flags; @@ -41,6 +42,8 @@ class DebugInfo : public Struct { bool HasBreakInfo() const; + bool IsPreparedForBreakpoints() const; + // Clears all fields related to break points. Returns true iff the // DebugInfo is now empty. bool ClearBreakInfo(); @@ -68,11 +71,9 @@ class DebugInfo : public Struct { int GetBreakPointCount(); inline bool HasDebugBytecodeArray(); - inline bool HasDebugCode(); inline BytecodeArray* OriginalBytecodeArray(); inline BytecodeArray* DebugBytecodeArray(); - inline Code* DebugCode(); // --- Block Coverage --- // ---------------------- @@ -162,6 +163,9 @@ class CoverageInfo : public FixedArray { DECL_CAST(CoverageInfo) + // Print debug info. + void Print(String* function_name); + private: static int FirstIndexForSlot(int slot_index) { return kFirstSlotIndex + slot_index * kSlotIndexCount; @@ -179,6 +183,21 @@ class CoverageInfo : public FixedArray { DISALLOW_IMPLICIT_CONSTRUCTORS(CoverageInfo); }; +// Holds breakpoint related information. This object is used by inspector. +class BreakPoint : public Tuple2 { + public: + DECL_INT_ACCESSORS(id) + DECL_ACCESSORS(condition, String) + + DECL_CAST(BreakPoint) + + static const int kIdOffset = kValue1Offset; + static const int kConditionOffset = kValue2Offset; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(BreakPoint); +}; + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/objects/descriptor-array.h b/deps/v8/src/objects/descriptor-array.h index 0dd5742e93..b74b1dac7c 100644 --- a/deps/v8/src/objects/descriptor-array.h +++ b/deps/v8/src/objects/descriptor-array.h @@ -161,9 +161,6 @@ class DescriptorArray : public FixedArray { // Is the descriptor array sorted and without duplicates? bool IsSortedNoDuplicates(int valid_descriptors = -1); - // Is the descriptor array consistent with the back pointers in targets? - bool IsConsistentWithBackPointers(Map* current_map); - // Are two DescriptorArrays equal? bool IsEqualTo(DescriptorArray* other); #endif diff --git a/deps/v8/src/objects/dictionary.h b/deps/v8/src/objects/dictionary.h index bb8e63b267..a989c8fc8a 100644 --- a/deps/v8/src/objects/dictionary.h +++ b/deps/v8/src/objects/dictionary.h @@ -112,7 +112,7 @@ class NameDictionaryShape : public BaseDictionaryShape<Handle<Name>> { static inline uint32_t Hash(Isolate* isolate, Handle<Name> key); static inline uint32_t HashForObject(Isolate* isolate, Object* object); static inline Handle<Object> AsHandle(Isolate* isolate, Handle<Name> key); - static const int kPrefixSize = 1; + static const int kPrefixSize = 2; static const int kEntrySize = 3; static const int kEntryValueIndex = 1; static const bool kNeedsHoleCheck = false; @@ -125,6 +125,7 @@ class BaseNameDictionary : public Dictionary<Derived, Shape> { public: static const int kNextEnumerationIndexIndex = HashTableBase::kPrefixStartIndex; + static const int kObjectHashIndex = kNextEnumerationIndexIndex + 1; static const int kEntryValueIndex = 1; // Accessors for next enumeration index. @@ -137,6 +138,16 @@ class BaseNameDictionary : public Dictionary<Derived, Shape> { return Smi::ToInt(this->get(kNextEnumerationIndexIndex)); } + void SetHash(int masked_hash) { + DCHECK_EQ(masked_hash & JSReceiver::kHashMask, masked_hash); + this->set(kObjectHashIndex, Smi::FromInt(masked_hash)); + } + + int Hash() const { + Object* hash_obj = this->get(kObjectHashIndex); + return Smi::ToInt(hash_obj); + } + // Creates a new dictionary. MUST_USE_RESULT static Handle<Derived> New( Isolate* isolate, int at_least_space_for, @@ -171,7 +182,10 @@ class NameDictionary static const int kEntryDetailsIndex = 2; static const int kInitialCapacity = 2; + inline Name* NameAt(int entry); + inline void set_hash(int hash); + inline int hash() const; }; class GlobalDictionaryShape : public NameDictionaryShape { diff --git a/deps/v8/src/objects/hash-table.h b/deps/v8/src/objects/hash-table.h index 90146c8f29..6b5682535a 100644 --- a/deps/v8/src/objects/hash-table.h +++ b/deps/v8/src/objects/hash-table.h @@ -271,6 +271,7 @@ class ObjectHashTableShape : public BaseShape<Handle<Object>> { static inline uint32_t HashForObject(Isolate* isolate, Object* object); static inline Handle<Object> AsHandle(Isolate* isolate, Handle<Object> key); static const int kPrefixSize = 0; + static const int kEntryValueIndex = 1; static const int kEntrySize = 2; static const bool kNeedsHoleCheck = false; }; @@ -311,16 +312,16 @@ class ObjectHashTable Handle<Object> key, bool* was_present, int32_t hash); + // Returns the index to the value of an entry. + static inline int EntryToValueIndex(int entry) { + return EntryToIndex(entry) + ObjectHashTableShape::kEntryValueIndex; + } + protected: friend class MarkCompactCollector; void AddEntry(int entry, Object* key, Object* value); void RemoveEntry(int entry); - - // Returns the index to the value of an entry. - static inline int EntryToValueIndex(int entry) { - return EntryToIndex(entry) + 1; - } }; class ObjectHashSetShape : public ObjectHashTableShape { diff --git a/deps/v8/src/objects/intl-objects.cc b/deps/v8/src/objects/intl-objects.cc index fd6546b390..f889e6899b 100644 --- a/deps/v8/src/objects/intl-objects.cc +++ b/deps/v8/src/objects/intl-objects.cc @@ -14,6 +14,7 @@ #include "src/factory.h" #include "src/isolate.h" #include "src/objects-inl.h" +#include "src/property-descriptor.h" #include "unicode/brkiter.h" #include "unicode/bytestream.h" #include "unicode/calendar.h" @@ -27,6 +28,7 @@ #include "unicode/locid.h" #include "unicode/numfmt.h" #include "unicode/numsys.h" +#include "unicode/plurrule.h" #include "unicode/rbbi.h" #include "unicode/smpdtfmt.h" #include "unicode/timezone.h" @@ -34,6 +36,7 @@ #include "unicode/ucol.h" #include "unicode/ucurr.h" #include "unicode/unum.h" +#include "unicode/upluralrules.h" #include "unicode/uvernum.h" #include "unicode/uversion.h" @@ -48,12 +51,13 @@ namespace { bool ExtractStringSetting(Isolate* isolate, Handle<JSObject> options, const char* key, icu::UnicodeString* setting) { + v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); Handle<String> str = isolate->factory()->NewStringFromAsciiChecked(key); Handle<Object> object = JSReceiver::GetProperty(options, str).ToHandleChecked(); if (object->IsString()) { v8::String::Utf8Value utf8_string( - v8::Utils::ToLocal(Handle<String>::cast(object))); + v8_isolate, v8::Utils::ToLocal(Handle<String>::cast(object))); *setting = icu::UnicodeString::fromUTF8(*utf8_string); return true; } @@ -237,6 +241,42 @@ void SetResolvedDateSettings(Isolate* isolate, const icu::Locale& icu_locale, } } +void SetNumericSettings(Isolate* isolate, icu::DecimalFormat* number_format, + Handle<JSObject> options) { + int32_t digits; + if (ExtractIntegerSetting(isolate, options, "minimumIntegerDigits", + &digits)) { + number_format->setMinimumIntegerDigits(digits); + } + + if (ExtractIntegerSetting(isolate, options, "minimumFractionDigits", + &digits)) { + number_format->setMinimumFractionDigits(digits); + } + + if (ExtractIntegerSetting(isolate, options, "maximumFractionDigits", + &digits)) { + number_format->setMaximumFractionDigits(digits); + } + + bool significant_digits_used = false; + if (ExtractIntegerSetting(isolate, options, "minimumSignificantDigits", + &digits)) { + number_format->setMinimumSignificantDigits(digits); + significant_digits_used = true; + } + + if (ExtractIntegerSetting(isolate, options, "maximumSignificantDigits", + &digits)) { + number_format->setMaximumSignificantDigits(digits); + significant_digits_used = true; + } + + number_format->setSignificantDigitsUsed(significant_digits_used); + + number_format->setRoundingMode(icu::DecimalFormat::kRoundHalfUp); +} + icu::DecimalFormat* CreateICUNumberFormat(Isolate* isolate, const icu::Locale& icu_locale, Handle<JSObject> options) { @@ -305,102 +345,20 @@ icu::DecimalFormat* CreateICUNumberFormat(Isolate* isolate, number_format->setCurrency(currency.getBuffer(), status); } - int32_t digits; - if (ExtractIntegerSetting(isolate, options, "minimumIntegerDigits", - &digits)) { - number_format->setMinimumIntegerDigits(digits); - } - - if (ExtractIntegerSetting(isolate, options, "minimumFractionDigits", - &digits)) { - number_format->setMinimumFractionDigits(digits); - } - - if (ExtractIntegerSetting(isolate, options, "maximumFractionDigits", - &digits)) { - number_format->setMaximumFractionDigits(digits); - } - - bool significant_digits_used = false; - if (ExtractIntegerSetting(isolate, options, "minimumSignificantDigits", - &digits)) { - number_format->setMinimumSignificantDigits(digits); - significant_digits_used = true; - } - - if (ExtractIntegerSetting(isolate, options, "maximumSignificantDigits", - &digits)) { - number_format->setMaximumSignificantDigits(digits); - significant_digits_used = true; - } - - number_format->setSignificantDigitsUsed(significant_digits_used); + SetNumericSettings(isolate, number_format, options); bool grouping; if (ExtractBooleanSetting(isolate, options, "useGrouping", &grouping)) { number_format->setGroupingUsed(grouping); } - // Set rounding mode. - number_format->setRoundingMode(icu::DecimalFormat::kRoundHalfUp); - return number_format; } -void SetResolvedNumberSettings(Isolate* isolate, const icu::Locale& icu_locale, - icu::DecimalFormat* number_format, - Handle<JSObject> resolved) { +void SetResolvedNumericSettings(Isolate* isolate, const icu::Locale& icu_locale, + icu::DecimalFormat* number_format, + Handle<JSObject> resolved) { Factory* factory = isolate->factory(); - icu::UnicodeString pattern; - number_format->toPattern(pattern); - JSObject::SetProperty( - resolved, factory->intl_pattern_symbol(), - factory - ->NewStringFromTwoByte(Vector<const uint16_t>( - reinterpret_cast<const uint16_t*>(pattern.getBuffer()), - pattern.length())) - .ToHandleChecked(), - SLOPPY) - .Assert(); - - // Set resolved currency code in options.currency if not empty. - icu::UnicodeString currency(number_format->getCurrency()); - if (!currency.isEmpty()) { - JSObject::SetProperty( - resolved, factory->NewStringFromStaticChars("currency"), - factory - ->NewStringFromTwoByte(Vector<const uint16_t>( - reinterpret_cast<const uint16_t*>(currency.getBuffer()), - currency.length())) - .ToHandleChecked(), - SLOPPY) - .Assert(); - } - - // Ugly hack. ICU doesn't expose numbering system in any way, so we have - // to assume that for given locale NumberingSystem constructor produces the - // same digits as NumberFormat/Calendar would. - UErrorCode status = U_ZERO_ERROR; - icu::NumberingSystem* numbering_system = - icu::NumberingSystem::createInstance(icu_locale, status); - if (U_SUCCESS(status)) { - const char* ns = numbering_system->getName(); - JSObject::SetProperty(resolved, - factory->NewStringFromStaticChars("numberingSystem"), - factory->NewStringFromAsciiChecked(ns), SLOPPY) - .Assert(); - } else { - JSObject::SetProperty(resolved, - factory->NewStringFromStaticChars("numberingSystem"), - factory->undefined_value(), SLOPPY) - .Assert(); - } - delete numbering_system; - - JSObject::SetProperty( - resolved, factory->NewStringFromStaticChars("useGrouping"), - factory->ToBoolean(number_format->isGroupingUsed()), SLOPPY) - .Assert(); JSObject::SetProperty( resolved, factory->NewStringFromStaticChars("minimumIntegerDigits"), @@ -445,7 +403,7 @@ void SetResolvedNumberSettings(Isolate* isolate, const icu::Locale& icu_locale, // Set the locale char result[ULOC_FULLNAME_CAPACITY]; - status = U_ZERO_ERROR; + UErrorCode status = U_ZERO_ERROR; uloc_toLanguageTag(icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status); if (U_SUCCESS(status)) { @@ -460,6 +418,53 @@ void SetResolvedNumberSettings(Isolate* isolate, const icu::Locale& icu_locale, } } +void SetResolvedNumberSettings(Isolate* isolate, const icu::Locale& icu_locale, + icu::DecimalFormat* number_format, + Handle<JSObject> resolved) { + Factory* factory = isolate->factory(); + + // Set resolved currency code in options.currency if not empty. + icu::UnicodeString currency(number_format->getCurrency()); + if (!currency.isEmpty()) { + JSObject::SetProperty( + resolved, factory->NewStringFromStaticChars("currency"), + factory + ->NewStringFromTwoByte(Vector<const uint16_t>( + reinterpret_cast<const uint16_t*>(currency.getBuffer()), + currency.length())) + .ToHandleChecked(), + SLOPPY) + .Assert(); + } + + // Ugly hack. ICU doesn't expose numbering system in any way, so we have + // to assume that for given locale NumberingSystem constructor produces the + // same digits as NumberFormat/Calendar would. + UErrorCode status = U_ZERO_ERROR; + icu::NumberingSystem* numbering_system = + icu::NumberingSystem::createInstance(icu_locale, status); + if (U_SUCCESS(status)) { + const char* ns = numbering_system->getName(); + JSObject::SetProperty(resolved, + factory->NewStringFromStaticChars("numberingSystem"), + factory->NewStringFromAsciiChecked(ns), SLOPPY) + .Assert(); + } else { + JSObject::SetProperty(resolved, + factory->NewStringFromStaticChars("numberingSystem"), + factory->undefined_value(), SLOPPY) + .Assert(); + } + delete numbering_system; + + JSObject::SetProperty( + resolved, factory->NewStringFromStaticChars("useGrouping"), + factory->ToBoolean(number_format->isGroupingUsed()), SLOPPY) + .Assert(); + + SetResolvedNumericSettings(isolate, icu_locale, number_format, resolved); +} + icu::Collator* CreateICUCollator(Isolate* isolate, const icu::Locale& icu_locale, Handle<JSObject> options) { @@ -644,6 +649,88 @@ void SetResolvedCollatorSettings(Isolate* isolate, } } +bool CreateICUPluralRules(Isolate* isolate, const icu::Locale& icu_locale, + Handle<JSObject> options, icu::PluralRules** pl, + icu::DecimalFormat** nf) { + // Make formatter from options. Numbering system is added + // to the locale as Unicode extension (if it was specified at all). + UErrorCode status = U_ZERO_ERROR; + + UPluralType type = UPLURAL_TYPE_CARDINAL; + + icu::UnicodeString type_string; + if (ExtractStringSetting(isolate, options, "type", &type_string)) { + if (type_string == UNICODE_STRING_SIMPLE("ordinal")) { + type = UPLURAL_TYPE_ORDINAL; + } else { + CHECK(type_string == UNICODE_STRING_SIMPLE("cardinal")); + } + } + + icu::PluralRules* plural_rules = + icu::PluralRules::forLocale(icu_locale, type, status); + + if (U_FAILURE(status)) { + delete plural_rules; + return false; + } + + icu::DecimalFormat* number_format = static_cast<icu::DecimalFormat*>( + icu::NumberFormat::createInstance(icu_locale, UNUM_DECIMAL, status)); + + if (U_FAILURE(status)) { + delete plural_rules; + delete number_format; + return false; + } + + *pl = plural_rules; + *nf = number_format; + + SetNumericSettings(isolate, number_format, options); + + // Set rounding mode. + + return true; +} + +bool SetResolvedPluralRulesSettings(Isolate* isolate, + const icu::Locale& icu_locale, + icu::PluralRules* plural_rules, + icu::DecimalFormat* number_format, + Handle<JSObject> resolved) { + SetResolvedNumericSettings(isolate, icu_locale, number_format, resolved); + + Factory* factory = isolate->factory(); + + Handle<JSObject> pluralCategories = Handle<JSObject>::cast( + JSObject::GetProperty( + resolved, factory->NewStringFromStaticChars("pluralCategories")) + .ToHandleChecked()); + + UErrorCode status = U_ZERO_ERROR; + std::unique_ptr<icu::StringEnumeration> categories( + plural_rules->getKeywords(status)); + if (U_FAILURE(status)) return false; + + if (U_FAILURE(status)) return false; + + for (int32_t i = 0;; i++) { + const icu::UnicodeString* category = categories->snext(status); + if (U_FAILURE(status)) return false; + if (category == NULL) return true; + + std::string keyword; + Handle<String> value = factory->NewStringFromAsciiChecked( + category->toUTF8String(keyword).data()); + + LookupIterator it(isolate, pluralCategories, i, LookupIterator::OWN); + JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, + PropertyAttributes::NONE) + .ToHandleChecked(); + } +} + icu::BreakIterator* CreateICUBreakIterator(Isolate* isolate, const icu::Locale& icu_locale, Handle<JSObject> options) { @@ -704,12 +791,13 @@ void SetResolvedBreakIteratorSettings(Isolate* isolate, icu::SimpleDateFormat* DateFormat::InitializeDateTimeFormat( Isolate* isolate, Handle<String> locale, Handle<JSObject> options, Handle<JSObject> resolved) { + v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); // Convert BCP47 into ICU locale format. UErrorCode status = U_ZERO_ERROR; icu::Locale icu_locale; char icu_result[ULOC_FULLNAME_CAPACITY]; int icu_length = 0; - v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale)); + v8::String::Utf8Value bcp47_locale(v8_isolate, v8::Utils::ToLocal(locale)); if (bcp47_locale.length() != 0) { uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY, &icu_length, &status); @@ -753,12 +841,14 @@ void DateFormat::DeleteDateFormat(const v8::WeakCallbackInfo<void>& data) { icu::DecimalFormat* NumberFormat::InitializeNumberFormat( Isolate* isolate, Handle<String> locale, Handle<JSObject> options, Handle<JSObject> resolved) { + v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); + // Convert BCP47 into ICU locale format. UErrorCode status = U_ZERO_ERROR; icu::Locale icu_locale; char icu_result[ULOC_FULLNAME_CAPACITY]; int icu_length = 0; - v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale)); + v8::String::Utf8Value bcp47_locale(v8_isolate, v8::Utils::ToLocal(locale)); if (bcp47_locale.length() != 0) { uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY, &icu_length, &status); @@ -804,12 +894,13 @@ icu::Collator* Collator::InitializeCollator(Isolate* isolate, Handle<String> locale, Handle<JSObject> options, Handle<JSObject> resolved) { + v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); // Convert BCP47 into ICU locale format. UErrorCode status = U_ZERO_ERROR; icu::Locale icu_locale; char icu_result[ULOC_FULLNAME_CAPACITY]; int icu_length = 0; - v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale)); + v8::String::Utf8Value bcp47_locale(v8_isolate, v8::Utils::ToLocal(locale)); if (bcp47_locale.length() != 0) { uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY, &icu_length, &status); @@ -849,15 +940,76 @@ void Collator::DeleteCollator(const v8::WeakCallbackInfo<void>& data) { GlobalHandles::Destroy(reinterpret_cast<Object**>(data.GetParameter())); } +bool PluralRules::InitializePluralRules(Isolate* isolate, Handle<String> locale, + Handle<JSObject> options, + Handle<JSObject> resolved, + icu::PluralRules** plural_rules, + icu::DecimalFormat** number_format) { + // Convert BCP47 into ICU locale format. + UErrorCode status = U_ZERO_ERROR; + icu::Locale icu_locale; + char locale_name[ULOC_FULLNAME_CAPACITY]; + int icu_length = 0; + v8::String::Utf8Value bcp47_locale(reinterpret_cast<v8::Isolate*>(isolate), + v8::Utils::ToLocal(locale)); + if (bcp47_locale.length() != 0) { + uloc_forLanguageTag(*bcp47_locale, locale_name, ULOC_FULLNAME_CAPACITY, + &icu_length, &status); + if (U_FAILURE(status) || icu_length == 0) { + return false; + } + icu_locale = icu::Locale(locale_name); + } + + bool success = CreateICUPluralRules(isolate, icu_locale, options, + plural_rules, number_format); + if (!success) { + // Remove extensions and try again. + icu::Locale no_extension_locale(icu_locale.getBaseName()); + success = CreateICUPluralRules(isolate, no_extension_locale, options, + plural_rules, number_format); + + if (!success) { + FATAL("Failed to create ICU PluralRules, are ICU data files missing?"); + } + + // Set resolved settings (pattern, numbering system). + success = SetResolvedPluralRulesSettings( + isolate, no_extension_locale, *plural_rules, *number_format, resolved); + } else { + success = SetResolvedPluralRulesSettings(isolate, icu_locale, *plural_rules, + *number_format, resolved); + } + + return success; +} + +icu::PluralRules* PluralRules::UnpackPluralRules(Isolate* isolate, + Handle<JSObject> obj) { + return reinterpret_cast<icu::PluralRules*>(obj->GetEmbedderField(0)); +} + +icu::DecimalFormat* PluralRules::UnpackNumberFormat(Isolate* isolate, + Handle<JSObject> obj) { + return reinterpret_cast<icu::DecimalFormat*>(obj->GetEmbedderField(1)); +} + +void PluralRules::DeletePluralRules(const v8::WeakCallbackInfo<void>& data) { + delete reinterpret_cast<icu::PluralRules*>(data.GetInternalField(0)); + delete reinterpret_cast<icu::DecimalFormat*>(data.GetInternalField(1)); + GlobalHandles::Destroy(reinterpret_cast<Object**>(data.GetParameter())); +} + icu::BreakIterator* V8BreakIterator::InitializeBreakIterator( Isolate* isolate, Handle<String> locale, Handle<JSObject> options, Handle<JSObject> resolved) { + v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); // Convert BCP47 into ICU locale format. UErrorCode status = U_ZERO_ERROR; icu::Locale icu_locale; char icu_result[ULOC_FULLNAME_CAPACITY]; int icu_length = 0; - v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale)); + v8::String::Utf8Value bcp47_locale(v8_isolate, v8::Utils::ToLocal(locale)); if (bcp47_locale.length() != 0) { uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY, &icu_length, &status); diff --git a/deps/v8/src/objects/intl-objects.h b/deps/v8/src/objects/intl-objects.h index 890a21d074..d4bdb1e067 100644 --- a/deps/v8/src/objects/intl-objects.h +++ b/deps/v8/src/objects/intl-objects.h @@ -16,6 +16,7 @@ namespace U_ICU_NAMESPACE { class BreakIterator; class Collator; class DecimalFormat; +class PluralRules; class SimpleDateFormat; } @@ -98,6 +99,43 @@ class Collator { Collator(); }; +class PluralRules { + public: + // Create a PluralRules and DecimalFormat for the specificied locale and + // options. Returns false on an ICU failure. + static bool InitializePluralRules(Isolate* isolate, Handle<String> locale, + Handle<JSObject> options, + Handle<JSObject> resolved, + icu::PluralRules** plural_rules, + icu::DecimalFormat** decimal_format); + + // Unpacks PluralRules object from corresponding JavaScript object. + static icu::PluralRules* UnpackPluralRules(Isolate* isolate, + Handle<JSObject> obj); + + // Unpacks NumberFormat object from corresponding JavaScript PluralRUles + // object. + static icu::DecimalFormat* UnpackNumberFormat(Isolate* isolate, + Handle<JSObject> obj); + + // Release memory we allocated for the Collator once the JS object that holds + // the pointer gets garbage collected. + static void DeletePluralRules(const v8::WeakCallbackInfo<void>& data); + + // Layout description. + static const int kPluralRules = JSObject::kHeaderSize; + // Values are formatted with this NumberFormat and then parsed as a Number + // to round them based on the options passed into the PluralRules objct. + // TODO(littledan): If a future version of ICU supports the rounding + // built-in to PluralRules, switch to that, see this bug: + // http://bugs.icu-project.org/trac/ticket/12763 + static const int kNumberFormat = kPluralRules + kPointerSize; + static const int kSize = kNumberFormat + kPointerSize; + + private: + PluralRules(); +}; + class V8BreakIterator { public: // Create a BreakIterator for the specificied locale and options. Returns the diff --git a/deps/v8/src/objects/literal-objects.h b/deps/v8/src/objects/literal-objects.h index f544ee37b8..74a5afde42 100644 --- a/deps/v8/src/objects/literal-objects.h +++ b/deps/v8/src/objects/literal-objects.h @@ -45,6 +45,8 @@ class ConstantElementsPair : public Tuple2 { DECL_INT_ACCESSORS(elements_kind) DECL_ACCESSORS(constant_values, FixedArrayBase) + inline bool is_empty() const; + DECL_CAST(ConstantElementsPair) static const int kElementsKindOffset = kValue1Offset; diff --git a/deps/v8/src/objects/map.h b/deps/v8/src/objects/map.h index 2fa992e153..114ec0b430 100644 --- a/deps/v8/src/objects/map.h +++ b/deps/v8/src/objects/map.h @@ -23,6 +23,7 @@ namespace internal { V(Code) \ V(ConsString) \ V(DataObject) \ + V(FeedbackVector) \ V(FixedArray) \ V(FixedDoubleArray) \ V(FixedFloat64Array) \ @@ -142,7 +143,7 @@ class Map : public HeapObject { class IsMigrationTarget : public BitField<bool, 25, 1> {}; class ImmutablePrototype : public BitField<bool, 26, 1> {}; class NewTargetIsBase : public BitField<bool, 27, 1> {}; - // Bit 28 is free. + class MayHaveInterestingSymbols : public BitField<bool, 28, 1> {}; // Keep this bit field at the very end for better code in // Builtins::kJSConstructStubGeneric stub. @@ -218,6 +219,13 @@ class Map : public HeapObject { inline void set_is_constructor(bool value); inline bool is_constructor() const; + // Tells whether the instance with this map may have properties for + // interesting symbols on it. + // An "interesting symbol" is one for which Name::IsInterestingSymbol() + // returns true, i.e. a well-known symbol like @@toStringTag. + inline void set_may_have_interesting_symbols(bool value); + inline bool may_have_interesting_symbols() const; + // Tells whether the instance with this map has a hidden prototype. inline void set_has_hidden_prototype(bool value); inline bool has_hidden_prototype() const; @@ -250,6 +258,7 @@ class Map : public HeapObject { inline bool is_extensible() const; inline void set_is_prototype_map(bool value); inline bool is_prototype_map() const; + inline bool is_abandoned_prototype_map() const; inline void set_elements_kind(ElementsKind elements_kind); inline ElementsKind elements_kind() const; @@ -275,7 +284,7 @@ class Map : public HeapObject { // map with DICTIONARY_ELEMENTS was found in the prototype chain. bool DictionaryElementsInPrototypeChainOnly(); - inline Map* ElementsTransitionMap() const; + inline Map* ElementsTransitionMap(); inline FixedArrayBase* GetInitialElements() const; @@ -311,7 +320,7 @@ class Map : public HeapObject { // Returns a WeakCell object containing given prototype. The cell is cached // in PrototypeInfo which is created lazily. static Handle<WeakCell> GetOrCreatePrototypeWeakCell( - Handle<JSObject> prototype, Isolate* isolate); + Handle<JSReceiver> prototype, Isolate* isolate); Map* FindRootMap() const; Map* FindFieldOwner(int descriptor) const; @@ -519,12 +528,10 @@ class Map : public HeapObject { // transitions to avoid an explosion in the number of maps for objects used as // dictionaries. inline bool TooManyFastProperties(StoreFromKeyed store_mode) const; - static Handle<Map> TransitionToDataProperty(Handle<Map> map, - Handle<Name> name, - Handle<Object> value, - PropertyAttributes attributes, - PropertyConstness constness, - StoreFromKeyed store_mode); + static Handle<Map> TransitionToDataProperty( + Handle<Map> map, Handle<Name> name, Handle<Object> value, + PropertyAttributes attributes, PropertyConstness constness, + StoreFromKeyed store_mode, bool* created_new_map); static Handle<Map> TransitionToAccessorProperty( Isolate* isolate, Handle<Map> map, Handle<Name> name, int descriptor, Handle<Object> getter, Handle<Object> setter, @@ -602,8 +609,6 @@ class Map : public HeapObject { inline bool IsSpecialReceiverMap() const; - inline bool CanOmitMapChecks() const; - static void AddDependentCode(Handle<Map> map, DependentCode::DependencyGroup group, Handle<Code> code); @@ -618,7 +623,6 @@ class Map : public HeapObject { #ifdef VERIFY_HEAP void DictionaryMapVerify(); - void VerifyOmittedMapChecks(); #endif inline int visitor_id() const; diff --git a/deps/v8/src/objects/module-info.h b/deps/v8/src/objects/module-info.h deleted file mode 100644 index b797db7156..0000000000 --- a/deps/v8/src/objects/module-info.h +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2017 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_OBJECTS_MODULE_INFO_H_ -#define V8_OBJECTS_MODULE_INFO_H_ - -#include "src/objects.h" - -// Has to be the last include (doesn't have include guards): -#include "src/objects/object-macros.h" - -namespace v8 { -namespace internal { - -template <typename T> -class Handle; -class Isolate; -class ModuleDescriptor; -class ModuleInfoEntry; -class String; -class Zone; - -// ModuleInfo is to ModuleDescriptor what ScopeInfo is to Scope. -class ModuleInfo : public FixedArray { - public: - DECL_CAST(ModuleInfo) - - static Handle<ModuleInfo> New(Isolate* isolate, Zone* zone, - ModuleDescriptor* descr); - - inline FixedArray* module_requests() const { - return FixedArray::cast(get(kModuleRequestsIndex)); - } - - inline FixedArray* special_exports() const { - return FixedArray::cast(get(kSpecialExportsIndex)); - } - - inline FixedArray* regular_exports() const { - return FixedArray::cast(get(kRegularExportsIndex)); - } - - inline FixedArray* regular_imports() const { - return FixedArray::cast(get(kRegularImportsIndex)); - } - - inline FixedArray* namespace_imports() const { - return FixedArray::cast(get(kNamespaceImportsIndex)); - } - - inline FixedArray* module_request_positions() const { - return FixedArray::cast(get(kModuleRequestPositionsIndex)); - } - - // Accessors for [regular_exports]. - int RegularExportCount() const; - String* RegularExportLocalName(int i) const; - int RegularExportCellIndex(int i) const; - FixedArray* RegularExportExportNames(int i) const; - -#ifdef DEBUG - inline bool Equals(ModuleInfo* other) const { - return regular_exports() == other->regular_exports() && - regular_imports() == other->regular_imports() && - special_exports() == other->special_exports() && - namespace_imports() == other->namespace_imports() && - module_requests() == other->module_requests() && - module_request_positions() == other->module_request_positions(); - } -#endif - - private: - friend class Factory; - friend class ModuleDescriptor; - enum { - kModuleRequestsIndex, - kSpecialExportsIndex, - kRegularExportsIndex, - kNamespaceImportsIndex, - kRegularImportsIndex, - kModuleRequestPositionsIndex, - kLength - }; - enum { - kRegularExportLocalNameOffset, - kRegularExportCellIndexOffset, - kRegularExportExportNamesOffset, - kRegularExportLength - }; - DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleInfo); -}; - -class ModuleInfoEntry : public Struct { - public: - DECL_CAST(ModuleInfoEntry) - DECL_PRINTER(ModuleInfoEntry) - DECL_VERIFIER(ModuleInfoEntry) - - DECL_ACCESSORS(export_name, Object) - DECL_ACCESSORS(local_name, Object) - DECL_ACCESSORS(import_name, Object) - DECL_INT_ACCESSORS(module_request) - DECL_INT_ACCESSORS(cell_index) - DECL_INT_ACCESSORS(beg_pos) - DECL_INT_ACCESSORS(end_pos) - - static Handle<ModuleInfoEntry> New(Isolate* isolate, - Handle<Object> export_name, - Handle<Object> local_name, - Handle<Object> import_name, - int module_request, int cell_index, - int beg_pos, int end_pos); - - static const int kExportNameOffset = HeapObject::kHeaderSize; - static const int kLocalNameOffset = kExportNameOffset + kPointerSize; - static const int kImportNameOffset = kLocalNameOffset + kPointerSize; - static const int kModuleRequestOffset = kImportNameOffset + kPointerSize; - static const int kCellIndexOffset = kModuleRequestOffset + kPointerSize; - static const int kBegPosOffset = kCellIndexOffset + kPointerSize; - static const int kEndPosOffset = kBegPosOffset + kPointerSize; - static const int kSize = kEndPosOffset + kPointerSize; - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleInfoEntry); -}; - -} // namespace internal -} // namespace v8 - -#include "src/objects/object-macros-undef.h" - -#endif // V8_OBJECTS_MODULE_INFO_H_ diff --git a/deps/v8/src/objects/module-inl.h b/deps/v8/src/objects/module-inl.h new file mode 100644 index 0000000000..7e5310ff3b --- /dev/null +++ b/deps/v8/src/objects/module-inl.h @@ -0,0 +1,67 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_OBJECTS_MODULE_INL_H_ +#define V8_OBJECTS_MODULE_INL_H_ + +#include "src/objects/module.h" + +// Has to be the last include (doesn't have include guards): +#include "src/objects/object-macros.h" + +namespace v8 { +namespace internal { + +CAST_ACCESSOR(Module) +ACCESSORS(Module, code, Object, kCodeOffset) +ACCESSORS(Module, exports, ObjectHashTable, kExportsOffset) +ACCESSORS(Module, regular_exports, FixedArray, kRegularExportsOffset) +ACCESSORS(Module, regular_imports, FixedArray, kRegularImportsOffset) +ACCESSORS(Module, module_namespace, HeapObject, kModuleNamespaceOffset) +ACCESSORS(Module, requested_modules, FixedArray, kRequestedModulesOffset) +ACCESSORS(Module, script, Script, kScriptOffset) +ACCESSORS(Module, exception, Object, kExceptionOffset) +SMI_ACCESSORS(Module, status, kStatusOffset) +SMI_ACCESSORS(Module, dfs_index, kDfsIndexOffset) +SMI_ACCESSORS(Module, dfs_ancestor_index, kDfsAncestorIndexOffset) +SMI_ACCESSORS(Module, hash, kHashOffset) + +ModuleInfo* Module::info() const { + if (status() >= kEvaluating) { + return ModuleInfo::cast(code()); + } + ScopeInfo* scope_info = + status() == kInstantiated + ? JSGeneratorObject::cast(code())->function()->shared()->scope_info() + : status() == kInstantiating + ? JSFunction::cast(code())->shared()->scope_info() + : SharedFunctionInfo::cast(code())->scope_info(); + return scope_info->ModuleDescriptorInfo(); +} + +TYPE_CHECKER(JSModuleNamespace, JS_MODULE_NAMESPACE_TYPE) +CAST_ACCESSOR(JSModuleNamespace) +ACCESSORS(JSModuleNamespace, module, Module, kModuleOffset) + +CAST_ACCESSOR(ModuleInfoEntry) +ACCESSORS(ModuleInfoEntry, export_name, Object, kExportNameOffset) +ACCESSORS(ModuleInfoEntry, local_name, Object, kLocalNameOffset) +ACCESSORS(ModuleInfoEntry, import_name, Object, kImportNameOffset) +SMI_ACCESSORS(ModuleInfoEntry, module_request, kModuleRequestOffset) +SMI_ACCESSORS(ModuleInfoEntry, cell_index, kCellIndexOffset) +SMI_ACCESSORS(ModuleInfoEntry, beg_pos, kBegPosOffset) +SMI_ACCESSORS(ModuleInfoEntry, end_pos, kEndPosOffset) + +CAST_ACCESSOR(ModuleInfo) + +bool HeapObject::IsModuleInfo() const { + return map() == GetHeap()->module_info_map(); +} + +} // namespace internal +} // namespace v8 + +#include "src/objects/object-macros-undef.h" + +#endif // V8_OBJECTS_MODULE_INL_H_ diff --git a/deps/v8/src/objects/module.cc b/deps/v8/src/objects/module.cc new file mode 100644 index 0000000000..a73d91ace8 --- /dev/null +++ b/deps/v8/src/objects/module.cc @@ -0,0 +1,873 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <unordered_map> +#include <unordered_set> + +#include "src/objects/module.h" + +#include "src/accessors.h" +#include "src/ast/modules.h" +#include "src/objects-inl.h" + +namespace v8 { +namespace internal { + +namespace { + +struct ModuleHandleHash { + V8_INLINE size_t operator()(Handle<Module> module) const { + return module->hash(); + } +}; + +struct ModuleHandleEqual { + V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const { + return *lhs == *rhs; + } +}; + +struct StringHandleHash { + V8_INLINE size_t operator()(Handle<String> string) const { + return string->Hash(); + } +}; + +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>, StringHandleHash, + StringHandleEqual, + ZoneAllocator<Handle<String>>> { + public: + explicit UnorderedStringSet(Zone* zone) + : std::unordered_set<Handle<String>, StringHandleHash, StringHandleEqual, + ZoneAllocator<Handle<String>>>( + 2 /* bucket count */, StringHandleHash(), StringHandleEqual(), + ZoneAllocator<Handle<String>>(zone)) {} +}; + +class UnorderedModuleSet + : public std::unordered_set<Handle<Module>, ModuleHandleHash, + ModuleHandleEqual, + ZoneAllocator<Handle<Module>>> { + public: + explicit UnorderedModuleSet(Zone* zone) + : std::unordered_set<Handle<Module>, ModuleHandleHash, ModuleHandleEqual, + ZoneAllocator<Handle<Module>>>( + 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(), + ZoneAllocator<Handle<Module>>(zone)) {} +}; + +class UnorderedStringMap + : public std::unordered_map< + Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual, + ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>> { + public: + explicit UnorderedStringMap(Zone* zone) + : std::unordered_map< + Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual, + ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>>( + 2 /* bucket count */, StringHandleHash(), StringHandleEqual(), + ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>( + zone)) {} +}; + +} // anonymous namespace + +class Module::ResolveSet + : public std::unordered_map< + Handle<Module>, UnorderedStringSet*, ModuleHandleHash, + ModuleHandleEqual, + ZoneAllocator<std::pair<const Handle<Module>, UnorderedStringSet*>>> { + public: + explicit ResolveSet(Zone* zone) + : std::unordered_map<Handle<Module>, UnorderedStringSet*, + ModuleHandleHash, ModuleHandleEqual, + ZoneAllocator<std::pair<const Handle<Module>, + UnorderedStringSet*>>>( + 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(), + ZoneAllocator<std::pair<const Handle<Module>, UnorderedStringSet*>>( + zone)), + zone_(zone) {} + + Zone* zone() const { return zone_; } + + private: + Zone* zone_; +}; + +namespace { + +int ExportIndex(int cell_index) { + DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index), + ModuleDescriptor::kExport); + return cell_index - 1; +} + +int ImportIndex(int cell_index) { + DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index), + ModuleDescriptor::kImport); + return -cell_index - 1; +} + +} // anonymous namespace + +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, int cell_index, + Handle<FixedArray> names) { + DCHECK_LT(0, names->length()); + Isolate* isolate = module->GetIsolate(); + + Handle<Cell> cell = + isolate->factory()->NewCell(isolate->factory()->undefined_value()); + module->regular_exports()->set(ExportIndex(cell_index), *cell); + + 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); +} + +Cell* Module::GetCell(int cell_index) { + DisallowHeapAllocation no_gc; + Object* cell; + switch (ModuleDescriptor::GetCellIndexKind(cell_index)) { + case ModuleDescriptor::kImport: + cell = regular_imports()->get(ImportIndex(cell_index)); + break; + case ModuleDescriptor::kExport: + cell = regular_exports()->get(ExportIndex(cell_index)); + break; + case ModuleDescriptor::kInvalid: + UNREACHABLE(); + cell = nullptr; + break; + } + return Cell::cast(cell); +} + +Handle<Object> Module::LoadVariable(Handle<Module> module, int cell_index) { + Isolate* isolate = module->GetIsolate(); + return handle(module->GetCell(cell_index)->value(), isolate); +} + +void Module::StoreVariable(Handle<Module> module, int cell_index, + Handle<Object> value) { + DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index), + ModuleDescriptor::kExport); + module->GetCell(cell_index)->set_value(*value); +} + +#ifdef DEBUG +void Module::PrintStatusTransition(Status new_status) { + if (FLAG_trace_module_status) { + OFStream os(stdout); + os << "Changing module status from " << status() << " to " << new_status + << " for "; + script()->GetNameOrSourceURL()->Print(os); +#ifndef OBJECT_PRINT + os << "\n"; +#endif // OBJECT_PRINT + } +} +#endif // DEBUG + +void Module::SetStatus(Status new_status) { + DisallowHeapAllocation no_alloc; + DCHECK_LE(status(), new_status); + DCHECK_NE(new_status, Module::kErrored); +#ifdef DEBUG + PrintStatusTransition(new_status); +#endif // DEBUG + set_status(new_status); +} + +void Module::RecordError() { + DisallowHeapAllocation no_alloc; + + Isolate* isolate = GetIsolate(); + Object* the_exception = isolate->pending_exception(); + DCHECK(!the_exception->IsTheHole(isolate)); + + switch (status()) { + case Module::kUninstantiated: + case Module::kPreInstantiating: + case Module::kInstantiating: + case Module::kEvaluating: + break; + case Module::kErrored: + DCHECK_EQ(exception(), the_exception); + return; + default: + UNREACHABLE(); + } + + set_code(info()); + + DCHECK(exception()->IsTheHole(isolate)); +#ifdef DEBUG + PrintStatusTransition(Module::kErrored); +#endif // DEBUG + set_status(Module::kErrored); + set_exception(the_exception); +} + +Object* Module::GetException() { + DisallowHeapAllocation no_alloc; + DCHECK_EQ(status(), Module::kErrored); + Object* the_exception = exception(); + DCHECK(!the_exception->IsTheHole(GetIsolate())); + return the_exception; +} + +MaybeHandle<Cell> Module::ResolveImport(Handle<Module> module, + Handle<String> name, int module_request, + MessageLocation loc, bool must_resolve, + Module::ResolveSet* resolve_set) { + Isolate* isolate = module->GetIsolate(); + Handle<Module> requested_module( + Module::cast(module->requested_modules()->get(module_request)), isolate); + MaybeHandle<Cell> result = Module::ResolveExport(requested_module, name, loc, + must_resolve, resolve_set); + if (isolate->has_pending_exception()) { + DCHECK(result.is_null()); + if (must_resolve) module->RecordError(); + // If {must_resolve} is false and there's an exception, then either that + // exception was already recorded where it happened, or it's the + // kAmbiguousExport exception (see ResolveExportUsingStarExports) and the + // culprit module is still to be determined. + } + return result; +} + +MaybeHandle<Cell> Module::ResolveExport(Handle<Module> module, + Handle<String> name, + MessageLocation loc, bool must_resolve, + Module::ResolveSet* resolve_set) { + DCHECK_NE(module->status(), kErrored); + DCHECK_NE(module->status(), kEvaluating); + DCHECK_GE(module->status(), kPreInstantiating); + + 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) { + return isolate->Throw<Cell>( + isolate->factory()->NewSyntaxError( + MessageTemplate::kCyclicModuleDependency, name), + &loc); + } + return MaybeHandle<Cell>(); + } + name_set->insert(name); + } + + if (object->IsModuleInfoEntry()) { + // Not yet resolved indirect export. + Handle<ModuleInfoEntry> entry = Handle<ModuleInfoEntry>::cast(object); + Handle<String> import_name(String::cast(entry->import_name()), isolate); + Handle<Script> script(module->script(), isolate); + MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos()); + + Handle<Cell> cell; + if (!ResolveImport(module, import_name, entry->module_request(), new_loc, + 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, loc, must_resolve, + resolve_set); +} + +MaybeHandle<Cell> Module::ResolveExportUsingStarExports( + Handle<Module> module, Handle<String> name, MessageLocation loc, + 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. + } + + Handle<Script> script(module->script(), isolate); + MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos()); + + Handle<Cell> cell; + if (ResolveImport(module, name, entry->module_request(), new_loc, false, + resolve_set) + .ToHandle(&cell)) { + if (unique_cell.is_null()) unique_cell = cell; + if (*unique_cell != *cell) { + return isolate->Throw<Cell>( + isolate->factory()->NewSyntaxError( + MessageTemplate::kAmbiguousExport, name), + &loc); + } + } 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) { + return isolate->Throw<Cell>(isolate->factory()->NewSyntaxError( + MessageTemplate::kUnresolvableExport, name), + &loc); + } + return MaybeHandle<Cell>(); +} + +bool Module::Instantiate(Handle<Module> module, v8::Local<v8::Context> context, + v8::Module::ResolveCallback callback) { +#ifdef DEBUG + if (FLAG_trace_module_status) { + OFStream os(stdout); + os << "Instantiating module "; + module->script()->GetNameOrSourceURL()->Print(os); +#ifndef OBJECT_PRINT + os << "\n"; +#endif // OBJECT_PRINT + } +#endif // DEBUG + + Isolate* isolate = module->GetIsolate(); + if (module->status() == kErrored) { + isolate->Throw(module->GetException()); + return false; + } + + if (!PrepareInstantiate(module, context, callback)) { + return false; + } + + Zone zone(isolate->allocator(), ZONE_NAME); + ZoneForwardList<Handle<Module>> stack(&zone); + unsigned dfs_index = 0; + if (!FinishInstantiate(module, &stack, &dfs_index, &zone)) { + for (auto& descendant : stack) { + descendant->RecordError(); + } + DCHECK_EQ(module->GetException(), isolate->pending_exception()); + return false; + } + DCHECK(module->status() == kInstantiated || module->status() == kEvaluated); + DCHECK(stack.empty()); + return true; +} + +bool Module::PrepareInstantiate(Handle<Module> module, + v8::Local<v8::Context> context, + v8::Module::ResolveCallback callback) { + DCHECK_NE(module->status(), kErrored); + DCHECK_NE(module->status(), kEvaluating); + DCHECK_NE(module->status(), kInstantiating); + if (module->status() >= kPreInstantiating) return true; + module->SetStatus(kPreInstantiating); + + // Obtain requested modules. + Isolate* isolate = module->GetIsolate(); + Handle<ModuleInfo> module_info(module->info(), isolate); + Handle<FixedArray> module_requests(module_info->module_requests(), isolate); + Handle<FixedArray> requested_modules(module->requested_modules(), 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; + if (!callback(context, v8::Utils::ToLocal(specifier), + v8::Utils::ToLocal(module)) + .ToLocal(&api_requested_module)) { + isolate->PromoteScheduledException(); + module->RecordError(); + return false; + } + Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module); + if (requested_module->status() == kErrored) { + // TODO(neis): Move this into callback? + isolate->Throw(requested_module->GetException()); + module->RecordError(); + DCHECK_EQ(module->GetException(), requested_module->GetException()); + return false; + } + requested_modules->set(i, *requested_module); + } + + // Recurse. + for (int i = 0, length = requested_modules->length(); i < length; ++i) { + Handle<Module> requested_module(Module::cast(requested_modules->get(i)), + isolate); + if (!PrepareInstantiate(requested_module, context, callback)) { + module->RecordError(); + DCHECK_EQ(module->GetException(), requested_module->GetException()); + return false; + } + } + + // Set up local exports. + // TODO(neis): Create regular_exports array here instead of in factory method? + for (int i = 0, n = module_info->RegularExportCount(); i < n; ++i) { + int cell_index = module_info->RegularExportCellIndex(i); + Handle<FixedArray> export_names(module_info->RegularExportExportNames(i), + isolate); + CreateExport(module, cell_index, 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); + } + + DCHECK_EQ(module->status(), kPreInstantiating); + return true; +} + +void Module::RunInitializationCode(Handle<Module> module) { + DCHECK_EQ(module->status(), kInstantiating); + Isolate* isolate = module->GetIsolate(); + 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 = + Execution::Call(isolate, function, receiver, arraysize(argv), argv) + .ToHandleChecked(); + DCHECK_EQ(*function, Handle<JSGeneratorObject>::cast(generator)->function()); + module->set_code(*generator); +} + +void Module::MaybeTransitionComponent(Handle<Module> module, + ZoneForwardList<Handle<Module>>* stack, + Status new_status) { + DCHECK(new_status == kInstantiated || new_status == kEvaluated); + SLOW_DCHECK( + // {module} is on the {stack}. + std::count_if(stack->begin(), stack->end(), + [&](Handle<Module> m) { return *m == *module; }) == 1); + DCHECK_LE(module->dfs_ancestor_index(), module->dfs_index()); + if (module->dfs_ancestor_index() == module->dfs_index()) { + // This is the root of its strongly connected component. + Handle<Module> ancestor; + do { + ancestor = stack->front(); + stack->pop_front(); + DCHECK_EQ(ancestor->status(), + new_status == kInstantiated ? kInstantiating : kEvaluating); + if (new_status == kInstantiated) RunInitializationCode(ancestor); + ancestor->SetStatus(new_status); + } while (*ancestor != *module); + } +} + +bool Module::FinishInstantiate(Handle<Module> module, + ZoneForwardList<Handle<Module>>* stack, + unsigned* dfs_index, Zone* zone) { + DCHECK_NE(module->status(), kErrored); + DCHECK_NE(module->status(), kEvaluating); + if (module->status() >= kInstantiating) return true; + DCHECK_EQ(module->status(), kPreInstantiating); + + // Instantiate SharedFunctionInfo and mark module as instantiating for + // the recursion. + Isolate* isolate = module->GetIsolate(); + Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(module->code()), + isolate); + Handle<JSFunction> function = + isolate->factory()->NewFunctionFromSharedFunctionInfo( + shared, isolate->native_context()); + module->set_code(*function); + module->SetStatus(kInstantiating); + module->set_dfs_index(*dfs_index); + module->set_dfs_ancestor_index(*dfs_index); + stack->push_front(module); + (*dfs_index)++; + + // Recurse. + Handle<FixedArray> requested_modules(module->requested_modules(), isolate); + for (int i = 0, length = requested_modules->length(); i < length; ++i) { + Handle<Module> requested_module(Module::cast(requested_modules->get(i)), + isolate); + if (!FinishInstantiate(requested_module, stack, dfs_index, zone)) { + return false; + } + + DCHECK_NE(requested_module->status(), kErrored); + DCHECK_NE(requested_module->status(), kEvaluating); + DCHECK_GE(requested_module->status(), kInstantiating); + SLOW_DCHECK( + // {requested_module} is instantiating iff it's on the {stack}. + (requested_module->status() == kInstantiating) == + std::count_if(stack->begin(), stack->end(), [&](Handle<Module> m) { + return *m == *requested_module; + })); + + if (requested_module->status() == kInstantiating) { + module->set_dfs_ancestor_index( + std::min(module->dfs_ancestor_index(), + requested_module->dfs_ancestor_index())); + } + } + + Handle<Script> script(module->script(), isolate); + Handle<ModuleInfo> module_info(module->info(), isolate); + + // 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); + MessageLocation loc(script, entry->beg_pos(), entry->end_pos()); + ResolveSet resolve_set(zone); + Handle<Cell> cell; + if (!ResolveImport(module, name, entry->module_request(), loc, true, + &resolve_set) + .ToHandle(&cell)) { + return false; + } + module->regular_imports()->set(ImportIndex(entry->cell_index()), *cell); + } + + // Resolve indirect exports. + 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> name(entry->export_name(), isolate); + if (name->IsUndefined(isolate)) continue; // Star export. + MessageLocation loc(script, entry->beg_pos(), entry->end_pos()); + ResolveSet resolve_set(zone); + if (ResolveExport(module, Handle<String>::cast(name), loc, true, + &resolve_set) + .is_null()) { + return false; + } + } + + MaybeTransitionComponent(module, stack, kInstantiated); + return true; +} + +MaybeHandle<Object> Module::Evaluate(Handle<Module> module) { +#ifdef DEBUG + if (FLAG_trace_module_status) { + OFStream os(stdout); + os << "Evaluating module "; + module->script()->GetNameOrSourceURL()->Print(os); +#ifndef OBJECT_PRINT + os << "\n"; +#endif // OBJECT_PRINT + } +#endif // DEBUG + + Isolate* isolate = module->GetIsolate(); + if (module->status() == kErrored) { + isolate->Throw(module->GetException()); + return MaybeHandle<Object>(); + } + DCHECK_NE(module->status(), kEvaluating); + DCHECK_GE(module->status(), kInstantiated); + Zone zone(isolate->allocator(), ZONE_NAME); + + ZoneForwardList<Handle<Module>> stack(&zone); + unsigned dfs_index = 0; + Handle<Object> result; + if (!Evaluate(module, &stack, &dfs_index).ToHandle(&result)) { + for (auto& descendant : stack) { + DCHECK_EQ(descendant->status(), kEvaluating); + descendant->RecordError(); + } + DCHECK_EQ(module->GetException(), isolate->pending_exception()); + return MaybeHandle<Object>(); + } + DCHECK_EQ(module->status(), kEvaluated); + DCHECK(stack.empty()); + return result; +} + +MaybeHandle<Object> Module::Evaluate(Handle<Module> module, + ZoneForwardList<Handle<Module>>* stack, + unsigned* dfs_index) { + Isolate* isolate = module->GetIsolate(); + if (module->status() == kErrored) { + isolate->Throw(module->GetException()); + return MaybeHandle<Object>(); + } + if (module->status() >= kEvaluating) { + return isolate->factory()->undefined_value(); + } + DCHECK_EQ(module->status(), kInstantiated); + + Handle<JSGeneratorObject> generator(JSGeneratorObject::cast(module->code()), + isolate); + module->set_code( + generator->function()->shared()->scope_info()->ModuleDescriptorInfo()); + module->SetStatus(kEvaluating); + module->set_dfs_index(*dfs_index); + module->set_dfs_ancestor_index(*dfs_index); + stack->push_front(module); + (*dfs_index)++; + + // Recursion. + Handle<FixedArray> requested_modules(module->requested_modules(), isolate); + for (int i = 0, length = requested_modules->length(); i < length; ++i) { + Handle<Module> requested_module(Module::cast(requested_modules->get(i)), + isolate); + RETURN_ON_EXCEPTION(isolate, Evaluate(requested_module, stack, dfs_index), + Object); + + DCHECK_GE(requested_module->status(), kEvaluating); + DCHECK_NE(requested_module->status(), kErrored); + SLOW_DCHECK( + // {requested_module} is evaluating iff it's on the {stack}. + (requested_module->status() == kEvaluating) == + std::count_if(stack->begin(), stack->end(), [&](Handle<Module> m) { + return *m == *requested_module; + })); + + if (requested_module->status() == kEvaluating) { + module->set_dfs_ancestor_index( + std::min(module->dfs_ancestor_index(), + requested_module->dfs_ancestor_index())); + } + } + + // Evaluation of module body. + Handle<JSFunction> resume( + isolate->native_context()->generator_next_internal(), isolate); + Handle<Object> result; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, result, Execution::Call(isolate, resume, generator, 0, nullptr), + Object); + DCHECK(static_cast<JSIteratorResult*>(JSObject::cast(*result)) + ->done() + ->BooleanValue()); + + MaybeTransitionComponent(module, stack, kEvaluated); + return handle( + static_cast<JSIteratorResult*>(JSObject::cast(*result))->value(), + isolate); +} + +namespace { + +void FetchStarExports(Handle<Module> module, Zone* zone, + UnorderedModuleSet* visited) { + DCHECK_NE(module->status(), Module::kErrored); + DCHECK_GE(module->status(), Module::kInstantiating); + + if (module->module_namespace()->IsJSModuleNamespace()) return; // Shortcut. + + bool cycle = !visited->insert(module).second; + if (cycle) return; + + Isolate* isolate = module->GetIsolate(); + Handle<ObjectHashTable> exports(module->exports(), isolate); + UnorderedStringMap more_exports(zone); + + // TODO(neis): Only allocate more_exports if there are star exports. + // Maybe split special_exports into indirect_exports and star_exports. + + 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); + if (!entry->export_name()->IsUndefined(isolate)) { + continue; // Indirect export. + } + + Handle<Module> requested_module( + Module::cast(module->requested_modules()->get(entry->module_request())), + isolate); + + // Recurse. + FetchStarExports(requested_module, zone, visited); + + // Collect all of [requested_module]'s exports that must be added to + // [module]'s exports (i.e. to [exports]). We record these in + // [more_exports]. Ambiguities (conflicting exports) are marked by mapping + // the name to undefined instead of a Cell. + Handle<ObjectHashTable> requested_exports(requested_module->exports(), + isolate); + for (int i = 0, n = requested_exports->Capacity(); i < n; ++i) { + Object* key; + if (!requested_exports->ToKey(isolate, i, &key)) continue; + Handle<String> name(String::cast(key), isolate); + + if (name->Equals(isolate->heap()->default_string())) continue; + if (!exports->Lookup(name)->IsTheHole(isolate)) continue; + + Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate); + auto insert_result = more_exports.insert(std::make_pair(name, cell)); + if (!insert_result.second) { + auto it = insert_result.first; + if (*it->second == *cell || it->second->IsUndefined(isolate)) { + // We already recorded this mapping before, or the name is already + // known to be ambiguous. In either case, there's nothing to do. + } else { + DCHECK(it->second->IsCell()); + // Different star exports provide different cells for this name, hence + // mark the name as ambiguous. + it->second = isolate->factory()->undefined_value(); + } + } + } + } + + // Copy [more_exports] into [exports]. + for (const auto& elem : more_exports) { + if (elem.second->IsUndefined(isolate)) continue; // Ambiguous export. + DCHECK(!elem.first->Equals(isolate->heap()->default_string())); + DCHECK(elem.second->IsCell()); + exports = ObjectHashTable::Put(exports, elem.first, elem.second); + } + module->set_exports(*exports); +} + +} // anonymous namespace + +Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module, + int module_request) { + Isolate* isolate = module->GetIsolate(); + Handle<Module> requested_module( + Module::cast(module->requested_modules()->get(module_request)), isolate); + return Module::GetModuleNamespace(requested_module); +} + +Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module) { + Isolate* isolate = module->GetIsolate(); + + Handle<HeapObject> object(module->module_namespace(), isolate); + if (!object->IsUndefined(isolate)) { + // Namespace object already exists. + return Handle<JSModuleNamespace>::cast(object); + } + + // Collect the export names. + Zone zone(isolate->allocator(), ZONE_NAME); + UnorderedModuleSet visited(&zone); + FetchStarExports(module, &zone, &visited); + Handle<ObjectHashTable> exports(module->exports(), isolate); + ZoneVector<Handle<String>> names(&zone); + names.reserve(exports->NumberOfElements()); + for (int i = 0, n = exports->Capacity(); i < n; ++i) { + Object* key; + if (!exports->ToKey(isolate, i, &key)) continue; + names.push_back(handle(String::cast(key), isolate)); + } + DCHECK_EQ(static_cast<int>(names.size()), exports->NumberOfElements()); + + // Sort them alphabetically. + struct { + bool operator()(Handle<String> a, Handle<String> b) { + return String::Compare(a, b) == ComparisonResult::kLessThan; + } + } StringLess; + std::sort(names.begin(), names.end(), StringLess); + + // Create the namespace object (initially empty). + Handle<JSModuleNamespace> ns = isolate->factory()->NewJSModuleNamespace(); + ns->set_module(*module); + module->set_module_namespace(*ns); + + // Create the properties in the namespace object. + PropertyAttributes attr = DONT_DELETE; + for (const auto& name : names) { + JSObject::SetAccessor( + ns, Accessors::ModuleNamespaceEntryInfo(isolate, name, attr)) + .Check(); + } + JSObject::PreventExtensions(ns, THROW_ON_ERROR).ToChecked(); + + return ns; +} + +MaybeHandle<Object> JSModuleNamespace::GetExport(Handle<String> name) { + Isolate* isolate = name->GetIsolate(); + + Handle<Object> object(module()->exports()->Lookup(name), isolate); + if (object->IsTheHole(isolate)) { + return isolate->factory()->undefined_value(); + } + + Handle<Object> value(Handle<Cell>::cast(object)->value(), isolate); + if (value->IsTheHole(isolate)) { + THROW_NEW_ERROR( + isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object); + } + + return value; +} + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/src/objects/module.h b/deps/v8/src/objects/module.h new file mode 100644 index 0000000000..ee59d97bd1 --- /dev/null +++ b/deps/v8/src/objects/module.h @@ -0,0 +1,329 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_OBJECTS_MODULE_H_ +#define V8_OBJECTS_MODULE_H_ + +#include "src/objects.h" + +// Has to be the last include (doesn't have include guards): +#include "src/objects/object-macros.h" + +namespace v8 { +namespace internal { + +template <typename T> +class Handle; +class Isolate; +class JSModuleNamespace; +class ModuleDescriptor; +class ModuleInfo; +class ModuleInfoEntry; +class String; +class Zone; + +// A Module object is a mapping from export names to cells +// This is still very much in flux. +class Module : public Struct { + public: + DECL_CAST(Module) + DECL_VERIFIER(Module) + DECL_PRINTER(Module) + + // The code representing this Module, or an abstraction thereof. + // This is either a SharedFunctionInfo or a JSFunction or a ModuleInfo + // depending on whether the module has been instantiated and evaluated. See + // Module::ModuleVerify() for the precise invariant. + DECL_ACCESSORS(code, Object) + + // Arrays of cells corresponding to regular exports and regular imports. + // A cell's position in the array is determined by the cell index of the + // associated module entry (which coincides with the variable index of the + // associated variable). + DECL_ACCESSORS(regular_exports, FixedArray) + DECL_ACCESSORS(regular_imports, FixedArray) + + // The complete export table, mapping an export name to its cell. + // TODO(neis): We may want to remove the regular exports from the table. + DECL_ACCESSORS(exports, ObjectHashTable) + + // Hash for this object (a random non-zero Smi). + DECL_INT_ACCESSORS(hash) + + // Status. + DECL_INT_ACCESSORS(status) + enum Status { + // Order matters! + kUninstantiated, + kPreInstantiating, + kInstantiating, + kInstantiated, + kEvaluating, + kEvaluated, + kErrored + }; + + // The exception in the case {status} is kErrored. + Object* GetException(); + + // The namespace object (or undefined). + DECL_ACCESSORS(module_namespace, HeapObject) + + // Modules imported or re-exported by this module. + // Corresponds 1-to-1 to the module specifier strings in + // ModuleInfo::module_requests. + DECL_ACCESSORS(requested_modules, FixedArray) + + // [script]: Script from which the module originates. + DECL_ACCESSORS(script, Script) + + // Get the ModuleInfo associated with the code. + inline ModuleInfo* info() const; + + // Implementation of spec operation ModuleDeclarationInstantiation. + // Returns false if an exception occurred during instantiation, true + // otherwise. (In the case where the callback throws an exception, that + // exception is propagated.) + static MUST_USE_RESULT bool Instantiate(Handle<Module> module, + v8::Local<v8::Context> context, + v8::Module::ResolveCallback callback); + + // Implementation of spec operation ModuleEvaluation. + static MUST_USE_RESULT MaybeHandle<Object> Evaluate(Handle<Module> module); + + Cell* GetCell(int cell_index); + static Handle<Object> LoadVariable(Handle<Module> module, int cell_index); + static void StoreVariable(Handle<Module> module, int cell_index, + Handle<Object> value); + + // Get the namespace object for [module_request] of [module]. If it doesn't + // exist yet, it is created. + static Handle<JSModuleNamespace> GetModuleNamespace(Handle<Module> module, + int module_request); + + // Get the namespace object for [module]. If it doesn't exist yet, it is + // created. + static Handle<JSModuleNamespace> GetModuleNamespace(Handle<Module> module); + + static const int kCodeOffset = HeapObject::kHeaderSize; + static const int kExportsOffset = kCodeOffset + kPointerSize; + static const int kRegularExportsOffset = kExportsOffset + kPointerSize; + static const int kRegularImportsOffset = kRegularExportsOffset + kPointerSize; + static const int kHashOffset = kRegularImportsOffset + kPointerSize; + static const int kModuleNamespaceOffset = kHashOffset + kPointerSize; + static const int kRequestedModulesOffset = + kModuleNamespaceOffset + kPointerSize; + static const int kStatusOffset = kRequestedModulesOffset + kPointerSize; + static const int kDfsIndexOffset = kStatusOffset + kPointerSize; + static const int kDfsAncestorIndexOffset = kDfsIndexOffset + kPointerSize; + static const int kExceptionOffset = kDfsAncestorIndexOffset + kPointerSize; + static const int kScriptOffset = kExceptionOffset + kPointerSize; + static const int kSize = kScriptOffset + kPointerSize; + + private: + friend class Factory; + + DECL_ACCESSORS(exception, Object) + + // TODO(neis): Don't store those in the module object? + DECL_INT_ACCESSORS(dfs_index) + DECL_INT_ACCESSORS(dfs_ancestor_index) + + // Helpers for Instantiate and Evaluate. + + static void CreateExport(Handle<Module> module, int cell_index, + Handle<FixedArray> names); + static void CreateIndirectExport(Handle<Module> module, Handle<String> name, + Handle<ModuleInfoEntry> entry); + + // The [must_resolve] argument indicates whether or not an exception should be + // thrown in case the module does not provide an export named [name] + // (including when a cycle is detected). An exception is always thrown in the + // case of conflicting star exports. + // + // If [must_resolve] is true, a null result indicates an exception. If + // [must_resolve] is false, a null result may or may not indicate an + // exception (so check manually!). + class ResolveSet; + static MUST_USE_RESULT MaybeHandle<Cell> ResolveExport( + Handle<Module> module, Handle<String> name, MessageLocation loc, + bool must_resolve, ResolveSet* resolve_set); + static MUST_USE_RESULT MaybeHandle<Cell> ResolveImport( + Handle<Module> module, Handle<String> name, int module_request, + MessageLocation loc, bool must_resolve, ResolveSet* resolve_set); + + static MUST_USE_RESULT MaybeHandle<Cell> ResolveExportUsingStarExports( + Handle<Module> module, Handle<String> name, MessageLocation loc, + bool must_resolve, ResolveSet* resolve_set); + + static MUST_USE_RESULT bool PrepareInstantiate( + Handle<Module> module, v8::Local<v8::Context> context, + v8::Module::ResolveCallback callback); + static MUST_USE_RESULT bool FinishInstantiate( + Handle<Module> module, ZoneForwardList<Handle<Module>>* stack, + unsigned* dfs_index, Zone* zone); + static void RunInitializationCode(Handle<Module> module); + + static MUST_USE_RESULT MaybeHandle<Object> Evaluate( + Handle<Module> module, ZoneForwardList<Handle<Module>>* stack, + unsigned* dfs_index); + + static void MaybeTransitionComponent(Handle<Module> module, + ZoneForwardList<Handle<Module>>* stack, + Status new_status); + + // To set status to kErrored, RecordError should be used. + void SetStatus(Status status); + void RecordError(); + +#ifdef DEBUG + // For --trace-module-status. + void PrintStatusTransition(Status new_status); +#endif // DEBUG + + DISALLOW_IMPLICIT_CONSTRUCTORS(Module); +}; + +// When importing a module namespace (import * as foo from "bar"), a +// JSModuleNamespace object (representing module "bar") is created and bound to +// the declared variable (foo). A module can have at most one namespace object. +class JSModuleNamespace : public JSObject { + public: + DECL_CAST(JSModuleNamespace) + DECL_PRINTER(JSModuleNamespace) + DECL_VERIFIER(JSModuleNamespace) + + // The actual module whose namespace is being represented. + DECL_ACCESSORS(module, Module) + + // Retrieve the value exported by [module] under the given [name]. If there is + // no such export, return Just(undefined). If the export is uninitialized, + // schedule an exception and return Nothing. + MUST_USE_RESULT MaybeHandle<Object> GetExport(Handle<String> name); + + // In-object fields. + enum { + kToStringTagFieldIndex, + kInObjectFieldCount, + }; + + static const int kModuleOffset = JSObject::kHeaderSize; + static const int kHeaderSize = kModuleOffset + kPointerSize; + + static const int kSize = kHeaderSize + kPointerSize * kInObjectFieldCount; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(JSModuleNamespace); +}; + +// ModuleInfo is to ModuleDescriptor what ScopeInfo is to Scope. +class ModuleInfo : public FixedArray { + public: + DECL_CAST(ModuleInfo) + + static Handle<ModuleInfo> New(Isolate* isolate, Zone* zone, + ModuleDescriptor* descr); + + inline FixedArray* module_requests() const { + return FixedArray::cast(get(kModuleRequestsIndex)); + } + + inline FixedArray* special_exports() const { + return FixedArray::cast(get(kSpecialExportsIndex)); + } + + inline FixedArray* regular_exports() const { + return FixedArray::cast(get(kRegularExportsIndex)); + } + + inline FixedArray* regular_imports() const { + return FixedArray::cast(get(kRegularImportsIndex)); + } + + inline FixedArray* namespace_imports() const { + return FixedArray::cast(get(kNamespaceImportsIndex)); + } + + inline FixedArray* module_request_positions() const { + return FixedArray::cast(get(kModuleRequestPositionsIndex)); + } + + // Accessors for [regular_exports]. + int RegularExportCount() const; + String* RegularExportLocalName(int i) const; + int RegularExportCellIndex(int i) const; + FixedArray* RegularExportExportNames(int i) const; + +#ifdef DEBUG + inline bool Equals(ModuleInfo* other) const { + return regular_exports() == other->regular_exports() && + regular_imports() == other->regular_imports() && + special_exports() == other->special_exports() && + namespace_imports() == other->namespace_imports() && + module_requests() == other->module_requests() && + module_request_positions() == other->module_request_positions(); + } +#endif + + private: + friend class Factory; + friend class ModuleDescriptor; + enum { + kModuleRequestsIndex, + kSpecialExportsIndex, + kRegularExportsIndex, + kNamespaceImportsIndex, + kRegularImportsIndex, + kModuleRequestPositionsIndex, + kLength + }; + enum { + kRegularExportLocalNameOffset, + kRegularExportCellIndexOffset, + kRegularExportExportNamesOffset, + kRegularExportLength + }; + DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleInfo); +}; + +class ModuleInfoEntry : public Struct { + public: + DECL_CAST(ModuleInfoEntry) + DECL_PRINTER(ModuleInfoEntry) + DECL_VERIFIER(ModuleInfoEntry) + + DECL_ACCESSORS(export_name, Object) + DECL_ACCESSORS(local_name, Object) + DECL_ACCESSORS(import_name, Object) + DECL_INT_ACCESSORS(module_request) + DECL_INT_ACCESSORS(cell_index) + DECL_INT_ACCESSORS(beg_pos) + DECL_INT_ACCESSORS(end_pos) + + static Handle<ModuleInfoEntry> New(Isolate* isolate, + Handle<Object> export_name, + Handle<Object> local_name, + Handle<Object> import_name, + int module_request, int cell_index, + int beg_pos, int end_pos); + + static const int kExportNameOffset = HeapObject::kHeaderSize; + static const int kLocalNameOffset = kExportNameOffset + kPointerSize; + static const int kImportNameOffset = kLocalNameOffset + kPointerSize; + static const int kModuleRequestOffset = kImportNameOffset + kPointerSize; + static const int kCellIndexOffset = kModuleRequestOffset + kPointerSize; + static const int kBegPosOffset = kCellIndexOffset + kPointerSize; + static const int kEndPosOffset = kBegPosOffset + kPointerSize; + static const int kSize = kEndPosOffset + kPointerSize; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleInfoEntry); +}; + +} // namespace internal +} // namespace v8 + +#include "src/objects/object-macros-undef.h" + +#endif // V8_OBJECTS_MODULE_H_ diff --git a/deps/v8/src/objects/name-inl.h b/deps/v8/src/objects/name-inl.h index 4271a1da14..389427cd0d 100644 --- a/deps/v8/src/objects/name-inl.h +++ b/deps/v8/src/objects/name-inl.h @@ -21,6 +21,7 @@ SMI_ACCESSORS(Symbol, flags, kFlagsOffset) BOOL_ACCESSORS(Symbol, flags, is_private, kPrivateBit) BOOL_ACCESSORS(Symbol, flags, is_well_known_symbol, kWellKnownSymbolBit) BOOL_ACCESSORS(Symbol, flags, is_public, kPublicBit) +BOOL_ACCESSORS(Symbol, flags, is_interesting_symbol, kInterestingSymbolBit) TYPE_CHECKER(Symbol, SYMBOL_TYPE) @@ -78,6 +79,10 @@ uint32_t Name::Hash() { return String::cast(this)->ComputeAndSetHash(); } +bool Name::IsInterestingSymbol() const { + return IsSymbol() && Symbol::cast(this)->is_interesting_symbol(); +} + bool Name::IsPrivate() { return this->IsSymbol() && Symbol::cast(this)->is_private(); } diff --git a/deps/v8/src/objects/name.h b/deps/v8/src/objects/name.h index 1f35cac865..ede1d14fb0 100644 --- a/deps/v8/src/objects/name.h +++ b/deps/v8/src/objects/name.h @@ -34,6 +34,13 @@ class Name : public HeapObject { // Conversion. inline bool AsArrayIndex(uint32_t* index); + // An "interesting symbol" is a well-known symbol, like @@toStringTag, + // that's often looked up on random objects but is usually not present. + // We optimize this by setting a flag on the object's map when such + // symbol properties are added, so we can optimize lookups on objects + // that don't have the flag. + inline bool IsInterestingSymbol() const; + // If the name is private, it can only name own properties. inline bool IsPrivate(); @@ -145,6 +152,12 @@ class Symbol : public Name { // a load. DECL_BOOLEAN_ACCESSORS(is_well_known_symbol) + // [is_interesting_symbol]: Whether this is an "interesting symbol", which + // is a well-known symbol like @@toStringTag that's often looked up on + // random objects but is usually not present. See Name::IsInterestingSymbol() + // for a detailed description. + DECL_BOOLEAN_ACCESSORS(is_interesting_symbol) + // [is_public]: Whether this is a symbol created by Symbol.for. Calling // Symbol.keyFor on such a symbol simply needs to return the attached name. DECL_BOOLEAN_ACCESSORS(is_public) @@ -164,6 +177,7 @@ class Symbol : public Name { static const int kPrivateBit = 0; static const int kWellKnownSymbolBit = 1; static const int kPublicBit = 2; + static const int kInterestingSymbolBit = 3; typedef FixedBodyDescriptor<kNameOffset, kFlagsOffset, kSize> BodyDescriptor; // No weak fields. diff --git a/deps/v8/src/objects/object-macros-undef.h b/deps/v8/src/objects/object-macros-undef.h index 6d5f10c07d..4ad2cd2f71 100644 --- a/deps/v8/src/objects/object-macros-undef.h +++ b/deps/v8/src/objects/object-macros-undef.h @@ -34,6 +34,8 @@ #undef WRITE_INT_FIELD #undef READ_INTPTR_FIELD #undef WRITE_INTPTR_FIELD +#undef RELAXED_READ_INTPTR_FIELD +#undef RELAXED_WRITE_INTPTR_FIELD #undef READ_UINT8_FIELD #undef WRITE_UINT8_FIELD #undef READ_INT8_FIELD diff --git a/deps/v8/src/objects/object-macros.h b/deps/v8/src/objects/object-macros.h index e672af14c9..eb192bcd8c 100644 --- a/deps/v8/src/objects/object-macros.h +++ b/deps/v8/src/objects/object-macros.h @@ -20,6 +20,10 @@ inline int name() const; \ inline void set_##name(int value); +#define DECL_INT32_ACCESSORS(name) \ + inline int32_t name() const; \ + inline void set_##name(int32_t value); + #define DECL_ACCESSORS(name, type) \ inline type* name() const; \ inline void set_##name(type* value, \ @@ -43,6 +47,12 @@ int holder::name() const { return READ_INT_FIELD(this, offset); } \ void holder::set_##name(int value) { WRITE_INT_FIELD(this, offset, value); } +#define INT32_ACCESSORS(holder, name, offset) \ + int32_t holder::name() const { return READ_INT32_FIELD(this, offset); } \ + void holder::set_##name(int32_t value) { \ + WRITE_INT32_FIELD(this, offset, value); \ + } + #define ACCESSORS_CHECKED2(holder, name, type, offset, get_condition, \ set_condition) \ type* holder::name() const { \ @@ -155,15 +165,15 @@ #define WRITE_BARRIER(heap, object, offset, value) \ heap->incremental_marking()->RecordWrite( \ object, HeapObject::RawField(object, offset), value); \ - heap->RecordWrite(object, offset, value); - -#define CONDITIONAL_WRITE_BARRIER(heap, object, offset, value, mode) \ - if (mode != SKIP_WRITE_BARRIER) { \ - if (mode == UPDATE_WRITE_BARRIER) { \ - heap->incremental_marking()->RecordWrite( \ - object, HeapObject::RawField(object, offset), value); \ - } \ - heap->RecordWrite(object, offset, value); \ + heap->RecordWrite(object, HeapObject::RawField(object, offset), value); + +#define CONDITIONAL_WRITE_BARRIER(heap, object, offset, value, mode) \ + if (mode != SKIP_WRITE_BARRIER) { \ + if (mode == UPDATE_WRITE_BARRIER) { \ + heap->incremental_marking()->RecordWrite( \ + object, HeapObject::RawField(object, offset), value); \ + } \ + heap->RecordWrite(object, HeapObject::RawField(object, offset), value); \ } #define READ_DOUBLE_FIELD(p, offset) \ @@ -178,6 +188,10 @@ #define WRITE_INT_FIELD(p, offset, value) \ (*reinterpret_cast<int*>(FIELD_ADDR(p, offset)) = value) +#define RELAXED_READ_INTPTR_FIELD(p, offset) \ + static_cast<intptr_t>(base::Relaxed_Load( \ + reinterpret_cast<const base::AtomicWord*>(FIELD_ADDR_CONST(p, offset)))) + #define READ_INTPTR_FIELD(p, offset) \ (*reinterpret_cast<const intptr_t*>(FIELD_ADDR_CONST(p, offset))) @@ -195,9 +209,17 @@ #define WRITE_UINT8_FIELD(p, offset, value) \ (*reinterpret_cast<uint8_t*>(FIELD_ADDR(p, offset)) = value) +#define RELAXED_WRITE_INT8_FIELD(p, offset, value) \ + base::Relaxed_Store(reinterpret_cast<base::Atomic8*>(FIELD_ADDR(p, offset)), \ + static_cast<base::Atomic8>(value)); + #define READ_INT8_FIELD(p, offset) \ (*reinterpret_cast<const int8_t*>(FIELD_ADDR_CONST(p, offset))) +#define RELAXED_READ_INT8_FIELD(p, offset) \ + static_cast<int8_t>(base::Relaxed_Load( \ + reinterpret_cast<const base::Atomic8*>(FIELD_ADDR_CONST(p, offset)))) + #define WRITE_INT8_FIELD(p, offset, value) \ (*reinterpret_cast<int8_t*>(FIELD_ADDR(p, offset)) = value) diff --git a/deps/v8/src/objects/scope-info.cc b/deps/v8/src/objects/scope-info.cc index 9a30b710d7..87045d044e 100644 --- a/deps/v8/src/objects/scope-info.cc +++ b/deps/v8/src/objects/scope-info.cc @@ -144,29 +144,28 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope, bool has_simple_parameters = false; bool asm_module = false; - bool asm_function = false; + bool calls_sloppy_eval = false; if (scope->is_function_scope()) { DeclarationScope* function_scope = scope->AsDeclarationScope(); has_simple_parameters = function_scope->has_simple_parameters(); asm_module = function_scope->asm_module(); - asm_function = function_scope->asm_function(); } FunctionKind function_kind = kNormalFunction; if (scope->is_declaration_scope()) { function_kind = scope->AsDeclarationScope()->function_kind(); + calls_sloppy_eval = scope->AsDeclarationScope()->calls_sloppy_eval(); } // Encode the flags. int flags = ScopeTypeField::encode(scope->scope_type()) | - CallsEvalField::encode(scope->calls_eval()) | + CallsSloppyEvalField::encode(calls_sloppy_eval) | LanguageModeField::encode(scope->language_mode()) | DeclarationScopeField::encode(scope->is_declaration_scope()) | ReceiverVariableField::encode(receiver_info) | HasNewTargetField::encode(has_new_target) | FunctionVariableField::encode(function_name_info) | AsmModuleField::encode(asm_module) | - AsmFunctionField::encode(asm_function) | HasSimpleParametersField::encode(has_simple_parameters) | FunctionKindField::encode(function_kind) | HasOuterScopeInfoField::encode(has_outer_scope_info) | @@ -299,11 +298,11 @@ Handle<ScopeInfo> ScopeInfo::CreateForWithScope( // Encode the flags. int flags = - ScopeTypeField::encode(WITH_SCOPE) | CallsEvalField::encode(false) | + ScopeTypeField::encode(WITH_SCOPE) | CallsSloppyEvalField::encode(false) | LanguageModeField::encode(SLOPPY) | DeclarationScopeField::encode(false) | ReceiverVariableField::encode(NONE) | HasNewTargetField::encode(false) | FunctionVariableField::encode(NONE) | AsmModuleField::encode(false) | - AsmFunctionField::encode(false) | HasSimpleParametersField::encode(true) | + HasSimpleParametersField::encode(true) | FunctionKindField::encode(kNormalFunction) | HasOuterScopeInfoField::encode(has_outer_scope_info) | IsDebugEvaluateScopeField::encode(false); @@ -351,16 +350,17 @@ Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) { Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length); // Encode the flags. - int flags = - ScopeTypeField::encode(SCRIPT_SCOPE) | CallsEvalField::encode(false) | - LanguageModeField::encode(SLOPPY) | DeclarationScopeField::encode(true) | - ReceiverVariableField::encode(receiver_info) | - FunctionVariableField::encode(function_name_info) | - AsmModuleField::encode(false) | AsmFunctionField::encode(false) | - HasSimpleParametersField::encode(has_simple_parameters) | - FunctionKindField::encode(FunctionKind::kNormalFunction) | - HasOuterScopeInfoField::encode(has_outer_scope_info) | - IsDebugEvaluateScopeField::encode(false); + int flags = ScopeTypeField::encode(SCRIPT_SCOPE) | + CallsSloppyEvalField::encode(false) | + LanguageModeField::encode(SLOPPY) | + DeclarationScopeField::encode(true) | + ReceiverVariableField::encode(receiver_info) | + FunctionVariableField::encode(function_name_info) | + AsmModuleField::encode(false) | + HasSimpleParametersField::encode(has_simple_parameters) | + FunctionKindField::encode(FunctionKind::kNormalFunction) | + HasOuterScopeInfoField::encode(has_outer_scope_info) | + IsDebugEvaluateScopeField::encode(false); scope_info->SetFlags(flags); scope_info->SetParameterCount(parameter_count); scope_info->SetStackLocalCount(stack_local_count); @@ -404,8 +404,12 @@ ScopeType ScopeInfo::scope_type() { return ScopeTypeField::decode(Flags()); } -bool ScopeInfo::CallsEval() { - return length() > 0 && CallsEvalField::decode(Flags()); +bool ScopeInfo::CallsSloppyEval() { + bool calls_sloppy_eval = + length() > 0 && CallsSloppyEvalField::decode(Flags()); + DCHECK_IMPLIES(calls_sloppy_eval, is_sloppy(language_mode())); + DCHECK_IMPLIES(calls_sloppy_eval, is_declaration_scope()); + return calls_sloppy_eval; } LanguageMode ScopeInfo::language_mode() { diff --git a/deps/v8/src/objects/scope-info.h b/deps/v8/src/objects/scope-info.h index e60ac99162..db8bd3a5a8 100644 --- a/deps/v8/src/objects/scope-info.h +++ b/deps/v8/src/objects/scope-info.h @@ -20,6 +20,7 @@ class Handle; class Isolate; template <typename T> class MaybeHandle; +class ModuleInfo; class Scope; class Zone; @@ -37,9 +38,6 @@ class ScopeInfo : public FixedArray { // Return the type of this scope. ScopeType scope_type(); - // Does this scope call eval? - bool CallsEval(); - // Return the language mode of this scope. LanguageMode language_mode(); @@ -47,7 +45,7 @@ class ScopeInfo : public FixedArray { bool is_declaration_scope(); // Does this scope make a sloppy eval call? - bool CallsSloppyEval() { return CallsEval() && is_sloppy(language_mode()); } + bool CallsSloppyEval(); // Return the total number of locals allocated on the stack and in the // context. This includes the parameters that are allocated in the context. @@ -87,9 +85,6 @@ class ScopeInfo : public FixedArray { // Return if this is a function scope with "use asm". inline bool IsAsmModule() { return AsmModuleField::decode(Flags()); } - // Return if this is a nested function within an asm module scope. - inline bool IsAsmFunction() { return AsmFunctionField::decode(Flags()); } - inline bool HasSimpleParameters() { return HasSimpleParametersField::decode(Flags()); } @@ -301,10 +296,11 @@ class ScopeInfo : public FixedArray { // Properties of scopes. class ScopeTypeField : public BitField<ScopeType, 0, 4> {}; - class CallsEvalField : public BitField<bool, ScopeTypeField::kNext, 1> {}; + class CallsSloppyEvalField : public BitField<bool, ScopeTypeField::kNext, 1> { + }; STATIC_ASSERT(LANGUAGE_END == 2); class LanguageModeField - : public BitField<LanguageMode, CallsEvalField::kNext, 1> {}; + : public BitField<LanguageMode, CallsSloppyEvalField::kNext, 1> {}; class DeclarationScopeField : public BitField<bool, LanguageModeField::kNext, 1> {}; class ReceiverVariableField @@ -316,9 +312,8 @@ class ScopeInfo : public FixedArray { : public BitField<VariableAllocationInfo, HasNewTargetField::kNext, 2> {}; class AsmModuleField : public BitField<bool, FunctionVariableField::kNext, 1> {}; - class AsmFunctionField : public BitField<bool, AsmModuleField::kNext, 1> {}; class HasSimpleParametersField - : public BitField<bool, AsmFunctionField::kNext, 1> {}; + : public BitField<bool, AsmModuleField::kNext, 1> {}; class FunctionKindField : public BitField<FunctionKind, HasSimpleParametersField::kNext, 10> {}; class HasOuterScopeInfoField diff --git a/deps/v8/src/objects/shared-function-info-inl.h b/deps/v8/src/objects/shared-function-info-inl.h index 028d3cf086..d9e0407617 100644 --- a/deps/v8/src/objects/shared-function-info-inl.h +++ b/deps/v8/src/objects/shared-function-info-inl.h @@ -6,6 +6,7 @@ #define V8_OBJECTS_SHARED_FUNCTION_INFO_INL_H_ #include "src/heap/heap-inl.h" +#include "src/objects/scope-info.h" #include "src/objects/shared-function-info.h" // Has to be the last include (doesn't have include guards): @@ -57,11 +58,6 @@ INT_ACCESSORS(SharedFunctionInfo, start_position_and_type, INT_ACCESSORS(SharedFunctionInfo, function_token_position, kFunctionTokenPositionOffset) INT_ACCESSORS(SharedFunctionInfo, compiler_hints, kCompilerHintsOffset) -INT_ACCESSORS(SharedFunctionInfo, opt_count_and_bailout_reason, - kOptCountAndBailoutReasonOffset) -INT_ACCESSORS(SharedFunctionInfo, counters, kCountersOffset) -INT_ACCESSORS(SharedFunctionInfo, ast_node_count, kAstNodeCountOffset) -INT_ACCESSORS(SharedFunctionInfo, profiler_ticks, kProfilerTicksOffset) bool SharedFunctionInfo::has_shared_name() const { return raw_name() != kNoSharedNameSentinel; @@ -93,8 +89,6 @@ BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints, uses_arguments, BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints, has_duplicate_parameters, SharedFunctionInfo::HasDuplicateParametersBit) -BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints, asm_function, - SharedFunctionInfo::IsAsmFunctionBit) BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints, is_declaration, SharedFunctionInfo::IsDeclarationBit) @@ -104,8 +98,14 @@ BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints, force_inline, SharedFunctionInfo::ForceInlineBit) BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints, is_asm_wasm_broken, SharedFunctionInfo::IsAsmWasmBrokenBit) -BIT_FIELD_ACCESSORS(SharedFunctionInfo, compiler_hints, optimization_disabled, - SharedFunctionInfo::OptimizationDisabledBit) + +bool SharedFunctionInfo::optimization_disabled() const { + return disable_optimization_reason() != BailoutReason::kNoReason; +} + +BailoutReason SharedFunctionInfo::disable_optimization_reason() const { + return DisabledOptimizationReasonBits::decode(compiler_hints()); +} LanguageMode SharedFunctionInfo::language_mode() { STATIC_ASSERT(LANGUAGE_END == 2); @@ -163,6 +163,10 @@ void SharedFunctionInfo::set_function_map_index(int index) { set_compiler_hints(FunctionMapIndexBits::update(compiler_hints(), index)); } +void SharedFunctionInfo::clear_padding() { + memset(this->address() + kSize, 0, kAlignedSize - kSize); +} + void SharedFunctionInfo::UpdateFunctionMapIndex() { int map_index = Context::FunctionMapIndex( language_mode(), kind(), has_shared_name(), needs_home_object()); @@ -269,11 +273,6 @@ bool SharedFunctionInfo::HasDebugInfo() const { return has_debug_info; } -bool SharedFunctionInfo::HasDebugCode() const { - if (HasBaselineCode()) return code()->has_debug_break_slots(); - return HasBytecodeArray(); -} - bool SharedFunctionInfo::IsApiFunction() { return function_data()->IsFunctionTemplateInfo(); } @@ -357,42 +356,6 @@ void SharedFunctionInfo::set_inferred_name(String* inferred_name) { set_function_identifier(inferred_name); } -BIT_FIELD_ACCESSORS(SharedFunctionInfo, counters, ic_age, - SharedFunctionInfo::ICAgeBits) - -BIT_FIELD_ACCESSORS(SharedFunctionInfo, counters, deopt_count, - SharedFunctionInfo::DeoptCountBits) - -void SharedFunctionInfo::increment_deopt_count() { - int value = counters(); - int deopt_count = DeoptCountBits::decode(value); - // Saturate the deopt count when incrementing, rather than overflowing. - if (deopt_count < DeoptCountBits::kMax) { - set_counters(DeoptCountBits::update(value, deopt_count + 1)); - } -} - -BIT_FIELD_ACCESSORS(SharedFunctionInfo, counters, opt_reenable_tries, - SharedFunctionInfo::OptReenableTriesBits) - -BIT_FIELD_ACCESSORS(SharedFunctionInfo, opt_count_and_bailout_reason, opt_count, - SharedFunctionInfo::OptCountBits) - -BIT_FIELD_ACCESSORS(SharedFunctionInfo, opt_count_and_bailout_reason, - disable_optimization_reason, - SharedFunctionInfo::DisabledOptimizationReasonBits) - -void SharedFunctionInfo::TryReenableOptimization() { - int tries = opt_reenable_tries(); - set_opt_reenable_tries((tries + 1) & OptReenableTriesBits::kMax); - // We reenable optimization whenever the number of tries is a large - // enough power of 2. - if (tries >= 16 && (((tries - 1) & tries) == 0)) { - set_optimization_disabled(false); - set_deopt_count(0); - } -} - bool SharedFunctionInfo::IsUserJavaScript() { Object* script_obj = script(); if (script_obj->IsUndefined(GetIsolate())) return false; diff --git a/deps/v8/src/objects/shared-function-info.h b/deps/v8/src/objects/shared-function-info.h index 03cae0aede..6676c619a6 100644 --- a/deps/v8/src/objects/shared-function-info.h +++ b/deps/v8/src/objects/shared-function-info.h @@ -201,9 +201,6 @@ class SharedFunctionInfo : public HeapObject { bool HasCoverageInfo() const; CoverageInfo* GetCoverageInfo() const; - // A function has debug code if the compiled code has debug break slots. - inline bool HasDebugCode() const; - // [debug info]: Debug information. DECL_ACCESSORS(debug_info, Object) @@ -253,7 +250,7 @@ class SharedFunctionInfo : public HeapObject { // The function cannot cause any side effects. bool HasNoSideEffect(); - // Used for flags such as --hydrogen-filter. + // Used for flags such as --turbo-filter. bool PassesFilter(const char* raw_filter); // Position of the 'function' token in the script source. @@ -278,23 +275,9 @@ class SharedFunctionInfo : public HeapObject { // drive optimization. DECL_INT_ACCESSORS(compiler_hints) - DECL_INT_ACCESSORS(ast_node_count) - - DECL_INT_ACCESSORS(profiler_ticks) - - // Inline cache age is used to infer whether the function survived a context - // disposal or not. In the former case we reset the opt_count. - DECL_INT_ACCESSORS(ic_age) - // Indicates if this function can be lazy compiled. DECL_BOOLEAN_ACCESSORS(allows_lazy_compilation) - // Indicates whether optimizations have been disabled for this - // shared function info. If a function is repeatedly optimized or if - // we cannot optimize the function we disable optimization to avoid - // spending time attempting to optimize it again. - DECL_BOOLEAN_ACCESSORS(optimization_disabled) - // Indicates the language mode. inline LanguageMode language_mode(); inline void set_language_mode(LanguageMode language_mode); @@ -314,9 +297,6 @@ class SharedFunctionInfo : public HeapObject { // Indicate that this function should always be inlined in optimized code. DECL_BOOLEAN_ACCESSORS(force_inline) - // Indicates that this function is an asm function. - DECL_BOOLEAN_ACCESSORS(asm_function) - // Whether this function was created from a FunctionDeclaration. DECL_BOOLEAN_ACCESSORS(is_declaration) @@ -329,9 +309,21 @@ class SharedFunctionInfo : public HeapObject { // this shared function info. DECL_INT_ACCESSORS(function_map_index) + // Clear uninitialized padding space. This ensures that the snapshot content + // is deterministic. + inline void clear_padding(); + // Recalculates the |map_index| value after modifications of this shared info. inline void UpdateFunctionMapIndex(); + // Indicates whether optimizations have been disabled for this shared function + // info. If we cannot optimize the function we disable optimization to avoid + // spending time attempting to optimize it again. + inline bool optimization_disabled() const; + + // The reason why optimization was disabled. + inline BailoutReason disable_optimization_reason() const; + // Disable (further) attempted optimization of all functions sharing this // shared function info. void DisableOptimization(BailoutReason reason); @@ -341,29 +333,6 @@ class SharedFunctionInfo : public HeapObject { Handle<Object> GetSourceCode(); Handle<Object> GetSourceCodeHarmony(); - // Number of times the function was optimized. - DECL_INT_ACCESSORS(opt_count) - - // Number of times the function was deoptimized. - DECL_INT_ACCESSORS(deopt_count) - inline void increment_deopt_count(); - - // Number of time we tried to re-enable optimization after it - // was disabled due to high number of deoptimizations. - DECL_INT_ACCESSORS(opt_reenable_tries) - - inline void TryReenableOptimization(); - - // Stores deopt_count, opt_reenable_tries and ic_age as bit-fields. - inline void set_counters(int value); - inline int counters() const; - - // Stores opt_count and bailout_reason as bit-fields. - DECL_INT_ACCESSORS(opt_count_and_bailout_reason) - - inline BailoutReason disable_optimization_reason() const; - inline void set_disable_optimization_reason(BailoutReason reason); - // Tells whether this function should be subject to debugging. inline bool IsSubjectToDebugging(); @@ -391,8 +360,9 @@ class SharedFunctionInfo : public HeapObject { // Dispatched behavior. DECL_PRINTER(SharedFunctionInfo) DECL_VERIFIER(SharedFunctionInfo) - - void ResetForNewContext(int new_ic_age); +#ifdef OBJECT_PRINT + void PrintSourceCode(std::ostream& os); +#endif // Iterate over all shared function infos in a given script. class ScriptIterator { @@ -438,36 +408,32 @@ class SharedFunctionInfo : public HeapObject { #endif // Layout description. -#define SHARED_FUNCTION_INFO_FIELDS(V) \ - /* Pointer fields. */ \ - V(kCodeOffset, kPointerSize) \ - V(kNameOffset, kPointerSize) \ - V(kScopeInfoOffset, kPointerSize) \ - V(kOuterScopeInfoOffset, kPointerSize) \ - V(kConstructStubOffset, kPointerSize) \ - V(kInstanceClassNameOffset, kPointerSize) \ - V(kFunctionDataOffset, kPointerSize) \ - V(kScriptOffset, kPointerSize) \ - V(kDebugInfoOffset, kPointerSize) \ - V(kFunctionIdentifierOffset, kPointerSize) \ - V(kFeedbackMetadataOffset, kPointerSize) \ - V(kPreParsedScopeDataOffset, kPointerSize) \ - V(kEndOfPointerFieldsOffset, 0) \ - /* Raw data fields. */ \ - V(kFunctionLiteralIdOffset, kInt32Size) \ - V(kUniqueIdOffset, kUniqueIdFieldSize) \ - V(kLengthOffset, kInt32Size) \ - V(kFormalParameterCountOffset, kInt32Size) \ - V(kExpectedNofPropertiesOffset, kInt32Size) \ - V(kStartPositionAndTypeOffset, kInt32Size) \ - V(kEndPositionOffset, kInt32Size) \ - V(kFunctionTokenPositionOffset, kInt32Size) \ - V(kCompilerHintsOffset, kInt32Size) \ - V(kOptCountAndBailoutReasonOffset, kInt32Size) \ - V(kCountersOffset, kInt32Size) \ - V(kAstNodeCountOffset, kInt32Size) \ - V(kProfilerTicksOffset, kInt32Size) \ - /* Total size. */ \ +#define SHARED_FUNCTION_INFO_FIELDS(V) \ + /* Pointer fields. */ \ + V(kCodeOffset, kPointerSize) \ + V(kNameOffset, kPointerSize) \ + V(kScopeInfoOffset, kPointerSize) \ + V(kOuterScopeInfoOffset, kPointerSize) \ + V(kConstructStubOffset, kPointerSize) \ + V(kInstanceClassNameOffset, kPointerSize) \ + V(kFunctionDataOffset, kPointerSize) \ + V(kScriptOffset, kPointerSize) \ + V(kDebugInfoOffset, kPointerSize) \ + V(kFunctionIdentifierOffset, kPointerSize) \ + V(kFeedbackMetadataOffset, kPointerSize) \ + V(kPreParsedScopeDataOffset, kPointerSize) \ + V(kEndOfPointerFieldsOffset, 0) \ + /* Raw data fields. */ \ + V(kFunctionLiteralIdOffset, kInt32Size) \ + V(kUniqueIdOffset, kUniqueIdFieldSize) \ + V(kLengthOffset, kInt32Size) \ + V(kFormalParameterCountOffset, kInt32Size) \ + V(kExpectedNofPropertiesOffset, kInt32Size) \ + V(kStartPositionAndTypeOffset, kInt32Size) \ + V(kEndPositionOffset, kInt32Size) \ + V(kFunctionTokenPositionOffset, kInt32Size) \ + V(kCompilerHintsOffset, kInt32Size) \ + /* Total size. */ \ V(kSize, 0) DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, @@ -496,19 +462,20 @@ class SharedFunctionInfo : public HeapObject { V(FunctionKindBits, FunctionKind, 10, _) \ V(HasDuplicateParametersBit, bool, 1, _) \ V(AllowLazyCompilationBit, bool, 1, _) \ - V(OptimizationDisabledBit, bool, 1, _) \ V(UsesArgumentsBit, bool, 1, _) \ V(NeedsHomeObjectBit, bool, 1, _) \ V(ForceInlineBit, bool, 1, _) \ - V(IsAsmFunctionBit, bool, 1, _) \ V(IsDeclarationBit, bool, 1, _) \ V(IsAsmWasmBrokenBit, bool, 1, _) \ V(FunctionMapIndexBits, int, 5, _) \ - /* Bits 26-31 are unused. */ + V(DisabledOptimizationReasonBits, BailoutReason, 7, _) DEFINE_BIT_FIELDS(COMPILER_HINTS_BIT_FIELDS) #undef COMPILER_HINTS_BIT_FIELDS + // Bailout reasons must fit in the DisabledOptimizationReason bitfield. + STATIC_ASSERT(kLastErrorMessage <= DisabledOptimizationReasonBits::kMax); + // Masks for checking if certain FunctionKind bits are set without fully // decoding of the FunctionKind bit field. static const int kClassConstructorMask = FunctionKind::kClassConstructor @@ -530,23 +497,6 @@ class SharedFunctionInfo : public HeapObject { DEFINE_BIT_FIELDS(DEBUGGER_HINTS_BIT_FIELDS) #undef DEBUGGER_HINTS_BIT_FIELDS -// Bit fields in |counters|. -#define COUNTERS_BIT_FIELDS(V, _) \ - V(DeoptCountBits, int, 4, _) \ - V(OptReenableTriesBits, int, 18, _) \ - V(ICAgeBits, int, 8, _) - - DEFINE_BIT_FIELDS(COUNTERS_BIT_FIELDS) -#undef COUNTERS_BIT_FIELDS - -// Bit fields in |opt_count_and_bailout_reason|. -#define OPT_COUNT_AND_BAILOUT_REASON_BIT_FIELDS(V, _) \ - V(OptCountBits, int, 22, _) \ - V(DisabledOptimizationReasonBits, BailoutReason, 8, _) - - DEFINE_BIT_FIELDS(OPT_COUNT_AND_BAILOUT_REASON_BIT_FIELDS) -#undef OPT_COUNT_AND_BAILOUT_REASON_BIT_FIELDS - private: // [raw_name]: Function name string or kNoSharedNameSentinel. DECL_ACCESSORS(raw_name, Object) diff --git a/deps/v8/src/objects/string-inl.h b/deps/v8/src/objects/string-inl.h index c83ecffa46..a30b65da95 100644 --- a/deps/v8/src/objects/string-inl.h +++ b/deps/v8/src/objects/string-inl.h @@ -8,6 +8,7 @@ #include "src/objects/string.h" #include "src/conversions-inl.h" +#include "src/factory.h" #include "src/objects/name-inl.h" #include "src/string-hasher-inl.h" @@ -514,7 +515,7 @@ String* ConsString::second() { } Object* ConsString::unchecked_second() { - return READ_FIELD(this, kSecondOffset); + return RELAXED_READ_FIELD(this, kSecondOffset); } void ConsString::set_second(String* value, WriteBarrierMode mode) { diff --git a/deps/v8/src/objects/string.h b/deps/v8/src/objects/string.h index 04dbe9bbb7..1a9baa61b7 100644 --- a/deps/v8/src/objects/string.h +++ b/deps/v8/src/objects/string.h @@ -345,7 +345,14 @@ class String : public Name { static const uc32 kMaxCodePoint = 0x10ffff; // Maximal string length. - static const int kMaxLength = (1 << 28) - 16; + // The max length is different on 32 and 64 bit platforms. Max length for a + // 32-bit platform is ~268.4M chars. On 64-bit platforms, max length is + // ~1.073B chars. The limit on 64-bit is so that SeqTwoByteString::kMaxSize + // can fit in a 32bit int: 2^31 - 1 is the max positive int, minus one bit as + // each char needs two bytes, subtract 24 bytes for the string header size. + + // See include/v8.h for the definition. + static const int kMaxLength = v8::String::kMaxLength; // Max length for computing hash. For strings longer than this limit the // string length is used as the hash value. @@ -489,6 +496,10 @@ class SeqOneByteString : public SeqString { inline uint8_t* GetChars(); + // Clear uninitialized padding space. This ensures that the snapshot content + // is deterministic. + void clear_padding(); + DECL_CAST(SeqOneByteString) // Garbage collection support. This method is called by the @@ -502,7 +513,7 @@ class SeqOneByteString : public SeqString { } // Maximal memory usage for a single sequential one-byte string. - static const int kMaxSize = 512 * MB - 1; + static const int kMaxSize = OBJECT_POINTER_ALIGN(kMaxLength + kHeaderSize); STATIC_ASSERT((kMaxSize - kHeaderSize) >= String::kMaxLength); class BodyDescriptor; @@ -528,6 +539,10 @@ class SeqTwoByteString : public SeqString { inline uc16* GetChars(); + // Clear uninitialized padding space. This ensures that the snapshot content + // is deterministic. + void clear_padding(); + // For regexp code. const uint16_t* SeqTwoByteStringGetData(unsigned start); @@ -544,7 +559,8 @@ class SeqTwoByteString : public SeqString { } // Maximal memory usage for a single sequential two-byte string. - static const int kMaxSize = 512 * MB - 1; + static const int kMaxSize = + OBJECT_POINTER_ALIGN(kMaxLength * 2 + kHeaderSize); STATIC_ASSERT(static_cast<int>((kMaxSize - kHeaderSize) / sizeof(uint16_t)) >= String::kMaxLength); |