Introduce 'top-of-stack caching' to the toplevel code generator by

allowing the value of the rightmost subexpressions to be evaluated
into an accumulator register (eg, eax, rax, or r0) rather than onto
the stack.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3630 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 40cef2dc
This diff is collapsed.
......@@ -75,39 +75,6 @@ int FastCodeGenerator::SlotOffset(Slot* slot) {
}
void FastCodeGenerator::Apply(Expression::Context context, Register reg) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
break;
case Expression::kValue:
__ push(reg);
break;
case Expression::kTest:
TestAndBranch(reg, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
__ push(reg);
TestAndBranch(reg, true_label_, &discard);
__ bind(&discard);
__ Drop(1);
__ jmp(false_label_);
break;
}
case Expression::kTestValue: {
Label discard;
__ push(reg);
TestAndBranch(reg, &discard, false_label_);
__ bind(&discard);
__ Drop(1);
__ jmp(true_label_);
}
}
}
void FastCodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
int length = declarations->length();
......@@ -345,14 +312,7 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
Comment cmnt(masm_, "[ ReturnStatement");
SetStatementPosition(stmt);
Expression* expr = stmt->expression();
// Complete the statement based on the type of the subexpression.
if (expr->AsLiteral() != NULL) {
__ Move(result_register(), expr->AsLiteral()->handle());
} else {
ASSERT_EQ(Expression::kValue, expr->context());
Visit(expr);
__ pop(result_register());
}
VisitForValue(expr, kAccumulator);
// Exit all nested statements.
NestedStatement* current = nesting_stack_;
......@@ -371,7 +331,7 @@ void FastCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
Comment cmnt(masm_, "[ WithEnterStatement");
SetStatementPosition(stmt);
Visit(stmt->expression());
VisitForValue(stmt->expression(), kStack);
if (stmt->is_catch_block()) {
__ CallRuntime(Runtime::kPushCatchContext, 1);
} else {
......@@ -658,21 +618,19 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
// Nothing to do here.
break;
case NAMED_PROPERTY:
Visit(prop->obj());
ASSERT_EQ(Expression::kValue, prop->obj()->context());
VisitForValue(prop->obj(), kStack);
break;
case KEYED_PROPERTY:
Visit(prop->obj());
ASSERT_EQ(Expression::kValue, prop->obj()->context());
Visit(prop->key());
ASSERT_EQ(Expression::kValue, prop->key()->context());
VisitForValue(prop->obj(), kStack);
VisitForValue(prop->key(), kStack);
break;
}
// If we have a compound assignment: Get value of LHS expression and
// store in on top of the stack.
// Note: Relies on kValue context being 'stack'.
if (expr->is_compound()) {
Location saved_location = location_;
location_ = kStack;
switch (assign_type) {
case VARIABLE:
EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
......@@ -687,16 +645,19 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
__ push(result_register());
break;
}
location_ = saved_location;
}
// Evaluate RHS expression.
Expression* rhs = expr->value();
ASSERT_EQ(Expression::kValue, rhs->context());
Visit(rhs);
VisitForValue(rhs, kAccumulator);
// If we have a compount assignment: Apply operator.
if (expr->is_compound()) {
EmitCompoundAssignmentOp(expr->binary_op(), Expression::kValue);
Location saved_location = location_;
location_ = kAccumulator;
EmitBinaryOp(expr->binary_op(), Expression::kValue);
location_ = saved_location;
}
// Record source position before possible IC call.
......@@ -723,11 +684,8 @@ void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
// assign the exception value to the catch variable.
Comment cmnt(masm_, "[ CatchExtensionObject");
// Push key string.
ASSERT_EQ(Expression::kValue, expr->key()->context());
Visit(expr->key());
ASSERT_EQ(Expression::kValue, expr->value()->context());
Visit(expr->value());
VisitForValue(expr->key(), kStack);
VisitForValue(expr->value(), kStack);
// Create catch extension object.
__ CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
......@@ -738,8 +696,7 @@ void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
void FastCodeGenerator::VisitThrow(Throw* expr) {
Comment cmnt(masm_, "[ Throw");
Visit(expr->exception());
// Exception is on stack.
VisitForValue(expr->exception(), kStack);
__ CallRuntime(Runtime::kThrow, 1);
// Never returns here.
}
......
......@@ -47,6 +47,7 @@ class FastCodeGenerator: public AstVisitor {
is_eval_(is_eval),
nesting_stack_(NULL),
loop_depth_(0),
location_(kStack),
true_label_(NULL),
false_label_(NULL) {
}
......@@ -210,25 +211,37 @@ class FastCodeGenerator: public AstVisitor {
DISALLOW_COPY_AND_ASSIGN(ForIn);
};
enum Location {
kAccumulator,
kStack
};
int SlotOffset(Slot* slot);
// Emit code to complete the evaluation of an expression based on its
// expression context and given its value is in a register, non-lookup
// slot, or a literal.
// Emit code to convert a pure value (in a register, slot, as a literal,
// or on top of the stack) into the result expected according to an
// expression context.
void Apply(Expression::Context context, Register reg);
void Apply(Expression::Context context, Slot* slot, Register scratch);
void Apply(Expression::Context context, Slot* slot);
void Apply(Expression::Context context, Literal* lit);
// Emit code to complete the evaluation of an expression based on its
// expression context and given its value is on top of the stack.
void ApplyTOS(Expression::Context context);
// Emit code to discard count elements from the top of stack, then
// complete the evaluation of an expression based on its expression
// context and given its value is in a register.
// Emit code to discard count elements from the top of stack, then convert
// a pure value into the result expected according to an expression
// context.
void DropAndApply(int count, Expression::Context context, Register reg);
// Emit code to convert pure control flow to a pair of labels into the
// result expected according to an expression context.
void Apply(Expression::Context context,
Label* materialize_true,
Label* materialize_false);
// Helper function to convert a pure value into a test context. The value
// is expected on the stack or the accumulator, depending on the platform.
// See the platform-specific implementation for details.
void DoTest(Expression::Context context);
void Move(Slot* dst, Register source, Register scratch1, Register scratch2);
void Move(Register dst, Slot* source);
......@@ -237,9 +250,13 @@ class FastCodeGenerator: public AstVisitor {
// register.
MemOperand EmitSlotSearch(Slot* slot, Register scratch);
// Test the JavaScript value in source as if in a test context, compile
// control flow to a pair of labels.
void TestAndBranch(Register source, Label* true_label, Label* false_label);
void VisitForValue(Expression* expr, Location where) {
ASSERT(expr->context() == Expression::kValue);
Location saved_location = location_;
location_ = where;
Visit(expr);
location_ = saved_location;
}
void VisitForControl(Expression* expr, Label* if_true, Label* if_false) {
ASSERT(expr->context() == Expression::kTest ||
......@@ -277,20 +294,21 @@ class FastCodeGenerator: public AstVisitor {
// The receiver and the key is left on the stack by the IC.
void EmitKeyedPropertyLoad(Property* expr);
// Apply the compound assignment operator. Expects both operands on top
// of the stack.
void EmitCompoundAssignmentOp(Token::Value op, Expression::Context context);
// Apply the compound assignment operator. Expects the left operand on top
// of the stack and the right one in the accumulator.
void EmitBinaryOp(Token::Value op, Expression::Context context);
// Complete a variable assignment. The right-hand-side value is expected
// on top of the stack.
// in the accumulator.
void EmitVariableAssignment(Variable* var, Expression::Context context);
// Complete a named property assignment. The receiver and right-hand-side
// value are expected on top of the stack.
// Complete a named property assignment. The receiver is expected on top
// of the stack and the right-hand-side value in the accumulator.
void EmitNamedPropertyAssignment(Assignment* expr);
// Complete a keyed property assignment. The reciever, key, and
// right-hand-side value are expected on top of the stack.
// Complete a keyed property assignment. The receiver and key are
// expected on top of the stack and the right-hand-side value in the
// accumulator.
void EmitKeyedPropertyAssignment(Assignment* expr);
void SetFunctionPosition(FunctionLiteral* fun);
......@@ -338,6 +356,7 @@ class FastCodeGenerator: public AstVisitor {
NestedStatement* nesting_stack_;
int loop_depth_;
Location location_;
Label* true_label_;
Label* false_label_;
......
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 some expression contexts involving short-circuit boolean
// operations that did not otherwise have test coverage.
var x = 42;
// Literals in value/test context.
assertEquals(x, function () { return 0 || x }());
assertEquals(1, function () { return 1 || x }());
// Literals in test/value context.
assertEquals(0, function () { return 0 && x }());
assertEquals(x, function () { return 1 && x }());
// A value on top of the stack in value/test context.
assertEquals(x, function(y) { return y++ || x }(0));
assertEquals(1, function(y) { return y++ || x }(1));
// A value on top of the stack in a test/value context.
assertEquals(0, function(y) { return y++ && x }(0));
assertEquals(x, function(y) { return y++ && x }(1));
// An object literal in value context.
assertEquals(0, function () { return {x: 0}}().x);
// An object literal in value/test context.
assertEquals(0, function () { return {x: 0} || this }().x);
// An object literal in test/value context.
assertEquals(x, function () { return {x: 0} && this }().x);
// An array literal in value/test context.
assertEquals(0, function () { return [0,1] || new Array(x,1) }()[0]);
// An array literal in test/value context.
assertEquals(x, function () { return [0,1] && new Array(x,1) }()[0]);
// Slot assignment in value/test context.
assertEquals(x, function (y) { return (y = 0) || x }("?"));
assertEquals(1, function (y) { return (y = 1) || x }("?"));
// Slot assignment in test/value context.
assertEquals(0, function (y) { return (y = 0) && x }("?"));
assertEquals(x, function (y) { return (y = 1) && x }("?"));
// void in value context.
assertEquals(void 0, function () { return void x }());
// void in value/test context.
assertEquals(x, function () { return (void x) || x }());
// void in test/value context.
assertEquals(void 0, function () { return (void x) && x }());
// Unary not in value context.
assertEquals(false, function () { return !x }());
// Unary not in value/test context.
assertEquals(true, function (y) { return !y || x }(0));
assertEquals(x, function (y) { return !y || x }(1));
// Unary not in test/value context.
assertEquals(x, function (y) { return !y && x }(0));
assertEquals(false, function (y) { return !y && x }(1));
// Comparison in value context.
assertEquals(false, function () { return x < x; }());
// Comparison in value/test context.
assertEquals(x, function () { return x < x || x; }());
assertEquals(true, function () { return x <= x || x; }());
// Comparison in test/value context.
assertEquals(false, function () { return x < x && x; }());
assertEquals(x, function () { return x <= x && x; }());
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