Skip to content

Commit bf84766

Browse files
caitpCommit Bot
authored andcommitted
[CloneObjectIC] clone MutableHeapNumbers instead of referencing them
Adds a helper macro "CloneIfMutablePrimitive", which tests if the operand is a MutableHeapNumber, and if so, clones it, otherwise returning the original value. Also modifies the signature of "CopyPropertyArrayValues" to take a "DestroySource" enum, indicating whether or not the resulting object is supplanting the source object or not, and removes all default parameters from that macro (which were not used anyways). This corrects the issue reported in chromium:901301, where StaNamedOwnProperty was replacing the value of a MutableHeapNumber referenced by both the cloned object and the source object. BUG=chromium:901301, v8:7611 [email protected], [email protected] Change-Id: I43df1ddc84dfa4840e680b6affeba452ce0b6629 Reviewed-on: https://chromium-review.googlesource.com/c/1318096 Commit-Queue: Caitlin Potter <[email protected]> Reviewed-by: Jakob Kummerow <[email protected]> Reviewed-by: Camillo Bruni <[email protected]> Cr-Commit-Position: refs/heads/master@{#57304}
1 parent aacd370 commit bf84766

4 files changed

Lines changed: 82 additions & 9 deletions

File tree

src/code-stub-assembler.cc

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3085,6 +3085,24 @@ TNode<MutableHeapNumber> CodeStubAssembler::AllocateMutableHeapNumber() {
30853085
return UncheckedCast<MutableHeapNumber>(result);
30863086
}
30873087

