[deoptimizer] Preserve double bit patterns correctly.
This makes sure that the deoptimizer preserves the exact bit pattern of floating-point values (both 32-bit and 64-bit) up to the point where a potential {HeapNumber} is allocated. It in turn allows us to correctly recognize the {hole_nan_value} when stored into a {FixedDouleArray}. R=jarin@chromium.org TEST=mjsunit/regress/regress-crbug-684208 BUG=chromium:684208 Review-Url: https://codereview.chromium.org/2652303002 Cr-Commit-Position: refs/heads/master@{#42679}
This commit is contained in:
parent
f6d0dc6d88
commit
7376e12e00
@ -95,7 +95,7 @@ void Deoptimizer::SetPlatformCompiledStubRegisters(
|
||||
|
||||
void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
|
||||
for (int i = 0; i < DwVfpRegister::kMaxNumRegisters; ++i) {
|
||||
double double_value = input_->GetDoubleRegister(i);
|
||||
Float64 double_value = input_->GetDoubleRegister(i);
|
||||
output_frame->SetDoubleRegister(i, double_value);
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ void Deoptimizer::SetPlatformCompiledStubRegisters(
|
||||
|
||||
void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
|
||||
for (int i = 0; i < DoubleRegister::kMaxNumRegisters; ++i) {
|
||||
double double_value = input_->GetDoubleRegister(i);
|
||||
Float64 double_value = input_->GetDoubleRegister(i);
|
||||
output_frame->SetDoubleRegister(i, double_value);
|
||||
}
|
||||
}
|
||||
|
@ -2793,7 +2793,7 @@ TranslatedValue TranslatedValue::NewDuplicateObject(TranslatedState* container,
|
||||
|
||||
// static
|
||||
TranslatedValue TranslatedValue::NewFloat(TranslatedState* container,
|
||||
float value) {
|
||||
Float32 value) {
|
||||
TranslatedValue slot(container, kFloat);
|
||||
slot.float_value_ = value;
|
||||
return slot;
|
||||
@ -2801,7 +2801,7 @@ TranslatedValue TranslatedValue::NewFloat(TranslatedState* container,
|
||||
|
||||
// static
|
||||
TranslatedValue TranslatedValue::NewDouble(TranslatedState* container,
|
||||
double value) {
|
||||
Float64 value) {
|
||||
TranslatedValue slot(container, kDouble);
|
||||
slot.double_value_ = value;
|
||||
return slot;
|
||||
@ -2870,12 +2870,12 @@ uint32_t TranslatedValue::uint32_value() const {
|
||||
return uint32_value_;
|
||||
}
|
||||
|
||||
float TranslatedValue::float_value() const {
|
||||
Float32 TranslatedValue::float_value() const {
|
||||
DCHECK_EQ(kFloat, kind());
|
||||
return float_value_;
|
||||
}
|
||||
|
||||
double TranslatedValue::double_value() const {
|
||||
Float64 TranslatedValue::double_value() const {
|
||||
DCHECK_EQ(kDouble, kind());
|
||||
return double_value_;
|
||||
}
|
||||
@ -2985,22 +2985,29 @@ void TranslatedValue::MaterializeSimple() {
|
||||
}
|
||||
|
||||
switch (kind()) {
|
||||
case kInt32: {
|
||||
case kInt32:
|
||||
value_ = Handle<Object>(isolate()->factory()->NewNumber(int32_value()));
|
||||
return;
|
||||
}
|
||||
|
||||
case kUInt32:
|
||||
value_ = Handle<Object>(isolate()->factory()->NewNumber(uint32_value()));
|
||||
return;
|
||||
|
||||
case kFloat:
|
||||
value_ = Handle<Object>(isolate()->factory()->NewNumber(float_value()));
|
||||
case kFloat: {
|
||||
double scalar_value = float_value().get_scalar();
|
||||
value_ = Handle<Object>(isolate()->factory()->NewNumber(scalar_value));
|
||||
return;
|
||||
}
|
||||
|
||||
case kDouble:
|
||||
value_ = Handle<Object>(isolate()->factory()->NewNumber(double_value()));
|
||||
case kDouble: {
|
||||
if (double_value().is_hole_nan()) {
|
||||
value_ = isolate()->factory()->hole_nan_value();
|
||||
return;
|
||||
}
|
||||
double scalar_value = double_value().get_scalar();
|
||||
value_ = Handle<Object>(isolate()->factory()->NewNumber(scalar_value));
|
||||
return;
|
||||
}
|
||||
|
||||
case kCapturedObject:
|
||||
case kDuplicatedObject:
|
||||
@ -3048,6 +3055,13 @@ uint32_t TranslatedState::GetUInt32Slot(Address fp, int slot_offset) {
|
||||
#endif
|
||||
}
|
||||
|
||||
Float32 TranslatedState::GetFloatSlot(Address fp, int slot_offset) {
|
||||
return Float32::FromBits(GetUInt32Slot(fp, slot_offset));
|
||||
}
|
||||
|
||||
Float64 TranslatedState::GetDoubleSlot(Address fp, int slot_offset) {
|
||||
return Float64::FromBits(Memory::uint64_at(fp + slot_offset));
|
||||
}
|
||||
|
||||
void TranslatedValue::Handlify() {
|
||||
if (kind() == kTagged) {
|
||||
@ -3403,9 +3417,9 @@ TranslatedValue TranslatedState::CreateNextTranslatedValue(
|
||||
case Translation::FLOAT_REGISTER: {
|
||||
int input_reg = iterator->Next();
|
||||
if (registers == nullptr) return TranslatedValue::NewInvalid(this);
|
||||
float value = registers->GetFloatRegister(input_reg);
|
||||
Float32 value = registers->GetFloatRegister(input_reg);
|
||||
if (trace_file != nullptr) {
|
||||
PrintF(trace_file, "%e ; %s (float)", value,
|
||||
PrintF(trace_file, "%e ; %s (float)", value.get_scalar(),
|
||||
RegisterConfiguration::Crankshaft()->GetFloatRegisterName(
|
||||
input_reg));
|
||||
}
|
||||
@ -3415,9 +3429,9 @@ TranslatedValue TranslatedState::CreateNextTranslatedValue(
|
||||
case Translation::DOUBLE_REGISTER: {
|
||||
int input_reg = iterator->Next();
|
||||
if (registers == nullptr) return TranslatedValue::NewInvalid(this);
|
||||
double value = registers->GetDoubleRegister(input_reg);
|
||||
Float64 value = registers->GetDoubleRegister(input_reg);
|
||||
if (trace_file != nullptr) {
|
||||
PrintF(trace_file, "%e ; %s (double)", value,
|
||||
PrintF(trace_file, "%e ; %s (double)", value.get_scalar(),
|
||||
RegisterConfiguration::Crankshaft()->GetDoubleRegisterName(
|
||||
input_reg));
|
||||
}
|
||||
@ -3473,9 +3487,9 @@ TranslatedValue TranslatedState::CreateNextTranslatedValue(
|
||||
case Translation::FLOAT_STACK_SLOT: {
|
||||
int slot_offset =
|
||||
OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
|
||||
float value = ReadFloatValue(fp + slot_offset);
|
||||
Float32 value = GetFloatSlot(fp, slot_offset);
|
||||
if (trace_file != nullptr) {
|
||||
PrintF(trace_file, "%e ; (float) [fp %c %d] ", value,
|
||||
PrintF(trace_file, "%e ; (float) [fp %c %d] ", value.get_scalar(),
|
||||
slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
|
||||
}
|
||||
return TranslatedValue::NewFloat(this, value);
|
||||
@ -3484,9 +3498,9 @@ TranslatedValue TranslatedState::CreateNextTranslatedValue(
|
||||
case Translation::DOUBLE_STACK_SLOT: {
|
||||
int slot_offset =
|
||||
OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
|
||||
double value = ReadDoubleValue(fp + slot_offset);
|
||||
Float64 value = GetDoubleSlot(fp, slot_offset);
|
||||
if (trace_file != nullptr) {
|
||||
PrintF(trace_file, "%e ; (double) [fp %c %d] ", value,
|
||||
PrintF(trace_file, "%e ; (double) [fp %c %d] ", value.get_scalar(),
|
||||
slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
|
||||
}
|
||||
return TranslatedValue::NewDouble(this, value);
|
||||
@ -3857,7 +3871,11 @@ Handle<Object> TranslatedState::MaterializeCapturedObjectAt(
|
||||
for (int i = 0; i < length; ++i) {
|
||||
Handle<Object> value = materializer.FieldAt(value_index);
|
||||
CHECK(value->IsNumber());
|
||||
double_array->set(i, value->Number());
|
||||
if (value.is_identical_to(isolate_->factory()->hole_nan_value())) {
|
||||
double_array->set_the_hole(isolate_, i);
|
||||
} else {
|
||||
double_array->set(i, value->Number());
|
||||
}
|
||||
}
|
||||
}
|
||||
return object;
|
||||
|
@ -20,6 +20,37 @@ class DeoptimizedFrameInfo;
|
||||
class TranslatedState;
|
||||
class RegisterValues;
|
||||
|
||||
// Safety wrapper for a 32-bit floating-point value to make sure we don't loose
|
||||
// the exact bit pattern during deoptimization when passing this value. Note
|
||||
// that there is intentionally no way to construct it from a {float} value.
|
||||
class Float32 {
|
||||
public:
|
||||
Float32() : bit_pattern_(0) {}
|
||||
uint32_t get_bits() const { return bit_pattern_; }
|
||||
float get_scalar() const { return bit_cast<float>(bit_pattern_); }
|
||||
static Float32 FromBits(uint32_t bits) { return Float32(bits); }
|
||||
|
||||
private:
|
||||
explicit Float32(uint32_t bit_pattern) : bit_pattern_(bit_pattern) {}
|
||||
uint32_t bit_pattern_;
|
||||
};
|
||||
|
||||
// Safety wrapper for a 64-bit floating-point value to make sure we don't loose
|
||||
// the exact bit pattern during deoptimization when passing this value. Note
|
||||
// that there is intentionally no way to construct it from a {double} value.
|
||||
class Float64 {
|
||||
public:
|
||||
Float64() : bit_pattern_(0) {}
|
||||
uint64_t get_bits() const { return bit_pattern_; }
|
||||
double get_scalar() const { return bit_cast<double>(bit_pattern_); }
|
||||
bool is_hole_nan() const { return bit_pattern_ == kHoleNanInt64; }
|
||||
static Float64 FromBits(uint64_t bits) { return Float64(bits); }
|
||||
|
||||
private:
|
||||
explicit Float64(uint64_t bit_pattern) : bit_pattern_(bit_pattern) {}
|
||||
uint64_t bit_pattern_;
|
||||
};
|
||||
|
||||
class TranslatedValue {
|
||||
public:
|
||||
// Allocation-less getter of the value.
|
||||
@ -64,8 +95,8 @@ class TranslatedValue {
|
||||
static TranslatedValue NewDeferredObject(TranslatedState* container,
|
||||
int length, int object_index);
|
||||
static TranslatedValue NewDuplicateObject(TranslatedState* container, int id);
|
||||
static TranslatedValue NewFloat(TranslatedState* container, float value);
|
||||
static TranslatedValue NewDouble(TranslatedState* container, double value);
|
||||
static TranslatedValue NewFloat(TranslatedState* container, Float32 value);
|
||||
static TranslatedValue NewDouble(TranslatedState* container, Float64 value);
|
||||
static TranslatedValue NewInt32(TranslatedState* container, int32_t value);
|
||||
static TranslatedValue NewUInt32(TranslatedState* container, uint32_t value);
|
||||
static TranslatedValue NewBool(TranslatedState* container, uint32_t value);
|
||||
@ -98,9 +129,9 @@ class TranslatedValue {
|
||||
// kind is kInt32.
|
||||
int32_t int32_value_;
|
||||
// kind is kFloat
|
||||
float float_value_;
|
||||
Float32 float_value_;
|
||||
// kind is kDouble
|
||||
double double_value_;
|
||||
Float64 double_value_;
|
||||
// kind is kDuplicatedObject or kArgumentsObject or kCapturedObject.
|
||||
MaterializedObjectInfo materialization_info_;
|
||||
};
|
||||
@ -109,8 +140,8 @@ class TranslatedValue {
|
||||
Object* raw_literal() const;
|
||||
int32_t int32_value() const;
|
||||
uint32_t uint32_value() const;
|
||||
float float_value() const;
|
||||
double double_value() const;
|
||||
Float32 float_value() const;
|
||||
Float64 double_value() const;
|
||||
int object_length() const;
|
||||
int object_index() const;
|
||||
};
|
||||
@ -298,6 +329,8 @@ class TranslatedState {
|
||||
bool GetAdaptedArguments(Handle<JSObject>* result, int frame_index);
|
||||
|
||||
static uint32_t GetUInt32Slot(Address fp, int slot_index);
|
||||
static Float32 GetFloatSlot(Address fp, int slot_index);
|
||||
static Float64 GetDoubleSlot(Address fp, int slot_index);
|
||||
|
||||
std::vector<TranslatedFrame> frames_;
|
||||
Isolate* isolate_;
|
||||
@ -652,12 +685,12 @@ class RegisterValues {
|
||||
return registers_[n];
|
||||
}
|
||||
|
||||
float GetFloatRegister(unsigned n) const {
|
||||
Float32 GetFloatRegister(unsigned n) const {
|
||||
DCHECK(n < arraysize(float_registers_));
|
||||
return float_registers_[n];
|
||||
}
|
||||
|
||||
double GetDoubleRegister(unsigned n) const {
|
||||
Float64 GetDoubleRegister(unsigned n) const {
|
||||
DCHECK(n < arraysize(double_registers_));
|
||||
return double_registers_[n];
|
||||
}
|
||||
@ -667,19 +700,24 @@ class RegisterValues {
|
||||
registers_[n] = value;
|
||||
}
|
||||
|
||||
void SetFloatRegister(unsigned n, float value) {
|
||||
void SetFloatRegister(unsigned n, Float32 value) {
|
||||
DCHECK(n < arraysize(float_registers_));
|
||||
float_registers_[n] = value;
|
||||
}
|
||||
|
||||
void SetDoubleRegister(unsigned n, double value) {
|
||||
void SetDoubleRegister(unsigned n, Float64 value) {
|
||||
DCHECK(n < arraysize(double_registers_));
|
||||
double_registers_[n] = value;
|
||||
}
|
||||
|
||||
// Generated code is writing directly into the below arrays, make sure their
|
||||
// element sizes fit what the machine instructions expect.
|
||||
static_assert(sizeof(Float32) == kFloatSize, "size mismatch");
|
||||
static_assert(sizeof(Float64) == kDoubleSize, "size mismatch");
|
||||
|
||||
intptr_t registers_[Register::kNumRegisters];
|
||||
float float_registers_[FloatRegister::kMaxNumRegisters];
|
||||
double double_registers_[DoubleRegister::kMaxNumRegisters];
|
||||
Float32 float_registers_[FloatRegister::kMaxNumRegisters];
|
||||
Float64 double_registers_[DoubleRegister::kMaxNumRegisters];
|
||||
};
|
||||
|
||||
|
||||
@ -732,7 +770,7 @@ class FrameDescription {
|
||||
return register_values_.GetRegister(n);
|
||||
}
|
||||
|
||||
double GetDoubleRegister(unsigned n) const {
|
||||
Float64 GetDoubleRegister(unsigned n) const {
|
||||
return register_values_.GetDoubleRegister(n);
|
||||
}
|
||||
|
||||
@ -740,7 +778,7 @@ class FrameDescription {
|
||||
register_values_.SetRegister(n, value);
|
||||
}
|
||||
|
||||
void SetDoubleRegister(unsigned n, double value) {
|
||||
void SetDoubleRegister(unsigned n, Float64 value) {
|
||||
register_values_.SetDoubleRegister(n, value);
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ void Deoptimizer::SetPlatformCompiledStubRegisters(
|
||||
|
||||
void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; ++i) {
|
||||
double double_value = input_->GetDoubleRegister(i);
|
||||
Float64 double_value = input_->GetDoubleRegister(i);
|
||||
output_frame->SetDoubleRegister(i, double_value);
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ void Deoptimizer::SetPlatformCompiledStubRegisters(
|
||||
|
||||
void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
|
||||
for (int i = 0; i < DoubleRegister::kMaxNumRegisters; ++i) {
|
||||
double double_value = input_->GetDoubleRegister(i);
|
||||
Float64 double_value = input_->GetDoubleRegister(i);
|
||||
output_frame->SetDoubleRegister(i, double_value);
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ void Deoptimizer::SetPlatformCompiledStubRegisters(
|
||||
|
||||
void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
|
||||
for (int i = 0; i < DoubleRegister::kMaxNumRegisters; ++i) {
|
||||
double double_value = input_->GetDoubleRegister(i);
|
||||
Float64 double_value = input_->GetDoubleRegister(i);
|
||||
output_frame->SetDoubleRegister(i, double_value);
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ void Deoptimizer::SetPlatformCompiledStubRegisters(
|
||||
|
||||
void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
|
||||
for (int i = 0; i < DoubleRegister::kNumRegisters; ++i) {
|
||||
double double_value = input_->GetDoubleRegister(i);
|
||||
Float64 double_value = input_->GetDoubleRegister(i);
|
||||
output_frame->SetDoubleRegister(i, double_value);
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ void Deoptimizer::SetPlatformCompiledStubRegisters(
|
||||
|
||||
void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
|
||||
for (int i = 0; i < DoubleRegister::kNumRegisters; ++i) {
|
||||
double double_value = input_->GetDoubleRegister(i);
|
||||
Float64 double_value = input_->GetDoubleRegister(i);
|
||||
output_frame->SetDoubleRegister(i, double_value);
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ void Deoptimizer::SetPlatformCompiledStubRegisters(
|
||||
|
||||
void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
|
||||
for (int i = 0; i < XMMRegister::kMaxNumRegisters; ++i) {
|
||||
double double_value = input_->GetDoubleRegister(i);
|
||||
Float64 double_value = input_->GetDoubleRegister(i);
|
||||
output_frame->SetDoubleRegister(i, double_value);
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ void Deoptimizer::SetPlatformCompiledStubRegisters(
|
||||
|
||||
void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
|
||||
for (int i = 0; i < X87Register::kMaxNumRegisters; ++i) {
|
||||
double double_value = input_->GetDoubleRegister(i);
|
||||
Float64 double_value = input_->GetDoubleRegister(i);
|
||||
output_frame->SetDoubleRegister(i, double_value);
|
||||
}
|
||||
}
|
||||
|
15
test/mjsunit/regress/regress-crbug-684208.js
Normal file
15
test/mjsunit/regress/regress-crbug-684208.js
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
function foo() {
|
||||
var a = [1, 2.3, /*hole*/, 4.2];
|
||||
%_DeoptimizeNow();
|
||||
return a[2];
|
||||
}
|
||||
assertSame(undefined, foo());
|
||||
assertSame(undefined, foo());
|
||||
%OptimizeFunctionOnNextCall(foo)
|
||||
assertSame(undefined, foo());
|
Loading…
Reference in New Issue
Block a user