From: verwaest@chromium.org Date: Thu, 30 May 2013 09:11:06 +0000 (+0000) Subject: Replace DeoptimizeOnUndefined with whitelisting AllowUndefinedAsNan X-Git-Tag: upstream/4.7.83~14051 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1a4a904bef5d3bd5c91ab5f6f9c20e85550aacd3;p=platform%2Fupstream%2Fv8.git Replace DeoptimizeOnUndefined with whitelisting AllowUndefinedAsNan R=danno@chromium.org Review URL: https://chromiumcodereview.appspot.com/15952007 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14894 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 54b1a43..06a6506 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -4976,7 +4976,7 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { void LCodeGen::EmitNumberUntagD(Register input_reg, DwVfpRegister result_reg, - bool deoptimize_on_undefined, + bool allow_undefined_as_nan, bool deoptimize_on_minus_zero, LEnvironment* env, NumberUntagDMode mode) { @@ -4996,7 +4996,7 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset)); __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); __ cmp(scratch, Operand(ip)); - if (deoptimize_on_undefined) { + if (!allow_undefined_as_nan) { DeoptimizeIf(ne, env); } else { Label heap_number, convert; @@ -5166,7 +5166,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { } EmitNumberUntagD(input_reg, result_reg, - instr->hydrogen()->deoptimize_on_undefined(), + instr->hydrogen()->allow_undefined_as_nan(), instr->hydrogen()->deoptimize_on_minus_zero(), instr->environment(), mode); diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h index 58aa93d..f282847 100644 --- a/src/arm/lithium-codegen-arm.h +++ b/src/arm/lithium-codegen-arm.h @@ -335,7 +335,7 @@ class LCodeGen BASE_EMBEDDED { void EmitBranch(int left_block, int right_block, Condition cc); void EmitNumberUntagD(Register input, DwVfpRegister result, - bool deoptimize_on_undefined, + bool allow_undefined_as_nan, bool deoptimize_on_minus_zero, LEnvironment* env, NumberUntagDMode mode); diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index ddccbf3..d4938e5 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -1485,7 +1485,7 @@ void HChange::PrintDataTo(StringStream* stream) { if (CanTruncateToInt32()) stream->Add(" truncating-int32"); if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?"); - if (CheckFlag(kDeoptimizeOnUndefined)) stream->Add(" deopt-on-undefined"); + if (CheckFlag(kAllowUndefinedAsNaN)) stream->Add(" allow-undefined-as-nan"); } @@ -2490,8 +2490,8 @@ void HCompareIDAndBranch::InferRepresentation(HInferRepresentation* h_infer) { // (false). Therefore, any comparisons other than ordered relational // comparisons must cause a deopt when one of their arguments is undefined. // See also v8:1434 - if (!Token::IsOrderedRelationalCompareOp(token_)) { - SetFlag(kDeoptimizeOnUndefined); + if (Token::IsOrderedRelationalCompareOp(token_)) { + SetFlag(kAllowUndefinedAsNaN); } } ChangeRepresentation(rep); @@ -2754,7 +2754,7 @@ bool HLoadKeyed::AllUsesCanTreatHoleAsNaN() const { for (HUseIterator it(uses()); !it.Done(); it.Advance()) { HValue* use = it.value(); - if (use->CheckFlag(HValue::kDeoptimizeOnUndefined)) { + if (!use->CheckFlag(HValue::kAllowUndefinedAsNaN)) { return false; } } @@ -3749,7 +3749,6 @@ void HObjectAccess::SetGVNFlags(HValue *instr, bool is_store) { // track dominating allocations in order to eliminate write barriers instr->SetGVNFlag(kDependsOnNewSpacePromotion); instr->SetFlag(HValue::kTrackSideEffectDominators); - instr->SetFlag(HValue::kDeoptimizeOnUndefined); } else { // try to GVN loads, but don't hoist above map changes instr->SetFlag(HValue::kUseGVN); diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 3d2de9d..9f52569 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -790,7 +790,7 @@ class HValue: public ZoneObject { kCanOverflow, kBailoutOnMinusZero, kCanBeDivByZero, - kDeoptimizeOnUndefined, + kAllowUndefinedAsNaN, kIsArguments, kTruncatingToInt32, // Set after an instruction is killed. @@ -1715,14 +1715,14 @@ class HChange: public HUnaryOperation { HChange(HValue* value, Representation to, bool is_truncating, - bool deoptimize_on_undefined) + bool allow_undefined_as_nan) : HUnaryOperation(value) { ASSERT(!value->representation().IsNone()); ASSERT(!to.IsNone()); ASSERT(!value->representation().Equals(to)); set_representation(to); SetFlag(kUseGVN); - if (deoptimize_on_undefined) SetFlag(kDeoptimizeOnUndefined); + if (allow_undefined_as_nan) SetFlag(kAllowUndefinedAsNaN); if (is_truncating) SetFlag(kTruncatingToInt32); if (value->representation().IsSmi() || value->type().IsSmi()) { set_type(HType::Smi()); @@ -1738,8 +1738,8 @@ class HChange: public HUnaryOperation { Representation from() const { return value()->representation(); } Representation to() const { return representation(); } - bool deoptimize_on_undefined() const { - return CheckFlag(kDeoptimizeOnUndefined); + bool allow_undefined_as_nan() const { + return CheckFlag(kAllowUndefinedAsNaN); } bool deoptimize_on_minus_zero() const { return CheckFlag(kBailoutOnMinusZero); @@ -1769,6 +1769,7 @@ class HClampToUint8: public HUnaryOperation { explicit HClampToUint8(HValue* value) : HUnaryOperation(value) { set_representation(Representation::Integer32()); + SetFlag(kAllowUndefinedAsNaN); SetFlag(kUseGVN); } @@ -2495,6 +2496,7 @@ class HBitNot: public HUnaryOperation { set_representation(Representation::Integer32()); SetFlag(kUseGVN); SetFlag(kTruncatingToInt32); + SetFlag(kAllowUndefinedAsNaN); } virtual Representation RequiredInputRepresentation(int index) { @@ -2604,6 +2606,7 @@ class HUnaryMathOperation: public HTemplateInstruction<2> { UNREACHABLE(); } SetFlag(kUseGVN); + SetFlag(kAllowUndefinedAsNaN); } virtual bool IsDeletable() const { return true; } @@ -2945,6 +2948,7 @@ class HPhi: public HValue { } ASSERT(merged_index >= 0); SetFlag(kFlexibleRepresentation); + SetFlag(kAllowUndefinedAsNaN); } virtual Representation RepresentationFromInputs(); @@ -3668,6 +3672,7 @@ class HBitwiseBinaryOperation: public HBinaryOperation { : HBinaryOperation(context, left, right) { SetFlag(kFlexibleRepresentation); SetFlag(kTruncatingToInt32); + SetFlag(kAllowUndefinedAsNaN); SetAllSideEffects(); } @@ -3722,6 +3727,7 @@ class HMathFloorOfDiv: public HBinaryOperation { if (!right->IsConstant()) { SetFlag(kCanBeDivByZero); } + SetFlag(kAllowUndefinedAsNaN); } virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); @@ -3746,6 +3752,7 @@ class HArithmeticBinaryOperation: public HBinaryOperation { : HBinaryOperation(context, left, right) { SetAllSideEffects(); SetFlag(kFlexibleRepresentation); + SetFlag(kAllowUndefinedAsNaN); } virtual void RepresentationChanged(Representation to) { @@ -5731,12 +5738,11 @@ class HStoreKeyed } if (is_external()) { SetGVNFlag(kChangesSpecializedArrayElements); + SetFlag(kAllowUndefinedAsNaN); } else if (IsFastDoubleElementsKind(elements_kind)) { SetGVNFlag(kChangesDoubleArrayElements); - SetFlag(kDeoptimizeOnUndefined); } else if (IsFastSmiElementsKind(elements_kind)) { SetGVNFlag(kChangesArrayElements); - SetFlag(kDeoptimizeOnUndefined); } else { SetGVNFlag(kChangesArrayElements); } diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 2d1e844..54a5225 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -1586,7 +1586,10 @@ void HGraphBuilder::BuildCopyElements(HValue* context, ? FAST_HOLEY_ELEMENTS : to_elements_kind; HInstruction* holey_store = AddInstruction( new(zone()) HStoreKeyed(to_elements, key, element, holey_kind)); - holey_store->ClearFlag(HValue::kDeoptimizeOnUndefined); + // Allow NaN hole values to converted to their tagged counterparts. + if (IsFastHoleyElementsKind(to_elements_kind)) { + holey_store->SetFlag(HValue::kAllowUndefinedAsNaN); + } builder.EndBody(); @@ -3100,8 +3103,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); + bool allow_undefined_as_nan = + use_value->CheckFlag(HValue::kAllowUndefinedAsNaN); if (value->IsConstant()) { HConstant* constant = HConstant::cast(value); // Try to create a new copy of the constant with the new representation. @@ -3112,7 +3115,7 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value, if (new_value == NULL) { new_value = new(zone()) HChange(value, to, - is_truncating, deoptimize_on_undefined); + is_truncating, allow_undefined_as_nan); } new_value->InsertBefore(next); @@ -3219,8 +3222,8 @@ void HGraph::InsertRepresentationChanges() { void HGraph::RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi) { - if (phi->CheckFlag(HValue::kDeoptimizeOnUndefined)) return; - phi->SetFlag(HValue::kDeoptimizeOnUndefined); + if (!phi->CheckFlag(HValue::kAllowUndefinedAsNaN)) return; + phi->ClearFlag(HValue::kAllowUndefinedAsNaN); for (int i = 0; i < phi->OperandCount(); ++i) { HValue* input = phi->OperandAt(i); if (input->IsPhi()) { @@ -3240,16 +3243,11 @@ void HGraph::MarkDeoptimizeOnUndefined() { // 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()) { - int use_index = it.index(); - HValue* use_value = it.value(); - Representation req = use_value->RequiredInputRepresentation(use_index); - if (!req.IsDouble() || - use_value->CheckFlag(HValue::kDeoptimizeOnUndefined)) { - RecursivelyMarkPhiDeoptimizeOnUndefined(phi); - break; - } + for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) { + HValue* use_value = it.value(); + if (!use_value->CheckFlag(HValue::kAllowUndefinedAsNaN)) { + RecursivelyMarkPhiDeoptimizeOnUndefined(phi); + break; } } } @@ -10109,7 +10107,7 @@ void HOptimizedGraphBuilder::BuildEmitFixedDoubleArray( boilerplate_elements, key_constant, NULL, kind, ALLOW_RETURN_HOLE)); HInstruction* store = AddInstruction(new(zone) HStoreKeyed( object_elements, key_constant, value_instruction, kind)); - store->ClearFlag(HValue::kDeoptimizeOnUndefined); + store->SetFlag(HValue::kAllowUndefinedAsNaN); } } diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 849e438..f8b28c4 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -5095,7 +5095,7 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg, Register temp_reg, - bool deoptimize_on_undefined, + bool allow_undefined_as_nan, bool deoptimize_on_minus_zero, LEnvironment* env, NumberUntagDMode mode) { @@ -5110,7 +5110,7 @@ void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg, // Heap number map check. __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), factory()->heap_number_map()); - if (deoptimize_on_undefined) { + if (!allow_undefined_as_nan) { DeoptimizeIf(not_equal, env); } else { Label heap_number, convert; @@ -5167,7 +5167,7 @@ void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg, void LCodeGen::EmitNumberUntagD(Register input_reg, Register temp_reg, XMMRegister result_reg, - bool deoptimize_on_undefined, + bool allow_undefined_as_nan, bool deoptimize_on_minus_zero, LEnvironment* env, NumberUntagDMode mode) { @@ -5182,7 +5182,7 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, // Heap number map check. __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), factory()->heap_number_map()); - if (deoptimize_on_undefined) { + if (!allow_undefined_as_nan) { DeoptimizeIf(not_equal, env); } else { Label heap_number, convert; @@ -5530,14 +5530,14 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { EmitNumberUntagD(input_reg, temp_reg, result_reg, - instr->hydrogen()->deoptimize_on_undefined(), + instr->hydrogen()->allow_undefined_as_nan(), deoptimize_on_minus_zero, instr->environment(), mode); } else { EmitNumberUntagDNoSSE2(input_reg, temp_reg, - instr->hydrogen()->deoptimize_on_undefined(), + instr->hydrogen()->allow_undefined_as_nan(), deoptimize_on_minus_zero, instr->environment(), mode); diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h index dce225c..dec768b 100644 --- a/src/ia32/lithium-codegen-ia32.h +++ b/src/ia32/lithium-codegen-ia32.h @@ -331,7 +331,7 @@ class LCodeGen BASE_EMBEDDED { Register input, Register temp, XMMRegister result, - bool deoptimize_on_undefined, + bool allow_undefined_as_nan, bool deoptimize_on_minus_zero, LEnvironment* env, NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED); @@ -339,7 +339,7 @@ class LCodeGen BASE_EMBEDDED { void EmitNumberUntagDNoSSE2( Register input, Register temp, - bool deoptimize_on_undefined, + bool allow_undefined_as_nan, bool deoptimize_on_minus_zero, LEnvironment* env, NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED); diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index cc45e53..c94af7d 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -4688,7 +4688,7 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { void LCodeGen::EmitNumberUntagD(Register input_reg, XMMRegister result_reg, - bool deoptimize_on_undefined, + bool allow_undefined_as_nan, bool deoptimize_on_minus_zero, LEnvironment* env, NumberUntagDMode mode) { @@ -4703,7 +4703,7 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, // Heap number map check. __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), Heap::kHeapNumberMapRootIndex); - if (deoptimize_on_undefined) { + if (!allow_undefined_as_nan) { DeoptimizeIf(not_equal, env); } else { Label heap_number, convert; @@ -4839,7 +4839,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { } EmitNumberUntagD(input_reg, result_reg, - instr->hydrogen()->deoptimize_on_undefined(), + instr->hydrogen()->allow_undefined_as_nan(), instr->hydrogen()->deoptimize_on_minus_zero(), instr->environment(), mode); diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h index 697d49d..9890649 100644 --- a/src/x64/lithium-codegen-x64.h +++ b/src/x64/lithium-codegen-x64.h @@ -295,7 +295,7 @@ class LCodeGen BASE_EMBEDDED { void EmitNumberUntagD( Register input, XMMRegister result, - bool deoptimize_on_undefined, + bool allow_undefined_as_nan, bool deoptimize_on_minus_zero, LEnvironment* env, NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED); diff --git a/test/mjsunit/regress/regress-convert-hole.js b/test/mjsunit/regress/regress-convert-hole.js index 1424221..3316f30 100644 --- a/test/mjsunit/regress/regress-convert-hole.js +++ b/test/mjsunit/regress/regress-convert-hole.js @@ -27,7 +27,7 @@ // Flags: --allow-natives-syntax -function f(test, test2, a, i) { +function f_store(test, test2, a, i) { var o = [0.5,1,,3]; var d; if (test) { @@ -42,11 +42,67 @@ function f(test, test2, a, i) { return d; } -var a = [0, 0, 0, {}]; -f(true, false, a, 0); -f(true, true, a, 0); -f(false, false, a, 1); -f(false, true, a, 1); -%OptimizeFunctionOnNextCall(f); -f(false, false, a, 2); -assertEquals(undefined, a[2]); +var a1 = [0, 0, 0, {}]; +f_store(true, false, a1, 0); +f_store(true, true, a1, 0); +f_store(false, false, a1, 1); +f_store(false, true, a1, 1); +%OptimizeFunctionOnNextCall(f_store); +f_store(false, false, a1, 2); +assertEquals(undefined, a1[2]); + +function test_arg(expected) { + return function(v) { + assertEquals(expected, v); + } +} + +function f_call(f, test, test2, i) { + var o = [0.5,1,,3]; + var d; + if (test) { + d = 1.5; + } else { + d = o[i]; + } + if (test2) { + d += 1; + } + f(d); + return d; +} + +f_call(test_arg(1.5), true, false, 0); +f_call(test_arg(2.5), true, true, 0); +f_call(test_arg(1), false, false, 1); +f_call(test_arg(2), false, true, 1); +%OptimizeFunctionOnNextCall(f_call); +f_call(test_arg(undefined), false, false, 2); + + +function f_external(test, test2, test3, a, i) { + var o = [0.5,1,,3]; + var d; + if (test) { + d = 1.5; + } else { + d = o[i]; + } + if (test2) { + d += 1; + } + if (test3) { + d = d|0; + } + a[d] = 1; + return d; +} + +var a2 = new Int32Array(10); +f_external(true, false, true, a2, 0); +f_external(true, true, true, a2, 0); +f_external(false, false, true, a2, 1); +f_external(false, true, true, a2, 1); +%OptimizeFunctionOnNextCall(f_external); +f_external(false, false, false, a2, 2); +assertEquals(1, a2[undefined]);