3088+
TNode<Object> CodeStubAssembler::CloneIfMutablePrimitive(TNode<Object> object) {
3089+
TVARIABLE(Object, result, object);
3090+
Label done(this);
3091+
3092+
GotoIf(TaggedIsSmi(object), &done);
3093+
GotoIfNot(IsMutableHeapNumber(UncheckedCast<HeapObject>(object)), &done);
3094+
{
3095+
// Mutable heap number found --- allocate a clone.
3096+
TNode<Float64T> value =
3097+
LoadHeapNumberValue(UncheckedCast<HeapNumber>(object));
3098+
result = AllocateMutableHeapNumberWithValue(value);
3099+
Goto(&done);
3100+
}
3101+
3102+
BIND(&done);
3103+
return result.value();
3104+
}
3105+
30883106
TNode<MutableHeapNumber> CodeStubAssembler::AllocateMutableHeapNumberWithValue(
30893107
SloppyTNode<Float64T> value) {
30903108
TNode<MutableHeapNumber> result = AllocateMutableHeapNumber();
@@ -5027,7 +5045,8 @@ void CodeStubAssembler::CopyPropertyArrayValues(Node* from_array,
50275045
Node* to_array,
50285046
Node* property_count,
50295047
WriteBarrierMode barrier_mode,
5030-
ParameterMode mode) {
5048+
ParameterMode mode,
5049+
DestroySource destroy_source) {
50315050
CSA_SLOW_ASSERT(this, MatchesParameterMode(property_count, mode));
50325051
CSA_SLOW_ASSERT(this, Word32Or(IsPropertyArray(from_array),
50335052
IsEmptyFixedArray(from_array)));
@@ -5039,9 +5058,14 @@ void CodeStubAssembler::CopyPropertyArrayValues(Node* from_array,
50395058
ElementsKind kind = PACKED_ELEMENTS;
50405059
BuildFastFixedArrayForEach(
50415060
from_array, kind, start, property_count,
5042-
[this, to_array, needs_write_barrier](Node* array, Node* offset) {
5061+
[this, to_array, needs_write_barrier, destroy_source](Node* array,
5062+
Node* offset) {
50435063
Node* value = Load(MachineType::AnyTagged(), array, offset);
50445064

5065+
if (destroy_source == DestroySource::kNo) {
5066+
value = CloneIfMutablePrimitive(CAST(value));
5067+
}
5068+
50455069
if (needs_write_barrier) {
50465070
Store(to_array, offset, value);
50475071
} else {
@@ -5050,6 +5074,18 @@ void CodeStubAssembler::CopyPropertyArrayValues(Node* from_array,
50505074
}
50515075
},
50525076
mode);
5077+
5078+
#ifdef DEBUG
5079+
// Zap {from_array} if the copying above has made it invalid.
5080+
if (destroy_source == DestroySource::kYes) {
5081+
Label did_zap(this);
5082+
GotoIf(IsEmptyFixedArray(from_array), &did_zap);
5083+
FillPropertyArrayWithUndefined(from_array, start, property_count, mode);
5084+
5085+
Goto(&did_zap);
5086+
BIND(&did_zap);
5087+
}
5088+
#endif
50535089
Comment("] CopyPropertyArrayValues");
50545090
}
50555091

src/code-stub-assembler.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,10 +1589,19 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
15891589
Node* to_index,
15901590
ParameterMode mode = INTPTR_PARAMETERS);
15911591

1592-
void CopyPropertyArrayValues(
1593-
Node* from_array, Node* to_array, Node* length,
1594-
WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
1595-
ParameterMode mode = INTPTR_PARAMETERS);
1592+
enum class DestroySource { kNo, kYes };
1593+
1594+
// Specify DestroySource::kYes if {from_array} is being supplanted by
1595+
// {to_array}. This offers a slight performance benefit by simply copying the
1596+
// array word by word. The source may be destroyed at the end of this macro.
1597+
//
1598+
// Otherwise, specify DestroySource::kNo for operations where an Object is
1599+
// being cloned, to ensure that MutableHeapNumbers are unique between the
1600+
// source and cloned object.
1601+
void CopyPropertyArrayValues(Node* from_array, Node* to_array, Node* length,
1602+
WriteBarrierMode barrier_mode,
1603+
ParameterMode mode,
1604+
DestroySource destroy_source);
15961605

15971606
// Copies all elements from |from_array| of |length| size to
15981607
// |to_array| of the same size respecting the elements kind.
@@ -3213,6 +3222,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
32133222

32143223
TNode<JSArray> ArrayCreate(TNode<Context> context, TNode<Number> length);
32153224

3225+
// Allocate a clone of a mutable primitive, if {object} is a
3226+
// MutableHeapNumber.
3227+
TNode<Object> CloneIfMutablePrimitive(TNode<Object> object);
3228+
32163229
private:
32173230
friend class CodeStubArguments;
32183231

src/ic/accessor-assembler.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,7 +1684,8 @@ Node* AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
16841684
// |new_properties| is guaranteed to be in new space, so we can skip
16851685
// the write barrier.
16861686
CopyPropertyArrayValues(var_properties.value(), new_properties,
1687-
var_length.value(), SKIP_WRITE_BARRIER, mode);
1687+
var_length.value(), SKIP_WRITE_BARRIER, mode,
1688+
DestroySource::kYes);
16881689

16891690
// TODO(gsathya): Clean up the type conversions by creating smarter
16901691
// helpers that do the correct op based on the mode.
@@ -3620,7 +3621,7 @@ void AccessorAssembler::GenerateCloneObjectIC() {
36203621
auto mode = INTPTR_PARAMETERS;
36213622
var_properties = CAST(AllocatePropertyArray(length, mode));
36223623
CopyPropertyArrayValues(source_properties, var_properties.value(), length,
3623-
SKIP_WRITE_BARRIER, mode);
3624+
SKIP_WRITE_BARRIER, mode, DestroySource::kNo);
36243625
}
36253626

36263627
Goto(&allocate_object);
@@ -3640,7 +3641,8 @@ void AccessorAssembler::GenerateCloneObjectIC() {
36403641
BuildFastLoop(source_start, source_size,
36413642
[=](Node* field_index) {
36423643
Node* field_offset = TimesPointerSize(field_index);
3643-
Node* field = LoadObjectField(source, field_offset);
3644+
TNode<Object> field = LoadObjectField(source, field_offset);
3645+
field = CloneIfMutablePrimitive(field);
36443646
Node* result_offset =
36453647
IntPtrAdd(field_offset, field_offset_difference);
36463648
StoreObjectFieldNoWriteBarrier(object, result_offset,

test/mjsunit/es9/object-spread-ic.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,25 @@
9999
// Megamorphic
100100
assertEquals({ boop: 1 }, f({ boop: 1 }));
101101
})();
102+
103+
// There are 2 paths in CloneObjectIC's handler which need to handle double
104+
// fields specially --- in object properties, and copying the property array.
105+
function testMutableInlineProperties() {
106+
function inobject() { "use strict"; this.x = 1.1; }
107+
const src = new inobject();
108+
const x0 = src.x;
109+
const clone = { ...src, x: x0 + 1 };
110+
assertEquals(x0, src.x);
111+
assertEquals({ x: 2.1 }, clone);
112+
}
113+
testMutableInlineProperties()
114+
115+
function testMutableOutOfLineProperties() {
116+
const src = { a: 1, b: 2, c: 3 };
117+
src.x = 2.3;
118+
const x0 = src.x;
119+
const clone = { ...src, x: x0 + 1 };
120+
assertEquals(x0, src.x);
121+
assertEquals({ a: 1, b: 2, c: 3, x: 3.3 }, clone);
122+
}
123+
testMutableOutOfLineProperties();

0 commit comments

Comments
 (0)