Commit 3e010af2 authored by Caitlin Potter's avatar Caitlin Potter Committed by Commit Bot

[CloneObjectIC] clone MutableHeapNumbers only if !FLAG_unbox_double_fields

Change the macros added in bf84766a to
only do the hard work if FLAG_unbox_double_fields is unset (otherwise,
they will attempt to dereference raw float64s, which is bad!)

Also adds a write barrier in CopyPropertyArrayValues for each store if
it's possible that a MutableHeapNumber is cloned.

BUG=chromium:901301, chromium:902965, chromium:903070, v8:7611
R=cbruni@chromium.org, jkummerow@chromium.org, ishell@chromium.org

Change-Id: I224d3c4e7b0a887684bff68985b4d97021ba4cfb
Reviewed-on: https://chromium-review.googlesource.com/c/1323911
Commit-Queue: Caitlin Potter <caitp@igalia.com>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57368}
parent dbbc3886
......@@ -526,8 +526,7 @@ Node* ConstructorBuiltinsAssembler::EmitCreateShallowObjectLiteral(
Label continue_with_write_barrier(this), done_init(this);
TVARIABLE(IntPtrT, offset, IntPtrConstant(JSObject::kHeaderSize));
// Mutable heap numbers only occur on 32-bit platforms.
bool may_use_mutable_heap_numbers =
FLAG_track_double_fields && !FLAG_unbox_double_fields;
bool may_use_mutable_heap_numbers = !FLAG_unbox_double_fields;
{
Comment("Copy in-object properties fast");
Label continue_fast(this, &offset);
......
......@@ -5053,6 +5053,13 @@ void CodeStubAssembler::CopyPropertyArrayValues(Node* from_array,
Comment("[ CopyPropertyArrayValues");
bool needs_write_barrier = barrier_mode == UPDATE_WRITE_BARRIER;
if (destroy_source == DestroySource::kNo) {
// PropertyArray may contain MutableHeapNumbers, which will be cloned on the
// heap, requiring a write barrier.
needs_write_barrier = true;
}
Node* start = IntPtrOrSmiConstant(0, mode);
ElementsKind kind = PACKED_ELEMENTS;
BuildFastFixedArrayForEach(
......
......@@ -3566,7 +3566,7 @@ void AccessorAssembler::GenerateCloneObjectIC_Slow() {
void AccessorAssembler::GenerateCloneObjectIC() {
typedef CloneObjectWithVectorDescriptor Descriptor;
Node* source = Parameter(Descriptor::kSource);
TNode<HeapObject> source = CAST(Parameter(Descriptor::kSource));
Node* flags = Parameter(Descriptor::kFlags);
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
......@@ -3576,8 +3576,7 @@ void AccessorAssembler::GenerateCloneObjectIC() {
Label miss(this, Label::kDeferred), try_polymorphic(this, Label::kDeferred),
try_megamorphic(this, Label::kDeferred);
CSA_SLOW_ASSERT(this, TaggedIsNotSmi(source));
Node* source_map = LoadMap(UncheckedCast<HeapObject>(source));
TNode<Map> source_map = LoadMap(UncheckedCast<HeapObject>(source));
GotoIf(IsDeprecatedMap(source_map), &miss);
TNode<MaybeObject> feedback = TryMonomorphicCase(
slot, vector, source_map, &if_handler, &var_handler, &try_polymorphic);
......@@ -3598,7 +3597,7 @@ void AccessorAssembler::GenerateCloneObjectIC() {
// The IC fast case should only be taken if the result map a compatible
// elements kind with the source object.
TNode<FixedArrayBase> source_elements = LoadElements(source);
TNode<FixedArrayBase> source_elements = LoadElements(CAST(source));
auto flags = ExtractFixedArrayFlag::kAllFixedArraysDontCopyCOW;
var_elements = CAST(CloneFixedArray(source_elements, flags));
......@@ -3633,22 +3632,43 @@ void AccessorAssembler::GenerateCloneObjectIC() {
// Lastly, clone any in-object properties.
// Determine the inobject property capacity of both objects, and copy the
// smaller number into the resulting object.
Node* source_start = LoadMapInobjectPropertiesStartInWords(source_map);
Node* source_size = LoadMapInstanceSizeInWords(source_map);
Node* result_start = LoadMapInobjectPropertiesStartInWords(result_map);
Node* field_offset_difference =
TNode<IntPtrT> source_start =
LoadMapInobjectPropertiesStartInWords(source_map);
TNode<IntPtrT> source_size = LoadMapInstanceSizeInWords(source_map);
TNode<IntPtrT> result_start =
LoadMapInobjectPropertiesStartInWords(result_map);
TNode<IntPtrT> field_offset_difference =
TimesPointerSize(IntPtrSub(result_start, source_start));
BuildFastLoop(source_start, source_size,
[=](Node* field_index) {
Node* field_offset = TimesPointerSize(field_index);
TNode<Object> field = LoadObjectField(source, field_offset);
field = CloneIfMutablePrimitive(field);
Node* result_offset =
IntPtrAdd(field_offset, field_offset_difference);
StoreObjectFieldNoWriteBarrier(object, result_offset,
field);
},
1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
// If MutableHeapNumbers may be present in-object, allocations may occur
// within this loop, thus the write barrier is required.
//
// TODO(caitp): skip the write barrier until the first MutableHeapNumber
// field is found
const bool may_use_mutable_heap_numbers = !FLAG_unbox_double_fields;
BuildFastLoop(
source_start, source_size,
[=](Node* field_index) {
TNode<IntPtrT> field_offset =
TimesPointerSize(UncheckedCast<IntPtrT>(field_index));
if (may_use_mutable_heap_numbers) {
TNode<Object> field = LoadObjectField(source, field_offset);
field = CloneIfMutablePrimitive(field);
TNode<IntPtrT> result_offset =
IntPtrAdd(field_offset, field_offset_difference);
StoreObjectField(object, result_offset, field);
} else {
// Copy fields as raw data.
TNode<IntPtrT> field =
LoadObjectField<IntPtrT>(source, field_offset);
TNode<IntPtrT> result_offset =
IntPtrAdd(field_offset, field_offset_difference);
StoreObjectFieldNoWriteBarrier(object, result_offset, field);
}
},
1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
Return(object);
}
......
// 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.
// Previously, spreading in-object properties would always treat double fields
// as tagged, potentially dereferencing a Float64.
function inobjectDouble() {
"use strict";
this.x = -3.9;
}
const instance = new inobjectDouble();
const clone = { ...instance, };
// 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.
function clone(src) {
return { ...src };
}
function inobjectDoubles() {
"use strict";
this.p0 = -6400510997704731;
}
// Check that unboxed double is not treated as tagged
assertEquals({ p0: -6400510997704731 }, clone(new inobjectDoubles()));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment