// 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_;
};
cc_reg_(no_condition),
state_(NULL),
is_inside_try_(false),
- break_stack_height_(0) {
+ break_stack_height_(0),
+ loop_nesting_(0) {
}
void CodeGenerator::GenericBinaryOperation(Token::Value op,
+ StaticType* type,
OverwriteMode overwrite_mode) {
Comment cmnt(masm_, "[ BinaryOperation");
Comment cmnt_token(masm_, Token::String(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;
}
void CodeGenerator::SmiOperation(Token::Value op,
+ StaticType* type,
Handle<Object> value,
bool reversed,
OverwriteMode overwrite_mode) {
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 =
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 =
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 =
frame_->Push(Immediate(value));
frame_->Push(eax);
}
- GenericBinaryOperation(op, overwrite_mode);
+ GenericBinaryOperation(op, type, overwrite_mode);
break;
}
}
__ jmp(&entry);
}
+ IncrementLoopNesting();
+
// body
__ bind(&loop);
CheckStack(); // TODO(1222600): ignore if body contains calls.
break;
}
+ DecrementLoopNesting();
+
// exit
__ bind(node->break_target());
}
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());
}
}
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);
}
}
}
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) \
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);
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);
CodeGenState* state_;
bool is_inside_try_;
int break_stack_height_;
+ int loop_nesting_;
// Labels
Label function_return_;
}
#endif
+ // Optimize the AST.
+ Rewriter::Optimize(literal);
+
// Generate code and return it.
Handle<Code> result = CodeGenerator::MakeCode(literal, script, is_eval);
return result;
// 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")
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();
}
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);
}
}
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());
}
}
}
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 ");
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;
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());
}
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());
}
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_++; }
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)
}
+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
class Rewriter {
public:
static bool Process(FunctionLiteral* function);
+ static void Optimize(FunctionLiteral* function);
};
#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.
};
+// 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
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);
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_;
/* 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>"; };
897FF1310E719B8F00D62E90 /* execution.h */,
897FF1320E719B8F00D62E90 /* factory.cc */,
897FF1330E719B8F00D62E90 /* factory.h */,
+ 89471C7F0EB23EE400B6874B /* flag-definitions.h */,
897FF1350E719B8F00D62E90 /* flags.cc */,
897FF1360E719B8F00D62E90 /* flags.h */,
897FF1370E719B8F00D62E90 /* frames-arm.cc */,