summaryrefslogtreecommitdiff
path: root/deps/v8/src/objects
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/objects')
-rw-r--r--deps/v8/src/objects/allocation-site-inl.h197
-rw-r--r--deps/v8/src/objects/allocation-site.h186
-rw-r--r--deps/v8/src/objects/api-callbacks-inl.h18
-rw-r--r--deps/v8/src/objects/api-callbacks.h23
-rw-r--r--deps/v8/src/objects/arguments-inl.h3
-rw-r--r--deps/v8/src/objects/arguments.h28
-rw-r--r--deps/v8/src/objects/bigint.cc42
-rw-r--r--deps/v8/src/objects/bigint.h3
-rw-r--r--deps/v8/src/objects/builtin-function-id.h217
-rw-r--r--deps/v8/src/objects/code-inl.h10
-rw-r--r--deps/v8/src/objects/code.h48
-rw-r--r--deps/v8/src/objects/compilation-cache.h11
-rw-r--r--deps/v8/src/objects/debug-objects.cc2
-rw-r--r--deps/v8/src/objects/debug-objects.h3
-rw-r--r--deps/v8/src/objects/dictionary.h12
-rw-r--r--deps/v8/src/objects/fixed-array-inl.h4
-rw-r--r--deps/v8/src/objects/fixed-array.h15
-rw-r--r--deps/v8/src/objects/frame-array.h3
-rw-r--r--deps/v8/src/objects/hash-table-inl.h8
-rw-r--r--deps/v8/src/objects/hash-table.h6
-rw-r--r--deps/v8/src/objects/intl-objects.cc1543
-rw-r--r--deps/v8/src/objects/intl-objects.h276
-rw-r--r--deps/v8/src/objects/js-array-buffer-inl.h88
-rw-r--r--deps/v8/src/objects/js-array-buffer.cc45
-rw-r--r--deps/v8/src/objects/js-array-buffer.h106
-rw-r--r--deps/v8/src/objects/js-array.h3
-rw-r--r--deps/v8/src/objects/js-break-iterator-inl.h49
-rw-r--r--deps/v8/src/objects/js-break-iterator.cc170
-rw-r--r--deps/v8/src/objects/js-break-iterator.h87
-rw-r--r--deps/v8/src/objects/js-collator-inl.h12
-rw-r--r--deps/v8/src/objects/js-collator.cc212
-rw-r--r--deps/v8/src/objects/js-collator.h37
-rw-r--r--deps/v8/src/objects/js-collection.h3
-rw-r--r--deps/v8/src/objects/js-date-time-format-inl.h33
-rw-r--r--deps/v8/src/objects/js-date-time-format.cc980
-rw-r--r--deps/v8/src/objects/js-date-time-format.h100
-rw-r--r--deps/v8/src/objects/js-generator.h2
-rw-r--r--deps/v8/src/objects/js-list-format-inl.h3
-rw-r--r--deps/v8/src/objects/js-list-format.cc12
-rw-r--r--deps/v8/src/objects/js-list-format.h13
-rw-r--r--deps/v8/src/objects/js-locale-inl.h37
-rw-r--r--deps/v8/src/objects/js-locale.cc170
-rw-r--r--deps/v8/src/objects/js-locale.h80
-rw-r--r--deps/v8/src/objects/js-number-format-inl.h58
-rw-r--r--deps/v8/src/objects/js-number-format.cc709
-rw-r--r--deps/v8/src/objects/js-number-format.h135
-rw-r--r--deps/v8/src/objects/js-objects-inl.h904
-rw-r--r--deps/v8/src/objects/js-objects.h1408
-rw-r--r--deps/v8/src/objects/js-plural-rules.cc7
-rw-r--r--deps/v8/src/objects/js-plural-rules.h9
-rw-r--r--deps/v8/src/objects/js-promise.h2
-rw-r--r--deps/v8/src/objects/js-proxy.h4
-rw-r--r--deps/v8/src/objects/js-regexp-string-iterator.h2
-rw-r--r--deps/v8/src/objects/js-relative-time-format-inl.h3
-rw-r--r--deps/v8/src/objects/js-relative-time-format.cc220
-rw-r--r--deps/v8/src/objects/js-relative-time-format.h21
-rw-r--r--deps/v8/src/objects/js-segmenter-inl.h56
-rw-r--r--deps/v8/src/objects/js-segmenter.cc214
-rw-r--r--deps/v8/src/objects/js-segmenter.h118
-rw-r--r--deps/v8/src/objects/map-inl.h51
-rw-r--r--deps/v8/src/objects/map.h36
-rw-r--r--deps/v8/src/objects/maybe-object-inl.h54
-rw-r--r--deps/v8/src/objects/maybe-object.h56
-rw-r--r--deps/v8/src/objects/microtask-queue-inl.h28
-rw-r--r--deps/v8/src/objects/microtask-queue.cc40
-rw-r--r--deps/v8/src/objects/microtask-queue.h55
-rw-r--r--deps/v8/src/objects/module.cc12
-rw-r--r--deps/v8/src/objects/module.h7
-rw-r--r--deps/v8/src/objects/name-inl.h26
-rw-r--r--deps/v8/src/objects/name.h39
-rw-r--r--deps/v8/src/objects/object-macros-undef.h2
-rw-r--r--deps/v8/src/objects/object-macros.h6
-rw-r--r--deps/v8/src/objects/ordered-hash-table-inl.h16
-rw-r--r--deps/v8/src/objects/ordered-hash-table.cc2
-rw-r--r--deps/v8/src/objects/ordered-hash-table.h12
-rw-r--r--deps/v8/src/objects/promise.h2
-rw-r--r--deps/v8/src/objects/property-array-inl.h83
-rw-r--r--deps/v8/src/objects/property-array.h73
-rw-r--r--deps/v8/src/objects/prototype-info-inl.h6
-rw-r--r--deps/v8/src/objects/scope-info.cc1
-rw-r--r--deps/v8/src/objects/scope-info.h3
-rw-r--r--deps/v8/src/objects/script.h3
-rw-r--r--deps/v8/src/objects/shared-function-info-inl.h69
-rw-r--r--deps/v8/src/objects/shared-function-info.h20
-rw-r--r--deps/v8/src/objects/stack-frame-info-inl.h38
-rw-r--r--deps/v8/src/objects/stack-frame-info.h62
-rw-r--r--deps/v8/src/objects/string-inl.h26
-rw-r--r--deps/v8/src/objects/string-table.h2
-rw-r--r--deps/v8/src/objects/string.h55
-rw-r--r--deps/v8/src/objects/templates.h3
90 files changed, 7311 insertions, 2347 deletions
diff --git a/deps/v8/src/objects/allocation-site-inl.h b/deps/v8/src/objects/allocation-site-inl.h
new file mode 100644
index 0000000000..2ed280c054
--- /dev/null
+++ b/deps/v8/src/objects/allocation-site-inl.h
@@ -0,0 +1,197 @@
+// Copyright 2018 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_ALLOCATION_SITE_INL_H_
+#define V8_OBJECTS_ALLOCATION_SITE_INL_H_
+
+#include "src/objects/allocation-site.h"
+
+#include "src/heap/heap-inl.h"
+#include "src/objects/js-objects-inl.h"
+
+// Has to be the last include (doesn't have include guards):
+#include "src/objects/object-macros.h"
+
+namespace v8 {
+namespace internal {
+
+CAST_ACCESSOR(AllocationMemento)
+CAST_ACCESSOR(AllocationSite)
+
+ACCESSORS(AllocationSite, transition_info_or_boilerplate, Object,
+ kTransitionInfoOrBoilerplateOffset)
+ACCESSORS(AllocationSite, nested_site, Object, kNestedSiteOffset)
+INT32_ACCESSORS(AllocationSite, pretenure_data, kPretenureDataOffset)
+INT32_ACCESSORS(AllocationSite, pretenure_create_count,
+ kPretenureCreateCountOffset)
+ACCESSORS(AllocationSite, dependent_code, DependentCode, kDependentCodeOffset)
+ACCESSORS_CHECKED(AllocationSite, weak_next, Object, kWeakNextOffset,
+ HasWeakNext())
+ACCESSORS(AllocationMemento, allocation_site, Object, kAllocationSiteOffset)
+
+JSObject* AllocationSite::boilerplate() const {
+ DCHECK(PointsToLiteral());
+ return JSObject::cast(transition_info_or_boilerplate());
+}
+
+void AllocationSite::set_boilerplate(JSObject* object, WriteBarrierMode mode) {
+ set_transition_info_or_boilerplate(object, mode);
+}
+
+int AllocationSite::transition_info() const {
+ DCHECK(!PointsToLiteral());
+ return Smi::cast(transition_info_or_boilerplate())->value();
+}
+
+void AllocationSite::set_transition_info(int value) {
+ DCHECK(!PointsToLiteral());
+ set_transition_info_or_boilerplate(Smi::FromInt(value), SKIP_WRITE_BARRIER);
+}
+
+bool AllocationSite::HasWeakNext() const {
+ return map() == GetReadOnlyRoots().allocation_site_map();
+}
+
+void AllocationSite::Initialize() {
+ set_transition_info_or_boilerplate(Smi::kZero);
+ SetElementsKind(GetInitialFastElementsKind());
+ set_nested_site(Smi::kZero);
+ set_pretenure_data(0);
+ set_pretenure_create_count(0);
+ set_dependent_code(
+ DependentCode::cast(GetReadOnlyRoots().empty_weak_fixed_array()),
+ SKIP_WRITE_BARRIER);
+}
+
+bool AllocationSite::IsZombie() const {
+ return pretenure_decision() == kZombie;
+}
+
+bool AllocationSite::IsMaybeTenure() const {
+ return pretenure_decision() == kMaybeTenure;
+}
+
+bool AllocationSite::PretenuringDecisionMade() const {
+ return pretenure_decision() != kUndecided;
+}
+
+void AllocationSite::MarkZombie() {
+ DCHECK(!IsZombie());
+ Initialize();
+ set_pretenure_decision(kZombie);
+}
+
+ElementsKind AllocationSite::GetElementsKind() const {
+ return ElementsKindBits::decode(transition_info());
+}
+
+void AllocationSite::SetElementsKind(ElementsKind kind) {
+ set_transition_info(ElementsKindBits::update(transition_info(), kind));
+}
+
+bool AllocationSite::CanInlineCall() const {
+ return DoNotInlineBit::decode(transition_info()) == 0;
+}
+
+void AllocationSite::SetDoNotInlineCall() {
+ set_transition_info(DoNotInlineBit::update(transition_info(), true));
+}
+
+bool AllocationSite::PointsToLiteral() const {
+ Object* raw_value = transition_info_or_boilerplate();
+ DCHECK_EQ(!raw_value->IsSmi(),
+ raw_value->IsJSArray() || raw_value->IsJSObject());
+ return !raw_value->IsSmi();
+}
+
+// Heuristic: We only need to create allocation site info if the boilerplate
+// elements kind is the initial elements kind.
+bool AllocationSite::ShouldTrack(ElementsKind boilerplate_elements_kind) {
+ return IsSmiElementsKind(boilerplate_elements_kind);
+}
+
+inline bool AllocationSite::CanTrack(InstanceType type) {
+ if (FLAG_allocation_site_pretenuring) {
+ // TurboFan doesn't care at all about String pretenuring feedback,
+ // so don't bother even trying to track that.
+ return type == JS_ARRAY_TYPE || type == JS_OBJECT_TYPE;
+ }
+ return type == JS_ARRAY_TYPE;
+}
+
+AllocationSite::PretenureDecision AllocationSite::pretenure_decision() const {
+ return PretenureDecisionBits::decode(pretenure_data());
+}
+
+void AllocationSite::set_pretenure_decision(PretenureDecision decision) {
+ int32_t value = pretenure_data();
+ set_pretenure_data(PretenureDecisionBits::update(value, decision));
+}
+
+bool AllocationSite::deopt_dependent_code() const {
+ return DeoptDependentCodeBit::decode(pretenure_data());
+}
+
+void AllocationSite::set_deopt_dependent_code(bool deopt) {
+ int32_t value = pretenure_data();
+ set_pretenure_data(DeoptDependentCodeBit::update(value, deopt));
+}
+
+int AllocationSite::memento_found_count() const {
+ return MementoFoundCountBits::decode(pretenure_data());
+}
+
+inline void AllocationSite::set_memento_found_count(int count) {
+ int32_t value = pretenure_data();
+ // Verify that we can count more mementos than we can possibly find in one
+ // new space collection.
+ DCHECK((GetHeap()->MaxSemiSpaceSize() /
+ (Heap::kMinObjectSizeInWords * kPointerSize +
+ AllocationMemento::kSize)) < MementoFoundCountBits::kMax);
+ DCHECK_LT(count, MementoFoundCountBits::kMax);
+ set_pretenure_data(MementoFoundCountBits::update(value, count));
+}
+
+int AllocationSite::memento_create_count() const {
+ return pretenure_create_count();
+}
+
+void AllocationSite::set_memento_create_count(int count) {
+ set_pretenure_create_count(count);
+}
+
+bool AllocationSite::IncrementMementoFoundCount(int increment) {
+ if (IsZombie()) return false;
+
+ int value = memento_found_count();
+ set_memento_found_count(value + increment);
+ return memento_found_count() >= kPretenureMinimumCreated;
+}
+
+inline void AllocationSite::IncrementMementoCreateCount() {
+ DCHECK(FLAG_allocation_site_pretenuring);
+ int value = memento_create_count();
+ set_memento_create_count(value + 1);
+}
+
+bool AllocationMemento::IsValid() const {
+ return allocation_site()->IsAllocationSite() &&
+ !AllocationSite::cast(allocation_site())->IsZombie();
+}
+
+AllocationSite* AllocationMemento::GetAllocationSite() const {
+ DCHECK(IsValid());
+ return AllocationSite::cast(allocation_site());
+}
+
+Address AllocationMemento::GetAllocationSiteUnchecked() const {
+ return reinterpret_cast<Address>(allocation_site());
+}
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_ALLOCATION_SITE_INL_H_
diff --git a/deps/v8/src/objects/allocation-site.h b/deps/v8/src/objects/allocation-site.h
new file mode 100644
index 0000000000..d923fd8f23
--- /dev/null
+++ b/deps/v8/src/objects/allocation-site.h
@@ -0,0 +1,186 @@
+// Copyright 2018 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_ALLOCATION_SITE_H_
+#define V8_OBJECTS_ALLOCATION_SITE_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 {
+
+class AllocationSite : public Struct, public NeverReadOnlySpaceObject {
+ public:
+ static const uint32_t kMaximumArrayBytesToPretransition = 8 * 1024;
+ static const double kPretenureRatio;
+ static const int kPretenureMinimumCreated = 100;
+
+ // Values for pretenure decision field.
+ enum PretenureDecision {
+ kUndecided = 0,
+ kDontTenure = 1,
+ kMaybeTenure = 2,
+ kTenure = 3,
+ kZombie = 4,
+ kLastPretenureDecisionValue = kZombie
+ };
+
+ const char* PretenureDecisionName(PretenureDecision decision);
+
+ // Contains either a Smi-encoded bitfield or a boilerplate. If it's a Smi the
+ // AllocationSite is for a constructed Array.
+ DECL_ACCESSORS(transition_info_or_boilerplate, Object)
+ DECL_ACCESSORS(boilerplate, JSObject)
+ DECL_INT_ACCESSORS(transition_info)
+
+ // nested_site threads a list of sites that represent nested literals
+ // walked in a particular order. So [[1, 2], 1, 2] will have one
+ // nested_site, but [[1, 2], 3, [4]] will have a list of two.
+ DECL_ACCESSORS(nested_site, Object)
+
+ // Bitfield containing pretenuring information.
+ DECL_INT32_ACCESSORS(pretenure_data)
+
+ DECL_INT32_ACCESSORS(pretenure_create_count)
+ DECL_ACCESSORS(dependent_code, DependentCode)
+
+ // heap->allocation_site_list() points to the last AllocationSite which form
+ // a linked list through the weak_next property. The GC might remove elements
+ // from the list by updateing weak_next.
+ DECL_ACCESSORS(weak_next, Object)
+
+ inline void Initialize();
+
+ // Checks if the allocation site contain weak_next field;
+ inline bool HasWeakNext() const;
+
+ // This method is expensive, it should only be called for reporting.
+ bool IsNested();
+
+ // transition_info bitfields, for constructed array transition info.
+ class ElementsKindBits : public BitField<ElementsKind, 0, 5> {};
+ class DoNotInlineBit : public BitField<bool, 5, 1> {};
+ // Unused bits 6-30.
+
+ // Bitfields for pretenure_data
+ class MementoFoundCountBits : public BitField<int, 0, 26> {};
+ class PretenureDecisionBits : public BitField<PretenureDecision, 26, 3> {};
+ class DeoptDependentCodeBit : public BitField<bool, 29, 1> {};
+ STATIC_ASSERT(PretenureDecisionBits::kMax >= kLastPretenureDecisionValue);
+
+ // Increments the mementos found counter and returns true when the first
+ // memento was found for a given allocation site.
+ inline bool IncrementMementoFoundCount(int increment = 1);
+
+ inline void IncrementMementoCreateCount();
+
+ PretenureFlag GetPretenureMode() const;
+
+ void ResetPretenureDecision();
+
+ inline PretenureDecision pretenure_decision() const;
+ inline void set_pretenure_decision(PretenureDecision decision);
+
+ inline bool deopt_dependent_code() const;
+ inline void set_deopt_dependent_code(bool deopt);
+
+ inline int memento_found_count() const;
+ inline void set_memento_found_count(int count);
+
+ inline int memento_create_count() const;
+ inline void set_memento_create_count(int count);
+
+ // The pretenuring decision is made during gc, and the zombie state allows
+ // us to recognize when an allocation site is just being kept alive because
+ // a later traversal of new space may discover AllocationMementos that point
+ // to this AllocationSite.
+ inline bool IsZombie() const;
+
+ inline bool IsMaybeTenure() const;
+
+ inline void MarkZombie();
+
+ inline bool MakePretenureDecision(PretenureDecision current_decision,
+ double ratio, bool maximum_size_scavenge);
+
+ inline bool DigestPretenuringFeedback(bool maximum_size_scavenge);
+
+ inline ElementsKind GetElementsKind() const;
+ inline void SetElementsKind(ElementsKind kind);
+
+ inline bool CanInlineCall() const;
+ inline void SetDoNotInlineCall();
+
+ inline bool PointsToLiteral() const;
+
+ template <AllocationSiteUpdateMode update_or_check =
+ AllocationSiteUpdateMode::kUpdate>
+ static bool DigestTransitionFeedback(Handle<AllocationSite> site,
+ ElementsKind to_kind);
+
+ DECL_PRINTER(AllocationSite)
+ DECL_VERIFIER(AllocationSite)
+
+ DECL_CAST(AllocationSite)
+ static inline bool ShouldTrack(ElementsKind boilerplate_elements_kind);
+ static bool ShouldTrack(ElementsKind from, ElementsKind to);
+ static inline bool CanTrack(InstanceType type);
+
+// Layout description.
+// AllocationSite has to start with TransitionInfoOrboilerPlateOffset
+// and end with WeakNext field.
+#define ALLOCATION_SITE_FIELDS(V) \
+ V(kTransitionInfoOrBoilerplateOffset, kPointerSize) \
+ V(kNestedSiteOffset, kPointerSize) \
+ V(kDependentCodeOffset, kPointerSize) \
+ V(kCommonPointerFieldEndOffset, 0) \
+ V(kPretenureDataOffset, kInt32Size) \
+ V(kPretenureCreateCountOffset, kInt32Size) \
+ /* Size of AllocationSite without WeakNext field */ \
+ V(kSizeWithoutWeakNext, 0) \
+ V(kWeakNextOffset, kPointerSize) \
+ /* Size of AllocationSite with WeakNext field */ \
+ V(kSizeWithWeakNext, 0)
+
+ DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, ALLOCATION_SITE_FIELDS)
+
+ static const int kStartOffset = HeapObject::kHeaderSize;
+
+ class BodyDescriptor;
+
+ private:
+ inline bool PretenuringDecisionMade() const;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(AllocationSite);
+};
+
+class AllocationMemento : public Struct {
+ public:
+ static const int kAllocationSiteOffset = HeapObject::kHeaderSize;
+ static const int kSize = kAllocationSiteOffset + kPointerSize;
+
+ DECL_ACCESSORS(allocation_site, Object)
+
+ inline bool IsValid() const;
+ inline AllocationSite* GetAllocationSite() const;
+ inline Address GetAllocationSiteUnchecked() const;
+
+ DECL_PRINTER(AllocationMemento)
+ DECL_VERIFIER(AllocationMemento)
+
+ DECL_CAST(AllocationMemento)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(AllocationMemento);
+};
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_ALLOCATION_SITE_H_
diff --git a/deps/v8/src/objects/api-callbacks-inl.h b/deps/v8/src/objects/api-callbacks-inl.h
index 4f7680d8ed..b8ca8bef20 100644
--- a/deps/v8/src/objects/api-callbacks-inl.h
+++ b/deps/v8/src/objects/api-callbacks-inl.h
@@ -59,8 +59,22 @@ BIT_FIELD_ACCESSORS(AccessorInfo, flags, is_special_data_property,
BIT_FIELD_ACCESSORS(AccessorInfo, flags, replace_on_access,
AccessorInfo::ReplaceOnAccessBit)
BIT_FIELD_ACCESSORS(AccessorInfo, flags, is_sloppy, AccessorInfo::IsSloppyBit)
-BIT_FIELD_ACCESSORS(AccessorInfo, flags, has_no_side_effect,
- AccessorInfo::HasNoSideEffectBit)
+BIT_FIELD_ACCESSORS(AccessorInfo, flags, getter_side_effect_type,
+ AccessorInfo::GetterSideEffectTypeBits)
+
+SideEffectType AccessorInfo::setter_side_effect_type() const {
+ return SetterSideEffectTypeBits::decode(flags());
+}
+
+void AccessorInfo::set_setter_side_effect_type(SideEffectType value) {
+ // We do not support describing setters as having no side effect, since
+ // calling set accessors must go through a store bytecode. Store bytecodes
+ // support checking receivers for temporary objects, but still expect
+ // the receiver to be written to.
+ CHECK_NE(value, SideEffectType::kHasNoSideEffect);
+ set_flags(SetterSideEffectTypeBits::update(flags(), value));
+}
+
BIT_FIELD_ACCESSORS(AccessorInfo, flags, initial_property_attributes,
AccessorInfo::InitialAttributesBits)
diff --git a/deps/v8/src/objects/api-callbacks.h b/deps/v8/src/objects/api-callbacks.h
index 6f3629a2c3..f7522da8a7 100644
--- a/deps/v8/src/objects/api-callbacks.h
+++ b/deps/v8/src/objects/api-callbacks.h
@@ -48,7 +48,12 @@ class AccessorInfo : public Struct {
DECL_BOOLEAN_ACCESSORS(is_special_data_property)
DECL_BOOLEAN_ACCESSORS(replace_on_access)
DECL_BOOLEAN_ACCESSORS(is_sloppy)
- DECL_BOOLEAN_ACCESSORS(has_no_side_effect)
+
+ inline SideEffectType getter_side_effect_type() const;
+ inline void set_getter_side_effect_type(SideEffectType type);
+
+ inline SideEffectType setter_side_effect_type() const;
+ inline void set_setter_side_effect_type(SideEffectType type);
// The property attributes used when an API object template is instantiated
// for the first time. Changing of this value afterwards does not affect
@@ -89,13 +94,15 @@ class AccessorInfo : public Struct {
inline bool HasExpectedReceiverType();
// Bit positions in |flags|.
-#define ACCESSOR_INFO_FLAGS_BIT_FIELDS(V, _) \
- V(AllCanReadBit, bool, 1, _) \
- V(AllCanWriteBit, bool, 1, _) \
- V(IsSpecialDataPropertyBit, bool, 1, _) \
- V(IsSloppyBit, bool, 1, _) \
- V(ReplaceOnAccessBit, bool, 1, _) \
- V(HasNoSideEffectBit, bool, 1, _) \
+#define ACCESSOR_INFO_FLAGS_BIT_FIELDS(V, _) \
+ V(AllCanReadBit, bool, 1, _) \
+ V(AllCanWriteBit, bool, 1, _) \
+ V(IsSpecialDataPropertyBit, bool, 1, _) \
+ V(IsSloppyBit, bool, 1, _) \
+ V(ReplaceOnAccessBit, bool, 1, _) \
+ V(GetterSideEffectTypeBits, SideEffectType, 2, _) \
+ /* We could save a bit from setter side-effect type, if necessary */ \
+ V(SetterSideEffectTypeBits, SideEffectType, 2, _) \
V(InitialAttributesBits, PropertyAttributes, 3, _)
DEFINE_BIT_FIELDS(ACCESSOR_INFO_FLAGS_BIT_FIELDS)
diff --git a/deps/v8/src/objects/arguments-inl.h b/deps/v8/src/objects/arguments-inl.h
index 7d92ce0496..222ca7954e 100644
--- a/deps/v8/src/objects/arguments-inl.h
+++ b/deps/v8/src/objects/arguments-inl.h
@@ -63,7 +63,8 @@ bool JSSloppyArgumentsObject::GetSloppyArgumentsLength(Isolate* isolate,
return false;
}
DCHECK(object->HasFastElements() || object->HasFastArgumentsElements());
- Object* len_obj = object->InObjectPropertyAt(JSArgumentsObject::kLengthIndex);
+ Object* len_obj =
+ object->InObjectPropertyAt(JSArgumentsObjectWithLength::kLengthIndex);
if (!len_obj->IsSmi()) return false;
*out = Max(0, Smi::ToInt(len_obj));
diff --git a/deps/v8/src/objects/arguments.h b/deps/v8/src/objects/arguments.h
index 36c6204d1a..15f3d2a2f5 100644
--- a/deps/v8/src/objects/arguments.h
+++ b/deps/v8/src/objects/arguments.h
@@ -5,8 +5,8 @@
#ifndef V8_OBJECTS_ARGUMENTS_H_
#define V8_OBJECTS_ARGUMENTS_H_
-#include "src/objects.h"
#include "src/objects/fixed-array.h"
+#include "src/objects/js-objects.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
@@ -14,11 +14,21 @@
namespace v8 {
namespace internal {
+// Superclass for all objects with instance type {JS_ARGUMENTS_TYPE}
+class JSArgumentsObject : public JSObject {
+ public:
+ DECL_VERIFIER(JSArgumentsObject)
+ DECL_CAST(JSArgumentsObject)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSArgumentsObject);
+};
+
// 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 {
+class JSArgumentsObjectWithLength : public JSArgumentsObject {
public:
// Offsets of object fields.
static const int kLengthOffset = JSObject::kHeaderSize;
@@ -26,19 +36,19 @@ class JSArgumentsObject : public JSObject {
// Indices of in-object properties.
static const int kLengthIndex = 0;
- DECL_VERIFIER(JSArgumentsObject)
- DECL_CAST(JSArgumentsObject)
+ DECL_VERIFIER(JSArgumentsObjectWithLength)
+ DECL_CAST(JSArgumentsObjectWithLength)
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(JSArgumentsObject);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSArgumentsObjectWithLength);
};
// JSSloppyArgumentsObject is just a JSObject with specific initial map.
// This initial map adds in-object properties for "length" and "callee".
-class JSSloppyArgumentsObject : public JSArgumentsObject {
+class JSSloppyArgumentsObject : public JSArgumentsObjectWithLength {
public:
// Offsets of object fields.
- static const int kCalleeOffset = JSArgumentsObject::kSize;
+ static const int kCalleeOffset = JSArgumentsObjectWithLength::kSize;
static const int kSize = kCalleeOffset + kPointerSize;
// Indices of in-object properties.
static const int kCalleeIndex = kLengthIndex + 1;
@@ -53,10 +63,10 @@ class JSSloppyArgumentsObject : public JSArgumentsObject {
// JSStrictArgumentsObject is just a JSObject with specific initial map.
// This initial map adds an in-object property for "length".
-class JSStrictArgumentsObject : public JSArgumentsObject {
+class JSStrictArgumentsObject : public JSArgumentsObjectWithLength {
public:
// Offsets of object fields.
- static const int kSize = JSArgumentsObject::kSize;
+ static const int kSize = JSArgumentsObjectWithLength::kSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSStrictArgumentsObject);
diff --git a/deps/v8/src/objects/bigint.cc b/deps/v8/src/objects/bigint.cc
index 458aa7c1eb..dcf99e2f29 100644
--- a/deps/v8/src/objects/bigint.cc
+++ b/deps/v8/src/objects/bigint.cc
@@ -36,9 +36,6 @@ namespace internal {
class MutableBigInt : public FreshlyAllocatedBigInt,
public NeverReadOnlySpaceObject {
public:
- using NeverReadOnlySpaceObject::GetHeap;
- using NeverReadOnlySpaceObject::GetIsolate;
-
// Bottleneck for converting MutableBigInts to BigInts.
static MaybeHandle<BigInt> MakeImmutable(MaybeHandle<MutableBigInt> maybe);
static Handle<BigInt> MakeImmutable(Handle<MutableBigInt> result);
@@ -96,7 +93,8 @@ class MutableBigInt : public FreshlyAllocatedBigInt,
static inline Handle<MutableBigInt> AbsoluteBitwiseOp(
Isolate* isolate, Handle<BigIntBase> x, Handle<BigIntBase> y,
MutableBigInt* result_storage, ExtraDigitsHandling extra_digits,
- SymmetricOp symmetric, std::function<digit_t(digit_t, digit_t)> op);
+ SymmetricOp symmetric,
+ const std::function<digit_t(digit_t, digit_t)>& op);
static Handle<MutableBigInt> AbsoluteAnd(
Isolate* isolate, Handle<BigIntBase> x, Handle<BigIntBase> y,
MutableBigInt* result_storage = nullptr);
@@ -155,9 +153,11 @@ class MutableBigInt : public FreshlyAllocatedBigInt,
static MaybeHandle<String> ToStringBasePowerOfTwo(Isolate* isolate,
Handle<BigIntBase> x,
- int radix);
+ int radix,
+ ShouldThrow should_throw);
static MaybeHandle<String> ToStringGeneric(Isolate* isolate,
- Handle<BigIntBase> x, int radix);
+ Handle<BigIntBase> x, int radix,
+ ShouldThrow should_throw);
static double ToDouble(Handle<BigIntBase> x);
enum Rounding { kRoundDown, kTie, kRoundUp };
@@ -924,14 +924,15 @@ ComparisonResult BigInt::CompareToDouble(Handle<BigInt> x, double y) {
}
MaybeHandle<String> BigInt::ToString(Isolate* isolate, Handle<BigInt> bigint,
- int radix) {
+ int radix, ShouldThrow should_throw) {
if (bigint->is_zero()) {
return isolate->factory()->NewStringFromStaticChars("0");
}
if (base::bits::IsPowerOfTwo(radix)) {
- return MutableBigInt::ToStringBasePowerOfTwo(isolate, bigint, radix);
+ return MutableBigInt::ToStringBasePowerOfTwo(isolate, bigint, radix,
+ should_throw);
}
- return MutableBigInt::ToStringGeneric(isolate, bigint, radix);
+ return MutableBigInt::ToStringGeneric(isolate, bigint, radix, should_throw);
}
MaybeHandle<BigInt> BigInt::FromNumber(Isolate* isolate,
@@ -1255,7 +1256,7 @@ MaybeHandle<MutableBigInt> MutableBigInt::AbsoluteSubOne(Isolate* isolate,
inline Handle<MutableBigInt> MutableBigInt::AbsoluteBitwiseOp(
Isolate* isolate, Handle<BigIntBase> x, Handle<BigIntBase> y,
MutableBigInt* result_storage, ExtraDigitsHandling extra_digits,
- SymmetricOp symmetric, std::function<digit_t(digit_t, digit_t)> op) {
+ SymmetricOp symmetric, const std::function<digit_t(digit_t, digit_t)>& op) {
int x_length = x->length();
int y_length = y->length();
int num_pairs = y_length;
@@ -1924,9 +1925,9 @@ MaybeHandle<BigInt> BigInt::FromSerializedDigits(
static const char kConversionChars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
-MaybeHandle<String> MutableBigInt::ToStringBasePowerOfTwo(Isolate* isolate,
- Handle<BigIntBase> x,
- int radix) {
+MaybeHandle<String> MutableBigInt::ToStringBasePowerOfTwo(
+ Isolate* isolate, Handle<BigIntBase> x, int radix,
+ ShouldThrow should_throw) {
STATIC_ASSERT(base::bits::IsPowerOfTwo(kDigitBits));
DCHECK(base::bits::IsPowerOfTwo(radix));
DCHECK(radix >= 2 && radix <= 32);
@@ -1945,7 +1946,11 @@ MaybeHandle<String> MutableBigInt::ToStringBasePowerOfTwo(Isolate* isolate,
(bit_length + bits_per_char - 1) / bits_per_char + sign;
if (chars_required > String::kMaxLength) {
- THROW_NEW_ERROR(isolate, NewInvalidStringLengthError(), String);
+ if (should_throw == kThrowOnError) {
+ THROW_NEW_ERROR(isolate, NewInvalidStringLengthError(), String);
+ } else {
+ return MaybeHandle<String>();
+ }
}
Handle<SeqOneByteString> result =
@@ -1988,7 +1993,8 @@ MaybeHandle<String> MutableBigInt::ToStringBasePowerOfTwo(Isolate* isolate,
MaybeHandle<String> MutableBigInt::ToStringGeneric(Isolate* isolate,
Handle<BigIntBase> x,
- int radix) {
+ int radix,
+ ShouldThrow should_throw) {
DCHECK(radix >= 2 && radix <= 36);
DCHECK(!x->is_zero());
Heap* heap = isolate->heap();
@@ -2014,7 +2020,11 @@ MaybeHandle<String> MutableBigInt::ToStringGeneric(Isolate* isolate,
chars_required += sign;
if (chars_required > String::kMaxLength) {
- THROW_NEW_ERROR(isolate, NewInvalidStringLengthError(), String);
+ if (should_throw == kThrowOnError) {
+ THROW_NEW_ERROR(isolate, NewInvalidStringLengthError(), String);
+ } else {
+ return MaybeHandle<String>();
+ }
}
Handle<SeqOneByteString> result =
isolate->factory()
diff --git a/deps/v8/src/objects/bigint.h b/deps/v8/src/objects/bigint.h
index a30a4779de..6081c5e3f8 100644
--- a/deps/v8/src/objects/bigint.h
+++ b/deps/v8/src/objects/bigint.h
@@ -173,7 +173,8 @@ class V8_EXPORT_PRIVATE BigInt : public BigIntBase {
}
static MaybeHandle<String> ToString(Isolate* isolate, Handle<BigInt> bigint,
- int radix = 10);
+ int radix = 10,
+ ShouldThrow should_throw = kThrowOnError);
// "The Number value for x", see:
// https://tc39.github.io/ecma262/#sec-ecmascript-language-types-number-type
// Returns a Smi or HeapNumber.
diff --git a/deps/v8/src/objects/builtin-function-id.h b/deps/v8/src/objects/builtin-function-id.h
new file mode 100644
index 0000000000..ed54811a2b
--- /dev/null
+++ b/deps/v8/src/objects/builtin-function-id.h
@@ -0,0 +1,217 @@
+// Copyright 2018 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_BUILTIN_FUNCTION_ID_H_
+#define V8_OBJECTS_BUILTIN_FUNCTION_ID_H_
+
+#include <stdint.h>
+
+namespace v8 {
+namespace internal {
+
+// List of builtin functions we want to identify to improve code
+// generation.
+//
+// Each entry has a name of a global object property holding an object
+// optionally followed by ".prototype", a name of a builtin function
+// on the object (the one the id is set for), and a label.
+//
+// Installation of ids for the selected builtin functions is handled
+// by the bootstrapper.
+#define FUNCTIONS_WITH_ID_LIST(V) \
+ V(Array, isArray, ArrayIsArray) \
+ V(Array.prototype, concat, ArrayConcat) \
+ V(Array.prototype, every, ArrayEvery) \
+ V(Array.prototype, fill, ArrayFill) \
+ V(Array.prototype, filter, ArrayFilter) \
+ V(Array.prototype, findIndex, ArrayFindIndex) \
+ V(Array.prototype, forEach, ArrayForEach) \
+ V(Array.prototype, includes, ArrayIncludes) \
+ V(Array.prototype, indexOf, ArrayIndexOf) \
+ V(Array.prototype, join, ArrayJoin) \
+ V(Array.prototype, lastIndexOf, ArrayLastIndexOf) \
+ V(Array.prototype, map, ArrayMap) \
+ V(Array.prototype, pop, ArrayPop) \
+ V(Array.prototype, push, ArrayPush) \
+ V(Array.prototype, reverse, ArrayReverse) \
+ V(Array.prototype, shift, ArrayShift) \
+ V(Array.prototype, slice, ArraySlice) \
+ V(Array.prototype, some, ArraySome) \
+ V(Array.prototype, splice, ArraySplice) \
+ V(Array.prototype, unshift, ArrayUnshift) \
+ V(Date, now, DateNow) \
+ V(Date.prototype, getDate, DateGetDate) \
+ V(Date.prototype, getDay, DateGetDay) \
+ V(Date.prototype, getFullYear, DateGetFullYear) \
+ V(Date.prototype, getHours, DateGetHours) \
+ V(Date.prototype, getMilliseconds, DateGetMilliseconds) \
+ V(Date.prototype, getMinutes, DateGetMinutes) \
+ V(Date.prototype, getMonth, DateGetMonth) \
+ V(Date.prototype, getSeconds, DateGetSeconds) \
+ V(Date.prototype, getTime, DateGetTime) \
+ V(Function.prototype, apply, FunctionApply) \
+ V(Function.prototype, bind, FunctionBind) \
+ V(Function.prototype, call, FunctionCall) \
+ V(Object, assign, ObjectAssign) \
+ V(Object, create, ObjectCreate) \
+ V(Object, is, ObjectIs) \
+ V(Object.prototype, hasOwnProperty, ObjectHasOwnProperty) \
+ V(Object.prototype, isPrototypeOf, ObjectIsPrototypeOf) \
+ V(Object.prototype, toString, ObjectToString) \
+ V(RegExp.prototype, compile, RegExpCompile) \
+ V(RegExp.prototype, exec, RegExpExec) \
+ V(RegExp.prototype, test, RegExpTest) \
+ V(RegExp.prototype, toString, RegExpToString) \
+ V(String.prototype, charCodeAt, StringCharCodeAt) \
+ V(String.prototype, charAt, StringCharAt) \
+ V(String.prototype, codePointAt, StringCodePointAt) \
+ V(String.prototype, concat, StringConcat) \
+ V(String.prototype, endsWith, StringEndsWith) \
+ V(String.prototype, includes, StringIncludes) \
+ V(String.prototype, indexOf, StringIndexOf) \
+ V(String.prototype, lastIndexOf, StringLastIndexOf) \
+ V(String.prototype, repeat, StringRepeat) \
+ V(String.prototype, slice, StringSlice) \
+ V(String.prototype, startsWith, StringStartsWith) \
+ V(String.prototype, substr, StringSubstr) \
+ V(String.prototype, substring, StringSubstring) \
+ V(String.prototype, toLowerCase, StringToLowerCase) \
+ V(String.prototype, toString, StringToString) \
+ V(String.prototype, toUpperCase, StringToUpperCase) \
+ V(String.prototype, trim, StringTrim) \
+ V(String.prototype, trimLeft, StringTrimStart) \
+ V(String.prototype, trimRight, StringTrimEnd) \
+ V(String.prototype, valueOf, StringValueOf) \
+ V(String, fromCharCode, StringFromCharCode) \
+ V(String, fromCodePoint, StringFromCodePoint) \
+ V(String, raw, StringRaw) \
+ V(Math, random, MathRandom) \
+ V(Math, floor, MathFloor) \
+ V(Math, round, MathRound) \
+ V(Math, ceil, MathCeil) \
+ V(Math, abs, MathAbs) \
+ V(Math, log, MathLog) \
+ V(Math, log1p, MathLog1p) \
+ V(Math, log2, MathLog2) \
+ V(Math, log10, MathLog10) \
+ V(Math, cbrt, MathCbrt) \
+ V(Math, exp, MathExp) \
+ V(Math, expm1, MathExpm1) \
+ V(Math, sqrt, MathSqrt) \
+ V(Math, pow, MathPow) \
+ V(Math, max, MathMax) \
+ V(Math, min, MathMin) \
+ V(Math, cos, MathCos) \
+ V(Math, cosh, MathCosh) \
+ V(Math, sign, MathSign) \
+ V(Math, sin, MathSin) \
+ V(Math, sinh, MathSinh) \
+ V(Math, tan, MathTan) \
+ V(Math, tanh, MathTanh) \
+ V(Math, acos, MathAcos) \
+ V(Math, acosh, MathAcosh) \
+ V(Math, asin, MathAsin) \
+ V(Math, asinh, MathAsinh) \
+ V(Math, atan, MathAtan) \
+ V(Math, atan2, MathAtan2) \
+ V(Math, atanh, MathAtanh) \
+ V(Math, imul, MathImul) \
+ V(Math, clz32, MathClz32) \
+ V(Math, fround, MathFround) \
+ V(Math, trunc, MathTrunc) \
+ V(Number, isFinite, NumberIsFinite) \
+ V(Number, isInteger, NumberIsInteger) \
+ V(Number, isNaN, NumberIsNaN) \
+ V(Number, isSafeInteger, NumberIsSafeInteger) \
+ V(Number, parseFloat, NumberParseFloat) \
+ V(Number, parseInt, NumberParseInt) \
+ V(Number.prototype, toString, NumberToString) \
+ V(Map.prototype, clear, MapClear) \
+ V(Map.prototype, delete, MapDelete) \
+ V(Map.prototype, entries, MapEntries) \
+ V(Map.prototype, forEach, MapForEach) \
+ V(Map.prototype, has, MapHas) \
+ V(Map.prototype, keys, MapKeys) \
+ V(Map.prototype, get, MapGet) \
+ V(Map.prototype, set, MapSet) \
+ V(Map.prototype, values, MapValues) \
+ V(Set.prototype, add, SetAdd) \
+ V(Set.prototype, clear, SetClear) \
+ V(Set.prototype, delete, SetDelete) \
+ V(Set.prototype, entries, SetEntries) \
+ V(Set.prototype, forEach, SetForEach) \
+ V(Set.prototype, has, SetHas) \
+ V(Set.prototype, values, SetValues) \
+ V(WeakMap.prototype, delete, WeakMapDelete) \
+ V(WeakMap.prototype, has, WeakMapHas) \
+ V(WeakMap.prototype, set, WeakMapSet) \
+ V(WeakSet.prototype, add, WeakSetAdd) \
+ V(WeakSet.prototype, delete, WeakSetDelete) \
+ V(WeakSet.prototype, has, WeakSetHas)
+
+#define ATOMIC_FUNCTIONS_WITH_ID_LIST(V) \
+ V(Atomics, load, AtomicsLoad) \
+ V(Atomics, store, AtomicsStore) \
+ V(Atomics, exchange, AtomicsExchange) \
+ V(Atomics, compareExchange, AtomicsCompareExchange) \
+ V(Atomics, add, AtomicsAdd) \
+ V(Atomics, sub, AtomicsSub) \
+ V(Atomics, and, AtomicsAnd) \
+ V(Atomics, or, AtomicsOr) \
+ V(Atomics, xor, AtomicsXor)
+
+enum class BuiltinFunctionId : uint8_t {
+ kArrayConstructor,
+#define DECL_FUNCTION_ID(ignored1, ignore2, name) k##name,
+ FUNCTIONS_WITH_ID_LIST(DECL_FUNCTION_ID)
+ ATOMIC_FUNCTIONS_WITH_ID_LIST(DECL_FUNCTION_ID)
+#undef DECL_FUNCTION_ID
+ // These are manually assigned to special getters during bootstrapping.
+ kArrayBufferByteLength,
+ kArrayBufferIsView,
+ kArrayEntries,
+ kArrayKeys,
+ kArrayValues,
+ kArrayIteratorNext,
+ kBigIntConstructor,
+ kMapSize,
+ kSetSize,
+ kMapIteratorNext,
+ kSetIteratorNext,
+ kDataViewBuffer,
+ kDataViewByteLength,
+ kDataViewByteOffset,
+ kFunctionHasInstance,
+ kGlobalDecodeURI,
+ kGlobalDecodeURIComponent,
+ kGlobalEncodeURI,
+ kGlobalEncodeURIComponent,
+ kGlobalEscape,
+ kGlobalUnescape,
+ kGlobalIsFinite,
+ kGlobalIsNaN,
+ kNumberConstructor,
+ kSymbolConstructor,
+ kSymbolPrototypeToString,
+ kSymbolPrototypeValueOf,
+ kTypedArrayByteLength,
+ kTypedArrayByteOffset,
+ kTypedArrayEntries,
+ kTypedArrayKeys,
+ kTypedArrayLength,
+ kTypedArrayToStringTag,
+ kTypedArrayValues,
+ kSharedArrayBufferByteLength,
+ kStringConstructor,
+ kStringIterator,
+ kStringIteratorNext,
+ kStringToLowerCaseIntl,
+ kStringToUpperCaseIntl,
+ kInvalidBuiltinFunctionId = static_cast<uint8_t>(-1),
+};
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_OBJECTS_BUILTIN_FUNCTION_ID_H_
diff --git a/deps/v8/src/objects/code-inl.h b/deps/v8/src/objects/code-inl.h
index 308e645c84..34c9f2fc28 100644
--- a/deps/v8/src/objects/code-inl.h
+++ b/deps/v8/src/objects/code-inl.h
@@ -26,6 +26,12 @@ CAST_ACCESSOR(Code)
CAST_ACCESSOR(CodeDataContainer)
CAST_ACCESSOR(DependentCode)
CAST_ACCESSOR(DeoptimizationData)
+CAST_ACCESSOR(SourcePositionTableWithFrameCache)
+
+ACCESSORS(SourcePositionTableWithFrameCache, source_position_table, ByteArray,
+ kSourcePositionTableIndex)
+ACCESSORS(SourcePositionTableWithFrameCache, stack_frame_cache,
+ SimpleNumberDictionary, kStackFrameCacheIndex)
int AbstractCode::raw_instruction_size() {
if (IsCode()) {
@@ -133,14 +139,14 @@ BytecodeArray* AbstractCode::GetBytecodeArray() {
}
DependentCode* DependentCode::next_link() {
- return DependentCode::cast(Get(kNextLinkIndex)->ToStrongHeapObject());
+ return DependentCode::cast(Get(kNextLinkIndex)->GetHeapObjectAssumeStrong());
}
void DependentCode::set_next_link(DependentCode* next) {
Set(kNextLinkIndex, HeapObjectReference::Strong(next));
}
-int DependentCode::flags() { return Smi::ToInt(Get(kFlagsIndex)->ToSmi()); }
+int DependentCode::flags() { return Smi::ToInt(Get(kFlagsIndex)->cast<Smi>()); }
void DependentCode::set_flags(int flags) {
Set(kFlagsIndex, MaybeObject::FromObject(Smi::FromInt(flags)));
diff --git a/deps/v8/src/objects/code.h b/deps/v8/src/objects/code.h
index f3c3c0b5b3..1f1d4b71d6 100644
--- a/deps/v8/src/objects/code.h
+++ b/deps/v8/src/objects/code.h
@@ -27,8 +27,6 @@ class Register;
// Code describes objects with on-the-fly generated machine code.
class Code : public HeapObject, public NeverReadOnlySpaceObject {
public:
- using NeverReadOnlySpaceObject::GetHeap;
- using NeverReadOnlySpaceObject::GetIsolate;
// Opaque data type for encapsulating code flags like kind, inline
// cache state, and arguments count.
typedef uint32_t Flags;
@@ -307,9 +305,6 @@ class Code : public HeapObject, public NeverReadOnlySpaceObject {
// object has been moved by delta bytes.
void Relocate(intptr_t delta);
- // Migrate code described by desc.
- void CopyFrom(Heap* heap, const CodeDesc& desc);
-
// Migrate code from desc without flushing the instruction cache.
void CopyFromNoFlush(Heap* heap, const CodeDesc& desc);
@@ -459,9 +454,6 @@ class Code : public HeapObject, public NeverReadOnlySpaceObject {
// field {Code::code_data_container} itself is immutable.
class CodeDataContainer : public HeapObject, public NeverReadOnlySpaceObject {
public:
- using NeverReadOnlySpaceObject::GetHeap;
- using NeverReadOnlySpaceObject::GetIsolate;
-
DECL_ACCESSORS(next_code_link, Object)
DECL_INT_ACCESSORS(kind_specific_flags)
@@ -485,15 +477,7 @@ class CodeDataContainer : public HeapObject, public NeverReadOnlySpaceObject {
static const int kPointerFieldsStrongEndOffset = kNextCodeLinkOffset;
static const int kPointerFieldsWeakEndOffset = kKindSpecificFlagsOffset;
- // Ignores weakness.
- typedef FixedBodyDescriptor<HeapObject::kHeaderSize,
- kPointerFieldsWeakEndOffset, kSize>
- BodyDescriptor;
-
- // Respects weakness.
- typedef FixedBodyDescriptor<HeapObject::kHeaderSize,
- kPointerFieldsStrongEndOffset, kSize>
- BodyDescriptorWeak;
+ class BodyDescriptor;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(CodeDataContainer);
@@ -501,9 +485,6 @@ class CodeDataContainer : public HeapObject, public NeverReadOnlySpaceObject {
class AbstractCode : public HeapObject, public NeverReadOnlySpaceObject {
public:
- using NeverReadOnlySpaceObject::GetHeap;
- using NeverReadOnlySpaceObject::GetIsolate;
-
// All code kinds and INTERPRETED_FUNCTION.
enum Kind {
#define DEFINE_CODE_KIND_ENUM(name) name,
@@ -624,13 +605,10 @@ class DependentCode : public WeakFixedArray {
};
// Register a code dependency of {cell} on {object}.
- static void InstallDependency(Isolate* isolate, MaybeObjectHandle code,
+ static void InstallDependency(Isolate* isolate, const MaybeObjectHandle& code,
Handle<HeapObject> object,
DependencyGroup group);
- bool Contains(DependencyGroup group, MaybeObject* code);
- bool IsEmpty(DependencyGroup group);
-
void DeoptimizeDependentCodeGroup(Isolate* isolate, DependencyGroup group);
bool MarkCodeForDeoptimization(Isolate* isolate, DependencyGroup group);
@@ -650,14 +628,14 @@ class DependentCode : public WeakFixedArray {
Handle<DependentCode> dep);
static Handle<DependentCode> New(Isolate* isolate, DependencyGroup group,
- MaybeObjectHandle object,
+ const MaybeObjectHandle& object,
Handle<DependentCode> next);
static Handle<DependentCode> EnsureSpace(Isolate* isolate,
Handle<DependentCode> entries);
static Handle<DependentCode> InsertWeakCode(Isolate* isolate,
Handle<DependentCode> entries,
DependencyGroup group,
- MaybeObjectHandle code);
+ const MaybeObjectHandle& code);
// Compact by removing cleared weak cells and return true if there was
// any cleared weak cell.
@@ -811,8 +789,6 @@ class BytecodeArray : public FixedArrayBase {
static const int kMaxLength = kMaxSize - kHeaderSize;
class BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BytecodeArray);
@@ -903,6 +879,22 @@ class DeoptimizationData : public FixedArray {
static int LengthFor(int entry_count) { return IndexForEntry(entry_count); }
};
+class SourcePositionTableWithFrameCache : public Tuple2 {
+ public:
+ DECL_ACCESSORS(source_position_table, ByteArray)
+ DECL_ACCESSORS(stack_frame_cache, SimpleNumberDictionary)
+
+ DECL_CAST(SourcePositionTableWithFrameCache)
+
+ static const int kSourcePositionTableIndex = Struct::kHeaderSize;
+ static const int kStackFrameCacheIndex =
+ kSourcePositionTableIndex + kPointerSize;
+ static const int kSize = kStackFrameCacheIndex + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(SourcePositionTableWithFrameCache);
+};
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/objects/compilation-cache.h b/deps/v8/src/objects/compilation-cache.h
index 76deeb9684..8e118a0e60 100644
--- a/deps/v8/src/objects/compilation-cache.h
+++ b/deps/v8/src/objects/compilation-cache.h
@@ -69,12 +69,6 @@ class CompilationCacheTable
: public HashTable<CompilationCacheTable, CompilationCacheShape>,
public NeverReadOnlySpaceObject {
public:
- using NeverReadOnlySpaceObject::GetHeap;
- using NeverReadOnlySpaceObject::GetIsolate;
-
- // Find cached value for a string key, otherwise return null.
- Handle<Object> Lookup(Handle<String> src, Handle<SharedFunctionInfo> shared,
- LanguageMode language_mode);
MaybeHandle<SharedFunctionInfo> LookupScript(Handle<String> src,
Handle<Context> native_context,
LanguageMode language_mode);
@@ -82,11 +76,6 @@ class CompilationCacheTable
Handle<Context> native_context,
LanguageMode language_mode, int position);
Handle<Object> LookupRegExp(Handle<String> source, JSRegExp::Flags flags);
- static Handle<CompilationCacheTable> Put(Handle<CompilationCacheTable> cache,
- Handle<String> src,
- Handle<SharedFunctionInfo> shared,
- LanguageMode language_mode,
- Handle<Object> value);
static Handle<CompilationCacheTable> PutScript(
Handle<CompilationCacheTable> cache, Handle<String> src,
Handle<Context> native_context, LanguageMode language_mode,
diff --git a/deps/v8/src/objects/debug-objects.cc b/deps/v8/src/objects/debug-objects.cc
index b77b6e136e..43fcdb5aee 100644
--- a/deps/v8/src/objects/debug-objects.cc
+++ b/deps/v8/src/objects/debug-objects.cc
@@ -375,7 +375,7 @@ void CoverageInfo::Print(std::unique_ptr<char[]> function_name) {
for (int i = 0; i < SlotCount(); i++) {
os << "{" << StartSourcePosition(i) << "," << EndSourcePosition(i) << "}"
- << std::endl;
+ << ": " << BlockCount(i) << std::endl;
}
}
diff --git a/deps/v8/src/objects/debug-objects.h b/deps/v8/src/objects/debug-objects.h
index 3b94a4e46e..84f244c758 100644
--- a/deps/v8/src/objects/debug-objects.h
+++ b/deps/v8/src/objects/debug-objects.h
@@ -21,9 +21,6 @@ class BytecodeArray;
// debugged.
class DebugInfo : public Struct, public NeverReadOnlySpaceObject {
public:
- using NeverReadOnlySpaceObject::GetHeap;
- using NeverReadOnlySpaceObject::GetIsolate;
-
enum Flag {
kNone = 0,
kHasBreakInfo = 1 << 0,
diff --git a/deps/v8/src/objects/dictionary.h b/deps/v8/src/objects/dictionary.h
index eac358c1cd..6d7ee42eec 100644
--- a/deps/v8/src/objects/dictionary.h
+++ b/deps/v8/src/objects/dictionary.h
@@ -5,10 +5,10 @@
#ifndef V8_OBJECTS_DICTIONARY_H_
#define V8_OBJECTS_DICTIONARY_H_
-#include "src/objects/hash-table.h"
-
#include "src/base/export-template.h"
#include "src/globals.h"
+#include "src/objects/hash-table.h"
+#include "src/objects/property-array.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
@@ -113,7 +113,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 inline int GetMapRootIndex();
+ static inline RootIndex GetMapRootIndex();
static const int kPrefixSize = 2;
static const int kEntrySize = 3;
static const int kEntryValueIndex = 1;
@@ -216,7 +216,7 @@ class GlobalDictionaryShape : public NameDictionaryShape {
static inline Object* Unwrap(Object* key);
static inline bool IsKey(ReadOnlyRoots roots, Object* k);
static inline bool IsLive(ReadOnlyRoots roots, Object* key);
- static inline int GetMapRootIndex();
+ static inline RootIndex GetMapRootIndex();
};
class GlobalDictionary
@@ -246,7 +246,7 @@ class NumberDictionaryShape : public NumberDictionaryBaseShape {
static const int kPrefixSize = 1;
static const int kEntrySize = 3;
- static inline int GetMapRootIndex();
+ static inline RootIndex GetMapRootIndex();
};
class SimpleNumberDictionaryShape : public NumberDictionaryBaseShape {
@@ -266,7 +266,7 @@ class SimpleNumberDictionaryShape : public NumberDictionaryBaseShape {
UNREACHABLE();
}
- static inline int GetMapRootIndex();
+ static inline RootIndex GetMapRootIndex();
};
extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
diff --git a/deps/v8/src/objects/fixed-array-inl.h b/deps/v8/src/objects/fixed-array-inl.h
index 29c4593cfd..8c24ee80be 100644
--- a/deps/v8/src/objects/fixed-array-inl.h
+++ b/deps/v8/src/objects/fixed-array-inl.h
@@ -288,8 +288,8 @@ HeapObject* WeakArrayList::Iterator::Next() {
if (array_ != nullptr) {
while (index_ < array_->length()) {
MaybeObject* item = array_->Get(index_++);
- DCHECK(item->IsWeakHeapObject() || item->IsClearedWeakHeapObject());
- if (!item->IsClearedWeakHeapObject()) return item->ToWeakHeapObject();
+ DCHECK(item->IsWeakOrCleared());
+ if (!item->IsCleared()) return item->GetHeapObjectAssumeWeak();
}
array_ = nullptr;
}
diff --git a/deps/v8/src/objects/fixed-array.h b/deps/v8/src/objects/fixed-array.h
index 287015ef7c..867d04e638 100644
--- a/deps/v8/src/objects/fixed-array.h
+++ b/deps/v8/src/objects/fixed-array.h
@@ -188,8 +188,6 @@ class FixedArray : public FixedArrayBase {
#endif
typedef FlexibleBodyDescriptor<kHeaderSize> BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
protected:
// Set operation on FixedArray without using write barriers. Can
@@ -256,8 +254,6 @@ class FixedDoubleArray : public FixedArrayBase {
DECL_VERIFIER(FixedDoubleArray)
class BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(FixedDoubleArray);
@@ -298,7 +294,6 @@ class WeakFixedArray : public HeapObject {
DECL_VERIFIER(WeakFixedArray)
typedef WeakArrayBodyDescriptor BodyDescriptor;
- typedef BodyDescriptor BodyDescriptorWeak;
static const int kLengthOffset = HeapObject::kHeaderSize;
static const int kHeaderSize = kLengthOffset + kPointerSize;
@@ -334,7 +329,7 @@ class WeakArrayList : public HeapObject {
static Handle<WeakArrayList> AddToEnd(Isolate* isolate,
Handle<WeakArrayList> array,
- MaybeObjectHandle value);
+ const MaybeObjectHandle& value);
inline MaybeObject* Get(int index) const;
@@ -361,7 +356,6 @@ class WeakArrayList : public HeapObject {
inline void synchronized_set_capacity(int value);
typedef WeakArrayBodyDescriptor BodyDescriptor;
- typedef BodyDescriptor BodyDescriptorWeak;
static const int kCapacityOffset = HeapObject::kHeaderSize;
static const int kLengthOffset = kCapacityOffset + kPointerSize;
@@ -381,7 +375,7 @@ class WeakArrayList : public HeapObject {
// around in the array - this method can only be used in cases where the user
// doesn't care about the indices! Users should make sure there are no
// duplicates.
- bool RemoveOne(MaybeObjectHandle value);
+ bool RemoveOne(const MaybeObjectHandle& value);
class Iterator {
public:
@@ -442,7 +436,6 @@ class ArrayList : public FixedArray {
// Return a copy of the list of size Length() without the first entry. The
// number returned by Length() is stored in the first entry.
static Handle<FixedArray> Elements(Isolate* isolate, Handle<ArrayList> array);
- bool IsFull();
DECL_CAST(ArrayList)
private:
@@ -521,8 +514,6 @@ class ByteArray : public FixedArrayBase {
"ByteArray maxLength not a Smi");
class BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ByteArray);
@@ -587,8 +578,6 @@ class FixedTypedArrayBase : public FixedArrayBase {
static const size_t kMaxLength = Smi::kMaxValue;
class BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
inline int size() const;
diff --git a/deps/v8/src/objects/frame-array.h b/deps/v8/src/objects/frame-array.h
index 0ae22f9526..5bccfb5807 100644
--- a/deps/v8/src/objects/frame-array.h
+++ b/deps/v8/src/objects/frame-array.h
@@ -50,7 +50,8 @@ class FrameArray : public FixedArray {
kIsAsmJsWasmFrame = 1 << 2,
kIsStrict = 1 << 3,
kIsConstructor = 1 << 4,
- kAsmJsAtNumberConversion = 1 << 5
+ kAsmJsAtNumberConversion = 1 << 5,
+ kIsAsync = 1 << 6
};
static Handle<FrameArray> AppendJSFrame(Handle<FrameArray> in,
diff --git a/deps/v8/src/objects/hash-table-inl.h b/deps/v8/src/objects/hash-table-inl.h
index 1f2c09316d..bc391fede6 100644
--- a/deps/v8/src/objects/hash-table-inl.h
+++ b/deps/v8/src/objects/hash-table-inl.h
@@ -58,12 +58,12 @@ void HashTableBase::SetNumberOfDeletedElements(int nod) {
}
template <typename Key>
-int BaseShape<Key>::GetMapRootIndex() {
- return Heap::kHashTableMapRootIndex;
+RootIndex BaseShape<Key>::GetMapRootIndex() {
+ return RootIndex::kHashTableMap;
}
-int EphemeronHashTableShape::GetMapRootIndex() {
- return Heap::kEphemeronHashTableMapRootIndex;
+RootIndex EphemeronHashTableShape::GetMapRootIndex() {
+ return RootIndex::kEphemeronHashTableMap;
}
template <typename Derived, typename Shape>
diff --git a/deps/v8/src/objects/hash-table.h b/deps/v8/src/objects/hash-table.h
index aa86865abf..66d3f6dfb2 100644
--- a/deps/v8/src/objects/hash-table.h
+++ b/deps/v8/src/objects/hash-table.h
@@ -55,7 +55,7 @@ template <typename KeyT>
class BaseShape {
public:
typedef KeyT Key;
- static inline int GetMapRootIndex();
+ static inline RootIndex GetMapRootIndex();
static const bool kNeedsHoleCheck = true;
static Object* Unwrap(Object* key) { return key; }
static inline bool IsKey(ReadOnlyRoots roots, Object* key);
@@ -244,7 +244,7 @@ class HashTableKey {
virtual bool IsMatch(Object* other) = 0;
// Returns the hash value for this key.
// Required.
- virtual ~HashTableKey() {}
+ virtual ~HashTableKey() = default;
uint32_t Hash() const { return hash_; }
@@ -321,7 +321,7 @@ class ObjectHashTable
class EphemeronHashTableShape : public ObjectHashTableShape {
public:
- static inline int GetMapRootIndex();
+ static inline RootIndex GetMapRootIndex();
};
// EphemeronHashTable is similar to ObjectHashTable but gets special treatment
diff --git a/deps/v8/src/objects/intl-objects.cc b/deps/v8/src/objects/intl-objects.cc
index b9ceecf9a1..dcacb4dd2f 100644
--- a/deps/v8/src/objects/intl-objects.cc
+++ b/deps/v8/src/objects/intl-objects.cc
@@ -21,543 +21,44 @@
#include "src/isolate.h"
#include "src/objects-inl.h"
#include "src/objects/js-collator-inl.h"
-#include "src/objects/managed.h"
+#include "src/objects/js-date-time-format-inl.h"
+#include "src/objects/js-number-format-inl.h"
#include "src/objects/string.h"
#include "src/property-descriptor.h"
#include "unicode/brkiter.h"
-#include "unicode/bytestream.h"
-#include "unicode/calendar.h"
#include "unicode/coll.h"
-#include "unicode/curramt.h"
-#include "unicode/dcfmtsym.h"
#include "unicode/decimfmt.h"
-#include "unicode/dtfmtsym.h"
-#include "unicode/dtptngen.h"
-#include "unicode/gregocal.h"
#include "unicode/locid.h"
#include "unicode/numfmt.h"
#include "unicode/numsys.h"
-#include "unicode/plurrule.h"
-#include "unicode/rbbi.h"
#include "unicode/regex.h"
#include "unicode/smpdtfmt.h"
#include "unicode/timezone.h"
-#include "unicode/uchar.h"
#include "unicode/ucol.h"
-#include "unicode/ucurr.h"
-#include "unicode/unum.h"
-#include "unicode/upluralrules.h"
#include "unicode/ures.h"
#include "unicode/uvernum.h"
#include "unicode/uversion.h"
-#if U_ICU_VERSION_MAJOR_NUM >= 59
-#include "unicode/char16ptr.h"
-#endif
-
namespace v8 {
namespace internal {
-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(isolate, options, str).ToHandleChecked();
- if (object->IsString()) {
- v8::String::Utf8Value utf8_string(
- v8_isolate, v8::Utils::ToLocal(Handle<String>::cast(object)));
- *setting = icu::UnicodeString::fromUTF8(*utf8_string);
- return true;
- }
- return false;
-}
-
-bool ExtractIntegerSetting(Isolate* isolate, Handle<JSObject> options,
- const char* key, int32_t* value) {
- Handle<String> str = isolate->factory()->NewStringFromAsciiChecked(key);
- Handle<Object> object =
- JSReceiver::GetProperty(isolate, options, str).ToHandleChecked();
- if (object->IsNumber()) {
- return object->ToInt32(value);
- }
- return false;
-}
-
-bool ExtractBooleanSetting(Isolate* isolate, Handle<JSObject> options,
- const char* key, bool* value) {
- Handle<String> str = isolate->factory()->NewStringFromAsciiChecked(key);
- Handle<Object> object =
- JSReceiver::GetProperty(isolate, options, str).ToHandleChecked();
- if (object->IsBoolean()) {
- *value = object->BooleanValue(isolate);
- return true;
- }
- return false;
-}
-
-icu::SimpleDateFormat* CreateICUDateFormat(Isolate* isolate,
- const icu::Locale& icu_locale,
- Handle<JSObject> options) {
- // Create time zone as specified by the user. We have to re-create time zone
- // since calendar takes ownership.
- icu::TimeZone* tz = nullptr;
- icu::UnicodeString timezone;
- if (ExtractStringSetting(isolate, options, "timeZone", &timezone)) {
- tz = icu::TimeZone::createTimeZone(timezone);
- } else {
- tz = icu::TimeZone::createDefault();
- }
-
- // Create a calendar using locale, and apply time zone to it.
- UErrorCode status = U_ZERO_ERROR;
- icu::Calendar* calendar =
- icu::Calendar::createInstance(tz, icu_locale, status);
-
- if (calendar->getDynamicClassID() ==
- icu::GregorianCalendar::getStaticClassID()) {
- icu::GregorianCalendar* gc = (icu::GregorianCalendar*)calendar;
- UErrorCode status = U_ZERO_ERROR;
- // The beginning of ECMAScript time, namely -(2**53)
- const double start_of_time = -9007199254740992;
- gc->setGregorianChange(start_of_time, status);
- DCHECK(U_SUCCESS(status));
- }
-
- // Make formatter from skeleton. Calendar and numbering system are added
- // to the locale as Unicode extension (if they were specified at all).
- icu::SimpleDateFormat* date_format = nullptr;
- icu::UnicodeString skeleton;
- if (ExtractStringSetting(isolate, options, "skeleton", &skeleton)) {
- // See https://github.com/tc39/ecma402/issues/225 . The best pattern
- // generation needs to be done in the base locale according to the
- // current spec however odd it may be. See also crbug.com/826549 .
- // This is a temporary work-around to get v8's external behavior to match
- // the current spec, but does not follow the spec provisions mentioned
- // in the above Ecma 402 issue.
- // TODO(jshin): The spec may need to be revised because using the base
- // locale for the pattern match is not quite right. Moreover, what to
- // do with 'related year' part when 'chinese/dangi' calendar is specified
- // has to be discussed. Revisit once the spec is clarified/revised.
- icu::Locale no_extension_locale(icu_locale.getBaseName());
- std::unique_ptr<icu::DateTimePatternGenerator> generator(
- icu::DateTimePatternGenerator::createInstance(no_extension_locale,
- status));
- icu::UnicodeString pattern;
- if (U_SUCCESS(status))
- pattern = generator->getBestPattern(skeleton, status);
-
- date_format = new icu::SimpleDateFormat(pattern, icu_locale, status);
- if (U_SUCCESS(status)) {
- date_format->adoptCalendar(calendar);
- }
- }
-
- if (U_FAILURE(status)) {
- delete calendar;
- delete date_format;
- date_format = nullptr;
- }
-
- return date_format;
-}
-
-void SetResolvedDateSettings(Isolate* isolate, const icu::Locale& icu_locale,
- icu::SimpleDateFormat* date_format,
- Handle<JSObject> resolved) {
- Factory* factory = isolate->factory();
- UErrorCode status = U_ZERO_ERROR;
- icu::UnicodeString pattern;
- date_format->toPattern(pattern);
- JSObject::SetProperty(
- isolate, resolved, factory->intl_pattern_symbol(),
- factory
- ->NewStringFromTwoByte(Vector<const uint16_t>(
- reinterpret_cast<const uint16_t*>(pattern.getBuffer()),
- pattern.length()))
- .ToHandleChecked(),
- LanguageMode::kSloppy)
- .Assert();
-
- // Set time zone and calendar.
- const icu::Calendar* calendar = date_format->getCalendar();
- // getType() returns legacy calendar type name instead of LDML/BCP47 calendar
- // key values. intl.js maps them to BCP47 values for key "ca".
- // TODO(jshin): Consider doing it here, instead.
- const char* calendar_name = calendar->getType();
- JSObject::SetProperty(
- isolate, resolved, factory->NewStringFromStaticChars("calendar"),
- factory->NewStringFromAsciiChecked(calendar_name), LanguageMode::kSloppy)
- .Assert();
-
- const icu::TimeZone& tz = calendar->getTimeZone();
- icu::UnicodeString time_zone;
- tz.getID(time_zone);
-
- icu::UnicodeString canonical_time_zone;
- icu::TimeZone::getCanonicalID(time_zone, canonical_time_zone, status);
- if (U_SUCCESS(status)) {
- // In CLDR (http://unicode.org/cldr/trac/ticket/9943), Etc/UTC is made
- // a separate timezone ID from Etc/GMT even though they're still the same
- // timezone. We have Etc/UTC because 'UTC', 'Etc/Universal',
- // 'Etc/Zulu' and others are turned to 'Etc/UTC' by ICU. Etc/GMT comes
- // from Etc/GMT0, Etc/GMT+0, Etc/GMT-0, Etc/Greenwich.
- // ecma402##sec-canonicalizetimezonename step 3
- if (canonical_time_zone == UNICODE_STRING_SIMPLE("Etc/UTC") ||
- canonical_time_zone == UNICODE_STRING_SIMPLE("Etc/GMT")) {
- JSObject::SetProperty(
- isolate, resolved, factory->NewStringFromStaticChars("timeZone"),
- factory->NewStringFromStaticChars("UTC"), LanguageMode::kSloppy)
- .Assert();
- } else {
- JSObject::SetProperty(isolate, resolved,
- factory->NewStringFromStaticChars("timeZone"),
- factory
- ->NewStringFromTwoByte(Vector<const uint16_t>(
- reinterpret_cast<const uint16_t*>(
- canonical_time_zone.getBuffer()),
- canonical_time_zone.length()))
- .ToHandleChecked(),
- LanguageMode::kSloppy)
- .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.
- 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(
- isolate, resolved, factory->NewStringFromStaticChars("numberingSystem"),
- factory->NewStringFromAsciiChecked(ns), LanguageMode::kSloppy)
- .Assert();
- } else {
- JSObject::SetProperty(isolate, resolved,
- factory->NewStringFromStaticChars("numberingSystem"),
- factory->undefined_value(), LanguageMode::kSloppy)
- .Assert();
- }
- delete numbering_system;
-
- // Set the locale
- char result[ULOC_FULLNAME_CAPACITY];
- status = U_ZERO_ERROR;
- uloc_toLanguageTag(icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY,
- FALSE, &status);
- if (U_SUCCESS(status)) {
- JSObject::SetProperty(
- isolate, resolved, factory->NewStringFromStaticChars("locale"),
- factory->NewStringFromAsciiChecked(result), LanguageMode::kSloppy)
- .Assert();
- } else {
- // This would never happen, since we got the locale from ICU.
- JSObject::SetProperty(
- isolate, resolved, factory->NewStringFromStaticChars("locale"),
- factory->NewStringFromStaticChars("und"), LanguageMode::kSloppy)
- .Assert();
- }
-}
-
-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) {
- // 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;
- icu::DecimalFormat* number_format = nullptr;
- icu::UnicodeString style;
- icu::UnicodeString currency;
- if (ExtractStringSetting(isolate, options, "style", &style)) {
- if (style == UNICODE_STRING_SIMPLE("currency")) {
- icu::UnicodeString display;
- ExtractStringSetting(isolate, options, "currency", &currency);
- ExtractStringSetting(isolate, options, "currencyDisplay", &display);
-
-#if (U_ICU_VERSION_MAJOR_NUM == 4) && (U_ICU_VERSION_MINOR_NUM <= 6)
- icu::NumberFormat::EStyles format_style;
- if (display == UNICODE_STRING_SIMPLE("code")) {
- format_style = icu::NumberFormat::kIsoCurrencyStyle;
- } else if (display == UNICODE_STRING_SIMPLE("name")) {
- format_style = icu::NumberFormat::kPluralCurrencyStyle;
- } else {
- format_style = icu::NumberFormat::kCurrencyStyle;
- }
-#else // ICU version is 4.8 or above (we ignore versions below 4.0).
- UNumberFormatStyle format_style;
- if (display == UNICODE_STRING_SIMPLE("code")) {
- format_style = UNUM_CURRENCY_ISO;
- } else if (display == UNICODE_STRING_SIMPLE("name")) {
- format_style = UNUM_CURRENCY_PLURAL;
- } else {
- format_style = UNUM_CURRENCY;
- }
-#endif
-
- number_format = static_cast<icu::DecimalFormat*>(
- icu::NumberFormat::createInstance(icu_locale, format_style, status));
-
- if (U_FAILURE(status)) {
- delete number_format;
- return nullptr;
- }
- } else if (style == UNICODE_STRING_SIMPLE("percent")) {
- number_format = static_cast<icu::DecimalFormat*>(
- icu::NumberFormat::createPercentInstance(icu_locale, status));
- if (U_FAILURE(status)) {
- delete number_format;
- return nullptr;
- }
- // Make sure 1.1% doesn't go into 2%.
- number_format->setMinimumFractionDigits(1);
- } else {
- // Make a decimal instance by default.
- number_format = static_cast<icu::DecimalFormat*>(
- icu::NumberFormat::createInstance(icu_locale, status));
- }
- }
-
- if (U_FAILURE(status)) {
- delete number_format;
- return nullptr;
- }
-
- // Set all options.
- if (!currency.isEmpty()) {
- number_format->setCurrency(currency.getBuffer(), status);
- }
-
- SetNumericSettings(isolate, number_format, options);
-
- bool grouping;
- if (ExtractBooleanSetting(isolate, options, "useGrouping", &grouping)) {
- number_format->setGroupingUsed(grouping);
- }
-
- return number_format;
-}
-
-void SetResolvedNumericSettings(Isolate* isolate, const icu::Locale& icu_locale,
- icu::DecimalFormat* number_format,
- Handle<JSObject> resolved) {
- Factory* factory = isolate->factory();
-
- JSObject::SetProperty(
- isolate, resolved,
- factory->NewStringFromStaticChars("minimumIntegerDigits"),
- factory->NewNumberFromInt(number_format->getMinimumIntegerDigits()),
- LanguageMode::kSloppy)
- .Assert();
-
- JSObject::SetProperty(
- isolate, resolved,
- factory->NewStringFromStaticChars("minimumFractionDigits"),
- factory->NewNumberFromInt(number_format->getMinimumFractionDigits()),
- LanguageMode::kSloppy)
- .Assert();
-
- JSObject::SetProperty(
- isolate, resolved,
- factory->NewStringFromStaticChars("maximumFractionDigits"),
- factory->NewNumberFromInt(number_format->getMaximumFractionDigits()),
- LanguageMode::kSloppy)
- .Assert();
-
- Handle<String> key =
- factory->NewStringFromStaticChars("minimumSignificantDigits");
- Maybe<bool> maybe = JSReceiver::HasOwnProperty(resolved, key);
- CHECK(maybe.IsJust());
- if (maybe.FromJust()) {
- JSObject::SetProperty(
- isolate, resolved,
- factory->NewStringFromStaticChars("minimumSignificantDigits"),
- factory->NewNumberFromInt(number_format->getMinimumSignificantDigits()),
- LanguageMode::kSloppy)
- .Assert();
- }
-
- key = factory->NewStringFromStaticChars("maximumSignificantDigits");
- maybe = JSReceiver::HasOwnProperty(resolved, key);
- CHECK(maybe.IsJust());
- if (maybe.FromJust()) {
- JSObject::SetProperty(
- isolate, resolved,
- factory->NewStringFromStaticChars("maximumSignificantDigits"),
- factory->NewNumberFromInt(number_format->getMaximumSignificantDigits()),
- LanguageMode::kSloppy)
- .Assert();
- }
-
- // Set the locale
- char result[ULOC_FULLNAME_CAPACITY];
- UErrorCode status = U_ZERO_ERROR;
- uloc_toLanguageTag(icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY,
- FALSE, &status);
- if (U_SUCCESS(status)) {
- JSObject::SetProperty(
- isolate, resolved, factory->NewStringFromStaticChars("locale"),
- factory->NewStringFromAsciiChecked(result), LanguageMode::kSloppy)
- .Assert();
- } else {
- // This would never happen, since we got the locale from ICU.
- JSObject::SetProperty(
- isolate, resolved, factory->NewStringFromStaticChars("locale"),
- factory->NewStringFromStaticChars("und"), LanguageMode::kSloppy)
- .Assert();
- }
-}
-
-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(
- isolate, resolved, factory->NewStringFromStaticChars("currency"),
- factory
- ->NewStringFromTwoByte(Vector<const uint16_t>(
- reinterpret_cast<const uint16_t*>(currency.getBuffer()),
- currency.length()))
- .ToHandleChecked(),
- LanguageMode::kSloppy)
- .Assert();
- }
-
+std::string Intl::GetNumberingSystem(const icu::Locale& icu_locale) {
// 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(
- isolate, resolved, factory->NewStringFromStaticChars("numberingSystem"),
- factory->NewStringFromAsciiChecked(ns), LanguageMode::kSloppy)
- .Assert();
- } else {
- JSObject::SetProperty(isolate, resolved,
- factory->NewStringFromStaticChars("numberingSystem"),
- factory->undefined_value(), LanguageMode::kSloppy)
- .Assert();
- }
- delete numbering_system;
-
- JSObject::SetProperty(isolate, resolved,
- factory->NewStringFromStaticChars("useGrouping"),
- factory->ToBoolean(number_format->isGroupingUsed()),
- LanguageMode::kSloppy)
- .Assert();
-
- SetResolvedNumericSettings(isolate, icu_locale, number_format, resolved);
-}
-
-icu::BreakIterator* CreateICUBreakIterator(Isolate* isolate,
- const icu::Locale& icu_locale,
- Handle<JSObject> options) {
- UErrorCode status = U_ZERO_ERROR;
- icu::BreakIterator* break_iterator = nullptr;
- icu::UnicodeString type;
- if (!ExtractStringSetting(isolate, options, "type", &type)) return nullptr;
-
- if (type == UNICODE_STRING_SIMPLE("character")) {
- break_iterator =
- icu::BreakIterator::createCharacterInstance(icu_locale, status);
- } else if (type == UNICODE_STRING_SIMPLE("sentence")) {
- break_iterator =
- icu::BreakIterator::createSentenceInstance(icu_locale, status);
- } else if (type == UNICODE_STRING_SIMPLE("line")) {
- break_iterator = icu::BreakIterator::createLineInstance(icu_locale, status);
- } else {
- // Defualt is word iterator.
- break_iterator = icu::BreakIterator::createWordInstance(icu_locale, status);
- }
-
- if (U_FAILURE(status)) {
- delete break_iterator;
- return nullptr;
- }
-
- isolate->CountUsage(v8::Isolate::UseCounterFeature::kBreakIterator);
-
- return break_iterator;
-}
-
-void SetResolvedBreakIteratorSettings(Isolate* isolate,
- const icu::Locale& icu_locale,
- icu::BreakIterator* break_iterator,
- Handle<JSObject> resolved) {
- Factory* factory = isolate->factory();
- UErrorCode status = U_ZERO_ERROR;
-
- // Set the locale
- char result[ULOC_FULLNAME_CAPACITY];
- status = U_ZERO_ERROR;
- uloc_toLanguageTag(icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY,
- FALSE, &status);
+ std::unique_ptr<icu::NumberingSystem> numbering_system(
+ icu::NumberingSystem::createInstance(icu_locale, status));
+ std::string value;
if (U_SUCCESS(status)) {
- JSObject::SetProperty(
- isolate, resolved, factory->NewStringFromStaticChars("locale"),
- factory->NewStringFromAsciiChecked(result), LanguageMode::kSloppy)
- .Assert();
- } else {
- // This would never happen, since we got the locale from ICU.
- JSObject::SetProperty(
- isolate, resolved, factory->NewStringFromStaticChars("locale"),
- factory->NewStringFromStaticChars("und"), LanguageMode::kSloppy)
- .Assert();
+ value = numbering_system->getName();
}
+ return value;
}
-MaybeHandle<JSObject> CachedOrNewService(Isolate* isolate,
- Handle<String> service,
- Handle<Object> locales,
- Handle<Object> options,
- Handle<Object> internal_options) {
+MaybeHandle<JSObject> Intl::CachedOrNewService(
+ Isolate* isolate, Handle<String> service, Handle<Object> locales,
+ Handle<Object> options, Handle<Object> internal_options) {
Handle<Object> result;
Handle<Object> undefined_value(ReadOnlyRoots(isolate).undefined_value(),
isolate);
@@ -569,7 +70,6 @@ MaybeHandle<JSObject> CachedOrNewService(Isolate* isolate,
JSArray);
return Handle<JSObject>::cast(result);
}
-} // namespace
icu::Locale Intl::CreateICULocale(Isolate* isolate,
Handle<String> bcp47_locale_str) {
@@ -583,14 +83,18 @@ icu::Locale Intl::CreateICULocale(Isolate* isolate,
// Convert BCP47 into ICU locale format.
UErrorCode status = U_ZERO_ERROR;
char icu_result[ULOC_FULLNAME_CAPACITY];
- int icu_length = 0;
+ int parsed_length = 0;
// bcp47_locale_str should be a canonicalized language tag, which
// means this shouldn't fail.
uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
- &icu_length, &status);
+ &parsed_length, &status);
CHECK(U_SUCCESS(status));
- CHECK_LT(0, icu_length);
+
+ // bcp47_locale is already checked for its structural validity
+ // so that it should be parsed completely.
+ int bcp47length = bcp47_locale.length();
+ CHECK_EQ(bcp47length, parsed_length);
icu::Locale icu_locale(icu_result);
if (icu_locale.isBogus()) {
@@ -601,253 +105,6 @@ icu::Locale Intl::CreateICULocale(Isolate* isolate,
}
// static
-icu::SimpleDateFormat* DateFormat::InitializeDateTimeFormat(
- Isolate* isolate, Handle<String> locale, Handle<JSObject> options,
- Handle<JSObject> resolved) {
- icu::Locale icu_locale = Intl::CreateICULocale(isolate, locale);
- DCHECK(!icu_locale.isBogus());
-
- icu::SimpleDateFormat* date_format =
- CreateICUDateFormat(isolate, icu_locale, options);
- if (!date_format) {
- // Remove extensions and try again.
- icu::Locale no_extension_locale(icu_locale.getBaseName());
- date_format = CreateICUDateFormat(isolate, no_extension_locale, options);
-
- if (!date_format) {
- FATAL("Failed to create ICU date format, are ICU data files missing?");
- }
-
- // Set resolved settings (pattern, numbering system, calendar).
- SetResolvedDateSettings(isolate, no_extension_locale, date_format,
- resolved);
- } else {
- SetResolvedDateSettings(isolate, icu_locale, date_format, resolved);
- }
-
- CHECK_NOT_NULL(date_format);
- return date_format;
-}
-
-icu::SimpleDateFormat* DateFormat::UnpackDateFormat(Handle<JSObject> obj) {
- return reinterpret_cast<icu::SimpleDateFormat*>(
- obj->GetEmbedderField(DateFormat::kSimpleDateFormatIndex));
-}
-
-void DateFormat::DeleteDateFormat(const v8::WeakCallbackInfo<void>& data) {
- delete reinterpret_cast<icu::SimpleDateFormat*>(data.GetInternalField(0));
- GlobalHandles::Destroy(reinterpret_cast<Object**>(data.GetParameter()));
-}
-
-MaybeHandle<JSObject> DateFormat::Unwrap(Isolate* isolate,
- Handle<JSReceiver> receiver,
- const char* method_name) {
- Handle<Context> native_context =
- Handle<Context>(isolate->context()->native_context(), isolate);
- Handle<JSFunction> constructor = Handle<JSFunction>(
- JSFunction::cast(native_context->intl_date_time_format_function()),
- isolate);
- Handle<String> method_name_str =
- isolate->factory()->NewStringFromAsciiChecked(method_name);
-
- return Intl::UnwrapReceiver(isolate, receiver, constructor,
- Intl::Type::kDateTimeFormat, method_name_str,
- true);
-}
-
-// ecma402/#sec-formatdatetime
-// FormatDateTime( dateTimeFormat, x )
-MaybeHandle<String> DateFormat::FormatDateTime(
- Isolate* isolate, Handle<JSObject> date_time_format_holder, double x) {
- double date_value = DateCache::TimeClip(x);
- if (std::isnan(date_value)) {
- THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidTimeValue),
- String);
- }
-
- CHECK(Intl::IsObjectOfType(isolate, date_time_format_holder,
- Intl::Type::kDateTimeFormat));
- icu::SimpleDateFormat* date_format =
- DateFormat::UnpackDateFormat(date_time_format_holder);
- CHECK_NOT_NULL(date_format);
-
- icu::UnicodeString result;
- date_format->format(date_value, result);
-
- return isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
- reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length()));
-}
-
-// ecma402/#sec-datetime-format-functions
-// DateTime Format Functions
-MaybeHandle<String> DateFormat::DateTimeFormat(
- Isolate* isolate, Handle<JSObject> date_time_format_holder,
- Handle<Object> date) {
- // 2. Assert: Type(dtf) is Object and dtf has an [[InitializedDateTimeFormat]]
- // internal slot.
- DCHECK(Intl::IsObjectOfType(isolate, date_time_format_holder,
- Intl::Type::kDateTimeFormat));
-
- // 3. If date is not provided or is undefined, then
- double x;
- if (date->IsUndefined()) {
- // 3.a Let x be Call(%Date_now%, undefined).
- x = JSDate::CurrentTimeValue(isolate);
- } else {
- // 4. Else,
- // a. Let x be ? ToNumber(date).
- ASSIGN_RETURN_ON_EXCEPTION(isolate, date, Object::ToNumber(isolate, date),
- String);
- CHECK(date->IsNumber());
- x = date->Number();
- }
- // 5. Return FormatDateTime(dtf, x).
- return DateFormat::FormatDateTime(isolate, date_time_format_holder, x);
-}
-
-MaybeHandle<String> DateFormat::ToLocaleDateTime(
- Isolate* isolate, Handle<Object> date, Handle<Object> locales,
- Handle<Object> options, const char* required, const char* defaults,
- const char* service) {
- Factory* factory = isolate->factory();
- // 1. Let x be ? thisTimeValue(this value);
- if (!date->IsJSDate()) {
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
- factory->NewStringFromStaticChars("Date")),
- String);
- }
-
- double const x = Handle<JSDate>::cast(date)->value()->Number();
- // 2. If x is NaN, return "Invalid Date"
- if (std::isnan(x)) {
- return factory->NewStringFromStaticChars("Invalid Date");
- }
-
- // 3. Let options be ? ToDateTimeOptions(options, required, defaults).
- Handle<JSObject> internal_options;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, internal_options,
- DateFormat::ToDateTimeOptions(isolate, options, required, defaults),
- String);
-
- // 4. Let dateFormat be ? Construct(%DateTimeFormat%, « locales, options »).
- Handle<JSObject> date_format;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, date_format,
- CachedOrNewService(isolate, factory->NewStringFromAsciiChecked(service),
- locales, options, internal_options),
- String);
-
- // 5. Return FormatDateTime(dateFormat, x).
- return DateFormat::FormatDateTime(isolate, date_format, x);
-}
-
-icu::DecimalFormat* NumberFormat::InitializeNumberFormat(
- Isolate* isolate, Handle<String> locale, Handle<JSObject> options,
- Handle<JSObject> resolved) {
- icu::Locale icu_locale = Intl::CreateICULocale(isolate, locale);
- DCHECK(!icu_locale.isBogus());
-
- icu::DecimalFormat* number_format =
- CreateICUNumberFormat(isolate, icu_locale, options);
- if (!number_format) {
- // Remove extensions and try again.
- icu::Locale no_extension_locale(icu_locale.getBaseName());
- number_format =
- CreateICUNumberFormat(isolate, no_extension_locale, options);
-
- if (!number_format) {
- FATAL("Failed to create ICU number format, are ICU data files missing?");
- }
-
- // Set resolved settings (pattern, numbering system).
- SetResolvedNumberSettings(isolate, no_extension_locale, number_format,
- resolved);
- } else {
- SetResolvedNumberSettings(isolate, icu_locale, number_format, resolved);
- }
-
- CHECK_NOT_NULL(number_format);
- return number_format;
-}
-
-icu::DecimalFormat* NumberFormat::UnpackNumberFormat(Handle<JSObject> obj) {
- return reinterpret_cast<icu::DecimalFormat*>(
- obj->GetEmbedderField(NumberFormat::kDecimalFormatIndex));
-}
-
-void NumberFormat::DeleteNumberFormat(const v8::WeakCallbackInfo<void>& data) {
- delete reinterpret_cast<icu::DecimalFormat*>(data.GetInternalField(0));
- GlobalHandles::Destroy(reinterpret_cast<Object**>(data.GetParameter()));
-}
-
-icu::BreakIterator* V8BreakIterator::InitializeBreakIterator(
- Isolate* isolate, Handle<String> locale, Handle<JSObject> options,
- Handle<JSObject> resolved) {
- icu::Locale icu_locale = Intl::CreateICULocale(isolate, locale);
- DCHECK(!icu_locale.isBogus());
-
- icu::BreakIterator* break_iterator =
- CreateICUBreakIterator(isolate, icu_locale, options);
- if (!break_iterator) {
- // Remove extensions and try again.
- icu::Locale no_extension_locale(icu_locale.getBaseName());
- break_iterator =
- CreateICUBreakIterator(isolate, no_extension_locale, options);
-
- if (!break_iterator) {
- FATAL("Failed to create ICU break iterator, are ICU data files missing?");
- }
-
- // Set resolved settings (locale).
- SetResolvedBreakIteratorSettings(isolate, no_extension_locale,
- break_iterator, resolved);
- } else {
- SetResolvedBreakIteratorSettings(isolate, icu_locale, break_iterator,
- resolved);
- }
-
- CHECK_NOT_NULL(break_iterator);
- return break_iterator;
-}
-
-icu::BreakIterator* V8BreakIterator::UnpackBreakIterator(Handle<JSObject> obj) {
- return reinterpret_cast<icu::BreakIterator*>(
- obj->GetEmbedderField(V8BreakIterator::kBreakIteratorIndex));
-}
-
-void V8BreakIterator::DeleteBreakIterator(
- const v8::WeakCallbackInfo<void>& data) {
- delete reinterpret_cast<icu::BreakIterator*>(data.GetInternalField(0));
- delete reinterpret_cast<icu::UnicodeString*>(data.GetInternalField(1));
- GlobalHandles::Destroy(reinterpret_cast<Object**>(data.GetParameter()));
-}
-
-void V8BreakIterator::AdoptText(Isolate* isolate,
- Handle<JSObject> break_iterator_holder,
- Handle<String> text) {
- icu::BreakIterator* break_iterator =
- V8BreakIterator::UnpackBreakIterator(break_iterator_holder);
- CHECK_NOT_NULL(break_iterator);
-
- icu::UnicodeString* u_text = reinterpret_cast<icu::UnicodeString*>(
- break_iterator_holder->GetEmbedderField(
- V8BreakIterator::kUnicodeStringIndex));
- delete u_text;
-
- int length = text->length();
- text = String::Flatten(isolate, text);
- DisallowHeapAllocation no_gc;
- String::FlatContent flat = text->GetFlatContent();
- std::unique_ptr<uc16[]> sap;
- const UChar* text_value = GetUCharBufferFromFlat(flat, &sap, length);
- u_text = new icu::UnicodeString(text_value, length);
- break_iterator_holder->SetEmbedderField(V8BreakIterator::kUnicodeStringIndex,
- reinterpret_cast<Smi*>(u_text));
-
- break_iterator->setText(*u_text);
-}
MaybeHandle<String> Intl::ToString(Isolate* isolate,
const icu::UnicodeString& string) {
@@ -902,12 +159,18 @@ void Intl::AddElement(Isolate* isolate, Handle<JSArray> array, int index,
JSObject::AddProperty(isolate, element, additional_property_name,
additional_property_value, NONE);
}
+
+namespace {
+
// Build the shortened locale; eg, convert xx_Yyyy_ZZ to xx_ZZ.
-bool Intl::RemoveLocaleScriptTag(const std::string& icu_locale,
- std::string* locale_less_script) {
+//
+// If locale has a script tag then return true and the locale without the
+// script else return false and an empty string.
+bool RemoveLocaleScriptTag(const std::string& icu_locale,
+ std::string* locale_less_script) {
icu::Locale new_locale = icu::Locale::createCanonical(icu_locale.c_str());
const char* icu_script = new_locale.getScript();
- if (icu_script == NULL || strlen(icu_script) == 0) {
+ if (icu_script == nullptr || strlen(icu_script) == 0) {
*locale_less_script = std::string();
return false;
}
@@ -915,134 +178,33 @@ bool Intl::RemoveLocaleScriptTag(const std::string& icu_locale,
const char* icu_language = new_locale.getLanguage();
const char* icu_country = new_locale.getCountry();
icu::Locale short_locale = icu::Locale(icu_language, icu_country);
- const char* icu_name = short_locale.getName();
- *locale_less_script = std::string(icu_name);
+ *locale_less_script = short_locale.getName();
return true;
}
-namespace {
-
-Maybe<bool> IsPropertyUndefined(Isolate* isolate, Handle<JSObject> options,
- const char* property) {
- Factory* factory = isolate->factory();
- // i. Let prop be the property name.
- // ii. Let value be ? Get(options, prop).
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(
- isolate, value,
- Object::GetPropertyOrElement(
- isolate, options, factory->NewStringFromAsciiChecked(property)),
- Nothing<bool>());
- return Just(value->IsUndefined(isolate));
-}
-
} // namespace
-// ecma-402/#sec-todatetimeoptions
-MaybeHandle<JSObject> DateFormat::ToDateTimeOptions(
- Isolate* isolate, Handle<Object> input_options, const char* required,
- const char* defaults) {
- Factory* factory = isolate->factory();
- // 1. If options is undefined, let options be null; otherwise let options be ?
- // ToObject(options).
- Handle<JSObject> options;
- if (input_options->IsUndefined(isolate)) {
- options = factory->NewJSObjectWithNullProto();
- } else {
- Handle<JSReceiver> options_obj;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, options_obj,
- Object::ToObject(isolate, input_options),
- JSObject);
- // 2. Let options be ObjectCreate(options).
- ASSIGN_RETURN_ON_EXCEPTION(isolate, options,
- JSObject::ObjectCreate(isolate, options_obj),
- JSObject);
- }
-
- // 3. Let needDefaults be true.
- bool needs_default = true;
-
- bool required_is_any = strcmp(required, "any") == 0;
- // 4. If required is "date" or "any", then
- if (required_is_any || (strcmp(required, "date") == 0)) {
- // a. For each of the property names "weekday", "year", "month", "day", do
- for (auto& prop : {"weekday", "year", "month", "day"}) {
- // i. Let prop be the property name.
- // ii. Let value be ? Get(options, prop)
- Maybe<bool> maybe_undefined = IsPropertyUndefined(isolate, options, prop);
- MAYBE_RETURN(maybe_undefined, Handle<JSObject>());
- // iii. If value is not undefined, let needDefaults be false.
- if (!maybe_undefined.FromJust()) {
- needs_default = false;
- }
- }
- }
-
- // 5. If required is "time" or "any", then
- if (required_is_any || (strcmp(required, "time") == 0)) {
- // a. For each of the property names "hour", "minute", "second", do
- for (auto& prop : {"hour", "minute", "second"}) {
- // i. Let prop be the property name.
- // ii. Let value be ? Get(options, prop)
- Maybe<bool> maybe_undefined = IsPropertyUndefined(isolate, options, prop);
- MAYBE_RETURN(maybe_undefined, Handle<JSObject>());
- // iii. If value is not undefined, let needDefaults be false.
- if (!maybe_undefined.FromJust()) {
- needs_default = false;
- }
- }
- }
-
- // 6. If needDefaults is true and defaults is either "date" or "all", then
- if (needs_default) {
- bool default_is_all = strcmp(defaults, "all") == 0;
- if (default_is_all || (strcmp(defaults, "date") == 0)) {
- // a. For each of the property names "year", "month", "day", do
- // i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric").
- for (auto& prop : {"year", "month", "day"}) {
- MAYBE_RETURN(
- JSReceiver::CreateDataProperty(
- isolate, options, factory->NewStringFromAsciiChecked(prop),
- factory->numeric_string(), kThrowOnError),
- Handle<JSObject>());
- }
- }
- // 7. If needDefaults is true and defaults is either "time" or "all", then
- if (default_is_all || (strcmp(defaults, "time") == 0)) {
- // a. For each of the property names "hour", "minute", "second", do
- // i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric").
- for (auto& prop : {"hour", "minute", "second"}) {
- MAYBE_RETURN(
- JSReceiver::CreateDataProperty(
- isolate, options, factory->NewStringFromAsciiChecked(prop),
- factory->numeric_string(), kThrowOnError),
- Handle<JSObject>());
- }
- }
- }
- // 8. Return options.
- return options;
-}
-
-std::set<std::string> Intl::GetAvailableLocales(const IcuService& service) {
+std::set<std::string> Intl::GetAvailableLocales(const ICUService service) {
const icu::Locale* icu_available_locales = nullptr;
int32_t count = 0;
std::set<std::string> locales;
switch (service) {
- case IcuService::kBreakIterator:
+ case ICUService::kBreakIterator:
+ case ICUService::kSegmenter:
icu_available_locales = icu::BreakIterator::getAvailableLocales(count);
break;
- case IcuService::kCollator:
+ case ICUService::kCollator:
icu_available_locales = icu::Collator::getAvailableLocales(count);
break;
- case IcuService::kDateFormat:
+ case ICUService::kRelativeDateTimeFormatter:
+ case ICUService::kDateFormat:
icu_available_locales = icu::DateFormat::getAvailableLocales(count);
break;
- case IcuService::kNumberFormat:
+ case ICUService::kNumberFormat:
icu_available_locales = icu::NumberFormat::getAvailableLocales(count);
break;
- case IcuService::kPluralRules:
+ case ICUService::kPluralRules:
// TODO(littledan): For PluralRules, filter out locales that
// don't support PluralRules.
// PluralRules is missing an appropriate getAvailableLocales method,
@@ -1050,44 +212,7 @@ std::set<std::string> Intl::GetAvailableLocales(const IcuService& service) {
// https://ssl.icu-project.org/trac/ticket/12756
icu_available_locales = icu::Locale::getAvailableLocales(count);
break;
- case IcuService::kResourceBundle: {
- UErrorCode status = U_ZERO_ERROR;
- UEnumeration* en = ures_openAvailableLocales(nullptr, &status);
- int32_t length = 0;
- const char* locale_str = uenum_next(en, &length, &status);
- while (U_SUCCESS(status) && (locale_str != nullptr)) {
- std::string locale(locale_str, length);
- std::replace(locale.begin(), locale.end(), '_', '-');
- locales.insert(locale);
- std::string shortened_locale;
- if (Intl::RemoveLocaleScriptTag(locale_str, &shortened_locale)) {
- std::replace(shortened_locale.begin(), shortened_locale.end(), '_',
- '-');
- locales.insert(shortened_locale);
- }
- locale_str = uenum_next(en, &length, &status);
- }
- uenum_close(en);
- return locales;
- }
- case IcuService::kRelativeDateTimeFormatter: {
- // ICU RelativeDateTimeFormatter does not provide a getAvailableLocales()
- // interface, because RelativeDateTimeFormatter depends on
- // 1. NumberFormat and 2. ResourceBundle, return the
- // intersection of these two set.
- // ICU FR at https://unicode-org.atlassian.net/browse/ICU-20009
- // TODO(ftang): change to call ICU's getAvailableLocales() after it is
- // added.
- std::set<std::string> number_format_set(
- Intl::GetAvailableLocales(IcuService::kNumberFormat));
- std::set<std::string> resource_bundle_set(
- Intl::GetAvailableLocales(IcuService::kResourceBundle));
- set_intersection(resource_bundle_set.begin(), resource_bundle_set.end(),
- number_format_set.begin(), number_format_set.end(),
- std::inserter(locales, locales.begin()));
- return locales;
- }
- case IcuService::kListFormatter: {
+ case ICUService::kListFormatter: {
// TODO(ftang): for now just use
// icu::Locale::getAvailableLocales(count) until we migrate to
// Intl::GetAvailableLocales().
@@ -1114,7 +239,7 @@ std::set<std::string> Intl::GetAvailableLocales(const IcuService& service) {
locales.insert(locale);
std::string shortened_locale;
- if (Intl::RemoveLocaleScriptTag(icu_name, &shortened_locale)) {
+ if (RemoveLocaleScriptTag(icu_name, &shortened_locale)) {
std::replace(shortened_locale.begin(), shortened_locale.end(), '_', '-');
locales.insert(shortened_locale);
}
@@ -1123,30 +248,60 @@ std::set<std::string> Intl::GetAvailableLocales(const IcuService& service) {
return locales;
}
-IcuService Intl::StringToIcuService(Handle<String> service) {
- if (service->IsUtf8EqualTo(CStrVector("collator"))) {
- return IcuService::kCollator;
- } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) {
- return IcuService::kNumberFormat;
- } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) {
- return IcuService::kDateFormat;
- } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) {
- return IcuService::kBreakIterator;
- } else if (service->IsUtf8EqualTo(CStrVector("pluralrules"))) {
- return IcuService::kPluralRules;
- } else if (service->IsUtf8EqualTo(CStrVector("relativetimeformat"))) {
- return IcuService::kRelativeDateTimeFormatter;
- } else if (service->IsUtf8EqualTo(CStrVector("listformat"))) {
- return IcuService::kListFormatter;
+namespace {
+
+// TODO(gsathya): Remove this once we port ResolveLocale to C++.
+ICUService StringToICUService(Handle<String> service) {
+ std::unique_ptr<char[]> service_cstr = service->ToCString();
+ if (strcmp(service_cstr.get(), "collator") == 0) {
+ return ICUService::kCollator;
+ } else if (strcmp(service_cstr.get(), "numberformat") == 0) {
+ return ICUService::kNumberFormat;
+ } else if (strcmp(service_cstr.get(), "dateformat") == 0) {
+ return ICUService::kDateFormat;
+ } else if (strcmp(service_cstr.get(), "breakiterator") == 0) {
+ return ICUService::kBreakIterator;
+ } else if (strcmp(service_cstr.get(), "pluralrules") == 0) {
+ return ICUService::kPluralRules;
+ } else if (strcmp(service_cstr.get(), "relativetimeformat") == 0) {
+ return ICUService::kRelativeDateTimeFormatter;
+ } else if (strcmp(service_cstr.get(), "listformat") == 0) {
+ return ICUService::kListFormatter;
+ } else if (service->IsUtf8EqualTo(CStrVector("segmenter"))) {
+ return ICUService::kSegmenter;
+ }
+ UNREACHABLE();
+}
+
+const char* ICUServiceToString(ICUService service) {
+ switch (service) {
+ case ICUService::kCollator:
+ return "Intl.Collator";
+ case ICUService::kNumberFormat:
+ return "Intl.NumberFormat";
+ case ICUService::kDateFormat:
+ return "Intl.DateFormat";
+ case ICUService::kBreakIterator:
+ return "Intl.v8BreakIterator";
+ case ICUService::kPluralRules:
+ return "Intl.PluralRules";
+ case ICUService::kRelativeDateTimeFormatter:
+ return "Intl.RelativeTimeFormat";
+ case ICUService::kListFormatter:
+ return "Intl.kListFormat";
+ case ICUService::kSegmenter:
+ return "Intl.kSegmenter";
}
UNREACHABLE();
}
+} // namespace
+
V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> Intl::AvailableLocalesOf(
Isolate* isolate, Handle<String> service) {
Factory* factory = isolate->factory();
std::set<std::string> results =
- Intl::GetAvailableLocales(StringToIcuService(service));
+ Intl::GetAvailableLocales(StringToICUService(service));
Handle<JSObject> locales = factory->NewJSObjectWithNullProto();
int32_t i = 0;
@@ -1196,24 +351,11 @@ bool Intl::IsObjectOfType(Isolate* isolate, Handle<Object> input,
return type == expected_type;
}
-namespace {
-
-// In ECMA 402 v1, Intl constructors supported a mode of operation
-// where calling them with an existing object as a receiver would
-// transform the receiver into the relevant Intl instance with all
-// internal slots. In ECMA 402 v2, this capability was removed, to
-// avoid adding internal slots on existing objects. In ECMA 402 v3,
-// the capability was re-added as "normative optional" in a mode
-// which chains the underlying Intl instance on any object, when the
-// constructor is called
-//
// See ecma402/#legacy-constructor.
-MaybeHandle<Object> LegacyUnwrapReceiver(Isolate* isolate,
- Handle<JSReceiver> receiver,
- Handle<JSFunction> constructor,
- Intl::Type type) {
- bool has_initialized_slot = Intl::IsObjectOfType(isolate, receiver, type);
-
+MaybeHandle<Object> Intl::LegacyUnwrapReceiver(Isolate* isolate,
+ Handle<JSReceiver> receiver,
+ Handle<JSFunction> constructor,
+ bool has_initialized_slot) {
Handle<Object> obj_is_instance_of;
ASSIGN_RETURN_ON_EXCEPTION(isolate, obj_is_instance_of,
Object::InstanceOf(isolate, receiver, constructor),
@@ -1236,94 +378,9 @@ MaybeHandle<Object> LegacyUnwrapReceiver(Isolate* isolate,
return receiver;
}
-} // namespace
-
-MaybeHandle<JSObject> Intl::UnwrapReceiver(Isolate* isolate,
- Handle<JSReceiver> receiver,
- Handle<JSFunction> constructor,
- Intl::Type type,
- Handle<String> method_name,
- bool check_legacy_constructor) {
- DCHECK(type == Intl::Type::kCollator || type == Intl::Type::kNumberFormat ||
- type == Intl::Type::kDateTimeFormat ||
- type == Intl::Type::kBreakIterator);
- Handle<Object> new_receiver = receiver;
- if (check_legacy_constructor) {
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, new_receiver,
- LegacyUnwrapReceiver(isolate, receiver, constructor, type), JSObject);
- }
-
- // Collator has been ported to use regular instance types. We
- // shouldn't be using Intl::IsObjectOfType anymore.
- if (type == Intl::Type::kCollator) {
- if (!receiver->IsJSCollator()) {
- // 3. a. Throw a TypeError exception.
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
- method_name, receiver),
- JSObject);
- }
- return Handle<JSCollator>::cast(receiver);
- }
-
- DCHECK_NE(type, Intl::Type::kCollator);
- // 3. If Type(new_receiver) is not Object or nf does not have an
- // [[Initialized...]] internal slot, then
- if (!Intl::IsObjectOfType(isolate, new_receiver, type)) {
- // 3. a. Throw a TypeError exception.
- THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
- method_name, receiver),
- JSObject);
- }
-
- // The above IsObjectOfType returns true only for JSObjects, which
- // makes this cast safe.
- return Handle<JSObject>::cast(new_receiver);
-}
-
-MaybeHandle<JSObject> NumberFormat::Unwrap(Isolate* isolate,
- Handle<JSReceiver> receiver,
- const char* method_name) {
- Handle<Context> native_context =
- Handle<Context>(isolate->context()->native_context(), isolate);
- Handle<JSFunction> constructor = Handle<JSFunction>(
- JSFunction::cast(native_context->intl_number_format_function()), isolate);
- Handle<String> method_name_str =
- isolate->factory()->NewStringFromAsciiChecked(method_name);
-
- return Intl::UnwrapReceiver(isolate, receiver, constructor,
- Intl::Type::kNumberFormat, method_name_str, true);
-}
-
-MaybeHandle<String> NumberFormat::FormatNumber(
- Isolate* isolate, Handle<JSObject> number_format_holder, double value) {
- icu::DecimalFormat* number_format =
- NumberFormat::UnpackNumberFormat(number_format_holder);
- CHECK_NOT_NULL(number_format);
-
- icu::UnicodeString result;
- number_format->format(value, result);
-
- return isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
- reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length()));
-}
-
-void Intl::DefineWEProperty(Isolate* isolate, Handle<JSObject> target,
- Handle<Name> key, Handle<Object> value) {
- PropertyDescriptor desc;
- desc.set_writable(true);
- desc.set_enumerable(true);
- desc.set_value(value);
- Maybe<bool> success =
- JSReceiver::DefineOwnProperty(isolate, target, key, &desc, kDontThrow);
- DCHECK(success.IsJust() && success.FromJust());
- USE(success);
-}
-
namespace {
+#if USE_CHROMIUM_ICU == 0 && U_ICU_VERSION_MAJOR_NUM < 63
// Define general regexp macros.
// Note "(?:" means the regexp group a non-capture group.
#define REGEX_ALPHA "[a-z]"
@@ -1435,6 +492,7 @@ icu::RegexMatcher* GetLanguageVariantRegexMatcher(Isolate* isolate) {
}
return language_variant_regexp_matcher;
}
+#endif // USE_CHROMIUM_ICU == 0 && U_ICU_VERSION_MAJOR_NUM < 63
} // anonymous namespace
@@ -1560,6 +618,7 @@ char AsciiToLower(char c) {
return c | (1 << 5);
}
+#if USE_CHROMIUM_ICU == 0 && U_ICU_VERSION_MAJOR_NUM < 63
/**
* Check the structural Validity of the language tag per ECMA 402 6.2.2:
* - Well-formed per RFC 5646 2.1
@@ -1571,7 +630,7 @@ char AsciiToLower(char c) {
* primary/extended language, script, region, variant are not checked
* against the IANA language subtag registry.
*
- * ICU is too permissible and lets invalid tags, like
+ * ICU 62 or earlier is too permissible and lets invalid tags, like
* hant-cmn-cn, through.
*
* Returns false if the language tag is invalid.
@@ -1612,7 +671,7 @@ bool IsStructurallyValidLanguageTag(Isolate* isolate,
// is not valid and would fail LANGUAGE_TAG_RE test.
size_t pos = 0;
std::vector<std::string> parts;
- while ((pos = locale.find("-")) != std::string::npos) {
+ while ((pos = locale.find('-')) != std::string::npos) {
std::string token = locale.substr(0, pos);
parts.push_back(token);
locale = locale.substr(pos + 1);
@@ -1662,6 +721,7 @@ bool IsStructurallyValidLanguageTag(Isolate* isolate,
return true;
}
+#endif // USE_CHROMIUM_ICU == 0 || U_ICU_VERSION_MAJOR_NUM < 63
bool IsLowerAscii(char c) { return c >= 'a' && c < 'z'; }
@@ -1713,6 +773,14 @@ Maybe<std::string> Intl::CanonicalizeLanguageTag(Isolate* isolate,
}
std::string locale(locale_str->ToCString().get());
+ if (locale.length() == 0 ||
+ !String::IsAscii(locale.data(), static_cast<int>(locale.length()))) {
+ THROW_NEW_ERROR_RETURN_VALUE(
+ isolate,
+ NewRangeError(MessageTemplate::kInvalidLanguageTag, locale_str),
+ Nothing<std::string>());
+ }
+
// Optimize for the most common case: a 2-letter language code in the
// canonical form/lowercase that is not one of the deprecated codes
// (in, iw, ji, jw). Don't check for ~70 of 3-letter deprecated language
@@ -1726,12 +794,15 @@ Maybe<std::string> Intl::CanonicalizeLanguageTag(Isolate* isolate,
// Because per BCP 47 2.1.1 language tags are case-insensitive, lowercase
// the input before any more check.
std::transform(locale.begin(), locale.end(), locale.begin(), AsciiToLower);
+
+#if USE_CHROMIUM_ICU == 0 && U_ICU_VERSION_MAJOR_NUM < 63
if (!IsStructurallyValidLanguageTag(isolate, locale)) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate,
NewRangeError(MessageTemplate::kInvalidLanguageTag, locale_str),
Nothing<std::string>());
}
+#endif
// ICU maps a few grandfathered tags to what looks like a regular language
// tag even though IANA language tag registry does not have a preferred
@@ -1749,11 +820,18 @@ Maybe<std::string> Intl::CanonicalizeLanguageTag(Isolate* isolate,
// https://unicode-org.atlassian.net/browse/ICU-13417
UErrorCode error = U_ZERO_ERROR;
char icu_result[ULOC_FULLNAME_CAPACITY];
+ // uloc_forLanguageTag checks the structrual validity. If the input BCP47
+ // language tag is parsed all the way to the end, it indicates that the input
+ // is structurally valid. Due to a couple of bugs, we can't use it
+ // without Chromium patches or ICU 62 or earlier.
+ int parsed_length;
uloc_forLanguageTag(locale.c_str(), icu_result, ULOC_FULLNAME_CAPACITY,
- nullptr, &error);
- if (U_FAILURE(error) || error == U_STRING_NOT_TERMINATED_WARNING) {
- // TODO(jshin): This should not happen because the structural validity
- // is already checked. If that's the case, remove this.
+ &parsed_length, &error);
+ if (U_FAILURE(error) ||
+#if USE_CHROMIUM_ICU == 1 || U_ICU_VERSION_MAJOR_NUM >= 63
+ static_cast<size_t>(parsed_length) < locale.length() ||
+#endif
+ error == U_STRING_NOT_TERMINATED_WARNING) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate,
NewRangeError(MessageTemplate::kInvalidLanguageTag, locale_str),
@@ -1849,120 +927,6 @@ Maybe<std::vector<std::string>> Intl::CanonicalizeLocaleList(
return Just(seen);
}
-// ecma-402/#sec-currencydigits
-Handle<Smi> Intl::CurrencyDigits(Isolate* isolate, Handle<String> currency) {
- v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
- v8::String::Value currency_string(v8_isolate, v8::Utils::ToLocal(currency));
- CHECK_NOT_NULL(*currency_string);
-
- DisallowHeapAllocation no_gc;
- UErrorCode status = U_ZERO_ERROR;
- uint32_t fraction_digits = ucurr_getDefaultFractionDigits(
- reinterpret_cast<const UChar*>(*currency_string), &status);
- // For missing currency codes, default to the most common, 2
- if (U_FAILURE(status)) fraction_digits = 2;
- return Handle<Smi>(Smi::FromInt(fraction_digits), isolate);
-}
-
-MaybeHandle<JSObject> Intl::CreateNumberFormat(Isolate* isolate,
- Handle<String> locale,
- Handle<JSObject> options,
- Handle<JSObject> resolved) {
- Handle<JSFunction> constructor(
- isolate->native_context()->intl_number_format_function(), isolate);
-
- Handle<JSObject> local_object;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, local_object,
- JSObject::New(constructor, constructor), JSObject);
-
- // Set number formatter as embedder field of the resulting JS object.
- icu::DecimalFormat* number_format =
- NumberFormat::InitializeNumberFormat(isolate, locale, options, resolved);
-
- CHECK_NOT_NULL(number_format);
-
- local_object->SetEmbedderField(NumberFormat::kDecimalFormatIndex,
- reinterpret_cast<Smi*>(number_format));
-
- Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
- GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(),
- NumberFormat::DeleteNumberFormat,
- WeakCallbackType::kInternalFields);
- return local_object;
-}
-
-/**
- * Parses Unicode extension into key - value map.
- * Returns empty object if the extension string is invalid.
- * We are not concerned with the validity of the values at this point.
- * 'attribute' in RFC 6047 is not supported. Keys without explicit
- * values are assigned UNDEFINED.
- * TODO(jshin): Fix the handling of 'attribute' (in RFC 6047, but none
- * has been defined so that it's not used) and boolean keys without
- * an explicit value.
- */
-void Intl::ParseExtension(Isolate* isolate, const std::string& extension,
- std::map<std::string, std::string>& out) {
- if (extension.compare(0, 3, "-u-") != 0) return;
-
- // Key is {2}alphanum, value is {3,8}alphanum.
- // Some keys may not have explicit values (booleans).
- std::string key;
- std::string value;
- // Skip the "-u-".
- size_t start = 3;
- size_t end;
- do {
- end = extension.find("-", start);
- size_t length =
- (end == std::string::npos) ? extension.length() - start : end - start;
- std::string element = extension.substr(start, length);
- // Key is {2}alphanum
- if (length == 2) {
- if (!key.empty()) {
- out.insert(std::pair<std::string, std::string>(key, value));
- value.clear();
- }
- key = element;
- // value is {3,8}alphanum.
- } else if (length >= 3 && length <= 8 && !key.empty()) {
- value = value.empty() ? element : (value + "-" + element);
- } else {
- return;
- }
- start = end + 1;
- } while (end != std::string::npos);
- if (!key.empty()) out.insert(std::pair<std::string, std::string>(key, value));
-}
-
-namespace {
-
-bool IsAToZ(char ch) {
- return IsInRange(AsciiAlphaToLower(ch), 'a', 'z');
-}
-
-} // namespace
-
-// Verifies that the input is a well-formed ISO 4217 currency code.
-// ecma402/#sec-currency-codes
-bool Intl::IsWellFormedCurrencyCode(Isolate* isolate, Handle<String> currency) {
- // 2. If the number of elements in normalized is not 3, return false.
- if (currency->length() != 3) return false;
-
- currency = String::Flatten(isolate, currency);
- {
- DisallowHeapAllocation no_gc;
- String::FlatContent flat = currency->GetFlatContent();
-
- // 1. Let normalized be the result of mapping currency to upper case as
- // described in 6.1. 3. If normalized contains any character that is not in
- // the range "A" to "Z" (U+0041 to U+005A), return false. 4. Return true.
- // Don't uppercase to test. It could convert invalid code into a valid one.
- // For example \u00DFP (Eszett+P) becomes SSP.
- return (IsAToZ(flat.Get(0)) && IsAToZ(flat.Get(1)) && IsAToZ(flat.Get(2)));
- }
-}
-
// ecma402 #sup-string.prototype.tolocalelowercase
// ecma402 #sup-string.prototype.tolocaleuppercase
MaybeHandle<String> Intl::StringLocaleConvertCase(Isolate* isolate,
@@ -1976,7 +940,7 @@ MaybeHandle<String> Intl::StringLocaleConvertCase(Isolate* isolate,
std::string requested_locale = requested_locales.size() == 0
? Intl::DefaultLocale(isolate)
: requested_locales[0];
- size_t dash = requested_locale.find("-");
+ size_t dash = requested_locale.find('-');
if (dash != std::string::npos) {
requested_locale = requested_locale.substr(0, dash);
}
@@ -2069,22 +1033,26 @@ MaybeHandle<String> Intl::NumberToLocaleString(Isolate* isolate,
factory->NewStringFromStaticChars("numberformat"),
locales, options, factory->undefined_value()),
String);
- DCHECK(
- Intl::IsObjectOfType(isolate, number_format_holder, Intl::kNumberFormat));
+ DCHECK(number_format_holder->IsJSNumberFormat());
+ Handle<JSNumberFormat> number_format = Handle<JSNumberFormat>(
+ JSNumberFormat::cast(*number_format_holder), isolate);
+
Handle<Object> number_obj;
ASSIGN_RETURN_ON_EXCEPTION(isolate, number_obj,
Object::ToNumber(isolate, num), String);
// Spec treats -0 and +0 as 0.
double number = number_obj->Number() + 0;
+
// Return FormatNumber(numberFormat, x).
- return NumberFormat::FormatNumber(isolate, number_format_holder, number);
+ return JSNumberFormat::FormatNumber(isolate, number_format, number);
}
+namespace {
+
// ecma402/#sec-defaultnumberoption
-Maybe<int> Intl::DefaultNumberOption(Isolate* isolate, Handle<Object> value,
- int min, int max, int fallback,
- Handle<String> property) {
+Maybe<int> DefaultNumberOption(Isolate* isolate, Handle<Object> value, int min,
+ int max, int fallback, Handle<String> property) {
// 2. Else, return fallback.
if (value->IsUndefined()) return Just(fallback);
@@ -2114,9 +1082,9 @@ Maybe<int> Intl::DefaultNumberOption(Isolate* isolate, Handle<Object> value,
}
// ecma402/#sec-getnumberoption
-Maybe<int> Intl::GetNumberOption(Isolate* isolate, Handle<JSReceiver> options,
- Handle<String> property, int min, int max,
- int fallback) {
+Maybe<int> GetNumberOption(Isolate* isolate, Handle<JSReceiver> options,
+ Handle<String> property, int min, int max,
+ int fallback) {
// 1. Let value be ? Get(options, property).
Handle<Object> value;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
@@ -2127,14 +1095,16 @@ Maybe<int> Intl::GetNumberOption(Isolate* isolate, Handle<JSReceiver> options,
return DefaultNumberOption(isolate, value, min, max, fallback, property);
}
-Maybe<int> Intl::GetNumberOption(Isolate* isolate, Handle<JSReceiver> options,
- const char* property, int min, int max,
- int fallback) {
+Maybe<int> GetNumberOption(Isolate* isolate, Handle<JSReceiver> options,
+ const char* property, int min, int max,
+ int fallback) {
Handle<String> property_str =
isolate->factory()->NewStringFromAsciiChecked(property);
return GetNumberOption(isolate, options, property_str, min, max, fallback);
}
+} // namespace
+
Maybe<bool> Intl::SetNumberFormatDigitOptions(Isolate* isolate,
icu::DecimalFormat* number_format,
Handle<JSReceiver> options,
@@ -2174,7 +1144,7 @@ Maybe<bool> Intl::SetNumberFormatDigitOptions(Isolate* isolate,
// 9. Let mnsd be ? Get(options, "minimumSignificantDigits").
Handle<Object> mnsd_obj;
Handle<String> mnsd_str =
- isolate->factory()->NewStringFromStaticChars("minimumSignificantDigits");
+ isolate->factory()->minimumSignificantDigits_string();
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, mnsd_obj, JSReceiver::GetProperty(isolate, options, mnsd_str),
Nothing<bool>());
@@ -2182,7 +1152,7 @@ Maybe<bool> Intl::SetNumberFormatDigitOptions(Isolate* isolate,
// 10. Let mxsd be ? Get(options, "maximumSignificantDigits").
Handle<Object> mxsd_obj;
Handle<String> mxsd_str =
- isolate->factory()->NewStringFromStaticChars("maximumSignificantDigits");
+ isolate->factory()->maximumSignificantDigits_string();
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, mxsd_obj, JSReceiver::GetProperty(isolate, options, mxsd_str),
Nothing<bool>());
@@ -2228,96 +1198,108 @@ Maybe<bool> Intl::SetNumberFormatDigitOptions(Isolate* isolate,
namespace {
-// ECMA 402 9.2.2 BestAvailableLocale(availableLocales, locale)
-// https://tc39.github.io/ecma402/#sec-bestavailablelocale
-std::string BestAvailableLocale(std::set<std::string> available_locales,
- std::string locale) {
- const char separator = '-';
-
+// ecma402/#sec-bestavailablelocale
+std::string BestAvailableLocale(const std::set<std::string>& available_locales,
+ const std::string& locale) {
// 1. Let candidate be locale.
+ std::string candidate = locale;
+
// 2. Repeat,
- do {
+ while (true) {
// 2.a. If availableLocales contains an element equal to candidate, return
// candidate.
- if (available_locales.find(locale) != available_locales.end()) {
- return locale;
+ if (available_locales.find(candidate) != available_locales.end()) {
+ return candidate;
}
+
// 2.b. Let pos be the character index of the last occurrence of "-"
// (U+002D) within candidate. If that character does not occur, return
// undefined.
- size_t pos = locale.rfind(separator);
+ size_t pos = candidate.rfind('-');
if (pos == std::string::npos) {
- return "";
+ return std::string();
}
+
// 2.c. If pos ≥ 2 and the character "-" occurs at index pos-2 of candidate,
// decrease pos by 2.
- if (pos >= 2 && locale[pos - 2] == separator) {
+ if (pos >= 2 && candidate[pos - 2] == '-') {
pos -= 2;
}
+
// 2.d. Let candidate be the substring of candidate from position 0,
// inclusive, to position pos, exclusive.
- locale = locale.substr(0, pos);
- } while (true);
+ candidate = candidate.substr(0, pos);
+ }
}
-#define ANY_EXTENSION_REGEXP "-[a-z0-9]{1}-.*"
+// Removes unicode extensions from a given bcp47 language tag.
+// For example, converts 'en-US-u-co-emoji' to 'en-US'.
+std::string RemoveUnicodeExtensions(const std::string& locale) {
+ size_t length = locale.length();
-std::unique_ptr<icu::RegexMatcher> GetAnyExtensionRegexpMatcher() {
- UErrorCode status = U_ZERO_ERROR;
- std::unique_ptr<icu::RegexMatcher> matcher(new icu::RegexMatcher(
- icu::UnicodeString(ANY_EXTENSION_REGEXP, -1, US_INV), 0, status));
- DCHECK(U_SUCCESS(status));
- return matcher;
-}
+ // Privateuse or grandfathered locales have no extension sequences.
+ if ((length > 1) && (locale[1] == '-')) {
+ // Check to make sure that this really is a grandfathered or
+ // privateuse extension. ICU can sometimes mess up the
+ // canonicalization.
+ CHECK(locale[0] == 'x' || locale[0] == 'i');
+ return locale;
+ }
-#undef ANY_EXTENSION_REGEXP
+ size_t unicode_extension_start = locale.find("-u-");
-// ECMA 402 9.2.7 LookupSupportedLocales(availableLocales, requestedLocales)
-// https://tc39.github.io/ecma402/#sec-lookupsupportedlocales
-std::vector<std::string> LookupSupportedLocales(
- std::set<std::string> available_locales,
- std::vector<std::string> requested_locales) {
- std::unique_ptr<icu::RegexMatcher> matcher = GetAnyExtensionRegexpMatcher();
+ // No unicode extensions found.
+ if (unicode_extension_start == std::string::npos) return locale;
+
+ size_t private_extension_start = locale.find("-x-");
+
+ // Unicode extensions found within privateuse subtags don't count.
+ if (private_extension_start != std::string::npos &&
+ private_extension_start < unicode_extension_start) {
+ return locale;
+ }
+
+ const std::string beginning = locale.substr(0, unicode_extension_start);
+ size_t unicode_extension_end = length;
+ DCHECK_GT(length, 2);
+
+ // Find the end of the extension production as per the bcp47 grammar
+ // by looking for '-' followed by 2 chars and then another '-'.
+ for (size_t i = unicode_extension_start + 1; i < length - 2; i++) {
+ if (locale[i] != '-') continue;
+
+ if (locale[i + 2] == '-') {
+ unicode_extension_end = i;
+ break;
+ }
+
+ i += 2;
+ }
+ const std::string end = locale.substr(unicode_extension_end);
+ return beginning + end;
+}
+
+// ecma402/#sec-lookupsupportedlocales
+std::vector<std::string> LookupSupportedLocales(
+ const std::set<std::string>& available_locales,
+ const std::vector<std::string>& requested_locales) {
// 1. Let subset be a new empty List.
std::vector<std::string> subset;
// 2. For each element locale of requestedLocales in List order, do
- for (auto locale : requested_locales) {
- // 2.a. Let noExtensionsLocale be the String value that is locale with all
- // Unicode locale extension sequences removed.
- icu::UnicodeString locale_uni(locale.c_str(), -1, US_INV);
- // TODO(bstell): look at using uloc_forLanguageTag to convert the language
- // tag to locale id
- // TODO(bstell): look at using uloc_getBaseName to just get the name without
- // all the keywords
- matcher->reset(locale_uni);
- UErrorCode status = U_ZERO_ERROR;
- // TODO(bstell): need to determine if this is the correct behavior.
- // This matches the JS implementation but might not match the spec.
- // According to
- // https://tc39.github.io/ecma402/#sec-unicode-locale-extension-sequences:
- //
- // This standard uses the term "Unicode locale extension sequence" for
- // any substring of a language tag that is not part of a private use
- // subtag sequence, starts with a separator "-" and the singleton "u",
- // and includes the maximum sequence of following non-singleton subtags
- // and their preceding "-" separators.
- //
- // According to the spec a locale "en-t-aaa-u-bbb-v-ccc-x-u-ddd", should
- // remove only the "-u-bbb" part, and keep everything else, whereas this
- // regexp matcher would leave only the "en".
- icu::UnicodeString no_extensions_locale_uni =
- matcher->replaceAll("", status);
- DCHECK(U_SUCCESS(status));
- std::string no_extensions_locale;
- no_extensions_locale_uni.toUTF8String(no_extensions_locale);
- // 2.b. Let availableLocale be BestAvailableLocale(availableLocales,
- // noExtensionsLocale).
+ for (const std::string& locale : requested_locales) {
+ // 2. a. Let noExtensionsLocale be the String value that is locale
+ // with all Unicode locale extension sequences removed.
+ std::string no_extension_locale = RemoveUnicodeExtensions(locale);
+
+ // 2. b. Let availableLocale be
+ // BestAvailableLocale(availableLocales, noExtensionsLocale).
std::string available_locale =
- BestAvailableLocale(available_locales, no_extensions_locale);
- // 2.c. If availableLocale is not undefined, append locale to the end of
- // subset.
+ BestAvailableLocale(available_locales, no_extension_locale);
+
+ // 2. c. If availableLocale is not undefined, append locale to the
+ // end of subset.
if (!available_locale.empty()) {
subset.push_back(locale);
}
@@ -2330,8 +1312,8 @@ std::vector<std::string> LookupSupportedLocales(
// ECMA 402 9.2.8 BestFitSupportedLocales(availableLocales, requestedLocales)
// https://tc39.github.io/ecma402/#sec-bestfitsupportedlocales
std::vector<std::string> BestFitSupportedLocales(
- std::set<std::string> available_locales,
- std::vector<std::string> requested_locales) {
+ const std::set<std::string>& available_locales,
+ const std::vector<std::string>& requested_locales) {
return LookupSupportedLocales(available_locales, requested_locales);
}
@@ -2378,26 +1360,28 @@ MaybeHandle<JSObject> CreateReadOnlyArray(Isolate* isolate,
// ECMA 402 9.2.9 SupportedLocales(availableLocales, requestedLocales, options)
// https://tc39.github.io/ecma402/#sec-supportedlocales
MaybeHandle<JSObject> SupportedLocales(
- Isolate* isolate, std::string service,
- std::set<std::string> available_locales,
- std::vector<std::string> requested_locales, Handle<Object> options) {
+ Isolate* isolate, ICUService service,
+ const std::set<std::string>& available_locales,
+ const std::vector<std::string>& requested_locales, Handle<Object> options) {
std::vector<std::string> supported_locales;
- // 1. If options is not undefined, then
- // a. Let options be ? ToObject(options).
- // b. Let matcher be ? GetOption(options, "localeMatcher", "string",
- // « "lookup", "best fit" », "best fit").
// 2. Else, let matcher be "best fit".
MatcherOption matcher = kBestFit;
+
+ // 1. If options is not undefined, then
if (!options->IsUndefined(isolate)) {
+ // 1. a. Let options be ? ToObject(options).
Handle<JSReceiver> options_obj;
ASSIGN_RETURN_ON_EXCEPTION(isolate, options_obj,
Object::ToObject(isolate, options), JSObject);
+
+ // 1. b. Let matcher be ? GetOption(options, "localeMatcher", "string",
+ // « "lookup", "best fit" », "best fit").
std::unique_ptr<char[]> matcher_str = nullptr;
std::vector<const char*> matcher_values = {"lookup", "best fit"};
- Maybe<bool> maybe_found_matcher =
- Intl::GetStringOption(isolate, options_obj, "localeMatcher",
- matcher_values, service.c_str(), &matcher_str);
+ Maybe<bool> maybe_found_matcher = Intl::GetStringOption(
+ isolate, options_obj, "localeMatcher", matcher_values,
+ ICUServiceToString(service), &matcher_str);
MAYBE_RETURN(maybe_found_matcher, MaybeHandle<JSObject>());
if (maybe_found_matcher.FromJust()) {
DCHECK_NOT_NULL(matcher_str.get());
@@ -2440,28 +1424,69 @@ MaybeHandle<JSObject> SupportedLocales(
}
} // namespace
-// ECMA 402 10.2.2 Intl.Collator.supportedLocalesOf
-// https://tc39.github.io/ecma402/#sec-intl.collator.supportedlocalesof
-// of Intl::SupportedLocalesOf thru JS
+// ECMA 402 Intl.*.supportedLocalesOf
MaybeHandle<JSObject> Intl::SupportedLocalesOf(Isolate* isolate,
- Handle<String> service,
- Handle<Object> locales_in,
- Handle<Object> options_in) {
+ ICUService service,
+ Handle<Object> locales,
+ Handle<Object> options) {
// Let availableLocales be %Collator%.[[AvailableLocales]].
- IcuService icu_service = Intl::StringToIcuService(service);
- std::set<std::string> available_locales = GetAvailableLocales(icu_service);
- std::vector<std::string> requested_locales;
+ std::set<std::string> available_locales = GetAvailableLocales(service);
+
// Let requestedLocales be ? CanonicalizeLocaleList(locales).
- bool got_requested_locales =
- CanonicalizeLocaleList(isolate, locales_in, false).To(&requested_locales);
- if (!got_requested_locales) {
- return MaybeHandle<JSObject>();
- }
+ Maybe<std::vector<std::string>> requested_locales =
+ CanonicalizeLocaleList(isolate, locales, false);
+ MAYBE_RETURN(requested_locales, MaybeHandle<JSObject>());
// Return ? SupportedLocales(availableLocales, requestedLocales, options).
- std::string service_str(service->ToCString().get());
- return SupportedLocales(isolate, service_str, available_locales,
- requested_locales, options_in);
+ return SupportedLocales(isolate, service, available_locales,
+ requested_locales.FromJust(), options);
+}
+
+std::map<std::string, std::string> Intl::LookupUnicodeExtensions(
+ const icu::Locale& icu_locale, const std::set<std::string>& relevant_keys) {
+ std::map<std::string, std::string> extensions;
+
+ UErrorCode status = U_ZERO_ERROR;
+ std::unique_ptr<icu::StringEnumeration> keywords(
+ icu_locale.createKeywords(status));
+ if (U_FAILURE(status)) return extensions;
+
+ if (!keywords) return extensions;
+ char value[ULOC_FULLNAME_CAPACITY];
+
+ int32_t length;
+ status = U_ZERO_ERROR;
+ for (const char* keyword = keywords->next(&length, status);
+ keyword != nullptr; keyword = keywords->next(&length, status)) {
+ // Ignore failures in ICU and skip to the next keyword.
+ //
+ // This is fine.â„¢
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ continue;
+ }
+
+ icu_locale.getKeywordValue(keyword, value, ULOC_FULLNAME_CAPACITY, status);
+
+ // Ignore failures in ICU and skip to the next keyword.
+ //
+ // This is fine.â„¢
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ continue;
+ }
+
+ const char* bcp47_key = uloc_toUnicodeLocaleKey(keyword);
+
+ // Ignore keywords that we don't recognize - spec allows that.
+ if (bcp47_key && (relevant_keys.find(bcp47_key) != relevant_keys.end())) {
+ const char* bcp47_value = uloc_toUnicodeLocaleType(bcp47_key, value);
+ extensions.insert(
+ std::pair<std::string, std::string>(bcp47_key, bcp47_value));
+ }
+ }
+
+ return extensions;
}
} // namespace internal
diff --git a/deps/v8/src/objects/intl-objects.h b/deps/v8/src/objects/intl-objects.h
index 38d11772a4..fd2842ebbb 100644
--- a/deps/v8/src/objects/intl-objects.h
+++ b/deps/v8/src/objects/intl-objects.h
@@ -20,10 +20,7 @@
#include "unicode/uversion.h"
namespace U_ICU_NAMESPACE {
-class BreakIterator;
-class Collator;
class DecimalFormat;
-class PluralRules;
class SimpleDateFormat;
class UnicodeString;
}
@@ -33,191 +30,7 @@ namespace internal {
template <typename T>
class Handle;
-
-class DateFormat {
- public:
- // Create a formatter for the specificied locale and options. Returns the
- // resolved settings for the locale / options.
- static icu::SimpleDateFormat* InitializeDateTimeFormat(
- Isolate* isolate, Handle<String> locale, Handle<JSObject> options,
- Handle<JSObject> resolved);
-
- // Unpacks date format object from corresponding JavaScript object.
- static icu::SimpleDateFormat* UnpackDateFormat(Handle<JSObject> obj);
-
- // Release memory we allocated for the DateFormat once the JS object that
- // holds the pointer gets garbage collected.
- static void DeleteDateFormat(const v8::WeakCallbackInfo<void>& data);
-
- // ecma402/#sec-formatdatetime
- // FormatDateTime( dateTimeFormat, x )
- V8_WARN_UNUSED_RESULT static MaybeHandle<String> FormatDateTime(
- Isolate* isolate, Handle<JSObject> date_time_format_holder, double x);
-
- // ecma402/#sec-datetime-format-functions
- // DateTime Format Functions
- V8_WARN_UNUSED_RESULT static MaybeHandle<String> DateTimeFormat(
- Isolate* isolate, Handle<JSObject> date_time_format_holder,
- Handle<Object> date);
-
- // The UnwrapDateTimeFormat abstract operation gets the underlying
- // DateTimeFormat operation for various methods which implement ECMA-402 v1
- // semantics for supporting initializing existing Intl objects.
- //
- // ecma402/#sec-unwrapdatetimeformat
- V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> Unwrap(
- Isolate* isolate, Handle<JSReceiver> receiver, const char* method_name);
-
- // ecma-402/#sec-todatetimeoptions
- V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> ToDateTimeOptions(
- Isolate* isolate, Handle<Object> input_options, const char* required,
- const char* defaults);
-
- V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToLocaleDateTime(
- Isolate* isolate, Handle<Object> date, Handle<Object> locales,
- Handle<Object> options, const char* required, const char* defaults,
- const char* service);
-
- // Layout description.
-#define DATE_FORMAT_FIELDS(V) \
- V(kSimpleDateFormat, kPointerSize) \
- V(kBoundFormat, kPointerSize) \
- V(kSize, 0)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, DATE_FORMAT_FIELDS)
-#undef DATE_FORMAT_FIELDS
-
- // ContextSlot defines the context structure for the bound
- // DateTimeFormat.prototype.format function
- enum ContextSlot {
- kDateFormat = Context::MIN_CONTEXT_SLOTS,
-
- kLength
- };
-
- // TODO(ryzokuken): Remove this and use regular accessors once DateFormat is a
- // subclass of JSObject
- //
- // This needs to be consistent with the above Layout Description
- static const int kSimpleDateFormatIndex = 0;
- static const int kBoundFormatIndex = 1;
-
- private:
- DateFormat();
-};
-
-class NumberFormat {
- public:
- // Create a formatter for the specificied locale and options. Returns the
- // resolved settings for the locale / options.
- static icu::DecimalFormat* InitializeNumberFormat(Isolate* isolate,
- Handle<String> locale,
- Handle<JSObject> options,
- Handle<JSObject> resolved);
-
- // Unpacks number format object from corresponding JavaScript object.
- static icu::DecimalFormat* UnpackNumberFormat(Handle<JSObject> obj);
-
- // Release memory we allocated for the NumberFormat once the JS object that
- // holds the pointer gets garbage collected.
- static void DeleteNumberFormat(const v8::WeakCallbackInfo<void>& data);
-
- // The UnwrapNumberFormat abstract operation gets the underlying
- // NumberFormat operation for various methods which implement
- // ECMA-402 v1 semantics for supporting initializing existing Intl
- // objects.
- //
- // ecma402/#sec-unwrapnumberformat
- static MaybeHandle<JSObject> Unwrap(Isolate* isolate,
- Handle<JSReceiver> receiver,
- const char* method_name);
-
- // ecm402/#sec-formatnumber
- static MaybeHandle<String> FormatNumber(Isolate* isolate,
- Handle<JSObject> number_format_holder,
- double value);
-
- // Layout description.
-#define NUMBER_FORMAT_FIELDS(V) \
- /* Pointer fields. */ \
- V(kDecimalFormat, kPointerSize) \
- V(kBoundFormat, kPointerSize) \
- V(kSize, 0)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, NUMBER_FORMAT_FIELDS)
-#undef NUMBER_FORMAT_FIELDS
-
- // ContextSlot defines the context structure for the bound
- // NumberFormat.prototype.format function.
- enum ContextSlot {
- // The number format instance that the function holding this
- // context is bound to.
- kNumberFormat = Context::MIN_CONTEXT_SLOTS,
-
- kLength
- };
-
- // TODO(gsathya): Remove this and use regular accessors once
- // NumberFormat is a sub class of JSObject.
- //
- // This needs to be consistent with the above LayoutDescription.
- static const int kDecimalFormatIndex = 0;
- static const int kBoundFormatIndex = 1;
-
- private:
- NumberFormat();
-};
-
-class V8BreakIterator {
- public:
- // Create a BreakIterator for the specificied locale and options. Returns the
- // resolved settings for the locale / options.
- static icu::BreakIterator* InitializeBreakIterator(Isolate* isolate,
- Handle<String> locale,
- Handle<JSObject> options,
- Handle<JSObject> resolved);
-
- // Unpacks break iterator object from corresponding JavaScript object.
- static icu::BreakIterator* UnpackBreakIterator(Handle<JSObject> obj);
-
- // Release memory we allocated for the BreakIterator once the JS object that
- // holds the pointer gets garbage collected.
- static void DeleteBreakIterator(const v8::WeakCallbackInfo<void>& data);
-
- static void AdoptText(Isolate* isolate,
- Handle<JSObject> break_iterator_holder,
- Handle<String> text);
-
- // Layout description.
-#define BREAK_ITERATOR_FIELDS(V) \
- /* Pointer fields. */ \
- V(kBreakIterator, kPointerSize) \
- V(kUnicodeString, kPointerSize) \
- V(kBoundAdoptText, kPointerSize) \
- V(kSize, 0)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, BREAK_ITERATOR_FIELDS)
-#undef BREAK_ITERATOR_FIELDS
-
- // ContextSlot defines the context structure for the bound
- // v8BreakIterator.prototype.adoptText function
- enum class ContextSlot {
- kV8BreakIterator = Context::MIN_CONTEXT_SLOTS,
-
- kLength
- };
-
- // TODO(ryzokuken): Remove this and use regular accessors once v8BreakIterator
- // is a subclass of JSObject
- //
- // This needs to be consistent with the above Layour Description
- static const int kBreakIteratorIndex = 0;
- static const int kUnicodeStringIndex = 1;
- static const int kBoundAdoptTextIndex = 2;
-
- private:
- V8BreakIterator();
-};
+class JSCollator;
class Intl {
public:
@@ -232,6 +45,11 @@ class Intl {
kTypeCount
};
+ enum class BoundFunctionContextSlot {
+ kBoundFunction = Context::MIN_CONTEXT_SLOTS,
+ kLength
+ };
+
inline static Intl::Type TypeFromInt(int type);
inline static Intl::Type TypeFromSmi(Smi* type);
@@ -243,41 +61,27 @@ class Intl {
static bool IsObjectOfType(Isolate* isolate, Handle<Object> object,
Intl::Type expected_type);
- static IcuService StringToIcuService(Handle<String> service);
-
// Gets the ICU locales for a given service. If there is a locale with a
// script tag then the locales also include a locale without the script; eg,
// pa_Guru_IN (language=Panjabi, script=Gurmukhi, country-India) would include
// pa_IN.
- static std::set<std::string> GetAvailableLocales(const IcuService& service);
+ static std::set<std::string> GetAvailableLocales(ICUService service);
+
+ // Get the name of the numbering system from locale.
+ // 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.
+ static std::string GetNumberingSystem(const icu::Locale& icu_locale);
static V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> AvailableLocalesOf(
Isolate* isolate, Handle<String> service);
- static MaybeHandle<JSObject> SupportedLocalesOf(Isolate* isolate,
- Handle<String> service,
- Handle<Object> locales_in,
- Handle<Object> options_in);
+ static V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> SupportedLocalesOf(
+ Isolate* isolate, ICUService service, Handle<Object> locales_in,
+ Handle<Object> options_in);
static std::string DefaultLocale(Isolate* isolate);
- static void DefineWEProperty(Isolate* isolate, Handle<JSObject> target,
- Handle<Name> key, Handle<Object> value);
-
- // If locale has a script tag then return true and the locale without the
- // script else return false and an empty string
- static bool RemoveLocaleScriptTag(const std::string& icu_locale,
- std::string* locale_less_script);
-
- // Returns the underlying Intl receiver for various methods which
- // implement ECMA-402 v1 semantics for supporting initializing
- // existing Intl objects.
- V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> UnwrapReceiver(
- Isolate* isolate, Handle<JSReceiver> receiver,
- Handle<JSFunction> constructor, Intl::Type type,
- Handle<String> method_name /* TODO(gsathya): Make this char const* */,
- bool check_legacy_constructor = false);
-
// The ResolveLocale abstract operation compares a BCP 47 language
// priority list requestedLocales against the locales in
// availableLocales and determines the best available language to
@@ -355,22 +159,10 @@ class Intl {
Isolate* isolate, Handle<Object> locales,
bool only_return_one_result = false);
- // ecma-402/#sec-currencydigits
- // The currency is expected to an all upper case string value.
- static Handle<Smi> CurrencyDigits(Isolate* isolate, Handle<String> currency);
-
- // TODO(ftang): Remove this and use ICU to the conversion in the future
- static void ParseExtension(Isolate* isolate, const std::string& extension,
- std::map<std::string, std::string>& out);
-
V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> CreateNumberFormat(
Isolate* isolate, Handle<String> locale, Handle<JSObject> options,
Handle<JSObject> resolved);
- // ecma402/#sec-iswellformedcurrencycode
- static bool IsWellFormedCurrencyCode(Isolate* isolate,
- Handle<String> currency);
-
// For locale sensitive functions
V8_WARN_UNUSED_RESULT static MaybeHandle<String> StringLocaleConvertCase(
Isolate* isolate, Handle<String> s, bool is_upper,
@@ -389,19 +181,6 @@ class Intl {
Isolate* isolate, Handle<Object> num, Handle<Object> locales,
Handle<Object> options);
- // ecma402/#sec-defaultnumberoption
- V8_WARN_UNUSED_RESULT static Maybe<int> DefaultNumberOption(
- Isolate* isolate, Handle<Object> value, int min, int max, int fallback,
- Handle<String> property);
-
- // ecma402/#sec-getnumberoption
- V8_WARN_UNUSED_RESULT static Maybe<int> GetNumberOption(
- Isolate* isolate, Handle<JSReceiver> options, Handle<String> property,
- int min, int max, int fallback);
- V8_WARN_UNUSED_RESULT static Maybe<int> GetNumberOption(
- Isolate* isolate, Handle<JSReceiver> options, const char* property,
- int min, int max, int fallback);
-
// ecma402/#sec-setnfdigitoptions
V8_WARN_UNUSED_RESULT static Maybe<bool> SetNumberFormatDigitOptions(
Isolate* isolate, icu::DecimalFormat* number_format,
@@ -434,6 +213,29 @@ class Intl {
Handle<String> field_type_string, Handle<String> value,
Handle<String> additional_property_name,
Handle<String> additional_property_value);
+
+ // A helper function to help handle Unicode Extensions in locale.
+ static std::map<std::string, std::string> LookupUnicodeExtensions(
+ const icu::Locale& icu_locale, const std::set<std::string>& relevant_keys);
+
+ // In ECMA 402 v1, Intl constructors supported a mode of operation
+ // where calling them with an existing object as a receiver would
+ // transform the receiver into the relevant Intl instance with all
+ // internal slots. In ECMA 402 v2, this capability was removed, to
+ // avoid adding internal slots on existing objects. In ECMA 402 v3,
+ // the capability was re-added as "normative optional" in a mode
+ // which chains the underlying Intl instance on any object, when the
+ // constructor is called
+ //
+ // See ecma402/#legacy-constructor.
+ V8_WARN_UNUSED_RESULT static MaybeHandle<Object> LegacyUnwrapReceiver(
+ Isolate* isolate, Handle<JSReceiver> receiver,
+ Handle<JSFunction> constructor, bool has_initialized_slot);
+
+ // A factory method to got cached objects.
+ V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> CachedOrNewService(
+ Isolate* isolate, Handle<String> service, Handle<Object> locales,
+ Handle<Object> options, Handle<Object> internal_options);
};
} // namespace internal
diff --git a/deps/v8/src/objects/js-array-buffer-inl.h b/deps/v8/src/objects/js-array-buffer-inl.h
index 43bc294d04..7bc01a8b8a 100644
--- a/deps/v8/src/objects/js-array-buffer-inl.h
+++ b/deps/v8/src/objects/js-array-buffer-inl.h
@@ -20,6 +20,14 @@ CAST_ACCESSOR(JSArrayBuffer)
CAST_ACCESSOR(JSArrayBufferView)
CAST_ACCESSOR(JSTypedArray)
+size_t JSArrayBuffer::byte_length() const {
+ return READ_UINTPTR_FIELD(this, kByteLengthOffset);
+}
+
+void JSArrayBuffer::set_byte_length(size_t value) {
+ WRITE_UINTPTR_FIELD(this, kByteLengthOffset, value);
+}
+
void* JSArrayBuffer::backing_store() const {
intptr_t ptr = READ_INTPTR_FIELD(this, kBackingStoreOffset);
return reinterpret_cast<void*>(ptr);
@@ -30,8 +38,6 @@ void JSArrayBuffer::set_backing_store(void* value, WriteBarrierMode mode) {
WRITE_INTPTR_FIELD(this, kBackingStoreOffset, ptr);
}
-ACCESSORS(JSArrayBuffer, byte_length, Object, kByteLengthOffset)
-
size_t JSArrayBuffer::allocation_length() const {
if (backing_store() == nullptr) {
return 0;
@@ -44,7 +50,7 @@ size_t JSArrayBuffer::allocation_length() const {
DCHECK_NOT_NULL(data);
return data->allocation_length;
}
- return byte_length()->Number();
+ return byte_length();
}
void* JSArrayBuffer::allocation_base() const {
@@ -63,13 +69,17 @@ void* JSArrayBuffer::allocation_base() const {
}
bool JSArrayBuffer::is_wasm_memory() const {
- bool const is_wasm_memory = IsWasmMemory::decode(bit_field());
+ bool const is_wasm_memory = IsWasmMemoryBit::decode(bit_field());
DCHECK_EQ(is_wasm_memory,
GetIsolate()->wasm_engine()->memory_tracker()->IsWasmMemory(
backing_store()));
return is_wasm_memory;
}
+void JSArrayBuffer::set_is_wasm_memory(bool is_wasm_memory) {
+ set_bit_field(IsWasmMemoryBit::update(bit_field(), is_wasm_memory));
+}
+
void JSArrayBuffer::set_bit_field(uint32_t bits) {
if (kInt32Size != kPointerSize) {
#if V8_TARGET_LITTLE_ENDIAN
@@ -85,76 +95,46 @@ uint32_t JSArrayBuffer::bit_field() const {
return READ_UINT32_FIELD(this, kBitFieldOffset);
}
-bool JSArrayBuffer::is_external() { return IsExternal::decode(bit_field()); }
-
-void JSArrayBuffer::set_is_external(bool value) {
- set_bit_field(IsExternal::update(bit_field(), value));
-}
-
-bool JSArrayBuffer::is_neuterable() {
- return IsNeuterable::decode(bit_field());
-}
-
-void JSArrayBuffer::set_is_neuterable(bool value) {
- set_bit_field(IsNeuterable::update(bit_field(), value));
-}
-
-bool JSArrayBuffer::was_neutered() { return WasNeutered::decode(bit_field()); }
-
-void JSArrayBuffer::set_was_neutered(bool value) {
- set_bit_field(WasNeutered::update(bit_field(), value));
-}
-
-bool JSArrayBuffer::is_shared() { return IsShared::decode(bit_field()); }
-
-void JSArrayBuffer::set_is_shared(bool value) {
- set_bit_field(IsShared::update(bit_field(), value));
-}
-
-bool JSArrayBuffer::is_growable() { return IsGrowable::decode(bit_field()); }
-
-void JSArrayBuffer::set_is_growable(bool value) {
- set_bit_field(IsGrowable::update(bit_field(), value));
-}
+// |bit_field| fields.
+BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_external,
+ JSArrayBuffer::IsExternalBit)
+BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_neuterable,
+ JSArrayBuffer::IsNeuterableBit)
+BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, was_neutered,
+ JSArrayBuffer::WasNeuteredBit)
+BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_shared,
+ JSArrayBuffer::IsSharedBit)
+BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_growable,
+ JSArrayBuffer::IsGrowableBit)
-Object* JSArrayBufferView::byte_offset() const {
- if (WasNeutered()) return Smi::kZero;
- return Object::cast(READ_FIELD(this, kByteOffsetOffset));
+size_t JSArrayBufferView::byte_offset() const {
+ return READ_UINTPTR_FIELD(this, kByteOffsetOffset);
}
-void JSArrayBufferView::set_byte_offset(Object* value, WriteBarrierMode mode) {
- WRITE_FIELD(this, kByteOffsetOffset, value);
- CONDITIONAL_WRITE_BARRIER(this, kByteOffsetOffset, value, mode);
+void JSArrayBufferView::set_byte_offset(size_t value) {
+ WRITE_UINTPTR_FIELD(this, kByteOffsetOffset, value);
}
-Object* JSArrayBufferView::byte_length() const {
- if (WasNeutered()) return Smi::kZero;
- return Object::cast(READ_FIELD(this, kByteLengthOffset));
+size_t JSArrayBufferView::byte_length() const {
+ return READ_UINTPTR_FIELD(this, kByteLengthOffset);
}
-void JSArrayBufferView::set_byte_length(Object* value, WriteBarrierMode mode) {
- WRITE_FIELD(this, kByteLengthOffset, value);
- CONDITIONAL_WRITE_BARRIER(this, kByteLengthOffset, value, mode);
+void JSArrayBufferView::set_byte_length(size_t value) {
+ WRITE_UINTPTR_FIELD(this, kByteLengthOffset, value);
}
ACCESSORS(JSArrayBufferView, buffer, Object, kBufferOffset)
-#ifdef VERIFY_HEAP
-ACCESSORS(JSArrayBufferView, raw_byte_offset, Object, kByteOffsetOffset)
-ACCESSORS(JSArrayBufferView, raw_byte_length, Object, kByteLengthOffset)
-#endif
bool JSArrayBufferView::WasNeutered() const {
return JSArrayBuffer::cast(buffer())->was_neutered();
}
Object* JSTypedArray::length() const {
- if (WasNeutered()) return Smi::kZero;
return Object::cast(READ_FIELD(this, kLengthOffset));
}
size_t JSTypedArray::length_value() const {
- if (WasNeutered()) return 0;
- double val = Object::cast(READ_FIELD(this, kLengthOffset))->Number();
+ double val = length()->Number();
DCHECK_LE(val, kMaxSafeInteger); // 2^53-1
DCHECK_GE(val, -kMaxSafeInteger); // -2^53+1
DCHECK_LE(val, std::numeric_limits<size_t>::max());
diff --git a/deps/v8/src/objects/js-array-buffer.cc b/deps/v8/src/objects/js-array-buffer.cc
index 5ff7828ead..36950f9de6 100644
--- a/deps/v8/src/objects/js-array-buffer.cc
+++ b/deps/v8/src/objects/js-array-buffer.cc
@@ -41,7 +41,7 @@ void JSArrayBuffer::Neuter() {
CHECK(!was_neutered());
CHECK(is_external());
set_backing_store(nullptr);
- set_byte_length(Smi::kZero);
+ set_byte_length(0);
set_was_neutered(true);
set_is_neuterable(false);
// Invalidate the neutering protector.
@@ -51,13 +51,6 @@ void JSArrayBuffer::Neuter() {
}
}
-void JSArrayBuffer::StopTrackingWasmMemory(Isolate* isolate) {
- DCHECK(is_wasm_memory());
- isolate->wasm_engine()->memory_tracker()->ReleaseAllocation(isolate,
- backing_store());
- set_is_wasm_memory(false);
-}
-
void JSArrayBuffer::FreeBackingStoreFromMainThread() {
if (allocation_base() == nullptr) {
return;
@@ -76,7 +69,8 @@ void JSArrayBuffer::FreeBackingStore(Isolate* isolate, Allocation allocation) {
isolate->wasm_engine()->memory_tracker();
if (!memory_tracker->FreeMemoryIfIsWasmMemory(isolate,
allocation.backing_store)) {
- CHECK(FreePages(allocation.allocation_base, allocation.length));
+ CHECK(FreePages(GetPlatformPageAllocator(), allocation.allocation_base,
+ allocation.length));
}
} else {
isolate->array_buffer_allocator()->Free(allocation.allocation_base,
@@ -84,28 +78,21 @@ void JSArrayBuffer::FreeBackingStore(Isolate* isolate, Allocation allocation) {
}
}
-void JSArrayBuffer::set_is_wasm_memory(bool is_wasm_memory) {
- set_bit_field(IsWasmMemory::update(bit_field(), is_wasm_memory));
-}
-
void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
bool is_external, void* data, size_t byte_length,
- SharedFlag shared, bool is_wasm_memory) {
+ SharedFlag shared_flag, bool is_wasm_memory) {
DCHECK_EQ(array_buffer->GetEmbedderFieldCount(),
v8::ArrayBuffer::kEmbedderFieldCount);
+ DCHECK_LE(byte_length, JSArrayBuffer::kMaxByteLength);
for (int i = 0; i < v8::ArrayBuffer::kEmbedderFieldCount; i++) {
array_buffer->SetEmbedderField(i, Smi::kZero);
}
+ array_buffer->set_byte_length(byte_length);
array_buffer->set_bit_field(0);
array_buffer->set_is_external(is_external);
- array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared);
- array_buffer->set_is_shared(shared == SharedFlag::kShared);
+ array_buffer->set_is_neuterable(shared_flag == SharedFlag::kNotShared);
+ array_buffer->set_is_shared(shared_flag == SharedFlag::kShared);
array_buffer->set_is_wasm_memory(is_wasm_memory);
-
- Handle<Object> heap_byte_length =
- isolate->factory()->NewNumberFromSize(byte_length);
- CHECK(heap_byte_length->IsSmi() || heap_byte_length->IsHeapNumber());
- array_buffer->set_byte_length(*heap_byte_length);
// Initialize backing store at last to avoid handling of |JSArrayBuffers| that
// are currently being constructed in the |ArrayBufferTracker|. The
// registration method below handles the case of registering a buffer that has
@@ -120,14 +107,15 @@ void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
Isolate* isolate,
size_t allocated_length,
- bool initialize, SharedFlag shared) {
+ bool initialize,
+ SharedFlag shared_flag) {
void* data;
CHECK_NOT_NULL(isolate->array_buffer_allocator());
if (allocated_length != 0) {
if (allocated_length >= MB)
isolate->counters()->array_buffer_big_allocations()->AddSample(
ConvertToMb(allocated_length));
- if (shared == SharedFlag::kShared)
+ if (shared_flag == SharedFlag::kShared)
isolate->counters()->shared_array_allocations()->AddSample(
ConvertToMb(allocated_length));
if (initialize) {
@@ -147,7 +135,7 @@ bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
const bool is_external = false;
JSArrayBuffer::Setup(array_buffer, isolate, is_external, data,
- allocated_length, shared);
+ allocated_length, shared_flag);
return true;
}
@@ -175,9 +163,8 @@ Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
"JSTypedArray::MaterializeArrayBuffer");
}
buffer->set_is_external(false);
- DCHECK(buffer->byte_length()->IsSmi() ||
- buffer->byte_length()->IsHeapNumber());
- DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize());
+ DCHECK_EQ(buffer->byte_length(),
+ static_cast<uintptr_t>(fixed_typed_array->DataSize()));
// Initialize backing store at last to avoid handling of |JSArrayBuffers| that
// are currently being constructed in the |ArrayBufferTracker|. The
// registration method below handles the case of registering a buffer that has
@@ -234,9 +221,9 @@ Maybe<bool> JSTypedArray::DefineOwnProperty(Isolate* isolate,
NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
}
// 3b iv. Let length be O.[[ArrayLength]].
- uint32_t length = o->length()->Number();
+ size_t length = o->length_value();
// 3b v. If numericIndex ≥ length, return false.
- if (index >= length) {
+ if (o->WasNeutered() || index >= length) {
RETURN_FAILURE(isolate, should_throw,
NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
}
diff --git a/deps/v8/src/objects/js-array-buffer.h b/deps/v8/src/objects/js-array-buffer.h
index 109aacbc47..3f0dd064fa 100644
--- a/deps/v8/src/objects/js-array-buffer.h
+++ b/deps/v8/src/objects/js-array-buffer.h
@@ -5,7 +5,7 @@
#ifndef V8_OBJECTS_JS_ARRAY_BUFFER_H_
#define V8_OBJECTS_JS_ARRAY_BUFFER_H_
-#include "src/objects.h"
+#include "src/objects/js-objects.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
@@ -14,12 +14,22 @@ namespace v8 {
namespace internal {
// Whether a JSArrayBuffer is a SharedArrayBuffer or not.
-enum class SharedFlag { kNotShared, kShared };
+enum class SharedFlag : uint32_t { kNotShared, kShared };
class JSArrayBuffer : public JSObject {
public:
+// The maximum length for JSArrayBuffer's supported by V8.
+// On 32-bit architectures we limit this to 2GiB, so that
+// we can continue to use CheckBounds with the Unsigned31
+// restriction for the length.
+#if V8_HOST_ARCH_32_BIT
+ static constexpr size_t kMaxByteLength = kMaxInt;
+#else
+ static constexpr size_t kMaxByteLength = kMaxSafeInteger;
+#endif
+
// [byte_length]: length in bytes
- DECL_ACCESSORS(byte_length, Object)
+ DECL_PRIMITIVE_ACCESSORS(byte_length, size_t)
// [backing_store]: backing memory for this array
DECL_ACCESSORS(backing_store, void)
@@ -29,26 +39,39 @@ class JSArrayBuffer : public JSObject {
inline size_t allocation_length() const;
inline void* allocation_base() const;
- inline uint32_t bit_field() const;
- inline void set_bit_field(uint32_t bits);
+ // [bit_field]: boolean flags
+ DECL_PRIMITIVE_ACCESSORS(bit_field, uint32_t)
+
+// Bit positions for [bit_field].
+#define JS_ARRAY_BUFFER_BIT_FIELD_FIELDS(V, _) \
+ V(IsExternalBit, bool, 1, _) \
+ V(IsNeuterableBit, bool, 1, _) \
+ V(WasNeuteredBit, bool, 1, _) \
+ V(IsSharedBit, bool, 1, _) \
+ V(IsGrowableBit, bool, 1, _) \
+ V(IsWasmMemoryBit, bool, 1, _)
+ DEFINE_BIT_FIELDS(JS_ARRAY_BUFFER_BIT_FIELD_FIELDS)
+#undef JS_ARRAY_BUFFER_BIT_FIELD_FIELDS
// [is_external]: true indicates that the embedder is in charge of freeing the
// backing_store, while is_external == false means that v8 will free the
// memory block once all ArrayBuffers referencing it are collected by the GC.
- inline bool is_external();
- inline void set_is_external(bool value);
+ DECL_BOOLEAN_ACCESSORS(is_external)
+
+ // [is_neuterable]: false indicates that this buffer cannot be detached.
+ DECL_BOOLEAN_ACCESSORS(is_neuterable)
- inline bool is_neuterable();
- inline void set_is_neuterable(bool value);
+ // [was_neutered]: true if the buffer was previously detached.
+ DECL_BOOLEAN_ACCESSORS(was_neutered)
- inline bool was_neutered();
- inline void set_was_neutered(bool value);
+ // [is_shared]: tells whether this is an ArrayBuffer or a SharedArrayBuffer.
+ DECL_BOOLEAN_ACCESSORS(is_shared)
- inline bool is_shared();
- inline void set_is_shared(bool value);
+ // [is_growable]: indicates whether it's possible to grow this buffer.
+ DECL_BOOLEAN_ACCESSORS(is_growable)
- inline bool is_growable();
- inline void set_is_growable(bool value);
+ // [is_wasm_memory]: whether the buffer is tracked by the WasmMemoryTracker.
+ DECL_BOOLEAN_ACCESSORS(is_wasm_memory)
DECL_CAST(JSArrayBuffer)
@@ -68,39 +91,30 @@ class JSArrayBuffer : public JSObject {
bool is_wasm_memory;
};
- // Returns whether the buffer is tracked by the WasmMemoryTracker.
- inline bool is_wasm_memory() const;
-
- // Sets whether the buffer is tracked by the WasmMemoryTracker.
- void set_is_wasm_memory(bool is_wasm_memory);
-
- // Removes the backing store from the WasmMemoryTracker and sets
- // |is_wasm_memory| to false.
- void StopTrackingWasmMemory(Isolate* isolate);
-
void FreeBackingStoreFromMainThread();
static void FreeBackingStore(Isolate* isolate, Allocation allocation);
V8_EXPORT_PRIVATE static void Setup(
Handle<JSArrayBuffer> array_buffer, Isolate* isolate, bool is_external,
void* data, size_t allocated_length,
- SharedFlag shared = SharedFlag::kNotShared, bool is_wasm_memory = false);
+ SharedFlag shared_flag = SharedFlag::kNotShared,
+ bool is_wasm_memory = false);
// Returns false if array buffer contents could not be allocated.
// In this case, |array_buffer| will not be set up.
static bool SetupAllocatingData(
Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
size_t allocated_length, bool initialize = true,
- SharedFlag shared = SharedFlag::kNotShared) V8_WARN_UNUSED_RESULT;
+ SharedFlag shared_flag = SharedFlag::kNotShared) V8_WARN_UNUSED_RESULT;
// Dispatched behavior.
DECL_PRINTER(JSArrayBuffer)
DECL_VERIFIER(JSArrayBuffer)
- static const int kByteLengthOffset = JSObject::kHeaderSize;
- // The rest of the fields are not JSObjects, so they are not iterated over in
+ // The fields are not pointers into our heap, so they are not iterated over in
// objects-body-descriptors-inl.h.
- static const int kBackingStoreOffset = kByteLengthOffset + kPointerSize;
+ static const int kByteLengthOffset = JSObject::kHeaderSize;
+ static const int kBackingStoreOffset = kByteLengthOffset + kUIntptrSize;
static const int kBitFieldSlot = kBackingStoreOffset + kPointerSize;
#if V8_TARGET_LITTLE_ENDIAN || !V8_HOST_ARCH_64_BIT
static const int kBitFieldOffset = kBitFieldSlot;
@@ -115,15 +129,6 @@ class JSArrayBuffer : public JSObject {
// Iterates all fields in the object including internal ones except
// kBackingStoreOffset and kBitFieldSlot.
class BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
-
- class IsExternal : public BitField<bool, 1, 1> {};
- class IsNeuterable : public BitField<bool, 2, 1> {};
- class WasNeutered : public BitField<bool, 3, 1> {};
- class IsShared : public BitField<bool, 4, 1> {};
- class IsGrowable : public BitField<bool, 5, 1> {};
- class IsWasmMemory : public BitField<bool, 6, 1> {};
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBuffer);
@@ -135,10 +140,10 @@ class JSArrayBufferView : public JSObject {
DECL_ACCESSORS(buffer, Object)
// [byte_offset]: offset of typed array in bytes.
- DECL_ACCESSORS(byte_offset, Object)
+ DECL_PRIMITIVE_ACCESSORS(byte_offset, size_t)
// [byte_length]: length of typed array in bytes.
- DECL_ACCESSORS(byte_length, Object)
+ DECL_PRIMITIVE_ACCESSORS(byte_length, size_t)
DECL_CAST(JSArrayBufferView)
@@ -148,15 +153,14 @@ class JSArrayBufferView : public JSObject {
static const int kBufferOffset = JSObject::kHeaderSize;
static const int kByteOffsetOffset = kBufferOffset + kPointerSize;
- static const int kByteLengthOffset = kByteOffsetOffset + kPointerSize;
- static const int kViewSize = kByteLengthOffset + kPointerSize;
+ static const int kByteLengthOffset = kByteOffsetOffset + kUIntptrSize;
+ static const int kHeaderSize = kByteLengthOffset + kUIntptrSize;
- private:
-#ifdef VERIFY_HEAP
- DECL_ACCESSORS(raw_byte_offset, Object)
- DECL_ACCESSORS(raw_byte_length, Object)
-#endif
+ // Iterates all fields in the object including internal ones except
+ // kByteOffset and kByteLengthOffset.
+ class BodyDescriptor;
+ private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBufferView);
};
@@ -189,9 +193,8 @@ class JSTypedArray : public JSArrayBufferView {
DECL_PRINTER(JSTypedArray)
DECL_VERIFIER(JSTypedArray)
- static const int kLengthOffset = kViewSize;
+ static const int kLengthOffset = JSArrayBufferView::kHeaderSize;
static const int kSize = kLengthOffset + kPointerSize;
-
static const int kSizeWithEmbedderFields =
kSize + v8::ArrayBufferView::kEmbedderFieldCount * kPointerSize;
@@ -213,8 +216,7 @@ class JSDataView : public JSArrayBufferView {
DECL_PRINTER(JSDataView)
DECL_VERIFIER(JSDataView)
- static const int kSize = kViewSize;
-
+ static const int kSize = JSArrayBufferView::kHeaderSize;
static const int kSizeWithEmbedderFields =
kSize + v8::ArrayBufferView::kEmbedderFieldCount * kPointerSize;
diff --git a/deps/v8/src/objects/js-array.h b/deps/v8/src/objects/js-array.h
index b212848ce7..3a9fe48d24 100644
--- a/deps/v8/src/objects/js-array.h
+++ b/deps/v8/src/objects/js-array.h
@@ -5,8 +5,9 @@
#ifndef V8_OBJECTS_JS_ARRAY_H_
#define V8_OBJECTS_JS_ARRAY_H_
-#include "src/objects.h"
+#include "src/objects/allocation-site.h"
#include "src/objects/fixed-array.h"
+#include "src/objects/js-objects.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
diff --git a/deps/v8/src/objects/js-break-iterator-inl.h b/deps/v8/src/objects/js-break-iterator-inl.h
new file mode 100644
index 0000000000..16f8111953
--- /dev/null
+++ b/deps/v8/src/objects/js-break-iterator-inl.h
@@ -0,0 +1,49 @@
+// Copyright 2018 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_INTL_SUPPORT
+#error Internationalization is expected to be enabled.
+#endif // V8_INTL_SUPPORT
+
+#ifndef V8_OBJECTS_JS_BREAK_ITERATOR_INL_H_
+#define V8_OBJECTS_JS_BREAK_ITERATOR_INL_H_
+
+#include "src/objects-inl.h"
+#include "src/objects/js-break-iterator.h"
+
+// Has to be the last include (doesn't have include guards):
+#include "src/objects/object-macros.h"
+
+namespace v8 {
+namespace internal {
+
+inline void JSV8BreakIterator::set_type(Type type) {
+ DCHECK_GT(JSV8BreakIterator::Type::COUNT, type);
+ WRITE_FIELD(this, kTypeOffset, Smi::FromInt(static_cast<int>(type)));
+}
+
+inline JSV8BreakIterator::Type JSV8BreakIterator::type() const {
+ Object* value = READ_FIELD(this, kTypeOffset);
+ return static_cast<JSV8BreakIterator::Type>(Smi::ToInt(value));
+}
+
+ACCESSORS(JSV8BreakIterator, locale, String, kLocaleOffset)
+ACCESSORS(JSV8BreakIterator, break_iterator, Managed<icu::BreakIterator>,
+ kBreakIteratorOffset)
+ACCESSORS(JSV8BreakIterator, unicode_string, Managed<icu::UnicodeString>,
+ kUnicodeStringOffset)
+ACCESSORS(JSV8BreakIterator, bound_adopt_text, Object, kBoundAdoptTextOffset)
+ACCESSORS(JSV8BreakIterator, bound_first, Object, kBoundFirstOffset)
+ACCESSORS(JSV8BreakIterator, bound_next, Object, kBoundNextOffset)
+ACCESSORS(JSV8BreakIterator, bound_current, Object, kBoundCurrentOffset)
+ACCESSORS(JSV8BreakIterator, bound_break_type, Object, kBoundBreakTypeOffset)
+
+CAST_ACCESSOR(JSV8BreakIterator)
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_JS_BREAK_ITERATOR_INL_H_
diff --git a/deps/v8/src/objects/js-break-iterator.cc b/deps/v8/src/objects/js-break-iterator.cc
new file mode 100644
index 0000000000..2031c2cc5b
--- /dev/null
+++ b/deps/v8/src/objects/js-break-iterator.cc
@@ -0,0 +1,170 @@
+// Copyright 2018 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_INTL_SUPPORT
+#error Internationalization is expected to be enabled.
+#endif // V8_INTL_SUPPORT
+
+#include "src/objects/js-break-iterator.h"
+
+#include "src/objects/intl-objects-inl.h"
+#include "src/objects/intl-objects.h"
+#include "src/objects/js-break-iterator-inl.h"
+#include "unicode/brkiter.h"
+
+namespace v8 {
+namespace internal {
+
+JSV8BreakIterator::Type JSV8BreakIterator::getType(const char* str) {
+ if (strcmp(str, "character") == 0) return Type::CHARACTER;
+ if (strcmp(str, "word") == 0) return Type::WORD;
+ if (strcmp(str, "sentence") == 0) return Type::SENTENCE;
+ if (strcmp(str, "line") == 0) return Type::LINE;
+ UNREACHABLE();
+}
+
+MaybeHandle<JSV8BreakIterator> JSV8BreakIterator::Initialize(
+ Isolate* isolate, Handle<JSV8BreakIterator> break_iterator_holder,
+ Handle<Object> locales, Handle<Object> options_obj) {
+ Factory* factory = isolate->factory();
+
+ Handle<JSReceiver> options;
+ if (options_obj->IsUndefined(isolate)) {
+ options = factory->NewJSObjectWithNullProto();
+ } else {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, options,
+ Object::ToObject(isolate, options_obj, "Intl.JSV8BreakIterator"),
+ JSV8BreakIterator);
+ }
+
+ // Extract locale string
+ Handle<JSObject> r;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, r,
+ Intl::ResolveLocale(isolate, "breakiterator", locales, options),
+ JSV8BreakIterator);
+ Handle<Object> locale_obj =
+ JSObject::GetDataProperty(r, factory->locale_string());
+ CHECK(locale_obj->IsString());
+ Handle<String> locale = Handle<String>::cast(locale_obj);
+
+ // Extract type from options
+ std::unique_ptr<char[]> type_str = nullptr;
+ std::vector<const char*> type_values = {"character", "word", "sentence",
+ "line"};
+ Maybe<bool> maybe_found_type = Intl::GetStringOption(
+ isolate, options, "type", type_values, "Intl.v8BreakIterator", &type_str);
+ Type type_enum = Type::WORD;
+ MAYBE_RETURN(maybe_found_type, MaybeHandle<JSV8BreakIterator>());
+ if (maybe_found_type.FromJust()) {
+ DCHECK_NOT_NULL(type_str.get());
+ type_enum = getType(type_str.get());
+ }
+
+ // Construct icu_locale using the locale string
+ icu::Locale icu_locale = Intl::CreateICULocale(isolate, locale);
+ DCHECK(!icu_locale.isBogus());
+
+ // Construct break_iterator using icu_locale and type
+ UErrorCode status = U_ZERO_ERROR;
+ std::unique_ptr<icu::BreakIterator> break_iterator = nullptr;
+ switch (type_enum) {
+ case Type::CHARACTER:
+ break_iterator.reset(
+ icu::BreakIterator::createCharacterInstance(icu_locale, status));
+ break;
+ case Type::SENTENCE:
+ break_iterator.reset(
+ icu::BreakIterator::createSentenceInstance(icu_locale, status));
+ break;
+ case Type::LINE:
+ break_iterator.reset(
+ icu::BreakIterator::createLineInstance(icu_locale, status));
+ break;
+ default:
+ break_iterator.reset(
+ icu::BreakIterator::createWordInstance(icu_locale, status));
+ break;
+ }
+
+ // Error handling for break_iterator
+ if (U_FAILURE(status)) {
+ FATAL("Failed to create ICU break iterator, are ICU data files missing?");
+ }
+ CHECK_NOT_NULL(break_iterator.get());
+ isolate->CountUsage(v8::Isolate::UseCounterFeature::kBreakIterator);
+
+ // Construct managed objects from pointers
+ Handle<Managed<icu::BreakIterator>> managed_break_iterator =
+ Managed<icu::BreakIterator>::FromUniquePtr(isolate, 0,
+ std::move(break_iterator));
+ Handle<Managed<icu::UnicodeString>> managed_unicode_string =
+ Managed<icu::UnicodeString>::FromRawPtr(isolate, 0, nullptr);
+
+ // Setting fields
+ break_iterator_holder->set_locale(*locale);
+ break_iterator_holder->set_type(type_enum);
+ break_iterator_holder->set_break_iterator(*managed_break_iterator);
+ break_iterator_holder->set_unicode_string(*managed_unicode_string);
+
+ // Return break_iterator_holder
+ return break_iterator_holder;
+}
+
+Handle<JSObject> JSV8BreakIterator::ResolvedOptions(
+ Isolate* isolate, Handle<JSV8BreakIterator> break_iterator) {
+ Factory* factory = isolate->factory();
+
+ Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
+ Handle<String> locale(break_iterator->locale(), isolate);
+
+ JSObject::AddProperty(isolate, result, factory->locale_string(), locale,
+ NONE);
+ JSObject::AddProperty(isolate, result, factory->type_string(),
+ break_iterator->TypeAsString(), NONE);
+ return result;
+}
+
+void JSV8BreakIterator::AdoptText(
+ Isolate* isolate, Handle<JSV8BreakIterator> break_iterator_holder,
+ Handle<String> text) {
+ icu::UnicodeString* u_text;
+ int length = text->length();
+ text = String::Flatten(isolate, text);
+ {
+ DisallowHeapAllocation no_gc;
+ String::FlatContent flat = text->GetFlatContent();
+ std::unique_ptr<uc16[]> sap;
+ const UChar* text_value = GetUCharBufferFromFlat(flat, &sap, length);
+ u_text = new icu::UnicodeString(text_value, length);
+ }
+
+ Handle<Managed<icu::UnicodeString>> new_u_text =
+ Managed<icu::UnicodeString>::FromRawPtr(isolate, 0, u_text);
+ break_iterator_holder->set_unicode_string(*new_u_text);
+
+ icu::BreakIterator* break_iterator =
+ break_iterator_holder->break_iterator()->raw();
+ CHECK_NOT_NULL(break_iterator);
+ break_iterator->setText(*u_text);
+}
+
+Handle<String> JSV8BreakIterator::TypeAsString() const {
+ switch (type()) {
+ case Type::CHARACTER:
+ return GetReadOnlyRoots().character_string_handle();
+ case Type::WORD:
+ return GetReadOnlyRoots().word_string_handle();
+ case Type::SENTENCE:
+ return GetReadOnlyRoots().sentence_string_handle();
+ case Type::LINE:
+ return GetReadOnlyRoots().line_string_handle();
+ case Type::COUNT:
+ UNREACHABLE();
+ }
+}
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/objects/js-break-iterator.h b/deps/v8/src/objects/js-break-iterator.h
new file mode 100644
index 0000000000..d5847bdaf6
--- /dev/null
+++ b/deps/v8/src/objects/js-break-iterator.h
@@ -0,0 +1,87 @@
+// Copyright 2018 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_INTL_SUPPORT
+#error Internationalization is expected to be enabled.
+#endif // V8_INTL_SUPPORT
+
+#ifndef V8_OBJECTS_JS_BREAK_ITERATOR_H_
+#define V8_OBJECTS_JS_BREAK_ITERATOR_H_
+
+#include "src/objects.h"
+#include "src/objects/intl-objects.h"
+#include "src/objects/managed.h"
+
+// Has to be the last include (doesn't have include guards):
+#include "src/objects/object-macros.h"
+
+namespace U_ICU_NAMESPACE {
+class BreakIterator;
+} // namespace U_ICU_NAMESPACE
+
+namespace v8 {
+namespace internal {
+
+class JSV8BreakIterator : public JSObject {
+ public:
+ V8_WARN_UNUSED_RESULT static MaybeHandle<JSV8BreakIterator> Initialize(
+ Isolate* isolate, Handle<JSV8BreakIterator> break_iterator_holder,
+ Handle<Object> input_locales, Handle<Object> input_options);
+
+ static Handle<JSObject> ResolvedOptions(
+ Isolate* isolate, Handle<JSV8BreakIterator> break_iterator);
+
+ static void AdoptText(Isolate* isolate,
+ Handle<JSV8BreakIterator> break_iterator_holder,
+ Handle<String> text);
+
+ enum class Type { CHARACTER, WORD, SENTENCE, LINE, COUNT };
+ inline void set_type(Type type);
+ inline Type type() const;
+
+ Handle<String> TypeAsString() const;
+
+ DECL_CAST(JSV8BreakIterator)
+ DECL_PRINTER(JSV8BreakIterator)
+ DECL_VERIFIER(JSV8BreakIterator)
+
+ DECL_ACCESSORS(locale, String)
+ DECL_ACCESSORS(break_iterator, Managed<icu::BreakIterator>)
+ DECL_ACCESSORS(unicode_string, Managed<icu::UnicodeString>)
+ DECL_ACCESSORS(bound_adopt_text, Object)
+ DECL_ACCESSORS(bound_first, Object)
+ DECL_ACCESSORS(bound_next, Object)
+ DECL_ACCESSORS(bound_current, Object)
+ DECL_ACCESSORS(bound_break_type, Object)
+
+// Layout description.
+#define BREAK_ITERATOR_FIELDS(V) \
+ /* Pointer fields. */ \
+ V(kLocaleOffset, kPointerSize) \
+ V(kTypeOffset, kPointerSize) \
+ V(kBreakIteratorOffset, kPointerSize) \
+ V(kUnicodeStringOffset, kPointerSize) \
+ V(kBoundAdoptTextOffset, kPointerSize) \
+ V(kBoundFirstOffset, kPointerSize) \
+ V(kBoundNextOffset, kPointerSize) \
+ V(kBoundCurrentOffset, kPointerSize) \
+ V(kBoundBreakTypeOffset, kPointerSize) \
+ /* Total Size */ \
+ V(kSize, 0)
+
+ DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, BREAK_ITERATOR_FIELDS)
+#undef BREAK_ITERATOR_FIELDS
+
+ private:
+ static Type getType(const char* str);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSV8BreakIterator)
+};
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_JS_BREAK_ITERATOR_H_
diff --git a/deps/v8/src/objects/js-collator-inl.h b/deps/v8/src/objects/js-collator-inl.h
index 279a8bfd49..1a94ac805c 100644
--- a/deps/v8/src/objects/js-collator-inl.h
+++ b/deps/v8/src/objects/js-collator-inl.h
@@ -20,18 +20,6 @@ namespace internal {
ACCESSORS(JSCollator, icu_collator, Managed<icu::Collator>, kICUCollatorOffset)
ACCESSORS(JSCollator, bound_compare, Object, kBoundCompareOffset);
-SMI_ACCESSORS(JSCollator, flags, kFlagsOffset)
-
-inline void JSCollator::set_usage(Usage usage) {
- DCHECK_LT(usage, Usage::COUNT);
- int hints = flags();
- hints = UsageBits::update(hints, usage);
- set_flags(hints);
-}
-
-inline JSCollator::Usage JSCollator::usage() const {
- return UsageBits::decode(flags());
-}
CAST_ACCESSOR(JSCollator);
diff --git a/deps/v8/src/objects/js-collator.cc b/deps/v8/src/objects/js-collator.cc
index c6cbecfb01..f62177b875 100644
--- a/deps/v8/src/objects/js-collator.cc
+++ b/deps/v8/src/objects/js-collator.cc
@@ -22,6 +22,11 @@ namespace internal {
namespace {
+enum class Usage {
+ SORT,
+ SEARCH,
+};
+
// TODO(gsathya): Consider internalizing the value strings.
void CreateDataPropertyForOptions(Isolate* isolate, Handle<JSObject> options,
Handle<String> key, const char* value) {
@@ -47,6 +52,13 @@ void CreateDataPropertyForOptions(Isolate* isolate, Handle<JSObject> options,
.FromJust());
}
+void toLanguageTag(const icu::Locale& locale, char* tag) {
+ UErrorCode status = U_ZERO_ERROR;
+ uloc_toLanguageTag(locale.getName(), tag, ULOC_FULLNAME_CAPACITY, FALSE,
+ &status);
+ CHECK(U_SUCCESS(status));
+}
+
} // anonymous namespace
// static
@@ -55,11 +67,6 @@ Handle<JSObject> JSCollator::ResolvedOptions(Isolate* isolate,
Handle<JSObject> options =
isolate->factory()->NewJSObject(isolate->object_function());
- JSCollator::Usage usage = collator->usage();
- CreateDataPropertyForOptions(isolate, options,
- isolate->factory()->usage_string(),
- JSCollator::UsageToString(usage));
-
icu::Collator* icu_collator = collator->icu_collator()->raw();
CHECK_NOT_NULL(icu_collator);
@@ -128,97 +135,71 @@ Handle<JSObject> JSCollator::ResolvedOptions(Isolate* isolate,
ignore_punctuation);
status = U_ZERO_ERROR;
- const char* collation;
- std::unique_ptr<icu::StringEnumeration> collation_values(
- icu_collator->getKeywordValues("co", status));
- // Collation wasn't provided as a keyword to icu, use default.
- if (status == U_ILLEGAL_ARGUMENT_ERROR) {
- CreateDataPropertyForOptions(
- isolate, options, isolate->factory()->collation_string(), "default");
- } else {
- CHECK(U_SUCCESS(status));
- CHECK_NOT_NULL(collation_values.get());
-
- int32_t length;
- status = U_ZERO_ERROR;
- collation = collation_values->next(&length, status);
- CHECK(U_SUCCESS(status));
-
- // There has to be at least one value.
- CHECK_NOT_NULL(collation);
- CreateDataPropertyForOptions(
- isolate, options, isolate->factory()->collation_string(), collation);
-
- status = U_ZERO_ERROR;
- collation_values->reset(status);
- CHECK(U_SUCCESS(status));
- }
-
- status = U_ZERO_ERROR;
- icu::Locale icu_locale = icu_collator->getLocale(ULOC_VALID_LOCALE, status);
- CHECK(U_SUCCESS(status));
- char result[ULOC_FULLNAME_CAPACITY];
- status = U_ZERO_ERROR;
- uloc_toLanguageTag(icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY,
- FALSE, &status);
+ icu::Locale icu_locale(icu_collator->getLocale(ULOC_VALID_LOCALE, status));
CHECK(U_SUCCESS(status));
- CreateDataPropertyForOptions(isolate, options,
- isolate->factory()->locale_string(), result);
-
- return options;
-}
-
-namespace {
-
-std::map<std::string, std::string> LookupUnicodeExtensions(
- const icu::Locale& icu_locale, const std::set<std::string>& relevant_keys) {
- std::map<std::string, std::string> extensions;
-
- UErrorCode status = U_ZERO_ERROR;
- std::unique_ptr<icu::StringEnumeration> keywords(
- icu_locale.createKeywords(status));
- if (U_FAILURE(status)) return extensions;
+ const char* collation = "default";
+ const char* usage = "sort";
+ const char* collation_key = "co";
+ const char* legacy_collation_key = uloc_toLegacyKey(collation_key);
+ DCHECK_NOT_NULL(legacy_collation_key);
- if (!keywords) return extensions;
- char value[ULOC_FULLNAME_CAPACITY];
-
- int32_t length;
+ char bcp47_locale_tag[ULOC_FULLNAME_CAPACITY];
+ char legacy_collation_value[ULOC_FULLNAME_CAPACITY];
status = U_ZERO_ERROR;
- for (const char* keyword = keywords->next(&length, status);
- keyword != nullptr; keyword = keywords->next(&length, status)) {
- // Ignore failures in ICU and skip to the next keyword.
- //
- // This is fine.â„¢
- if (U_FAILURE(status)) {
+ int32_t length =
+ icu_locale.getKeywordValue(legacy_collation_key, legacy_collation_value,
+ ULOC_FULLNAME_CAPACITY, status);
+
+ if (length > 0 && U_SUCCESS(status)) {
+ const char* collation_value =
+ uloc_toUnicodeLocaleType(collation_key, legacy_collation_value);
+ CHECK_NOT_NULL(collation_value);
+
+ if (strcmp(collation_value, "search") == 0) {
+ usage = "search";
+
+ // Search is disallowed as a collation value per spec. Let's
+ // use `default`, instead.
+ //
+ // https://tc39.github.io/ecma402/#sec-properties-of-intl-collator-instances
+ collation = "default";
+
+ // We clone the icu::Locale because we don't want the
+ // icu_collator to be affected when we remove the collation key
+ // below.
+ icu::Locale new_icu_locale = icu_locale;
+
+ // The spec forbids the search as a collation value in the
+ // locale tag, so let's filter it out.
status = U_ZERO_ERROR;
- continue;
- }
-
- icu_locale.getKeywordValue(keyword, value, ULOC_FULLNAME_CAPACITY, status);
+ new_icu_locale.setKeywordValue(legacy_collation_key, nullptr, status);
+ CHECK(U_SUCCESS(status));
- // Ignore failures in ICU and skip to the next keyword.
- //
- // This is fine.â„¢
- if (U_FAILURE(status)) {
- status = U_ZERO_ERROR;
- continue;
+ toLanguageTag(new_icu_locale, bcp47_locale_tag);
+ } else {
+ collation = collation_value;
+ toLanguageTag(icu_locale, bcp47_locale_tag);
}
+ } else {
+ toLanguageTag(icu_locale, bcp47_locale_tag);
+ }
- const char* bcp47_key = uloc_toUnicodeLocaleKey(keyword);
+ CreateDataPropertyForOptions(
+ isolate, options, isolate->factory()->collation_string(), collation);
- // Ignore keywords that we don't recognize - spec allows that.
- if (bcp47_key && (relevant_keys.find(bcp47_key) != relevant_keys.end())) {
- const char* bcp47_value = uloc_toUnicodeLocaleType(bcp47_key, value);
- extensions.insert(
- std::pair<std::string, std::string>(bcp47_key, bcp47_value));
- }
- }
+ CreateDataPropertyForOptions(isolate, options,
+ isolate->factory()->usage_string(), usage);
+
+ CreateDataPropertyForOptions(
+ isolate, options, isolate->factory()->locale_string(), bcp47_locale_tag);
- return extensions;
+ return options;
}
+namespace {
+
void SetCaseFirstOption(icu::Collator* icu_collator, const char* value) {
CHECK_NOT_NULL(icu_collator);
CHECK_NOT_NULL(value);
@@ -236,9 +217,10 @@ void SetCaseFirstOption(icu::Collator* icu_collator, const char* value) {
} // anonymous namespace
// static
-MaybeHandle<JSCollator> JSCollator::InitializeCollator(
- Isolate* isolate, Handle<JSCollator> collator, Handle<Object> locales,
- Handle<Object> options_obj) {
+MaybeHandle<JSCollator> JSCollator::Initialize(Isolate* isolate,
+ Handle<JSCollator> collator,
+ Handle<Object> locales,
+ Handle<Object> options_obj) {
// 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
Handle<JSObject> requested_locales;
ASSIGN_RETURN_ON_EXCEPTION(isolate, requested_locales,
@@ -264,7 +246,7 @@ MaybeHandle<JSCollator> JSCollator::InitializeCollator(
// "search" », "sort").
std::vector<const char*> values = {"sort", "search"};
std::unique_ptr<char[]> usage_str = nullptr;
- JSCollator::Usage usage = JSCollator::Usage::SORT;
+ Usage usage = Usage::SORT;
Maybe<bool> found_usage = Intl::GetStringOption(
isolate, options, "usage", values, "Intl.Collator", &usage_str);
MAYBE_RETURN(found_usage, MaybeHandle<JSCollator>());
@@ -272,21 +254,10 @@ MaybeHandle<JSCollator> JSCollator::InitializeCollator(
if (found_usage.FromJust()) {
DCHECK_NOT_NULL(usage_str.get());
if (strcmp(usage_str.get(), "search") == 0) {
- usage = JSCollator::Usage::SEARCH;
+ usage = Usage::SEARCH;
}
}
- // 5. Set collator.[[Usage]] to usage.
- collator->set_usage(usage);
-
- // 6. If usage is "sort", then
- // a. Let localeData be %Collator%.[[SortLocaleData]].
- // 7. Else,
- // a. Let localeData be %Collator%.[[SearchLocaleData]].
- //
- // The above two spec operations aren't required, the Intl spec is
- // crazy. See https://github.com/tc39/ecma402/issues/256
-
// TODO(gsathya): This is currently done as part of the
// Intl::ResolveLocale call below. Fix this once resolveLocale is
// changed to not do the lookup.
@@ -368,7 +339,7 @@ MaybeHandle<JSCollator> JSCollator::InitializeCollator(
DCHECK(!icu_locale.isBogus());
std::map<std::string, std::string> extensions =
- LookupUnicodeExtensions(icu_locale, relevant_extension_keys);
+ Intl::LookupUnicodeExtensions(icu_locale, relevant_extension_keys);
// 19. Let collation be r.[[co]].
//
@@ -386,11 +357,38 @@ MaybeHandle<JSCollator> JSCollator::InitializeCollator(
const std::string& value = co_extension_it->second;
if ((value == "search") || (value == "standard")) {
UErrorCode status = U_ZERO_ERROR;
- icu_locale.setKeywordValue("co", NULL, status);
+ const char* key = uloc_toLegacyKey("co");
+ icu_locale.setKeywordValue(key, nullptr, status);
CHECK(U_SUCCESS(status));
}
}
+ // 5. Set collator.[[Usage]] to usage.
+ //
+ // 6. If usage is "sort", then
+ // a. Let localeData be %Collator%.[[SortLocaleData]].
+ // 7. Else,
+ // a. Let localeData be %Collator%.[[SearchLocaleData]].
+ //
+ // The Intl spec doesn't allow us to use "search" as an extension
+ // value for collation as per:
+ // https://tc39.github.io/ecma402/#sec-intl-collator-internal-slots
+ //
+ // But the only way to pass the value "search" for collation from
+ // the options object to ICU is to use the 'co' extension keyword.
+ //
+ // This will need to be filtered out when creating the
+ // resolvedOptions object.
+ if (usage == Usage::SEARCH) {
+ const char* key = uloc_toLegacyKey("co");
+ CHECK_NOT_NULL(key);
+ const char* value = uloc_toLegacyType(key, "search");
+ CHECK_NOT_NULL(value);
+ UErrorCode status = U_ZERO_ERROR;
+ icu_locale.setKeywordValue(key, value, status);
+ CHECK(U_SUCCESS(status));
+ }
+
// 20. If collation is null, let collation be "default".
// 21. Set collator.[[Collation]] to collation.
//
@@ -525,17 +523,5 @@ MaybeHandle<JSCollator> JSCollator::InitializeCollator(
return collator;
}
-// static
-const char* JSCollator::UsageToString(Usage usage) {
- switch (usage) {
- case Usage::SORT:
- return "sort";
- case Usage::SEARCH:
- return "search";
- case Usage::COUNT:
- UNREACHABLE();
- }
-}
-
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/objects/js-collator.h b/deps/v8/src/objects/js-collator.h
index b2751a446e..f857df95b1 100644
--- a/deps/v8/src/objects/js-collator.h
+++ b/deps/v8/src/objects/js-collator.h
@@ -18,13 +18,17 @@
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
+namespace U_ICU_NAMESPACE {
+class Collator;
+} // namespace U_ICU_NAMESPACE
+
namespace v8 {
namespace internal {
class JSCollator : public JSObject {
public:
// ecma402/#sec-initializecollator
- V8_WARN_UNUSED_RESULT static MaybeHandle<JSCollator> InitializeCollator(
+ V8_WARN_UNUSED_RESULT static MaybeHandle<JSCollator> Initialize(
Isolate* isolate, Handle<JSCollator> collator, Handle<Object> locales,
Handle<Object> options);
@@ -36,22 +40,9 @@ class JSCollator : public JSObject {
DECL_PRINTER(JSCollator)
DECL_VERIFIER(JSCollator)
- // [[Usage]] is one of the values "sort" or "search", identifying
- // the collator usage.
- enum class Usage {
- SORT,
- SEARCH,
-
- COUNT
- };
- inline void set_usage(Usage usage);
- inline Usage usage() const;
- static const char* UsageToString(Usage usage);
-
// Layout description.
#define JS_COLLATOR_FIELDS(V) \
V(kICUCollatorOffset, kPointerSize) \
- V(kFlagsOffset, kPointerSize) \
V(kBoundCompareOffset, kPointerSize) \
/* Total size. */ \
V(kSize, 0)
@@ -59,26 +50,8 @@ class JSCollator : public JSObject {
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, JS_COLLATOR_FIELDS)
#undef JS_COLLATOR_FIELDS
- // ContextSlot defines the context structure for the bound
- // Collator.prototype.compare function.
- enum ContextSlot {
- // The collator instance that the function holding this context is bound to.
- kCollator = Context::MIN_CONTEXT_SLOTS,
- kLength
- };
-
-// Bit positions in |flags|.
-#define FLAGS_BIT_FIELDS(V, _) V(UsageBits, Usage, 1, _)
-
- DEFINE_BIT_FIELDS(FLAGS_BIT_FIELDS)
-#undef FLAGS_BIT_FIELDS
-
- STATIC_ASSERT(Usage::SORT <= UsageBits::kMax);
- STATIC_ASSERT(Usage::SEARCH <= UsageBits::kMax);
-
DECL_ACCESSORS(icu_collator, Managed<icu::Collator>)
DECL_ACCESSORS(bound_compare, Object);
- DECL_INT_ACCESSORS(flags)
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSCollator);
diff --git a/deps/v8/src/objects/js-collection.h b/deps/v8/src/objects/js-collection.h
index 47bb7a9c2a..7b5e38e7d8 100644
--- a/deps/v8/src/objects/js-collection.h
+++ b/deps/v8/src/objects/js-collection.h
@@ -113,9 +113,6 @@ class JSWeakCollection : public JSObject {
// Visit the whole object.
typedef BodyDescriptorImpl BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
-
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSWeakCollection);
};
diff --git a/deps/v8/src/objects/js-date-time-format-inl.h b/deps/v8/src/objects/js-date-time-format-inl.h
new file mode 100644
index 0000000000..0ad7f363c5
--- /dev/null
+++ b/deps/v8/src/objects/js-date-time-format-inl.h
@@ -0,0 +1,33 @@
+// Copyright 2018 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_INTL_SUPPORT
+#error Internationalization is expected to be enabled.
+#endif // V8_INTL_SUPPORT
+
+#ifndef V8_OBJECTS_JS_DATE_TIME_FORMAT_INL_H_
+#define V8_OBJECTS_JS_DATE_TIME_FORMAT_INL_H_
+
+#include "src/objects-inl.h"
+#include "src/objects/js-date-time-format.h"
+
+// Has to be the last include (doesn't have include guards):
+#include "src/objects/object-macros.h"
+
+namespace v8 {
+namespace internal {
+
+ACCESSORS(JSDateTimeFormat, icu_locale, Managed<icu::Locale>, kICULocaleOffset);
+ACCESSORS(JSDateTimeFormat, icu_simple_date_format,
+ Managed<icu::SimpleDateFormat>, kICUSimpleDateFormatOffset)
+ACCESSORS(JSDateTimeFormat, bound_format, Object, kBoundFormatOffset);
+
+CAST_ACCESSOR(JSDateTimeFormat);
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_JS_DATE_TIME_FORMAT_INL_H_
diff --git a/deps/v8/src/objects/js-date-time-format.cc b/deps/v8/src/objects/js-date-time-format.cc
new file mode 100644
index 0000000000..6285b74b04
--- /dev/null
+++ b/deps/v8/src/objects/js-date-time-format.cc
@@ -0,0 +1,980 @@
+// Copyright 2018 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_INTL_SUPPORT
+#error Internationalization is expected to be enabled.
+#endif // V8_INTL_SUPPORT
+
+#include "src/objects/js-date-time-format.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "src/heap/factory.h"
+#include "src/isolate.h"
+#include "src/objects/intl-objects.h"
+#include "src/objects/js-date-time-format-inl.h"
+
+#include "unicode/calendar.h"
+#include "unicode/dtptngen.h"
+#include "unicode/gregocal.h"
+#include "unicode/numsys.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/unistr.h"
+
+namespace v8 {
+namespace internal {
+
+namespace {
+
+class PatternMap {
+ public:
+ PatternMap(std::string pattern, std::string value)
+ : pattern(std::move(pattern)), value(std::move(value)) {}
+ virtual ~PatternMap() = default;
+ std::string pattern;
+ std::string value;
+};
+
+class PatternItem {
+ public:
+ PatternItem(const std::string property, std::vector<PatternMap> pairs,
+ std::vector<const char*> allowed_values)
+ : property(std::move(property)),
+ pairs(std::move(pairs)),
+ allowed_values(allowed_values) {}
+ virtual ~PatternItem() = default;
+
+ const std::string property;
+ // It is important for the pattern in the pairs from longer one to shorter one
+ // if the longer one contains substring of an shorter one.
+ std::vector<PatternMap> pairs;
+ std::vector<const char*> allowed_values;
+};
+
+const std::vector<PatternItem> GetPatternItems() {
+ const std::vector<const char*> kLongShort = {"long", "short"};
+ const std::vector<const char*> kNarrowLongShort = {"narrow", "long", "short"};
+ const std::vector<const char*> k2DigitNumeric = {"2-digit", "numeric"};
+ const std::vector<const char*> kNarrowLongShort2DigitNumeric = {
+ "narrow", "long", "short", "2-digit", "numeric"};
+ const std::vector<PatternItem> kPatternItems = {
+ PatternItem("weekday",
+ {{"EEEEE", "narrow"}, {"EEEE", "long"}, {"EEE", "short"}},
+ kNarrowLongShort),
+ PatternItem("era",
+ {{"GGGGG", "narrow"}, {"GGGG", "long"}, {"GGG", "short"}},
+ kNarrowLongShort),
+ PatternItem("year", {{"yy", "2-digit"}, {"y", "numeric"}},
+ k2DigitNumeric),
+ // Sometimes we get L instead of M for month - standalone name.
+ PatternItem("month",
+ {{"MMMMM", "narrow"},
+ {"MMMM", "long"},
+ {"MMM", "short"},
+ {"MM", "2-digit"},
+ {"M", "numeric"},
+ {"LLLLL", "narrow"},
+ {"LLLL", "long"},
+ {"LLL", "short"},
+ {"LL", "2-digit"},
+ {"L", "numeric"}},
+ kNarrowLongShort2DigitNumeric),
+ PatternItem("day", {{"dd", "2-digit"}, {"d", "numeric"}}, k2DigitNumeric),
+ PatternItem("hour",
+ {{"HH", "2-digit"},
+ {"H", "numeric"},
+ {"hh", "2-digit"},
+ {"h", "numeric"}},
+ k2DigitNumeric),
+ PatternItem("minute", {{"mm", "2-digit"}, {"m", "numeric"}},
+ k2DigitNumeric),
+ PatternItem("second", {{"ss", "2-digit"}, {"s", "numeric"}},
+ k2DigitNumeric),
+ PatternItem("timeZoneName", {{"zzzz", "long"}, {"z", "short"}},
+ kLongShort)};
+ return kPatternItems;
+}
+
+class PatternData {
+ public:
+ PatternData(const std::string property, std::vector<PatternMap> pairs,
+ std::vector<const char*> allowed_values)
+ : property(std::move(property)), allowed_values(allowed_values) {
+ for (const auto& pair : pairs) {
+ map.insert(std::make_pair(pair.value, pair.pattern));
+ }
+ }
+ virtual ~PatternData() = default;
+
+ const std::string property;
+ std::map<const std::string, const std::string> map;
+ std::vector<const char*> allowed_values;
+};
+
+enum HourOption {
+ H_UNKNOWN,
+ H_12,
+ H_24,
+};
+
+const std::vector<PatternData> CreateCommonData(const PatternData& hour_data) {
+ std::vector<PatternData> build;
+ for (const PatternItem& item : GetPatternItems()) {
+ if (item.property == "hour") {
+ build.push_back(hour_data);
+ } else {
+ build.push_back(
+ PatternData(item.property, item.pairs, item.allowed_values));
+ }
+ }
+ return build;
+}
+
+const std::vector<PatternData> CreateData(const char* digit2,
+ const char* numeric) {
+ static std::vector<const char*> k2DigitNumeric = {"2-digit", "numeric"};
+ return CreateCommonData(PatternData(
+ "hour", {{digit2, "2-digit"}, {numeric, "numeric"}}, k2DigitNumeric));
+}
+
+const std::vector<PatternData> GetPatternData(HourOption option) {
+ const std::vector<PatternData> data = CreateData("jj", "j");
+ const std::vector<PatternData> data_h12 = CreateData("hh", "h");
+ const std::vector<PatternData> data_h24 = CreateData("HH", "H");
+ switch (option) {
+ case HourOption::H_12:
+ return data_h12;
+ case HourOption::H_24:
+ return data_h24;
+ case HourOption::H_UNKNOWN:
+ return data;
+ }
+}
+
+void SetPropertyFromPattern(Isolate* isolate, const std::string& pattern,
+ Handle<JSObject> options) {
+ Factory* factory = isolate->factory();
+ const std::vector<PatternItem> items = GetPatternItems();
+ for (const auto& item : items) {
+ for (const auto& pair : item.pairs) {
+ if (pattern.find(pair.pattern) != std::string::npos) {
+ // After we find the first pair in the item which matching the pattern,
+ // we set the property and look for the next item in kPatternItems.
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options,
+ factory->NewStringFromAsciiChecked(item.property.c_str()),
+ factory->NewStringFromAsciiChecked(pair.value.c_str()),
+ kDontThrow)
+ .FromJust());
+ break;
+ }
+ }
+ }
+ // hour12
+ // b. If p is "hour12", then
+ // i. Let hc be dtf.[[HourCycle]].
+ // ii. If hc is "h11" or "h12", let v be true.
+ // iii. Else if, hc is "h23" or "h24", let v be false.
+ // iv. Else, let v be undefined.
+ if (pattern.find('h') != std::string::npos) {
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options, factory->NewStringFromStaticChars("hour12"),
+ factory->true_value(), kDontThrow)
+ .FromJust());
+ } else if (pattern.find('H') != std::string::npos) {
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options, factory->NewStringFromStaticChars("hour12"),
+ factory->false_value(), kDontThrow)
+ .FromJust());
+ }
+}
+
+std::string GetGMTTzID(Isolate* isolate, const std::string& input) {
+ std::string ret = "Etc/GMT";
+ switch (input.length()) {
+ case 8:
+ if (input[7] == '0') return ret + '0';
+ break;
+ case 9:
+ if ((input[7] == '+' || input[7] == '-') &&
+ IsInRange(input[8], '0', '9')) {
+ return ret + input[7] + input[8];
+ }
+ break;
+ case 10:
+ if ((input[7] == '+' || input[7] == '-') && (input[8] == '1') &&
+ IsInRange(input[9], '0', '4')) {
+ return ret + input[7] + input[8] + input[9];
+ }
+ break;
+ }
+ return "";
+}
+
+// Locale independenty version of isalpha for ascii range. This will return
+// false if the ch is alpha but not in ascii range.
+bool IsAsciiAlpha(char ch) {
+ return IsInRange(ch, 'A', 'Z') || IsInRange(ch, 'a', 'z');
+}
+
+// Locale independent toupper for ascii range. This will not return Ä° (dotted I)
+// for i under Turkish locale while std::toupper may.
+char LocaleIndependentAsciiToUpper(char ch) {
+ return (IsInRange(ch, 'a', 'z')) ? (ch - 'a' + 'A') : ch;
+}
+
+// Locale independent tolower for ascii range.
+char LocaleIndependentAsciiToLower(char ch) {
+ return (IsInRange(ch, 'A', 'Z')) ? (ch - 'A' + 'a') : ch;
+}
+
+// Returns titlecased location, bueNos_airES -> Buenos_Aires
+// or ho_cHi_minH -> Ho_Chi_Minh. It is locale-agnostic and only
+// deals with ASCII only characters.
+// 'of', 'au' and 'es' are special-cased and lowercased.
+// ICU's timezone parsing is case sensitive, but ECMAScript is case insensitive
+std::string ToTitleCaseTimezoneLocation(Isolate* isolate,
+ const std::string& input) {
+ std::string title_cased;
+ int word_length = 0;
+ for (char ch : input) {
+ // Convert first char to upper case, the rest to lower case
+ if (IsAsciiAlpha(ch)) {
+ title_cased += word_length == 0 ? LocaleIndependentAsciiToUpper(ch)
+ : LocaleIndependentAsciiToLower(ch);
+ word_length++;
+ } else if (ch == '_' || ch == '-' || ch == '/') {
+ // Special case Au/Es/Of to be lower case.
+ if (word_length == 2) {
+ size_t pos = title_cased.length() - 2;
+ std::string substr = title_cased.substr(pos, 2);
+ if (substr == "Of" || substr == "Es" || substr == "Au") {
+ title_cased[pos] = LocaleIndependentAsciiToLower(title_cased[pos]);
+ }
+ }
+ title_cased += ch;
+ word_length = 0;
+ } else {
+ // Invalid input
+ return std::string();
+ }
+ }
+ return title_cased;
+}
+
+} // namespace
+
+std::string JSDateTimeFormat::CanonicalizeTimeZoneID(Isolate* isolate,
+ const std::string& input) {
+ std::string upper = input;
+ transform(upper.begin(), upper.end(), upper.begin(),
+ LocaleIndependentAsciiToUpper);
+ if (upper == "UTC" || upper == "GMT" || upper == "ETC/UTC" ||
+ upper == "ETC/GMT") {
+ return "UTC";
+ }
+ // We expect only _, '-' and / beside ASCII letters.
+ // All inputs should conform to Area/Location(/Location)*, or Etc/GMT* .
+ // TODO(jshin): 1. Support 'GB-Eire", 'EST5EDT", "ROK', 'US/*', 'NZ' and many
+ // other aliases/linked names when moving timezone validation code to C++.
+ // See crbug.com/364374 and crbug.com/v8/8007 .
+ // 2. Resolve the difference betwee CLDR/ICU and IANA time zone db.
+ // See http://unicode.org/cldr/trac/ticket/9892 and crbug.com/645807 .
+ if (strncmp(upper.c_str(), "ETC/GMT", 7) == 0) {
+ return GetGMTTzID(isolate, input);
+ }
+ return ToTitleCaseTimezoneLocation(isolate, input);
+}
+
+MaybeHandle<JSObject> JSDateTimeFormat::ResolvedOptions(
+ Isolate* isolate, Handle<JSDateTimeFormat> date_time_format) {
+ Factory* factory = isolate->factory();
+ // 4. Let options be ! ObjectCreate(%ObjectPrototype%).
+ Handle<JSObject> options = factory->NewJSObject(isolate->object_function());
+
+ // 5. For each row of Table 6, except the header row, in any order, do
+ // a. Let p be the Property value of the current row.
+ Handle<Object> resolved_obj;
+
+ // locale
+ UErrorCode status = U_ZERO_ERROR;
+ char language[ULOC_FULLNAME_CAPACITY];
+ uloc_toLanguageTag(date_time_format->icu_locale()->raw()->getName(), language,
+ ULOC_FULLNAME_CAPACITY, FALSE, &status);
+ CHECK(U_SUCCESS(status));
+ Handle<String> locale = factory->NewStringFromAsciiChecked(language);
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options, factory->locale_string(), locale, kDontThrow)
+ .FromJust());
+
+ icu::SimpleDateFormat* icu_simple_date_format =
+ date_time_format->icu_simple_date_format()->raw();
+ // calendar
+ const icu::Calendar* calendar = icu_simple_date_format->getCalendar();
+ // getType() returns legacy calendar type name instead of LDML/BCP47 calendar
+ // key values. intl.js maps them to BCP47 values for key "ca".
+ // TODO(jshin): Consider doing it here, instead.
+ std::string calendar_str = calendar->getType();
+
+ // Maps ICU calendar names to LDML/BCP47 types for key 'ca'.
+ // See typeMap section in third_party/icu/source/data/misc/keyTypeData.txt
+ // and
+ // http://www.unicode.org/repos/cldr/tags/latest/common/bcp47/calendar.xml
+ if (calendar_str == "gregorian") {
+ calendar_str = "gregory";
+ } else if (calendar_str == "ethiopic-amete-alem") {
+ calendar_str = "ethioaa";
+ }
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options, factory->NewStringFromStaticChars("calendar"),
+ factory->NewStringFromAsciiChecked(calendar_str.c_str()),
+ kDontThrow)
+ .FromJust());
+
+ // 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.
+ // Tracked by https://unicode-org.atlassian.net/browse/ICU-13431
+ std::unique_ptr<icu::NumberingSystem> numbering_system(
+ icu::NumberingSystem::createInstance(
+ *(date_time_format->icu_locale()->raw()), status));
+ if (U_SUCCESS(status)) {
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options, factory->numberingSystem_string(),
+ factory->NewStringFromAsciiChecked(numbering_system->getName()),
+ kDontThrow)
+ .FromJust());
+ }
+
+ // timezone
+ const icu::TimeZone& tz = calendar->getTimeZone();
+ icu::UnicodeString time_zone;
+ tz.getID(time_zone);
+ status = U_ZERO_ERROR;
+ icu::UnicodeString canonical_time_zone;
+ icu::TimeZone::getCanonicalID(time_zone, canonical_time_zone, status);
+ if (U_SUCCESS(status)) {
+ Handle<String> timezone_value;
+ // In CLDR (http://unicode.org/cldr/trac/ticket/9943), Etc/UTC is made
+ // a separate timezone ID from Etc/GMT even though they're still the same
+ // timezone. We have Etc/UTC because 'UTC', 'Etc/Universal',
+ // 'Etc/Zulu' and others are turned to 'Etc/UTC' by ICU. Etc/GMT comes
+ // from Etc/GMT0, Etc/GMT+0, Etc/GMT-0, Etc/Greenwich.
+ // ecma402#sec-canonicalizetimezonename step 3
+ if (canonical_time_zone == UNICODE_STRING_SIMPLE("Etc/UTC") ||
+ canonical_time_zone == UNICODE_STRING_SIMPLE("Etc/GMT")) {
+ timezone_value = factory->NewStringFromStaticChars("UTC");
+ } else {
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, timezone_value,
+ Intl::ToString(isolate, canonical_time_zone),
+ JSObject);
+ }
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options, factory->NewStringFromStaticChars("timeZone"),
+ timezone_value, kDontThrow)
+ .FromJust());
+ } else {
+ // Somehow on Windows we will reach here.
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options, factory->NewStringFromStaticChars("timeZone"),
+ factory->undefined_value(), kDontThrow)
+ .FromJust());
+ }
+
+ icu::UnicodeString pattern_unicode;
+ icu_simple_date_format->toPattern(pattern_unicode);
+ std::string pattern;
+ pattern_unicode.toUTF8String(pattern);
+ SetPropertyFromPattern(isolate, pattern, options);
+ return options;
+}
+
+namespace {
+
+// ecma402/#sec-formatdatetime
+// FormatDateTime( dateTimeFormat, x )
+MaybeHandle<String> FormatDateTime(Isolate* isolate,
+ Handle<JSDateTimeFormat> date_time_format,
+ double x) {
+ double date_value = DateCache::TimeClip(x);
+ if (std::isnan(date_value)) {
+ THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidTimeValue),
+ String);
+ }
+
+ icu::SimpleDateFormat* date_format =
+ date_time_format->icu_simple_date_format()->raw();
+ CHECK_NOT_NULL(date_format);
+
+ icu::UnicodeString result;
+ date_format->format(date_value, result);
+
+ return Intl::ToString(isolate, result);
+}
+
+} // namespace
+
+// ecma402/#sec-datetime-format-functions
+// DateTime Format Functions
+MaybeHandle<String> JSDateTimeFormat::DateTimeFormat(
+ Isolate* isolate, Handle<JSDateTimeFormat> date_time_format,
+ Handle<Object> date) {
+ // 2. Assert: Type(dtf) is Object and dtf has an [[InitializedDateTimeFormat]]
+ // internal slot.
+
+ // 3. If date is not provided or is undefined, then
+ double x;
+ if (date->IsUndefined()) {
+ // 3.a Let x be Call(%Date_now%, undefined).
+ x = JSDate::CurrentTimeValue(isolate);
+ } else {
+ // 4. Else,
+ // a. Let x be ? ToNumber(date).
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, date, Object::ToNumber(isolate, date),
+ String);
+ CHECK(date->IsNumber());
+ x = date->Number();
+ }
+ // 5. Return FormatDateTime(dtf, x).
+ return FormatDateTime(isolate, date_time_format, x);
+}
+
+MaybeHandle<String> JSDateTimeFormat::ToLocaleDateTime(
+ Isolate* isolate, Handle<Object> date, Handle<Object> locales,
+ Handle<Object> options, RequiredOption required, DefaultsOption defaults,
+ const char* service) {
+ Factory* factory = isolate->factory();
+ // 1. Let x be ? thisTimeValue(this value);
+ if (!date->IsJSDate()) {
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
+ factory->NewStringFromStaticChars("Date")),
+ String);
+ }
+
+ double const x = Handle<JSDate>::cast(date)->value()->Number();
+ // 2. If x is NaN, return "Invalid Date"
+ if (std::isnan(x)) {
+ return factory->NewStringFromStaticChars("Invalid Date");
+ }
+
+ // 3. Let options be ? ToDateTimeOptions(options, required, defaults).
+ Handle<JSObject> internal_options;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, internal_options,
+ ToDateTimeOptions(isolate, options, required, defaults), String);
+
+ // 4. Let dateFormat be ? Construct(%DateTimeFormat%, « locales, options »).
+ Handle<JSObject> object;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, object,
+ Intl::CachedOrNewService(isolate,
+ factory->NewStringFromAsciiChecked(service),
+ locales, options, internal_options),
+ String);
+
+ CHECK(object->IsJSDateTimeFormat());
+ Handle<JSDateTimeFormat> date_time_format =
+ Handle<JSDateTimeFormat>::cast(object);
+ // 5. Return FormatDateTime(dateFormat, x).
+ return FormatDateTime(isolate, date_time_format, x);
+}
+
+namespace {
+
+Maybe<bool> IsPropertyUndefined(Isolate* isolate, Handle<JSObject> options,
+ const char* property) {
+ Factory* factory = isolate->factory();
+ // i. Let prop be the property name.
+ // ii. Let value be ? Get(options, prop).
+ Handle<Object> value;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, value,
+ Object::GetPropertyOrElement(
+ isolate, options, factory->NewStringFromAsciiChecked(property)),
+ Nothing<bool>());
+ return Just(value->IsUndefined(isolate));
+}
+
+Maybe<bool> NeedsDefault(Isolate* isolate, Handle<JSObject> options,
+ const std::vector<std::string>& props) {
+ bool needs_default = true;
+ for (const auto& prop : props) {
+ // i. Let prop be the property name.
+ // ii. Let value be ? Get(options, prop)
+ Maybe<bool> maybe_undefined =
+ IsPropertyUndefined(isolate, options, prop.c_str());
+ MAYBE_RETURN(maybe_undefined, Nothing<bool>());
+ // iii. If value is not undefined, let needDefaults be false.
+ if (!maybe_undefined.FromJust()) {
+ needs_default = false;
+ }
+ }
+ return Just(needs_default);
+}
+
+Maybe<bool> CreateDefault(Isolate* isolate, Handle<JSObject> options,
+ const std::vector<std::string>& props) {
+ Factory* factory = isolate->factory();
+ // i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric").
+ for (const auto& prop : props) {
+ MAYBE_RETURN(
+ JSReceiver::CreateDataProperty(
+ isolate, options, factory->NewStringFromAsciiChecked(prop.c_str()),
+ factory->numeric_string(), kThrowOnError),
+ Nothing<bool>());
+ }
+ return Just(true);
+}
+
+} // namespace
+
+// ecma-402/#sec-todatetimeoptions
+MaybeHandle<JSObject> JSDateTimeFormat::ToDateTimeOptions(
+ Isolate* isolate, Handle<Object> input_options, RequiredOption required,
+ DefaultsOption defaults) {
+ Factory* factory = isolate->factory();
+ // 1. If options is undefined, let options be null; otherwise let options be ?
+ // ToObject(options).
+ Handle<JSObject> options;
+ if (input_options->IsUndefined(isolate)) {
+ options = factory->NewJSObjectWithNullProto();
+ } else {
+ Handle<JSReceiver> options_obj;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, options_obj,
+ Object::ToObject(isolate, input_options),
+ JSObject);
+ // 2. Let options be ObjectCreate(options).
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, options,
+ JSObject::ObjectCreate(isolate, options_obj),
+ JSObject);
+ }
+
+ // 3. Let needDefaults be true.
+ bool needs_default = true;
+
+ // 4. If required is "date" or "any", then
+ if (required == RequiredOption::kAny || required == RequiredOption::kDate) {
+ // a. For each of the property names "weekday", "year", "month", "day", do
+ const std::vector<std::string> list({"weekday", "year", "month", "day"});
+ Maybe<bool> maybe_needs_default = NeedsDefault(isolate, options, list);
+ MAYBE_RETURN(maybe_needs_default, Handle<JSObject>());
+ needs_default = maybe_needs_default.FromJust();
+ }
+
+ // 5. If required is "time" or "any", then
+ if (required == RequiredOption::kAny || required == RequiredOption::kTime) {
+ // a. For each of the property names "hour", "minute", "second", do
+ const std::vector<std::string> list({"hour", "minute", "second"});
+ Maybe<bool> maybe_needs_default = NeedsDefault(isolate, options, list);
+ MAYBE_RETURN(maybe_needs_default, Handle<JSObject>());
+ needs_default &= maybe_needs_default.FromJust();
+ }
+
+ // 6. If needDefaults is true and defaults is either "date" or "all", then
+ if (needs_default) {
+ if (defaults == DefaultsOption::kAll || defaults == DefaultsOption::kDate) {
+ // a. For each of the property names "year", "month", "day", do)
+ const std::vector<std::string> list({"year", "month", "day"});
+ MAYBE_RETURN(CreateDefault(isolate, options, list), Handle<JSObject>());
+ }
+ // 7. If needDefaults is true and defaults is either "time" or "all", then
+ if (defaults == DefaultsOption::kAll || defaults == DefaultsOption::kTime) {
+ // a. For each of the property names "hour", "minute", "second", do
+ const std::vector<std::string> list({"hour", "minute", "second"});
+ MAYBE_RETURN(CreateDefault(isolate, options, list), Handle<JSObject>());
+ }
+ }
+ // 8. Return options.
+ return options;
+}
+
+MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::UnwrapDateTimeFormat(
+ Isolate* isolate, Handle<JSReceiver> format_holder) {
+ Handle<Context> native_context =
+ Handle<Context>(isolate->context()->native_context(), isolate);
+ Handle<JSFunction> constructor = Handle<JSFunction>(
+ JSFunction::cast(native_context->intl_date_time_format_function()),
+ isolate);
+ Handle<Object> dtf;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, dtf,
+ Intl::LegacyUnwrapReceiver(isolate, format_holder, constructor,
+ format_holder->IsJSDateTimeFormat()),
+ JSDateTimeFormat);
+ // 2. If Type(dtf) is not Object or dtf does not have an
+ // [[InitializedDateTimeFormat]] internal slot, then
+ if (!dtf->IsJSDateTimeFormat()) {
+ // a. Throw a TypeError exception.
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
+ isolate->factory()->NewStringFromAsciiChecked(
+ "UnwrapDateTimeFormat"),
+ format_holder),
+ JSDateTimeFormat);
+ }
+ // 3. Return dtf.
+ return Handle<JSDateTimeFormat>::cast(dtf);
+}
+
+namespace {
+
+// ecma-402/#sec-isvalidtimezonename
+bool IsValidTimeZoneName(const icu::TimeZone& tz) {
+ UErrorCode status = U_ZERO_ERROR;
+ icu::UnicodeString id;
+ tz.getID(id);
+ icu::UnicodeString canonical;
+ icu::TimeZone::getCanonicalID(id, canonical, status);
+ return U_SUCCESS(status) &&
+ canonical != icu::UnicodeString("Etc/Unknown", -1, US_INV);
+}
+
+std::unique_ptr<icu::TimeZone> CreateTimeZone(Isolate* isolate,
+ const char* timezone) {
+ // Create time zone as specified by the user. We have to re-create time zone
+ // since calendar takes ownership.
+ if (timezone == nullptr) {
+ // 19.a. Else / Let timeZone be DefaultTimeZone().
+ return std::unique_ptr<icu::TimeZone>(icu::TimeZone::createDefault());
+ }
+ std::string canonicalized =
+ JSDateTimeFormat::CanonicalizeTimeZoneID(isolate, timezone);
+ if (canonicalized.empty()) return std::unique_ptr<icu::TimeZone>();
+ std::unique_ptr<icu::TimeZone> tz(
+ icu::TimeZone::createTimeZone(canonicalized.c_str()));
+ // 18.b If the result of IsValidTimeZoneName(timeZone) is false, then
+ // i. Throw a RangeError exception.
+ if (!IsValidTimeZoneName(*tz)) return std::unique_ptr<icu::TimeZone>();
+ return tz;
+}
+
+std::unique_ptr<icu::Calendar> CreateCalendar(Isolate* isolate,
+ const icu::Locale& icu_locale,
+ const char* timezone) {
+ std::unique_ptr<icu::TimeZone> tz = CreateTimeZone(isolate, timezone);
+ if (tz.get() == nullptr) return std::unique_ptr<icu::Calendar>();
+
+ // Create a calendar using locale, and apply time zone to it.
+ UErrorCode status = U_ZERO_ERROR;
+ std::unique_ptr<icu::Calendar> calendar(
+ icu::Calendar::createInstance(tz.release(), icu_locale, status));
+ CHECK(U_SUCCESS(status));
+ CHECK_NOT_NULL(calendar.get());
+
+ if (calendar->getDynamicClassID() ==
+ icu::GregorianCalendar::getStaticClassID()) {
+ icu::GregorianCalendar* gc =
+ static_cast<icu::GregorianCalendar*>(calendar.get());
+ UErrorCode status = U_ZERO_ERROR;
+ // The beginning of ECMAScript time, namely -(2**53)
+ const double start_of_time = -9007199254740992;
+ gc->setGregorianChange(start_of_time, status);
+ DCHECK(U_SUCCESS(status));
+ }
+ return calendar;
+}
+
+std::unique_ptr<icu::SimpleDateFormat> CreateICUDateFormat(
+ Isolate* isolate, const icu::Locale& icu_locale,
+ const std::string& skeleton) {
+ // See https://github.com/tc39/ecma402/issues/225 . The best pattern
+ // generation needs to be done in the base locale according to the
+ // current spec however odd it may be. See also crbug.com/826549 .
+ // This is a temporary work-around to get v8's external behavior to match
+ // the current spec, but does not follow the spec provisions mentioned
+ // in the above Ecma 402 issue.
+ // TODO(jshin): The spec may need to be revised because using the base
+ // locale for the pattern match is not quite right. Moreover, what to
+ // do with 'related year' part when 'chinese/dangi' calendar is specified
+ // has to be discussed. Revisit once the spec is clarified/revised.
+ icu::Locale no_extension_locale(icu_locale.getBaseName());
+ UErrorCode status = U_ZERO_ERROR;
+ std::unique_ptr<icu::DateTimePatternGenerator> generator(
+ icu::DateTimePatternGenerator::createInstance(no_extension_locale,
+ status));
+ icu::UnicodeString pattern;
+ if (U_SUCCESS(status)) {
+ pattern =
+ generator->getBestPattern(icu::UnicodeString(skeleton.c_str()), status);
+ }
+
+ // Make formatter from skeleton. Calendar and numbering system are added
+ // to the locale as Unicode extension (if they were specified at all).
+ status = U_ZERO_ERROR;
+ std::unique_ptr<icu::SimpleDateFormat> date_format(
+ new icu::SimpleDateFormat(pattern, icu_locale, status));
+ if (U_FAILURE(status)) return std::unique_ptr<icu::SimpleDateFormat>();
+
+ CHECK_NOT_NULL(date_format.get());
+ return date_format;
+}
+
+} // namespace
+
+enum FormatMatcherOption { kBestFit, kBasic };
+
+// ecma402/#sec-initializedatetimeformat
+MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::Initialize(
+ Isolate* isolate, Handle<JSDateTimeFormat> date_time_format,
+ Handle<Object> requested_locales, Handle<Object> input_options) {
+ // 2. Let options be ? ToDateTimeOptions(options, "any", "date").
+ Handle<JSObject> options;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, options,
+ JSDateTimeFormat::ToDateTimeOptions(
+ isolate, input_options, RequiredOption::kAny, DefaultsOption::kDate),
+ JSDateTimeFormat);
+
+ // ResolveLocale currently get option of localeMatcher so we have to call
+ // ResolveLocale before "hour12" and "hourCycle".
+ // TODO(ftang): fix this once ResolveLocale is ported to C++
+ // 11. Let r be ResolveLocale( %DateTimeFormat%.[[AvailableLocales]],
+ // requestedLocales, opt, %DateTimeFormat%.[[RelevantExtensionKeys]],
+ // localeData).
+ Handle<JSObject> r;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, r,
+ Intl::ResolveLocale(isolate, "dateformat", requested_locales, options),
+ JSDateTimeFormat);
+
+ // 6. Let hour12 be ? GetOption(options, "hour12", "boolean", undefined,
+ // undefined).
+ bool hour12;
+ Maybe<bool> maybe_get_hour12 = Intl::GetBoolOption(
+ isolate, options, "hour12", "Intl.DateTimeFormat", &hour12);
+ MAYBE_RETURN(maybe_get_hour12, Handle<JSDateTimeFormat>());
+ HourOption hour_option = HourOption::H_UNKNOWN;
+ if (maybe_get_hour12.FromJust()) {
+ hour_option = hour12 ? HourOption::H_12 : HourOption::H_24;
+ }
+
+ // 7. Let hourCycle be ? GetOption(options, "hourCycle", "string", « "h11",
+ // "h12", "h23", "h24" », undefined).
+ static std::vector<const char*> hour_cycle_values = {"h11", "h12", "h23",
+ "h24"};
+ std::unique_ptr<char[]> hour_cycle = nullptr;
+ Maybe<bool> maybe_hour_cycle =
+ Intl::GetStringOption(isolate, options, "hourCycle", hour_cycle_values,
+ "Intl.DateTimeFormat", &hour_cycle);
+ MAYBE_RETURN(maybe_hour_cycle, Handle<JSDateTimeFormat>());
+ // 8. If hour12 is not undefined, then
+ if (maybe_get_hour12.FromJust()) {
+ // a. Let hourCycle be null.
+ hour_cycle = nullptr;
+ }
+ // 9. Set opt.[[hc]] to hourCycle.
+ // TODO(ftang): change behavior based on hour_cycle.
+
+ Handle<String> locale_with_extension_str =
+ isolate->factory()->NewStringFromStaticChars("localeWithExtension");
+ Handle<Object> locale_with_extension_obj =
+ JSObject::GetDataProperty(r, locale_with_extension_str);
+
+ // The locale_with_extension has to be a string. Either a user
+ // provided canonicalized string or the default locale.
+ CHECK(locale_with_extension_obj->IsString());
+ Handle<String> locale_with_extension =
+ Handle<String>::cast(locale_with_extension_obj);
+
+ icu::Locale icu_locale =
+ Intl::CreateICULocale(isolate, locale_with_extension);
+ DCHECK(!icu_locale.isBogus());
+
+ // 17. Let timeZone be ? Get(options, "timeZone").
+ static std::vector<const char*> empty_values = {};
+ std::unique_ptr<char[]> timezone = nullptr;
+ Maybe<bool> maybe_timezone =
+ Intl::GetStringOption(isolate, options, "timeZone", empty_values,
+ "Intl.DateTimeFormat", &timezone);
+ MAYBE_RETURN(maybe_timezone, Handle<JSDateTimeFormat>());
+
+ // 22. For each row of Table 5, except the header row, do
+ std::string skeleton;
+ for (const auto& item : GetPatternData(hour_option)) {
+ std::unique_ptr<char[]> input;
+ // a. Let prop be the name given in the Property column of the row.
+ // b. Let value be ? GetOption(options, prop, "string", « the strings given
+ // in the Values column of the row », undefined).
+ Maybe<bool> maybe_get_option = Intl::GetStringOption(
+ isolate, options, item.property.c_str(), item.allowed_values,
+ "Intl.DateTimeFormat", &input);
+ MAYBE_RETURN(maybe_get_option, Handle<JSDateTimeFormat>());
+ if (maybe_get_option.FromJust()) {
+ DCHECK_NOT_NULL(input.get());
+ // c. Set opt.[[<prop>]] to value.
+ skeleton += item.map.find(input.get())->second;
+ }
+ }
+
+ // We implement only best fit algorithm, but still need to check
+ // if the formatMatcher values are in range.
+ // 25. Let matcher be ? GetOption(options, "formatMatcher", "string",
+ // « "basic", "best fit" », "best fit").
+ Handle<JSReceiver> options_obj;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, options_obj,
+ Object::ToObject(isolate, options),
+ JSDateTimeFormat);
+ std::unique_ptr<char[]> matcher_str = nullptr;
+ std::vector<const char*> matcher_values = {"basic", "best fit"};
+ Maybe<bool> maybe_found_matcher = Intl::GetStringOption(
+ isolate, options_obj, "formatMatcher", matcher_values,
+ "Intl.DateTimeFormat", &matcher_str);
+ MAYBE_RETURN(maybe_found_matcher, Handle<JSDateTimeFormat>());
+
+ std::unique_ptr<icu::SimpleDateFormat> date_format(
+ CreateICUDateFormat(isolate, icu_locale, skeleton));
+ if (date_format.get() == nullptr) {
+ // Remove extensions and try again.
+ icu_locale = icu::Locale(icu_locale.getBaseName());
+ date_format = CreateICUDateFormat(isolate, icu_locale, skeleton);
+ if (date_format.get() == nullptr) {
+ FATAL("Failed to create ICU date format, are ICU data files missing?");
+ }
+ }
+
+ // Set the locale
+ // 12. Set dateTimeFormat.[[Locale]] to r.[[locale]].
+ icu::Locale* cloned_locale = icu_locale.clone();
+ CHECK_NOT_NULL(cloned_locale);
+ Handle<Managed<icu::Locale>> managed_locale =
+ Managed<icu::Locale>::FromRawPtr(isolate, 0, cloned_locale);
+ date_time_format->set_icu_locale(*managed_locale);
+
+ // 13. Set dateTimeFormat.[[Calendar]] to r.[[ca]].
+ std::unique_ptr<icu::Calendar> calendar(
+ CreateCalendar(isolate, icu_locale, timezone.get()));
+
+ // 18.b If the result of IsValidTimeZoneName(timeZone) is false, then
+ // i. Throw a RangeError exception.
+ if (calendar.get() == nullptr) {
+ THROW_NEW_ERROR(isolate,
+ NewRangeError(MessageTemplate::kInvalidTimeZone,
+ isolate->factory()->NewStringFromAsciiChecked(
+ timezone.get())),
+ JSDateTimeFormat);
+ }
+ date_format->adoptCalendar(calendar.release());
+
+ Handle<Managed<icu::SimpleDateFormat>> managed_format =
+ Managed<icu::SimpleDateFormat>::FromUniquePtr(isolate, 0,
+ std::move(date_format));
+ date_time_format->set_icu_simple_date_format(*managed_format);
+ return date_time_format;
+}
+
+namespace {
+
+// The list comes from third_party/icu/source/i18n/unicode/udat.h.
+// They're mapped to DateTimeFormat components listed at
+// https://tc39.github.io/ecma402/#sec-datetimeformat-abstracts .
+Handle<String> IcuDateFieldIdToDateType(int32_t field_id, Isolate* isolate) {
+ switch (field_id) {
+ case -1:
+ return isolate->factory()->literal_string();
+ case UDAT_YEAR_FIELD:
+ case UDAT_EXTENDED_YEAR_FIELD:
+ case UDAT_YEAR_NAME_FIELD:
+ return isolate->factory()->year_string();
+ case UDAT_MONTH_FIELD:
+ case UDAT_STANDALONE_MONTH_FIELD:
+ return isolate->factory()->month_string();
+ case UDAT_DATE_FIELD:
+ return isolate->factory()->day_string();
+ case UDAT_HOUR_OF_DAY1_FIELD:
+ case UDAT_HOUR_OF_DAY0_FIELD:
+ case UDAT_HOUR1_FIELD:
+ case UDAT_HOUR0_FIELD:
+ return isolate->factory()->hour_string();
+ case UDAT_MINUTE_FIELD:
+ return isolate->factory()->minute_string();
+ case UDAT_SECOND_FIELD:
+ return isolate->factory()->second_string();
+ case UDAT_DAY_OF_WEEK_FIELD:
+ case UDAT_DOW_LOCAL_FIELD:
+ case UDAT_STANDALONE_DAY_FIELD:
+ return isolate->factory()->weekday_string();
+ case UDAT_AM_PM_FIELD:
+ return isolate->factory()->dayPeriod_string();
+ case UDAT_TIMEZONE_FIELD:
+ case UDAT_TIMEZONE_RFC_FIELD:
+ case UDAT_TIMEZONE_GENERIC_FIELD:
+ case UDAT_TIMEZONE_SPECIAL_FIELD:
+ case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD:
+ case UDAT_TIMEZONE_ISO_FIELD:
+ case UDAT_TIMEZONE_ISO_LOCAL_FIELD:
+ return isolate->factory()->timeZoneName_string();
+ case UDAT_ERA_FIELD:
+ return isolate->factory()->era_string();
+ default:
+ // Other UDAT_*_FIELD's cannot show up because there is no way to specify
+ // them via options of Intl.DateTimeFormat.
+ UNREACHABLE();
+ // To prevent MSVC from issuing C4715 warning.
+ return Handle<String>();
+ }
+}
+
+} // namespace
+
+MaybeHandle<Object> JSDateTimeFormat::FormatToParts(
+ Isolate* isolate, Handle<JSDateTimeFormat> date_time_format,
+ double date_value) {
+ Factory* factory = isolate->factory();
+ icu::SimpleDateFormat* format =
+ date_time_format->icu_simple_date_format()->raw();
+ CHECK_NOT_NULL(format);
+
+ icu::UnicodeString formatted;
+ icu::FieldPositionIterator fp_iter;
+ icu::FieldPosition fp;
+ UErrorCode status = U_ZERO_ERROR;
+ format->format(date_value, formatted, &fp_iter, status);
+ if (U_FAILURE(status)) {
+ THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), Object);
+ }
+
+ Handle<JSArray> result = factory->NewJSArray(0);
+ int32_t length = formatted.length();
+ if (length == 0) return result;
+
+ int index = 0;
+ int32_t previous_end_pos = 0;
+ Handle<String> substring;
+ while (fp_iter.next(fp)) {
+ int32_t begin_pos = fp.getBeginIndex();
+ int32_t end_pos = fp.getEndIndex();
+
+ if (previous_end_pos < begin_pos) {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, substring,
+ Intl::ToString(isolate, formatted, previous_end_pos, begin_pos),
+ Object);
+ Intl::AddElement(isolate, result, index,
+ IcuDateFieldIdToDateType(-1, isolate), substring);
+ ++index;
+ }
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, substring,
+ Intl::ToString(isolate, formatted, begin_pos, end_pos), Object);
+ Intl::AddElement(isolate, result, index,
+ IcuDateFieldIdToDateType(fp.getField(), isolate),
+ substring);
+ previous_end_pos = end_pos;
+ ++index;
+ }
+ if (previous_end_pos < length) {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, substring,
+ Intl::ToString(isolate, formatted, previous_end_pos, length), Object);
+ Intl::AddElement(isolate, result, index,
+ IcuDateFieldIdToDateType(-1, isolate), substring);
+ }
+ JSObject::ValidateElements(*result);
+ return result;
+}
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/objects/js-date-time-format.h b/deps/v8/src/objects/js-date-time-format.h
new file mode 100644
index 0000000000..ae2aa36a97
--- /dev/null
+++ b/deps/v8/src/objects/js-date-time-format.h
@@ -0,0 +1,100 @@
+// Copyright 2018 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_INTL_SUPPORT
+#error Internationalization is expected to be enabled.
+#endif // V8_INTL_SUPPORT
+
+#ifndef V8_OBJECTS_JS_DATE_TIME_FORMAT_H_
+#define V8_OBJECTS_JS_DATE_TIME_FORMAT_H_
+
+#include "src/isolate.h"
+#include "src/objects/managed.h"
+
+// Has to be the last include (doesn't have include guards):
+#include "src/objects/object-macros.h"
+
+namespace U_ICU_NAMESPACE {
+class Locale;
+class SimpleDateFormat;
+}
+
+namespace v8 {
+namespace internal {
+
+class JSDateTimeFormat : public JSObject {
+ public:
+ V8_WARN_UNUSED_RESULT static MaybeHandle<JSDateTimeFormat> Initialize(
+ Isolate* isolate, Handle<JSDateTimeFormat> date_time_format,
+ Handle<Object> locales, Handle<Object> options);
+
+ V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> ResolvedOptions(
+ Isolate* isolate, Handle<JSDateTimeFormat> date_time_format);
+
+ // ecma402/#sec-unwrapdatetimeformat
+ V8_WARN_UNUSED_RESULT static MaybeHandle<JSDateTimeFormat>
+ UnwrapDateTimeFormat(Isolate* isolate, Handle<JSReceiver> format_holder);
+
+ // Convert the options to ICU DateTimePatternGenerator skeleton.
+ static Maybe<std::string> OptionsToSkeleton(Isolate* isolate,
+ Handle<JSReceiver> options);
+
+ // Return the time zone id which match ICU's expectation of title casing
+ // return empty string when error.
+ static std::string CanonicalizeTimeZoneID(Isolate* isolate,
+ const std::string& input);
+
+ // ecma402/#sec-datetime-format-functions
+ // DateTime Format Functions
+ V8_WARN_UNUSED_RESULT static MaybeHandle<String> DateTimeFormat(
+ Isolate* isolate, Handle<JSDateTimeFormat> date_time_format,
+ Handle<Object> date);
+
+ V8_WARN_UNUSED_RESULT static MaybeHandle<Object> FormatToParts(
+ Isolate* isolate, Handle<JSDateTimeFormat> date_time_format,
+ double date_value);
+
+ // ecma-402/#sec-todatetimeoptions
+ enum class RequiredOption { kDate, kTime, kAny };
+ enum class DefaultsOption { kDate, kTime, kAll };
+ V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> ToDateTimeOptions(
+ Isolate* isolate, Handle<Object> input_options, RequiredOption required,
+ DefaultsOption defaults);
+
+ V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToLocaleDateTime(
+ Isolate* isolate, Handle<Object> date, Handle<Object> locales,
+ Handle<Object> options, RequiredOption required, DefaultsOption defaults,
+ const char* service);
+
+ DECL_CAST(JSDateTimeFormat)
+
+// Layout description.
+#define JS_DATE_TIME_FORMAT_FIELDS(V) \
+ V(kICULocaleOffset, kPointerSize) \
+ V(kICUSimpleDateFormatOffset, kPointerSize) \
+ V(kBoundFormatOffset, kPointerSize) \
+ /* Total size. */ \
+ V(kSize, 0)
+
+ DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
+ JS_DATE_TIME_FORMAT_FIELDS)
+#undef JS_DATE_TIME_FORMAT_FIELDS
+
+ DECL_ACCESSORS(icu_locale, Managed<icu::Locale>)
+ DECL_ACCESSORS(icu_simple_date_format, Managed<icu::SimpleDateFormat>)
+ DECL_ACCESSORS(bound_format, Object)
+
+ DECL_PRINTER(JSDateTimeFormat)
+ DECL_VERIFIER(JSDateTimeFormat)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSDateTimeFormat);
+};
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_JS_DATE_TIME_FORMAT_H_
diff --git a/deps/v8/src/objects/js-generator.h b/deps/v8/src/objects/js-generator.h
index 4d63d524ea..043b457cf0 100644
--- a/deps/v8/src/objects/js-generator.h
+++ b/deps/v8/src/objects/js-generator.h
@@ -5,7 +5,7 @@
#ifndef V8_OBJECTS_JS_GENERATOR_H_
#define V8_OBJECTS_JS_GENERATOR_H_
-#include "src/objects.h"
+#include "src/objects/js-objects.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
diff --git a/deps/v8/src/objects/js-list-format-inl.h b/deps/v8/src/objects/js-list-format-inl.h
index 554b3488b6..0f1395719e 100644
--- a/deps/v8/src/objects/js-list-format-inl.h
+++ b/deps/v8/src/objects/js-list-format-inl.h
@@ -20,7 +20,8 @@ namespace internal {
// Base list format accessors.
ACCESSORS(JSListFormat, locale, String, kLocaleOffset)
-ACCESSORS(JSListFormat, formatter, Foreign, kFormatterOffset)
+ACCESSORS(JSListFormat, icu_formatter, Managed<icu::ListFormatter>,
+ kICUFormatterOffset)
SMI_ACCESSORS(JSListFormat, flags, kFlagsOffset)
inline void JSListFormat::set_style(Style style) {
diff --git a/deps/v8/src/objects/js-list-format.cc b/deps/v8/src/objects/js-list-format.cc
index 66dbe0bfd9..d2713d489f 100644
--- a/deps/v8/src/objects/js-list-format.cc
+++ b/deps/v8/src/objects/js-list-format.cc
@@ -119,7 +119,7 @@ JSListFormat::Type get_type(const char* str) {
UNREACHABLE();
}
-MaybeHandle<JSListFormat> JSListFormat::InitializeListFormat(
+MaybeHandle<JSListFormat> JSListFormat::Initialize(
Isolate* isolate, Handle<JSListFormat> list_format_holder,
Handle<Object> input_locales, Handle<Object> input_options) {
Factory* factory = isolate->factory();
@@ -199,7 +199,7 @@ MaybeHandle<JSListFormat> JSListFormat::InitializeListFormat(
Handle<Managed<icu::ListFormatter>> managed_formatter =
Managed<icu::ListFormatter>::FromRawPtr(isolate, 0, formatter);
- list_format_holder->set_formatter(*managed_formatter);
+ list_format_holder->set_icu_formatter(*managed_formatter);
return list_format_holder;
}
@@ -217,11 +217,6 @@ Handle<JSObject> JSListFormat::ResolvedOptions(
return result;
}
-icu::ListFormatter* JSListFormat::UnpackFormatter(Isolate* isolate,
- Handle<JSListFormat> holder) {
- return Managed<icu::ListFormatter>::cast(holder->formatter())->raw();
-}
-
Handle<String> JSListFormat::StyleAsString() const {
switch (style()) {
case Style::LONG:
@@ -352,8 +347,7 @@ Maybe<bool> FormatListCommon(Isolate* isolate,
std::unique_ptr<icu::UnicodeString[]>& array) {
DCHECK(!list->IsUndefined());
- icu::ListFormatter* formatter =
- JSListFormat::UnpackFormatter(isolate, format_holder);
+ icu::ListFormatter* formatter = format_holder->icu_formatter()->raw();
CHECK_NOT_NULL(formatter);
*length = list->GetElementsAccessor()->NumberOfElements(*list);
diff --git a/deps/v8/src/objects/js-list-format.h b/deps/v8/src/objects/js-list-format.h
index 22f8d20005..e9bfec7cc8 100644
--- a/deps/v8/src/objects/js-list-format.h
+++ b/deps/v8/src/objects/js-list-format.h
@@ -12,6 +12,7 @@
#include "src/heap/factory.h"
#include "src/isolate.h"
#include "src/objects.h"
+#include "src/objects/managed.h"
#include "unicode/uversion.h"
// Has to be the last include (doesn't have include guards):
@@ -28,17 +29,13 @@ class JSListFormat : public JSObject {
public:
// Initializes relative time format object with properties derived from input
// locales and options.
- static MaybeHandle<JSListFormat> InitializeListFormat(
+ static MaybeHandle<JSListFormat> Initialize(
Isolate* isolate, Handle<JSListFormat> list_format_holder,
Handle<Object> locales, Handle<Object> options);
static Handle<JSObject> ResolvedOptions(Isolate* isolate,
Handle<JSListFormat> format_holder);
- // Unpacks formatter object from corresponding JavaScript object.
- static icu::ListFormatter* UnpackFormatter(
- Isolate* isolate, Handle<JSListFormat> list_format_holder);
-
// ecma402 #sec-formatlist
V8_WARN_UNUSED_RESULT static MaybeHandle<String> FormatList(
Isolate* isolate, Handle<JSListFormat> format_holder,
@@ -56,7 +53,7 @@ class JSListFormat : public JSObject {
// ListFormat accessors.
DECL_ACCESSORS(locale, String)
- DECL_ACCESSORS(formatter, Foreign)
+ DECL_ACCESSORS(icu_formatter, Managed<icu::ListFormatter>)
// Style: identifying the relative time format style used.
//
@@ -105,8 +102,8 @@ class JSListFormat : public JSObject {
// Layout description.
static const int kJSListFormatOffset = JSObject::kHeaderSize;
static const int kLocaleOffset = kJSListFormatOffset + kPointerSize;
- static const int kFormatterOffset = kLocaleOffset + kPointerSize;
- static const int kFlagsOffset = kFormatterOffset + kPointerSize;
+ static const int kICUFormatterOffset = kLocaleOffset + kPointerSize;
+ static const int kFlagsOffset = kICUFormatterOffset + kPointerSize;
static const int kSize = kFlagsOffset + kPointerSize;
private:
diff --git a/deps/v8/src/objects/js-locale-inl.h b/deps/v8/src/objects/js-locale-inl.h
index a70bef998e..ac0a7a914f 100644
--- a/deps/v8/src/objects/js-locale-inl.h
+++ b/deps/v8/src/objects/js-locale-inl.h
@@ -28,14 +28,45 @@ ACCESSORS(JSLocale, locale, String, kLocaleOffset);
// Unicode extension accessors.
ACCESSORS(JSLocale, calendar, Object, kCalendarOffset);
-ACCESSORS(JSLocale, case_first, Object, kCaseFirstOffset);
ACCESSORS(JSLocale, collation, Object, kCollationOffset);
-ACCESSORS(JSLocale, hour_cycle, Object, kHourCycleOffset);
-ACCESSORS(JSLocale, numeric, Object, kNumericOffset);
ACCESSORS(JSLocale, numbering_system, Object, kNumberingSystemOffset);
+SMI_ACCESSORS(JSLocale, flags, kFlagsOffset)
CAST_ACCESSOR(JSLocale);
+inline void JSLocale::set_case_first(CaseFirst case_first) {
+ DCHECK_GT(CaseFirst::COUNT, case_first);
+ int hints = flags();
+ hints = CaseFirstBits::update(hints, case_first);
+ set_flags(hints);
+}
+
+inline JSLocale::CaseFirst JSLocale::case_first() const {
+ return CaseFirstBits::decode(flags());
+}
+
+inline void JSLocale::set_hour_cycle(HourCycle hour_cycle) {
+ DCHECK_GT(HourCycle::COUNT, hour_cycle);
+ int hints = flags();
+ hints = HourCycleBits::update(hints, hour_cycle);
+ set_flags(hints);
+}
+
+inline JSLocale::HourCycle JSLocale::hour_cycle() const {
+ return HourCycleBits::decode(flags());
+}
+
+inline void JSLocale::set_numeric(Numeric numeric) {
+ DCHECK_GT(Numeric::COUNT, numeric);
+ int hints = flags();
+ hints = NumericBits::update(hints, numeric);
+ set_flags(hints);
+}
+
+inline JSLocale::Numeric JSLocale::numeric() const {
+ return NumericBits::decode(flags());
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/objects/js-locale.cc b/deps/v8/src/objects/js-locale.cc
index 8968aa58c9..78fb30fa41 100644
--- a/deps/v8/src/objects/js-locale.cc
+++ b/deps/v8/src/objects/js-locale.cc
@@ -35,6 +35,26 @@ namespace internal {
namespace {
+JSLocale::CaseFirst GetCaseFirst(const char* str) {
+ if (strcmp(str, "upper") == 0) return JSLocale::CaseFirst::UPPER;
+ if (strcmp(str, "lower") == 0) return JSLocale::CaseFirst::LOWER;
+ if (strcmp(str, "false") == 0) return JSLocale::CaseFirst::FALSE_VALUE;
+ UNREACHABLE();
+}
+
+JSLocale::HourCycle GetHourCycle(const char* str) {
+ if (strcmp(str, "h11") == 0) return JSLocale::HourCycle::H11;
+ if (strcmp(str, "h12") == 0) return JSLocale::HourCycle::H12;
+ if (strcmp(str, "h23") == 0) return JSLocale::HourCycle::H23;
+ if (strcmp(str, "h24") == 0) return JSLocale::HourCycle::H24;
+ UNREACHABLE();
+}
+
+JSLocale::Numeric GetNumeric(const char* str) {
+ return strcmp(str, "true") == 0 ? JSLocale::Numeric::TRUE_VALUE
+ : JSLocale::Numeric::FALSE_VALUE;
+}
+
struct OptionData {
const char* name;
const char* key;
@@ -49,12 +69,12 @@ Maybe<bool> InsertOptionsIntoLocale(Isolate* isolate,
CHECK(isolate);
CHECK(icu_locale);
- static std::vector<const char*> hour_cycle_values = {"h11", "h12", "h23",
- "h24"};
- static std::vector<const char*> case_first_values = {"upper", "lower",
- "false"};
- static std::vector<const char*> empty_values = {};
- static const std::array<OptionData, 6> kOptionToUnicodeTagMap = {
+ const std::vector<const char*> hour_cycle_values = {"h11", "h12", "h23",
+ "h24"};
+ const std::vector<const char*> case_first_values = {"upper", "lower",
+ "false"};
+ const std::vector<const char*> empty_values = {};
+ const std::array<OptionData, 6> kOptionToUnicodeTagMap = {
{{"calendar", "ca", &empty_values, false},
{"collation", "co", &empty_values, false},
{"hourCycle", "hc", &hour_cycle_values, false},
@@ -75,7 +95,7 @@ Maybe<bool> InsertOptionsIntoLocale(Isolate* isolate,
: Intl::GetStringOption(isolate, options, option_to_bcp47.name,
*(option_to_bcp47.possible_values),
"locale", &value_str);
- if (maybe_found.IsNothing()) return maybe_found;
+ MAYBE_RETURN(maybe_found, Nothing<bool>());
// TODO(cira): Use fallback value if value is not found to make
// this spec compliant.
@@ -138,19 +158,23 @@ bool PopulateLocaleWithUnicodeTags(Isolate* isolate, const char* icu_locale,
if (bcp47_key) {
const char* bcp47_value = uloc_toUnicodeLocaleType(bcp47_key, value);
if (bcp47_value) {
- Handle<String> bcp47_handle =
- factory->NewStringFromAsciiChecked(bcp47_value);
if (strcmp(bcp47_key, "kn") == 0) {
- locale_holder->set_numeric(*bcp47_handle);
+ locale_holder->set_numeric(GetNumeric(bcp47_value));
} else if (strcmp(bcp47_key, "ca") == 0) {
+ Handle<String> bcp47_handle =
+ factory->NewStringFromAsciiChecked(bcp47_value);
locale_holder->set_calendar(*bcp47_handle);
} else if (strcmp(bcp47_key, "kf") == 0) {
- locale_holder->set_case_first(*bcp47_handle);
+ locale_holder->set_case_first(GetCaseFirst(bcp47_value));
} else if (strcmp(bcp47_key, "co") == 0) {
+ Handle<String> bcp47_handle =
+ factory->NewStringFromAsciiChecked(bcp47_value);
locale_holder->set_collation(*bcp47_handle);
} else if (strcmp(bcp47_key, "hc") == 0) {
- locale_holder->set_hour_cycle(*bcp47_handle);
+ locale_holder->set_hour_cycle(GetHourCycle(bcp47_value));
} else if (strcmp(bcp47_key, "nu") == 0) {
+ Handle<String> bcp47_handle =
+ factory->NewStringFromAsciiChecked(bcp47_value);
locale_holder->set_numbering_system(*bcp47_handle);
}
}
@@ -163,17 +187,17 @@ bool PopulateLocaleWithUnicodeTags(Isolate* isolate, const char* icu_locale,
}
} // namespace
-MaybeHandle<JSLocale> JSLocale::InitializeLocale(Isolate* isolate,
- Handle<JSLocale> locale_holder,
- Handle<String> locale,
- Handle<JSReceiver> options) {
+MaybeHandle<JSLocale> JSLocale::Initialize(Isolate* isolate,
+ Handle<JSLocale> locale_holder,
+ Handle<String> locale,
+ Handle<JSReceiver> options) {
+ locale_holder->set_flags(0);
static const char* const kMethod = "Intl.Locale";
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
UErrorCode status = U_ZERO_ERROR;
// Get ICU locale format, and canonicalize it.
char icu_result[ULOC_FULLNAME_CAPACITY];
- char icu_canonical[ULOC_FULLNAME_CAPACITY];
if (locale->length() == 0) {
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kLocaleNotEmpty),
@@ -184,18 +208,20 @@ MaybeHandle<JSLocale> JSLocale::InitializeLocale(Isolate* isolate,
CHECK_LT(0, bcp47_locale.length());
CHECK_NOT_NULL(*bcp47_locale);
- int icu_length = uloc_forLanguageTag(
- *bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY, nullptr, &status);
+ int parsed_length = 0;
+ int icu_length =
+ uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
+ &parsed_length, &status);
- if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING ||
- icu_length == 0) {
+ if (U_FAILURE(status) ||
+ parsed_length < static_cast<int>(bcp47_locale.length()) ||
+ status == U_STRING_NOT_TERMINATED_WARNING || icu_length == 0) {
THROW_NEW_ERROR(
isolate,
NewRangeError(MessageTemplate::kLocaleBadParameters,
isolate->factory()->NewStringFromAsciiChecked(kMethod),
locale_holder),
JSLocale);
- return MaybeHandle<JSLocale>();
}
Maybe<bool> error = InsertOptionsIntoLocale(isolate, options, icu_result);
@@ -207,40 +233,26 @@ MaybeHandle<JSLocale> JSLocale::InitializeLocale(Isolate* isolate,
isolate->factory()->NewStringFromAsciiChecked(kMethod),
locale_holder),
JSLocale);
- return MaybeHandle<JSLocale>();
- }
- DCHECK(error.FromJust());
-
- uloc_canonicalize(icu_result, icu_canonical, ULOC_FULLNAME_CAPACITY, &status);
- if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
- THROW_NEW_ERROR(
- isolate,
- NewRangeError(MessageTemplate::kLocaleBadParameters,
- isolate->factory()->NewStringFromAsciiChecked(kMethod),
- locale_holder),
- JSLocale);
- return MaybeHandle<JSLocale>();
}
- if (!PopulateLocaleWithUnicodeTags(isolate, icu_canonical, locale_holder)) {
+ if (!PopulateLocaleWithUnicodeTags(isolate, icu_result, locale_holder)) {
THROW_NEW_ERROR(
isolate,
NewRangeError(MessageTemplate::kLocaleBadParameters,
isolate->factory()->NewStringFromAsciiChecked(kMethod),
locale_holder),
JSLocale);
- return MaybeHandle<JSLocale>();
}
// Extract language, script and region parts.
char icu_language[ULOC_LANG_CAPACITY];
- uloc_getLanguage(icu_canonical, icu_language, ULOC_LANG_CAPACITY, &status);
+ uloc_getLanguage(icu_result, icu_language, ULOC_LANG_CAPACITY, &status);
char icu_script[ULOC_SCRIPT_CAPACITY];
- uloc_getScript(icu_canonical, icu_script, ULOC_SCRIPT_CAPACITY, &status);
+ uloc_getScript(icu_result, icu_script, ULOC_SCRIPT_CAPACITY, &status);
char icu_region[ULOC_COUNTRY_CAPACITY];
- uloc_getCountry(icu_canonical, icu_region, ULOC_COUNTRY_CAPACITY, &status);
+ uloc_getCountry(icu_result, icu_region, ULOC_COUNTRY_CAPACITY, &status);
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
THROW_NEW_ERROR(
@@ -249,7 +261,6 @@ MaybeHandle<JSLocale> JSLocale::InitializeLocale(Isolate* isolate,
isolate->factory()->NewStringFromAsciiChecked(kMethod),
locale_holder),
JSLocale);
- return MaybeHandle<JSLocale>();
}
Factory* factory = isolate->factory();
@@ -271,8 +282,7 @@ MaybeHandle<JSLocale> JSLocale::InitializeLocale(Isolate* isolate,
}
char icu_base_name[ULOC_FULLNAME_CAPACITY];
- uloc_getBaseName(icu_canonical, icu_base_name, ULOC_FULLNAME_CAPACITY,
- &status);
+ uloc_getBaseName(icu_result, icu_base_name, ULOC_FULLNAME_CAPACITY, &status);
// We need to convert it back to BCP47.
char bcp47_result[ULOC_FULLNAME_CAPACITY];
uloc_toLanguageTag(icu_base_name, bcp47_result, ULOC_FULLNAME_CAPACITY, true,
@@ -284,13 +294,12 @@ MaybeHandle<JSLocale> JSLocale::InitializeLocale(Isolate* isolate,
isolate->factory()->NewStringFromAsciiChecked(kMethod),
locale_holder),
JSLocale);
- return MaybeHandle<JSLocale>();
}
Handle<String> base_name = factory->NewStringFromAsciiChecked(bcp47_result);
locale_holder->set_base_name(*base_name);
// Produce final representation of the locale string, for toString().
- uloc_toLanguageTag(icu_canonical, bcp47_result, ULOC_FULLNAME_CAPACITY, true,
+ uloc_toLanguageTag(icu_result, bcp47_result, ULOC_FULLNAME_CAPACITY, true,
&status);
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
THROW_NEW_ERROR(
@@ -299,7 +308,6 @@ MaybeHandle<JSLocale> JSLocale::InitializeLocale(Isolate* isolate,
isolate->factory()->NewStringFromAsciiChecked(kMethod),
locale_holder),
JSLocale);
- return MaybeHandle<JSLocale>();
}
Handle<String> locale_handle =
factory->NewStringFromAsciiChecked(bcp47_result);
@@ -310,20 +318,37 @@ MaybeHandle<JSLocale> JSLocale::InitializeLocale(Isolate* isolate,
namespace {
-Handle<String> MorphLocale(Isolate* isolate, String* input,
+Handle<String> MorphLocale(Isolate* isolate, String* language_tag,
int32_t (*morph_func)(const char*, char*, int32_t,
UErrorCode*)) {
Factory* factory = isolate->factory();
char localeBuffer[ULOC_FULLNAME_CAPACITY];
+ char morphBuffer[ULOC_FULLNAME_CAPACITY];
+
UErrorCode status = U_ZERO_ERROR;
+ // Convert from language id to locale.
+ int32_t parsed_length;
+ int32_t length =
+ uloc_forLanguageTag(language_tag->ToCString().get(), localeBuffer,
+ ULOC_FULLNAME_CAPACITY, &parsed_length, &status);
+ CHECK(parsed_length == language_tag->length());
+ DCHECK(U_SUCCESS(status));
+ DCHECK_GT(length, 0);
DCHECK_NOT_NULL(morph_func);
- int32_t length = (*morph_func)(input->ToCString().get(), localeBuffer,
- ULOC_FULLNAME_CAPACITY, &status);
+ // Add the likely subtags or Minimize the subtags on the locale id
+ length =
+ (*morph_func)(localeBuffer, morphBuffer, ULOC_FULLNAME_CAPACITY, &status);
+ DCHECK(U_SUCCESS(status));
+ DCHECK_GT(length, 0);
+ // Returns a well-formed language tag
+ length = uloc_toLanguageTag(morphBuffer, localeBuffer, ULOC_FULLNAME_CAPACITY,
+ false, &status);
DCHECK(U_SUCCESS(status));
DCHECK_GT(length, 0);
- std::string locale(localeBuffer, length);
- std::replace(locale.begin(), locale.end(), '_', '-');
- return factory->NewStringFromAsciiChecked(locale.c_str());
+ std::string lang(localeBuffer, length);
+ std::replace(lang.begin(), lang.end(), '_', '-');
+
+ return factory->NewStringFromAsciiChecked(lang.c_str());
}
} // namespace
@@ -336,5 +361,46 @@ Handle<String> JSLocale::Minimize(Isolate* isolate, String* locale) {
return MorphLocale(isolate, locale, uloc_minimizeSubtags);
}
+Handle<String> JSLocale::CaseFirstAsString() const {
+ switch (case_first()) {
+ case CaseFirst::UPPER:
+ return GetReadOnlyRoots().upper_string_handle();
+ case CaseFirst::LOWER:
+ return GetReadOnlyRoots().lower_string_handle();
+ case CaseFirst::FALSE_VALUE:
+ return GetReadOnlyRoots().false_string_handle();
+ case CaseFirst::COUNT:
+ UNREACHABLE();
+ }
+}
+
+Handle<String> JSLocale::HourCycleAsString() const {
+ switch (hour_cycle()) {
+ case HourCycle::H11:
+ return GetReadOnlyRoots().h11_string_handle();
+ case HourCycle::H12:
+ return GetReadOnlyRoots().h12_string_handle();
+ case HourCycle::H23:
+ return GetReadOnlyRoots().h23_string_handle();
+ case HourCycle::H24:
+ return GetReadOnlyRoots().h24_string_handle();
+ case HourCycle::COUNT:
+ UNREACHABLE();
+ }
+}
+
+Handle<String> JSLocale::NumericAsString() const {
+ switch (numeric()) {
+ case Numeric::NOTSET:
+ return GetReadOnlyRoots().undefined_string_handle();
+ case Numeric::TRUE_VALUE:
+ return GetReadOnlyRoots().true_string_handle();
+ case Numeric::FALSE_VALUE:
+ return GetReadOnlyRoots().false_string_handle();
+ case Numeric::COUNT:
+ UNREACHABLE();
+ }
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/objects/js-locale.h b/deps/v8/src/objects/js-locale.h
index d111885d52..f42a4cdaee 100644
--- a/deps/v8/src/objects/js-locale.h
+++ b/deps/v8/src/objects/js-locale.h
@@ -25,13 +25,17 @@ class JSLocale : public JSObject {
public:
// Initializes locale object with properties derived from input locale string
// and options.
- static MaybeHandle<JSLocale> InitializeLocale(Isolate* isolate,
- Handle<JSLocale> locale_holder,
- Handle<String> locale,
- Handle<JSReceiver> options);
+ static MaybeHandle<JSLocale> Initialize(Isolate* isolate,
+ Handle<JSLocale> locale_holder,
+ Handle<String> locale,
+ Handle<JSReceiver> options);
static Handle<String> Maximize(Isolate* isolate, String* locale);
static Handle<String> Minimize(Isolate* isolate, String* locale);
+ Handle<String> CaseFirstAsString() const;
+ Handle<String> NumericAsString() const;
+ Handle<String> HourCycleAsString() const;
+
DECL_CAST(JSLocale)
// Locale accessors.
@@ -43,12 +47,64 @@ class JSLocale : public JSObject {
// Unicode extension accessors.
DECL_ACCESSORS(calendar, Object)
- DECL_ACCESSORS(case_first, Object)
DECL_ACCESSORS(collation, Object)
- DECL_ACCESSORS(hour_cycle, Object)
- DECL_ACCESSORS(numeric, Object)
DECL_ACCESSORS(numbering_system, Object)
+ // CaseFirst: "kf"
+ //
+ // ecma402 #sec-Intl.Locale.prototype.caseFirst
+ enum class CaseFirst {
+ UPPER, // upper case sorts before lower case
+ LOWER, // lower case sorts before upper case
+ // (compiler does not like FALSE so we have to name it FALSE_VALUE)
+ FALSE_VALUE, // Turn the feature off
+ COUNT
+ };
+ inline void set_case_first(CaseFirst case_first);
+ inline CaseFirst case_first() const;
+
+ // Numeric: 'kn"
+ //
+ // ecma402 #sec-Intl.Locale.prototype.numeric
+ enum class Numeric { NOTSET, TRUE_VALUE, FALSE_VALUE, COUNT };
+ inline void set_numeric(Numeric numeric);
+ inline Numeric numeric() const;
+
+ // CaseFirst: "hc"
+ //
+ // ecma402 #sec-Intl.Locale.prototype.hourCycle
+ enum class HourCycle {
+ H11, // 12-hour format start with hour 0 and go up to 11.
+ H12, // 12-hour format start with hour 1 and go up to 12.
+ H23, // 24-hour format start with hour 0 and go up to 23.
+ H24, // 24-hour format start with hour 1 and go up to 24.
+ COUNT
+ };
+ inline void set_hour_cycle(HourCycle hour_cycle);
+ inline HourCycle hour_cycle() const;
+
+// Bit positions in |flags|.
+#define FLAGS_BIT_FIELDS(V, _) \
+ V(CaseFirstBits, CaseFirst, 2, _) \
+ V(NumericBits, Numeric, 2, _) \
+ V(HourCycleBits, HourCycle, 2, _)
+ DEFINE_BIT_FIELDS(FLAGS_BIT_FIELDS)
+#undef FLAGS_BIT_FIELDS
+
+ STATIC_ASSERT(CaseFirst::UPPER <= CaseFirstBits::kMax);
+ STATIC_ASSERT(CaseFirst::LOWER <= CaseFirstBits::kMax);
+ STATIC_ASSERT(CaseFirst::FALSE_VALUE <= CaseFirstBits::kMax);
+ STATIC_ASSERT(Numeric::NOTSET <= NumericBits::kMax);
+ STATIC_ASSERT(Numeric::FALSE_VALUE <= NumericBits::kMax);
+ STATIC_ASSERT(Numeric::TRUE_VALUE <= NumericBits::kMax);
+ STATIC_ASSERT(HourCycle::H11 <= HourCycleBits::kMax);
+ STATIC_ASSERT(HourCycle::H12 <= HourCycleBits::kMax);
+ STATIC_ASSERT(HourCycle::H23 <= HourCycleBits::kMax);
+ STATIC_ASSERT(HourCycle::H24 <= HourCycleBits::kMax);
+
+ // [flags] Bit field containing various flags about the function.
+ DECL_INT_ACCESSORS(flags)
+
DECL_PRINTER(JSLocale)
DECL_VERIFIER(JSLocale)
@@ -61,12 +117,10 @@ class JSLocale : public JSObject {
static const int kBaseNameOffset = kRegionOffset + kPointerSize;
static const int kLocaleOffset = kBaseNameOffset + kPointerSize;
// Unicode extension fields.
- static const int kCalendarOffset = kLocaleOffset + kPointerSize;
- static const int kCaseFirstOffset = kCalendarOffset + kPointerSize;
- static const int kCollationOffset = kCaseFirstOffset + kPointerSize;
- static const int kHourCycleOffset = kCollationOffset + kPointerSize;
- static const int kNumericOffset = kHourCycleOffset + kPointerSize;
- static const int kNumberingSystemOffset = kNumericOffset + kPointerSize;
+ static const int kFlagsOffset = kLocaleOffset + kPointerSize;
+ static const int kCalendarOffset = kFlagsOffset + kPointerSize;
+ static const int kCollationOffset = kCalendarOffset + kPointerSize;
+ static const int kNumberingSystemOffset = kCollationOffset + kPointerSize;
// Final size.
static const int kSize = kNumberingSystemOffset + kPointerSize;
diff --git a/deps/v8/src/objects/js-number-format-inl.h b/deps/v8/src/objects/js-number-format-inl.h
new file mode 100644
index 0000000000..880ef9344f
--- /dev/null
+++ b/deps/v8/src/objects/js-number-format-inl.h
@@ -0,0 +1,58 @@
+// Copyright 2018 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_INTL_SUPPORT
+#error Internationalization is expected to be enabled.
+#endif // V8_INTL_SUPPORT
+
+#ifndef V8_OBJECTS_JS_NUMBER_FORMAT_INL_H_
+#define V8_OBJECTS_JS_NUMBER_FORMAT_INL_H_
+
+#include "src/objects-inl.h"
+#include "src/objects/js-number-format.h"
+
+// Has to be the last include (doesn't have include guards):
+#include "src/objects/object-macros.h"
+
+namespace v8 {
+namespace internal {
+
+ACCESSORS(JSNumberFormat, locale, String, kLocaleOffset)
+ACCESSORS(JSNumberFormat, icu_number_format, Managed<icu::NumberFormat>,
+ kICUNumberFormatOffset)
+ACCESSORS(JSNumberFormat, bound_format, Object, kBoundFormatOffset)
+SMI_ACCESSORS(JSNumberFormat, flags, kFlagsOffset)
+
+inline void JSNumberFormat::set_style(Style style) {
+ DCHECK_LT(style, Style::COUNT);
+ int hints = flags();
+ hints = StyleBits::update(hints, style);
+ set_flags(hints);
+}
+
+inline JSNumberFormat::Style JSNumberFormat::style() const {
+ return StyleBits::decode(flags());
+}
+
+inline void JSNumberFormat::set_currency_display(
+ CurrencyDisplay currency_display) {
+ DCHECK_LT(currency_display, CurrencyDisplay::COUNT);
+ int hints = flags();
+ hints = CurrencyDisplayBits::update(hints, currency_display);
+ set_flags(hints);
+}
+
+inline JSNumberFormat::CurrencyDisplay JSNumberFormat::currency_display()
+ const {
+ return CurrencyDisplayBits::decode(flags());
+}
+
+CAST_ACCESSOR(JSNumberFormat);
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_JS_NUMBER_FORMAT_INL_H_
diff --git a/deps/v8/src/objects/js-number-format.cc b/deps/v8/src/objects/js-number-format.cc
new file mode 100644
index 0000000000..9fe7c30a9d
--- /dev/null
+++ b/deps/v8/src/objects/js-number-format.cc
@@ -0,0 +1,709 @@
+// Copyright 2018 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_INTL_SUPPORT
+#error Internationalization is expected to be enabled.
+#endif // V8_INTL_SUPPORT
+
+#include "src/objects/js-number-format.h"
+
+#include <set>
+#include <string>
+
+#include "src/isolate.h"
+#include "src/objects-inl.h"
+#include "src/objects/intl-objects.h"
+#include "src/objects/js-number-format-inl.h"
+#include "unicode/decimfmt.h"
+#include "unicode/locid.h"
+#include "unicode/numfmt.h"
+#include "unicode/strenum.h"
+#include "unicode/ucurr.h"
+#include "unicode/uloc.h"
+
+namespace v8 {
+namespace internal {
+
+namespace {
+
+// ecma-402/#sec-currencydigits
+// The currency is expected to an all upper case string value.
+int CurrencyDigits(const icu::UnicodeString& currency) {
+ UErrorCode status = U_ZERO_ERROR;
+ uint32_t fraction_digits = ucurr_getDefaultFractionDigits(
+ reinterpret_cast<const UChar*>(currency.getBuffer()), &status);
+ // For missing currency codes, default to the most common, 2
+ return U_SUCCESS(status) ? fraction_digits : 2;
+}
+
+bool IsAToZ(char ch) { return IsInRange(AsciiAlphaToLower(ch), 'a', 'z'); }
+
+// ecma402/#sec-iswellformedcurrencycode
+bool IsWellFormedCurrencyCode(const std::string& currency) {
+ // Verifies that the input is a well-formed ISO 4217 currency code.
+ // ecma402/#sec-currency-codes
+ // 2. If the number of elements in normalized is not 3, return false.
+ if (currency.length() != 3) return false;
+ // 1. Let normalized be the result of mapping currency to upper case as
+ // described in 6.1.
+ //
+ // 3. If normalized contains any character that is not in
+ // the range "A" to "Z" (U+0041 to U+005A), return false.
+ //
+ // 4. Return true.
+ // Don't uppercase to test. It could convert invalid code into a valid one.
+ // For example \u00DFP (Eszett+P) becomes SSP.
+ return (IsAToZ(currency[0]) && IsAToZ(currency[1]) && IsAToZ(currency[2]));
+}
+
+} // anonymous namespace
+
+// static
+Handle<JSObject> JSNumberFormat::ResolvedOptions(
+ Isolate* isolate, Handle<JSNumberFormat> number_format_holder) {
+ Factory* factory = isolate->factory();
+ Handle<JSObject> options = factory->NewJSObject(isolate->object_function());
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options, factory->style_string(),
+ number_format_holder->StyleAsString(), kDontThrow)
+ .FromJust());
+
+ icu::NumberFormat* number_format =
+ number_format_holder->icu_number_format()->raw();
+ CHECK_NOT_NULL(number_format);
+ icu::DecimalFormat* decimal_format =
+ static_cast<icu::DecimalFormat*>(number_format);
+ CHECK_NOT_NULL(decimal_format);
+
+ Handle<String> locale =
+ Handle<String>(number_format_holder->locale(), isolate);
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options, factory->locale_string(), locale, kDontThrow)
+ .FromJust());
+ UErrorCode error = U_ZERO_ERROR;
+ icu::Locale icu_locale = number_format->getLocale(ULOC_VALID_LOCALE, error);
+ DCHECK(U_SUCCESS(error));
+
+ std::string numbering_system = Intl::GetNumberingSystem(icu_locale);
+ if (!numbering_system.empty()) {
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options, factory->numberingSystem_string(),
+ factory->NewStringFromAsciiChecked(numbering_system.c_str()),
+ kDontThrow)
+ .FromJust());
+ }
+
+ if (number_format_holder->style() == Style::CURRENCY) {
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options, factory->currencyDisplay_string(),
+ number_format_holder->CurrencyDisplayAsString(), kDontThrow)
+ .FromJust());
+ icu::UnicodeString currency(number_format->getCurrency());
+ DCHECK(!currency.isEmpty());
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options, factory->currency_string(),
+ factory
+ ->NewStringFromTwoByte(Vector<const uint16_t>(
+ reinterpret_cast<const uint16_t*>(currency.getBuffer()),
+ currency.length()))
+ .ToHandleChecked(),
+ kDontThrow)
+ .FromJust());
+ }
+
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options, factory->minimumIntegerDigits_string(),
+ factory->NewNumberFromInt(number_format->getMinimumIntegerDigits()),
+ kDontThrow)
+ .FromJust());
+ CHECK(
+ JSReceiver::CreateDataProperty(
+ isolate, options, factory->minimumFractionDigits_string(),
+ factory->NewNumberFromInt(number_format->getMinimumFractionDigits()),
+ kDontThrow)
+ .FromJust());
+ CHECK(
+ JSReceiver::CreateDataProperty(
+ isolate, options, factory->maximumFractionDigits_string(),
+ factory->NewNumberFromInt(number_format->getMaximumFractionDigits()),
+ kDontThrow)
+ .FromJust());
+ if (decimal_format->areSignificantDigitsUsed()) {
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options, factory->minimumSignificantDigits_string(),
+ factory->NewNumberFromInt(
+ decimal_format->getMinimumSignificantDigits()),
+ kDontThrow)
+ .FromJust());
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options, factory->maximumSignificantDigits_string(),
+ factory->NewNumberFromInt(
+ decimal_format->getMaximumSignificantDigits()),
+ kDontThrow)
+ .FromJust());
+ }
+ CHECK(JSReceiver::CreateDataProperty(
+ isolate, options, factory->useGrouping_string(),
+ factory->ToBoolean((number_format->isGroupingUsed() == TRUE)),
+ kDontThrow)
+ .FromJust());
+
+ return options;
+}
+
+// ecma402/#sec-unwrapnumberformat
+MaybeHandle<JSNumberFormat> JSNumberFormat::UnwrapNumberFormat(
+ Isolate* isolate, Handle<JSReceiver> format_holder) {
+ // old code copy from NumberFormat::Unwrap that has no spec comment and
+ // compiled but fail unit tests.
+ Handle<Context> native_context =
+ Handle<Context>(isolate->context()->native_context(), isolate);
+ Handle<JSFunction> constructor = Handle<JSFunction>(
+ JSFunction::cast(native_context->intl_number_format_function()), isolate);
+ Handle<Object> object;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, object,
+ Intl::LegacyUnwrapReceiver(isolate, format_holder, constructor,
+ format_holder->IsJSNumberFormat()),
+ JSNumberFormat);
+ // 4. If ... or nf does not have an [[InitializedNumberFormat]] internal slot,
+ // then
+ if (!object->IsJSNumberFormat()) {
+ // a. Throw a TypeError exception.
+ THROW_NEW_ERROR(isolate,
+ NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
+ isolate->factory()->NewStringFromAsciiChecked(
+ "UnwrapNumberFormat")),
+ JSNumberFormat);
+ }
+ // 5. Return nf.
+ return Handle<JSNumberFormat>::cast(object);
+}
+
+// static
+MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize(
+ Isolate* isolate, Handle<JSNumberFormat> number_format,
+ Handle<Object> locales, Handle<Object> options_obj) {
+ // set the flags to 0 ASAP.
+ number_format->set_flags(0);
+ Factory* factory = isolate->factory();
+ // 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
+ Handle<JSObject> requested_locales;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, requested_locales,
+ Intl::CanonicalizeLocaleListJS(isolate, locales),
+ JSNumberFormat);
+
+ // 2. If options is undefined, then
+ if (options_obj->IsUndefined(isolate)) {
+ // 2. a. Let options be ObjectCreate(null).
+ options_obj = isolate->factory()->NewJSObjectWithNullProto();
+ } else {
+ // 3. Else
+ // 3. a. Let options be ? ToObject(options).
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, options_obj,
+ Object::ToObject(isolate, options_obj, "Intl.NumberFormat"),
+ JSNumberFormat);
+ }
+
+ // At this point, options_obj can either be a JSObject or a JSProxy only.
+ Handle<JSReceiver> options = Handle<JSReceiver>::cast(options_obj);
+
+ // 4. Let opt be a new Record.
+ //
+ // 5. Let matcher be ? GetOption(options, "localeMatcher", "string", «
+ // "lookup", "best fit" », "best fit").
+ //
+ // 6. Set opt.[[localeMatcher]] to matcher.
+ //
+ // 7. Let localeData be %NumberFormat%.[[LocaleData]].
+ //
+ // 8. Let r be ResolveLocale(%NumberFormat%.[[AvailableLocales]],
+ // requestedLocales, opt, %NumberFormat%.[[RelevantExtensionKeys]],
+ // localeData).
+ //
+ // 9. Set numberFormat.[[Locale]] to r.[[locale]].
+
+ Handle<JSObject> r;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, r,
+ Intl::ResolveLocale(isolate, "numberformat", requested_locales, options),
+ JSNumberFormat);
+
+ Handle<String> locale_with_extension_str =
+ isolate->factory()->NewStringFromStaticChars("localeWithExtension");
+ Handle<Object> locale_with_extension_obj =
+ JSObject::GetDataProperty(r, locale_with_extension_str);
+
+ // The locale_with_extension has to be a string. Either a user
+ // provided canonicalized string or the default locale.
+ CHECK(locale_with_extension_obj->IsString());
+ Handle<String> locale_with_extension =
+ Handle<String>::cast(locale_with_extension_obj);
+
+ icu::Locale icu_locale =
+ Intl::CreateICULocale(isolate, locale_with_extension);
+ number_format->set_locale(*locale_with_extension);
+ DCHECK(!icu_locale.isBogus());
+
+ std::set<std::string> relevant_extension_keys{"nu"};
+ std::map<std::string, std::string> extensions =
+ Intl::LookupUnicodeExtensions(icu_locale, relevant_extension_keys);
+
+ // The list that is the value of the "nu" field of any locale field of
+ // [[LocaleData]] must not include the values "native", "traditio", or
+ // "finance".
+ //
+ // See https://tc39.github.io/ecma402/#sec-intl.numberformat-internal-slots
+ if (extensions.find("nu") != extensions.end()) {
+ const std::string value = extensions.at("nu");
+ if (value == "native" || value == "traditio" || value == "finance") {
+ // 10. Set numberFormat.[[NumberingSystem]] to r.[[nu]].
+ UErrorCode status = U_ZERO_ERROR;
+ icu_locale.setKeywordValue("nu", nullptr, status);
+ CHECK(U_SUCCESS(status));
+ }
+ }
+
+ // 11. Let dataLocale be r.[[dataLocale]].
+ //
+ // 12. Let style be ? GetOption(options, "style", "string", « "decimal",
+ // "percent", "currency" », "decimal").
+ const char* service = "Intl.NumberFormat";
+ std::unique_ptr<char[]> style_cstr;
+ const std::vector<const char*> style_values = {"decimal", "percent",
+ "currency"};
+ Maybe<bool> found_style = Intl::GetStringOption(
+ isolate, options, "style", style_values, service, &style_cstr);
+ MAYBE_RETURN(found_style, MaybeHandle<JSNumberFormat>());
+ Style style = Style::DECIMAL;
+ if (found_style.FromJust()) {
+ DCHECK_NOT_NULL(style_cstr.get());
+ if (strcmp(style_cstr.get(), "percent") == 0) {
+ style = Style::PERCENT;
+ } else if (strcmp(style_cstr.get(), "currency") == 0) {
+ style = Style::CURRENCY;
+ }
+ }
+
+ // 13. Set numberFormat.[[Style]] to style.
+ number_format->set_style(style);
+
+ // 14. Let currency be ? GetOption(options, "currency", "string", undefined,
+ // undefined).
+ std::unique_ptr<char[]> currency_cstr;
+ const std::vector<const char*> empty_values = {};
+ Maybe<bool> found_currency = Intl::GetStringOption(
+ isolate, options, "currency", empty_values, service, &currency_cstr);
+ MAYBE_RETURN(found_currency, MaybeHandle<JSNumberFormat>());
+
+ std::string currency;
+ // 15. If currency is not undefined, then
+ if (found_currency.FromJust()) {
+ DCHECK_NOT_NULL(currency_cstr.get());
+ currency = currency_cstr.get();
+ // 15. a. If the result of IsWellFormedCurrencyCode(currency) is false,
+ // throw a RangeError exception.
+ if (!IsWellFormedCurrencyCode(currency)) {
+ THROW_NEW_ERROR(
+ isolate,
+ NewRangeError(MessageTemplate::kInvalidCurrencyCode,
+ factory->NewStringFromAsciiChecked(currency.c_str())),
+ JSNumberFormat);
+ }
+ }
+
+ // 16. If style is "currency" and currency is undefined, throw a TypeError
+ // exception.
+ if (style == Style::CURRENCY && !found_currency.FromJust()) {
+ THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kCurrencyCode),
+ JSNumberFormat);
+ }
+ // 17. If style is "currency", then
+ int c_digits = 0;
+ icu::UnicodeString currency_ustr;
+ if (style == Style::CURRENCY) {
+ // a. Let currency be the result of converting currency to upper case as
+ // specified in 6.1
+ std::transform(currency.begin(), currency.end(), currency.begin(), toupper);
+ // c. Let cDigits be CurrencyDigits(currency).
+ currency_ustr = currency.c_str();
+ c_digits = CurrencyDigits(currency_ustr);
+ }
+
+ // 18. Let currencyDisplay be ? GetOption(options, "currencyDisplay",
+ // "string", « "code", "symbol", "name" », "symbol").
+ std::unique_ptr<char[]> currency_display_cstr;
+ const std::vector<const char*> currency_display_values = {"code", "name",
+ "symbol"};
+ Maybe<bool> found_currency_display = Intl::GetStringOption(
+ isolate, options, "currencyDisplay", currency_display_values, service,
+ &currency_display_cstr);
+ MAYBE_RETURN(found_currency_display, MaybeHandle<JSNumberFormat>());
+ CurrencyDisplay currency_display = CurrencyDisplay::SYMBOL;
+ UNumberFormatStyle format_style = UNUM_CURRENCY;
+
+ if (found_currency_display.FromJust()) {
+ DCHECK_NOT_NULL(currency_display_cstr.get());
+ if (strcmp(currency_display_cstr.get(), "code") == 0) {
+ currency_display = CurrencyDisplay::CODE;
+ format_style = UNUM_CURRENCY_ISO;
+ } else if (strcmp(currency_display_cstr.get(), "name") == 0) {
+ currency_display = CurrencyDisplay::NAME;
+ format_style = UNUM_CURRENCY_PLURAL;
+ }
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ std::unique_ptr<icu::NumberFormat> icu_number_format;
+ if (style == Style::DECIMAL) {
+ icu_number_format.reset(
+ icu::NumberFormat::createInstance(icu_locale, status));
+ } else if (style == Style::PERCENT) {
+ icu_number_format.reset(
+ icu::NumberFormat::createPercentInstance(icu_locale, status));
+ } else {
+ DCHECK_EQ(style, Style::CURRENCY);
+ icu_number_format.reset(
+ icu::NumberFormat::createInstance(icu_locale, format_style, status));
+ }
+
+ if (U_FAILURE(status) || icu_number_format.get() == nullptr) {
+ status = U_ZERO_ERROR;
+ // Remove extensions and try again.
+ icu::Locale no_extension_locale(icu_locale.getBaseName());
+ icu_number_format.reset(
+ icu::NumberFormat::createInstance(no_extension_locale, status));
+
+ if (U_FAILURE(status) || icu_number_format.get() == nullptr) {
+ FATAL("Failed to create ICU number_format, are ICU data files missing?");
+ }
+ }
+ DCHECK(U_SUCCESS(status));
+ CHECK_NOT_NULL(icu_number_format.get());
+ if (style == Style::CURRENCY) {
+ // 19. If style is "currency", set numberFormat.[[CurrencyDisplay]] to
+ // currencyDisplay.
+ number_format->set_currency_display(currency_display);
+
+ // 17.b. Set numberFormat.[[Currency]] to currency.
+ if (!currency_ustr.isEmpty()) {
+ status = U_ZERO_ERROR;
+ icu_number_format->setCurrency(currency_ustr.getBuffer(), status);
+ CHECK(U_SUCCESS(status));
+ }
+ }
+
+ // 20. If style is "currency", then
+ int mnfd_default, mxfd_default;
+ if (style == Style::CURRENCY) {
+ // a. Let mnfdDefault be cDigits.
+ // b. Let mxfdDefault be cDigits.
+ mnfd_default = c_digits;
+ mxfd_default = c_digits;
+ } else {
+ // 21. Else,
+ // a. Let mnfdDefault be 0.
+ mnfd_default = 0;
+ // b. If style is "percent", then
+ if (style == Style::PERCENT) {
+ // i. Let mxfdDefault be 0.
+ mxfd_default = 0;
+ } else {
+ // c. Else,
+ // i. Let mxfdDefault be 3.
+ mxfd_default = 3;
+ }
+ }
+ // 22. Perform ? SetNumberFormatDigitOptions(numberFormat, options,
+ // mnfdDefault, mxfdDefault).
+ icu::DecimalFormat* icu_decimal_format =
+ static_cast<icu::DecimalFormat*>(icu_number_format.get());
+ Maybe<bool> maybe_set_number_for_digit_options =
+ Intl::SetNumberFormatDigitOptions(isolate, icu_decimal_format, options,
+ mnfd_default, mxfd_default);
+ MAYBE_RETURN(maybe_set_number_for_digit_options, Handle<JSNumberFormat>());
+
+ // 23. Let useGrouping be ? GetOption(options, "useGrouping", "boolean",
+ // undefined, true).
+ bool use_grouping = true;
+ Maybe<bool> found_use_grouping = Intl::GetBoolOption(
+ isolate, options, "useGrouping", service, &use_grouping);
+ MAYBE_RETURN(found_use_grouping, MaybeHandle<JSNumberFormat>());
+ // 24. Set numberFormat.[[UseGrouping]] to useGrouping.
+ icu_number_format->setGroupingUsed(use_grouping ? TRUE : FALSE);
+
+ // 25. Let dataLocaleData be localeData.[[<dataLocale>]].
+ //
+ // 26. Let patterns be dataLocaleData.[[patterns]].
+ //
+ // 27. Assert: patterns is a record (see 11.3.3).
+ //
+ // 28. Let stylePatterns be patterns.[[<style>]].
+ //
+ // 29. Set numberFormat.[[PositivePattern]] to
+ // stylePatterns.[[positivePattern]].
+ //
+ // 30. Set numberFormat.[[NegativePattern]] to
+ // stylePatterns.[[negativePattern]].
+
+ Handle<Managed<icu::NumberFormat>> managed_number_format =
+ Managed<icu::NumberFormat>::FromUniquePtr(isolate, 0,
+ std::move(icu_number_format));
+ number_format->set_icu_number_format(*managed_number_format);
+ number_format->set_bound_format(*factory->undefined_value());
+
+ // 31. Return numberFormat.
+ return number_format;
+}
+
+Handle<String> JSNumberFormat::StyleAsString() const {
+ switch (style()) {
+ case Style::DECIMAL:
+ return GetReadOnlyRoots().decimal_string_handle();
+ case Style::PERCENT:
+ return GetReadOnlyRoots().percent_string_handle();
+ case Style::CURRENCY:
+ return GetReadOnlyRoots().currency_string_handle();
+ case Style::COUNT:
+ UNREACHABLE();
+ }
+}
+
+Handle<String> JSNumberFormat::CurrencyDisplayAsString() const {
+ switch (currency_display()) {
+ case CurrencyDisplay::CODE:
+ return GetReadOnlyRoots().code_string_handle();
+ case CurrencyDisplay::SYMBOL:
+ return GetReadOnlyRoots().symbol_string_handle();
+ case CurrencyDisplay::NAME:
+ return GetReadOnlyRoots().name_string_handle();
+ case CurrencyDisplay::COUNT:
+ UNREACHABLE();
+ }
+}
+
+MaybeHandle<String> JSNumberFormat::FormatNumber(
+ Isolate* isolate, Handle<JSNumberFormat> number_format_holder,
+ double number) {
+ icu::NumberFormat* number_format =
+ number_format_holder->icu_number_format()->raw();
+ CHECK_NOT_NULL(number_format);
+
+ icu::UnicodeString result;
+ number_format->format(number, result);
+
+ return isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
+ reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length()));
+}
+
+namespace {
+
+bool cmp_NumberFormatSpan(const NumberFormatSpan& a,
+ const NumberFormatSpan& b) {
+ // Regions that start earlier should be encountered earlier.
+ if (a.begin_pos < b.begin_pos) return true;
+ if (a.begin_pos > b.begin_pos) return false;
+ // For regions that start in the same place, regions that last longer should
+ // be encountered earlier.
+ if (a.end_pos < b.end_pos) return false;
+ if (a.end_pos > b.end_pos) return true;
+ // For regions that are exactly the same, one of them must be the "literal"
+ // backdrop we added, which has a field_id of -1, so consider higher field_ids
+ // to be later.
+ return a.field_id < b.field_id;
+}
+
+// The list comes from third_party/icu/source/i18n/unicode/unum.h.
+// They're mapped to NumberFormat part types mentioned throughout
+// https://tc39.github.io/ecma402/#sec-partitionnumberpattern .
+Handle<String> IcuNumberFieldIdToNumberType(int32_t field_id, double number,
+ Isolate* isolate) {
+ switch (static_cast<UNumberFormatFields>(field_id)) {
+ case UNUM_INTEGER_FIELD:
+ if (std::isfinite(number)) return isolate->factory()->integer_string();
+ if (std::isnan(number)) return isolate->factory()->nan_string();
+ return isolate->factory()->infinity_string();
+ case UNUM_FRACTION_FIELD:
+ return isolate->factory()->fraction_string();
+ case UNUM_DECIMAL_SEPARATOR_FIELD:
+ return isolate->factory()->decimal_string();
+ case UNUM_GROUPING_SEPARATOR_FIELD:
+ return isolate->factory()->group_string();
+ case UNUM_CURRENCY_FIELD:
+ return isolate->factory()->currency_string();
+ case UNUM_PERCENT_FIELD:
+ return isolate->factory()->percentSign_string();
+ case UNUM_SIGN_FIELD:
+ return number < 0 ? isolate->factory()->minusSign_string()
+ : isolate->factory()->plusSign_string();
+
+ case UNUM_EXPONENT_SYMBOL_FIELD:
+ case UNUM_EXPONENT_SIGN_FIELD:
+ case UNUM_EXPONENT_FIELD:
+ // We should never get these because we're not using any scientific
+ // formatter.
+ UNREACHABLE();
+ return Handle<String>();
+
+ case UNUM_PERMILL_FIELD:
+ // We're not creating any permill formatter, and it's not even clear how
+ // that would be possible with the ICU API.
+ UNREACHABLE();
+ return Handle<String>();
+
+ default:
+ UNREACHABLE();
+ return Handle<String>();
+ }
+}
+} // namespace
+
+// Flattens a list of possibly-overlapping "regions" to a list of
+// non-overlapping "parts". At least one of the input regions must span the
+// entire space of possible indexes. The regions parameter will sorted in-place
+// according to some criteria; this is done for performance to avoid copying the
+// input.
+std::vector<NumberFormatSpan> FlattenRegionsToParts(
+ std::vector<NumberFormatSpan>* regions) {
+ // The intention of this algorithm is that it's used to translate ICU "fields"
+ // to JavaScript "parts" of a formatted string. Each ICU field and JavaScript
+ // part has an integer field_id, which corresponds to something like "grouping
+ // separator", "fraction", or "percent sign", and has a begin and end
+ // position. Here's a diagram of:
+
+ // var nf = new Intl.NumberFormat(['de'], {style:'currency',currency:'EUR'});
+ // nf.formatToParts(123456.78);
+
+ // : 6
+ // input regions: 0000000211 7
+ // ('-' means -1): ------------
+ // formatted string: "123.456,78 €"
+ // output parts: 0006000211-7
+
+ // To illustrate the requirements of this algorithm, here's a contrived and
+ // convoluted example of inputs and expected outputs:
+
+ // : 4
+ // : 22 33 3
+ // : 11111 22
+ // input regions: 0000000 111
+ // : ------------
+ // formatted string: "abcdefghijkl"
+ // output parts: 0221340--231
+ // (The characters in the formatted string are irrelevant to this function.)
+
+ // We arrange the overlapping input regions like a mountain range where
+ // smaller regions are "on top" of larger regions, and we output a birds-eye
+ // view of the mountains, so that smaller regions take priority over larger
+ // regions.
+ std::sort(regions->begin(), regions->end(), cmp_NumberFormatSpan);
+ std::vector<size_t> overlapping_region_index_stack;
+ // At least one item in regions must be a region spanning the entire string.
+ // Due to the sorting above, the first item in the vector will be one of them.
+ overlapping_region_index_stack.push_back(0);
+ NumberFormatSpan top_region = regions->at(0);
+ size_t region_iterator = 1;
+ int32_t entire_size = top_region.end_pos;
+
+ std::vector<NumberFormatSpan> out_parts;
+
+ // The "climber" is a cursor that advances from left to right climbing "up"
+ // and "down" the mountains. Whenever the climber moves to the right, that
+ // represents an item of output.
+ int32_t climber = 0;
+ while (climber < entire_size) {
+ int32_t next_region_begin_pos;
+ if (region_iterator < regions->size()) {
+ next_region_begin_pos = regions->at(region_iterator).begin_pos;
+ } else {
+ // finish off the rest of the input by proceeding to the end.
+ next_region_begin_pos = entire_size;
+ }
+
+ if (climber < next_region_begin_pos) {
+ while (top_region.end_pos < next_region_begin_pos) {
+ if (climber < top_region.end_pos) {
+ // step down
+ out_parts.push_back(NumberFormatSpan(top_region.field_id, climber,
+ top_region.end_pos));
+ climber = top_region.end_pos;
+ } else {
+ // drop down
+ }
+ overlapping_region_index_stack.pop_back();
+ top_region = regions->at(overlapping_region_index_stack.back());
+ }
+ if (climber < next_region_begin_pos) {
+ // cross a plateau/mesa/valley
+ out_parts.push_back(NumberFormatSpan(top_region.field_id, climber,
+ next_region_begin_pos));
+ climber = next_region_begin_pos;
+ }
+ }
+ if (region_iterator < regions->size()) {
+ overlapping_region_index_stack.push_back(region_iterator++);
+ top_region = regions->at(overlapping_region_index_stack.back());
+ }
+ }
+ return out_parts;
+}
+
+MaybeHandle<JSArray> JSNumberFormat::FormatToParts(
+ Isolate* isolate, Handle<JSNumberFormat> number_format, double number) {
+ Factory* factory = isolate->factory();
+ icu::NumberFormat* fmt = number_format->icu_number_format()->raw();
+ CHECK_NOT_NULL(fmt);
+
+ icu::UnicodeString formatted;
+ icu::FieldPositionIterator fp_iter;
+ UErrorCode status = U_ZERO_ERROR;
+ fmt->format(number, formatted, &fp_iter, status);
+ if (U_FAILURE(status)) {
+ THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), JSArray);
+ }
+
+ Handle<JSArray> result = factory->NewJSArray(0);
+ int32_t length = formatted.length();
+ if (length == 0) return result;
+
+ std::vector<NumberFormatSpan> regions;
+ // Add a "literal" backdrop for the entire string. This will be used if no
+ // other region covers some part of the formatted string. It's possible
+ // there's another field with exactly the same begin and end as this backdrop,
+ // in which case the backdrop's field_id of -1 will give it lower priority.
+ regions.push_back(NumberFormatSpan(-1, 0, formatted.length()));
+
+ {
+ icu::FieldPosition fp;
+ while (fp_iter.next(fp)) {
+ regions.push_back(NumberFormatSpan(fp.getField(), fp.getBeginIndex(),
+ fp.getEndIndex()));
+ }
+ }
+
+ std::vector<NumberFormatSpan> parts = FlattenRegionsToParts(&regions);
+
+ int index = 0;
+ for (auto it = parts.begin(); it < parts.end(); it++) {
+ NumberFormatSpan part = *it;
+ Handle<String> field_type_string =
+ part.field_id == -1
+ ? isolate->factory()->literal_string()
+ : IcuNumberFieldIdToNumberType(part.field_id, number, isolate);
+ Handle<String> substring;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, substring,
+ Intl::ToString(isolate, formatted, part.begin_pos, part.end_pos),
+ JSArray);
+ Intl::AddElement(isolate, result, index, field_type_string, substring);
+ ++index;
+ }
+ JSObject::ValidateElements(*result);
+
+ return result;
+}
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/objects/js-number-format.h b/deps/v8/src/objects/js-number-format.h
new file mode 100644
index 0000000000..52443dc3d3
--- /dev/null
+++ b/deps/v8/src/objects/js-number-format.h
@@ -0,0 +1,135 @@
+// Copyright 2018 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_INTL_SUPPORT
+#error Internationalization is expected to be enabled.
+#endif // V8_INTL_SUPPORT
+
+#ifndef V8_OBJECTS_JS_NUMBER_FORMAT_H_
+#define V8_OBJECTS_JS_NUMBER_FORMAT_H_
+
+#include "src/heap/factory.h"
+#include "src/isolate.h"
+#include "src/objects.h"
+#include "src/objects/intl-objects.h"
+#include "src/objects/managed.h"
+
+// Has to be the last include (doesn't have include guards):
+#include "src/objects/object-macros.h"
+
+namespace U_ICU_NAMESPACE {
+class NumberFormat;
+} // namespace U_ICU_NAMESPACE
+
+namespace v8 {
+namespace internal {
+
+class JSNumberFormat : public JSObject {
+ public:
+ // ecma402/#sec-initializenumberformat
+ V8_WARN_UNUSED_RESULT static MaybeHandle<JSNumberFormat> Initialize(
+ Isolate* isolate, Handle<JSNumberFormat> number_format,
+ Handle<Object> locales, Handle<Object> options);
+
+ // ecma402/#sec-unwrapnumberformat
+ V8_WARN_UNUSED_RESULT static MaybeHandle<JSNumberFormat> UnwrapNumberFormat(
+ Isolate* isolate, Handle<JSReceiver> format_holder);
+
+ // ecma402/#sec-intl.numberformat.prototype.resolvedoptions
+ static Handle<JSObject> ResolvedOptions(Isolate* isolate,
+ Handle<JSNumberFormat> number_format);
+
+ V8_WARN_UNUSED_RESULT static MaybeHandle<JSArray> FormatToParts(
+ Isolate* isolate, Handle<JSNumberFormat> number_format, double number);
+
+ V8_WARN_UNUSED_RESULT static MaybeHandle<String> FormatNumber(
+ Isolate* isolate, Handle<JSNumberFormat> number_format, double number);
+
+ Handle<String> StyleAsString() const;
+ Handle<String> CurrencyDisplayAsString() const;
+
+ DECL_CAST(JSNumberFormat)
+ DECL_PRINTER(JSNumberFormat)
+ DECL_VERIFIER(JSNumberFormat)
+
+ // [[Style]] is one of the values "decimal", "percent" or "currency",
+ // identifying the style of the number format.
+ enum class Style {
+ DECIMAL,
+ PERCENT,
+ CURRENCY,
+
+ COUNT
+ };
+ inline void set_style(Style style);
+ inline Style style() const;
+
+ // [[CurrencyDisplay]] is one of the values "code", "symbol" or "name",
+ // identifying the display of the currency number format.
+ enum class CurrencyDisplay {
+ CODE,
+ SYMBOL,
+ NAME,
+
+ COUNT
+ };
+ inline void set_currency_display(CurrencyDisplay currency_display);
+ inline CurrencyDisplay currency_display() const;
+
+// Layout description.
+#define JS_NUMBER_FORMAT_FIELDS(V) \
+ V(kLocaleOffset, kPointerSize) \
+ V(kICUNumberFormatOffset, kPointerSize) \
+ V(kBoundFormatOffset, kPointerSize) \
+ V(kFlagsOffset, kPointerSize) \
+ /* Total size. */ \
+ V(kSize, 0)
+
+ DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, JS_NUMBER_FORMAT_FIELDS)
+#undef JS_NUMBER_FORMAT_FIELDS
+
+// Bit positions in |flags|.
+#define FLAGS_BIT_FIELDS(V, _) \
+ V(StyleBits, Style, 2, _) \
+ V(CurrencyDisplayBits, CurrencyDisplay, 2, _)
+
+ DEFINE_BIT_FIELDS(FLAGS_BIT_FIELDS)
+#undef FLAGS_BIT_FIELDS
+
+ STATIC_ASSERT(Style::DECIMAL <= StyleBits::kMax);
+ STATIC_ASSERT(Style::PERCENT <= StyleBits::kMax);
+ STATIC_ASSERT(Style::CURRENCY <= StyleBits::kMax);
+
+ STATIC_ASSERT(CurrencyDisplay::CODE <= CurrencyDisplayBits::kMax);
+ STATIC_ASSERT(CurrencyDisplay::SYMBOL <= CurrencyDisplayBits::kMax);
+ STATIC_ASSERT(CurrencyDisplay::NAME <= CurrencyDisplayBits::kMax);
+
+ DECL_ACCESSORS(locale, String)
+ DECL_ACCESSORS(icu_number_format, Managed<icu::NumberFormat>)
+ DECL_ACCESSORS(bound_format, Object)
+ DECL_INT_ACCESSORS(flags)
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSNumberFormat);
+};
+
+struct NumberFormatSpan {
+ int32_t field_id;
+ int32_t begin_pos;
+ int32_t end_pos;
+
+ NumberFormatSpan() = default;
+ NumberFormatSpan(int32_t field_id, int32_t begin_pos, int32_t end_pos)
+ : field_id(field_id), begin_pos(begin_pos), end_pos(end_pos) {}
+};
+
+std::vector<NumberFormatSpan> FlattenRegionsToParts(
+ std::vector<NumberFormatSpan>* regions);
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_JS_NUMBER_FORMAT_H_
diff --git a/deps/v8/src/objects/js-objects-inl.h b/deps/v8/src/objects/js-objects-inl.h
new file mode 100644
index 0000000000..53483136d8
--- /dev/null
+++ b/deps/v8/src/objects/js-objects-inl.h
@@ -0,0 +1,904 @@
+// Copyright 2018 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_JS_OBJECTS_INL_H_
+#define V8_OBJECTS_JS_OBJECTS_INL_H_
+
+#include "src/objects/js-objects.h"
+
+#include "src/feedback-vector.h"
+#include "src/heap/heap-write-barrier.h"
+#include "src/keys.h"
+#include "src/lookup-inl.h"
+#include "src/objects/property-array-inl.h"
+#include "src/objects/shared-function-info.h"
+#include "src/prototype.h"
+
+// Has to be the last include (doesn't have include guards):
+#include "src/objects/object-macros.h"
+
+namespace v8 {
+namespace internal {
+
+CAST_ACCESSOR(JSAsyncFromSyncIterator)
+CAST_ACCESSOR(JSBoundFunction)
+CAST_ACCESSOR(JSDataView)
+CAST_ACCESSOR(JSDate)
+CAST_ACCESSOR(JSFunction)
+CAST_ACCESSOR(JSGlobalObject)
+CAST_ACCESSOR(JSGlobalProxy)
+CAST_ACCESSOR(JSMessageObject)
+CAST_ACCESSOR(JSObject)
+CAST_ACCESSOR(JSReceiver)
+CAST_ACCESSOR(JSStringIterator)
+CAST_ACCESSOR(JSValue)
+
+MaybeHandle<Object> JSReceiver::GetProperty(Isolate* isolate,
+ Handle<JSReceiver> receiver,
+ Handle<Name> name) {
+ LookupIterator it(isolate, receiver, name, receiver);
+ if (!it.IsFound()) return it.factory()->undefined_value();
+ return Object::GetProperty(&it);
+}
+
+MaybeHandle<Object> JSReceiver::GetElement(Isolate* isolate,
+ Handle<JSReceiver> receiver,
+ uint32_t index) {
+ LookupIterator it(isolate, receiver, index, receiver);
+ if (!it.IsFound()) return it.factory()->undefined_value();
+ return Object::GetProperty(&it);
+}
+
+Handle<Object> JSReceiver::GetDataProperty(Handle<JSReceiver> object,
+ Handle<Name> name) {
+ LookupIterator it(object, name, object,
+ LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
+ if (!it.IsFound()) return it.factory()->undefined_value();
+ return GetDataProperty(&it);
+}
+
+MaybeHandle<Object> JSReceiver::GetPrototype(Isolate* isolate,
+ Handle<JSReceiver> receiver) {
+ // We don't expect access checks to be needed on JSProxy objects.
+ DCHECK(!receiver->IsAccessCheckNeeded() || receiver->IsJSObject());
+ PrototypeIterator iter(isolate, receiver, kStartAtReceiver,
+ PrototypeIterator::END_AT_NON_HIDDEN);
+ do {
+ if (!iter.AdvanceFollowingProxies()) return MaybeHandle<Object>();
+ } while (!iter.IsAtEnd());
+ return PrototypeIterator::GetCurrent(iter);
+}
+
+MaybeHandle<Object> JSReceiver::GetProperty(Isolate* isolate,
+ Handle<JSReceiver> receiver,
+ const char* name) {
+ Handle<String> str = isolate->factory()->InternalizeUtf8String(name);
+ return GetProperty(isolate, receiver, str);
+}
+
+// static
+V8_WARN_UNUSED_RESULT MaybeHandle<FixedArray> JSReceiver::OwnPropertyKeys(
+ Handle<JSReceiver> object) {
+ return KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
+ ALL_PROPERTIES,
+ GetKeysConversion::kConvertToString);
+}
+
+bool JSObject::PrototypeHasNoElements(Isolate* isolate, JSObject* object) {
+ DisallowHeapAllocation no_gc;
+ HeapObject* prototype = HeapObject::cast(object->map()->prototype());
+ ReadOnlyRoots roots(isolate);
+ HeapObject* null = roots.null_value();
+ HeapObject* empty_fixed_array = roots.empty_fixed_array();
+ HeapObject* empty_slow_element_dictionary =
+ roots.empty_slow_element_dictionary();
+ while (prototype != null) {
+ Map* map = prototype->map();
+ if (map->IsCustomElementsReceiverMap()) return false;
+ HeapObject* elements = JSObject::cast(prototype)->elements();
+ if (elements != empty_fixed_array &&
+ elements != empty_slow_element_dictionary) {
+ return false;
+ }
+ prototype = HeapObject::cast(map->prototype());
+ }
+ return true;
+}
+
+ACCESSORS(JSReceiver, raw_properties_or_hash, Object, kPropertiesOrHashOffset)
+
+FixedArrayBase* JSObject::elements() const {
+ Object* array = READ_FIELD(this, kElementsOffset);
+ return static_cast<FixedArrayBase*>(array);
+}
+
+void JSObject::EnsureCanContainHeapObjectElements(Handle<JSObject> object) {
+ JSObject::ValidateElements(*object);
+ ElementsKind elements_kind = object->map()->elements_kind();
+ if (!IsObjectElementsKind(elements_kind)) {
+ if (IsHoleyElementsKind(elements_kind)) {
+ TransitionElementsKind(object, HOLEY_ELEMENTS);
+ } else {
+ TransitionElementsKind(object, PACKED_ELEMENTS);
+ }
+ }
+}
+
+void JSObject::EnsureCanContainElements(Handle<JSObject> object,
+ Object** objects, uint32_t count,
+ EnsureElementsMode mode) {
+ ElementsKind current_kind = object->GetElementsKind();
+ ElementsKind target_kind = current_kind;
+ {
+ DisallowHeapAllocation no_allocation;
+ DCHECK(mode != ALLOW_COPIED_DOUBLE_ELEMENTS);
+ bool is_holey = IsHoleyElementsKind(current_kind);
+ if (current_kind == HOLEY_ELEMENTS) return;
+ Object* the_hole = object->GetReadOnlyRoots().the_hole_value();
+ for (uint32_t i = 0; i < count; ++i) {
+ Object* current = *objects++;
+ if (current == the_hole) {
+ is_holey = true;
+ target_kind = GetHoleyElementsKind(target_kind);
+ } else if (!current->IsSmi()) {
+ if (mode == ALLOW_CONVERTED_DOUBLE_ELEMENTS && current->IsNumber()) {
+ if (IsSmiElementsKind(target_kind)) {
+ if (is_holey) {
+ target_kind = HOLEY_DOUBLE_ELEMENTS;
+ } else {
+ target_kind = PACKED_DOUBLE_ELEMENTS;
+ }
+ }
+ } else if (is_holey) {
+ target_kind = HOLEY_ELEMENTS;
+ break;
+ } else {
+ target_kind = PACKED_ELEMENTS;
+ }
+ }
+ }
+ }
+ if (target_kind != current_kind) {
+ TransitionElementsKind(object, target_kind);
+ }
+}
+
+void JSObject::EnsureCanContainElements(Handle<JSObject> object,
+ Handle<FixedArrayBase> elements,
+ uint32_t length,
+ EnsureElementsMode mode) {
+ ReadOnlyRoots roots = object->GetReadOnlyRoots();
+ if (elements->map() != roots.fixed_double_array_map()) {
+ DCHECK(elements->map() == roots.fixed_array_map() ||
+ elements->map() == roots.fixed_cow_array_map());
+ if (mode == ALLOW_COPIED_DOUBLE_ELEMENTS) {
+ mode = DONT_ALLOW_DOUBLE_ELEMENTS;
+ }
+ Object** objects =
+ Handle<FixedArray>::cast(elements)->GetFirstElementAddress();
+ EnsureCanContainElements(object, objects, length, mode);
+ return;
+ }
+
+ DCHECK(mode == ALLOW_COPIED_DOUBLE_ELEMENTS);
+ if (object->GetElementsKind() == HOLEY_SMI_ELEMENTS) {
+ TransitionElementsKind(object, HOLEY_DOUBLE_ELEMENTS);
+ } else if (object->GetElementsKind() == PACKED_SMI_ELEMENTS) {
+ Handle<FixedDoubleArray> double_array =
+ Handle<FixedDoubleArray>::cast(elements);
+ for (uint32_t i = 0; i < length; ++i) {
+ if (double_array->is_the_hole(i)) {
+ TransitionElementsKind(object, HOLEY_DOUBLE_ELEMENTS);
+ return;
+ }
+ }
+ TransitionElementsKind(object, PACKED_DOUBLE_ELEMENTS);
+ }
+}
+
+void JSObject::SetMapAndElements(Handle<JSObject> object, Handle<Map> new_map,
+ Handle<FixedArrayBase> value) {
+ JSObject::MigrateToMap(object, new_map);
+ DCHECK((object->map()->has_fast_smi_or_object_elements() ||
+ (*value == object->GetReadOnlyRoots().empty_fixed_array()) ||
+ object->map()->has_fast_string_wrapper_elements()) ==
+ (value->map() == object->GetReadOnlyRoots().fixed_array_map() ||
+ value->map() == object->GetReadOnlyRoots().fixed_cow_array_map()));
+ DCHECK((*value == object->GetReadOnlyRoots().empty_fixed_array()) ||
+ (object->map()->has_fast_double_elements() ==
+ value->IsFixedDoubleArray()));
+ object->set_elements(*value);
+}
+
+void JSObject::set_elements(FixedArrayBase* value, WriteBarrierMode mode) {
+ WRITE_FIELD(this, kElementsOffset, value);
+ CONDITIONAL_WRITE_BARRIER(this, kElementsOffset, value, mode);
+}
+
+void JSObject::initialize_elements() {
+ FixedArrayBase* elements = map()->GetInitialElements();
+ WRITE_FIELD(this, kElementsOffset, elements);
+}
+
+InterceptorInfo* JSObject::GetIndexedInterceptor() {
+ return map()->GetIndexedInterceptor();
+}
+
+InterceptorInfo* JSObject::GetNamedInterceptor() {
+ return map()->GetNamedInterceptor();
+}
+
+int JSObject::GetHeaderSize() const { return GetHeaderSize(map()); }
+
+int JSObject::GetHeaderSize(const Map* map) {
+ // Check for the most common kind of JavaScript object before
+ // falling into the generic switch. This speeds up the internal
+ // field operations considerably on average.
+ InstanceType instance_type = map->instance_type();
+ return instance_type == JS_OBJECT_TYPE
+ ? JSObject::kHeaderSize
+ : GetHeaderSize(instance_type, map->has_prototype_slot());
+}
+
+// static
+int JSObject::GetEmbedderFieldCount(const Map* map) {
+ int instance_size = map->instance_size();
+ if (instance_size == kVariableSizeSentinel) return 0;
+ return ((instance_size - GetHeaderSize(map)) >> kPointerSizeLog2) -
+ map->GetInObjectProperties();
+}
+
+int JSObject::GetEmbedderFieldCount() const {
+ return GetEmbedderFieldCount(map());
+}
+
+int JSObject::GetEmbedderFieldOffset(int index) {
+ DCHECK(index < GetEmbedderFieldCount() && index >= 0);
+ return GetHeaderSize() + (kPointerSize * index);
+}
+
+Object* JSObject::GetEmbedderField(int index) {
+ DCHECK(index < GetEmbedderFieldCount() && index >= 0);
+ // Internal objects do follow immediately after the header, whereas in-object
+ // properties are at the end of the object. Therefore there is no need
+ // to adjust the index here.
+ return READ_FIELD(this, GetHeaderSize() + (kPointerSize * index));
+}
+
+void JSObject::SetEmbedderField(int index, Object* value) {
+ DCHECK(index < GetEmbedderFieldCount() && index >= 0);
+ // Internal objects do follow immediately after the header, whereas in-object
+ // properties are at the end of the object. Therefore there is no need
+ // to adjust the index here.
+ int offset = GetHeaderSize() + (kPointerSize * index);
+ WRITE_FIELD(this, offset, value);
+ WRITE_BARRIER(this, offset, value);
+}
+
+void JSObject::SetEmbedderField(int index, Smi* value) {
+ DCHECK(index < GetEmbedderFieldCount() && index >= 0);
+ // Internal objects do follow immediately after the header, whereas in-object
+ // properties are at the end of the object. Therefore there is no need
+ // to adjust the index here.
+ int offset = GetHeaderSize() + (kPointerSize * index);
+ WRITE_FIELD(this, offset, value);
+}
+
+bool JSObject::IsUnboxedDoubleField(FieldIndex index) {
+ if (!FLAG_unbox_double_fields) return false;
+ return map()->IsUnboxedDoubleField(index);
+}
+
+// Access fast-case object properties at index. The use of these routines
+// is needed to correctly distinguish between properties stored in-object and
+// properties stored in the properties array.
+Object* JSObject::RawFastPropertyAt(FieldIndex index) {
+ DCHECK(!IsUnboxedDoubleField(index));
+ if (index.is_inobject()) {
+ return READ_FIELD(this, index.offset());
+ } else {
+ return property_array()->get(index.outobject_array_index());
+ }
+}
+
+double JSObject::RawFastDoublePropertyAt(FieldIndex index) {
+ DCHECK(IsUnboxedDoubleField(index));
+ return READ_DOUBLE_FIELD(this, index.offset());
+}
+
+uint64_t JSObject::RawFastDoublePropertyAsBitsAt(FieldIndex index) {
+ DCHECK(IsUnboxedDoubleField(index));
+ return READ_UINT64_FIELD(this, index.offset());
+}
+
+void JSObject::RawFastPropertyAtPut(FieldIndex index, Object* value) {
+ if (index.is_inobject()) {
+ int offset = index.offset();
+ WRITE_FIELD(this, offset, value);
+ WRITE_BARRIER(this, offset, value);
+ } else {
+ property_array()->set(index.outobject_array_index(), value);
+ }
+}
+
+void JSObject::RawFastDoublePropertyAsBitsAtPut(FieldIndex index,
+ uint64_t bits) {
+ // Double unboxing is enabled only on 64-bit platforms.
+ DCHECK_EQ(kDoubleSize, kPointerSize);
+ Address field_addr = FIELD_ADDR(this, index.offset());
+ base::Relaxed_Store(reinterpret_cast<base::AtomicWord*>(field_addr),
+ static_cast<base::AtomicWord>(bits));
+}
+
+void JSObject::FastPropertyAtPut(FieldIndex index, Object* value) {
+ if (IsUnboxedDoubleField(index)) {
+ DCHECK(value->IsMutableHeapNumber());
+ // Ensure that all bits of the double value are preserved.
+ RawFastDoublePropertyAsBitsAtPut(
+ index, MutableHeapNumber::cast(value)->value_as_bits());
+ } else {
+ RawFastPropertyAtPut(index, value);
+ }
+}
+
+void JSObject::WriteToField(int descriptor, PropertyDetails details,
+ Object* value) {
+ DCHECK_EQ(kField, details.location());
+ DCHECK_EQ(kData, details.kind());
+ DisallowHeapAllocation no_gc;
+ FieldIndex index = FieldIndex::ForDescriptor(map(), descriptor);
+ if (details.representation().IsDouble()) {
+ // Nothing more to be done.
+ if (value->IsUninitialized()) {
+ return;
+ }
+ // Manipulating the signaling NaN used for the hole and uninitialized
+ // double field sentinel in C++, e.g. with bit_cast or value()/set_value(),
+ // will change its value on ia32 (the x87 stack is used to return values
+ // and stores to the stack silently clear the signalling bit).
+ uint64_t bits;
+ if (value->IsSmi()) {
+ bits = bit_cast<uint64_t>(static_cast<double>(Smi::ToInt(value)));
+ } else {
+ DCHECK(value->IsHeapNumber());
+ bits = HeapNumber::cast(value)->value_as_bits();
+ }
+ if (IsUnboxedDoubleField(index)) {
+ RawFastDoublePropertyAsBitsAtPut(index, bits);
+ } else {
+ auto box = MutableHeapNumber::cast(RawFastPropertyAt(index));
+ box->set_value_as_bits(bits);
+ }
+ } else {
+ RawFastPropertyAtPut(index, value);
+ }
+}
+
+int JSObject::GetInObjectPropertyOffset(int index) {
+ return map()->GetInObjectPropertyOffset(index);
+}
+
+Object* JSObject::InObjectPropertyAt(int index) {
+ int offset = GetInObjectPropertyOffset(index);
+ return READ_FIELD(this, offset);
+}
+
+Object* JSObject::InObjectPropertyAtPut(int index, Object* value,
+ WriteBarrierMode mode) {
+ // Adjust for the number of properties stored in the object.
+ int offset = GetInObjectPropertyOffset(index);
+ WRITE_FIELD(this, offset, value);
+ CONDITIONAL_WRITE_BARRIER(this, offset, value, mode);
+ return value;
+}
+
+void JSObject::InitializeBody(Map* map, int start_offset,
+ Object* pre_allocated_value,
+ Object* filler_value) {
+ DCHECK(!filler_value->IsHeapObject() || !Heap::InNewSpace(filler_value));
+ DCHECK(!pre_allocated_value->IsHeapObject() ||
+ !Heap::InNewSpace(pre_allocated_value));
+ int size = map->instance_size();
+ int offset = start_offset;
+ if (filler_value != pre_allocated_value) {
+ int end_of_pre_allocated_offset =
+ size - (map->UnusedPropertyFields() * kPointerSize);
+ DCHECK_LE(kHeaderSize, end_of_pre_allocated_offset);
+ while (offset < end_of_pre_allocated_offset) {
+ WRITE_FIELD(this, offset, pre_allocated_value);
+ offset += kPointerSize;
+ }
+ }
+ while (offset < size) {
+ WRITE_FIELD(this, offset, filler_value);
+ offset += kPointerSize;
+ }
+}
+
+Object* JSBoundFunction::raw_bound_target_function() const {
+ return READ_FIELD(this, kBoundTargetFunctionOffset);
+}
+
+ACCESSORS(JSBoundFunction, bound_target_function, JSReceiver,
+ kBoundTargetFunctionOffset)
+ACCESSORS(JSBoundFunction, bound_this, Object, kBoundThisOffset)
+ACCESSORS(JSBoundFunction, bound_arguments, FixedArray, kBoundArgumentsOffset)
+
+ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset)
+ACCESSORS(JSFunction, feedback_cell, FeedbackCell, kFeedbackCellOffset)
+
+ACCESSORS(JSGlobalObject, native_context, Context, kNativeContextOffset)
+ACCESSORS(JSGlobalObject, global_proxy, JSObject, kGlobalProxyOffset)
+
+ACCESSORS(JSGlobalProxy, native_context, Object, kNativeContextOffset)
+
+FeedbackVector* JSFunction::feedback_vector() const {
+ DCHECK(has_feedback_vector());
+ return FeedbackVector::cast(feedback_cell()->value());
+}
+
+// Code objects that are marked for deoptimization are not considered to be
+// optimized. This is because the JSFunction might have been already
+// deoptimized but its code() still needs to be unlinked, which will happen on
+// its next activation.
+// TODO(jupvfranco): rename this function. Maybe RunOptimizedCode,
+// or IsValidOptimizedCode.
+bool JSFunction::IsOptimized() {
+ return code()->kind() == Code::OPTIMIZED_FUNCTION &&
+ !code()->marked_for_deoptimization();
+}
+
+bool JSFunction::HasOptimizedCode() {
+ return IsOptimized() ||
+ (has_feedback_vector() && feedback_vector()->has_optimized_code() &&
+ !feedback_vector()->optimized_code()->marked_for_deoptimization());
+}
+
+bool JSFunction::HasOptimizationMarker() {
+ return has_feedback_vector() && feedback_vector()->has_optimization_marker();
+}
+
+void JSFunction::ClearOptimizationMarker() {
+ DCHECK(has_feedback_vector());
+ feedback_vector()->ClearOptimizationMarker();
+}
+
+// Optimized code marked for deoptimization will tier back down to running
+// interpreted on its next activation, and already doesn't count as IsOptimized.
+bool JSFunction::IsInterpreted() {
+ return code()->is_interpreter_trampoline_builtin() ||
+ (code()->kind() == Code::OPTIMIZED_FUNCTION &&
+ code()->marked_for_deoptimization());
+}
+
+bool JSFunction::ChecksOptimizationMarker() {
+ return code()->checks_optimization_marker();
+}
+
+bool JSFunction::IsMarkedForOptimization() {
+ return has_feedback_vector() && feedback_vector()->optimization_marker() ==
+ OptimizationMarker::kCompileOptimized;
+}
+
+bool JSFunction::IsMarkedForConcurrentOptimization() {
+ return has_feedback_vector() &&
+ feedback_vector()->optimization_marker() ==
+ OptimizationMarker::kCompileOptimizedConcurrent;
+}
+
+bool JSFunction::IsInOptimizationQueue() {
+ return has_feedback_vector() && feedback_vector()->optimization_marker() ==
+ OptimizationMarker::kInOptimizationQueue;
+}
+
+void JSFunction::CompleteInobjectSlackTrackingIfActive() {
+ if (!has_prototype_slot()) return;
+ if (has_initial_map() && initial_map()->IsInobjectSlackTrackingInProgress()) {
+ initial_map()->CompleteInobjectSlackTracking(GetIsolate());
+ }
+}
+
+AbstractCode* JSFunction::abstract_code() {
+ if (IsInterpreted()) {
+ return AbstractCode::cast(shared()->GetBytecodeArray());
+ } else {
+ return AbstractCode::cast(code());
+ }
+}
+
+Code* JSFunction::code() { return Code::cast(READ_FIELD(this, kCodeOffset)); }
+
+void JSFunction::set_code(Code* value) {
+ DCHECK(!Heap::InNewSpace(value));
+ WRITE_FIELD(this, kCodeOffset, value);
+ MarkingBarrier(this, HeapObject::RawField(this, kCodeOffset), value);
+}
+
+void JSFunction::set_code_no_write_barrier(Code* value) {
+ DCHECK(!Heap::InNewSpace(value));
+ WRITE_FIELD(this, kCodeOffset, value);
+}
+
+void JSFunction::ClearOptimizedCodeSlot(const char* reason) {
+ if (has_feedback_vector() && feedback_vector()->has_optimized_code()) {
+ if (FLAG_trace_opt) {
+ PrintF("[evicting entry from optimizing code feedback slot (%s) for ",
+ reason);
+ ShortPrint();
+ PrintF("]\n");
+ }
+ feedback_vector()->ClearOptimizedCode();
+ }
+}
+
+void JSFunction::SetOptimizationMarker(OptimizationMarker marker) {
+ DCHECK(has_feedback_vector());
+ DCHECK(ChecksOptimizationMarker());
+ DCHECK(!HasOptimizedCode());
+
+ feedback_vector()->SetOptimizationMarker(marker);
+}
+
+bool JSFunction::has_feedback_vector() const {
+ return !feedback_cell()->value()->IsUndefined();
+}
+
+Context* JSFunction::context() {
+ return Context::cast(READ_FIELD(this, kContextOffset));
+}
+
+bool JSFunction::has_context() const {
+ return READ_FIELD(this, kContextOffset)->IsContext();
+}
+
+JSGlobalProxy* JSFunction::global_proxy() { return context()->global_proxy(); }
+
+Context* JSFunction::native_context() { return context()->native_context(); }
+
+void JSFunction::set_context(Object* value) {
+ DCHECK(value->IsUndefined() || value->IsContext());
+ WRITE_FIELD(this, kContextOffset, value);
+ WRITE_BARRIER(this, kContextOffset, value);
+}
+
+ACCESSORS_CHECKED(JSFunction, prototype_or_initial_map, Object,
+ kPrototypeOrInitialMapOffset, map()->has_prototype_slot())
+
+bool JSFunction::has_prototype_slot() const {
+ return map()->has_prototype_slot();
+}
+
+Map* JSFunction::initial_map() { return Map::cast(prototype_or_initial_map()); }
+
+bool JSFunction::has_initial_map() {
+ DCHECK(has_prototype_slot());
+ return prototype_or_initial_map()->IsMap();
+}
+
+bool JSFunction::has_instance_prototype() {
+ DCHECK(has_prototype_slot());
+ return has_initial_map() || !prototype_or_initial_map()->IsTheHole();
+}
+
+bool JSFunction::has_prototype() {
+ DCHECK(has_prototype_slot());
+ return map()->has_non_instance_prototype() || has_instance_prototype();
+}
+
+bool JSFunction::has_prototype_property() {
+ return (has_prototype_slot() && IsConstructor()) ||
+ IsGeneratorFunction(shared()->kind());
+}
+
+bool JSFunction::PrototypeRequiresRuntimeLookup() {
+ return !has_prototype_property() || map()->has_non_instance_prototype();
+}
+
+Object* JSFunction::instance_prototype() {
+ DCHECK(has_instance_prototype());
+ if (has_initial_map()) return initial_map()->prototype();
+ // When there is no initial map and the prototype is a JSReceiver, the
+ // initial map field is used for the prototype field.
+ return prototype_or_initial_map();
+}
+
+Object* JSFunction::prototype() {
+ DCHECK(has_prototype());
+ // If the function's prototype property has been set to a non-JSReceiver
+ // value, that value is stored in the constructor field of the map.
+ if (map()->has_non_instance_prototype()) {
+ Object* prototype = map()->GetConstructor();
+ // The map must have a prototype in that field, not a back pointer.
+ DCHECK(!prototype->IsMap());
+ DCHECK(!prototype->IsFunctionTemplateInfo());
+ return prototype;
+ }
+ return instance_prototype();
+}
+
+bool JSFunction::is_compiled() {
+ return code()->builtin_index() != Builtins::kCompileLazy;
+}
+
+ACCESSORS(JSValue, value, Object, kValueOffset)
+
+ACCESSORS(JSDate, value, Object, kValueOffset)
+ACCESSORS(JSDate, cache_stamp, Object, kCacheStampOffset)
+ACCESSORS(JSDate, year, Object, kYearOffset)
+ACCESSORS(JSDate, month, Object, kMonthOffset)
+ACCESSORS(JSDate, day, Object, kDayOffset)
+ACCESSORS(JSDate, weekday, Object, kWeekdayOffset)
+ACCESSORS(JSDate, hour, Object, kHourOffset)
+ACCESSORS(JSDate, min, Object, kMinOffset)
+ACCESSORS(JSDate, sec, Object, kSecOffset)
+
+SMI_ACCESSORS(JSMessageObject, type, kTypeOffset)
+ACCESSORS(JSMessageObject, argument, Object, kArgumentsOffset)
+ACCESSORS(JSMessageObject, script, Script, kScriptOffset)
+ACCESSORS(JSMessageObject, stack_frames, Object, kStackFramesOffset)
+SMI_ACCESSORS(JSMessageObject, start_position, kStartPositionOffset)
+SMI_ACCESSORS(JSMessageObject, end_position, kEndPositionOffset)
+SMI_ACCESSORS(JSMessageObject, error_level, kErrorLevelOffset)
+
+ElementsKind JSObject::GetElementsKind() const {
+ ElementsKind kind = map()->elements_kind();
+#if VERIFY_HEAP && DEBUG
+ FixedArrayBase* fixed_array =
+ reinterpret_cast<FixedArrayBase*>(READ_FIELD(this, kElementsOffset));
+
+ // If a GC was caused while constructing this object, the elements
+ // pointer may point to a one pointer filler map.
+ if (ElementsAreSafeToExamine()) {
+ Map* map = fixed_array->map();
+ if (IsSmiOrObjectElementsKind(kind)) {
+ DCHECK(map == GetReadOnlyRoots().fixed_array_map() ||
+ map == GetReadOnlyRoots().fixed_cow_array_map());
+ } else if (IsDoubleElementsKind(kind)) {
+ DCHECK(fixed_array->IsFixedDoubleArray() ||
+ fixed_array == GetReadOnlyRoots().empty_fixed_array());
+ } else if (kind == DICTIONARY_ELEMENTS) {
+ DCHECK(fixed_array->IsFixedArray());
+ DCHECK(fixed_array->IsDictionary());
+ } else {
+ DCHECK(kind > DICTIONARY_ELEMENTS);
+ }
+ DCHECK(!IsSloppyArgumentsElementsKind(kind) ||
+ (elements()->IsFixedArray() && elements()->length() >= 2));
+ }
+#endif
+ return kind;
+}
+
+bool JSObject::HasObjectElements() {
+ return IsObjectElementsKind(GetElementsKind());
+}
+
+bool JSObject::HasSmiElements() { return IsSmiElementsKind(GetElementsKind()); }
+
+bool JSObject::HasSmiOrObjectElements() {
+ return IsSmiOrObjectElementsKind(GetElementsKind());
+}
+
+bool JSObject::HasDoubleElements() {
+ return IsDoubleElementsKind(GetElementsKind());
+}
+
+bool JSObject::HasHoleyElements() {
+ return IsHoleyElementsKind(GetElementsKind());
+}
+
+bool JSObject::HasFastElements() {
+ return IsFastElementsKind(GetElementsKind());
+}
+
+bool JSObject::HasFastPackedElements() {
+ return IsFastPackedElementsKind(GetElementsKind());
+}
+
+bool JSObject::HasDictionaryElements() {
+ return GetElementsKind() == DICTIONARY_ELEMENTS;
+}
+
+bool JSObject::HasFastArgumentsElements() {
+ return GetElementsKind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS;
+}
+
+bool JSObject::HasSlowArgumentsElements() {
+ return GetElementsKind() == SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
+}
+
+bool JSObject::HasSloppyArgumentsElements() {
+ return IsSloppyArgumentsElementsKind(GetElementsKind());
+}
+
+bool JSObject::HasStringWrapperElements() {
+ return IsStringWrapperElementsKind(GetElementsKind());
+}
+
+bool JSObject::HasFastStringWrapperElements() {
+ return GetElementsKind() == FAST_STRING_WRAPPER_ELEMENTS;
+}
+
+bool JSObject::HasSlowStringWrapperElements() {
+ return GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS;
+}
+
+bool JSObject::HasFixedTypedArrayElements() {
+ DCHECK_NOT_NULL(elements());
+ return map()->has_fixed_typed_array_elements();
+}
+
+#define FIXED_TYPED_ELEMENTS_CHECK(Type, type, TYPE, ctype) \
+ bool JSObject::HasFixed##Type##Elements() { \
+ HeapObject* array = elements(); \
+ DCHECK_NOT_NULL(array); \
+ if (!array->IsHeapObject()) return false; \
+ return array->map()->instance_type() == FIXED_##TYPE##_ARRAY_TYPE; \
+ }
+
+TYPED_ARRAYS(FIXED_TYPED_ELEMENTS_CHECK)
+
+#undef FIXED_TYPED_ELEMENTS_CHECK
+
+bool JSObject::HasNamedInterceptor() { return map()->has_named_interceptor(); }
+
+bool JSObject::HasIndexedInterceptor() {
+ return map()->has_indexed_interceptor();
+}
+
+void JSGlobalObject::set_global_dictionary(GlobalDictionary* dictionary) {
+ DCHECK(IsJSGlobalObject());
+ set_raw_properties_or_hash(dictionary);
+}
+
+GlobalDictionary* JSGlobalObject::global_dictionary() {
+ DCHECK(!HasFastProperties());
+ DCHECK(IsJSGlobalObject());
+ return GlobalDictionary::cast(raw_properties_or_hash());
+}
+
+NumberDictionary* JSObject::element_dictionary() {
+ DCHECK(HasDictionaryElements() || HasSlowStringWrapperElements());
+ return NumberDictionary::cast(elements());
+}
+
+void JSReceiver::initialize_properties() {
+ Heap* heap = GetHeap();
+ ReadOnlyRoots roots(heap);
+ DCHECK(!Heap::InNewSpace(roots.empty_fixed_array()));
+ DCHECK(!Heap::InNewSpace(heap->empty_property_dictionary()));
+ if (map()->is_dictionary_map()) {
+ WRITE_FIELD(this, kPropertiesOrHashOffset,
+ heap->empty_property_dictionary());
+ } else {
+ WRITE_FIELD(this, kPropertiesOrHashOffset, roots.empty_fixed_array());
+ }
+}
+
+bool JSReceiver::HasFastProperties() const {
+ DCHECK(
+ raw_properties_or_hash()->IsSmi() ||
+ (raw_properties_or_hash()->IsDictionary() == map()->is_dictionary_map()));
+ return !map()->is_dictionary_map();
+}
+
+NameDictionary* JSReceiver::property_dictionary() const {
+ DCHECK(!IsJSGlobalObject());
+ DCHECK(!HasFastProperties());
+
+ Object* prop = raw_properties_or_hash();
+ if (prop->IsSmi()) {
+ return GetHeap()->empty_property_dictionary();
+ }
+
+ return NameDictionary::cast(prop);
+}
+
+// TODO(gsathya): Pass isolate directly to this function and access
+// the heap from this.
+PropertyArray* JSReceiver::property_array() const {
+ DCHECK(HasFastProperties());
+
+ Object* prop = raw_properties_or_hash();
+ if (prop->IsSmi() || prop == GetReadOnlyRoots().empty_fixed_array()) {
+ return GetReadOnlyRoots().empty_property_array();
+ }
+
+ return PropertyArray::cast(prop);
+}
+
+Maybe<bool> JSReceiver::HasProperty(Handle<JSReceiver> object,
+ Handle<Name> name) {
+ LookupIterator it = LookupIterator::PropertyOrElement(object->GetIsolate(),
+ object, name, object);
+ return HasProperty(&it);
+}
+
+Maybe<bool> JSReceiver::HasOwnProperty(Handle<JSReceiver> object,
+ uint32_t index) {
+ if (object->IsJSModuleNamespace()) return Just(false);
+
+ if (object->IsJSObject()) { // Shortcut.
+ LookupIterator it(object->GetIsolate(), object, index, object,
+ LookupIterator::OWN);
+ return HasProperty(&it);
+ }
+
+ Maybe<PropertyAttributes> attributes =
+ JSReceiver::GetOwnPropertyAttributes(object, index);
+ MAYBE_RETURN(attributes, Nothing<bool>());
+ return Just(attributes.FromJust() != ABSENT);
+}
+
+Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
+ Handle<JSReceiver> object, Handle<Name> name) {
+ LookupIterator it = LookupIterator::PropertyOrElement(object->GetIsolate(),
+ object, name, object);
+ return GetPropertyAttributes(&it);
+}
+
+Maybe<PropertyAttributes> JSReceiver::GetOwnPropertyAttributes(
+ Handle<JSReceiver> object, Handle<Name> name) {
+ LookupIterator it = LookupIterator::PropertyOrElement(
+ object->GetIsolate(), object, name, object, LookupIterator::OWN);
+ return GetPropertyAttributes(&it);
+}
+
+Maybe<PropertyAttributes> JSReceiver::GetOwnPropertyAttributes(
+ Handle<JSReceiver> object, uint32_t index) {
+ LookupIterator it(object->GetIsolate(), object, index, object,
+ LookupIterator::OWN);
+ return GetPropertyAttributes(&it);
+}
+
+Maybe<bool> JSReceiver::HasElement(Handle<JSReceiver> object, uint32_t index) {
+ LookupIterator it(object->GetIsolate(), object, index, object);
+ return HasProperty(&it);
+}
+
+Maybe<PropertyAttributes> JSReceiver::GetElementAttributes(
+ Handle<JSReceiver> object, uint32_t index) {
+ Isolate* isolate = object->GetIsolate();
+ LookupIterator it(isolate, object, index, object);
+ return GetPropertyAttributes(&it);
+}
+
+Maybe<PropertyAttributes> JSReceiver::GetOwnElementAttributes(
+ Handle<JSReceiver> object, uint32_t index) {
+ Isolate* isolate = object->GetIsolate();
+ LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
+ return GetPropertyAttributes(&it);
+}
+
+bool JSGlobalObject::IsDetached() {
+ return JSGlobalProxy::cast(global_proxy())->IsDetachedFrom(this);
+}
+
+bool JSGlobalProxy::IsDetachedFrom(JSGlobalObject* global) const {
+ const PrototypeIterator iter(this->GetIsolate(),
+ const_cast<JSGlobalProxy*>(this));
+ return iter.GetCurrent() != global;
+}
+
+inline int JSGlobalProxy::SizeWithEmbedderFields(int embedder_field_count) {
+ DCHECK_GE(embedder_field_count, 0);
+ return kSize + embedder_field_count * kPointerSize;
+}
+
+ACCESSORS(JSIteratorResult, value, Object, kValueOffset)
+ACCESSORS(JSIteratorResult, done, Object, kDoneOffset)
+
+ACCESSORS(JSAsyncFromSyncIterator, sync_iterator, JSReceiver,
+ kSyncIteratorOffset)
+ACCESSORS(JSAsyncFromSyncIterator, next, Object, kNextOffset)
+
+ACCESSORS(JSStringIterator, string, String, kStringOffset)
+SMI_ACCESSORS(JSStringIterator, index, kNextIndexOffset)
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_JS_OBJECTS_INL_H_
diff --git a/deps/v8/src/objects/js-objects.h b/deps/v8/src/objects/js-objects.h
new file mode 100644
index 0000000000..586fe757db
--- /dev/null
+++ b/deps/v8/src/objects/js-objects.h
@@ -0,0 +1,1408 @@
+// Copyright 2018 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_JS_OBJECTS_H_
+#define V8_OBJECTS_JS_OBJECTS_H_
+
+#include "src/objects.h"
+#include "src/objects/property-array.h"
+
+// Has to be the last include (doesn't have include guards):
+#include "src/objects/object-macros.h"
+
+namespace v8 {
+namespace internal {
+
+class JSGlobalObject;
+class JSGlobalProxy;
+
+// JSReceiver includes types on which properties can be defined, i.e.,
+// JSObject and JSProxy.
+class JSReceiver : public HeapObject, public NeverReadOnlySpaceObject {
+ public:
+ // Returns true if there is no slow (ie, dictionary) backing store.
+ inline bool HasFastProperties() const;
+
+ // Returns the properties array backing store if it
+ // exists. Otherwise, returns an empty_property_array when there's a
+ // Smi (hash code) or an empty_fixed_array for a fast properties
+ // map.
+ inline PropertyArray* property_array() const;
+
+ // Gets slow properties for non-global objects.
+ inline NameDictionary* property_dictionary() const;
+
+ // Sets the properties backing store and makes sure any existing hash is moved
+ // to the new properties store. To clear out the properties store, pass in the
+ // empty_fixed_array(), the hash will be maintained in this case as well.
+ void SetProperties(HeapObject* properties);
+
+ // There are five possible values for the properties offset.
+ // 1) EmptyFixedArray/EmptyPropertyDictionary - This is the standard
+ // placeholder.
+ //
+ // 2) Smi - This is the hash code of the object.
+ //
+ // 3) PropertyArray - This is similar to a FixedArray but stores
+ // the hash code of the object in its length field. This is a fast
+ // backing store.
+ //
+ // 4) NameDictionary - This is the dictionary-mode backing store.
+ //
+ // 4) GlobalDictionary - This is the backing store for the
+ // GlobalObject.
+ //
+ // This is used only in the deoptimizer and heap. Please use the
+ // above typed getters and setters to access the properties.
+ DECL_ACCESSORS(raw_properties_or_hash, Object)
+
+ inline void initialize_properties();
+
+ // Deletes an existing named property in a normalized object.
+ static void DeleteNormalizedProperty(Handle<JSReceiver> object, int entry);
+
+ DECL_CAST(JSReceiver)
+
+ // ES6 section 7.1.1 ToPrimitive
+ V8_WARN_UNUSED_RESULT static MaybeHandle<Object> ToPrimitive(
+ Handle<JSReceiver> receiver,
+ ToPrimitiveHint hint = ToPrimitiveHint::kDefault);
+
+ // ES6 section 7.1.1.1 OrdinaryToPrimitive
+ V8_WARN_UNUSED_RESULT static MaybeHandle<Object> OrdinaryToPrimitive(
+ Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint);
+
+ static MaybeHandle<Context> GetFunctionRealm(Handle<JSReceiver> receiver);
+
+ // Get the first non-hidden prototype.
+ static inline MaybeHandle<Object> GetPrototype(Isolate* isolate,
+ Handle<JSReceiver> receiver);
+
+ V8_WARN_UNUSED_RESULT static Maybe<bool> HasInPrototypeChain(
+ Isolate* isolate, Handle<JSReceiver> object, Handle<Object> proto);
+
+ // Reads all enumerable own properties of source and adds them to
+ // target, using either Set or CreateDataProperty depending on the
+ // use_set argument. This only copies values not present in the
+ // maybe_excluded_properties list.
+ V8_WARN_UNUSED_RESULT static Maybe<bool> SetOrCopyDataProperties(
+ Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source,
+ const ScopedVector<Handle<Object>>* excluded_properties = nullptr,
+ bool use_set = true);
+
+ // Implementation of [[HasProperty]], ECMA-262 5th edition, section 8.12.6.
+ V8_WARN_UNUSED_RESULT static Maybe<bool> HasProperty(LookupIterator* it);
+ V8_WARN_UNUSED_RESULT static inline Maybe<bool> HasProperty(
+ Handle<JSReceiver> object, Handle<Name> name);
+ V8_WARN_UNUSED_RESULT static inline Maybe<bool> HasElement(
+ Handle<JSReceiver> object, uint32_t index);
+
+ V8_WARN_UNUSED_RESULT static Maybe<bool> HasOwnProperty(
+ Handle<JSReceiver> object, Handle<Name> name);
+ V8_WARN_UNUSED_RESULT static inline Maybe<bool> HasOwnProperty(
+ Handle<JSReceiver> object, uint32_t index);
+
+ V8_WARN_UNUSED_RESULT static inline MaybeHandle<Object> GetProperty(
+ Isolate* isolate, Handle<JSReceiver> receiver, const char* key);
+ V8_WARN_UNUSED_RESULT static inline MaybeHandle<Object> GetProperty(
+ Isolate* isolate, Handle<JSReceiver> receiver, Handle<Name> name);
+ V8_WARN_UNUSED_RESULT static inline MaybeHandle<Object> GetElement(
+ Isolate* isolate, Handle<JSReceiver> receiver, uint32_t index);
+
+ // Implementation of ES6 [[Delete]]
+ V8_WARN_UNUSED_RESULT static Maybe<bool> DeletePropertyOrElement(
+ Handle<JSReceiver> object, Handle<Name> name,
+ LanguageMode language_mode = LanguageMode::kSloppy);
+ V8_WARN_UNUSED_RESULT static Maybe<bool> DeleteProperty(
+ Handle<JSReceiver> object, Handle<Name> name,
+ LanguageMode language_mode = LanguageMode::kSloppy);
+ V8_WARN_UNUSED_RESULT static Maybe<bool> DeleteProperty(
+ LookupIterator* it, LanguageMode language_mode);
+ V8_WARN_UNUSED_RESULT static Maybe<bool> DeleteElement(
+ Handle<JSReceiver> object, uint32_t index,
+ LanguageMode language_mode = LanguageMode::kSloppy);
+
+ V8_WARN_UNUSED_RESULT static Object* DefineProperty(
+ Isolate* isolate, Handle<Object> object, Handle<Object> name,
+ Handle<Object> attributes);
+ V8_WARN_UNUSED_RESULT static MaybeHandle<Object> DefineProperties(
+ Isolate* isolate, Handle<Object> object, Handle<Object> properties);
+
+ // "virtual" dispatcher to the correct [[DefineOwnProperty]] implementation.
+ V8_WARN_UNUSED_RESULT static Maybe<bool> DefineOwnProperty(
+ Isolate* isolate, Handle<JSReceiver> object, Handle<Object> key,
+ PropertyDescriptor* desc, ShouldThrow should_throw);
+
+ // ES6 7.3.4 (when passed kDontThrow)
+ V8_WARN_UNUSED_RESULT static Maybe<bool> CreateDataProperty(
+ Isolate* isolate, Handle<JSReceiver> object, Handle<Name> key,
+ Handle<Object> value, ShouldThrow should_throw);
+ V8_WARN_UNUSED_RESULT static Maybe<bool> CreateDataProperty(
+ LookupIterator* it, Handle<Object> value, ShouldThrow should_throw);
+
+ // ES6 9.1.6.1
+ V8_WARN_UNUSED_RESULT static Maybe<bool> OrdinaryDefineOwnProperty(
+ Isolate* isolate, Handle<JSObject> object, Handle<Object> key,
+ PropertyDescriptor* desc, ShouldThrow should_throw);
+ V8_WARN_UNUSED_RESULT static Maybe<bool> OrdinaryDefineOwnProperty(
+ LookupIterator* it, PropertyDescriptor* desc, ShouldThrow should_throw);
+ // ES6 9.1.6.2
+ V8_WARN_UNUSED_RESULT static Maybe<bool> IsCompatiblePropertyDescriptor(
+ Isolate* isolate, bool extensible, PropertyDescriptor* desc,
+ PropertyDescriptor* current, Handle<Name> property_name,
+ ShouldThrow should_throw);
+ // ES6 9.1.6.3
+ // |it| can be NULL in cases where the ES spec passes |undefined| as the
+ // receiver. Exactly one of |it| and |property_name| must be provided.
+ V8_WARN_UNUSED_RESULT static Maybe<bool> ValidateAndApplyPropertyDescriptor(
+ Isolate* isolate, LookupIterator* it, bool extensible,
+ PropertyDescriptor* desc, PropertyDescriptor* current,
+ ShouldThrow should_throw, Handle<Name> property_name);
+
+ V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static Maybe<bool>
+ GetOwnPropertyDescriptor(Isolate* isolate, Handle<JSReceiver> object,
+ Handle<Object> key, PropertyDescriptor* desc);
+ V8_WARN_UNUSED_RESULT static Maybe<bool> GetOwnPropertyDescriptor(
+ LookupIterator* it, PropertyDescriptor* desc);
+
+ typedef PropertyAttributes IntegrityLevel;
+
+ // ES6 7.3.14 (when passed kDontThrow)
+ // 'level' must be SEALED or FROZEN.
+ V8_WARN_UNUSED_RESULT static Maybe<bool> SetIntegrityLevel(
+ Handle<JSReceiver> object, IntegrityLevel lvl, ShouldThrow should_throw);
+
+ // ES6 7.3.15
+ // 'level' must be SEALED or FROZEN.
+ V8_WARN_UNUSED_RESULT static Maybe<bool> TestIntegrityLevel(
+ Handle<JSReceiver> object, IntegrityLevel lvl);
+
+ // ES6 [[PreventExtensions]] (when passed kDontThrow)
+ V8_WARN_UNUSED_RESULT static Maybe<bool> PreventExtensions(
+ Handle<JSReceiver> object, ShouldThrow should_throw);
+
+ V8_WARN_UNUSED_RESULT static Maybe<bool> IsExtensible(
+ Handle<JSReceiver> object);
+
+ // Returns the class name ([[Class]] property in the specification).
+ V8_EXPORT_PRIVATE String* class_name();
+
+ // Returns the constructor (the function that was used to instantiate the
+ // object).
+ static MaybeHandle<JSFunction> GetConstructor(Handle<JSReceiver> receiver);
+
+ // Returns the constructor name (the name (possibly, inferred name) of the
+ // function that was used to instantiate the object).
+ static Handle<String> GetConstructorName(Handle<JSReceiver> receiver);
+
+ Handle<Context> GetCreationContext();
+
+ V8_WARN_UNUSED_RESULT static inline Maybe<PropertyAttributes>
+ GetPropertyAttributes(Handle<JSReceiver> object, Handle<Name> name);
+ V8_WARN_UNUSED_RESULT static inline Maybe<PropertyAttributes>
+ GetOwnPropertyAttributes(Handle<JSReceiver> object, Handle<Name> name);
+ V8_WARN_UNUSED_RESULT static inline Maybe<PropertyAttributes>
+ GetOwnPropertyAttributes(Handle<JSReceiver> object, uint32_t index);
+
+ V8_WARN_UNUSED_RESULT static inline Maybe<PropertyAttributes>
+ GetElementAttributes(Handle<JSReceiver> object, uint32_t index);
+ V8_WARN_UNUSED_RESULT static inline Maybe<PropertyAttributes>
+ GetOwnElementAttributes(Handle<JSReceiver> object, uint32_t index);
+
+ V8_WARN_UNUSED_RESULT static Maybe<PropertyAttributes> GetPropertyAttributes(
+ LookupIterator* it);
+
+ // Set the object's prototype (only JSReceiver and null are allowed values).
+ V8_WARN_UNUSED_RESULT static Maybe<bool> SetPrototype(
+ Handle<JSReceiver> object, Handle<Object> value, bool from_javascript,
+ ShouldThrow should_throw);
+
+ inline static Handle<Object> GetDataProperty(Handle<JSReceiver> object,
+ Handle<Name> name);
+ static Handle<Object> GetDataProperty(LookupIterator* it);
+
+ // Retrieves a permanent object identity hash code. The undefined value might
+ // be returned in case no hash was created yet.
+ Object* GetIdentityHash(Isolate* isolate);
+
+ // Retrieves a permanent object identity hash code. May create and store a
+ // hash code if needed and none exists.
+ static Smi* CreateIdentityHash(Isolate* isolate, JSReceiver* key);
+ Smi* GetOrCreateIdentityHash(Isolate* isolate);
+
+ // Stores the hash code. The hash passed in must be masked with
+ // JSReceiver::kHashMask.
+ void SetIdentityHash(int masked_hash);
+
+ // ES6 [[OwnPropertyKeys]] (modulo return type)
+ V8_WARN_UNUSED_RESULT static inline MaybeHandle<FixedArray> OwnPropertyKeys(
+ Handle<JSReceiver> object);
+
+ V8_WARN_UNUSED_RESULT static MaybeHandle<FixedArray> GetOwnValues(
+ Handle<JSReceiver> object, PropertyFilter filter,
+ bool try_fast_path = true);
+
+ V8_WARN_UNUSED_RESULT static MaybeHandle<FixedArray> GetOwnEntries(
+ Handle<JSReceiver> object, PropertyFilter filter,
+ bool try_fast_path = true);
+
+ V8_WARN_UNUSED_RESULT static Handle<FixedArray> GetOwnElementIndices(
+ Isolate* isolate, Handle<JSReceiver> receiver, Handle<JSObject> object);
+
+ static const int kHashMask = PropertyArray::HashField::kMask;
+
+ // Layout description.
+ static const int kPropertiesOrHashOffset = HeapObject::kHeaderSize;
+ static const int kHeaderSize = HeapObject::kHeaderSize + kPointerSize;
+
+ bool HasProxyInPrototype(Isolate* isolate);
+
+ bool HasComplexElements();
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSReceiver);
+};
+
+// The JSObject describes real heap allocated JavaScript objects with
+// properties.
+// Note that the map of JSObject changes during execution to enable inline
+// caching.
+class JSObject : public JSReceiver {
+ public:
+ static bool IsUnmodifiedApiObject(Object** o);
+
+ static V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> New(
+ Handle<JSFunction> constructor, Handle<JSReceiver> new_target,
+ Handle<AllocationSite> site);
+
+ static MaybeHandle<Context> GetFunctionRealm(Handle<JSObject> object);
+
+ // 9.1.12 ObjectCreate ( proto [ , internalSlotsList ] )
+ // Notice: This is NOT 19.1.2.2 Object.create ( O, Properties )
+ static V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> ObjectCreate(
+ Isolate* isolate, Handle<Object> prototype);
+
+ // [elements]: The elements (properties with names that are integers).
+ //
+ // Elements can be in two general modes: fast and slow. Each mode
+ // corresponds to a set of object representations of elements that
+ // have something in common.
+ //
+ // In the fast mode elements is a FixedArray and so each element can
+ // be quickly accessed. This fact is used in the generated code. The
+ // elements array can have one of three maps in this mode:
+ // fixed_array_map, sloppy_arguments_elements_map or
+ // fixed_cow_array_map (for copy-on-write arrays). In the latter case
+ // the elements array may be shared by a few objects and so before
+ // writing to any element the array must be copied. Use
+ // EnsureWritableFastElements in this case.
+ //
+ // In the slow mode the elements is either a NumberDictionary, a
+ // FixedArray parameter map for a (sloppy) arguments object.
+ DECL_ACCESSORS(elements, FixedArrayBase)
+ inline void initialize_elements();
+ static inline void SetMapAndElements(Handle<JSObject> object, Handle<Map> map,
+ Handle<FixedArrayBase> elements);
+ inline ElementsKind GetElementsKind() const;
+ ElementsAccessor* GetElementsAccessor();
+ // Returns true if an object has elements of PACKED_SMI_ELEMENTS or
+ // HOLEY_SMI_ELEMENTS ElementsKind.
+ inline bool HasSmiElements();
+ // Returns true if an object has elements of PACKED_ELEMENTS or
+ // HOLEY_ELEMENTS ElementsKind.
+ inline bool HasObjectElements();
+ // Returns true if an object has elements of PACKED_SMI_ELEMENTS,
+ // HOLEY_SMI_ELEMENTS, PACKED_ELEMENTS, or HOLEY_ELEMENTS.
+ inline bool HasSmiOrObjectElements();
+ // Returns true if an object has any of the "fast" elements kinds.
+ inline bool HasFastElements();
+ // Returns true if an object has any of the PACKED elements kinds.
+ inline bool HasFastPackedElements();
+ // Returns true if an object has elements of PACKED_DOUBLE_ELEMENTS or
+ // HOLEY_DOUBLE_ELEMENTS ElementsKind.
+ inline bool HasDoubleElements();
+ // Returns true if an object has elements of HOLEY_SMI_ELEMENTS,
+ // HOLEY_DOUBLE_ELEMENTS, or HOLEY_ELEMENTS ElementsKind.
+ inline bool HasHoleyElements();
+ inline bool HasSloppyArgumentsElements();
+ inline bool HasStringWrapperElements();
+ inline bool HasDictionaryElements();
+
+ inline bool HasFixedTypedArrayElements();
+
+ inline bool HasFixedUint8ClampedElements();
+ inline bool HasFixedArrayElements();
+ inline bool HasFixedInt8Elements();
+ inline bool HasFixedUint8Elements();
+ inline bool HasFixedInt16Elements();
+ inline bool HasFixedUint16Elements();
+ inline bool HasFixedInt32Elements();
+ inline bool HasFixedUint32Elements();
+ inline bool HasFixedFloat32Elements();
+ inline bool HasFixedFloat64Elements();
+ inline bool HasFixedBigInt64Elements();
+ inline bool HasFixedBigUint64Elements();
+
+ inline bool HasFastArgumentsElements();
+ inline bool HasSlowArgumentsElements();
+ inline bool HasFastStringWrapperElements();
+ inline bool HasSlowStringWrapperElements();
+ bool HasEnumerableElements();
+
+ inline NumberDictionary* element_dictionary(); // Gets slow elements.
+
+ // Requires: HasFastElements().
+ static void EnsureWritableFastElements(Handle<JSObject> object);
+
+ V8_WARN_UNUSED_RESULT static Maybe<bool> SetPropertyWithInterceptor(
+ LookupIterator* it, ShouldThrow should_throw, Handle<Object> value);
+
+ // The API currently still wants DefineOwnPropertyIgnoreAttributes to convert
+ // AccessorInfo objects to data fields. We allow FORCE_FIELD as an exception
+ // to the default behavior that calls the setter.
+ enum AccessorInfoHandling { FORCE_FIELD, DONT_FORCE_FIELD };
+
+ V8_WARN_UNUSED_RESULT static MaybeHandle<Object>
+ DefineOwnPropertyIgnoreAttributes(
+ LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
+ AccessorInfoHandling handling = DONT_FORCE_FIELD);
+
+ V8_WARN_UNUSED_RESULT static Maybe<bool> DefineOwnPropertyIgnoreAttributes(
+ LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
+ ShouldThrow should_throw,
+ AccessorInfoHandling handling = DONT_FORCE_FIELD);
+
+ V8_WARN_UNUSED_RESULT static MaybeHandle<Object>
+ SetOwnPropertyIgnoreAttributes(Handle<JSObject> object, Handle<Name> name,
+ Handle<Object> value,
+ PropertyAttributes attributes);
+
+ V8_WARN_UNUSED_RESULT static MaybeHandle<Object>
+ SetOwnElementIgnoreAttributes(Handle<JSObject> object, uint32_t index,
+ Handle<Object> value,
+ PropertyAttributes attributes);
+
+ // Equivalent to one of the above depending on whether |name| can be converted
+ // to an array index.
+ V8_WARN_UNUSED_RESULT static MaybeHandle<Object>
+ DefinePropertyOrElementIgnoreAttributes(Handle<JSObject> object,
+ Handle<Name> name,
+ Handle<Object> value,
+ PropertyAttributes attributes = NONE);
+
+ // Adds or reconfigures a property to attributes NONE. It will fail when it
+ // cannot.
+ V8_WARN_UNUSED_RESULT static Maybe<bool> CreateDataProperty(
+ LookupIterator* it, Handle<Object> value,
+ ShouldThrow should_throw = kDontThrow);
+
+ static void AddProperty(Isolate* isolate, Handle<JSObject> object,
+ Handle<Name> name, Handle<Object> value,
+ PropertyAttributes attributes);
+
+ static void AddDataElement(Handle<JSObject> receiver, uint32_t index,
+ Handle<Object> value,
+ PropertyAttributes attributes);
+
+ // Extend the receiver with a single fast property appeared first in the
+ // passed map. This also extends the property backing store if necessary.
+ static void AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map);
+
+ // Migrates the given object to a map whose field representations are the
+ // lowest upper bound of all known representations for that field.
+ static void MigrateInstance(Handle<JSObject> instance);
+
+ // Migrates the given object only if the target map is already available,
+ // or returns false if such a map is not yet available.
+ static bool TryMigrateInstance(Handle<JSObject> instance);
+
+ // Sets the property value in a normalized object given (key, value, details).
+ // Handles the special representation of JS global objects.
+ static void SetNormalizedProperty(Handle<JSObject> object, Handle<Name> name,
+ Handle<Object> value,
+ PropertyDetails details);
+ static void SetDictionaryElement(Handle<JSObject> object, uint32_t index,
+ Handle<Object> value,
+ PropertyAttributes attributes);
+ static void SetDictionaryArgumentsElement(Handle<JSObject> object,
+ uint32_t index,
+ Handle<Object> value,
+ PropertyAttributes attributes);
+
+ static void OptimizeAsPrototype(Handle<JSObject> object,
+ bool enable_setup_mode = true);
+ static void ReoptimizeIfPrototype(Handle<JSObject> object);
+ static void MakePrototypesFast(Handle<Object> receiver,
+ WhereToStart where_to_start, Isolate* isolate);
+ static void LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate);
+ static void UpdatePrototypeUserRegistration(Handle<Map> old_map,
+ Handle<Map> new_map,
+ Isolate* isolate);
+ static bool UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate);
+ static Map* InvalidatePrototypeChains(Map* map);
+ static void InvalidatePrototypeValidityCell(JSGlobalObject* global);
+
+ // Updates prototype chain tracking information when an object changes its
+ // map from |old_map| to |new_map|.
+ static void NotifyMapChange(Handle<Map> old_map, Handle<Map> new_map,
+ Isolate* isolate);
+
+ // Utility used by many Array builtins and runtime functions
+ static inline bool PrototypeHasNoElements(Isolate* isolate, JSObject* object);
+
+ // To be passed to PrototypeUsers::Compact.
+ static void PrototypeRegistryCompactionCallback(HeapObject* value,
+ int old_index, int new_index);
+
+ // Retrieve interceptors.
+ inline InterceptorInfo* GetNamedInterceptor();
+ inline InterceptorInfo* GetIndexedInterceptor();
+
+ // Used from JSReceiver.
+ V8_WARN_UNUSED_RESULT static Maybe<PropertyAttributes>
+ GetPropertyAttributesWithInterceptor(LookupIterator* it);
+ V8_WARN_UNUSED_RESULT static Maybe<PropertyAttributes>
+ GetPropertyAttributesWithFailedAccessCheck(LookupIterator* it);
+
+ // Defines an AccessorPair property on the given object.
+ // TODO(mstarzinger): Rename to SetAccessor().
+ static MaybeHandle<Object> DefineAccessor(Handle<JSObject> object,
+ Handle<Name> name,
+ Handle<Object> getter,
+ Handle<Object> setter,
+ PropertyAttributes attributes);
+ static MaybeHandle<Object> DefineAccessor(LookupIterator* it,
+ Handle<Object> getter,
+ Handle<Object> setter,
+ PropertyAttributes attributes);
+
+ // Defines an AccessorInfo property on the given object.
+ V8_WARN_UNUSED_RESULT static MaybeHandle<Object> SetAccessor(
+ Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> info,
+ PropertyAttributes attributes);
+
+ // The result must be checked first for exceptions. If there's no exception,
+ // the output parameter |done| indicates whether the interceptor has a result
+ // or not.
+ V8_WARN_UNUSED_RESULT static MaybeHandle<Object> GetPropertyWithInterceptor(
+ LookupIterator* it, bool* done);
+
+ static void ValidateElements(JSObject* object);
+
+ // Makes sure that this object can contain HeapObject as elements.
+ static inline void EnsureCanContainHeapObjectElements(Handle<JSObject> obj);
+
+ // Makes sure that this object can contain the specified elements.
+ static inline void EnsureCanContainElements(Handle<JSObject> object,
+ Object** elements, uint32_t count,
+ EnsureElementsMode mode);
+ static inline void EnsureCanContainElements(Handle<JSObject> object,
+ Handle<FixedArrayBase> elements,
+ uint32_t length,
+ EnsureElementsMode mode);
+ static void EnsureCanContainElements(Handle<JSObject> object,
+ Arguments* arguments, uint32_t first_arg,
+ uint32_t arg_count,
+ EnsureElementsMode mode);
+
+ // Would we convert a fast elements array to dictionary mode given
+ // an access at key?
+ bool WouldConvertToSlowElements(uint32_t index);
+
+ static const uint32_t kMinAddedElementsCapacity = 16;
+
+ // Computes the new capacity when expanding the elements of a JSObject.
+ static uint32_t NewElementsCapacity(uint32_t old_capacity) {
+ // (old_capacity + 50%) + kMinAddedElementsCapacity
+ return old_capacity + (old_capacity >> 1) + kMinAddedElementsCapacity;
+ }
+
+ // These methods do not perform access checks!
+ template <AllocationSiteUpdateMode update_or_check =
+ AllocationSiteUpdateMode::kUpdate>
+ static bool UpdateAllocationSite(Handle<JSObject> object,
+ ElementsKind to_kind);
+
+ // Lookup interceptors are used for handling properties controlled by host
+ // objects.
+ inline bool HasNamedInterceptor();
+ inline bool HasIndexedInterceptor();
+
+ // Support functions for v8 api (needed for correct interceptor behavior).
+ V8_WARN_UNUSED_RESULT static Maybe<bool> HasRealNamedProperty(
+ Handle<JSObject> object, Handle<Name> name);
+ V8_WARN_UNUSED_RESULT static Maybe<bool> HasRealElementProperty(
+ Handle<JSObject> object, uint32_t index);
+ V8_WARN_UNUSED_RESULT static Maybe<bool> HasRealNamedCallbackProperty(
+ Handle<JSObject> object, Handle<Name> name);
+
+ // Get the header size for a JSObject. Used to compute the index of
+ // embedder fields as well as the number of embedder fields.
+ // The |function_has_prototype_slot| parameter is needed only for
+ // JSFunction objects.
+ static int GetHeaderSize(InstanceType instance_type,
+ bool function_has_prototype_slot = false);
+ static inline int GetHeaderSize(const Map* map);
+ inline int GetHeaderSize() const;
+
+ static inline int GetEmbedderFieldCount(const Map* map);
+ inline int GetEmbedderFieldCount() const;
+ inline int GetEmbedderFieldOffset(int index);
+ inline Object* GetEmbedderField(int index);
+ inline void SetEmbedderField(int index, Object* value);
+ inline void SetEmbedderField(int index, Smi* value);
+
+ // Returns true when the object is potentially a wrapper that gets special
+ // garbage collection treatment.
+ // TODO(mlippautz): Make check exact and replace the pattern match in
+ // Heap::TracePossibleWrapper.
+ bool IsApiWrapper();
+
+ // Same as IsApiWrapper() but also allow dropping the wrapper on minor GCs.
+ bool IsDroppableApiWrapper();
+
+ // Returns a new map with all transitions dropped from the object's current
+ // map and the ElementsKind set.
+ static Handle<Map> GetElementsTransitionMap(Handle<JSObject> object,
+ ElementsKind to_kind);
+ static void TransitionElementsKind(Handle<JSObject> object,
+ ElementsKind to_kind);
+
+ // Always use this to migrate an object to a new map.
+ // |expected_additional_properties| is only used for fast-to-slow transitions
+ // and ignored otherwise.
+ static void MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
+ int expected_additional_properties = 0);
+
+ // Forces a prototype without any of the checks that the regular SetPrototype
+ // would do.
+ static void ForceSetPrototype(Handle<JSObject> object, Handle<Object> proto);
+
+ // Convert the object to use the canonical dictionary
+ // representation. If the object is expected to have additional properties
+ // added this number can be indicated to have the backing store allocated to
+ // an initial capacity for holding these properties.
+ static void NormalizeProperties(Handle<JSObject> object,
+ PropertyNormalizationMode mode,
+ int expected_additional_properties,
+ const char* reason);
+
+ // Convert and update the elements backing store to be a
+ // NumberDictionary dictionary. Returns the backing after conversion.
+ static Handle<NumberDictionary> NormalizeElements(Handle<JSObject> object);
+
+ void RequireSlowElements(NumberDictionary* dictionary);
+
+ // Transform slow named properties to fast variants.
+ static void MigrateSlowToFast(Handle<JSObject> object,
+ int unused_property_fields, const char* reason);
+
+ inline bool IsUnboxedDoubleField(FieldIndex index);
+
+ // Access fast-case object properties at index.
+ static Handle<Object> FastPropertyAt(Handle<JSObject> object,
+ Representation representation,
+ FieldIndex index);
+ inline Object* RawFastPropertyAt(FieldIndex index);
+ inline double RawFastDoublePropertyAt(FieldIndex index);
+ inline uint64_t RawFastDoublePropertyAsBitsAt(FieldIndex index);
+
+ inline void FastPropertyAtPut(FieldIndex index, Object* value);
+ inline void RawFastPropertyAtPut(FieldIndex index, Object* value);
+ inline void RawFastDoublePropertyAsBitsAtPut(FieldIndex index, uint64_t bits);
+ inline void WriteToField(int descriptor, PropertyDetails details,
+ Object* value);
+
+ // Access to in object properties.
+ inline int GetInObjectPropertyOffset(int index);
+ inline Object* InObjectPropertyAt(int index);
+ inline Object* InObjectPropertyAtPut(
+ int index, Object* value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+
+ // Set the object's prototype (only JSReceiver and null are allowed values).
+ V8_WARN_UNUSED_RESULT static Maybe<bool> SetPrototype(
+ Handle<JSObject> object, Handle<Object> value, bool from_javascript,
+ ShouldThrow should_throw);
+
+ // Makes the object prototype immutable
+ // Never called from JavaScript
+ static void SetImmutableProto(Handle<JSObject> object);
+
+ // Initializes the body starting at |start_offset|. It is responsibility of
+ // the caller to initialize object header. Fill the pre-allocated fields with
+ // pre_allocated_value and the rest with filler_value.
+ // Note: this call does not update write barrier, the caller is responsible
+ // to ensure that |filler_value| can be collected without WB here.
+ inline void InitializeBody(Map* map, int start_offset,
+ Object* pre_allocated_value, Object* filler_value);
+
+ // Check whether this object references another object
+ bool ReferencesObject(Object* obj);
+
+ V8_WARN_UNUSED_RESULT static Maybe<bool> TestIntegrityLevel(
+ Handle<JSObject> object, IntegrityLevel lvl);
+
+ V8_WARN_UNUSED_RESULT static Maybe<bool> PreventExtensions(
+ Handle<JSObject> object, ShouldThrow should_throw);
+
+ static bool IsExtensible(Handle<JSObject> object);
+
+ DECL_CAST(JSObject)
+
+ // Dispatched behavior.
+ void JSObjectShortPrint(StringStream* accumulator);
+ DECL_PRINTER(JSObject)
+ DECL_VERIFIER(JSObject)
+#ifdef OBJECT_PRINT
+ bool PrintProperties(std::ostream& os); // NOLINT
+ void PrintElements(std::ostream& os); // NOLINT
+#endif
+#if defined(DEBUG) || defined(OBJECT_PRINT)
+ void PrintTransitions(std::ostream& os); // NOLINT
+#endif
+
+ static void PrintElementsTransition(FILE* file, Handle<JSObject> object,
+ ElementsKind from_kind,
+ Handle<FixedArrayBase> from_elements,
+ ElementsKind to_kind,
+ Handle<FixedArrayBase> to_elements);
+
+ void PrintInstanceMigration(FILE* file, Map* original_map, Map* new_map);
+
+#ifdef DEBUG
+ // Structure for collecting spill information about JSObjects.
+ class SpillInformation {
+ public:
+ void Clear();
+ void Print();
+ int number_of_objects_;
+ int number_of_objects_with_fast_properties_;
+ int number_of_objects_with_fast_elements_;
+ int number_of_fast_used_fields_;
+ int number_of_fast_unused_fields_;
+ int number_of_slow_used_properties_;
+ int number_of_slow_unused_properties_;
+ int number_of_fast_used_elements_;
+ int number_of_fast_unused_elements_;
+ int number_of_slow_used_elements_;
+ int number_of_slow_unused_elements_;
+ };
+
+ void IncrementSpillStatistics(Isolate* isolate, SpillInformation* info);
+#endif
+
+#ifdef VERIFY_HEAP
+ // If a GC was caused while constructing this object, the elements pointer
+ // may point to a one pointer filler map. The object won't be rooted, but
+ // our heap verification code could stumble across it.
+ bool ElementsAreSafeToExamine() const;
+#endif
+
+ Object* SlowReverseLookup(Object* value);
+
+ // Maximal number of elements (numbered 0 .. kMaxElementCount - 1).
+ // Also maximal value of JSArray's length property.
+ static const uint32_t kMaxElementCount = 0xffffffffu;
+
+ // Constants for heuristics controlling conversion of fast elements
+ // to slow elements.
+
+ // Maximal gap that can be introduced by adding an element beyond
+ // the current elements length.
+ static const uint32_t kMaxGap = 1024;
+
+ // Maximal length of fast elements array that won't be checked for
+ // being dense enough on expansion.
+ static const int kMaxUncheckedFastElementsLength = 5000;
+
+ // Same as above but for old arrays. This limit is more strict. We
+ // don't want to be wasteful with long lived objects.
+ static const int kMaxUncheckedOldFastElementsLength = 500;
+
+ // This constant applies only to the initial map of "global.Object" and
+ // not to arbitrary other JSObject maps.
+ static const int kInitialGlobalObjectUnusedPropertiesCount = 4;
+
+ static const int kMaxInstanceSize = 255 * kPointerSize;
+
+ // When extending the backing storage for property values, we increase
+ // its size by more than the 1 entry necessary, so sequentially adding fields
+ // to the same object requires fewer allocations and copies.
+ static const int kFieldsAdded = 3;
+ STATIC_ASSERT(kMaxNumberOfDescriptors + kFieldsAdded <=
+ PropertyArray::kMaxLength);
+
+ // Layout description.
+ static const int kElementsOffset = JSReceiver::kHeaderSize;
+ static const int kHeaderSize = kElementsOffset + kPointerSize;
+
+ STATIC_ASSERT(kHeaderSize == Internals::kJSObjectHeaderSize);
+ static const int kMaxInObjectProperties =
+ (kMaxInstanceSize - kHeaderSize) >> kPointerSizeLog2;
+ STATIC_ASSERT(kMaxInObjectProperties <= kMaxNumberOfDescriptors);
+ // TODO(cbruni): Revisit calculation of the max supported embedder fields.
+ static const int kMaxEmbedderFields =
+ ((1 << kFirstInobjectPropertyOffsetBitCount) - 1 - kHeaderSize) >>
+ kPointerSizeLog2;
+ STATIC_ASSERT(kMaxEmbedderFields <= kMaxInObjectProperties);
+
+ class BodyDescriptor;
+
+ class FastBodyDescriptor;
+
+ // Gets the number of currently used elements.
+ int GetFastElementsUsage();
+
+ static bool AllCanRead(LookupIterator* it);
+ static bool AllCanWrite(LookupIterator* it);
+
+ private:
+ friend class JSReceiver;
+ friend class Object;
+
+ // Used from Object::GetProperty().
+ V8_WARN_UNUSED_RESULT static MaybeHandle<Object>
+ GetPropertyWithFailedAccessCheck(LookupIterator* it);
+
+ V8_WARN_UNUSED_RESULT static Maybe<bool> SetPropertyWithFailedAccessCheck(
+ LookupIterator* it, Handle<Object> value, ShouldThrow should_throw);
+
+ V8_WARN_UNUSED_RESULT static Maybe<bool> DeletePropertyWithInterceptor(
+ LookupIterator* it, ShouldThrow should_throw);
+
+ bool ReferencesObjectFromElements(FixedArray* elements, ElementsKind kind,
+ Object* object);
+
+ // Helper for fast versions of preventExtensions, seal, and freeze.
+ // attrs is one of NONE, SEALED, or FROZEN (depending on the operation).
+ template <PropertyAttributes attrs>
+ V8_WARN_UNUSED_RESULT static Maybe<bool> PreventExtensionsWithTransition(
+ Handle<JSObject> object, ShouldThrow should_throw);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSObject);
+};
+
+// JSAccessorPropertyDescriptor is just a JSObject with a specific initial
+// map. This initial map adds in-object properties for "get", "set",
+// "enumerable" and "configurable" properties, as assigned by the
+// FromPropertyDescriptor function for regular accessor properties.
+class JSAccessorPropertyDescriptor : public JSObject {
+ public:
+ // Offsets of object fields.
+ static const int kGetOffset = JSObject::kHeaderSize;
+ static const int kSetOffset = kGetOffset + kPointerSize;
+ static const int kEnumerableOffset = kSetOffset + kPointerSize;
+ static const int kConfigurableOffset = kEnumerableOffset + kPointerSize;
+ static const int kSize = kConfigurableOffset + kPointerSize;
+ // Indices of in-object properties.
+ static const int kGetIndex = 0;
+ static const int kSetIndex = 1;
+ static const int kEnumerableIndex = 2;
+ static const int kConfigurableIndex = 3;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSAccessorPropertyDescriptor);
+};
+
+// JSDataPropertyDescriptor is just a JSObject with a specific initial map.
+// This initial map adds in-object properties for "value", "writable",
+// "enumerable" and "configurable" properties, as assigned by the
+// FromPropertyDescriptor function for regular data properties.
+class JSDataPropertyDescriptor : public JSObject {
+ public:
+ // Offsets of object fields.
+ static const int kValueOffset = JSObject::kHeaderSize;
+ static const int kWritableOffset = kValueOffset + kPointerSize;
+ static const int kEnumerableOffset = kWritableOffset + kPointerSize;
+ static const int kConfigurableOffset = kEnumerableOffset + kPointerSize;
+ static const int kSize = kConfigurableOffset + kPointerSize;
+ // Indices of in-object properties.
+ static const int kValueIndex = 0;
+ static const int kWritableIndex = 1;
+ static const int kEnumerableIndex = 2;
+ static const int kConfigurableIndex = 3;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSDataPropertyDescriptor);
+};
+
+// JSIteratorResult is just a JSObject with a specific initial map.
+// This initial map adds in-object properties for "done" and "value",
+// as specified by ES6 section 25.1.1.3 The IteratorResult Interface
+class JSIteratorResult : public JSObject {
+ public:
+ DECL_ACCESSORS(value, Object)
+
+ DECL_ACCESSORS(done, Object)
+
+ // Offsets of object fields.
+ static const int kValueOffset = JSObject::kHeaderSize;
+ static const int kDoneOffset = kValueOffset + kPointerSize;
+ static const int kSize = kDoneOffset + kPointerSize;
+ // Indices of in-object properties.
+ static const int kValueIndex = 0;
+ static const int kDoneIndex = 1;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSIteratorResult);
+};
+
+// JSBoundFunction describes a bound function exotic object.
+class JSBoundFunction : public JSObject {
+ public:
+ // [bound_target_function]: The wrapped function object.
+ inline Object* raw_bound_target_function() const;
+ DECL_ACCESSORS(bound_target_function, JSReceiver)
+
+ // [bound_this]: The value that is always passed as the this value when
+ // calling the wrapped function.
+ DECL_ACCESSORS(bound_this, Object)
+
+ // [bound_arguments]: A list of values whose elements are used as the first
+ // arguments to any call to the wrapped function.
+ DECL_ACCESSORS(bound_arguments, FixedArray)
+
+ static MaybeHandle<String> GetName(Isolate* isolate,
+ Handle<JSBoundFunction> function);
+ static Maybe<int> GetLength(Isolate* isolate,
+ Handle<JSBoundFunction> function);
+ static MaybeHandle<Context> GetFunctionRealm(
+ Handle<JSBoundFunction> function);
+
+ DECL_CAST(JSBoundFunction)
+
+ // Dispatched behavior.
+ DECL_PRINTER(JSBoundFunction)
+ DECL_VERIFIER(JSBoundFunction)
+
+ // The bound function's string representation implemented according
+ // to ES6 section 19.2.3.5 Function.prototype.toString ( ).
+ static Handle<String> ToString(Handle<JSBoundFunction> function);
+
+ // Layout description.
+ static const int kBoundTargetFunctionOffset = JSObject::kHeaderSize;
+ static const int kBoundThisOffset = kBoundTargetFunctionOffset + kPointerSize;
+ static const int kBoundArgumentsOffset = kBoundThisOffset + kPointerSize;
+ static const int kSize = kBoundArgumentsOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSBoundFunction);
+};
+
+// JSFunction describes JavaScript functions.
+class JSFunction : public JSObject {
+ public:
+ // [prototype_or_initial_map]:
+ DECL_ACCESSORS(prototype_or_initial_map, Object)
+
+ // [shared]: The information about the function that
+ // can be shared by instances.
+ DECL_ACCESSORS(shared, SharedFunctionInfo)
+
+ static const int kLengthDescriptorIndex = 0;
+ static const int kNameDescriptorIndex = 1;
+ // Home object descriptor index when function has a [[HomeObject]] slot.
+ static const int kMaybeHomeObjectDescriptorIndex = 2;
+
+ // [context]: The context for this function.
+ inline Context* context();
+ inline bool has_context() const;
+ inline void set_context(Object* context);
+ inline JSGlobalProxy* global_proxy();
+ inline Context* native_context();
+
+ static Handle<Object> GetName(Isolate* isolate, Handle<JSFunction> function);
+ static Maybe<int> GetLength(Isolate* isolate, Handle<JSFunction> function);
+ static Handle<Context> GetFunctionRealm(Handle<JSFunction> function);
+
+ // [code]: The generated code object for this function. Executed
+ // when the function is invoked, e.g. foo() or new foo(). See
+ // [[Call]] and [[Construct]] description in ECMA-262, section
+ // 8.6.2, page 27.
+ inline Code* code();
+ inline void set_code(Code* code);
+ inline void set_code_no_write_barrier(Code* code);
+
+ // Get the abstract code associated with the function, which will either be
+ // a Code object or a BytecodeArray.
+ inline AbstractCode* abstract_code();
+
+ // Tells whether or not this function is interpreted.
+ //
+ // Note: function->IsInterpreted() does not necessarily return the same value
+ // as function->shared()->IsInterpreted() because the closure might have been
+ // optimized.
+ inline bool IsInterpreted();
+
+ // Tells whether or not this function checks its optimization marker in its
+ // feedback vector.
+ inline bool ChecksOptimizationMarker();
+
+ // Tells whether or not this function holds optimized code.
+ //
+ // Note: Returning false does not necessarily mean that this function hasn't
+ // been optimized, as it may have optimized code on its feedback vector.
+ inline bool IsOptimized();
+
+ // Tells whether or not this function has optimized code available to it,
+ // either because it is optimized or because it has optimized code in its
+ // feedback vector.
+ inline bool HasOptimizedCode();
+
+ // Tells whether or not this function has a (non-zero) optimization marker.
+ inline bool HasOptimizationMarker();
+
+ // Mark this function for lazy recompilation. The function will be recompiled
+ // the next time it is executed.
+ void MarkForOptimization(ConcurrencyMode mode);
+
+ // Tells whether or not the function is already marked for lazy recompilation.
+ inline bool IsMarkedForOptimization();
+ inline bool IsMarkedForConcurrentOptimization();
+
+ // Tells whether or not the function is on the concurrent recompilation queue.
+ inline bool IsInOptimizationQueue();
+
+ // Clears the optimized code slot in the function's feedback vector.
+ inline void ClearOptimizedCodeSlot(const char* reason);
+
+ // Sets the optimization marker in the function's feedback vector.
+ inline void SetOptimizationMarker(OptimizationMarker marker);
+
+ // Clears the optimization marker in the function's feedback vector.
+ inline void ClearOptimizationMarker();
+
+ // If slack tracking is active, it computes instance size of the initial map
+ // with minimum permissible object slack. If it is not active, it simply
+ // returns the initial map's instance size.
+ int ComputeInstanceSizeWithMinSlack(Isolate* isolate);
+
+ // Completes inobject slack tracking on initial map if it is active.
+ inline void CompleteInobjectSlackTrackingIfActive();
+
+ // [feedback_cell]: The FeedbackCell used to hold the FeedbackVector
+ // eventually.
+ DECL_ACCESSORS(feedback_cell, FeedbackCell)
+
+ // feedback_vector() can be used once the function is compiled.
+ inline FeedbackVector* feedback_vector() const;
+ inline bool has_feedback_vector() const;
+ static void EnsureFeedbackVector(Handle<JSFunction> function);
+
+ // Unconditionally clear the type feedback vector.
+ void ClearTypeFeedbackInfo();
+
+ inline bool has_prototype_slot() const;
+
+ // The initial map for an object created by this constructor.
+ inline Map* initial_map();
+ static void SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
+ Handle<Object> prototype);
+ inline bool has_initial_map();
+ static void EnsureHasInitialMap(Handle<JSFunction> function);
+
+ // Creates a map that matches the constructor's initial map, but with
+ // [[prototype]] being new.target.prototype. Because new.target can be a
+ // JSProxy, this can call back into JavaScript.
+ static V8_WARN_UNUSED_RESULT MaybeHandle<Map> GetDerivedMap(
+ Isolate* isolate, Handle<JSFunction> constructor,
+ Handle<JSReceiver> new_target);
+
+ // Get and set the prototype property on a JSFunction. If the
+ // function has an initial map the prototype is set on the initial
+ // map. Otherwise, the prototype is put in the initial map field
+ // until an initial map is needed.
+ inline bool has_prototype();
+ inline bool has_instance_prototype();
+ inline Object* prototype();
+ inline Object* instance_prototype();
+ inline bool has_prototype_property();
+ inline bool PrototypeRequiresRuntimeLookup();
+ static void SetPrototype(Handle<JSFunction> function, Handle<Object> value);
+
+ // Returns if this function has been compiled to native code yet.
+ inline bool is_compiled();
+
+ static int GetHeaderSize(bool function_has_prototype_slot) {
+ return function_has_prototype_slot ? JSFunction::kSizeWithPrototype
+ : JSFunction::kSizeWithoutPrototype;
+ }
+
+ // Prints the name of the function using PrintF.
+ void PrintName(FILE* out = stdout);
+
+ DECL_CAST(JSFunction)
+
+ // Calculate the instance size and in-object properties count.
+ static bool CalculateInstanceSizeForDerivedClass(
+ Handle<JSFunction> function, InstanceType instance_type,
+ int requested_embedder_fields, int* instance_size,
+ int* in_object_properties);
+ static void CalculateInstanceSizeHelper(InstanceType instance_type,
+ bool has_prototype_slot,
+ int requested_embedder_fields,
+ int requested_in_object_properties,
+ int* instance_size,
+ int* in_object_properties);
+
+ class BodyDescriptor;
+
+ // Dispatched behavior.
+ DECL_PRINTER(JSFunction)
+ DECL_VERIFIER(JSFunction)
+
+ // The function's name if it is configured, otherwise shared function info
+ // debug name.
+ static Handle<String> GetName(Handle<JSFunction> function);
+
+ // ES6 section 9.2.11 SetFunctionName
+ // Because of the way this abstract operation is used in the spec,
+ // it should never fail, but in practice it will fail if the generated
+ // function name's length exceeds String::kMaxLength.
+ static V8_WARN_UNUSED_RESULT bool SetName(Handle<JSFunction> function,
+ Handle<Name> name,
+ Handle<String> prefix);
+
+ // The function's displayName if it is set, otherwise name if it is
+ // configured, otherwise shared function info
+ // debug name.
+ static Handle<String> GetDebugName(Handle<JSFunction> function);
+
+ // The function's string representation implemented according to
+ // ES6 section 19.2.3.5 Function.prototype.toString ( ).
+ static Handle<String> ToString(Handle<JSFunction> function);
+
+// Layout description.
+#define JS_FUNCTION_FIELDS(V) \
+ /* Pointer fields. */ \
+ V(kSharedFunctionInfoOffset, kPointerSize) \
+ V(kContextOffset, kPointerSize) \
+ V(kFeedbackCellOffset, kPointerSize) \
+ V(kEndOfStrongFieldsOffset, 0) \
+ V(kCodeOffset, kPointerSize) \
+ /* Size of JSFunction object without prototype field. */ \
+ V(kSizeWithoutPrototype, 0) \
+ V(kPrototypeOrInitialMapOffset, kPointerSize) \
+ /* Size of JSFunction object with prototype field. */ \
+ V(kSizeWithPrototype, 0)
+
+ DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, JS_FUNCTION_FIELDS)
+#undef JS_FUNCTION_FIELDS
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSFunction);
+};
+
+// JSGlobalProxy's prototype must be a JSGlobalObject or null,
+// and the prototype is hidden. JSGlobalProxy always delegates
+// property accesses to its prototype if the prototype is not null.
+//
+// A JSGlobalProxy can be reinitialized which will preserve its identity.
+//
+// Accessing a JSGlobalProxy requires security check.
+
+class JSGlobalProxy : public JSObject {
+ public:
+ // [native_context]: the owner native context of this global proxy object.
+ // It is null value if this object is not used by any context.
+ DECL_ACCESSORS(native_context, Object)
+
+ DECL_CAST(JSGlobalProxy)
+
+ inline bool IsDetachedFrom(JSGlobalObject* global) const;
+
+ static int SizeWithEmbedderFields(int embedder_field_count);
+
+ // Dispatched behavior.
+ DECL_PRINTER(JSGlobalProxy)
+ DECL_VERIFIER(JSGlobalProxy)
+
+ // Layout description.
+ static const int kNativeContextOffset = JSObject::kHeaderSize;
+ static const int kSize = kNativeContextOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSGlobalProxy);
+};
+
+// JavaScript global object.
+class JSGlobalObject : public JSObject {
+ public:
+ // [native context]: the natives corresponding to this global object.
+ DECL_ACCESSORS(native_context, Context)
+
+ // [global proxy]: the global proxy object of the context
+ DECL_ACCESSORS(global_proxy, JSObject)
+
+ // Gets global object properties.
+ inline GlobalDictionary* global_dictionary();
+ inline void set_global_dictionary(GlobalDictionary* dictionary);
+
+ static void InvalidatePropertyCell(Handle<JSGlobalObject> object,
+ Handle<Name> name);
+ // Ensure that the global object has a cell for the given property name.
+ static Handle<PropertyCell> EnsureEmptyPropertyCell(
+ Handle<JSGlobalObject> global, Handle<Name> name,
+ PropertyCellType cell_type, int* entry_out = nullptr);
+
+ DECL_CAST(JSGlobalObject)
+
+ inline bool IsDetached();
+
+ // Dispatched behavior.
+ DECL_PRINTER(JSGlobalObject)
+ DECL_VERIFIER(JSGlobalObject)
+
+ // Layout description.
+ static const int kNativeContextOffset = JSObject::kHeaderSize;
+ static const int kGlobalProxyOffset = kNativeContextOffset + kPointerSize;
+ static const int kHeaderSize = kGlobalProxyOffset + kPointerSize;
+ static const int kSize = kHeaderSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSGlobalObject);
+};
+
+// Representation for JS Wrapper objects, String, Number, Boolean, etc.
+class JSValue : public JSObject {
+ public:
+ // [value]: the object being wrapped.
+ DECL_ACCESSORS(value, Object)
+
+ DECL_CAST(JSValue)
+
+ // Dispatched behavior.
+ DECL_PRINTER(JSValue)
+ DECL_VERIFIER(JSValue)
+
+ // Layout description.
+ static const int kValueOffset = JSObject::kHeaderSize;
+ static const int kSize = kValueOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSValue);
+};
+
+class DateCache;
+
+// Representation for JS date objects.
+class JSDate : public JSObject {
+ public:
+ static V8_WARN_UNUSED_RESULT MaybeHandle<JSDate> New(
+ Handle<JSFunction> constructor, Handle<JSReceiver> new_target, double tv);
+
+ // If one component is NaN, all of them are, indicating a NaN time value.
+ // [value]: the time value.
+ DECL_ACCESSORS(value, Object)
+ // [year]: caches year. Either undefined, smi, or NaN.
+ DECL_ACCESSORS(year, Object)
+ // [month]: caches month. Either undefined, smi, or NaN.
+ DECL_ACCESSORS(month, Object)
+ // [day]: caches day. Either undefined, smi, or NaN.
+ DECL_ACCESSORS(day, Object)
+ // [weekday]: caches day of week. Either undefined, smi, or NaN.
+ DECL_ACCESSORS(weekday, Object)
+ // [hour]: caches hours. Either undefined, smi, or NaN.
+ DECL_ACCESSORS(hour, Object)
+ // [min]: caches minutes. Either undefined, smi, or NaN.
+ DECL_ACCESSORS(min, Object)
+ // [sec]: caches seconds. Either undefined, smi, or NaN.
+ DECL_ACCESSORS(sec, Object)
+ // [cache stamp]: sample of the date cache stamp at the
+ // moment when chached fields were cached.
+ DECL_ACCESSORS(cache_stamp, Object)
+
+ DECL_CAST(JSDate)
+
+ // Returns the time value (UTC) identifying the current time.
+ static double CurrentTimeValue(Isolate* isolate);
+
+ // Returns the date field with the specified index.
+ // See FieldIndex for the list of date fields.
+ static Object* GetField(Object* date, Smi* index);
+
+ static Handle<Object> SetValue(Handle<JSDate> date, double v);
+
+ void SetValue(Object* value, bool is_value_nan);
+
+ // Dispatched behavior.
+ DECL_PRINTER(JSDate)
+ DECL_VERIFIER(JSDate)
+
+ // The order is important. It must be kept in sync with date macros
+ // in macros.py.
+ enum FieldIndex {
+ kDateValue,
+ kYear,
+ kMonth,
+ kDay,
+ kWeekday,
+ kHour,
+ kMinute,
+ kSecond,
+ kFirstUncachedField,
+ kMillisecond = kFirstUncachedField,
+ kDays,
+ kTimeInDay,
+ kFirstUTCField,
+ kYearUTC = kFirstUTCField,
+ kMonthUTC,
+ kDayUTC,
+ kWeekdayUTC,
+ kHourUTC,
+ kMinuteUTC,
+ kSecondUTC,
+ kMillisecondUTC,
+ kDaysUTC,
+ kTimeInDayUTC,
+ kTimezoneOffset
+ };
+
+ // Layout description.
+ static const int kValueOffset = JSObject::kHeaderSize;
+ static const int kYearOffset = kValueOffset + kPointerSize;
+ static const int kMonthOffset = kYearOffset + kPointerSize;
+ static const int kDayOffset = kMonthOffset + kPointerSize;
+ static const int kWeekdayOffset = kDayOffset + kPointerSize;
+ static const int kHourOffset = kWeekdayOffset + kPointerSize;
+ static const int kMinOffset = kHourOffset + kPointerSize;
+ static const int kSecOffset = kMinOffset + kPointerSize;
+ static const int kCacheStampOffset = kSecOffset + kPointerSize;
+ static const int kSize = kCacheStampOffset + kPointerSize;
+
+ private:
+ inline Object* DoGetField(FieldIndex index);
+
+ Object* GetUTCField(FieldIndex index, double value, DateCache* date_cache);
+
+ // Computes and caches the cacheable fields of the date.
+ inline void SetCachedFields(int64_t local_time_ms, DateCache* date_cache);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSDate);
+};
+
+// Representation of message objects used for error reporting through
+// the API. The messages are formatted in JavaScript so this object is
+// a real JavaScript object. The information used for formatting the
+// error messages are not directly accessible from JavaScript to
+// prevent leaking information to user code called during error
+// formatting.
+class JSMessageObject : public JSObject {
+ public:
+ // [type]: the type of error message.
+ inline int type() const;
+ inline void set_type(int value);
+
+ // [arguments]: the arguments for formatting the error message.
+ DECL_ACCESSORS(argument, Object)
+
+ // [script]: the script from which the error message originated.
+ DECL_ACCESSORS(script, Script)
+
+ // [stack_frames]: an array of stack frames for this error object.
+ DECL_ACCESSORS(stack_frames, Object)
+
+ // [start_position]: the start position in the script for the error message.
+ inline int start_position() const;
+ inline void set_start_position(int value);
+
+ // [end_position]: the end position in the script for the error message.
+ inline int end_position() const;
+ inline void set_end_position(int value);
+
+ // Returns the line number for the error message (1-based), or
+ // Message::kNoLineNumberInfo if the line cannot be determined.
+ int GetLineNumber() const;
+
+ // Returns the offset of the given position within the containing line.
+ int GetColumnNumber() const;
+
+ // Returns the source code line containing the given source
+ // position, or the empty string if the position is invalid.
+ Handle<String> GetSourceLine() const;
+
+ inline int error_level() const;
+ inline void set_error_level(int level);
+
+ DECL_CAST(JSMessageObject)
+
+ // Dispatched behavior.
+ DECL_PRINTER(JSMessageObject)
+ DECL_VERIFIER(JSMessageObject)
+
+ // Layout description.
+ static const int kTypeOffset = JSObject::kHeaderSize;
+ static const int kArgumentsOffset = kTypeOffset + kPointerSize;
+ static const int kScriptOffset = kArgumentsOffset + kPointerSize;
+ static const int kStackFramesOffset = kScriptOffset + kPointerSize;
+ static const int kStartPositionOffset = kStackFramesOffset + kPointerSize;
+ static const int kEndPositionOffset = kStartPositionOffset + kPointerSize;
+ static const int kErrorLevelOffset = kEndPositionOffset + kPointerSize;
+ static const int kSize = kErrorLevelOffset + kPointerSize;
+
+ typedef FixedBodyDescriptor<HeapObject::kMapOffset,
+ kStackFramesOffset + kPointerSize, kSize>
+ BodyDescriptor;
+};
+
+// The [Async-from-Sync Iterator] object
+// (proposal-async-iteration/#sec-async-from-sync-iterator-objects)
+// An object which wraps an ordinary Iterator and converts it to behave
+// according to the Async Iterator protocol.
+// (See https://tc39.github.io/proposal-async-iteration/#sec-iteration)
+class JSAsyncFromSyncIterator : public JSObject {
+ public:
+ DECL_CAST(JSAsyncFromSyncIterator)
+ DECL_PRINTER(JSAsyncFromSyncIterator)
+ DECL_VERIFIER(JSAsyncFromSyncIterator)
+
+ // Async-from-Sync Iterator instances are ordinary objects that inherit
+ // properties from the %AsyncFromSyncIteratorPrototype% intrinsic object.
+ // Async-from-Sync Iterator instances are initially created with the internal
+ // slots listed in Table 4.
+ // (proposal-async-iteration/#table-async-from-sync-iterator-internal-slots)
+ DECL_ACCESSORS(sync_iterator, JSReceiver)
+
+ // The "next" method is loaded during GetIterator, and is not reloaded for
+ // subsequent "next" invocations.
+ DECL_ACCESSORS(next, Object)
+
+ // Offsets of object fields.
+ static const int kSyncIteratorOffset = JSObject::kHeaderSize;
+ static const int kNextOffset = kSyncIteratorOffset + kPointerSize;
+ static const int kSize = kNextOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSAsyncFromSyncIterator);
+};
+
+class JSStringIterator : public JSObject {
+ public:
+ // Dispatched behavior.
+ DECL_PRINTER(JSStringIterator)
+ DECL_VERIFIER(JSStringIterator)
+
+ DECL_CAST(JSStringIterator)
+
+ // [string]: the [[IteratedString]] inobject property.
+ DECL_ACCESSORS(string, String)
+
+ // [index]: The [[StringIteratorNextIndex]] inobject property.
+ inline int index() const;
+ inline void set_index(int value);
+
+ static const int kStringOffset = JSObject::kHeaderSize;
+ static const int kNextIndexOffset = kStringOffset + kPointerSize;
+ static const int kSize = kNextIndexOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSStringIterator);
+};
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_JS_OBJECTS_H_
diff --git a/deps/v8/src/objects/js-plural-rules.cc b/deps/v8/src/objects/js-plural-rules.cc
index 07cc62a41e..f76692c501 100644
--- a/deps/v8/src/objects/js-plural-rules.cc
+++ b/deps/v8/src/objects/js-plural-rules.cc
@@ -85,7 +85,7 @@ void InitializeICUPluralRules(
} // namespace
// static
-MaybeHandle<JSPluralRules> JSPluralRules::InitializePluralRules(
+MaybeHandle<JSPluralRules> JSPluralRules::Initialize(
Isolate* isolate, Handle<JSPluralRules> plural_rules,
Handle<Object> locales, Handle<Object> options_obj) {
// 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
@@ -190,8 +190,7 @@ MaybeHandle<JSPluralRules> JSPluralRules::InitializePluralRules(
}
MaybeHandle<String> JSPluralRules::ResolvePlural(
- Isolate* isolate, Handle<JSPluralRules> plural_rules,
- Handle<Object> number) {
+ Isolate* isolate, Handle<JSPluralRules> plural_rules, double number) {
icu::PluralRules* icu_plural_rules = plural_rules->icu_plural_rules()->raw();
CHECK_NOT_NULL(icu_plural_rules);
@@ -207,7 +206,7 @@ MaybeHandle<String> JSPluralRules::ResolvePlural(
// this step, then switch to that API. Bug thread:
// http://bugs.icu-project.org/trac/ticket/12763
icu::UnicodeString rounded_string;
- icu_decimal_format->format(number->Number(), rounded_string);
+ icu_decimal_format->format(number, rounded_string);
icu::Formattable formattable;
UErrorCode status = U_ZERO_ERROR;
diff --git a/deps/v8/src/objects/js-plural-rules.h b/deps/v8/src/objects/js-plural-rules.h
index 9d5da795ab..f262457acb 100644
--- a/deps/v8/src/objects/js-plural-rules.h
+++ b/deps/v8/src/objects/js-plural-rules.h
@@ -18,12 +18,16 @@
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
+namespace U_ICU_NAMESPACE {
+class PluralRules;
+} // namespace U_ICU_NAMESPACE
+
namespace v8 {
namespace internal {
class JSPluralRules : public JSObject {
public:
- V8_WARN_UNUSED_RESULT static MaybeHandle<JSPluralRules> InitializePluralRules(
+ V8_WARN_UNUSED_RESULT static MaybeHandle<JSPluralRules> Initialize(
Isolate* isolate, Handle<JSPluralRules> plural_rules,
Handle<Object> locales, Handle<Object> options);
@@ -31,8 +35,7 @@ class JSPluralRules : public JSObject {
Handle<JSPluralRules> plural_rules);
V8_WARN_UNUSED_RESULT static MaybeHandle<String> ResolvePlural(
- Isolate* isolate, Handle<JSPluralRules> plural_rules,
- Handle<Object> number);
+ Isolate* isolate, Handle<JSPluralRules> plural_rules, double number);
DECL_CAST(JSPluralRules)
DECL_PRINTER(JSPluralRules)
diff --git a/deps/v8/src/objects/js-promise.h b/deps/v8/src/objects/js-promise.h
index c52e19ce49..b395ac9b6d 100644
--- a/deps/v8/src/objects/js-promise.h
+++ b/deps/v8/src/objects/js-promise.h
@@ -5,7 +5,7 @@
#ifndef V8_OBJECTS_JS_PROMISE_H_
#define V8_OBJECTS_JS_PROMISE_H_
-#include "src/objects.h"
+#include "src/objects/js-objects.h"
#include "src/objects/promise.h"
// Has to be the last include (doesn't have include guards):
diff --git a/deps/v8/src/objects/js-proxy.h b/deps/v8/src/objects/js-proxy.h
index 45e27473fe..2a7c518be4 100644
--- a/deps/v8/src/objects/js-proxy.h
+++ b/deps/v8/src/objects/js-proxy.h
@@ -5,7 +5,7 @@
#ifndef V8_OBJECTS_JS_PROXY_H_
#define V8_OBJECTS_JS_PROXY_H_
-#include "src/objects.h"
+#include "src/objects/js-objects.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
@@ -118,8 +118,6 @@ class JSProxy : public JSReceiver {
typedef FixedBodyDescriptor<JSReceiver::kPropertiesOrHashOffset, kSize, kSize>
BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
static Maybe<bool> SetPrivateSymbol(Isolate* isolate, Handle<JSProxy> proxy,
Handle<Symbol> private_name,
diff --git a/deps/v8/src/objects/js-regexp-string-iterator.h b/deps/v8/src/objects/js-regexp-string-iterator.h
index 9821e33efb..9ad2851c7a 100644
--- a/deps/v8/src/objects/js-regexp-string-iterator.h
+++ b/deps/v8/src/objects/js-regexp-string-iterator.h
@@ -5,7 +5,7 @@
#ifndef V8_OBJECTS_JS_REGEXP_STRING_ITERATOR_H_
#define V8_OBJECTS_JS_REGEXP_STRING_ITERATOR_H_
-#include "src/objects.h"
+#include "src/objects/js-objects.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
diff --git a/deps/v8/src/objects/js-relative-time-format-inl.h b/deps/v8/src/objects/js-relative-time-format-inl.h
index 6dc984e252..a4ee3ee7f3 100644
--- a/deps/v8/src/objects/js-relative-time-format-inl.h
+++ b/deps/v8/src/objects/js-relative-time-format-inl.h
@@ -20,7 +20,8 @@ namespace internal {
// Base relative time format accessors.
ACCESSORS(JSRelativeTimeFormat, locale, String, kLocaleOffset)
-ACCESSORS(JSRelativeTimeFormat, formatter, Foreign, kFormatterOffset)
+ACCESSORS(JSRelativeTimeFormat, icu_formatter,
+ Managed<icu::RelativeDateTimeFormatter>, kICUFormatterOffset)
SMI_ACCESSORS(JSRelativeTimeFormat, flags, kFlagsOffset)
// TODO(ftang): Use bit field accessor for style and numeric later.
diff --git a/deps/v8/src/objects/js-relative-time-format.cc b/deps/v8/src/objects/js-relative-time-format.cc
index 56130f7311..b3aa996d64 100644
--- a/deps/v8/src/objects/js-relative-time-format.cc
+++ b/deps/v8/src/objects/js-relative-time-format.cc
@@ -17,9 +17,9 @@
#include "src/objects-inl.h"
#include "src/objects/intl-objects.h"
#include "src/objects/js-relative-time-format-inl.h"
-#include "src/objects/managed.h"
#include "unicode/numfmt.h"
#include "unicode/reldatefmt.h"
+#include "unicode/uvernum.h" // for U_ICU_VERSION_MAJOR_NUM
namespace v8 {
namespace internal {
@@ -54,8 +54,7 @@ JSRelativeTimeFormat::Numeric JSRelativeTimeFormat::getNumeric(
UNREACHABLE();
}
-MaybeHandle<JSRelativeTimeFormat>
-JSRelativeTimeFormat::InitializeRelativeTimeFormat(
+MaybeHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::Initialize(
Isolate* isolate, Handle<JSRelativeTimeFormat> relative_time_format_holder,
Handle<Object> input_locales, Handle<Object> input_options) {
Factory* factory = isolate->factory();
@@ -161,7 +160,7 @@ JSRelativeTimeFormat::InitializeRelativeTimeFormat(
icu_formatter);
// 30. Set relativeTimeFormat.[[InitializedRelativeTimeFormat]] to true.
- relative_time_format_holder->set_formatter(*managed_formatter);
+ relative_time_format_holder->set_icu_formatter(*managed_formatter);
// 31. Return relativeTimeFormat.
return relative_time_format_holder;
}
@@ -180,12 +179,6 @@ Handle<JSObject> JSRelativeTimeFormat::ResolvedOptions(
return result;
}
-icu::RelativeDateTimeFormatter* JSRelativeTimeFormat::UnpackFormatter(
- Handle<JSRelativeTimeFormat> holder) {
- return Managed<icu::RelativeDateTimeFormatter>::cast(holder->formatter())
- ->raw();
-}
-
Handle<String> JSRelativeTimeFormat::StyleAsString() const {
switch (style()) {
case Style::LONG:
@@ -210,5 +203,212 @@ Handle<String> JSRelativeTimeFormat::NumericAsString() const {
}
}
+namespace {
+
+Handle<String> UnitAsString(Isolate* isolate, URelativeDateTimeUnit unit_enum) {
+ Factory* factory = isolate->factory();
+ switch (unit_enum) {
+ case UDAT_REL_UNIT_SECOND:
+ return factory->second_string();
+ case UDAT_REL_UNIT_MINUTE:
+ return factory->minute_string();
+ case UDAT_REL_UNIT_HOUR:
+ return factory->hour_string();
+ case UDAT_REL_UNIT_DAY:
+ return factory->day_string();
+ case UDAT_REL_UNIT_WEEK:
+ return factory->week_string();
+ case UDAT_REL_UNIT_MONTH:
+ return factory->month_string();
+ case UDAT_REL_UNIT_QUARTER:
+ return factory->quarter_string();
+ case UDAT_REL_UNIT_YEAR:
+ return factory->year_string();
+ default:
+ UNREACHABLE();
+ }
+}
+
+MaybeHandle<JSArray> GenerateRelativeTimeFormatParts(
+ Isolate* isolate, const icu::UnicodeString& formatted,
+ const icu::UnicodeString& integer_part, URelativeDateTimeUnit unit_enum) {
+ Factory* factory = isolate->factory();
+ Handle<JSArray> array = factory->NewJSArray(0);
+ int32_t found = formatted.indexOf(integer_part);
+
+ Handle<String> substring;
+ if (found < 0) {
+ // Cannot find the integer_part in the formatted.
+ // Return [{'type': 'literal', 'value': formatted}]
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, substring,
+ Intl::ToString(isolate, formatted), JSArray);
+ Intl::AddElement(isolate, array,
+ 0, // index
+ factory->literal_string(), // field_type_string
+ substring);
+ } else {
+ // Found the formatted integer in the result.
+ int index = 0;
+
+ // array.push({
+ // 'type': 'literal',
+ // 'value': formatted.substring(0, found)})
+ if (found > 0) {
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, substring,
+ Intl::ToString(isolate, formatted, 0, found),
+ JSArray);
+ Intl::AddElement(isolate, array, index++,
+ factory->literal_string(), // field_type_string
+ substring);
+ }
+
+ // array.push({
+ // 'type': 'integer',
+ // 'value': formatted.substring(found, found + integer_part.length),
+ // 'unit': unit})
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, substring,
+ Intl::ToString(isolate, formatted, found,
+ found + integer_part.length()),
+ JSArray);
+ Handle<String> unit = UnitAsString(isolate, unit_enum);
+ Intl::AddElement(isolate, array, index++,
+ factory->integer_string(), // field_type_string
+ substring, factory->unit_string(), unit);
+
+ // array.push({
+ // 'type': 'literal',
+ // 'value': formatted.substring(
+ // found + integer_part.length, formatted.length)})
+ if (found + integer_part.length() < formatted.length()) {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, substring,
+ Intl::ToString(isolate, formatted, found + integer_part.length(),
+ formatted.length()),
+ JSArray);
+ Intl::AddElement(isolate, array, index,
+ factory->literal_string(), // field_type_string
+ substring);
+ }
+ }
+ return array;
+}
+
+bool GetURelativeDateTimeUnit(Handle<String> unit,
+ URelativeDateTimeUnit* unit_enum) {
+ std::unique_ptr<char[]> unit_str = unit->ToCString();
+ if ((strcmp("second", unit_str.get()) == 0) ||
+ (strcmp("seconds", unit_str.get()) == 0)) {
+ *unit_enum = UDAT_REL_UNIT_SECOND;
+ } else if ((strcmp("minute", unit_str.get()) == 0) ||
+ (strcmp("minutes", unit_str.get()) == 0)) {
+ *unit_enum = UDAT_REL_UNIT_MINUTE;
+ } else if ((strcmp("hour", unit_str.get()) == 0) ||
+ (strcmp("hours", unit_str.get()) == 0)) {
+ *unit_enum = UDAT_REL_UNIT_HOUR;
+ } else if ((strcmp("day", unit_str.get()) == 0) ||
+ (strcmp("days", unit_str.get()) == 0)) {
+ *unit_enum = UDAT_REL_UNIT_DAY;
+ } else if ((strcmp("week", unit_str.get()) == 0) ||
+ (strcmp("weeks", unit_str.get()) == 0)) {
+ *unit_enum = UDAT_REL_UNIT_WEEK;
+ } else if ((strcmp("month", unit_str.get()) == 0) ||
+ (strcmp("months", unit_str.get()) == 0)) {
+ *unit_enum = UDAT_REL_UNIT_MONTH;
+ } else if ((strcmp("quarter", unit_str.get()) == 0) ||
+ (strcmp("quarters", unit_str.get()) == 0)) {
+ *unit_enum = UDAT_REL_UNIT_QUARTER;
+ } else if ((strcmp("year", unit_str.get()) == 0) ||
+ (strcmp("years", unit_str.get()) == 0)) {
+ *unit_enum = UDAT_REL_UNIT_YEAR;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+MaybeHandle<Object> JSRelativeTimeFormat::Format(
+ Isolate* isolate, Handle<Object> value_obj, Handle<Object> unit_obj,
+ Handle<JSRelativeTimeFormat> format_holder, const char* func_name,
+ bool to_parts) {
+ Factory* factory = isolate->factory();
+
+ // 3. Let value be ? ToNumber(value).
+ Handle<Object> value;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
+ Object::ToNumber(isolate, value_obj), Object);
+ double number = value->Number();
+ // 4. Let unit be ? ToString(unit).
+ Handle<String> unit;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, unit, Object::ToString(isolate, unit_obj),
+ Object);
+
+ // 4. If isFinite(value) is false, then throw a RangeError exception.
+ if (!std::isfinite(number)) {
+ THROW_NEW_ERROR(
+ isolate,
+ NewRangeError(MessageTemplate::kNotFiniteNumber,
+ isolate->factory()->NewStringFromAsciiChecked(func_name)),
+ Object);
+ }
+
+ icu::RelativeDateTimeFormatter* formatter =
+ format_holder->icu_formatter()->raw();
+ CHECK_NOT_NULL(formatter);
+
+ URelativeDateTimeUnit unit_enum;
+ if (!GetURelativeDateTimeUnit(unit, &unit_enum)) {
+ THROW_NEW_ERROR(
+ isolate,
+ NewRangeError(MessageTemplate::kInvalidUnit,
+ isolate->factory()->NewStringFromAsciiChecked(func_name),
+ unit),
+ Object);
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ icu::UnicodeString formatted;
+
+#if USE_CHROMIUM_ICU != 1 && U_ICU_VERSION_MAJOR_NUM < 63
+ if (unit_enum != UDAT_REL_UNIT_QUARTER) { // ICU did not implement
+ // UDAT_REL_UNIT_QUARTER < 63
+#endif // USE_CHROMIUM_ICU != 1 && U_ICU_VERSION_MAJOR_NUM < 63
+ if (format_holder->numeric() == JSRelativeTimeFormat::Numeric::ALWAYS) {
+ formatter->formatNumeric(number, unit_enum, formatted, status);
+ } else {
+ DCHECK_EQ(JSRelativeTimeFormat::Numeric::AUTO, format_holder->numeric());
+ formatter->format(number, unit_enum, formatted, status);
+ }
+#if USE_CHROMIUM_ICU != 1 && U_ICU_VERSION_MAJOR_NUM < 63
+ }
+#endif // USE_CHROMIUM_ICU != 1 && U_ICU_VERSION_MAJOR_NUM < 63
+
+ if (U_FAILURE(status)) {
+ THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), Object);
+ }
+
+ if (to_parts) {
+ icu::UnicodeString integer;
+ icu::FieldPosition pos;
+ formatter->getNumberFormat().format(std::abs(number), integer, pos, status);
+ if (U_FAILURE(status)) {
+ THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError),
+ Object);
+ }
+
+ Handle<JSArray> elements;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, elements,
+ GenerateRelativeTimeFormatParts(isolate, formatted, integer, unit_enum),
+ Object);
+ return elements;
+ }
+
+ return factory->NewStringFromTwoByte(Vector<const uint16_t>(
+ reinterpret_cast<const uint16_t*>(formatted.getBuffer()),
+ formatted.length()));
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/objects/js-relative-time-format.h b/deps/v8/src/objects/js-relative-time-format.h
index 397c6fe287..eaaeb0e05f 100644
--- a/deps/v8/src/objects/js-relative-time-format.h
+++ b/deps/v8/src/objects/js-relative-time-format.h
@@ -12,6 +12,7 @@
#include "src/heap/factory.h"
#include "src/isolate.h"
#include "src/objects.h"
+#include "src/objects/managed.h"
#include "unicode/uversion.h"
// Has to be the last include (doesn't have include guards):
@@ -28,26 +29,30 @@ class JSRelativeTimeFormat : public JSObject {
public:
// Initializes relative time format object with properties derived from input
// locales and options.
- static MaybeHandle<JSRelativeTimeFormat> InitializeRelativeTimeFormat(
+ V8_WARN_UNUSED_RESULT static MaybeHandle<JSRelativeTimeFormat> Initialize(
Isolate* isolate,
Handle<JSRelativeTimeFormat> relative_time_format_holder,
Handle<Object> locales, Handle<Object> options);
- static Handle<JSObject> ResolvedOptions(
+ V8_WARN_UNUSED_RESULT static Handle<JSObject> ResolvedOptions(
Isolate* isolate, Handle<JSRelativeTimeFormat> format_holder);
- // Unpacks formatter object from corresponding JavaScript object.
- static icu::RelativeDateTimeFormatter* UnpackFormatter(
- Handle<JSRelativeTimeFormat> relative_time_format_holder);
Handle<String> StyleAsString() const;
Handle<String> NumericAsString() const;
+ // ecma402/#sec-Intl.RelativeTimeFormat.prototype.format
+ // ecma402/#sec-Intl.RelativeTimeFormat.prototype.formatToParts
+ V8_WARN_UNUSED_RESULT static MaybeHandle<Object> Format(
+ Isolate* isolate, Handle<Object> value_obj, Handle<Object> unit_obj,
+ Handle<JSRelativeTimeFormat> format_holder, const char* func_name,
+ bool to_parts);
+
DECL_CAST(JSRelativeTimeFormat)
// RelativeTimeFormat accessors.
DECL_ACCESSORS(locale, String)
- DECL_ACCESSORS(formatter, Foreign)
+ DECL_ACCESSORS(icu_formatter, Managed<icu::RelativeDateTimeFormatter>)
// Style: identifying the relative time format style used.
//
@@ -98,8 +103,8 @@ class JSRelativeTimeFormat : public JSObject {
// Layout description.
static const int kJSRelativeTimeFormatOffset = JSObject::kHeaderSize;
static const int kLocaleOffset = kJSRelativeTimeFormatOffset + kPointerSize;
- static const int kFormatterOffset = kLocaleOffset + kPointerSize;
- static const int kFlagsOffset = kFormatterOffset + kPointerSize;
+ static const int kICUFormatterOffset = kLocaleOffset + kPointerSize;
+ static const int kFlagsOffset = kICUFormatterOffset + kPointerSize;
static const int kSize = kFlagsOffset + kPointerSize;
private:
diff --git a/deps/v8/src/objects/js-segmenter-inl.h b/deps/v8/src/objects/js-segmenter-inl.h
new file mode 100644
index 0000000000..1aac2b1d63
--- /dev/null
+++ b/deps/v8/src/objects/js-segmenter-inl.h
@@ -0,0 +1,56 @@
+// Copyright 2018 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_INTL_SUPPORT
+#error Internationalization is expected to be enabled.
+#endif // V8_INTL_SUPPORT
+
+#ifndef V8_OBJECTS_JS_SEGMENTER_INL_H_
+#define V8_OBJECTS_JS_SEGMENTER_INL_H_
+
+#include "src/objects-inl.h"
+#include "src/objects/js-segmenter.h"
+
+// Has to be the last include (doesn't have include guards):
+#include "src/objects/object-macros.h"
+
+namespace v8 {
+namespace internal {
+
+// Base segmenter accessors.
+ACCESSORS(JSSegmenter, locale, String, kLocaleOffset)
+ACCESSORS(JSSegmenter, icu_break_iterator, Managed<icu::BreakIterator>,
+ kICUBreakIteratorOffset)
+SMI_ACCESSORS(JSSegmenter, flags, kFlagsOffset)
+
+inline void JSSegmenter::set_line_break_style(LineBreakStyle line_break_style) {
+ DCHECK_GT(LineBreakStyle::COUNT, line_break_style);
+ int hints = flags();
+ hints = LineBreakStyleBits::update(hints, line_break_style);
+ set_flags(hints);
+}
+
+inline JSSegmenter::LineBreakStyle JSSegmenter::line_break_style() const {
+ return LineBreakStyleBits::decode(flags());
+}
+
+inline void JSSegmenter::set_granularity(Granularity granularity) {
+ DCHECK_GT(Granularity::COUNT, granularity);
+ int hints = flags();
+ hints = GranularityBits::update(hints, granularity);
+ set_flags(hints);
+}
+
+inline JSSegmenter::Granularity JSSegmenter::granularity() const {
+ return GranularityBits::decode(flags());
+}
+
+CAST_ACCESSOR(JSSegmenter);
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_JS_SEGMENTER_INL_H_
diff --git a/deps/v8/src/objects/js-segmenter.cc b/deps/v8/src/objects/js-segmenter.cc
new file mode 100644
index 0000000000..62d9bd508a
--- /dev/null
+++ b/deps/v8/src/objects/js-segmenter.cc
@@ -0,0 +1,214 @@
+// Copyright 2018 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_INTL_SUPPORT
+#error Internationalization is expected to be enabled.
+#endif // V8_INTL_SUPPORT
+
+#include "src/objects/js-segmenter.h"
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "src/heap/factory.h"
+#include "src/isolate.h"
+#include "src/objects-inl.h"
+#include "src/objects/intl-objects.h"
+#include "src/objects/js-segmenter-inl.h"
+#include "src/objects/managed.h"
+#include "unicode/brkiter.h"
+
+namespace v8 {
+namespace internal {
+
+JSSegmenter::LineBreakStyle JSSegmenter::GetLineBreakStyle(const char* str) {
+ if (strcmp(str, "strict") == 0) return JSSegmenter::LineBreakStyle::STRICT;
+ if (strcmp(str, "normal") == 0) return JSSegmenter::LineBreakStyle::NORMAL;
+ if (strcmp(str, "loose") == 0) return JSSegmenter::LineBreakStyle::LOOSE;
+ UNREACHABLE();
+}
+
+JSSegmenter::Granularity JSSegmenter::GetGranularity(const char* str) {
+ if (strcmp(str, "grapheme") == 0) return JSSegmenter::Granularity::GRAPHEME;
+ if (strcmp(str, "word") == 0) return JSSegmenter::Granularity::WORD;
+ if (strcmp(str, "sentence") == 0) return JSSegmenter::Granularity::SENTENCE;
+ if (strcmp(str, "line") == 0) return JSSegmenter::Granularity::LINE;
+ UNREACHABLE();
+}
+
+MaybeHandle<JSSegmenter> JSSegmenter::Initialize(
+ Isolate* isolate, Handle<JSSegmenter> segmenter_holder,
+ Handle<Object> input_locales, Handle<Object> input_options) {
+ Factory* factory = isolate->factory();
+ segmenter_holder->set_flags(0);
+ // 3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
+ Handle<JSObject> requested_locales;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, requested_locales,
+ Intl::CanonicalizeLocaleListJS(isolate, input_locales), JSSegmenter);
+
+ // 11. If options is undefined, then
+ Handle<JSReceiver> options;
+ if (input_options->IsUndefined(isolate)) {
+ // a. Let options be ObjectCreate(null).
+ options = isolate->factory()->NewJSObjectWithNullProto();
+ // 12. Else
+ } else {
+ // a. Let options be ? ToObject(options).
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, options,
+ Object::ToObject(isolate, input_options),
+ JSSegmenter);
+ }
+
+ // 8. Set opt.[[lb]] to lineBreakStyle.
+
+ // Because currently we access localeMatcher inside ResolveLocale, we have to
+ // move ResolveLocale before get lineBreakStyle
+ // 9. Let r be ResolveLocale(%Segmenter%.[[AvailableLocales]],
+ // requestedLocales, opt, %Segmenter%.[[RelevantExtensionKeys]]).
+ Handle<JSObject> r;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, r,
+ Intl::ResolveLocale(isolate, "segmenter", requested_locales, options),
+ JSSegmenter);
+ Handle<Object> locale_obj =
+ JSObject::GetDataProperty(r, factory->locale_string());
+ Handle<String> locale;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, locale, Object::ToString(isolate, locale_obj), JSSegmenter);
+
+ // 7. Let lineBreakStyle be ? GetOption(options, "lineBreakStyle", "string", «
+ // "strict", "normal", "loose" », "normal").
+ std::unique_ptr<char[]> line_break_style_str = nullptr;
+ const std::vector<const char*> line_break_style_values = {"strict", "normal",
+ "loose"};
+ Maybe<bool> maybe_found_line_break_style = Intl::GetStringOption(
+ isolate, options, "lineBreakStyle", line_break_style_values,
+ "Intl.Segmenter", &line_break_style_str);
+ LineBreakStyle line_break_style_enum = LineBreakStyle::NORMAL;
+ MAYBE_RETURN(maybe_found_line_break_style, MaybeHandle<JSSegmenter>());
+ if (maybe_found_line_break_style.FromJust()) {
+ DCHECK_NOT_NULL(line_break_style_str.get());
+ line_break_style_enum = GetLineBreakStyle(line_break_style_str.get());
+ }
+
+ // 10. Set segmenter.[[Locale]] to the value of r.[[Locale]].
+ segmenter_holder->set_locale(*locale);
+
+ // 13. Let granularity be ? GetOption(options, "granularity", "string", «
+ // "grapheme", "word", "sentence", "line" », "grapheme").
+
+ std::unique_ptr<char[]> granularity_str = nullptr;
+ const std::vector<const char*> granularity_values = {"grapheme", "word",
+ "sentence", "line"};
+ Maybe<bool> maybe_found_granularity =
+ Intl::GetStringOption(isolate, options, "granularity", granularity_values,
+ "Intl.Segmenter", &granularity_str);
+ Granularity granularity_enum = Granularity::GRAPHEME;
+ MAYBE_RETURN(maybe_found_granularity, MaybeHandle<JSSegmenter>());
+ if (maybe_found_granularity.FromJust()) {
+ DCHECK_NOT_NULL(granularity_str.get());
+ granularity_enum = GetGranularity(granularity_str.get());
+ }
+
+ // 14. Set segmenter.[[SegmenterGranularity]] to granularity.
+ segmenter_holder->set_granularity(granularity_enum);
+
+ // 15. If granularity is "line",
+ if (granularity_enum == Granularity::LINE) {
+ // a. Set segmenter.[[SegmenterLineBreakStyle]] to r.[[lb]].
+ segmenter_holder->set_line_break_style(line_break_style_enum);
+ } else {
+ segmenter_holder->set_line_break_style(LineBreakStyle::NOTSET);
+ }
+
+ icu::Locale icu_locale = Intl::CreateICULocale(isolate, locale);
+ DCHECK(!icu_locale.isBogus());
+
+ UErrorCode status = U_ZERO_ERROR;
+ std::unique_ptr<icu::BreakIterator> icu_break_iterator;
+
+ switch (granularity_enum) {
+ case Granularity::GRAPHEME:
+ icu_break_iterator.reset(
+ icu::BreakIterator::createCharacterInstance(icu_locale, status));
+ break;
+ case Granularity::WORD:
+ icu_break_iterator.reset(
+ icu::BreakIterator::createWordInstance(icu_locale, status));
+ break;
+ case Granularity::SENTENCE:
+ icu_break_iterator.reset(
+ icu::BreakIterator::createSentenceInstance(icu_locale, status));
+ break;
+ case Granularity::LINE:
+ icu_break_iterator.reset(
+ icu::BreakIterator::createLineInstance(icu_locale, status));
+ // 15. If granularity is "line",
+ // a. Set segmenter.[[SegmenterLineBreakStyle]] to r.[[lb]].
+ // TBW
+ break;
+ case Granularity::COUNT:
+ UNREACHABLE();
+ }
+
+ CHECK(U_SUCCESS(status));
+ CHECK_NOT_NULL(icu_break_iterator.get());
+
+ Handle<Managed<icu::BreakIterator>> managed_break_iterator =
+ Managed<icu::BreakIterator>::FromUniquePtr(isolate, 0,
+ std::move(icu_break_iterator));
+
+ segmenter_holder->set_icu_break_iterator(*managed_break_iterator);
+ return segmenter_holder;
+}
+
+Handle<JSObject> JSSegmenter::ResolvedOptions(
+ Isolate* isolate, Handle<JSSegmenter> segmenter_holder) {
+ Factory* factory = isolate->factory();
+ Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
+ Handle<String> locale(segmenter_holder->locale(), isolate);
+ JSObject::AddProperty(isolate, result, factory->locale_string(), locale,
+ NONE);
+ if (segmenter_holder->line_break_style() != LineBreakStyle::NOTSET) {
+ JSObject::AddProperty(isolate, result, factory->lineBreakStyle_string(),
+ segmenter_holder->LineBreakStyleAsString(), NONE);
+ }
+ JSObject::AddProperty(isolate, result, factory->granularity_string(),
+ segmenter_holder->GranularityAsString(), NONE);
+ return result;
+}
+
+Handle<String> JSSegmenter::LineBreakStyleAsString() const {
+ switch (line_break_style()) {
+ case LineBreakStyle::STRICT:
+ return GetReadOnlyRoots().strict_string_handle();
+ case LineBreakStyle::NORMAL:
+ return GetReadOnlyRoots().normal_string_handle();
+ case LineBreakStyle::LOOSE:
+ return GetReadOnlyRoots().loose_string_handle();
+ case LineBreakStyle::COUNT:
+ case LineBreakStyle::NOTSET:
+ UNREACHABLE();
+ }
+}
+
+Handle<String> JSSegmenter::GranularityAsString() const {
+ switch (granularity()) {
+ case Granularity::GRAPHEME:
+ return GetReadOnlyRoots().grapheme_string_handle();
+ case Granularity::WORD:
+ return GetReadOnlyRoots().word_string_handle();
+ case Granularity::SENTENCE:
+ return GetReadOnlyRoots().sentence_string_handle();
+ case Granularity::LINE:
+ return GetReadOnlyRoots().line_string_handle();
+ case Granularity::COUNT:
+ UNREACHABLE();
+ }
+}
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/objects/js-segmenter.h b/deps/v8/src/objects/js-segmenter.h
new file mode 100644
index 0000000000..167d70c210
--- /dev/null
+++ b/deps/v8/src/objects/js-segmenter.h
@@ -0,0 +1,118 @@
+// Copyright 2018 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_INTL_SUPPORT
+#error Internationalization is expected to be enabled.
+#endif // V8_INTL_SUPPORT
+
+#ifndef V8_OBJECTS_JS_SEGMENTER_H_
+#define V8_OBJECTS_JS_SEGMENTER_H_
+
+#include "src/heap/factory.h"
+#include "src/isolate.h"
+#include "src/objects.h"
+#include "src/objects/managed.h"
+#include "unicode/uversion.h"
+
+// Has to be the last include (doesn't have include guards):
+#include "src/objects/object-macros.h"
+
+namespace U_ICU_NAMESPACE {
+class BreakIterator;
+}
+
+namespace v8 {
+namespace internal {
+
+class JSSegmenter : public JSObject {
+ public:
+ // Initializes segmenter object with properties derived from input
+ // locales and options.
+ V8_WARN_UNUSED_RESULT static MaybeHandle<JSSegmenter> Initialize(
+ Isolate* isolate, Handle<JSSegmenter> segmenter_holder,
+ Handle<Object> locales, Handle<Object> options);
+
+ V8_WARN_UNUSED_RESULT static Handle<JSObject> ResolvedOptions(
+ Isolate* isolate, Handle<JSSegmenter> segmenter_holder);
+
+ Handle<String> LineBreakStyleAsString() const;
+ Handle<String> GranularityAsString() const;
+
+ DECL_CAST(JSSegmenter)
+
+ // Segmenter accessors.
+ DECL_ACCESSORS(locale, String)
+
+ DECL_ACCESSORS(icu_break_iterator, Managed<icu::BreakIterator>)
+
+ // LineBreakStyle: identifying the style used for line break.
+ //
+ // ecma402 #sec-segmenter-internal-slots
+
+ enum class LineBreakStyle {
+ NOTSET, // While the granularity is not LINE
+ STRICT, // CSS level 3 line-break=strict, e.g. treat CJ as NS
+ NORMAL, // CSS level 3 line-break=normal, e.g. treat CJ as ID, break before
+ // hyphens for ja,zh
+ LOOSE, // CSS level 3 line-break=loose
+ COUNT
+ };
+ inline void set_line_break_style(LineBreakStyle line_break_style);
+ inline LineBreakStyle line_break_style() const;
+
+ // Granularity: identifying the segmenter used.
+ //
+ // ecma402 #sec-segmenter-internal-slots
+ enum class Granularity {
+ GRAPHEME, // for character-breaks
+ WORD, // for word-breaks
+ SENTENCE, // for sentence-breaks
+ LINE, // for line-breaks
+ COUNT
+ };
+ inline void set_granularity(Granularity granularity);
+ inline Granularity granularity() const;
+
+// Bit positions in |flags|.
+#define FLAGS_BIT_FIELDS(V, _) \
+ V(LineBreakStyleBits, LineBreakStyle, 3, _) \
+ V(GranularityBits, Granularity, 3, _)
+ DEFINE_BIT_FIELDS(FLAGS_BIT_FIELDS)
+#undef FLAGS_BIT_FIELDS
+
+ STATIC_ASSERT(LineBreakStyle::NOTSET <= LineBreakStyleBits::kMax);
+ STATIC_ASSERT(LineBreakStyle::STRICT <= LineBreakStyleBits::kMax);
+ STATIC_ASSERT(LineBreakStyle::NORMAL <= LineBreakStyleBits::kMax);
+ STATIC_ASSERT(LineBreakStyle::LOOSE <= LineBreakStyleBits::kMax);
+ STATIC_ASSERT(Granularity::GRAPHEME <= GranularityBits::kMax);
+ STATIC_ASSERT(Granularity::WORD <= GranularityBits::kMax);
+ STATIC_ASSERT(Granularity::SENTENCE <= GranularityBits::kMax);
+ STATIC_ASSERT(Granularity::LINE <= GranularityBits::kMax);
+
+ // [flags] Bit field containing various flags about the function.
+ DECL_INT_ACCESSORS(flags)
+
+ DECL_PRINTER(JSSegmenter)
+ DECL_VERIFIER(JSSegmenter)
+
+ // Layout description.
+ static const int kJSSegmenterOffset = JSObject::kHeaderSize;
+ static const int kLocaleOffset = kJSSegmenterOffset + kPointerSize;
+ static const int kICUBreakIteratorOffset = kLocaleOffset + kPointerSize;
+ static const int kFlagsOffset = kICUBreakIteratorOffset + kPointerSize;
+ static const int kSize = kFlagsOffset + kPointerSize;
+
+ private:
+ static LineBreakStyle GetLineBreakStyle(const char* str);
+ static Granularity GetGranularity(const char* str);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSSegmenter);
+};
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_JS_SEGMENTER_H_
diff --git a/deps/v8/src/objects/map-inl.h b/deps/v8/src/objects/map-inl.h
index 59f061dc05..0ec4113d4d 100644
--- a/deps/v8/src/objects/map-inl.h
+++ b/deps/v8/src/objects/map-inl.h
@@ -136,10 +136,10 @@ bool Map::IsUnboxedDoubleField(FieldIndex index) const {
return !layout_descriptor()->IsTagged(index.property_index());
}
-bool Map::TooManyFastProperties(StoreFromKeyed store_mode) const {
+bool Map::TooManyFastProperties(StoreOrigin store_origin) const {
if (UnusedPropertyFields() != 0) return false;
if (is_prototype_map()) return false;
- int minimum = store_mode == CERTAINLY_NOT_STORE_FROM_KEYED ? 128 : 12;
+ int minimum = store_origin == StoreOrigin::kNamed ? 128 : 12;
int limit = Max(minimum, GetInObjectProperties());
int external = NumberOfFields() - GetInObjectProperties();
return external > limit;
@@ -511,57 +511,30 @@ void Map::NotifyLeafMapLayoutChange(Isolate* isolate) {
}
}
-bool Map::IsJSObject(InstanceType type) {
- STATIC_ASSERT(LAST_TYPE == LAST_JS_OBJECT_TYPE);
- return type >= FIRST_JS_OBJECT_TYPE;
-}
-
bool Map::CanTransition() const {
// Only JSObject and subtypes have map transitions and back pointers.
- return IsJSObject(instance_type());
+ return InstanceTypeChecker::IsJSObject(instance_type());
}
+#define DEF_TESTER(Type, ...) \
+ bool Map::Is##Type##Map() const { \
+ return InstanceTypeChecker::Is##Type(instance_type()); \
+ }
+INSTANCE_TYPE_CHECKERS(DEF_TESTER)
+#undef DEF_TESTER
+
bool Map::IsBooleanMap() const {
return this == GetReadOnlyRoots().boolean_map();
}
-bool Map::IsNullMap() const { return this == GetReadOnlyRoots().null_map(); }
-
-bool Map::IsUndefinedMap() const {
- return this == GetReadOnlyRoots().undefined_map();
-}
-
bool Map::IsNullOrUndefinedMap() const {
- return IsNullMap() || IsUndefinedMap();
+ return this == GetReadOnlyRoots().null_map() ||
+ this == GetReadOnlyRoots().undefined_map();
}
bool Map::IsPrimitiveMap() const {
return instance_type() <= LAST_PRIMITIVE_TYPE;
}
-bool Map::IsJSReceiverMap() const {
- STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
- return instance_type() >= FIRST_JS_RECEIVER_TYPE;
-}
-bool Map::IsJSObjectMap() const { return IsJSObject(instance_type()); }
-bool Map::IsJSPromiseMap() const { return instance_type() == JS_PROMISE_TYPE; }
-bool Map::IsJSArrayMap() const { return instance_type() == JS_ARRAY_TYPE; }
-bool Map::IsJSFunctionMap() const {
- return instance_type() == JS_FUNCTION_TYPE;
-}
-bool Map::IsStringMap() const { return instance_type() < FIRST_NONSTRING_TYPE; }
-bool Map::IsJSProxyMap() const { return instance_type() == JS_PROXY_TYPE; }
-bool Map::IsJSGlobalProxyMap() const {
- return instance_type() == JS_GLOBAL_PROXY_TYPE;
-}
-bool Map::IsJSGlobalObjectMap() const {
- return instance_type() == JS_GLOBAL_OBJECT_TYPE;
-}
-bool Map::IsJSTypedArrayMap() const {
- return instance_type() == JS_TYPED_ARRAY_TYPE;
-}
-bool Map::IsJSDataViewMap() const {
- return instance_type() == JS_DATA_VIEW_TYPE;
-}
Object* Map::prototype() const { return READ_FIELD(this, kPrototypeOffset); }
diff --git a/deps/v8/src/objects/map.h b/deps/v8/src/objects/map.h
index 397f874610..5f6b173cd3 100644
--- a/deps/v8/src/objects/map.h
+++ b/deps/v8/src/objects/map.h
@@ -37,9 +37,10 @@ namespace internal {
V(FreeSpace) \
V(JSApiObject) \
V(JSArrayBuffer) \
- V(JSFunction) \
+ V(JSDataView) \
V(JSObject) \
V(JSObjectFast) \
+ V(JSTypedArray) \
V(JSWeakCollection) \
V(Map) \
V(NativeContext) \
@@ -403,9 +404,6 @@ class Map : public HeapObject {
inline bool has_fixed_typed_array_elements() const;
inline bool has_dictionary_elements() const;
- static bool IsValidElementsTransition(ElementsKind from_kind,
- ElementsKind to_kind);
-
// Returns true if the current map doesn't have DICTIONARY_ELEMENTS but if a
// map with DICTIONARY_ELEMENTS was found in the prototype chain.
bool DictionaryElementsInPrototypeChainOnly(Isolate* isolate);
@@ -471,8 +469,6 @@ class Map : public HeapObject {
bool InstancesNeedRewriting(Map* target, int target_number_of_fields,
int target_inobject, int target_unused,
int* old_number_of_fields) const;
- // TODO(ishell): moveit!
- static Handle<Map> GeneralizeAllFields(Isolate* isolate, Handle<Map> map);
V8_WARN_UNUSED_RESULT static Handle<FieldType> GeneralizeFieldType(
Representation rep1, Handle<FieldType> type1, Representation rep2,
Handle<FieldType> type2, Isolate* isolate);
@@ -693,13 +689,13 @@ class Map : public HeapObject {
// Maximal number of fast properties. Used to restrict the number of map
// transitions to avoid an explosion in the number of maps for objects used as
// dictionaries.
- inline bool TooManyFastProperties(StoreFromKeyed store_mode) const;
+ inline bool TooManyFastProperties(StoreOrigin store_origin) const;
static Handle<Map> TransitionToDataProperty(Isolate* isolate, Handle<Map> map,
Handle<Name> name,
Handle<Object> value,
PropertyAttributes attributes,
PropertyConstness constness,
- StoreFromKeyed store_mode);
+ StoreOrigin store_origin);
static Handle<Map> TransitionToAccessorProperty(
Isolate* isolate, Handle<Map> map, Handle<Name> name, int descriptor,
Handle<Object> getter, Handle<Object> setter,
@@ -756,27 +752,14 @@ class Map : public HeapObject {
Map* FindElementsKindTransitionedMap(Isolate* isolate,
MapHandles const& candidates);
- inline static bool IsJSObject(InstanceType type);
-
inline bool CanTransition() const;
+#define DECL_TESTER(Type, ...) inline bool Is##Type##Map() const;
+ INSTANCE_TYPE_CHECKERS(DECL_TESTER)
+#undef DECL_TESTER
inline bool IsBooleanMap() const;
- inline bool IsNullMap() const;
- inline bool IsUndefinedMap() const;
inline bool IsNullOrUndefinedMap() const;
inline bool IsPrimitiveMap() const;
- inline bool IsJSReceiverMap() const;
- inline bool IsJSObjectMap() const;
- inline bool IsJSPromiseMap() const;
- inline bool IsJSArrayMap() const;
- inline bool IsJSFunctionMap() const;
- inline bool IsStringMap() const;
- inline bool IsJSProxyMap() const;
- inline bool IsModuleMap() const;
- inline bool IsJSGlobalProxyMap() const;
- inline bool IsJSGlobalObjectMap() const;
- inline bool IsJSTypedArrayMap() const;
- inline bool IsJSDataViewMap() const;
inline bool IsSpecialReceiverMap() const;
inline bool IsCustomElementsReceiverMap() const;
@@ -945,7 +928,7 @@ class Map : public HeapObject {
void UpdateFieldType(Isolate* isolate, int descriptor_number,
Handle<Name> name, PropertyConstness new_constness,
Representation new_representation,
- MaybeObjectHandle new_wrapped_type);
+ const MaybeObjectHandle& new_wrapped_type);
// TODO(ishell): Move to MapUpdater.
void PrintReconfiguration(Isolate* isolate, FILE* file, int modify_index,
@@ -971,9 +954,6 @@ class Map : public HeapObject {
class NormalizedMapCache : public WeakFixedArray,
public NeverReadOnlySpaceObject {
public:
- using NeverReadOnlySpaceObject::GetHeap;
- using NeverReadOnlySpaceObject::GetIsolate;
-
static Handle<NormalizedMapCache> New(Isolate* isolate);
V8_WARN_UNUSED_RESULT MaybeHandle<Map> Get(Handle<Map> fast_map,
diff --git a/deps/v8/src/objects/maybe-object-inl.h b/deps/v8/src/objects/maybe-object-inl.h
index fa3cd8c14f..6d2bc6a9ab 100644
--- a/deps/v8/src/objects/maybe-object-inl.h
+++ b/deps/v8/src/objects/maybe-object-inl.h
@@ -20,29 +20,24 @@ bool MaybeObject::ToSmi(Smi** value) {
return false;
}
-Smi* MaybeObject::ToSmi() {
- DCHECK(HAS_SMI_TAG(this));
- return Smi::cast(reinterpret_cast<Object*>(this));
-}
-
-bool MaybeObject::IsStrongOrWeakHeapObject() const {
- if (IsSmi() || IsClearedWeakHeapObject()) {
+bool MaybeObject::IsStrongOrWeak() const {
+ if (IsSmi() || IsCleared()) {
return false;
}
return true;
}
-bool MaybeObject::ToStrongOrWeakHeapObject(HeapObject** result) {
- if (IsSmi() || IsClearedWeakHeapObject()) {
+bool MaybeObject::GetHeapObject(HeapObject** result) {
+ if (IsSmi() || IsCleared()) {
return false;
}
*result = GetHeapObject();
return true;
}
-bool MaybeObject::ToStrongOrWeakHeapObject(
- HeapObject** result, HeapObjectReferenceType* reference_type) {
- if (IsSmi() || IsClearedWeakHeapObject()) {
+bool MaybeObject::GetHeapObject(HeapObject** result,
+ HeapObjectReferenceType* reference_type) {
+ if (IsSmi() || IsCleared()) {
return false;
}
*reference_type = HasWeakHeapObjectTag(this)
@@ -52,11 +47,11 @@ bool MaybeObject::ToStrongOrWeakHeapObject(
return true;
}
-bool MaybeObject::IsStrongHeapObject() const {
+bool MaybeObject::IsStrong() const {
return !HasWeakHeapObjectTag(this) && !IsSmi();
}
-bool MaybeObject::ToStrongHeapObject(HeapObject** result) {
+bool MaybeObject::GetHeapObjectIfStrong(HeapObject** result) {
if (!HasWeakHeapObjectTag(this) && !IsSmi()) {
*result = reinterpret_cast<HeapObject*>(this);
return true;
@@ -64,35 +59,33 @@ bool MaybeObject::ToStrongHeapObject(HeapObject** result) {
return false;
}
-HeapObject* MaybeObject::ToStrongHeapObject() {
- DCHECK(IsStrongHeapObject());
+HeapObject* MaybeObject::GetHeapObjectAssumeStrong() {
+ DCHECK(IsStrong());
return reinterpret_cast<HeapObject*>(this);
}
-bool MaybeObject::IsWeakHeapObject() const {
- return HasWeakHeapObjectTag(this) && !IsClearedWeakHeapObject();
+bool MaybeObject::IsWeak() const {
+ return HasWeakHeapObjectTag(this) && !IsCleared();
}
-bool MaybeObject::IsWeakOrClearedHeapObject() const {
- return HasWeakHeapObjectTag(this);
-}
+bool MaybeObject::IsWeakOrCleared() const { return HasWeakHeapObjectTag(this); }
-bool MaybeObject::ToWeakHeapObject(HeapObject** result) {
- if (HasWeakHeapObjectTag(this) && !IsClearedWeakHeapObject()) {
+bool MaybeObject::GetHeapObjectIfWeak(HeapObject** result) {
+ if (IsWeak()) {
*result = GetHeapObject();
return true;
}
return false;
}
-HeapObject* MaybeObject::ToWeakHeapObject() {
- DCHECK(IsWeakHeapObject());
+HeapObject* MaybeObject::GetHeapObjectAssumeWeak() {
+ DCHECK(IsWeak());
return GetHeapObject();
}
HeapObject* MaybeObject::GetHeapObject() {
DCHECK(!IsSmi());
- DCHECK(!IsClearedWeakHeapObject());
+ DCHECK(!IsCleared());
return RemoveWeakHeapObjectMask(reinterpret_cast<HeapObjectReference*>(this));
}
@@ -103,15 +96,10 @@ Object* MaybeObject::GetHeapObjectOrSmi() {
return GetHeapObject();
}
-bool MaybeObject::IsObject() const { return IsSmi() || IsStrongHeapObject(); }
-
-Object* MaybeObject::ToObject() {
- DCHECK(!HasWeakHeapObjectTag(this));
- return reinterpret_cast<Object*>(this);
-}
+bool MaybeObject::IsObject() const { return IsSmi() || IsStrong(); }
MaybeObject* MaybeObject::MakeWeak(MaybeObject* object) {
- DCHECK(object->IsStrongOrWeakHeapObject());
+ DCHECK(object->IsStrongOrWeak());
return AddWeakHeapObjectMask(object);
}
diff --git a/deps/v8/src/objects/maybe-object.h b/deps/v8/src/objects/maybe-object.h
index 84c8538224..0d55ff859c 100644
--- a/deps/v8/src/objects/maybe-object.h
+++ b/deps/v8/src/objects/maybe-object.h
@@ -5,6 +5,7 @@
#ifndef V8_OBJECTS_MAYBE_OBJECT_H_
#define V8_OBJECTS_MAYBE_OBJECT_H_
+#include "include/v8-internal.h"
#include "include/v8.h"
#include "src/globals.h"
#include "src/objects.h"
@@ -23,30 +24,53 @@ class MaybeObject {
public:
bool IsSmi() const { return HAS_SMI_TAG(this); }
inline bool ToSmi(Smi** value);
- inline Smi* ToSmi();
- bool IsClearedWeakHeapObject() const {
+ bool IsCleared() const {
return ::v8::internal::IsClearedWeakHeapObject(this);
}
- inline bool IsStrongOrWeakHeapObject() const;
- inline bool ToStrongOrWeakHeapObject(HeapObject** result);
- inline bool ToStrongOrWeakHeapObject(HeapObject** result,
- HeapObjectReferenceType* reference_type);
- inline bool IsStrongHeapObject() const;
- inline bool ToStrongHeapObject(HeapObject** result);
- inline HeapObject* ToStrongHeapObject();
- inline bool IsWeakHeapObject() const;
- inline bool IsWeakOrClearedHeapObject() const;
- inline bool ToWeakHeapObject(HeapObject** result);
- inline HeapObject* ToWeakHeapObject();
-
- // Returns the HeapObject pointed to (either strongly or weakly).
+ inline bool IsStrongOrWeak() const;
+ inline bool IsStrong() const;
+
+ // If this MaybeObject is a strong pointer to a HeapObject, returns true and
+ // sets *result. Otherwise returns false.
+ inline bool GetHeapObjectIfStrong(HeapObject** result);
+
+ // DCHECKs that this MaybeObject is a strong pointer to a HeapObject and
+ // returns the HeapObject.
+ inline HeapObject* GetHeapObjectAssumeStrong();
+
+ inline bool IsWeak() const;
+ inline bool IsWeakOrCleared() const;
+
+ // If this MaybeObject is a weak pointer to a HeapObject, returns true and
+ // sets *result. Otherwise returns false.
+ inline bool GetHeapObjectIfWeak(HeapObject** result);
+
+ // DCHECKs that this MaybeObject is a weak pointer to a HeapObject and
+ // returns the HeapObject.
+ inline HeapObject* GetHeapObjectAssumeWeak();
+
+ // If this MaybeObject is a strong or weak pointer to a HeapObject, returns
+ // true and sets *result. Otherwise returns false.
+ inline bool GetHeapObject(HeapObject** result);
+ inline bool GetHeapObject(HeapObject** result,
+ HeapObjectReferenceType* reference_type);
+
+ // DCHECKs that this MaybeObject is a strong or a weak pointer to a HeapObject
+ // and returns the HeapObject.
inline HeapObject* GetHeapObject();
+
+ // DCHECKs that this MaybeObject is a strong or a weak pointer to a HeapObject
+ // or a SMI and returns the HeapObject or SMI.
inline Object* GetHeapObjectOrSmi();
inline bool IsObject() const;
- inline Object* ToObject();
+ template <typename T>
+ T* cast() {
+ DCHECK(!HasWeakHeapObjectTag(this));
+ return T::cast(reinterpret_cast<Object*>(this));
+ }
static MaybeObject* FromSmi(Smi* smi) {
DCHECK(HAS_SMI_TAG(smi));
diff --git a/deps/v8/src/objects/microtask-queue-inl.h b/deps/v8/src/objects/microtask-queue-inl.h
new file mode 100644
index 0000000000..8d93ee5226
--- /dev/null
+++ b/deps/v8/src/objects/microtask-queue-inl.h
@@ -0,0 +1,28 @@
+// Copyright 2018 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_MICROTASK_QUEUE_INL_H_
+#define V8_OBJECTS_MICROTASK_QUEUE_INL_H_
+
+#include "src/objects/microtask-queue.h"
+
+#include "src/objects-inl.h"
+
+// Has to be the last include (doesn't have include guards):
+#include "src/objects/object-macros.h"
+
+namespace v8 {
+namespace internal {
+
+CAST_ACCESSOR(MicrotaskQueue)
+ACCESSORS(MicrotaskQueue, queue, FixedArray, kQueueOffset)
+SMI_ACCESSORS(MicrotaskQueue, pending_microtask_count,
+ kPendingMicrotaskCountOffset)
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_MICROTASK_QUEUE_INL_H_
diff --git a/deps/v8/src/objects/microtask-queue.cc b/deps/v8/src/objects/microtask-queue.cc
new file mode 100644
index 0000000000..a8905acd36
--- /dev/null
+++ b/deps/v8/src/objects/microtask-queue.cc
@@ -0,0 +1,40 @@
+// Copyright 2018 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 "src/objects/microtask-queue.h"
+
+#include "src/objects/microtask-queue-inl.h"
+
+namespace v8 {
+namespace internal {
+
+// DCHECK requires this for taking the reference of it.
+constexpr int MicrotaskQueue::kMinimumQueueCapacity;
+
+// static
+void MicrotaskQueue::EnqueueMicrotask(Isolate* isolate,
+ Handle<MicrotaskQueue> microtask_queue,
+ Handle<Microtask> microtask) {
+ Handle<FixedArray> queue(microtask_queue->queue(), isolate);
+ int num_tasks = microtask_queue->pending_microtask_count();
+ DCHECK_LE(num_tasks, queue->length());
+ if (num_tasks == queue->length()) {
+ queue = isolate->factory()->CopyFixedArrayAndGrow(
+ queue, std::max(num_tasks, kMinimumQueueCapacity));
+ microtask_queue->set_queue(*queue);
+ }
+ DCHECK_LE(kMinimumQueueCapacity, queue->length());
+ DCHECK_LT(num_tasks, queue->length());
+ DCHECK(queue->get(num_tasks)->IsUndefined(isolate));
+ queue->set(num_tasks, *microtask);
+ microtask_queue->set_pending_microtask_count(num_tasks + 1);
+}
+
+// static
+void MicrotaskQueue::RunMicrotasks(Handle<MicrotaskQueue> microtask_queue) {
+ UNIMPLEMENTED();
+}
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/objects/microtask-queue.h b/deps/v8/src/objects/microtask-queue.h
new file mode 100644
index 0000000000..bb14cfb498
--- /dev/null
+++ b/deps/v8/src/objects/microtask-queue.h
@@ -0,0 +1,55 @@
+// Copyright 2018 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_MICROTASK_QUEUE_H_
+#define V8_OBJECTS_MICROTASK_QUEUE_H_
+
+#include "src/objects.h"
+#include "src/objects/microtask.h"
+
+// Has to be the last include (doesn't have include guards):
+#include "src/objects/object-macros.h"
+
+namespace v8 {
+namespace internal {
+
+class V8_EXPORT_PRIVATE MicrotaskQueue : public Struct {
+ public:
+ DECL_CAST(MicrotaskQueue)
+ DECL_VERIFIER(MicrotaskQueue)
+ DECL_PRINTER(MicrotaskQueue)
+
+ // A FixedArray that the queued microtasks are stored.
+ // The first |pending_microtask_count| slots contains Microtask instance
+ // for each, and followings are undefined_value if any.
+ DECL_ACCESSORS(queue, FixedArray)
+
+ // The number of microtasks queued in |queue|. This must be less or equal to
+ // the length of |queue|.
+ DECL_INT_ACCESSORS(pending_microtask_count)
+
+ // Enqueues |microtask| to |microtask_queue|.
+ static void EnqueueMicrotask(Isolate* isolate,
+ Handle<MicrotaskQueue> microtask_queue,
+ Handle<Microtask> microtask);
+
+ // Runs all enqueued microtasks.
+ static void RunMicrotasks(Handle<MicrotaskQueue> microtask_queue);
+
+ static constexpr int kMinimumQueueCapacity = 8;
+
+ static const int kQueueOffset = HeapObject::kHeaderSize;
+ static const int kPendingMicrotaskCountOffset = kQueueOffset + kPointerSize;
+ static const int kSize = kPendingMicrotaskCountOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(MicrotaskQueue);
+};
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_MICROTASK_QUEUE_H_
diff --git a/deps/v8/src/objects/module.cc b/deps/v8/src/objects/module.cc
index 02a94c446b..c4d2626e60 100644
--- a/deps/v8/src/objects/module.cc
+++ b/deps/v8/src/objects/module.cc
@@ -18,8 +18,6 @@
namespace v8 {
namespace internal {
-namespace {
-
struct ModuleHandleHash {
V8_INLINE size_t operator()(Handle<Module> module) const {
return module->hash();
@@ -82,8 +80,6 @@ class UnorderedStringMap
zone)) {}
};
-} // anonymous namespace
-
class Module::ResolveSet
: public std::unordered_map<
Handle<Module>, UnorderedStringSet*, ModuleHandleHash,
@@ -106,22 +102,18 @@ class Module::ResolveSet
Zone* zone_;
};
-namespace {
-
-int ExportIndex(int cell_index) {
+int Module::ExportIndex(int cell_index) {
DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
ModuleDescriptor::kExport);
return cell_index - 1;
}
-int ImportIndex(int cell_index) {
+int Module::ImportIndex(int cell_index) {
DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
ModuleDescriptor::kImport);
return -cell_index - 1;
}
-} // anonymous namespace
-
void Module::CreateIndirectExport(Isolate* isolate, Handle<Module> module,
Handle<String> name,
Handle<ModuleInfoEntry> entry) {
diff --git a/deps/v8/src/objects/module.h b/deps/v8/src/objects/module.h
index 4612d73c89..fd9f9ace80 100644
--- a/deps/v8/src/objects/module.h
+++ b/deps/v8/src/objects/module.h
@@ -7,6 +7,7 @@
#include "src/objects.h"
#include "src/objects/fixed-array.h"
+#include "src/objects/js-objects.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
@@ -27,9 +28,6 @@ class Zone;
// The runtime representation of an ECMAScript module.
class Module : public Struct, public NeverReadOnlySpaceObject {
public:
- using NeverReadOnlySpaceObject::GetHeap;
- using NeverReadOnlySpaceObject::GetIsolate;
-
DECL_CAST(Module)
DECL_VERIFIER(Module)
DECL_PRINTER(Module)
@@ -111,6 +109,9 @@ class Module : public Struct, public NeverReadOnlySpaceObject {
static void StoreVariable(Handle<Module> module, int cell_index,
Handle<Object> value);
+ static int ImportIndex(int cell_index);
+ static int ExportIndex(int cell_index);
+
// Get the namespace object for [module_request] of [module]. If it doesn't
// exist yet, it is created.
static Handle<JSModuleNamespace> GetModuleNamespace(Isolate* isolate,
diff --git a/deps/v8/src/objects/name-inl.h b/deps/v8/src/objects/name-inl.h
index e768a40ec2..512e47875c 100644
--- a/deps/v8/src/objects/name-inl.h
+++ b/deps/v8/src/objects/name-inl.h
@@ -19,24 +19,25 @@ CAST_ACCESSOR(Name)
CAST_ACCESSOR(Symbol)
ACCESSORS(Symbol, name, Object, kNameOffset)
-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)
+INT_ACCESSORS(Symbol, flags, kFlagsOffset)
+BIT_FIELD_ACCESSORS(Symbol, flags, is_private, Symbol::IsPrivateBit)
+BIT_FIELD_ACCESSORS(Symbol, flags, is_well_known_symbol,
+ Symbol::IsWellKnownSymbolBit)
+BIT_FIELD_ACCESSORS(Symbol, flags, is_public, Symbol::IsPublicBit)
+BIT_FIELD_ACCESSORS(Symbol, flags, is_interesting_symbol,
+ Symbol::IsInterestingSymbolBit)
bool Symbol::is_private_field() const {
- bool value = BooleanBit::get(flags(), kPrivateFieldBit);
+ bool value = Symbol::IsPrivateFieldBit::decode(flags());
DCHECK_IMPLIES(value, is_private());
return value;
}
void Symbol::set_is_private_field() {
- int old_value = flags();
// TODO(gsathya): Re-order the bits to have these next to each other
// and just do the bit shifts once.
- set_flags(BooleanBit::set(old_value, kPrivateBit, true) |
- BooleanBit::set(old_value, kPrivateFieldBit, true));
+ set_flags(Symbol::IsPrivateBit::update(flags(), true));
+ set_flags(Symbol::IsPrivateFieldBit::update(flags(), true));
}
bool Name::IsUniqueName() const {
@@ -51,13 +52,6 @@ uint32_t Name::hash_field() {
void Name::set_hash_field(uint32_t value) {
WRITE_UINT32_FIELD(this, kHashFieldOffset, value);
-#if V8_HOST_ARCH_64_BIT
-#if V8_TARGET_LITTLE_ENDIAN
- WRITE_UINT32_FIELD(this, kHashFieldSlot + kInt32Size, 0);
-#else
- WRITE_UINT32_FIELD(this, kHashFieldSlot, 0);
-#endif
-#endif
}
bool Name::Equals(Name* other) {
diff --git a/deps/v8/src/objects/name.h b/deps/v8/src/objects/name.h
index 06e08deb82..bcc1f2c27d 100644
--- a/deps/v8/src/objects/name.h
+++ b/deps/v8/src/objects/name.h
@@ -67,13 +67,8 @@ class Name : public HeapObject {
int NameShortPrint(Vector<char> str);
// Layout description.
- static const int kHashFieldSlot = HeapObject::kHeaderSize;
-#if V8_TARGET_LITTLE_ENDIAN || !V8_HOST_ARCH_64_BIT
- static const int kHashFieldOffset = kHashFieldSlot;
-#else
- static const int kHashFieldOffset = kHashFieldSlot + kInt32Size;
-#endif
- static const int kSize = kHashFieldSlot + kPointerSize;
+ static const int kHashFieldOffset = HeapObject::kHeaderSize;
+ static const int kHeaderSize = kHashFieldOffset + kInt32Size;
// Mask constant for checking if a name has a computed hash code
// and if it is a string that is an array index. The least significant bit
@@ -181,20 +176,22 @@ class Symbol : public Name {
DECL_VERIFIER(Symbol)
// Layout description.
- static const int kNameOffset = Name::kSize;
- static const int kFlagsOffset = kNameOffset + kPointerSize;
- static const int kSize = kFlagsOffset + kPointerSize;
-
- // Flags layout.
- static const int kPrivateBit = 0;
- static const int kWellKnownSymbolBit = 1;
- static const int kPublicBit = 2;
- static const int kInterestingSymbolBit = 3;
- static const int kPrivateFieldBit = 4;
-
- typedef FixedBodyDescriptor<kNameOffset, kFlagsOffset, kSize> BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
+ static const int kFlagsOffset = Name::kHeaderSize;
+ static const int kNameOffset = kFlagsOffset + kInt32Size;
+ static const int kSize = kNameOffset + kPointerSize;
+
+// Flags layout.
+#define FLAGS_BIT_FIELDS(V, _) \
+ V(IsPrivateBit, bool, 1, _) \
+ V(IsWellKnownSymbolBit, bool, 1, _) \
+ V(IsPublicBit, bool, 1, _) \
+ V(IsInterestingSymbolBit, bool, 1, _) \
+ V(IsPrivateFieldBit, bool, 1, _)
+
+ DEFINE_BIT_FIELDS(FLAGS_BIT_FIELDS)
+#undef FLAGS_BIT_FIELDS
+
+ typedef FixedBodyDescriptor<kNameOffset, kSize, kSize> BodyDescriptor;
void SymbolShortPrint(std::ostream& os);
diff --git a/deps/v8/src/objects/object-macros-undef.h b/deps/v8/src/objects/object-macros-undef.h
index 8176bb0324..a0c19cab5c 100644
--- a/deps/v8/src/objects/object-macros-undef.h
+++ b/deps/v8/src/objects/object-macros-undef.h
@@ -46,6 +46,8 @@
#undef WRITE_INTPTR_FIELD
#undef RELAXED_READ_INTPTR_FIELD
#undef RELAXED_WRITE_INTPTR_FIELD
+#undef READ_UINTPTR_FIELD
+#undef WRITE_UINTPTR_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 9ec24a62f7..c97f59f9c0 100644
--- a/deps/v8/src/objects/object-macros.h
+++ b/deps/v8/src/objects/object-macros.h
@@ -290,6 +290,12 @@
#define WRITE_INTPTR_FIELD(p, offset, value) \
(*reinterpret_cast<intptr_t*>(FIELD_ADDR(p, offset)) = value)
+#define READ_UINTPTR_FIELD(p, offset) \
+ (*reinterpret_cast<const uintptr_t*>(FIELD_ADDR(p, offset)))
+
+#define WRITE_UINTPTR_FIELD(p, offset, value) \
+ (*reinterpret_cast<uintptr_t*>(FIELD_ADDR(p, offset)) = value)
+
#define READ_UINT8_FIELD(p, offset) \
(*reinterpret_cast<const uint8_t*>(FIELD_ADDR(p, offset)))
diff --git a/deps/v8/src/objects/ordered-hash-table-inl.h b/deps/v8/src/objects/ordered-hash-table-inl.h
index 76b0692c46..76343c21ed 100644
--- a/deps/v8/src/objects/ordered-hash-table-inl.h
+++ b/deps/v8/src/objects/ordered-hash-table-inl.h
@@ -13,20 +13,20 @@
namespace v8 {
namespace internal {
-int OrderedHashSet::GetMapRootIndex() {
- return Heap::kOrderedHashSetMapRootIndex;
+RootIndex OrderedHashSet::GetMapRootIndex() {
+ return RootIndex::kOrderedHashSetMap;
}
-int OrderedHashMap::GetMapRootIndex() {
- return Heap::kOrderedHashMapMapRootIndex;
+RootIndex OrderedHashMap::GetMapRootIndex() {
+ return RootIndex::kOrderedHashMapMap;
}
-int SmallOrderedHashMap::GetMapRootIndex() {
- return Heap::kSmallOrderedHashMapMapRootIndex;
+RootIndex SmallOrderedHashMap::GetMapRootIndex() {
+ return RootIndex::kSmallOrderedHashMapMap;
}
-int SmallOrderedHashSet::GetMapRootIndex() {
- return Heap::kSmallOrderedHashSetMapRootIndex;
+RootIndex SmallOrderedHashSet::GetMapRootIndex() {
+ return RootIndex::kSmallOrderedHashSetMap;
}
inline Object* OrderedHashMap::ValueAt(int entry) {
diff --git a/deps/v8/src/objects/ordered-hash-table.cc b/deps/v8/src/objects/ordered-hash-table.cc
index fdafce56ae..171e4dfae3 100644
--- a/deps/v8/src/objects/ordered-hash-table.cc
+++ b/deps/v8/src/objects/ordered-hash-table.cc
@@ -26,7 +26,7 @@ Handle<Derived> OrderedHashTable<Derived, entrysize>::Allocate(
}
int num_buckets = capacity / kLoadFactor;
Handle<FixedArray> backing_store = isolate->factory()->NewFixedArrayWithMap(
- static_cast<Heap::RootListIndex>(Derived::GetMapRootIndex()),
+ Derived::GetMapRootIndex(),
kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure);
Handle<Derived> table = Handle<Derived>::cast(backing_store);
for (int i = 0; i < num_buckets; ++i) {
diff --git a/deps/v8/src/objects/ordered-hash-table.h b/deps/v8/src/objects/ordered-hash-table.h
index 0ee0f71c5c..6c606efc75 100644
--- a/deps/v8/src/objects/ordered-hash-table.h
+++ b/deps/v8/src/objects/ordered-hash-table.h
@@ -7,6 +7,7 @@
#include "src/globals.h"
#include "src/objects/fixed-array.h"
+#include "src/objects/js-objects.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
@@ -231,7 +232,7 @@ class OrderedHashSet : public OrderedHashTable<OrderedHashSet, 1> {
Handle<OrderedHashSet> table,
GetKeysConversion convert);
static HeapObject* GetEmpty(ReadOnlyRoots ro_roots);
- static inline int GetMapRootIndex();
+ static inline RootIndex GetMapRootIndex();
static inline bool Is(Handle<HeapObject> table);
};
@@ -249,7 +250,7 @@ class OrderedHashMap : public OrderedHashTable<OrderedHashMap, 2> {
static Object* GetHash(Isolate* isolate, Object* key);
static HeapObject* GetEmpty(ReadOnlyRoots ro_roots);
- static inline int GetMapRootIndex();
+ static inline RootIndex GetMapRootIndex();
static inline bool Is(Handle<HeapObject> table);
static const int kValueOffset = 1;
@@ -326,9 +327,6 @@ class SmallOrderedHashTable : public HeapObject {
// Iterates only fields in the DataTable.
class BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
-
// Returns total size in bytes required for a table of given
// capacity.
static int SizeFor(int capacity) {
@@ -554,7 +552,7 @@ class SmallOrderedHashSet : public SmallOrderedHashTable<SmallOrderedHashSet> {
Handle<SmallOrderedHashSet> table,
Handle<Object> key);
static inline bool Is(Handle<HeapObject> table);
- static inline int GetMapRootIndex();
+ static inline RootIndex GetMapRootIndex();
};
class SmallOrderedHashMap : public SmallOrderedHashTable<SmallOrderedHashMap> {
@@ -575,7 +573,7 @@ class SmallOrderedHashMap : public SmallOrderedHashTable<SmallOrderedHashMap> {
Handle<Object> key,
Handle<Object> value);
static inline bool Is(Handle<HeapObject> table);
- static inline int GetMapRootIndex();
+ static inline RootIndex GetMapRootIndex();
};
// TODO(gsathya): Rename this to OrderedHashTable, after we rename
diff --git a/deps/v8/src/objects/promise.h b/deps/v8/src/objects/promise.h
index 5ff5dac6f3..0f7b4f23ce 100644
--- a/deps/v8/src/objects/promise.h
+++ b/deps/v8/src/objects/promise.h
@@ -13,6 +13,8 @@
namespace v8 {
namespace internal {
+class JSPromise;
+
// Struct to hold state required for PromiseReactionJob. See the comment on the
// PromiseReaction below for details on how this is being managed to reduce the
// memory and allocation overhead. This is the base class for the concrete
diff --git a/deps/v8/src/objects/property-array-inl.h b/deps/v8/src/objects/property-array-inl.h
new file mode 100644
index 0000000000..cb157db5d6
--- /dev/null
+++ b/deps/v8/src/objects/property-array-inl.h
@@ -0,0 +1,83 @@
+// Copyright 2018 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_PROPERTY_ARRAY_INL_H_
+#define V8_OBJECTS_PROPERTY_ARRAY_INL_H_
+
+#include "src/objects/property-array.h"
+
+#include "src/heap/heap-write-barrier-inl.h"
+
+// Has to be the last include (doesn't have include guards):
+#include "src/objects/object-macros.h"
+
+namespace v8 {
+namespace internal {
+
+CAST_ACCESSOR(PropertyArray)
+
+Object* PropertyArray::get(int index) const {
+ DCHECK_GE(index, 0);
+ DCHECK_LE(index, this->length());
+ return RELAXED_READ_FIELD(this, kHeaderSize + index * kPointerSize);
+}
+
+void PropertyArray::set(int index, Object* value) {
+ DCHECK(IsPropertyArray());
+ DCHECK_GE(index, 0);
+ DCHECK_LT(index, this->length());
+ int offset = kHeaderSize + index * kPointerSize;
+ RELAXED_WRITE_FIELD(this, offset, value);
+ WRITE_BARRIER(this, offset, value);
+}
+
+void PropertyArray::set(int index, Object* value, WriteBarrierMode mode) {
+ DCHECK_GE(index, 0);
+ DCHECK_LT(index, this->length());
+ int offset = kHeaderSize + index * kPointerSize;
+ RELAXED_WRITE_FIELD(this, offset, value);
+ CONDITIONAL_WRITE_BARRIER(this, offset, value, mode);
+}
+
+Object** PropertyArray::data_start() {
+ return HeapObject::RawField(this, kHeaderSize);
+}
+
+int PropertyArray::length() const {
+ Object* value_obj = READ_FIELD(this, kLengthAndHashOffset);
+ int value = Smi::ToInt(value_obj);
+ return LengthField::decode(value);
+}
+
+void PropertyArray::initialize_length(int len) {
+ SLOW_DCHECK(len >= 0);
+ SLOW_DCHECK(len < LengthField::kMax);
+ WRITE_FIELD(this, kLengthAndHashOffset, Smi::FromInt(len));
+}
+
+int PropertyArray::synchronized_length() const {
+ Object* value_obj = ACQUIRE_READ_FIELD(this, kLengthAndHashOffset);
+ int value = Smi::ToInt(value_obj);
+ return LengthField::decode(value);
+}
+
+int PropertyArray::Hash() const {
+ Object* value_obj = READ_FIELD(this, kLengthAndHashOffset);
+ int value = Smi::ToInt(value_obj);
+ return HashField::decode(value);
+}
+
+void PropertyArray::SetHash(int hash) {
+ Object* value_obj = READ_FIELD(this, kLengthAndHashOffset);
+ int value = Smi::ToInt(value_obj);
+ value = HashField::update(value, hash);
+ WRITE_FIELD(this, kLengthAndHashOffset, Smi::FromInt(value));
+}
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_PROPERTY_ARRAY_INL_H_
diff --git a/deps/v8/src/objects/property-array.h b/deps/v8/src/objects/property-array.h
new file mode 100644
index 0000000000..70f535a8f0
--- /dev/null
+++ b/deps/v8/src/objects/property-array.h
@@ -0,0 +1,73 @@
+// Copyright 2018 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_PROPERTY_ARRAY_H_
+#define V8_OBJECTS_PROPERTY_ARRAY_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 {
+
+class PropertyArray : public HeapObject {
+ public:
+ // [length]: length of the array.
+ inline int length() const;
+
+ // Get the length using acquire loads.
+ inline int synchronized_length() const;
+
+ // This is only used on a newly allocated PropertyArray which
+ // doesn't have an existing hash.
+ inline void initialize_length(int length);
+
+ inline void SetHash(int hash);
+ inline int Hash() const;
+
+ inline Object* get(int index) const;
+
+ inline void set(int index, Object* value);
+ // Setter with explicit barrier mode.
+ inline void set(int index, Object* value, WriteBarrierMode mode);
+
+ // Gives access to raw memory which stores the array's data.
+ inline Object** data_start();
+
+ // Garbage collection support.
+ static constexpr int SizeFor(int length) {
+ return kHeaderSize + length * kPointerSize;
+ }
+
+ DECL_CAST(PropertyArray)
+ DECL_PRINTER(PropertyArray)
+ DECL_VERIFIER(PropertyArray)
+
+ // Layout description.
+ static const int kLengthAndHashOffset = HeapObject::kHeaderSize;
+ static const int kHeaderSize = kLengthAndHashOffset + kPointerSize;
+
+ // Garbage collection support.
+ typedef FlexibleBodyDescriptor<kHeaderSize> BodyDescriptor;
+
+ static const int kLengthFieldSize = 10;
+ class LengthField : public BitField<int, 0, kLengthFieldSize> {};
+ static const int kMaxLength = LengthField::kMax;
+ class HashField : public BitField<int, kLengthFieldSize,
+ kSmiValueSize - kLengthFieldSize - 1> {};
+
+ static const int kNoHashSentinel = 0;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(PropertyArray);
+};
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_PROPERTY_ARRAY_H_
diff --git a/deps/v8/src/objects/prototype-info-inl.h b/deps/v8/src/objects/prototype-info-inl.h
index 298674eb10..24e219d46c 100644
--- a/deps/v8/src/objects/prototype-info-inl.h
+++ b/deps/v8/src/objects/prototype-info-inl.h
@@ -20,7 +20,7 @@ namespace internal {
CAST_ACCESSOR(PrototypeInfo)
Map* PrototypeInfo::ObjectCreateMap() {
- return Map::cast(object_create_map()->ToWeakHeapObject());
+ return Map::cast(object_create_map()->GetHeapObjectAssumeWeak());
}
// static
@@ -31,7 +31,7 @@ void PrototypeInfo::SetObjectCreateMap(Handle<PrototypeInfo> info,
bool PrototypeInfo::HasObjectCreateMap() {
MaybeObject* cache = object_create_map();
- return cache->IsWeakHeapObject();
+ return cache->IsWeak();
}
ACCESSORS(PrototypeInfo, module_namespace, Object, kJSModuleNamespaceOffset)
@@ -51,7 +51,7 @@ void PrototypeUsers::MarkSlotEmpty(WeakArrayList* array, int index) {
}
Smi* PrototypeUsers::empty_slot_index(WeakArrayList* array) {
- return array->Get(kEmptySlotIndex)->ToSmi();
+ return array->Get(kEmptySlotIndex)->cast<Smi>();
}
void PrototypeUsers::set_empty_slot_index(WeakArrayList* array, int index) {
diff --git a/deps/v8/src/objects/scope-info.cc b/deps/v8/src/objects/scope-info.cc
index 9ec87dcb92..0fa5557e8c 100644
--- a/deps/v8/src/objects/scope-info.cc
+++ b/deps/v8/src/objects/scope-info.cc
@@ -369,7 +369,6 @@ Handle<ScopeInfo> ScopeInfo::CreateForEmptyFunction(Isolate* isolate) {
// static
Handle<ScopeInfo> ScopeInfo::CreateForBootstrapping(Isolate* isolate,
ScopeType type) {
- DCHECK(isolate->bootstrapper()->IsActive());
DCHECK(type == SCRIPT_SCOPE || type == FUNCTION_SCOPE);
const int parameter_count = 0;
diff --git a/deps/v8/src/objects/scope-info.h b/deps/v8/src/objects/scope-info.h
index ac0664f7fb..622c51210b 100644
--- a/deps/v8/src/objects/scope-info.h
+++ b/deps/v8/src/objects/scope-info.h
@@ -177,7 +177,8 @@ class ScopeInfo : public FixedArray {
MaybeHandle<ScopeInfo> outer_scope);
static Handle<ScopeInfo> CreateForWithScope(
Isolate* isolate, MaybeHandle<ScopeInfo> outer_scope);
- static Handle<ScopeInfo> CreateForEmptyFunction(Isolate* isolate);
+ V8_EXPORT_PRIVATE static Handle<ScopeInfo> CreateForEmptyFunction(
+ Isolate* isolate);
static Handle<ScopeInfo> CreateGlobalThisBinding(Isolate* isolate);
// Serializes empty scope info.
diff --git a/deps/v8/src/objects/script.h b/deps/v8/src/objects/script.h
index 3420b71754..bd789ba2ff 100644
--- a/deps/v8/src/objects/script.h
+++ b/deps/v8/src/objects/script.h
@@ -17,9 +17,6 @@ namespace internal {
// Script describes a script which has been added to the VM.
class Script : public Struct, public NeverReadOnlySpaceObject {
public:
- using NeverReadOnlySpaceObject::GetHeap;
- using NeverReadOnlySpaceObject::GetIsolate;
-
// Script types.
enum Type {
TYPE_NATIVE = 0,
diff --git a/deps/v8/src/objects/shared-function-info-inl.h b/deps/v8/src/objects/shared-function-info-inl.h
index 0b4a7effb9..cf057e9ca0 100644
--- a/deps/v8/src/objects/shared-function-info-inl.h
+++ b/deps/v8/src/objects/shared-function-info-inl.h
@@ -282,60 +282,6 @@ void SharedFunctionInfo::DontAdaptArguments() {
set_internal_formal_parameter_count(kDontAdaptArgumentsSentinel);
}
-int SharedFunctionInfo::StartPosition() const {
- Object* maybe_scope_info = name_or_scope_info();
- if (maybe_scope_info->IsScopeInfo()) {
- ScopeInfo* info = ScopeInfo::cast(maybe_scope_info);
- if (info->HasPositionInfo()) {
- return info->StartPosition();
- }
- } else if (HasUncompiledData()) {
- // Works with or without scope.
- return uncompiled_data()->start_position();
- } else if (IsApiFunction() || HasBuiltinId()) {
- DCHECK_IMPLIES(HasBuiltinId(), builtin_id() != Builtins::kCompileLazy);
- return 0;
- }
- return kNoSourcePosition;
-}
-
-int SharedFunctionInfo::EndPosition() const {
- Object* maybe_scope_info = name_or_scope_info();
- if (maybe_scope_info->IsScopeInfo()) {
- ScopeInfo* info = ScopeInfo::cast(maybe_scope_info);
- if (info->HasPositionInfo()) {
- return info->EndPosition();
- }
- } else if (HasUncompiledData()) {
- // Works with or without scope.
- return uncompiled_data()->end_position();
- } else if (IsApiFunction() || HasBuiltinId()) {
- DCHECK_IMPLIES(HasBuiltinId(), builtin_id() != Builtins::kCompileLazy);
- return 0;
- }
- return kNoSourcePosition;
-}
-
-void SharedFunctionInfo::SetPosition(int start_position, int end_position) {
- Object* maybe_scope_info = name_or_scope_info();
- if (maybe_scope_info->IsScopeInfo()) {
- ScopeInfo* info = ScopeInfo::cast(maybe_scope_info);
- if (info->HasPositionInfo()) {
- info->SetPositionInfo(start_position, end_position);
- }
- } else if (HasUncompiledData()) {
- if (HasUncompiledDataWithPreParsedScope()) {
- // Clear out preparsed scope data, since the position setter invalidates
- // any scope data.
- ClearPreParsedScopeData();
- }
- uncompiled_data()->set_start_position(start_position);
- uncompiled_data()->set_end_position(end_position);
- } else {
- UNREACHABLE();
- }
-}
-
bool SharedFunctionInfo::IsInterpreted() const { return HasBytecodeArray(); }
ScopeInfo* SharedFunctionInfo::scope_info() const {
@@ -613,21 +559,6 @@ bool SharedFunctionInfo::HasWasmExportedFunctionData() const {
return function_data()->IsWasmExportedFunctionData();
}
-int SharedFunctionInfo::FunctionLiteralId(Isolate* isolate) const {
- // Fast path for the common case when the SFI is uncompiled and so the
- // function literal id is already in the uncompiled data.
- if (HasUncompiledData()) {
- int id = uncompiled_data()->function_literal_id();
- // Make sure the id is what we should have found with the slow path.
- DCHECK_EQ(id, FindIndexInScript(isolate));
- return id;
- }
-
- // Otherwise, search for the function in the SFI's script's function list,
- // and return its index in that list.e
- return FindIndexInScript(isolate);
-}
-
Object* SharedFunctionInfo::script() const {
Object* maybe_script = script_or_debug_info();
if (maybe_script->IsDebugInfo()) {
diff --git a/deps/v8/src/objects/shared-function-info.h b/deps/v8/src/objects/shared-function-info.h
index d5f65a91d1..f43fa61b2f 100644
--- a/deps/v8/src/objects/shared-function-info.h
+++ b/deps/v8/src/objects/shared-function-info.h
@@ -7,6 +7,7 @@
#include "src/bailout-reason.h"
#include "src/objects.h"
+#include "src/objects/builtin-function-id.h"
#include "src/objects/script.h"
// Has to be the last include (doesn't have include guards):
@@ -53,8 +54,6 @@ class PreParsedScopeData : public HeapObject {
POINTER_SIZE_ALIGN(kUnalignedChildDataStartOffset);
class BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
static constexpr int SizeFor(int length) {
return kChildDataStartOffset + length * kPointerSize;
@@ -114,8 +113,6 @@ class UncompiledDataWithoutPreParsedScope : public UncompiledData {
// No extra fields compared to UncompiledData.
typedef UncompiledData::BodyDescriptor BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(UncompiledDataWithoutPreParsedScope);
@@ -150,8 +147,6 @@ class UncompiledDataWithPreParsedScope : public UncompiledData {
FixedBodyDescriptor<kStartOfPointerFieldsOffset,
kEndOfPointerFieldsOffset, kSize>>
BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(UncompiledDataWithPreParsedScope);
@@ -179,9 +174,6 @@ class InterpreterData : public Struct {
// shared by multiple instances of the function.
class SharedFunctionInfo : public HeapObject, public NeverReadOnlySpaceObject {
public:
- using NeverReadOnlySpaceObject::GetHeap;
- using NeverReadOnlySpaceObject::GetIsolate;
-
static constexpr Object* const kNoSharedNameSentinel = Smi::kZero;
// [name]: Returns shared name if it exists or an empty string otherwise.
@@ -230,14 +222,14 @@ class SharedFunctionInfo : public HeapObject, public NeverReadOnlySpaceObject {
DECL_ACCESSORS(scope_info, ScopeInfo)
// End position of this function in the script source.
- inline int EndPosition() const;
+ V8_EXPORT_PRIVATE int EndPosition() const;
// Start position of this function in the script source.
- inline int StartPosition() const;
+ V8_EXPORT_PRIVATE int StartPosition() const;
// Set the start and end position of this function in the script source.
// Updates the scope info if available.
- inline void SetPosition(int start_position, int end_position);
+ V8_EXPORT_PRIVATE void SetPosition(int start_position, int end_position);
// [outer scope info | feedback metadata] Shared storage for outer scope info
// (on uncompiled functions) and feedback metadata (on compiled functions).
@@ -358,7 +350,7 @@ class SharedFunctionInfo : public HeapObject, public NeverReadOnlySpaceObject {
inline String* inferred_name();
// Get the function literal id associated with this function, for parsing.
- inline int FunctionLiteralId(Isolate* isolate) const;
+ V8_EXPORT_PRIVATE int FunctionLiteralId(Isolate* isolate) const;
// Break infos are contained in DebugInfo, this is a convenience method
// to simplify access.
@@ -625,8 +617,6 @@ class SharedFunctionInfo : public HeapObject, public NeverReadOnlySpaceObject {
typedef FixedBodyDescriptor<kStartOfPointerFieldsOffset,
kEndOfPointerFieldsOffset, kAlignedSize>
BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
// Bit positions in |flags|.
#define FLAGS_BIT_FIELDS(V, _) \
diff --git a/deps/v8/src/objects/stack-frame-info-inl.h b/deps/v8/src/objects/stack-frame-info-inl.h
new file mode 100644
index 0000000000..8398c7cb5b
--- /dev/null
+++ b/deps/v8/src/objects/stack-frame-info-inl.h
@@ -0,0 +1,38 @@
+// Copyright 2018 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_STACK_FRAME_INFO_INL_H_
+#define V8_OBJECTS_STACK_FRAME_INFO_INL_H_
+
+#include "src/objects/stack-frame-info.h"
+
+#include "src/heap/heap-write-barrier-inl.h"
+
+// Has to be the last include (doesn't have include guards):
+#include "src/objects/object-macros.h"
+
+namespace v8 {
+namespace internal {
+
+CAST_ACCESSOR(StackFrameInfo)
+
+SMI_ACCESSORS(StackFrameInfo, line_number, kLineNumberIndex)
+SMI_ACCESSORS(StackFrameInfo, column_number, kColumnNumberIndex)
+SMI_ACCESSORS(StackFrameInfo, script_id, kScriptIdIndex)
+ACCESSORS(StackFrameInfo, script_name, Object, kScriptNameIndex)
+ACCESSORS(StackFrameInfo, script_name_or_source_url, Object,
+ kScriptNameOrSourceUrlIndex)
+ACCESSORS(StackFrameInfo, function_name, Object, kFunctionNameIndex)
+SMI_ACCESSORS(StackFrameInfo, flag, kFlagIndex)
+BOOL_ACCESSORS(StackFrameInfo, flag, is_eval, kIsEvalBit)
+BOOL_ACCESSORS(StackFrameInfo, flag, is_constructor, kIsConstructorBit)
+BOOL_ACCESSORS(StackFrameInfo, flag, is_wasm, kIsWasmBit)
+SMI_ACCESSORS(StackFrameInfo, id, kIdIndex)
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_STACK_FRAME_INFO_INL_H_
diff --git a/deps/v8/src/objects/stack-frame-info.h b/deps/v8/src/objects/stack-frame-info.h
new file mode 100644
index 0000000000..4adc37109e
--- /dev/null
+++ b/deps/v8/src/objects/stack-frame-info.h
@@ -0,0 +1,62 @@
+// Copyright 2018 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_STACK_FRAME_INFO_H_
+#define V8_OBJECTS_STACK_FRAME_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 {
+
+class StackFrameInfo : public Struct, public NeverReadOnlySpaceObject {
+ public:
+ DECL_INT_ACCESSORS(line_number)
+ DECL_INT_ACCESSORS(column_number)
+ DECL_INT_ACCESSORS(script_id)
+ DECL_ACCESSORS(script_name, Object)
+ DECL_ACCESSORS(script_name_or_source_url, Object)
+ DECL_ACCESSORS(function_name, Object)
+ DECL_BOOLEAN_ACCESSORS(is_eval)
+ DECL_BOOLEAN_ACCESSORS(is_constructor)
+ DECL_BOOLEAN_ACCESSORS(is_wasm)
+ DECL_INT_ACCESSORS(flag)
+ DECL_INT_ACCESSORS(id)
+
+ DECL_CAST(StackFrameInfo)
+
+ // Dispatched behavior.
+ DECL_PRINTER(StackFrameInfo)
+ DECL_VERIFIER(StackFrameInfo)
+
+ static const int kLineNumberIndex = Struct::kHeaderSize;
+ static const int kColumnNumberIndex = kLineNumberIndex + kPointerSize;
+ static const int kScriptIdIndex = kColumnNumberIndex + kPointerSize;
+ static const int kScriptNameIndex = kScriptIdIndex + kPointerSize;
+ static const int kScriptNameOrSourceUrlIndex =
+ kScriptNameIndex + kPointerSize;
+ static const int kFunctionNameIndex =
+ kScriptNameOrSourceUrlIndex + kPointerSize;
+ static const int kFlagIndex = kFunctionNameIndex + kPointerSize;
+ static const int kIdIndex = kFlagIndex + kPointerSize;
+ static const int kSize = kIdIndex + kPointerSize;
+
+ private:
+ // Bit position in the flag, from least significant bit position.
+ static const int kIsEvalBit = 0;
+ static const int kIsConstructorBit = 1;
+ static const int kIsWasmBit = 2;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(StackFrameInfo);
+};
+
+} // namespace internal
+} // namespace v8
+
+#include "src/objects/object-macros-undef.h"
+
+#endif // V8_OBJECTS_STACK_FRAME_INFO_H_
diff --git a/deps/v8/src/objects/string-inl.h b/deps/v8/src/objects/string-inl.h
index 39f642063e..349fa31f9d 100644
--- a/deps/v8/src/objects/string-inl.h
+++ b/deps/v8/src/objects/string-inl.h
@@ -19,8 +19,17 @@
namespace v8 {
namespace internal {
-SMI_ACCESSORS(String, length, kLengthOffset)
-SYNCHRONIZED_SMI_ACCESSORS(String, length, kLengthOffset)
+INT32_ACCESSORS(String, length, kLengthOffset)
+
+int String::synchronized_length() const {
+ return base::AsAtomic32::Acquire_Load(
+ reinterpret_cast<const int32_t*>(FIELD_ADDR(this, kLengthOffset)));
+}
+
+void String::synchronized_set_length(int value) {
+ base::AsAtomic32::Release_Store(
+ reinterpret_cast<int32_t*>(FIELD_ADDR(this, kLengthOffset)), value);
+}
CAST_ACCESSOR(ConsString)
CAST_ACCESSOR(ExternalOneByteString)
@@ -536,9 +545,9 @@ HeapObject* ThinString::unchecked_actual() const {
return reinterpret_cast<HeapObject*>(READ_FIELD(this, kActualOffset));
}
-bool ExternalString::is_short() const {
+bool ExternalString::is_uncached() const {
InstanceType type = map()->instance_type();
- return (type & kShortExternalStringMask) == kShortExternalStringTag;
+ return (type & kUncachedExternalStringMask) == kUncachedExternalStringTag;
}
Address ExternalString::resource_as_address() {
@@ -562,7 +571,7 @@ uint32_t ExternalString::resource_as_uint32() {
void ExternalString::set_uint32_as_resource(uint32_t value) {
*reinterpret_cast<uintptr_t*>(FIELD_ADDR(this, kResourceOffset)) = value;
- if (is_short()) return;
+ if (is_uncached()) return;
const char** data_field =
reinterpret_cast<const char**>(FIELD_ADDR(this, kResourceDataOffset));
*data_field = nullptr;
@@ -573,7 +582,7 @@ const ExternalOneByteString::Resource* ExternalOneByteString::resource() {
}
void ExternalOneByteString::update_data_cache() {
- if (is_short()) return;
+ if (is_uncached()) return;
const char** data_field =
reinterpret_cast<const char**>(FIELD_ADDR(this, kResourceDataOffset));
*data_field = resource()->data();
@@ -609,7 +618,7 @@ const ExternalTwoByteString::Resource* ExternalTwoByteString::resource() {
}
void ExternalTwoByteString::update_data_cache() {
- if (is_short()) return;
+ if (is_uncached()) return;
const uint16_t** data_field =
reinterpret_cast<const uint16_t**>(FIELD_ADDR(this, kResourceDataOffset));
*data_field = resource()->data();
@@ -733,8 +742,7 @@ class String::SubStringRange::iterator final {
typedef uc16* pointer;
typedef uc16& reference;
- iterator(const iterator& other)
- : content_(other.content_), offset_(other.offset_) {}
+ iterator(const iterator& other) = default;
uc16 operator*() { return content_.Get(offset_); }
bool operator==(const iterator& other) const {
diff --git a/deps/v8/src/objects/string-table.h b/deps/v8/src/objects/string-table.h
index 8003bf1aac..b26e86a381 100644
--- a/deps/v8/src/objects/string-table.h
+++ b/deps/v8/src/objects/string-table.h
@@ -42,7 +42,7 @@ class StringTableShape : public BaseShape<StringTableKey*> {
static inline Handle<Object> AsHandle(Isolate* isolate, Key key);
- static inline int GetMapRootIndex();
+ static inline RootIndex GetMapRootIndex();
static const int kPrefixSize = 0;
static const int kEntrySize = 1;
diff --git a/deps/v8/src/objects/string.h b/deps/v8/src/objects/string.h
index 4058c7cec3..206bed641c 100644
--- a/deps/v8/src/objects/string.h
+++ b/deps/v8/src/objects/string.h
@@ -31,7 +31,7 @@ enum RobustnessFlag { ROBUST_STRING_TRAVERSAL, FAST_STRING_TRAVERSAL };
// shortcutting. Keeping these restrictions in mind has proven to be error-
// prone and so we no longer put StringShapes in variables unless there is a
// concrete performance benefit at that particular point in the code.
-class StringShape BASE_EMBEDDED {
+class StringShape {
public:
inline explicit StringShape(const String* s);
inline explicit StringShape(Map* s);
@@ -264,7 +264,7 @@ class String : public Name {
virtual MaybeHandle<String> GetNamedCapture(Handle<String> name,
CaptureState* state) = 0;
- virtual ~Match() {}
+ virtual ~Match() = default;
};
// ES#sec-getsubstitution
@@ -300,11 +300,11 @@ class String : public Name {
// do any heap allocations. This is useful when printing stack traces.
std::unique_ptr<char[]> ToCString(AllowNullsFlag allow_nulls,
RobustnessFlag robustness_flag, int offset,
- int length, int* length_output = 0);
+ int length, int* length_output = nullptr);
std::unique_ptr<char[]> ToCString(
AllowNullsFlag allow_nulls = DISALLOW_NULLS,
RobustnessFlag robustness_flag = FAST_STRING_TRAVERSAL,
- int* length_output = 0);
+ int* length_output = nullptr);
bool ComputeArrayIndex(uint32_t* index);
@@ -341,8 +341,8 @@ class String : public Name {
inline bool IsFlat();
// Layout description.
- static const int kLengthOffset = Name::kSize;
- static const int kSize = kLengthOffset + kPointerSize;
+ static const int kLengthOffset = Name::kHeaderSize;
+ static const int kHeaderSize = kLengthOffset + kInt32Size;
// Max char codes.
static const int32_t kMaxOneByteCharCode = unibrow::Latin1::kMaxChar;
@@ -360,7 +360,7 @@ class String : public Name {
// See include/v8.h for the definition.
static const int kMaxLength = v8::String::kMaxLength;
- static_assert(kMaxLength <= (Smi::kMaxValue / 2 - kSize),
+ static_assert(kMaxLength <= (Smi::kMaxValue / 2 - kHeaderSize),
"Unexpected max String length");
// Max length for computing hash. For strings longer than this limit the
@@ -370,9 +370,6 @@ class String : public Name {
// Limit for truncation in short printing.
static const int kMaxShortPrintLength = 1024;
- // Support for regular expressions.
- const uc16* GetTwoByteData(unsigned start);
-
// Helper function for flattening strings.
template <typename sinkchar>
static void WriteToFlat(String* source, sinkchar* sink, int from, int to);
@@ -474,9 +471,6 @@ class SeqString : public String {
public:
DECL_CAST(SeqString)
- // Layout description.
- static const int kHeaderSize = String::kSize;
-
// Truncate the string in-place if possible and return the result.
// In case of new_length == 0, the empty string is returned without
// truncating the original string.
@@ -533,8 +527,6 @@ class SeqOneByteString : public SeqString {
STATIC_ASSERT((kMaxSize - kHeaderSize) >= String::kMaxLength);
class BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(SeqOneByteString);
@@ -559,9 +551,6 @@ class SeqTwoByteString : public SeqString {
// is deterministic.
void clear_padding();
- // For regexp code.
- const uint16_t* SeqTwoByteStringGetData(unsigned start);
-
DECL_CAST(SeqTwoByteString)
// Garbage collection support. This method is called by the
@@ -581,8 +570,6 @@ class SeqTwoByteString : public SeqString {
String::kMaxLength);
class BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(SeqTwoByteString);
@@ -620,7 +607,7 @@ class ConsString : public String {
DECL_CAST(ConsString)
// Layout description.
- static const int kFirstOffset = POINTER_SIZE_ALIGN(String::kSize);
+ static const int kFirstOffset = String::kHeaderSize;
static const int kSecondOffset = kFirstOffset + kPointerSize;
static const int kSize = kSecondOffset + kPointerSize;
@@ -629,8 +616,6 @@ class ConsString : public String {
typedef FixedBodyDescriptor<kFirstOffset, kSecondOffset + kPointerSize, kSize>
BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
DECL_VERIFIER(ConsString)
@@ -659,12 +644,10 @@ class ThinString : public String {
DECL_VERIFIER(ThinString)
// Layout description.
- static const int kActualOffset = String::kSize;
+ static const int kActualOffset = String::kHeaderSize;
static const int kSize = kActualOffset + kPointerSize;
typedef FixedBodyDescriptor<kActualOffset, kSize, kSize> BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
private:
DISALLOW_COPY_AND_ASSIGN(ThinString);
@@ -696,7 +679,7 @@ class SlicedString : public String {
DECL_CAST(SlicedString)
// Layout description.
- static const int kParentOffset = POINTER_SIZE_ALIGN(String::kSize);
+ static const int kParentOffset = String::kHeaderSize;
static const int kOffsetOffset = kParentOffset + kPointerSize;
static const int kSize = kOffsetOffset + kPointerSize;
@@ -706,8 +689,6 @@ class SlicedString : public String {
typedef FixedBodyDescriptor<kParentOffset, kOffsetOffset + kPointerSize,
kSize>
BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
DECL_VERIFIER(SlicedString)
@@ -729,13 +710,13 @@ class ExternalString : public String {
DECL_CAST(ExternalString)
// Layout description.
- static const int kResourceOffset = POINTER_SIZE_ALIGN(String::kSize);
- static const int kShortSize = kResourceOffset + kPointerSize;
+ static const int kResourceOffset = String::kHeaderSize;
+ static const int kUncachedSize = kResourceOffset + kPointerSize;
static const int kResourceDataOffset = kResourceOffset + kPointerSize;
static const int kSize = kResourceDataOffset + kPointerSize;
- // Return whether external string is short (data pointer is not cached).
- inline bool is_short() const;
+ // Return whether the external string data pointer is not cached.
+ inline bool is_uncached() const;
// Size in bytes of the external payload.
int ExternalPayloadSize() const;
@@ -782,8 +763,6 @@ class ExternalOneByteString : public ExternalString {
DECL_CAST(ExternalOneByteString)
class BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalOneByteString);
@@ -823,8 +802,6 @@ class ExternalTwoByteString : public ExternalString {
DECL_CAST(ExternalTwoByteString)
class BodyDescriptor;
- // No weak fields.
- typedef BodyDescriptor BodyDescriptorWeak;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalTwoByteString);
@@ -837,7 +814,7 @@ class FlatStringReader : public Relocatable {
public:
FlatStringReader(Isolate* isolate, Handle<String> str);
FlatStringReader(Isolate* isolate, Vector<const char> input);
- void PostGarbageCollection();
+ void PostGarbageCollection() override;
inline uc32 Get(int index);
template <typename Char>
inline Char Get(int index);
@@ -855,7 +832,7 @@ class FlatStringReader : public Relocatable {
// traversal of the entire string
class ConsStringIterator {
public:
- inline ConsStringIterator() {}
+ inline ConsStringIterator() = default;
inline explicit ConsStringIterator(ConsString* cons_string, int offset = 0) {
Reset(cons_string, offset);
}
diff --git a/deps/v8/src/objects/templates.h b/deps/v8/src/objects/templates.h
index 6a229d847b..24cbd18bd2 100644
--- a/deps/v8/src/objects/templates.h
+++ b/deps/v8/src/objects/templates.h
@@ -15,9 +15,6 @@ namespace internal {
class TemplateInfo : public Struct, public NeverReadOnlySpaceObject {
public:
- using NeverReadOnlySpaceObject::GetHeap;
- using NeverReadOnlySpaceObject::GetIsolate;
-
DECL_ACCESSORS(tag, Object)
DECL_ACCESSORS(serial_number, Object)
DECL_INT_ACCESSORS(number_of_properties)