Added general pre- and postfix count operations to top-level compiler.

Until now we only supported postfix operations on global variables.
This change add generic count operations to the top-level compiler.

I tried to re-use code from the code generator used for assignment expressions
where possible.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3530 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 88ba93d9
This diff is collapsed.
...@@ -649,12 +649,6 @@ void CodeGenSelector::VisitStatements(ZoneList<Statement*>* stmts) { ...@@ -649,12 +649,6 @@ void CodeGenSelector::VisitStatements(ZoneList<Statement*>* stmts) {
void CodeGenSelector::VisitDeclaration(Declaration* decl) { void CodeGenSelector::VisitDeclaration(Declaration* decl) {
Property* prop = decl->proxy()->AsProperty(); Property* prop = decl->proxy()->AsProperty();
if (prop != NULL) { if (prop != NULL) {
// Property rewrites are shared, ensure we are not changing its
// expression context state.
ASSERT(prop->obj()->context() == Expression::kUninitialized ||
prop->obj()->context() == Expression::kValue);
ASSERT(prop->key()->context() == Expression::kUninitialized ||
prop->key()->context() == Expression::kValue);
ProcessExpression(prop->obj(), Expression::kValue); ProcessExpression(prop->obj(), Expression::kValue);
ProcessExpression(prop->key(), Expression::kValue); ProcessExpression(prop->key(), Expression::kValue);
} }
...@@ -903,8 +897,6 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) { ...@@ -903,8 +897,6 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) {
} }
} }
} else if (prop != NULL) { } else if (prop != NULL) {
ASSERT(prop->obj()->context() == Expression::kUninitialized ||
prop->obj()->context() == Expression::kValue);
ProcessExpression(prop->obj(), Expression::kValue); ProcessExpression(prop->obj(), Expression::kValue);
CHECK_BAILOUT; CHECK_BAILOUT;
// We will only visit the key during code generation for keyed property // We will only visit the key during code generation for keyed property
...@@ -915,8 +907,6 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) { ...@@ -915,8 +907,6 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) {
if (lit == NULL || if (lit == NULL ||
!lit->handle()->IsSymbol() || !lit->handle()->IsSymbol() ||
String::cast(*(lit->handle()))->AsArrayIndex(&ignored)) { String::cast(*(lit->handle()))->AsArrayIndex(&ignored)) {
ASSERT(prop->key()->context() == Expression::kUninitialized ||
prop->key()->context() == Expression::kValue);
ProcessExpression(prop->key(), Expression::kValue); ProcessExpression(prop->key(), Expression::kValue);
CHECK_BAILOUT; CHECK_BAILOUT;
} }
...@@ -1022,11 +1012,36 @@ void CodeGenSelector::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -1022,11 +1012,36 @@ void CodeGenSelector::VisitUnaryOperation(UnaryOperation* expr) {
void CodeGenSelector::VisitCountOperation(CountOperation* expr) { void CodeGenSelector::VisitCountOperation(CountOperation* expr) {
// We support postfix count operations on global variables.
if (expr->is_prefix()) BAILOUT("Prefix CountOperation");
Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
if (var == NULL || !var->is_global()) BAILOUT("non-global postincrement"); Property* prop = expr->expression()->AsProperty();
ProcessExpression(expr->expression(), Expression::kValue); ASSERT(var == NULL || prop == NULL);
if (var != NULL) {
// All global variables are supported.
if (!var->is_global()) {
ASSERT(var->slot() != NULL);
Slot::Type type = var->slot()->type();
if (type == Slot::LOOKUP) {
BAILOUT("CountOperation with lookup slot");
}
}
} else if (prop != NULL) {
ProcessExpression(prop->obj(), Expression::kValue);
CHECK_BAILOUT;
// We will only visit the key during code generation for keyed property
// stores. Leave its expression context uninitialized for named
// property stores.
Literal* lit = prop->key()->AsLiteral();
uint32_t ignored;
if (lit == NULL ||
!lit->handle()->IsSymbol() ||
String::cast(*(lit->handle()))->AsArrayIndex(&ignored)) {
ProcessExpression(prop->key(), Expression::kValue);
CHECK_BAILOUT;
}
} else {
// This is a throw reference error.
BAILOUT("CountOperation non-variable/non-property expression");
}
} }
......
...@@ -676,7 +676,7 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -676,7 +676,7 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
EmitNamedPropertyLoad(prop, Expression::kValue); EmitNamedPropertyLoad(prop, Expression::kValue);
break; break;
case KEYED_PROPERTY: case KEYED_PROPERTY:
EmitKeyedPropertyLoad(Expression::kValue); EmitKeyedPropertyLoad(prop, Expression::kValue);
break; break;
} }
} }
...@@ -694,7 +694,8 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -694,7 +694,8 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
// Store the value. // Store the value.
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE:
EmitVariableAssignment(expr); EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
expr->context());
break; break;
case NAMED_PROPERTY: case NAMED_PROPERTY:
EmitNamedPropertyAssignment(expr); EmitNamedPropertyAssignment(expr);
......
...@@ -213,6 +213,7 @@ class FastCodeGenerator: public AstVisitor { ...@@ -213,6 +213,7 @@ class FastCodeGenerator: public AstVisitor {
int SlotOffset(Slot* slot); int SlotOffset(Slot* slot);
void Move(Expression::Context destination, Register source); void Move(Expression::Context destination, Register source);
void MoveTOS(Expression::Context destination);
void Move(Expression::Context destination, Slot* source, Register scratch); void Move(Expression::Context destination, Slot* source, Register scratch);
void Move(Expression::Context destination, Literal* source); void Move(Expression::Context destination, Literal* source);
void Move(Slot* dst, Register source, Register scratch1, Register scratch2); void Move(Slot* dst, Register source, Register scratch1, Register scratch2);
...@@ -247,13 +248,13 @@ class FastCodeGenerator: public AstVisitor { ...@@ -247,13 +248,13 @@ class FastCodeGenerator: public AstVisitor {
// Platform-specific support for compiling assignments. // Platform-specific support for compiling assignments.
// Load a value from a named property and push the result on the stack. // Load a value from a named property.
// The receiver is left on the stack by the IC. // The receiver is left on the stack by the IC.
void EmitNamedPropertyLoad(Property* expr, Expression::Context context); void EmitNamedPropertyLoad(Property* expr, Expression::Context context);
// Load a value from a named property and push the result on the stack. // Load a value from a keyed property.
// The receiver and the key is left on the stack by the IC. // The receiver and the key is left on the stack by the IC.
void EmitKeyedPropertyLoad(Expression::Context context); void EmitKeyedPropertyLoad(Property* expr, Expression::Context context);
// Apply the compound assignment operator. Expects both operands on top // Apply the compound assignment operator. Expects both operands on top
// of the stack. // of the stack.
...@@ -261,7 +262,7 @@ class FastCodeGenerator: public AstVisitor { ...@@ -261,7 +262,7 @@ class FastCodeGenerator: public AstVisitor {
// Complete a variable assignment. The right-hand-side value is expected // Complete a variable assignment. The right-hand-side value is expected
// on top of the stack. // on top of the stack.
void EmitVariableAssignment(Assignment* expr); void EmitVariableAssignment(Variable* var, Expression::Context context);
// Complete a named property assignment. The receiver and right-hand-side // Complete a named property assignment. The receiver and right-hand-side
// value are expected on top of the stack. // value are expected on top of the stack.
......
This diff is collapsed.
This diff is collapsed.
// Copyright 2009 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 pre- and postfix count operations.
// Test value context.
var a = 42;
var b = {x:42};
var c = "x";
assertEquals(43, ++a);
assertEquals(43, a);
assertEquals(43, a++);
assertEquals(44, a);
assertEquals(43, ++b.x);
assertEquals(43, b.x);
assertEquals(43, b.x++);
assertEquals(44, b.x);
assertEquals(45, ++b[c]);
assertEquals(45, b[c]);
assertEquals(45, b[c]++);
assertEquals(46, b[c]);
// Test effect context.
a = 42;
b = {x:42};
c = "x";
assertEquals(1, eval("++a; 1"));
assertEquals(43, a);
assertEquals(1, eval("a++; 1"));
assertEquals(44, a);
assertEquals(1, eval("++b.x; 1"));
assertEquals(43, b.x);
assertEquals(1, eval("b.x++; 1"));
assertEquals(44, b.x);
assertEquals(1, eval("++b[c]; 1"));
assertEquals(45, b[c]);
assertEquals(1, eval("b[c]++; 1"));
assertEquals(46, b[c]);
// Test test context.
a = 42;
b = {x:42};
c = "x";
assertEquals(1, (++a) ? 1 : 0);
assertEquals(43, a);
assertEquals(1, (a++) ? 1 : 0);
assertEquals(44, a);
assertEquals(1, (++b.x) ? 1 : 0);
assertEquals(43, b.x);
assertEquals(1, (b.x++) ? 1 : 0);
assertEquals(44, b.x);
assertEquals(1, (++b[c]) ? 1 : 0);
assertEquals(45, b[c]);
assertEquals(1, (b[c]++) ? 1 : 0);
assertEquals(46, b[c]);
// Test value/test and test/value contexts.
a = 42;
b = {x:42};
c = "x";
assertEquals(43, ++a || 1);
assertEquals(43, a);
assertEquals(43, a++ || 1);
assertEquals(44, a);
assertEquals(43, ++b.x || 1);
assertEquals(43, b.x);
assertEquals(43, (b.x++) || 1);
assertEquals(44, b.x);
assertEquals(45, ++b[c] || 1);
assertEquals(45, b[c]);
assertEquals(45, b[c]++ || 1);
assertEquals(46, b[c]);
a = 42;
b = {x:42};
c = "x";
assertEquals(1, ++a && 1);
assertEquals(43, a);
assertEquals(1, a++ && 1);
assertEquals(44, a);
assertEquals(1, ++b.x && 1);
assertEquals(43, b.x);
assertEquals(1, (b.x++) && 1);
assertEquals(44, b.x);
assertEquals(1, ++b[c] && 1);
assertEquals(45, b[c]);
assertEquals(1, b[c]++ && 1);
assertEquals(46, b[c]);
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