Commit 35939fd9 authored by iposva@chromium.org's avatar iposva@chromium.org

Track whether a node or variable are likely to be a Smi value. Propagate that

knowledge in the AST and inline the Smi check into the generated code if it
is deemed high value (e.g. in loops).

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@630 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent d0b263c3
......@@ -150,6 +150,12 @@ class Expression: public Node {
// statement. This is used to transform postfix increments to
// (faster) prefix increments.
virtual void MarkAsStatement() { /* do nothing */ }
// Static type information for this expression.
StaticType* type() { return &type_; }
private:
StaticType type_;
};
......
......@@ -175,7 +175,8 @@ CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script,
cc_reg_(no_condition),
state_(NULL),
is_inside_try_(false),
break_stack_height_(0) {
break_stack_height_(0),
loop_nesting_(0) {
}
......@@ -786,6 +787,7 @@ class DeferredInlineBinaryOperation: public DeferredCode {
void CodeGenerator::GenericBinaryOperation(Token::Value op,
StaticType* type,
OverwriteMode overwrite_mode) {
Comment cmnt(masm_, "[ BinaryOperation");
Comment cmnt_token(masm_, Token::String(op));
......@@ -808,11 +810,19 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
case Token::SHL:
case Token::SHR:
case Token::SAR:
flags = SMI_CODE_INLINED;
// Bit operations always assume they likely operate on Smis. Still only
// generate the inline Smi check code if this operation is part of a loop.
flags = (loop_nesting() > 0)
? SMI_CODE_INLINED
: SMI_CODE_IN_STUB;
break;
default:
flags = SMI_CODE_IN_STUB;
// By default only inline the Smi check code for likely smis if this
// operation is part of a loop.
flags = ((loop_nesting() > 0) && type->IsLikelySmi())
? SMI_CODE_INLINED
: SMI_CODE_IN_STUB;
break;
}
......@@ -985,6 +995,7 @@ class DeferredInlinedSmiSubReversed: public DeferredCode {
void CodeGenerator::SmiOperation(Token::Value op,
StaticType* type,
Handle<Object> value,
bool reversed,
OverwriteMode overwrite_mode) {
......@@ -1046,7 +1057,7 @@ void CodeGenerator::SmiOperation(Token::Value op,
frame_->Pop(eax);
frame_->Push(Immediate(value));
frame_->Push(eax);
GenericBinaryOperation(op, overwrite_mode);
GenericBinaryOperation(op, type, overwrite_mode);
} else {
int shift_value = int_value & 0x1f; // only least significant 5 bits
DeferredCode* deferred =
......@@ -1068,7 +1079,7 @@ void CodeGenerator::SmiOperation(Token::Value op,
frame_->Pop(eax);
frame_->Push(Immediate(value));
frame_->Push(eax);
GenericBinaryOperation(op, overwrite_mode);
GenericBinaryOperation(op, type, overwrite_mode);
} else {
int shift_value = int_value & 0x1f; // only least significant 5 bits
DeferredCode* deferred =
......@@ -1096,7 +1107,7 @@ void CodeGenerator::SmiOperation(Token::Value op,
frame_->Pop(eax);
frame_->Push(Immediate(value));
frame_->Push(eax);
GenericBinaryOperation(op, overwrite_mode);
GenericBinaryOperation(op, type, overwrite_mode);
} else {
int shift_value = int_value & 0x1f; // only least significant 5 bits
DeferredCode* deferred =
......@@ -1155,7 +1166,7 @@ void CodeGenerator::SmiOperation(Token::Value op,
frame_->Push(Immediate(value));
frame_->Push(eax);
}
GenericBinaryOperation(op, overwrite_mode);
GenericBinaryOperation(op, type, overwrite_mode);
break;
}
}
......@@ -1747,6 +1758,8 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
__ jmp(&entry);
}
IncrementLoopNesting();
// body
__ bind(&loop);
CheckStack(); // TODO(1222600): ignore if body contains calls.
......@@ -1779,6 +1792,8 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
break;
}
DecrementLoopNesting();
// exit
__ bind(node->break_target());
}
......@@ -2587,10 +2602,11 @@ void CodeGenerator::VisitAssignment(Assignment* node) {
target.GetValue(NOT_INSIDE_TYPEOF);
Literal* literal = node->value()->AsLiteral();
if (IsInlineSmi(literal)) {
SmiOperation(node->binary_op(), literal->handle(), false, NO_OVERWRITE);
SmiOperation(node->binary_op(), node->type(), literal->handle(), false,
NO_OVERWRITE);
} else {
Load(node->value());
GenericBinaryOperation(node->binary_op());
GenericBinaryOperation(node->binary_op(), node->type());
}
}
......@@ -3452,16 +3468,16 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
if (IsInlineSmi(rliteral)) {
Load(node->left());
SmiOperation(node->op(), rliteral->handle(), false, overwrite_mode);
SmiOperation(node->op(), node->type(), rliteral->handle(), false,
overwrite_mode);
} else if (IsInlineSmi(lliteral)) {
Load(node->right());
SmiOperation(node->op(), lliteral->handle(), true, overwrite_mode);
SmiOperation(node->op(), node->type(), lliteral->handle(), true,
overwrite_mode);
} else {
Load(node->left());
Load(node->right());
GenericBinaryOperation(node->op(), overwrite_mode);
GenericBinaryOperation(node->op(), node->type(), overwrite_mode);
}
}
}
......
......@@ -238,6 +238,11 @@ class CodeGenerator: public Visitor {
Label* true_target() const { return state_->true_target(); }
Label* false_target() const { return state_->false_target(); }
// Track loop nesting level.
int loop_nesting() const { return loop_nesting_; }
void IncrementLoopNesting() { loop_nesting_++; }
void DecrementLoopNesting() { loop_nesting_--; }
// Node visitors.
#define DEF_VISIT(type) \
......@@ -287,6 +292,7 @@ class CodeGenerator: public Visitor {
void ToBoolean(Label* true_target, Label* false_target);
void GenericBinaryOperation(Token::Value op,
StaticType* type,
const OverwriteMode overwrite_mode = NO_OVERWRITE);
void Comparison(Condition cc, bool strict = false);
......@@ -297,6 +303,7 @@ class CodeGenerator: public Visitor {
bool IsInlineSmi(Literal* literal);
void SmiComparison(Condition cc, Handle<Object> value, bool strict = false);
void SmiOperation(Token::Value op,
StaticType* type,
Handle<Object> value,
bool reversed,
OverwriteMode overwrite_mode);
......@@ -412,6 +419,7 @@ class CodeGenerator: public Visitor {
CodeGenState* state_;
bool is_inside_try_;
int break_stack_height_;
int loop_nesting_;
// Labels
Label function_return_;
......
......@@ -65,6 +65,9 @@ static Handle<Code> MakeCode(FunctionLiteral* literal,
}
#endif
// Optimize the AST.
Rewriter::Optimize(literal);
// Generate code and return it.
Handle<Code> result = CodeGenerator::MakeCode(literal, script, is_eval);
return result;
......
......@@ -160,6 +160,9 @@ DEFINE_bool(h, false, "print this message")
// parser.cc
DEFINE_bool(allow_natives_syntax, false, "allow natives syntax")
// rewriter.cc
DEFINE_bool(optimize_ast, true, "optimize the ast")
// simulator-arm.cc
DEFINE_bool(trace_sim, false, "trace simulator execution")
DEFINE_int(stop_sim_at, 0, "Simulator stop after x number of instructions")
......
......@@ -588,8 +588,13 @@ class IndentedScope BASE_EMBEDDED {
ast_printer_->inc_indent();
}
explicit IndentedScope(const char* txt) {
explicit IndentedScope(const char* txt, StaticType* type = NULL) {
ast_printer_->PrintIndented(txt);
if ((type != NULL) && (type->IsKnown())) {
ast_printer_->Print(" (type = ");
ast_printer_->Print(StaticType::Type2String(type));
ast_printer_->Print(")");
}
ast_printer_->Print("\n");
ast_printer_->inc_indent();
}
......@@ -645,13 +650,20 @@ void AstPrinter::PrintLiteralIndented(const char* info,
void AstPrinter::PrintLiteralWithModeIndented(const char* info,
Variable* var,
Handle<Object> value) {
Handle<Object> value,
StaticType* type) {
if (var == NULL) {
PrintLiteralIndented(info, value, true);
} else {
EmbeddedVector<char, 256> buf;
OS::SNPrintF(buf, "%s (mode = %s)", info,
Variable::Mode2String(var->mode()));
if (type->IsKnown()) {
OS::SNPrintF(buf, "%s (mode = %s, type = %s)", info,
Variable::Mode2String(var->mode()),
StaticType::Type2String(type));
} else {
OS::SNPrintF(buf, "%s (mode = %s)", info,
Variable::Mode2String(var->mode()));
}
PrintLiteralIndented(buf.start(), value, true);
}
}
......@@ -706,7 +718,8 @@ void AstPrinter::PrintParameters(Scope* scope) {
IndentedScope indent("PARAMS");
for (int i = 0; i < scope->num_parameters(); i++) {
PrintLiteralWithModeIndented("VAR ", scope->parameter(i),
scope->parameter(i)->name());
scope->parameter(i)->name(),
scope->parameter(i)->type());
}
}
}
......@@ -748,9 +761,10 @@ void AstPrinter::VisitBlock(Block* node) {
void AstPrinter::VisitDeclaration(Declaration* node) {
if (node->fun() == NULL) {
// var or const declarations
PrintLiteralWithModeIndented(
Variable::Mode2String(node->mode()),
node->proxy()->AsVariable(), node->proxy()->name());
PrintLiteralWithModeIndented(Variable::Mode2String(node->mode()),
node->proxy()->AsVariable(),
node->proxy()->name(),
node->proxy()->AsVariable()->type());
} else {
// function declarations
PrintIndented("FUNCTION ");
......@@ -960,7 +974,8 @@ void AstPrinter::VisitSlot(Slot* node) {
void AstPrinter::VisitVariableProxy(VariableProxy* node) {
PrintLiteralWithModeIndented("VAR PROXY", node->AsVariable(), node->name());
PrintLiteralWithModeIndented("VAR PROXY", node->AsVariable(), node->name(),
node->type());
Variable* var = node->var();
if (var != NULL && var->rewrite() != NULL) {
IndentedScope indent;
......@@ -970,7 +985,7 @@ void AstPrinter::VisitVariableProxy(VariableProxy* node) {
void AstPrinter::VisitAssignment(Assignment* node) {
IndentedScope indent(Token::Name(node->op()));
IndentedScope indent(Token::Name(node->op()), node->type());
Visit(node->target());
Visit(node->value());
}
......@@ -1021,21 +1036,28 @@ void AstPrinter::VisitUnaryOperation(UnaryOperation* node) {
void AstPrinter::VisitCountOperation(CountOperation* node) {
EmbeddedVector<char, 128> buf;
OS::SNPrintF(buf, "%s %s", (node->is_prefix() ? "PRE" : "POST"),
Token::Name(node->op()));
if (node->type()->IsKnown()) {
OS::SNPrintF(buf, "%s %s (type = %s)",
(node->is_prefix() ? "PRE" : "POST"),
Token::Name(node->op()),
StaticType::Type2String(node->type()));
} else {
OS::SNPrintF(buf, "%s %s", (node->is_prefix() ? "PRE" : "POST"),
Token::Name(node->op()));
}
PrintIndentedVisit(buf.start(), node->expression());
}
void AstPrinter::VisitBinaryOperation(BinaryOperation* node) {
IndentedScope indent(Token::Name(node->op()));
IndentedScope indent(Token::Name(node->op()), node->type());
Visit(node->left());
Visit(node->right());
}
void AstPrinter::VisitCompareOperation(CompareOperation* node) {
IndentedScope indent(Token::Name(node->op()));
IndentedScope indent(Token::Name(node->op()), node->type());
Visit(node->left());
Visit(node->right());
}
......
......@@ -101,7 +101,8 @@ class AstPrinter: public PrettyPrinter {
void PrintLiteralIndented(const char* info, Handle<Object> value, bool quote);
void PrintLiteralWithModeIndented(const char* info,
Variable* var,
Handle<Object> value);
Handle<Object> value,
StaticType* type);
void PrintLabelsIndented(const char* info, ZoneStringList* labels);
void inc_indent() { indent_++; }
......
......@@ -34,6 +34,441 @@
namespace v8 { namespace internal {
class AstOptimizer: public Visitor {
public:
explicit AstOptimizer() {
}
void Optimize(ZoneList<Statement*>* statements);
private:
// Helpers
void OptimizeArguments(ZoneList<Expression*>* arguments);
// Node visitors.
#define DEF_VISIT(type) \
virtual void Visit##type(type* node);
NODE_LIST(DEF_VISIT)
#undef DEF_VISIT
DISALLOW_COPY_AND_ASSIGN(AstOptimizer);
};
void AstOptimizer::Optimize(ZoneList<Statement*>* statements) {
int len = statements->length();
for (int i = 0; i < len; i++) {
Visit(statements->at(i));
}
}
void AstOptimizer::OptimizeArguments(ZoneList<Expression*>* arguments) {
for (int i = 0; i < arguments->length(); i++) {
Visit(arguments->at(i));
}
}
void AstOptimizer::VisitBlock(Block* node) {
Optimize(node->statements());
}
void AstOptimizer::VisitExpressionStatement(ExpressionStatement* node) {
Visit(node->expression());
}
void AstOptimizer::VisitIfStatement(IfStatement* node) {
Visit(node->condition());
Visit(node->then_statement());
if (node->HasElseStatement()) {
Visit(node->else_statement());
}
}
void AstOptimizer::VisitLoopStatement(LoopStatement* node) {
if (node->init() != NULL) {
Visit(node->init());
}
if (node->cond() != NULL) {
Visit(node->cond());
}
if (node->body() != NULL) {
Visit(node->body());
}
if (node->next() != NULL) {
Visit(node->next());
}
}
void AstOptimizer::VisitForInStatement(ForInStatement* node) {
Visit(node->each());
Visit(node->enumerable());
Visit(node->body());
}
void AstOptimizer::VisitTryCatch(TryCatch* node) {
Visit(node->try_block());
Visit(node->catch_var());
Visit(node->catch_block());
}
void AstOptimizer::VisitTryFinally(TryFinally* node) {
Visit(node->try_block());
Visit(node->finally_block());
}
void AstOptimizer::VisitSwitchStatement(SwitchStatement* node) {
Visit(node->tag());
for (int i = 0; i < node->cases()->length(); i++) {
CaseClause* clause = node->cases()->at(i);
if (!clause->is_default()) {
Visit(clause->label());
}
Optimize(clause->statements());
}
}
void AstOptimizer::VisitContinueStatement(ContinueStatement* node) {
USE(node);
}
void AstOptimizer::VisitBreakStatement(BreakStatement* node) {
USE(node);
}
void AstOptimizer::VisitDeclaration(Declaration* node) {
// Will not be reached by the current optimizations.
USE(node);
}
void AstOptimizer::VisitEmptyStatement(EmptyStatement* node) {
USE(node);
}
void AstOptimizer::VisitReturnStatement(ReturnStatement* node) {
Visit(node->expression());
}
void AstOptimizer::VisitWithEnterStatement(WithEnterStatement* node) {
Visit(node->expression());
}
void AstOptimizer::VisitWithExitStatement(WithExitStatement* node) {
USE(node);
}
void AstOptimizer::VisitDebuggerStatement(DebuggerStatement* node) {
USE(node);
}
void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) {
USE(node);
}
void AstOptimizer::VisitFunctionBoilerplateLiteral(
FunctionBoilerplateLiteral* node) {
USE(node);
}
void AstOptimizer::VisitConditional(Conditional* node) {
Visit(node->condition());
Visit(node->then_expression());
Visit(node->else_expression());
}
void AstOptimizer::VisitSlot(Slot* node) {
USE(node);
}
void AstOptimizer::VisitVariableProxy(VariableProxy* node) {
Variable* var = node->AsVariable();
if (var != NULL) {
if (var->type()->IsKnown()) {
node->type()->CopyFrom(var->type());
} else if (node->type()->IsLikelySmi()) {
var->type()->SetAsLikelySmi();
}
}
}
void AstOptimizer::VisitLiteral(Literal* node) {
Handle<Object> literal = node->handle();
if (literal->IsSmi()) {
node->type()->SetAsLikelySmi();
}
}
void AstOptimizer::VisitRegExpLiteral(RegExpLiteral* node) {
USE(node);
}
void AstOptimizer::VisitArrayLiteral(ArrayLiteral* node) {
for (int i = 0; i < node->values()->length(); i++) {
Visit(node->values()->at(i));
}
}
void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) {
for (int i = 0; i < node->properties()->length(); i++) {
Visit(node->properties()->at(i)->key());
Visit(node->properties()->at(i)->value());
}
}
void AstOptimizer::VisitAssignment(Assignment* node) {
switch (node->op()) {
case Token::INIT_VAR:
case Token::INIT_CONST:
case Token::ASSIGN:
// No type can be infered from the general assignment.
break;
case Token::ASSIGN_BIT_OR:
case Token::ASSIGN_BIT_XOR:
case Token::ASSIGN_BIT_AND:
case Token::ASSIGN_SHL:
case Token::ASSIGN_SAR:
case Token::ASSIGN_SHR:
node->type()->SetAsLikelySmiIfUnknown();
node->target()->type()->SetAsLikelySmiIfUnknown();
node->value()->type()->SetAsLikelySmiIfUnknown();
break;
case Token::ASSIGN_ADD:
case Token::ASSIGN_SUB:
case Token::ASSIGN_MUL:
case Token::ASSIGN_DIV:
case Token::ASSIGN_MOD:
if (node->type()->IsLikelySmi()) {
node->target()->type()->SetAsLikelySmiIfUnknown();
node->value()->type()->SetAsLikelySmiIfUnknown();
}
break;
default:
UNREACHABLE();
break;
}
Visit(node->target());
Visit(node->value());
switch (node->op()) {
case Token::INIT_VAR:
case Token::INIT_CONST:
case Token::ASSIGN:
// Pure assigment copies the type from the value.
node->type()->CopyFrom(node->value()->type());
break;
case Token::ASSIGN_BIT_OR:
case Token::ASSIGN_BIT_XOR:
case Token::ASSIGN_BIT_AND:
case Token::ASSIGN_SHL:
case Token::ASSIGN_SAR:
case Token::ASSIGN_SHR:
// Should have been setup above already.
break;
case Token::ASSIGN_ADD:
case Token::ASSIGN_SUB:
case Token::ASSIGN_MUL:
case Token::ASSIGN_DIV:
case Token::ASSIGN_MOD:
if (node->type()->IsUnknown()) {
if (node->target()->type()->IsLikelySmi() ||
node->value()->type()->IsLikelySmi()) {
node->type()->SetAsLikelySmi();
}
}
break;
default:
UNREACHABLE();
break;
}
// Since this is an assignment. We have to propagate this node's type to the
// variable.
VariableProxy* proxy = node->target()->AsVariableProxy();
if (proxy != NULL) {
Variable* var = proxy->AsVariable();
if (var != NULL) {
StaticType* var_type = var->type();
if (var_type->IsUnknown()) {
var_type->CopyFrom(node->type());
} else if (var_type->IsLikelySmi()) {
// We do not reset likely types to Unknown.
}
}
}
}
void AstOptimizer::VisitThrow(Throw* node) {
Visit(node->exception());
}
void AstOptimizer::VisitProperty(Property* node) {
Visit(node->obj());
Visit(node->key());
}
void AstOptimizer::VisitCall(Call* node) {
Visit(node->expression());
OptimizeArguments(node->arguments());
}
void AstOptimizer::VisitCallNew(CallNew* node) {
Visit(node->expression());
OptimizeArguments(node->arguments());
}
void AstOptimizer::VisitCallRuntime(CallRuntime* node) {
OptimizeArguments(node->arguments());
}
void AstOptimizer::VisitUnaryOperation(UnaryOperation* node) {
Visit(node->expression());
}
void AstOptimizer::VisitCountOperation(CountOperation* node) {
// Count operations assume that they work on Smis.
node->type()->SetAsLikelySmiIfUnknown();
node->expression()->type()->SetAsLikelySmiIfUnknown();
Visit(node->expression());
}
void AstOptimizer::VisitBinaryOperation(BinaryOperation* node) {
// Depending on the operation we can propagate this node's type down the
// AST nodes.
switch (node->op()) {
case Token::COMMA:
case Token::OR:
case Token::AND:
break;
case Token::BIT_OR:
case Token::BIT_XOR:
case Token::BIT_AND:
case Token::SHL:
case Token::SAR:
case Token::SHR:
node->type()->SetAsLikelySmiIfUnknown();
node->left()->type()->SetAsLikelySmiIfUnknown();
node->right()->type()->SetAsLikelySmiIfUnknown();
break;
case Token::ADD:
case Token::SUB:
case Token::MUL:
case Token::DIV:
case Token::MOD:
if (node->type()->IsLikelySmi()) {
node->left()->type()->SetAsLikelySmiIfUnknown();
node->right()->type()->SetAsLikelySmiIfUnknown();
}
break;
default:
UNREACHABLE();
break;
}
Visit(node->left());
Visit(node->right());
// After visiting the operand nodes we have to check if this node's type
// can be updated. If it does, then we can push that information down
// towards the leafs again if the new information is an upgrade over the
// previous type of the operand nodes.
if (node->type()->IsUnknown()) {
if (node->left()->type()->IsLikelySmi() ||
node->right()->type()->IsLikelySmi()) {
node->type()->SetAsLikelySmi();
}
if (node->type()->IsLikelySmi()) {
// The type of this node changed to LIKELY_SMI. Propagate this knowlege
// down through the nodes.
if (node->left()->type()->IsUnknown()) {
node->left()->type()->SetAsLikelySmi();
Visit(node->left());
}
if (node->right()->type()->IsUnknown()) {
node->right()->type()->SetAsLikelySmi();
Visit(node->right());
}
}
}
}
void AstOptimizer::VisitCompareOperation(CompareOperation* node) {
if (node->type()->IsKnown()) {
// Propagate useful information down towards the leafs.
node->left()->type()->SetAsLikelySmiIfUnknown();
node->right()->type()->SetAsLikelySmiIfUnknown();
}
Visit(node->left());
Visit(node->right());
// After visiting the operand nodes we have to check if this node's type
// can be updated. If it does, then we can push that information down
// towards the leafs again if the new information is an upgrade over the
// previous type of the operand nodes.
if (node->type()->IsUnknown()) {
if (node->left()->type()->IsLikelySmi() ||
node->right()->type()->IsLikelySmi()) {
node->type()->SetAsLikelySmi();
}
if (node->type()->IsLikelySmi()) {
// The type of this node changed to LIKELY_SMI. Propagate this knowlege
// down through the nodes.
if (node->left()->type()->IsUnknown()) {
node->left()->type()->SetAsLikelySmi();
Visit(node->left());
}
if (node->right()->type()->IsUnknown()) {
node->right()->type()->SetAsLikelySmi();
Visit(node->right());
}
}
}
}
void AstOptimizer::VisitThisFunction(ThisFunction* node) {
USE(node);
}
class Processor: public Visitor {
public:
explicit Processor(VariableProxy* result)
......@@ -326,4 +761,18 @@ bool Rewriter::Process(FunctionLiteral* function) {
}
void Rewriter::Optimize(FunctionLiteral* function) {
ZoneList<Statement*>* body = function->body();
if (body->is_empty()) return;
if (FLAG_optimize_ast) {
Scope* scope = function->scope();
if (!scope->is_global_scope()) {
AstOptimizer optimizer;
optimizer.Optimize(body);
}
}
}
} } // namespace v8::internal
......@@ -44,6 +44,7 @@ namespace v8 { namespace internal {
class Rewriter {
public:
static bool Process(FunctionLiteral* function);
static void Optimize(FunctionLiteral* function);
};
......
......@@ -84,6 +84,23 @@ void UseCount::Print() {
#endif
// ----------------------------------------------------------------------------
// Implementation StaticType.
char* StaticType::Type2String(StaticType* type) {
switch (type->kind_) {
case UNKNOWN:
return "UNKNOWN";
case LIKELY_SMI:
return "LIKELY_SMI";
default:
UNREACHABLE();
}
return "UNREACHABLE";
}
// ----------------------------------------------------------------------------
// Implementation Variable.
......
......@@ -61,6 +61,48 @@ class UseCount BASE_EMBEDDED {
};
// Variables and AST expression nodes can track their "type" to enable
// optimizations and removal of redundant checks when generating code.
class StaticType BASE_EMBEDDED {
public:
enum Kind {
UNKNOWN,
LIKELY_SMI
};
StaticType() : kind_(UNKNOWN) {}
bool Is(Kind kind) const { return kind_ == kind; }
bool IsKnown() const { return !Is(UNKNOWN); }
bool IsUnknown() const { return Is(UNKNOWN); }
bool IsLikelySmi() const { return Is(LIKELY_SMI); }
void CopyFrom(StaticType* other) {
kind_ = other->kind_;
}
static char* Type2String(StaticType* type);
// LIKELY_SMI accessors
void SetAsLikelySmi() {
kind_ = LIKELY_SMI;
}
void SetAsLikelySmiIfUnknown() {
if (IsUnknown()) {
SetAsLikelySmi();
}
}
private:
Kind kind_;
DISALLOW_COPY_AND_ASSIGN(StaticType);
};
// The AST refers to variables via VariableProxies - placeholders for the actual
// variables. Variables themselves are never directly referred to from the AST,
// they are maintained by scopes, and referred to from VariableProxies and Slots
......@@ -114,6 +156,8 @@ class Variable: public ZoneObject {
Expression* rewrite() const { return rewrite_; }
Slot* slot() const;
StaticType* type() { return &type_; }
private:
Variable(Scope* scope, Handle<String> name, Mode mode, bool is_valid_LHS,
bool is_this);
......@@ -129,6 +173,9 @@ class Variable: public ZoneObject {
UseCount var_uses_; // uses of the variable value
UseCount obj_uses_; // uses of the object the variable points to
// Static type information
StaticType type_;
// Code generation.
// rewrite_ is usually a Slot or a Property, but maybe any expression.
Expression* rewrite_;
......
......@@ -245,6 +245,7 @@
/* Begin PBXFileReference section */
8900116B0E71CA2300F91F35 /* libraries.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = libraries.cc; sourceTree = "<group>"; };
89471C7F0EB23EE400B6874B /* flag-definitions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "flag-definitions.h"; sourceTree = "<group>"; };
89495E460E79FC23001F68C3 /* compilation-cache.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "compilation-cache.cc"; sourceTree = "<group>"; };
89495E470E79FC23001F68C3 /* compilation-cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "compilation-cache.h"; sourceTree = "<group>"; };
8964482B0E9C00F700E7C516 /* codegen-ia32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "codegen-ia32.h"; sourceTree = "<group>"; };
......@@ -616,6 +617,7 @@
897FF1310E719B8F00D62E90 /* execution.h */,
897FF1320E719B8F00D62E90 /* factory.cc */,
897FF1330E719B8F00D62E90 /* factory.h */,
89471C7F0EB23EE400B6874B /* flag-definitions.h */,
897FF1350E719B8F00D62E90 /* flags.cc */,
897FF1360E719B8F00D62E90 /* flags.h */,
897FF1370E719B8F00D62E90 /* frames-arm.cc */,
......
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