Cleanup of contexts in the full code generator.
Review URL: http://codereview.chromium.org/3449004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5511 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
06c867404b
commit
94cf27373c
File diff suppressed because it is too large
Load Diff
12
src/ast.h
12
src/ast.h
@ -172,18 +172,6 @@ class Statement: public AstNode {
|
||||
|
||||
class Expression: public AstNode {
|
||||
public:
|
||||
enum Context {
|
||||
// Not assigned a context yet, or else will not be visited during
|
||||
// code generation.
|
||||
kUninitialized,
|
||||
// Evaluated for its side effects.
|
||||
kEffect,
|
||||
// Evaluated for its value (and side effects).
|
||||
kValue,
|
||||
// Evaluated for control flow (and side effects).
|
||||
kTest
|
||||
};
|
||||
|
||||
Expression() : bitfields_(0) {}
|
||||
|
||||
virtual Expression* AsExpression() { return this; }
|
||||
|
@ -332,30 +332,93 @@ bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::PrepareTest(Label* materialize_true,
|
||||
void FullCodeGenerator::EffectContext::Plug(Register reg) const {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const {
|
||||
// Move value into place.
|
||||
__ Move(result_register(), reg);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::StackValueContext::Plug(Register reg) const {
|
||||
// Move value into place.
|
||||
__ push(reg);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::TestContext::Plug(Register reg) const {
|
||||
// For simplicity we always test the accumulator register.
|
||||
__ Move(result_register(), reg);
|
||||
codegen()->DoTest(true_label_, false_label_, fall_through_);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EffectContext::PlugTOS() const {
|
||||
__ Drop(1);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const {
|
||||
__ pop(result_register());
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::StackValueContext::PlugTOS() const {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::TestContext::PlugTOS() const {
|
||||
// For simplicity we always test the accumulator register.
|
||||
__ pop(result_register());
|
||||
codegen()->DoTest(true_label_, false_label_, fall_through_);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EffectContext::PrepareTest(
|
||||
Label* materialize_true,
|
||||
Label* materialize_false,
|
||||
Label** if_true,
|
||||
Label** if_false,
|
||||
Label** fall_through) {
|
||||
switch (context_) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
case Expression::kEffect:
|
||||
Label** fall_through) const {
|
||||
// In an effect context, the true and the false case branch to the
|
||||
// same label.
|
||||
*if_true = *if_false = *fall_through = materialize_true;
|
||||
break;
|
||||
case Expression::kValue:
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::AccumulatorValueContext::PrepareTest(
|
||||
Label* materialize_true,
|
||||
Label* materialize_false,
|
||||
Label** if_true,
|
||||
Label** if_false,
|
||||
Label** fall_through) const {
|
||||
*if_true = *fall_through = materialize_true;
|
||||
*if_false = materialize_false;
|
||||
break;
|
||||
case Expression::kTest:
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::StackValueContext::PrepareTest(
|
||||
Label* materialize_true,
|
||||
Label* materialize_false,
|
||||
Label** if_true,
|
||||
Label** if_false,
|
||||
Label** fall_through) const {
|
||||
*if_true = *fall_through = materialize_true;
|
||||
*if_false = materialize_false;
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::TestContext::PrepareTest(
|
||||
Label* materialize_true,
|
||||
Label* materialize_false,
|
||||
Label** if_true,
|
||||
Label** if_false,
|
||||
Label** fall_through) const {
|
||||
*if_true = true_label_;
|
||||
*if_false = false_label_;
|
||||
*fall_through = fall_through_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -576,20 +639,20 @@ void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
|
||||
// Load only the operands that we need to materialize.
|
||||
if (constant == kNoConstants) {
|
||||
VisitForValue(left, kStack);
|
||||
VisitForValue(right, kAccumulator);
|
||||
VisitForStackValue(left);
|
||||
VisitForAccumulatorValue(right);
|
||||
} else if (constant == kRightConstant) {
|
||||
VisitForValue(left, kAccumulator);
|
||||
VisitForAccumulatorValue(left);
|
||||
} else {
|
||||
ASSERT(constant == kLeftConstant);
|
||||
VisitForValue(right, kAccumulator);
|
||||
VisitForAccumulatorValue(right);
|
||||
}
|
||||
|
||||
SetSourcePosition(expr->position());
|
||||
if (ShouldInlineSmiCase(op)) {
|
||||
EmitInlineSmiBinaryOp(expr, op, context_, mode, left, right, constant);
|
||||
EmitInlineSmiBinaryOp(expr, op, mode, left, right, constant);
|
||||
} else {
|
||||
EmitBinaryOp(op, context_, mode);
|
||||
EmitBinaryOp(op, mode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -603,39 +666,7 @@ void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
|
||||
Label eval_right, done;
|
||||
|
||||
// Set up the appropriate context for the left subexpression based
|
||||
// on the operation and our own context. Initially assume we can
|
||||
// inherit both true and false labels from our context.
|
||||
if (expr->op() == Token::OR) {
|
||||
switch (context_) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
VisitForControl(expr->left(), &done, &eval_right, &eval_right);
|
||||
break;
|
||||
case Expression::kValue:
|
||||
VisitLogicalForValue(expr->left(), expr->op(), location_, &done);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
VisitForControl(expr->left(), true_label_, &eval_right, &eval_right);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ASSERT_EQ(Token::AND, expr->op());
|
||||
switch (context_) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
VisitForControl(expr->left(), &eval_right, &done, &eval_right);
|
||||
break;
|
||||
case Expression::kValue:
|
||||
VisitLogicalForValue(expr->left(), expr->op(), location_, &done);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
VisitForControl(expr->left(), &eval_right, false_label_, &eval_right);
|
||||
break;
|
||||
}
|
||||
}
|
||||
context()->EmitLogicalLeft(expr, &eval_right, &done);
|
||||
|
||||
__ bind(&eval_right);
|
||||
Visit(expr->right());
|
||||
@ -644,43 +675,75 @@ void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitLogicalForValue(Expression* expr,
|
||||
Token::Value op,
|
||||
Location where,
|
||||
Label* done) {
|
||||
ASSERT(op == Token::AND || op == Token::OR);
|
||||
VisitForValue(expr, kAccumulator);
|
||||
__ push(result_register());
|
||||
|
||||
Label discard;
|
||||
switch (where) {
|
||||
case kAccumulator: {
|
||||
Label restore;
|
||||
if (op == Token::OR) {
|
||||
DoTest(&restore, &discard, &restore);
|
||||
void FullCodeGenerator::EffectContext::EmitLogicalLeft(BinaryOperation* expr,
|
||||
Label* eval_right,
|
||||
Label* done) const {
|
||||
if (expr->op() == Token::OR) {
|
||||
codegen()->VisitForControl(expr->left(), done, eval_right, eval_right);
|
||||
} else {
|
||||
DoTest(&discard, &restore, &restore);
|
||||
ASSERT(expr->op() == Token::AND);
|
||||
codegen()->VisitForControl(expr->left(), eval_right, done, eval_right);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::AccumulatorValueContext::EmitLogicalLeft(
|
||||
BinaryOperation* expr,
|
||||
Label* eval_right,
|
||||
Label* done) const {
|
||||
codegen()->Visit(expr->left());
|
||||
// We want the value in the accumulator for the test, and on the stack in case
|
||||
// we need it.
|
||||
__ push(result_register());
|
||||
Label discard, restore;
|
||||
if (expr->op() == Token::OR) {
|
||||
codegen()->DoTest(&restore, &discard, &restore);
|
||||
} else {
|
||||
ASSERT(expr->op() == Token::AND);
|
||||
codegen()->DoTest(&discard, &restore, &restore);
|
||||
}
|
||||
__ bind(&restore);
|
||||
__ pop(result_register());
|
||||
__ jmp(done);
|
||||
break;
|
||||
}
|
||||
case kStack: {
|
||||
if (op == Token::OR) {
|
||||
DoTest(done, &discard, &discard);
|
||||
} else {
|
||||
DoTest(&discard, done, &discard);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
__ bind(&discard);
|
||||
__ Drop(1);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::StackValueContext::EmitLogicalLeft(
|
||||
BinaryOperation* expr,
|
||||
Label* eval_right,
|
||||
Label* done) const {
|
||||
codegen()->VisitForAccumulatorValue(expr->left());
|
||||
// We want the value in the accumulator for the test, and on the stack in case
|
||||
// we need it.
|
||||
__ push(result_register());
|
||||
Label discard;
|
||||
if (expr->op() == Token::OR) {
|
||||
codegen()->DoTest(done, &discard, &discard);
|
||||
} else {
|
||||
ASSERT(expr->op() == Token::AND);
|
||||
codegen()->DoTest(&discard, done, &discard);
|
||||
}
|
||||
__ bind(&discard);
|
||||
__ Drop(1);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::TestContext::EmitLogicalLeft(BinaryOperation* expr,
|
||||
Label* eval_right,
|
||||
Label* done) const {
|
||||
if (expr->op() == Token::OR) {
|
||||
codegen()->VisitForControl(expr->left(),
|
||||
true_label_, eval_right, eval_right);
|
||||
} else {
|
||||
ASSERT(expr->op() == Token::AND);
|
||||
codegen()->VisitForControl(expr->left(),
|
||||
eval_right, false_label_, eval_right);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitBlock(Block* stmt) {
|
||||
Comment cmnt(masm_, "[ Block");
|
||||
Breakable nested_statement(this, stmt);
|
||||
@ -761,7 +824,7 @@ void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
|
||||
Comment cmnt(masm_, "[ ReturnStatement");
|
||||
SetStatementPosition(stmt);
|
||||
Expression* expr = stmt->expression();
|
||||
VisitForValue(expr, kAccumulator);
|
||||
VisitForAccumulatorValue(expr);
|
||||
|
||||
// Exit all nested statements.
|
||||
NestedStatement* current = nesting_stack_;
|
||||
@ -780,7 +843,7 @@ void FullCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
|
||||
Comment cmnt(masm_, "[ WithEnterStatement");
|
||||
SetStatementPosition(stmt);
|
||||
|
||||
VisitForValue(stmt->expression(), kStack);
|
||||
VisitForStackValue(stmt->expression());
|
||||
if (stmt->is_catch_block()) {
|
||||
__ CallRuntime(Runtime::kPushCatchContext, 1);
|
||||
} else {
|
||||
@ -1061,7 +1124,7 @@ void FullCodeGenerator::VisitConditional(Conditional* expr) {
|
||||
expr->then_expression_position());
|
||||
Visit(expr->then_expression());
|
||||
// If control flow falls through Visit, jump to done.
|
||||
if (context_ == Expression::kEffect || context_ == Expression::kValue) {
|
||||
if (!context()->IsTest()) {
|
||||
__ jmp(&done);
|
||||
}
|
||||
|
||||
@ -1070,7 +1133,7 @@ void FullCodeGenerator::VisitConditional(Conditional* expr) {
|
||||
expr->else_expression_position());
|
||||
Visit(expr->else_expression());
|
||||
// If control flow falls through Visit, merge it with true case here.
|
||||
if (context_ == Expression::kEffect || context_ == Expression::kValue) {
|
||||
if (!context()->IsTest()) {
|
||||
__ bind(&done);
|
||||
}
|
||||
}
|
||||
@ -1084,7 +1147,7 @@ void FullCodeGenerator::VisitSlot(Slot* expr) {
|
||||
|
||||
void FullCodeGenerator::VisitLiteral(Literal* expr) {
|
||||
Comment cmnt(masm_, "[ Literal");
|
||||
Apply(context_, expr);
|
||||
context()->Plug(expr->handle());
|
||||
}
|
||||
|
||||
|
||||
@ -1110,17 +1173,17 @@ void FullCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
|
||||
// Call runtime routine to allocate the catch extension object and
|
||||
// assign the exception value to the catch variable.
|
||||
Comment cmnt(masm_, "[ CatchExtensionObject");
|
||||
VisitForValue(expr->key(), kStack);
|
||||
VisitForValue(expr->value(), kStack);
|
||||
VisitForStackValue(expr->key());
|
||||
VisitForStackValue(expr->value());
|
||||
// Create catch extension object.
|
||||
__ CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
|
||||
Apply(context_, result_register());
|
||||
context()->Plug(result_register());
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitThrow(Throw* expr) {
|
||||
Comment cmnt(masm_, "[ Throw");
|
||||
VisitForValue(expr->exception(), kStack);
|
||||
VisitForStackValue(expr->exception());
|
||||
__ CallRuntime(Runtime::kThrow, 1);
|
||||
// Never returns here.
|
||||
}
|
||||
@ -1150,9 +1213,9 @@ int FullCodeGenerator::TryCatch::Exit(int stack_depth) {
|
||||
|
||||
void FullCodeGenerator::EmitRegExpCloneResult(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 1);
|
||||
VisitForValue(args->at(0), kStack);
|
||||
VisitForStackValue(args->at(0));
|
||||
__ CallRuntime(Runtime::kRegExpCloneResult, 1);
|
||||
Apply(context_, result_register());
|
||||
context()->Plug(result_register());
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
@ -71,10 +71,7 @@ class FullCodeGenerator: public AstVisitor {
|
||||
info_(NULL),
|
||||
nesting_stack_(NULL),
|
||||
loop_depth_(0),
|
||||
location_(kStack),
|
||||
true_label_(NULL),
|
||||
false_label_(NULL),
|
||||
fall_through_(NULL) {
|
||||
context_(NULL) {
|
||||
}
|
||||
|
||||
static Handle<Code> MakeCode(CompilationInfo* info);
|
||||
@ -232,11 +229,6 @@ class FullCodeGenerator: public AstVisitor {
|
||||
DISALLOW_COPY_AND_ASSIGN(ForIn);
|
||||
};
|
||||
|
||||
enum Location {
|
||||
kAccumulator,
|
||||
kStack
|
||||
};
|
||||
|
||||
enum ConstantOperand {
|
||||
kNoConstants,
|
||||
kLeftConstant,
|
||||
@ -262,39 +254,6 @@ class FullCodeGenerator: public AstVisitor {
|
||||
Expression* left,
|
||||
Expression* right);
|
||||
|
||||
// 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);
|
||||
|
||||
// Slot cannot have type Slot::LOOKUP.
|
||||
void Apply(Expression::Context context, Slot* slot);
|
||||
|
||||
void Apply(Expression::Context context, Literal* lit);
|
||||
void ApplyTOS(Expression::Context context);
|
||||
|
||||
// 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);
|
||||
|
||||
// Set up branch labels for a test expression.
|
||||
void PrepareTest(Label* materialize_true,
|
||||
Label* materialize_false,
|
||||
Label** if_true,
|
||||
Label** if_false,
|
||||
Label** fall_through);
|
||||
|
||||
// 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);
|
||||
|
||||
// Emit code to convert constant control flow (true or false) into
|
||||
// the result expected according to an expression context.
|
||||
void Apply(Expression::Context context, bool flag);
|
||||
|
||||
// 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.
|
||||
@ -316,39 +275,26 @@ class FullCodeGenerator: public AstVisitor {
|
||||
MemOperand EmitSlotSearch(Slot* slot, Register scratch);
|
||||
|
||||
void VisitForEffect(Expression* expr) {
|
||||
Expression::Context saved_context = context_;
|
||||
context_ = Expression::kEffect;
|
||||
EffectContext context(this);
|
||||
Visit(expr);
|
||||
context_ = saved_context;
|
||||
}
|
||||
|
||||
void VisitForValue(Expression* expr, Location where) {
|
||||
Expression::Context saved_context = context_;
|
||||
Location saved_location = location_;
|
||||
context_ = Expression::kValue;
|
||||
location_ = where;
|
||||
void VisitForAccumulatorValue(Expression* expr) {
|
||||
AccumulatorValueContext context(this);
|
||||
Visit(expr);
|
||||
}
|
||||
|
||||
void VisitForStackValue(Expression* expr) {
|
||||
StackValueContext context(this);
|
||||
Visit(expr);
|
||||
context_ = saved_context;
|
||||
location_ = saved_location;
|
||||
}
|
||||
|
||||
void VisitForControl(Expression* expr,
|
||||
Label* if_true,
|
||||
Label* if_false,
|
||||
Label* fall_through) {
|
||||
Expression::Context saved_context = context_;
|
||||
Label* saved_true = true_label_;
|
||||
Label* saved_false = false_label_;
|
||||
Label* saved_fall_through = fall_through_;
|
||||
context_ = Expression::kTest;
|
||||
true_label_ = if_true;
|
||||
false_label_ = if_false;
|
||||
fall_through_ = fall_through;
|
||||
TestContext context(this, if_true, if_false, fall_through);
|
||||
Visit(expr);
|
||||
context_ = saved_context;
|
||||
true_label_ = saved_true;
|
||||
false_label_ = saved_false;
|
||||
fall_through_ = saved_fall_through;
|
||||
}
|
||||
|
||||
void VisitDeclarations(ZoneList<Declaration*>* declarations);
|
||||
@ -398,7 +344,7 @@ class FullCodeGenerator: public AstVisitor {
|
||||
TypeofState typeof_state,
|
||||
Label* slow,
|
||||
Label* done);
|
||||
void EmitVariableLoad(Variable* expr, Expression::Context context);
|
||||
void EmitVariableLoad(Variable* expr);
|
||||
|
||||
// Platform-specific support for allocating a new closure based on
|
||||
// the given function info.
|
||||
@ -417,14 +363,12 @@ class FullCodeGenerator: public AstVisitor {
|
||||
// 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,
|
||||
OverwriteMode mode);
|
||||
|
||||
// Helper functions for generating inlined smi code for certain
|
||||
// binary operations.
|
||||
void EmitInlineSmiBinaryOp(Expression* expr,
|
||||
Token::Value op,
|
||||
Expression::Context context,
|
||||
OverwriteMode mode,
|
||||
Expression* left,
|
||||
Expression* right,
|
||||
@ -432,31 +376,26 @@ class FullCodeGenerator: public AstVisitor {
|
||||
|
||||
void EmitConstantSmiBinaryOp(Expression* expr,
|
||||
Token::Value op,
|
||||
Expression::Context context,
|
||||
OverwriteMode mode,
|
||||
bool left_is_constant_smi,
|
||||
Smi* value);
|
||||
|
||||
void EmitConstantSmiBitOp(Expression* expr,
|
||||
Token::Value op,
|
||||
Expression::Context context,
|
||||
OverwriteMode mode,
|
||||
Smi* value);
|
||||
|
||||
void EmitConstantSmiShiftOp(Expression* expr,
|
||||
Token::Value op,
|
||||
Expression::Context context,
|
||||
OverwriteMode mode,
|
||||
Smi* value);
|
||||
|
||||
void EmitConstantSmiAdd(Expression* expr,
|
||||
Expression::Context context,
|
||||
OverwriteMode mode,
|
||||
bool left_is_constant_smi,
|
||||
Smi* value);
|
||||
|
||||
void EmitConstantSmiSub(Expression* expr,
|
||||
Expression::Context context,
|
||||
OverwriteMode mode,
|
||||
bool left_is_constant_smi,
|
||||
Smi* value);
|
||||
@ -468,8 +407,7 @@ class FullCodeGenerator: public AstVisitor {
|
||||
// Complete a variable assignment. The right-hand-side value is expected
|
||||
// in the accumulator.
|
||||
void EmitVariableAssignment(Variable* var,
|
||||
Token::Value op,
|
||||
Expression::Context context);
|
||||
Token::Value op);
|
||||
|
||||
// Complete a named property assignment. The receiver is expected on top
|
||||
// of the stack and the right-hand-side value in the accumulator.
|
||||
@ -501,6 +439,10 @@ class FullCodeGenerator: public AstVisitor {
|
||||
|
||||
MacroAssembler* masm() { return masm_; }
|
||||
|
||||
class ExpressionContext;
|
||||
const ExpressionContext* context() { return context_; }
|
||||
void set_new_context(const ExpressionContext* context) { context_ = context; }
|
||||
|
||||
Handle<Script> script() { return info_->script(); }
|
||||
bool is_eval() { return info_->is_eval(); }
|
||||
FunctionLiteral* function() { return info_->function(); }
|
||||
@ -530,13 +472,7 @@ class FullCodeGenerator: public AstVisitor {
|
||||
// Handles the shortcutted logical binary operations in VisitBinaryOperation.
|
||||
void EmitLogicalOperation(BinaryOperation* expr);
|
||||
|
||||
void VisitForTypeofValue(Expression* expr, Location where);
|
||||
|
||||
void VisitLogicalForValue(Expression* expr,
|
||||
Token::Value op,
|
||||
Location where,
|
||||
Label* done);
|
||||
|
||||
void VisitForTypeofValue(Expression* expr);
|
||||
|
||||
MacroAssembler* masm_;
|
||||
CompilationInfo* info_;
|
||||
@ -545,11 +481,178 @@ class FullCodeGenerator: public AstVisitor {
|
||||
NestedStatement* nesting_stack_;
|
||||
int loop_depth_;
|
||||
|
||||
Expression::Context context_;
|
||||
Location location_;
|
||||
class ExpressionContext {
|
||||
public:
|
||||
explicit ExpressionContext(FullCodeGenerator* codegen)
|
||||
: masm_(codegen->masm()), old_(codegen->context()), codegen_(codegen) {
|
||||
codegen->set_new_context(this);
|
||||
}
|
||||
|
||||
virtual ~ExpressionContext() {
|
||||
codegen_->set_new_context(old_);
|
||||
}
|
||||
|
||||
// Convert constant control flow (true or false) to the result expected for
|
||||
// this expression context.
|
||||
virtual void Plug(bool flag) const = 0;
|
||||
|
||||
// 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 this
|
||||
// expression context.
|
||||
virtual void Plug(Register reg) const = 0;
|
||||
virtual void Plug(Slot* slot) const = 0;
|
||||
virtual void Plug(Handle<Object> lit) const = 0;
|
||||
virtual void Plug(Heap::RootListIndex index) const = 0;
|
||||
virtual void PlugTOS() const = 0;
|
||||
|
||||
// Emit code to convert pure control flow to a pair of unbound labels into
|
||||
// the result expected according to this expression context. The
|
||||
// implementation may decide to bind either of the labels.
|
||||
virtual void Plug(Label* materialize_true,
|
||||
Label* materialize_false) const = 0;
|
||||
|
||||
// Emit code to discard count elements from the top of stack, then convert
|
||||
// a pure value into the result expected according to this expression
|
||||
// context.
|
||||
virtual void DropAndPlug(int count, Register reg) const = 0;
|
||||
|
||||
// For shortcutting operations || and &&.
|
||||
virtual void EmitLogicalLeft(BinaryOperation* expr,
|
||||
Label* eval_right,
|
||||
Label* done) const = 0;
|
||||
|
||||
// Set up branch labels for a test expression. The three Label** parameters
|
||||
// are output parameters.
|
||||
virtual void PrepareTest(Label* materialize_true,
|
||||
Label* materialize_false,
|
||||
Label** if_true,
|
||||
Label** if_false,
|
||||
Label** fall_through) const = 0;
|
||||
|
||||
// Returns true if we are evaluating only for side effects (ie if the result
|
||||
// will be discarded.
|
||||
virtual bool IsEffect() const { return false; }
|
||||
|
||||
// Returns true if we are branching on the value rather than materializing
|
||||
// it.
|
||||
virtual bool IsTest() const { return false; }
|
||||
|
||||
protected:
|
||||
FullCodeGenerator* codegen() const { return codegen_; }
|
||||
MacroAssembler* masm() const { return masm_; }
|
||||
MacroAssembler* masm_;
|
||||
|
||||
private:
|
||||
const ExpressionContext* old_;
|
||||
FullCodeGenerator* codegen_;
|
||||
};
|
||||
|
||||
class AccumulatorValueContext : public ExpressionContext {
|
||||
public:
|
||||
explicit AccumulatorValueContext(FullCodeGenerator* codegen)
|
||||
: ExpressionContext(codegen) { }
|
||||
|
||||
virtual void Plug(bool flag) const;
|
||||
virtual void Plug(Register reg) const;
|
||||
virtual void Plug(Label* materialize_true, Label* materialize_false) const;
|
||||
virtual void Plug(Slot* slot) const;
|
||||
virtual void Plug(Handle<Object> lit) const;
|
||||
virtual void Plug(Heap::RootListIndex) const;
|
||||
virtual void PlugTOS() const;
|
||||
virtual void DropAndPlug(int count, Register reg) const;
|
||||
virtual void EmitLogicalLeft(BinaryOperation* expr,
|
||||
Label* eval_right,
|
||||
Label* done) const;
|
||||
virtual void PrepareTest(Label* materialize_true,
|
||||
Label* materialize_false,
|
||||
Label** if_true,
|
||||
Label** if_false,
|
||||
Label** fall_through) const;
|
||||
};
|
||||
|
||||
class StackValueContext : public ExpressionContext {
|
||||
public:
|
||||
explicit StackValueContext(FullCodeGenerator* codegen)
|
||||
: ExpressionContext(codegen) { }
|
||||
|
||||
virtual void Plug(bool flag) const;
|
||||
virtual void Plug(Register reg) const;
|
||||
virtual void Plug(Label* materialize_true, Label* materialize_false) const;
|
||||
virtual void Plug(Slot* slot) const;
|
||||
virtual void Plug(Handle<Object> lit) const;
|
||||
virtual void Plug(Heap::RootListIndex) const;
|
||||
virtual void PlugTOS() const;
|
||||
virtual void DropAndPlug(int count, Register reg) const;
|
||||
virtual void EmitLogicalLeft(BinaryOperation* expr,
|
||||
Label* eval_right,
|
||||
Label* done) const;
|
||||
virtual void PrepareTest(Label* materialize_true,
|
||||
Label* materialize_false,
|
||||
Label** if_true,
|
||||
Label** if_false,
|
||||
Label** fall_through) const;
|
||||
};
|
||||
|
||||
class TestContext : public ExpressionContext {
|
||||
public:
|
||||
explicit TestContext(FullCodeGenerator* codegen,
|
||||
Label* true_label,
|
||||
Label* false_label,
|
||||
Label* fall_through)
|
||||
: ExpressionContext(codegen),
|
||||
true_label_(true_label),
|
||||
false_label_(false_label),
|
||||
fall_through_(fall_through) { }
|
||||
|
||||
virtual void Plug(bool flag) const;
|
||||
virtual void Plug(Register reg) const;
|
||||
virtual void Plug(Label* materialize_true, Label* materialize_false) const;
|
||||
virtual void Plug(Slot* slot) const;
|
||||
virtual void Plug(Handle<Object> lit) const;
|
||||
virtual void Plug(Heap::RootListIndex) const;
|
||||
virtual void PlugTOS() const;
|
||||
virtual void DropAndPlug(int count, Register reg) const;
|
||||
virtual void EmitLogicalLeft(BinaryOperation* expr,
|
||||
Label* eval_right,
|
||||
Label* done) const;
|
||||
virtual void PrepareTest(Label* materialize_true,
|
||||
Label* materialize_false,
|
||||
Label** if_true,
|
||||
Label** if_false,
|
||||
Label** fall_through) const;
|
||||
virtual bool IsTest() const { return true; }
|
||||
|
||||
private:
|
||||
Label* true_label_;
|
||||
Label* false_label_;
|
||||
Label* fall_through_;
|
||||
};
|
||||
|
||||
class EffectContext : public ExpressionContext {
|
||||
public:
|
||||
explicit EffectContext(FullCodeGenerator* codegen)
|
||||
: ExpressionContext(codegen) { }
|
||||
|
||||
virtual void Plug(bool flag) const;
|
||||
virtual void Plug(Register reg) const;
|
||||
virtual void Plug(Label* materialize_true, Label* materialize_false) const;
|
||||
virtual void Plug(Slot* slot) const;
|
||||
virtual void Plug(Handle<Object> lit) const;
|
||||
virtual void Plug(Heap::RootListIndex) const;
|
||||
virtual void PlugTOS() const;
|
||||
virtual void DropAndPlug(int count, Register reg) const;
|
||||
virtual void EmitLogicalLeft(BinaryOperation* expr,
|
||||
Label* eval_right,
|
||||
Label* done) const;
|
||||
virtual void PrepareTest(Label* materialize_true,
|
||||
Label* materialize_false,
|
||||
Label** if_true,
|
||||
Label** if_false,
|
||||
Label** fall_through) const;
|
||||
virtual bool IsEffect() const { return true; }
|
||||
};
|
||||
|
||||
const ExpressionContext* context_;
|
||||
|
||||
friend class NestedStatement;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1361,6 +1361,13 @@ void MacroAssembler::Drop(int stack_elements) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Move(Register dst, Register src) {
|
||||
if (!dst.is(src)) {
|
||||
mov(dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Move(Register dst, Handle<Object> value) {
|
||||
mov(dst, value);
|
||||
}
|
||||
|
@ -505,6 +505,9 @@ class MacroAssembler: public Assembler {
|
||||
|
||||
void Call(Label* target) { call(target); }
|
||||
|
||||
// Move if the registers are not identical.
|
||||
void Move(Register target, Register source);
|
||||
|
||||
void Move(Register target, Handle<Object> value);
|
||||
|
||||
Handle<Object> CodeObject() { return code_object_; }
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1207,6 +1207,15 @@ SmiIndex MacroAssembler::SmiToNegativeIndex(Register dst,
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Move(Register dst, Register src) {
|
||||
if (!dst.is(src)) {
|
||||
movq(dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void MacroAssembler::Move(Register dst, Handle<Object> source) {
|
||||
ASSERT(!source->IsFailure());
|
||||
if (source->IsSmi()) {
|
||||
|
@ -557,6 +557,9 @@ class MacroAssembler: public Assembler {
|
||||
void Set(Register dst, int64_t x);
|
||||
void Set(const Operand& dst, int64_t x);
|
||||
|
||||
// Move if the registers are not identical.
|
||||
void Move(Register target, Register source);
|
||||
|
||||
// Handle support
|
||||
void Move(Register dst, Handle<Object> source);
|
||||
void Move(const Operand& dst, Handle<Object> source);
|
||||
|
Loading…
Reference in New Issue
Block a user