| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent dbc696d commit 3bfba6d
7 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -11,7 +11,7 @@ | |||
| 11 | 11 | #define V8_MAJOR_VERSION 10 | |
| 12 | 12 | #define V8_MINOR_VERSION 7 | |
| 13 | 13 | #define V8_BUILD_NUMBER 193 | |
| 14 | - #define V8_PATCH_LEVEL 13 | ||
| 14 | + #define V8_PATCH_LEVEL 16 | ||
| 15 | 15 | ||
| 16 | 16 | // Use 1 for candidates and 0 otherwise. | |
| 17 | 17 | // (Boolean macro values are not supported by all preprocessors.) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -34,7 +34,8 @@ namespace compiler { | |||
| 34 | 34 | V(Protector) \ | |
| 35 | 35 | V(PrototypeProperty) \ | |
| 36 | 36 | V(StableMap) \ | |
| 37 | - V(Transition) | ||
| 37 | + V(Transition) \ | ||
| 38 | + V(ObjectSlotValue) | ||
| 38 | 39 | ||
| 39 | 40 | CompilationDependencies::CompilationDependencies(JSHeapBroker* broker, | |
| 40 | 41 | Zone* zone) | |
@@ -868,6 +869,42 @@ class ProtectorDependency final : public CompilationDependency { | |||
| 868 | 869 | const PropertyCellRef cell_; | |
| 869 | 870 | }; | |
| 870 | 871 | ||
| 872 | + // Check that an object slot will not change during compilation. | ||
| 873 | + class ObjectSlotValueDependency final : public CompilationDependency { | ||
| 874 | + public: | ||
| 875 | + explicit ObjectSlotValueDependency(const HeapObjectRef& object, int offset, | ||
| 876 | + const ObjectRef& value) | ||
| 877 | + : CompilationDependency(kObjectSlotValue), | ||
| 878 | + object_(object.object()), | ||
| 879 | + offset_(offset), | ||
| 880 | + value_(value.object()) {} | ||
| 881 | + | ||
| 882 | + bool IsValid() const override { | ||
| 883 | + PtrComprCageBase cage_base = GetPtrComprCageBase(*object_); | ||
| 884 | + Object current_value = | ||
| 885 | + offset_ == HeapObject::kMapOffset | ||
| 886 | + ? object_->map() | ||
| 887 | + : TaggedField<Object>::Relaxed_Load(cage_base, *object_, offset_); | ||
| 888 | + return *value_ == current_value; | ||
| 889 | + } | ||
| 890 | + void Install(PendingDependencies* deps) const override {} | ||
| 891 | + | ||
| 892 | + private: | ||
| 893 | + size_t Hash() const override { | ||
| 894 | + return base::hash_combine(object_.address(), offset_, value_.address()); | ||
| 895 | + } | ||
| 896 | + | ||
| 897 | + bool Equals(const CompilationDependency* that) const override { | ||
| 898 | + const ObjectSlotValueDependency* const zat = that->AsObjectSlotValue(); | ||
| 899 | + return object_->address() == zat->object_->address() && | ||
| 900 | + offset_ == zat->offset_ && value_.address() == zat->value_.address(); | ||
| 901 | + } | ||
| 902 | + | ||
| 903 | + Handle<HeapObject> object_; | ||
| 904 | + int offset_; | ||
| 905 | + Handle<Object> value_; | ||
| 906 | + }; | ||
| 907 | + | ||
| 871 | 908 | class ElementsKindDependency final : public CompilationDependency { | |
| 872 | 909 | public: | |
| 873 | 910 | ElementsKindDependency(const AllocationSiteRef& site, ElementsKind kind) | |
@@ -1120,6 +1157,12 @@ void CompilationDependencies::DependOnElementsKind( | |||
| 1120 | 1157 | } | |
| 1121 | 1158 | } | |
| 1122 | 1159 | ||
| 1160 | + void CompilationDependencies::DependOnObjectSlotValue( | ||
| 1161 | + const HeapObjectRef& object, int offset, const ObjectRef& value) { | ||
| 1162 | + RecordDependency( | ||
| 1163 | + zone_->New<ObjectSlotValueDependency>(object, offset, value)); | ||
| 1164 | + } | ||
| 1165 | + | ||
| 1123 | 1166 | void CompilationDependencies::DependOnOwnConstantElement( | |
| 1124 | 1167 | const JSObjectRef& holder, uint32_t index, const ObjectRef& element) { | |
| 1125 | 1168 | RecordDependency( | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -93,6 +93,10 @@ class V8_EXPORT_PRIVATE CompilationDependencies : public ZoneObject { | |||
| 93 | 93 | // Record the assumption that {site}'s {ElementsKind} doesn't change. | |
| 94 | 94 | void DependOnElementsKind(const AllocationSiteRef& site); | |
| 95 | 95 | ||
| 96 | + // Check that an object slot will not change during compilation. | ||
| 97 | + void DependOnObjectSlotValue(const HeapObjectRef& object, int offset, | ||
| 98 | + const ObjectRef& value); | ||
| 99 | + | ||
| 96 | 100 | void DependOnOwnConstantElement(const JSObjectRef& holder, uint32_t index, | |
| 97 | 101 | const ObjectRef& element); | |
| 98 | 102 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1673,6 +1673,10 @@ base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteral( | |||
| 1673 | 1673 | ||
| 1674 | 1674 | // Now that we hold the migration lock, get the current map. | |
| 1675 | 1675 | MapRef boilerplate_map = boilerplate.map(); | |
| 1676 | + // Protect against concurrent changes to the boilerplate object by checking | ||
| 1677 | + // for an identical value at the end of the compilation. | ||
| 1678 | + dependencies()->DependOnObjectSlotValue(boilerplate, HeapObject::kMapOffset, | ||
| 1679 | + boilerplate_map); | ||
| 1676 | 1680 | { | |
| 1677 | 1681 | base::Optional<MapRef> current_boilerplate_map = | |
| 1678 | 1682 | boilerplate.map_direct_read(); | |
@@ -1838,10 +1842,18 @@ base::Optional<Node*> JSCreateLowering::TryAllocateFastLiteralElements( | |||
| 1838 | 1842 | boilerplate.elements(kRelaxedLoad); | |
| 1839 | 1843 | if (!maybe_boilerplate_elements.has_value()) return {}; | |
| 1840 | 1844 | FixedArrayBaseRef boilerplate_elements = maybe_boilerplate_elements.value(); | |
| 1845 | + // Protect against concurrent changes to the boilerplate object by checking | ||
| 1846 | + // for an identical value at the end of the compilation. | ||
| 1847 | + dependencies()->DependOnObjectSlotValue( | ||
| 1848 | + boilerplate, JSObject::kElementsOffset, boilerplate_elements); | ||
| 1841 | 1849 | ||
| 1842 | 1850 | // Empty or copy-on-write elements just store a constant. | |
| 1843 | 1851 | int const elements_length = boilerplate_elements.length(); | |
| 1844 | 1852 | MapRef elements_map = boilerplate_elements.map(); | |
| 1853 | + // Protect against concurrent changes to the boilerplate object by checking | ||
| 1854 | + // for an identical value at the end of the compilation. | ||
| 1855 | + dependencies()->DependOnObjectSlotValue(boilerplate_elements, | ||
| 1856 | + HeapObject::kMapOffset, elements_map); | ||
| 1845 | 1857 | if (boilerplate_elements.length() == 0 || elements_map.IsFixedCowArrayMap()) { | |
| 1846 | 1858 | if (allocation == AllocationType::kOld && | |
| 1847 | 1859 | !boilerplate.IsElementsTenured(boilerplate_elements)) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2797,13 +2797,15 @@ bool PromiseHasUserDefinedRejectHandlerInternal(Isolate* isolate, | |||
| 2797 | 2797 | Handle<PromiseCapability>::cast(promise_or_capability)->promise(), | |
| 2798 | 2798 | isolate); | |
| 2799 | 2799 | } | |
| 2800 | - promise = Handle<JSPromise>::cast(promise_or_capability); | ||
| 2801 | - if (!reaction->reject_handler().IsUndefined(isolate)) { | ||
| 2802 | - Handle<JSReceiver> reject_handler( | ||
| 2803 | - JSReceiver::cast(reaction->reject_handler()), isolate); | ||
| 2804 | - if (PromiseIsRejectHandler(isolate, reject_handler)) return true; | ||
| 2800 | + if (promise_or_capability->IsJSPromise()) { | ||
| 2801 | + promise = Handle<JSPromise>::cast(promise_or_capability); | ||
| 2802 | + if (!reaction->reject_handler().IsUndefined(isolate)) { | ||
| 2803 | + Handle<JSReceiver> reject_handler( | ||
| 2804 | + JSReceiver::cast(reaction->reject_handler()), isolate); | ||
| 2805 | + if (PromiseIsRejectHandler(isolate, reject_handler)) return true; | ||
| 2806 | + } | ||
| 2807 | + if (isolate->PromiseHasUserDefinedRejectHandler(promise)) return true; | ||
| 2805 | 2808 | } | |
| 2806 | - if (isolate->PromiseHasUserDefinedRejectHandler(promise)) return true; | ||
| 2807 | 2809 | } | |
| 2808 | 2810 | current = handle(reaction->next(), isolate); | |
| 2809 | 2811 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -65,21 +65,48 @@ class ConcurrentMarkingState final | |||
| 65 | 65 | // Helper class for storing in-object slot addresses and values. | |
| 66 | 66 | class SlotSnapshot { | |
| 67 | 67 | public: | |
| 68 | - SlotSnapshot() : number_of_slots_(0) {} | ||
| 68 | + SlotSnapshot() | ||
| 69 | + : number_of_object_slots_(0), number_of_external_pointer_slots_(0) {} | ||
| 69 | 70 | SlotSnapshot(const SlotSnapshot&) = delete; | |
| 70 | 71 | SlotSnapshot& operator=(const SlotSnapshot&) = delete; | |
| 71 | - int number_of_slots() const { return number_of_slots_; } | ||
| 72 | - ObjectSlot slot(int i) const { return snapshot_[i].first; } | ||
| 73 | - Object value(int i) const { return snapshot_[i].second; } | ||
| 74 | - void clear() { number_of_slots_ = 0; } | ||
| 72 | + int number_of_object_slots() const { return number_of_object_slots_; } | ||
| 73 | + int number_of_external_pointer_slots() const { | ||
| 74 | + return number_of_external_pointer_slots_; | ||
| 75 | + } | ||
| 76 | + ObjectSlot object_slot(int i) const { return object_snapshot_[i].first; } | ||
| 77 | + Object object_value(int i) const { return object_snapshot_[i].second; } | ||
| 78 | + ExternalPointerSlot external_pointer_slot(int i) const { | ||
| 79 | + return external_pointer_snapshot_[i].first; | ||
| 80 | + } | ||
| 81 | + ExternalPointerTag external_pointer_tag(int i) const { | ||
| 82 | + return external_pointer_snapshot_[i].second; | ||
| 83 | + } | ||
| 84 | + void clear() { | ||
| 85 | + number_of_object_slots_ = 0; | ||
| 86 | + number_of_external_pointer_slots_ = 0; | ||
| 87 | + } | ||
| 75 | 88 | void add(ObjectSlot slot, Object value) { | |
| 76 | - snapshot_[number_of_slots_++] = {slot, value}; | ||
| 89 | + DCHECK_LT(number_of_object_slots_, kMaxObjectSlots); | ||
| 90 | + object_snapshot_[number_of_object_slots_++] = {slot, value}; | ||
| 91 | + } | ||
| 92 | + void add(ExternalPointerSlot slot, ExternalPointerTag tag) { | ||
| 93 | + DCHECK_LT(number_of_external_pointer_slots_, kMaxExternalPointerSlots); | ||
| 94 | + external_pointer_snapshot_[number_of_external_pointer_slots_++] = {slot, | ||
| 95 | + tag}; | ||
| 77 | 96 | } | |
| 78 | 97 | ||
| 79 | 98 | private: | |
| 80 | - static const int kMaxSnapshotSize = JSObject::kMaxInstanceSize / kTaggedSize; | ||
| 81 | - int number_of_slots_; | ||
| 82 | - std::pair<ObjectSlot, Object> snapshot_[kMaxSnapshotSize]; | ||
| 99 | + // Maximum number of pointer slots of objects we use snapshotting for. | ||
| 100 | + // ConsStrings can have 3 (Map + Left + Right) pointers. | ||
| 101 | + static constexpr int kMaxObjectSlots = 3; | ||
| 102 | + // Maximum number of external pointer slots of objects we use snapshotting | ||
| 103 | + // for. ExternalStrings can have 2 (resource + cached data) external pointers. | ||
| 104 | + static constexpr int kMaxExternalPointerSlots = 2; | ||
| 105 | + int number_of_object_slots_; | ||
| 106 | + int number_of_external_pointer_slots_; | ||
| 107 | + std::pair<ObjectSlot, Object> object_snapshot_[kMaxObjectSlots]; | ||
| 108 | + std::pair<ExternalPointerSlot, ExternalPointerTag> | ||
| 109 | + external_pointer_snapshot_[kMaxExternalPointerSlots]; | ||
| 83 | 110 | }; | |
| 84 | 111 | ||
| 85 | 112 | class ConcurrentMarkingVisitorUtility { | |
@@ -111,9 +138,9 @@ class ConcurrentMarkingVisitorUtility { | |||
| 111 | 138 | template <typename Visitor> | |
| 112 | 139 | static void VisitPointersInSnapshot(Visitor* visitor, HeapObject host, | |
| 113 | 140 | const SlotSnapshot& snapshot) { | |
| 114 | - for (int i = 0; i < snapshot.number_of_slots(); i++) { | ||
| 115 | - ObjectSlot slot = snapshot.slot(i); | ||
| 116 | - Object object = snapshot.value(i); | ||
| 141 | + for (int i = 0; i < snapshot.number_of_object_slots(); i++) { | ||
| 142 | + ObjectSlot slot = snapshot.object_slot(i); | ||
| 143 | + Object object = snapshot.object_value(i); | ||
| 117 | 144 | DCHECK(!HasWeakHeapObjectTag(object)); | |
| 118 | 145 | if (!object.IsHeapObject()) continue; | |
| 119 | 146 | HeapObject heap_object = HeapObject::cast(object); | |
@@ -126,6 +153,16 @@ class ConcurrentMarkingVisitorUtility { | |||
| 126 | 153 | } | |
| 127 | 154 | } | |
| 128 | 155 | ||
| 156 | + template <typename Visitor> | ||
| 157 | + static void VisitExternalPointersInSnapshot(Visitor* visitor, HeapObject host, | ||
| 158 | + const SlotSnapshot& snapshot) { | ||
| 159 | + for (int i = 0; i < snapshot.number_of_external_pointer_slots(); i++) { | ||
| 160 | + ExternalPointerSlot slot = snapshot.external_pointer_slot(i); | ||
| 161 | + ExternalPointerTag tag = snapshot.external_pointer_tag(i); | ||
| 162 | + visitor->VisitExternalPointer(host, slot, tag); | ||
| 163 | + } | ||
| 164 | + } | ||
| 165 | + | ||
| 129 | 166 | template <typename Visitor, typename T> | |
| 130 | 167 | static int VisitFullyWithSnapshot(Visitor* visitor, Map map, T object) { | |
| 131 | 168 | using TBodyDescriptor = typename T::BodyDescriptor; | |
@@ -136,6 +173,8 @@ class ConcurrentMarkingVisitorUtility { | |||
| 136 | 173 | if (!visitor->ShouldVisit(object)) return 0; | |
| 137 | 174 | ConcurrentMarkingVisitorUtility::VisitPointersInSnapshot(visitor, object, | |
| 138 | 175 | snapshot); | |
| 176 | + ConcurrentMarkingVisitorUtility::VisitExternalPointersInSnapshot( | ||
| 177 | + visitor, object, snapshot); | ||
| 139 | 178 | return size; | |
| 140 | 179 | } | |
| 141 | 180 | ||
@@ -182,6 +221,11 @@ class ConcurrentMarkingVisitorUtility { | |||
| 182 | 221 | UNREACHABLE(); | |
| 183 | 222 | } | |
| 184 | 223 | ||
| 224 | + void VisitExternalPointer(HeapObject host, ExternalPointerSlot slot, | ||
| 225 | + ExternalPointerTag tag) override { | ||
| 226 | + slot_snapshot_->add(slot, tag); | ||
| 227 | + } | ||
| 228 | + | ||
| 185 | 229 | void VisitCodeTarget(Code host, RelocInfo* rinfo) final { | |
| 186 | 230 | // This should never happen, because snapshotting is performed only on | |
| 187 | 231 | // some String subclasses. | |
@@ -450,6 +494,16 @@ class ConcurrentMarkingVisitor final | |||
| 450 | 494 | return SeqTwoByteString::SizeFor(object.length(kAcquireLoad)); | |
| 451 | 495 | } | |
| 452 | 496 | ||
| 497 | + int VisitExternalOneByteString(Map map, ExternalOneByteString object) { | ||
| 498 | + return ConcurrentMarkingVisitorUtility::VisitFullyWithSnapshot(this, map, | ||
| 499 | + object); | ||
| 500 | + } | ||
| 501 | + | ||
| 502 | + int VisitExternalTwoByteString(Map map, ExternalTwoByteString object) { | ||
| 503 | + return ConcurrentMarkingVisitorUtility::VisitFullyWithSnapshot(this, map, | ||
| 504 | + object); | ||
| 505 | + } | ||
| 506 | + | ||
| 453 | 507 | // Implements ephemeron semantics: Marks value if key is already reachable. | |
| 454 | 508 | // Returns true if value was actually marked. | |
| 455 | 509 | bool ProcessEphemeron(HeapObject key, HeapObject value) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -223,6 +223,14 @@ void String::MakeThin(IsolateT* isolate, String internalized) { | |||
| 223 | 223 | Map target_map = ComputeThinStringMap(isolate, initial_shape, | |
| 224 | 224 | internalized.IsOneByteRepresentation()); | |
| 225 | 225 | if (initial_shape.IsExternal()) { | |
| 226 | + // Notify GC about the layout change before the transition to avoid | ||
| 227 | + // concurrent marking from observing any in-between state (e.g. | ||
| 228 | + // ExternalString map where the resource external pointer is overwritten | ||
| 229 | + // with a tagged pointer). | ||
| 230 | + // ExternalString -> ThinString transitions can only happen on the | ||
| 231 | + // main-thread. | ||
| 232 | + isolate->AsIsolate()->heap()->NotifyObjectLayoutChange( | ||
| 233 | + *this, no_gc, InvalidateRecordedSlots::kYes, ThinString::kSize); | ||
| 226 | 234 | MigrateExternalString(isolate->AsIsolate(), *this, internalized); | |
| 227 | 235 | } | |
| 228 | 236 | ||
@@ -231,7 +239,11 @@ void String::MakeThin(IsolateT* isolate, String internalized) { | |||
| 231 | 239 | // ThinString. | |
| 232 | 240 | ThinString thin = ThinString::unchecked_cast(*this); | |
| 233 | 241 | thin.set_actual(internalized); | |
| 234 | - set_map_safe_transition(target_map, kReleaseStore); | ||
| 242 | + if (initial_shape.IsExternal()) { | ||
| 243 | + set_map(target_map, kReleaseStore); | ||
| 244 | + } else { | ||
| 245 | + set_map_safe_transition(target_map, kReleaseStore); | ||
| 246 | + } | ||
| 235 | 247 | ||
| 236 | 248 | DCHECK_GE(old_size, ThinString::kSize); | |
| 237 | 249 | int size_delta = old_size - ThinString::kSize; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments