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_++; }
......
This diff is collapsed.
......@@ -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