Commit c40aa827 authored by whesse@chromium.org's avatar whesse@chromium.org

Add boolean flag to HChange and LNumberUntagD to not convert undefined to NaN.

This is needed so that HCompare, optimized for double inputs, works correctly on undefined inputs.
BUG=v8:1434
TEST=mjsunit/bugs/bug-1434.js

Review URL: http://codereview.chromium.org/7044049

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8237 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent c8b9f3ab
......@@ -1661,6 +1661,7 @@ class LNumberUntagD: public LTemplateInstruction<1, 1, 0> {
}
DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
DECLARE_HYDROGEN_ACCESSOR(Change)
};
......
......@@ -3836,6 +3836,7 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
void LCodeGen::EmitNumberUntagD(Register input_reg,
DoubleRegister result_reg,
bool deoptimize_on_undefined,
LEnvironment* env) {
Register scratch = scratch0();
SwVfpRegister flt_scratch = s0;
......@@ -3851,20 +3852,25 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
__ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
__ cmp(scratch, Operand(ip));
__ b(eq, &heap_number);
if (deoptimize_on_undefined) {
DeoptimizeIf(ne, env);
} else {
Label heap_number;
__ b(eq, &heap_number);
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
__ cmp(input_reg, Operand(ip));
DeoptimizeIf(ne, env);
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
__ cmp(input_reg, Operand(ip));
DeoptimizeIf(ne, env);
// Convert undefined to NaN.
__ LoadRoot(ip, Heap::kNanValueRootIndex);
__ sub(ip, ip, Operand(kHeapObjectTag));
__ vldr(result_reg, ip, HeapNumber::kValueOffset);
__ jmp(&done);
// Convert undefined to NaN.
__ LoadRoot(ip, Heap::kNanValueRootIndex);
__ sub(ip, ip, Operand(kHeapObjectTag));
__ vldr(result_reg, ip, HeapNumber::kValueOffset);
__ jmp(&done);
__ bind(&heap_number);
}
// Heap number to double register conversion.
__ bind(&heap_number);
__ sub(ip, input_reg, Operand(kHeapObjectTag));
__ vldr(result_reg, ip, HeapNumber::kValueOffset);
__ jmp(&done);
......@@ -3998,7 +4004,9 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
Register input_reg = ToRegister(input);
DoubleRegister result_reg = ToDoubleRegister(result);
EmitNumberUntagD(input_reg, result_reg, instr->environment());
EmitNumberUntagD(input_reg, result_reg,
instr->hydrogen()->deoptimize_on_undefined(),
instr->environment());
}
......
......@@ -266,6 +266,7 @@ class LCodeGen BASE_EMBEDDED {
void EmitCmpI(LOperand* left, LOperand* right);
void EmitNumberUntagD(Register input,
DoubleRegister result,
bool deoptimize_on_undefined,
LEnvironment* env);
// Emits optimized code for typeof x == "y". Modifies input register.
......
......@@ -1240,6 +1240,10 @@ void HCompare::SetInputRepresentation(Representation r) {
if (r.IsTagged()) {
SetAllSideEffects();
ClearFlag(kUseGVN);
} else if (r.IsDouble()) {
SetFlag(kDeoptimizeOnUndefined);
ClearAllSideEffects();
SetFlag(kUseGVN);
} else {
ClearAllSideEffects();
SetFlag(kUseGVN);
......
......@@ -487,6 +487,7 @@ class HValue: public ZoneObject {
kCanOverflow,
kBailoutOnMinusZero,
kCanBeDivByZero,
kDeoptimizeOnUndefined,
kIsArguments,
kTruncatingToInt32,
kLastFlag = kTruncatingToInt32
......@@ -1067,8 +1068,11 @@ class HChange: public HUnaryOperation {
HChange(HValue* value,
Representation from,
Representation to,
bool is_truncating)
: HUnaryOperation(value), from_(from) {
bool is_truncating,
bool deoptimize_on_undefined)
: HUnaryOperation(value),
from_(from),
deoptimize_on_undefined_(deoptimize_on_undefined) {
ASSERT(!from.IsNone() && !to.IsNone());
ASSERT(!from.Equals(to));
set_representation(to);
......@@ -1084,6 +1088,7 @@ class HChange: public HUnaryOperation {
Representation from() const { return from_; }
Representation to() const { return representation(); }
bool deoptimize_on_undefined() const { return deoptimize_on_undefined_; }
virtual Representation RequiredInputRepresentation(int index) const {
return from_;
}
......@@ -1097,11 +1102,13 @@ class HChange: public HUnaryOperation {
if (!other->IsChange()) return false;
HChange* change = HChange::cast(other);
return value() == change->value()
&& to().Equals(change->to());
&& to().Equals(change->to())
&& deoptimize_on_undefined() == change->deoptimize_on_undefined();
}
private:
Representation from_;
bool deoptimize_on_undefined_;
};
......
......@@ -1850,6 +1850,8 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value,
// change instructions for them.
HInstruction* new_value = NULL;
bool is_truncating = use_value->CheckFlag(HValue::kTruncatingToInt32);
bool deoptimize_on_undefined =
use_value->CheckFlag(HValue::kDeoptimizeOnUndefined);
if (value->IsConstant()) {
HConstant* constant = HConstant::cast(value);
// Try to create a new copy of the constant with the new representation.
......@@ -1859,8 +1861,8 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value,
}
if (new_value == NULL) {
new_value =
new(zone()) HChange(value, value->representation(), to, is_truncating);
new_value = new(zone()) HChange(value, value->representation(), to,
is_truncating, deoptimize_on_undefined);
}
new_value->InsertBefore(next);
......@@ -1942,6 +1944,40 @@ void HGraph::InsertRepresentationChanges() {
}
void HGraph::RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi) {
if (phi->CheckFlag(HValue::kDeoptimizeOnUndefined)) return;
phi->SetFlag(HValue::kDeoptimizeOnUndefined);
for (int i = 0; i < phi->OperandCount(); ++i) {
HValue* input = phi->OperandAt(i);
if (input->IsPhi()) {
RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi::cast(input));
}
}
}
void HGraph::MarkDeoptimizeOnUndefined() {
HPhase phase("MarkDeoptimizeOnUndefined", this);
// Compute DeoptimizeOnUndefined flag for phis.
// Any phi that can reach a use with DeoptimizeOnUndefined set must
// have DeoptimizeOnUndefined set. Currently only HCompare, with
// double input representation, has this flag set.
// The flag is used by HChange tagged->double, which must deoptimize
// if one of its uses has this flag set.
for (int i = 0; i < phi_list()->length(); i++) {
HPhi* phi = phi_list()->at(i);
if (phi->representation().IsDouble()) {
for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
if (it.value()->CheckFlag(HValue::kDeoptimizeOnUndefined)) {
RecursivelyMarkPhiDeoptimizeOnUndefined(phi);
break;
}
}
}
}
}
void HGraph::ComputeMinusZeroChecks() {
BitVector visited(GetMaximumValueID());
for (int i = 0; i < blocks_.length(); ++i) {
......@@ -2248,6 +2284,7 @@ HGraph* HGraphBuilder::CreateGraph() {
graph()->InitializeInferredTypes();
graph()->Canonicalize();
graph()->MarkDeoptimizeOnUndefined();
graph()->InsertRepresentationChanges();
graph()->ComputeMinusZeroChecks();
......
......@@ -216,6 +216,7 @@ class HGraph: public ZoneObject {
void InitializeInferredTypes();
void InsertTypeConversions();
void InsertRepresentationChanges();
void MarkDeoptimizeOnUndefined();
void ComputeMinusZeroChecks();
bool ProcessArgumentsObject();
void EliminateRedundantPhis();
......@@ -280,6 +281,7 @@ class HGraph: public ZoneObject {
void InsertTypeConversions(HInstruction* instr);
void PropagateMinusZeroChecks(HValue* value, BitVector* visited);
void RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi);
void InsertRepresentationChangeForUse(HValue* value,
HValue* use_value,
int use_index,
......
......@@ -3617,8 +3617,9 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
void LCodeGen::EmitNumberUntagD(Register input_reg,
XMMRegister result_reg,
bool deoptimize_on_undefined,
LEnvironment* env) {
Label load_smi, heap_number, done;
Label load_smi, done;
// Smi check.
__ test(input_reg, Immediate(kSmiTagMask));
......@@ -3627,18 +3628,23 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
// Heap number map check.
__ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
factory()->heap_number_map());
__ j(equal, &heap_number, Label::kNear);
if (deoptimize_on_undefined) {
DeoptimizeIf(not_equal, env);
} else {
Label heap_number;
__ j(equal, &heap_number, Label::kNear);
__ cmp(input_reg, factory()->undefined_value());
DeoptimizeIf(not_equal, env);
__ cmp(input_reg, factory()->undefined_value());
DeoptimizeIf(not_equal, env);
// Convert undefined to NaN.
ExternalReference nan = ExternalReference::address_of_nan();
__ movdbl(result_reg, Operand::StaticVariable(nan));
__ jmp(&done, Label::kNear);
// Convert undefined to NaN.
ExternalReference nan = ExternalReference::address_of_nan();
__ movdbl(result_reg, Operand::StaticVariable(nan));
__ jmp(&done, Label::kNear);
__ bind(&heap_number);
}
// Heap number to XMM conversion.
__ bind(&heap_number);
__ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
__ jmp(&done, Label::kNear);
......@@ -3770,7 +3776,9 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
Register input_reg = ToRegister(input);
XMMRegister result_reg = ToDoubleRegister(result);
EmitNumberUntagD(input_reg, result_reg, instr->environment());
EmitNumberUntagD(input_reg, result_reg,
instr->hydrogen()->deoptimize_on_undefined(),
instr->environment());
}
......
......@@ -261,7 +261,10 @@ class LCodeGen BASE_EMBEDDED {
void EmitGoto(int block, LDeferredCode* deferred_stack_check = NULL);
void EmitBranch(int left_block, int right_block, Condition cc);
void EmitCmpI(LOperand* left, LOperand* right);
void EmitNumberUntagD(Register input, XMMRegister result, LEnvironment* env);
void EmitNumberUntagD(Register input,
XMMRegister result,
bool deoptimize_on_undefined,
LEnvironment* env);
// Emits optimized code for typeof x == "y". Modifies input register.
// Returns the condition on which a final split to
......
......@@ -1705,6 +1705,7 @@ class LNumberUntagD: public LTemplateInstruction<1, 1, 0> {
}
DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
DECLARE_HYDROGEN_ACCESSOR(Change);
};
......
......@@ -3559,8 +3559,9 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
void LCodeGen::EmitNumberUntagD(Register input_reg,
XMMRegister result_reg,
bool deoptimize_on_undefined,
LEnvironment* env) {
Label load_smi, heap_number, done;
Label load_smi, done;
// Smi check.
__ JumpIfSmi(input_reg, &load_smi, Label::kNear);
......@@ -3568,18 +3569,23 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
// Heap number map check.
__ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
Heap::kHeapNumberMapRootIndex);
__ j(equal, &heap_number, Label::kNear);
if (deoptimize_on_undefined) {
DeoptimizeIf(not_equal, env);
} else {
Label heap_number;
__ j(equal, &heap_number, Label::kNear);
__ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
DeoptimizeIf(not_equal, env);
__ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
DeoptimizeIf(not_equal, env);
// Convert undefined to NaN. Compute NaN as 0/0.
__ xorps(result_reg, result_reg);
__ divsd(result_reg, result_reg);
__ jmp(&done, Label::kNear);
// Convert undefined to NaN. Compute NaN as 0/0.
__ xorps(result_reg, result_reg);
__ divsd(result_reg, result_reg);
__ jmp(&done, Label::kNear);
__ bind(&heap_number);
}
// Heap number to XMM conversion.
__ bind(&heap_number);
__ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
__ jmp(&done, Label::kNear);
......@@ -3670,7 +3676,9 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
Register input_reg = ToRegister(input);
XMMRegister result_reg = ToDoubleRegister(result);
EmitNumberUntagD(input_reg, result_reg, instr->environment());
EmitNumberUntagD(input_reg, result_reg,
instr->hydrogen()->deoptimize_on_undefined(),
instr->environment());
}
......
......@@ -249,7 +249,10 @@ class LCodeGen BASE_EMBEDDED {
void EmitGoto(int block, LDeferredCode* deferred_stack_check = NULL);
void EmitBranch(int left_block, int right_block, Condition cc);
void EmitCmpI(LOperand* left, LOperand* right);
void EmitNumberUntagD(Register input, XMMRegister result, LEnvironment* env);
void EmitNumberUntagD(Register input,
XMMRegister result,
bool deoptimize_on_undefined,
LEnvironment* env);
// Emits optimized code for typeof x == "y". Modifies input register.
// Returns the condition on which a final split to
......
......@@ -1651,6 +1651,7 @@ class LNumberUntagD: public LTemplateInstruction<1, 1, 0> {
}
DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
DECLARE_HYDROGEN_ACCESSOR(Change);
};
......
......@@ -30,9 +30,6 @@ prefix mjsunit
# All tests in the bug directory are expected to fail.
bugs: FAIL
# Reliably fails when crankshaft is active, passes with --nocrankshaft
bugs/bug-1434: FAIL || PASS
##############################################################################
# Too slow in debug mode with --stress-opt
compiler/regress-stacktrace-methods: PASS, SKIP if $mode == debug
......
// Copyright 2008 the V8 project authors. All rights reserved.
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
......
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