ASSERT(value->IsConstant());
value->DeleteAndReplaceWith(NULL);
}
+
+ // The only purpose of a HForceRepresentation is to represent the value
+ // after the (possible) HChange instruction. We make it disappear.
+ if (value->IsForceRepresentation()) {
+ value->DeleteAndReplaceWith(HForceRepresentation::cast(value)->value());
+ }
}
}
-HInstruction* HGraphBuilder::BuildIncrement(HValue* value,
- bool increment,
+HInstruction* HGraphBuilder::BuildIncrement(bool returns_original_input,
CountOperation* expr) {
- HConstant* delta = increment
- ? graph_->GetConstant1()
- : graph_->GetConstantMinus1();
- HInstruction* instr = new(zone()) HAdd(value, delta);
+ // The input to the count operation is on top of the expression stack.
TypeInfo info = oracle()->IncrementType(expr);
Representation rep = ToRepresentation(info);
if (rep.IsTagged()) {
rep = Representation::Integer32();
}
+
+ if (returns_original_input) {
+ // We need an explicit HValue representing ToNumber(input). The
+ // actual HChange instruction we need is (sometimes) added in a later
+ // phase, so it is not available now to be used as an input to HAdd and
+ // as the return value.
+ HInstruction* number_input = new(zone()) HForceRepresentation(Pop(), rep);
+ AddInstruction(number_input);
+ Push(number_input);
+ }
+
+ // The addition has no side effects, so we do not need
+ // to simulate the expression stack after this instruction.
+ // Any later failures deopt to the load of the input or earlier.
+ HConstant* delta = (expr->op() == Token::INC)
+ ? graph_->GetConstant1()
+ : graph_->GetConstantMinus1();
+ HInstruction* instr = new(zone()) HAdd(Top(), delta);
TraceRepresentation(expr->op(), info, instr, rep);
instr->AssumeRepresentation(rep);
+ AddInstruction(instr);
return instr;
}
VariableProxy* proxy = target->AsVariableProxy();
Variable* var = proxy->AsVariable();
Property* prop = target->AsProperty();
- ASSERT(var == NULL || prop == NULL);
- bool inc = expr->op() == Token::INC;
+ if (var == NULL && prop == NULL) {
+ return Bailout("invalid lhs in count operation");
+ }
+
+ // Match the full code generator stack by simulating an extra stack
+ // element for postfix operations in a non-effect context. The return
+ // value is ToNumber(input).
+ bool returns_original_input =
+ expr->is_postfix() && !ast_context()->IsEffect();
+ HValue* input = NULL; // ToNumber(original_input).
+ HValue* after = NULL; // The result after incrementing or decrementing.
if (var != NULL) {
+ // Argument of the count operation is a variable, not a property.
+ ASSERT(prop == NULL);
CHECK_ALIVE(VisitForValue(target));
- // Match the full code generator stack by simulating an extra stack
- // element for postfix operations in a non-effect context.
- bool has_extra = expr->is_postfix() && !ast_context()->IsEffect();
- HValue* before = has_extra ? Top() : Pop();
- HInstruction* after = BuildIncrement(before, inc, expr);
- AddInstruction(after);
+ after = BuildIncrement(returns_original_input, expr);
+ input = returns_original_input ? Top() : Pop();
Push(after);
if (var->is_global()) {
} else {
return Bailout("lookup variable in count operation");
}
- Drop(has_extra ? 2 : 1);
- ast_context()->ReturnValue(expr->is_postfix() ? before : after);
- } else if (prop != NULL) {
+ } else {
+ // Argument of the count operation is a property.
+ ASSERT(prop != NULL);
prop->RecordTypeFeedback(oracle());
if (prop->key()->IsPropertyName()) {
// Named property.
-
- // Match the full code generator stack by simulating an extra stack
- // element for postfix operations in a non-effect context.
- bool has_extra = expr->is_postfix() && !ast_context()->IsEffect();
- if (has_extra) Push(graph_->GetConstantUndefined());
+ if (returns_original_input) Push(graph_->GetConstantUndefined());
CHECK_ALIVE(VisitForValue(prop->obj()));
HValue* obj = Top();
PushAndAdd(load);
if (load->HasSideEffects()) AddSimulate(expr->CountId());
- HValue* before = Pop();
- // There is no deoptimization to after the increment, so we don't need
- // to simulate the expression stack after this instruction.
- HInstruction* after = BuildIncrement(before, inc, expr);
- AddInstruction(after);
+ after = BuildIncrement(returns_original_input, expr);
+ input = Pop();
HInstruction* store = BuildStoreNamed(obj, after, prop);
AddInstruction(store);
// of the operation, and the placeholder with the original value if
// necessary.
environment()->SetExpressionStackAt(0, after);
- if (has_extra) environment()->SetExpressionStackAt(1, before);
+ if (returns_original_input) environment()->SetExpressionStackAt(1, input);
if (store->HasSideEffects()) AddSimulate(expr->AssignmentId());
- Drop(has_extra ? 2 : 1);
-
- ast_context()->ReturnValue(expr->is_postfix() ? before : after);
} else {
// Keyed property.
-
- // Match the full code generator stack by simulate an extra stack element
- // for postfix operations in a non-effect context.
- bool has_extra = expr->is_postfix() && !ast_context()->IsEffect();
- if (has_extra) Push(graph_->GetConstantUndefined());
+ if (returns_original_input) Push(graph_->GetConstantUndefined());
CHECK_ALIVE(VisitForValue(prop->obj()));
CHECK_ALIVE(VisitForValue(prop->key()));
PushAndAdd(load);
if (load->HasSideEffects()) AddSimulate(expr->CountId());
- HValue* before = Pop();
- // There is no deoptimization to after the increment, so we don't need
- // to simulate the expression stack after this instruction.
- HInstruction* after = BuildIncrement(before, inc, expr);
- AddInstruction(after);
+ after = BuildIncrement(returns_original_input, expr);
+ input = Pop();
expr->RecordTypeFeedback(oracle());
HInstruction* store = BuildStoreKeyed(obj, key, after, expr);
// original value if necessary.
Drop(1);
environment()->SetExpressionStackAt(0, after);
- if (has_extra) environment()->SetExpressionStackAt(1, before);
+ if (returns_original_input) environment()->SetExpressionStackAt(1, input);
if (store->HasSideEffects()) AddSimulate(expr->AssignmentId());
- Drop(has_extra ? 2 : 1);
-
- ast_context()->ReturnValue(expr->is_postfix() ? before : after);
}
-
- } else {
- return Bailout("invalid lhs in count operation");
}
+
+ Drop(returns_original_input ? 2 : 1);
+ ast_context()->ReturnValue(expr->is_postfix() ? input : after);
}
--- /dev/null
+// 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:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test optimized implementation of postfix ++ on undefined input.
+// See http://code.google.com/p/v8/issues/detail?id=1389
+
+for (var i=0; i<4; i++) {
+ (function () {
+ (function () {
+ (function () {
+ var x;
+ y = x++;
+ })();
+ })();
+ })();
+}
+
+assertEquals(NaN, y);