execution.cc
factory.cc
flags.cc
- flow-graph.cc
frame-element.cc
frames.cc
full-codegen.cc
Expression* right = node->right();
Token::Value op = node->op();
- // To make null checks efficient, we check if either left or right is the
- // literal 'null'. If so, we optimize the code by inlining a null check
- // instead of calling the (very) general runtime routine for checking
- // equality.
- if (op == Token::EQ || op == Token::EQ_STRICT) {
- bool left_is_null =
- left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
- bool right_is_null =
- right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
- // The 'null' value can only be equal to 'null' or 'undefined'.
- if (left_is_null || right_is_null) {
- Load(left_is_null ? right : left);
- Register tos = frame_->PopToRegister();
- __ LoadRoot(ip, Heap::kNullValueRootIndex);
- __ cmp(tos, ip);
-
- // The 'null' value is only equal to 'undefined' if using non-strict
- // comparisons.
- if (op != Token::EQ_STRICT) {
- true_target()->Branch(eq);
-
- __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
- __ cmp(tos, Operand(ip));
- true_target()->Branch(eq);
-
- __ tst(tos, Operand(kSmiTagMask));
- false_target()->Branch(eq);
-
- // It can be an undetectable object.
- __ ldr(tos, FieldMemOperand(tos, HeapObject::kMapOffset));
- __ ldrb(tos, FieldMemOperand(tos, Map::kBitFieldOffset));
- __ and_(tos, tos, Operand(1 << Map::kIsUndetectable));
- __ cmp(tos, Operand(1 << Map::kIsUndetectable));
- }
-
- cc_reg_ = eq;
- ASSERT(has_cc() && frame_->height() == original_height);
- return;
- }
- }
-
// To make typeof testing for natives implemented in JavaScript really
// efficient, we generate special code for expressions of the form:
// 'typeof <expression> == <string>'.
}
+void CodeGenerator::VisitCompareToNull(CompareToNull* node) {
+#ifdef DEBUG
+ int original_height = frame_->height();
+#endif
+ Comment cmnt(masm_, "[ CompareToNull");
+
+ Load(node->expression());
+ Register tos = frame_->PopToRegister();
+ __ LoadRoot(ip, Heap::kNullValueRootIndex);
+ __ cmp(tos, ip);
+
+ // The 'null' value is only equal to 'undefined' if using non-strict
+ // comparisons.
+ if (!node->is_strict()) {
+ true_target()->Branch(eq);
+ __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+ __ cmp(tos, Operand(ip));
+ true_target()->Branch(eq);
+
+ __ tst(tos, Operand(kSmiTagMask));
+ false_target()->Branch(eq);
+
+ // It can be an undetectable object.
+ __ ldr(tos, FieldMemOperand(tos, HeapObject::kMapOffset));
+ __ ldrb(tos, FieldMemOperand(tos, Map::kBitFieldOffset));
+ __ and_(tos, tos, Operand(1 << Map::kIsUndetectable));
+ __ cmp(tos, Operand(1 << Map::kIsUndetectable));
+ }
+
+ cc_reg_ = eq;
+ ASSERT(has_cc() && frame_->height() == original_height);
+}
+
+
class DeferredReferenceGetNamedValue: public DeferredCode {
public:
explicit DeferredReferenceGetNamedValue(Register receiver,
}
+void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
+ Comment cmnt(masm_, "[ CompareToNull");
+ Label materialize_true, materialize_false;
+ Label* if_true = NULL;
+ Label* if_false = NULL;
+ PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+
+ VisitForValue(expr->expression(), kAccumulator);
+ __ LoadRoot(r1, Heap::kNullValueRootIndex);
+ __ cmp(r0, r1);
+ if (expr->is_strict()) {
+ Split(eq, if_true, if_false, NULL);
+ } else {
+ __ b(eq, if_true);
+ __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
+ __ cmp(r0, r1);
+ __ b(eq, if_true);
+ __ tst(r0, Operand(kSmiTagMask));
+ __ b(eq, if_false);
+ // It can be an undetectable object.
+ __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
+ __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset));
+ __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
+ __ cmp(r1, Operand(1 << Map::kIsUndetectable));
+ Split(eq, if_true, if_false, NULL);
+ }
+ Apply(context_, if_true, if_false);
+}
+
+
void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
__ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
Apply(context_, r0);
cond_(NULL),
next_(NULL),
may_have_function_literal_(true),
- loop_variable_(NULL),
- peel_this_loop_(false) {
+ loop_variable_(NULL) {
}
#include "v8.h"
#include "ast.h"
-#include "data-flow.h"
#include "parser.h"
#include "scopes.h"
#include "string-stream.h"
var_(NULL),
is_this_(is_this),
inside_with_(inside_with),
- is_trivial_(false),
- reaching_definitions_(NULL),
- is_primitive_(false) {
+ is_trivial_(false) {
// names must be canonicalized for fast equality checks
ASSERT(name->IsSymbol());
}
VariableProxy::VariableProxy(bool is_this)
- : is_this_(is_this),
- reaching_definitions_(NULL),
- is_primitive_(false) {
+ : is_this_(is_this) {
}
return false;
}
+
+void Expression::CopyAnalysisResultsFrom(Expression* other) {
+ bitfields_ = other->bitfields_;
+ type_ = other->type_;
+}
+
+
// ----------------------------------------------------------------------------
// Implementation of AstVisitor
}
}
-// IsPrimitive implementation. IsPrimitive is true if the value of an
-// expression is known at compile-time to be any JS type other than Object
-// (e.g, it is Undefined, Null, Boolean, String, or Number).
-
-// The following expression types are never primitive because they express
-// Object values.
-bool FunctionLiteral::IsPrimitive() { return false; }
-bool SharedFunctionInfoLiteral::IsPrimitive() { return false; }
-bool RegExpLiteral::IsPrimitive() { return false; }
-bool ObjectLiteral::IsPrimitive() { return false; }
-bool ArrayLiteral::IsPrimitive() { return false; }
-bool CatchExtensionObject::IsPrimitive() { return false; }
-bool CallNew::IsPrimitive() { return false; }
-bool ThisFunction::IsPrimitive() { return false; }
-
-
-// The following expression types are not always primitive because we do not
-// have enough information to conclude that they are.
-bool Property::IsPrimitive() { return false; }
-bool Call::IsPrimitive() { return false; }
-bool CallRuntime::IsPrimitive() { return false; }
-
-
-// A variable use is not primitive unless the primitive-type analysis
-// determines otherwise.
-bool VariableProxy::IsPrimitive() {
- ASSERT(!is_primitive_ || (var() != NULL && var()->IsStackAllocated()));
- return is_primitive_;
-}
-
-// The value of a conditional is the value of one of the alternatives. It's
-// always primitive if both alternatives are always primitive.
-bool Conditional::IsPrimitive() {
- return then_expression()->IsPrimitive() && else_expression()->IsPrimitive();
-}
-
-
-// A literal is primitive when it is not a JSObject.
-bool Literal::IsPrimitive() { return !handle()->IsJSObject(); }
-
-
-// The value of an assignment is the value of its right-hand side.
-bool Assignment::IsPrimitive() {
- switch (op()) {
- case Token::INIT_VAR:
- case Token::INIT_CONST:
- case Token::ASSIGN:
- return value()->IsPrimitive();
-
- default:
- // {|=, ^=, &=, <<=, >>=, >>>=, +=, -=, *=, /=, %=}
- // Arithmetic operations are always primitive. They express Numbers
- // with the exception of +, which expresses a Number or a String.
- return true;
- }
-}
-
-
-// Throw does not express a value, so it's trivially always primitive.
-bool Throw::IsPrimitive() { return true; }
-
-
-// Unary operations always express primitive values. delete and ! express
-// Booleans, void Undefined, typeof String, +, -, and ~ Numbers.
-bool UnaryOperation::IsPrimitive() { return true; }
-
-
-// Count operations (pre- and post-fix increment and decrement) always
-// express primitive values (Numbers). See ECMA-262-3, 11.3.1, 11.3.2,
-// 11.4.4, ane 11.4.5.
-bool CountOperation::IsPrimitive() { return true; }
-
-
-// Binary operations depend on the operator.
-bool BinaryOperation::IsPrimitive() {
- switch (op()) {
- case Token::COMMA:
- // Value is the value of the right subexpression.
- return right()->IsPrimitive();
-
- case Token::OR:
- case Token::AND:
- // Value is the value one of the subexpressions.
- return left()->IsPrimitive() && right()->IsPrimitive();
-
- default:
- // {|, ^, &, <<, >>, >>>, +, -, *, /, %}
- // Arithmetic operations are always primitive. They express Numbers
- // with the exception of +, which expresses a Number or a String.
- return true;
- }
-}
-
-
-// Compare operations always express Boolean values.
-bool CompareOperation::IsPrimitive() { return true; }
-
-
-// Overridden IsCritical member functions. IsCritical is true for AST nodes
-// whose evaluation is absolutely required (they are never dead) because
-// they are externally visible.
-
-// References to global variables or lookup slots are critical because they
-// may have getters. All others, including parameters rewritten to explicit
-// property references, are not critical.
-bool VariableProxy::IsCritical() {
- Variable* var = AsVariable();
- return var != NULL &&
- (var->slot() == NULL || var->slot()->type() == Slot::LOOKUP);
-}
-
-
-// Literals are never critical.
-bool Literal::IsCritical() { return false; }
-
-
-// Property assignments and throwing of reference errors are always
-// critical. Assignments to escaping variables are also critical. In
-// addition the operation of compound assignments is critical if either of
-// its operands is non-primitive (the arithmetic operations all use one of
-// ToPrimitive, ToNumber, ToInt32, or ToUint32 on each of their operands).
-// In this case, we mark the entire AST node as critical because there is
-// no binary operation node to mark.
-bool Assignment::IsCritical() {
- Variable* var = AssignedVariable();
- return var == NULL ||
- !var->IsStackAllocated() ||
- (is_compound() && (!target()->IsPrimitive() || !value()->IsPrimitive()));
-}
-
-
-// Property references are always critical, because they may have getters.
-bool Property::IsCritical() { return true; }
-
-
-// Calls are always critical.
-bool Call::IsCritical() { return true; }
-
-
-// +,- use ToNumber on the value of their operand.
-bool UnaryOperation::IsCritical() {
- ASSERT(op() == Token::ADD || op() == Token::SUB);
- return !expression()->IsPrimitive();
-}
-
-
-// Count operations targeting properties and reference errors are always
-// critical. Count operations on escaping variables are critical. Count
-// operations targeting non-primitives are also critical because they use
-// ToNumber.
-bool CountOperation::IsCritical() {
- Variable* var = AssignedVariable();
- return var == NULL ||
- !var->IsStackAllocated() ||
- !expression()->IsPrimitive();
-}
-
-
-// Arithmetic operations all use one of ToPrimitive, ToNumber, ToInt32, or
-// ToUint32 on each of their operands.
-bool BinaryOperation::IsCritical() {
- ASSERT(op() != Token::COMMA);
- ASSERT(op() != Token::OR);
- ASSERT(op() != Token::AND);
- return !left()->IsPrimitive() || !right()->IsPrimitive();
-}
-
-
-// <, >, <=, and >= all use ToPrimitive on both their operands.
-bool CompareOperation::IsCritical() {
- ASSERT(op() != Token::EQ);
- ASSERT(op() != Token::NE);
- ASSERT(op() != Token::EQ_STRICT);
- ASSERT(op() != Token::NE_STRICT);
- ASSERT(op() != Token::INSTANCEOF);
- ASSERT(op() != Token::IN);
- return !left()->IsPrimitive() || !right()->IsPrimitive();
-}
-
-
-// Implementation of a copy visitor. The visitor create a deep copy
-// of ast nodes. Nodes that do not require a deep copy are copied
-// with the default copy constructor.
-
-AstNode::AstNode(AstNode* other) : num_(kNoNumber) {
- // AST node number should be unique. Assert that we only copy AstNodes
- // before node numbers are assigned.
- ASSERT(other->num_ == kNoNumber);
-}
-
-
-Statement::Statement(Statement* other)
- : AstNode(other), statement_pos_(other->statement_pos_) {}
-
-
-Expression::Expression(Expression* other)
- : AstNode(other),
- bitfields_(other->bitfields_),
- type_(other->type_) {}
-
-
-BreakableStatement::BreakableStatement(BreakableStatement* other)
- : Statement(other), labels_(other->labels_), type_(other->type_) {}
-
-
-Block::Block(Block* other, ZoneList<Statement*>* statements)
- : BreakableStatement(other),
- statements_(statements->length()),
- is_initializer_block_(other->is_initializer_block_) {
- statements_.AddAll(*statements);
-}
-
WhileStatement::WhileStatement(ZoneStringList* labels)
: IterationStatement(labels),
}
-ExpressionStatement::ExpressionStatement(ExpressionStatement* other,
- Expression* expression)
- : Statement(other), expression_(expression) {}
-
-
-IfStatement::IfStatement(IfStatement* other,
- Expression* condition,
- Statement* then_statement,
- Statement* else_statement)
- : Statement(other),
- condition_(condition),
- then_statement_(then_statement),
- else_statement_(else_statement) {}
-
-
-EmptyStatement::EmptyStatement(EmptyStatement* other) : Statement(other) {}
-
-
-IterationStatement::IterationStatement(IterationStatement* other,
- Statement* body)
- : BreakableStatement(other), body_(body) {}
-
-
CaseClause::CaseClause(Expression* label, ZoneList<Statement*>* statements)
: label_(label), statements_(statements) {
}
-
-ForStatement::ForStatement(ForStatement* other,
- Statement* init,
- Expression* cond,
- Statement* next,
- Statement* body)
- : IterationStatement(other, body),
- init_(init),
- cond_(cond),
- next_(next),
- may_have_function_literal_(other->may_have_function_literal_),
- loop_variable_(other->loop_variable_),
- peel_this_loop_(other->peel_this_loop_) {}
-
-
-Assignment::Assignment(Assignment* other,
- Expression* target,
- Expression* value)
- : Expression(other),
- op_(other->op_),
- target_(target),
- value_(value),
- pos_(other->pos_),
- block_start_(other->block_start_),
- block_end_(other->block_end_) {}
-
-
-Property::Property(Property* other, Expression* obj, Expression* key)
- : Expression(other),
- obj_(obj),
- key_(key),
- pos_(other->pos_),
- type_(other->type_) {}
-
-
-Call::Call(Call* other,
- Expression* expression,
- ZoneList<Expression*>* arguments)
- : Expression(other),
- expression_(expression),
- arguments_(arguments),
- pos_(other->pos_) {}
-
-
-UnaryOperation::UnaryOperation(UnaryOperation* other, Expression* expression)
- : Expression(other), op_(other->op_), expression_(expression) {}
-
-
-BinaryOperation::BinaryOperation(Expression* other,
- Token::Value op,
- Expression* left,
- Expression* right)
- : Expression(other), op_(op), left_(left), right_(right) {}
-
-
-CountOperation::CountOperation(CountOperation* other, Expression* expression)
- : Expression(other),
- is_prefix_(other->is_prefix_),
- op_(other->op_),
- expression_(expression) {}
-
-
-CompareOperation::CompareOperation(CompareOperation* other,
- Expression* left,
- Expression* right)
- : Expression(other),
- op_(other->op_),
- left_(left),
- right_(right) {}
-
-
-Expression* CopyAstVisitor::DeepCopyExpr(Expression* expr) {
- expr_ = NULL;
- if (expr != NULL) Visit(expr);
- return expr_;
-}
-
-
-Statement* CopyAstVisitor::DeepCopyStmt(Statement* stmt) {
- stmt_ = NULL;
- if (stmt != NULL) Visit(stmt);
- return stmt_;
-}
-
-
-ZoneList<Expression*>* CopyAstVisitor::DeepCopyExprList(
- ZoneList<Expression*>* expressions) {
- ZoneList<Expression*>* copy =
- new ZoneList<Expression*>(expressions->length());
- for (int i = 0; i < expressions->length(); i++) {
- copy->Add(DeepCopyExpr(expressions->at(i)));
- }
- return copy;
-}
-
-
-ZoneList<Statement*>* CopyAstVisitor::DeepCopyStmtList(
- ZoneList<Statement*>* statements) {
- ZoneList<Statement*>* copy = new ZoneList<Statement*>(statements->length());
- for (int i = 0; i < statements->length(); i++) {
- copy->Add(DeepCopyStmt(statements->at(i)));
- }
- return copy;
-}
-
-
-void CopyAstVisitor::VisitBlock(Block* stmt) {
- stmt_ = new Block(stmt,
- DeepCopyStmtList(stmt->statements()));
-}
-
-
-void CopyAstVisitor::VisitExpressionStatement(
- ExpressionStatement* stmt) {
- stmt_ = new ExpressionStatement(stmt, DeepCopyExpr(stmt->expression()));
-}
-
-
-void CopyAstVisitor::VisitEmptyStatement(EmptyStatement* stmt) {
- stmt_ = new EmptyStatement(stmt);
-}
-
-
-void CopyAstVisitor::VisitIfStatement(IfStatement* stmt) {
- stmt_ = new IfStatement(stmt,
- DeepCopyExpr(stmt->condition()),
- DeepCopyStmt(stmt->then_statement()),
- DeepCopyStmt(stmt->else_statement()));
-}
-
-
-void CopyAstVisitor::VisitContinueStatement(ContinueStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitBreakStatement(BreakStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitReturnStatement(ReturnStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitWithEnterStatement(
- WithEnterStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitWithExitStatement(WithExitStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitSwitchStatement(SwitchStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitDoWhileStatement(DoWhileStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitWhileStatement(WhileStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitForStatement(ForStatement* stmt) {
- stmt_ = new ForStatement(stmt,
- DeepCopyStmt(stmt->init()),
- DeepCopyExpr(stmt->cond()),
- DeepCopyStmt(stmt->next()),
- DeepCopyStmt(stmt->body()));
-}
-
-
-void CopyAstVisitor::VisitForInStatement(ForInStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitTryCatchStatement(TryCatchStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitTryFinallyStatement(
- TryFinallyStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitDebuggerStatement(
- DebuggerStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitFunctionLiteral(FunctionLiteral* expr) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitSharedFunctionInfoLiteral(
- SharedFunctionInfoLiteral* expr) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitConditional(Conditional* expr) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitSlot(Slot* expr) {
- UNREACHABLE();
-}
-
-
-void CopyAstVisitor::VisitVariableProxy(VariableProxy* expr) {
- expr_ = new VariableProxy(*expr);
-}
-
-
-void CopyAstVisitor::VisitLiteral(Literal* expr) {
- expr_ = new Literal(*expr);
-}
-
-
-void CopyAstVisitor::VisitRegExpLiteral(RegExpLiteral* expr) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitObjectLiteral(ObjectLiteral* expr) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitArrayLiteral(ArrayLiteral* expr) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitCatchExtensionObject(
- CatchExtensionObject* expr) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitAssignment(Assignment* expr) {
- expr_ = new Assignment(expr,
- DeepCopyExpr(expr->target()),
- DeepCopyExpr(expr->value()));
-}
-
-
-void CopyAstVisitor::VisitThrow(Throw* expr) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitProperty(Property* expr) {
- expr_ = new Property(expr,
- DeepCopyExpr(expr->obj()),
- DeepCopyExpr(expr->key()));
-}
-
-
-void CopyAstVisitor::VisitCall(Call* expr) {
- expr_ = new Call(expr,
- DeepCopyExpr(expr->expression()),
- DeepCopyExprList(expr->arguments()));
-}
-
-
-void CopyAstVisitor::VisitCallNew(CallNew* expr) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitCallRuntime(CallRuntime* expr) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitUnaryOperation(UnaryOperation* expr) {
- expr_ = new UnaryOperation(expr, DeepCopyExpr(expr->expression()));
-}
-
-
-void CopyAstVisitor::VisitCountOperation(CountOperation* expr) {
- expr_ = new CountOperation(expr,
- DeepCopyExpr(expr->expression()));
-}
-
-
-void CopyAstVisitor::VisitBinaryOperation(BinaryOperation* expr) {
- expr_ = new BinaryOperation(expr,
- expr->op(),
- DeepCopyExpr(expr->left()),
- DeepCopyExpr(expr->right()));
-}
-
-
-void CopyAstVisitor::VisitCompareOperation(CompareOperation* expr) {
- expr_ = new CompareOperation(expr,
- DeepCopyExpr(expr->left()),
- DeepCopyExpr(expr->right()));
-}
-
-
-void CopyAstVisitor::VisitThisFunction(ThisFunction* expr) {
- SetStackOverflow();
-}
-
-
-void CopyAstVisitor::VisitDeclaration(Declaration* decl) {
- UNREACHABLE();
-}
-
-
} } // namespace v8::internal
V(CountOperation) \
V(BinaryOperation) \
V(CompareOperation) \
+ V(CompareToNull) \
V(ThisFunction)
#define AST_NODE_LIST(V) \
class AstNode: public ZoneObject {
public:
- static const int kNoNumber = -1;
-
- AstNode() : num_(kNoNumber) {}
-
- explicit AstNode(AstNode* other);
-
virtual ~AstNode() { }
virtual void Accept(AstVisitor* v) = 0;
virtual ObjectLiteral* AsObjectLiteral() { return NULL; }
virtual ArrayLiteral* AsArrayLiteral() { return NULL; }
virtual CompareOperation* AsCompareOperation() { return NULL; }
-
- // True if the AST node is critical (its execution is needed or externally
- // visible in some way).
- virtual bool IsCritical() {
- UNREACHABLE();
- return true;
- }
-
- int num() { return num_; }
- void set_num(int n) { num_ = n; }
-
- private:
- // Support for ast node numbering.
- int num_;
};
public:
Statement() : statement_pos_(RelocInfo::kNoPosition) {}
- explicit Statement(Statement* other);
-
virtual Statement* AsStatement() { return this; }
virtual ReturnStatement* AsReturnStatement() { return NULL; }
Expression() : bitfields_(0) {}
- explicit Expression(Expression* other);
-
virtual Expression* AsExpression() { return this; }
+ virtual bool IsTrivial() { return false; }
virtual bool IsValidLeftHandSide() { return false; }
- virtual Variable* AssignedVariable() { return NULL; }
-
// Symbols that cannot be parsed as array indices are considered property
// names. We do not treat symbols that can be array indexes as property
// names because [] for string objects is handled only by keyed ICs.
virtual bool IsPropertyName() { return false; }
- // True if the expression does not have (evaluated) subexpressions.
- // Function literals are leaves because their subexpressions are not
- // evaluated.
- virtual bool IsLeaf() { return false; }
-
- // True if the expression has no side effects and is safe to
- // evaluate out of order.
- virtual bool IsTrivial() { return false; }
-
- // True if the expression always has one of the non-Object JS types
- // (Undefined, Null, Boolean, String, or Number).
- virtual bool IsPrimitive() = 0;
-
// Mark the expression as being compiled as an expression
// statement. This is used to transform postfix increments to
// (faster) prefix increments.
// top operation is a bit operation with a mask, or a shift.
bool GuaranteedSmiResult();
- // AST analysis results
+ // AST analysis results.
+ void CopyAnalysisResultsFrom(Expression* other);
// True if the expression rooted at this node can be compiled by the
// side-effect free compiler.
virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
static ValidLeftHandSideSentinel* instance() { return &instance_; }
- virtual bool IsPrimitive() {
- UNREACHABLE();
- return false;
- }
-
private:
static ValidLeftHandSideSentinel instance_;
};
protected:
inline BreakableStatement(ZoneStringList* labels, Type type);
- explicit BreakableStatement(BreakableStatement* other);
-
private:
ZoneStringList* labels_;
Type type_;
public:
inline Block(ZoneStringList* labels, int capacity, bool is_initializer_block);
- // Construct a clone initialized from the original block and
- // a deep copy of all statements of the original block.
- Block(Block* other, ZoneList<Statement*>* statements);
-
virtual void Accept(AstVisitor* v);
virtual Block* AsBlock() { return this; }
protected:
explicit inline IterationStatement(ZoneStringList* labels);
- // Construct a clone initialized from original and
- // a deep copy of the original body.
- IterationStatement(IterationStatement* other, Statement* body);
-
void Initialize(Statement* body) {
body_ = body;
}
bool may_have_function_literal() const {
return may_have_function_literal_;
}
+ void set_may_have_function_literal(bool value) {
+ may_have_function_literal_ = value;
+ }
private:
Expression* cond_;
// True if there is a function literal subexpression in the condition.
bool may_have_function_literal_;
-
- friend class AstOptimizer;
};
public:
explicit inline ForStatement(ZoneStringList* labels);
- // Construct a for-statement initialized from another for-statement
- // and deep copies of all parts of the original statement.
- ForStatement(ForStatement* other,
- Statement* init,
- Expression* cond,
- Statement* next,
- Statement* body);
-
virtual ForStatement* AsForStatement() { return this; }
void Initialize(Statement* init,
void set_cond(Expression* expr) { cond_ = expr; }
Statement* next() const { return next_; }
void set_next(Statement* stmt) { next_ = stmt; }
+
bool may_have_function_literal() const {
return may_have_function_literal_;
}
+ void set_may_have_function_literal(bool value) {
+ may_have_function_literal_ = value;
+ }
bool is_fast_smi_loop() { return loop_variable_ != NULL; }
Variable* loop_variable() { return loop_variable_; }
void set_loop_variable(Variable* var) { loop_variable_ = var; }
- bool peel_this_loop() { return peel_this_loop_; }
- void set_peel_this_loop(bool b) { peel_this_loop_ = b; }
-
private:
Statement* init_;
Expression* cond_;
// True if there is a function literal subexpression in the condition.
bool may_have_function_literal_;
Variable* loop_variable_;
- bool peel_this_loop_;
-
- friend class AstOptimizer;
};
explicit ExpressionStatement(Expression* expression)
: expression_(expression) { }
- // Construct an expression statement initialized from another
- // expression statement and a deep copy of the original expression.
- ExpressionStatement(ExpressionStatement* other, Expression* expression);
-
virtual void Accept(AstVisitor* v);
// Type testing & conversion.
then_statement_(then_statement),
else_statement_(else_statement) { }
- // Construct an if-statement initialized from another if-statement
- // and deep copies of all parts of the original.
- IfStatement(IfStatement* other,
- Expression* condition,
- Statement* then_statement,
- Statement* else_statement);
-
virtual void Accept(AstVisitor* v);
bool HasThenStatement() const { return !then_statement()->IsEmpty(); }
public:
EmptyStatement() {}
- explicit EmptyStatement(EmptyStatement* other);
-
virtual void Accept(AstVisitor* v);
// Type testing & conversion.
explicit Literal(Handle<Object> handle) : handle_(handle) { }
virtual void Accept(AstVisitor* v);
+ virtual bool IsTrivial() { return true; }
// Type testing & conversion.
virtual Literal* AsLiteral() { return this; }
return false;
}
- virtual bool IsLeaf() { return true; }
- virtual bool IsTrivial() { return true; }
- virtual bool IsPrimitive();
- virtual bool IsCritical();
-
// Identity testers.
bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
bool IsTrue() const { return handle_.is_identical_to(Factory::true_value()); }
// to the code generator.
class Property: public ZoneObject {
public:
-
enum Kind {
CONSTANT, // Property with constant value (compile time).
COMPUTED, // Property with computed value (execution time).
virtual ObjectLiteral* AsObjectLiteral() { return this; }
virtual void Accept(AstVisitor* v);
- virtual bool IsLeaf() { return properties()->is_empty(); }
-
- virtual bool IsPrimitive();
-
Handle<FixedArray> constant_properties() const {
return constant_properties_;
}
virtual void Accept(AstVisitor* v);
- virtual bool IsLeaf() { return true; }
-
- virtual bool IsPrimitive();
-
Handle<String> pattern() const { return pattern_; }
Handle<String> flags() const { return flags_; }
virtual void Accept(AstVisitor* v);
virtual ArrayLiteral* AsArrayLiteral() { return this; }
- virtual bool IsLeaf() { return values()->is_empty(); }
-
- virtual bool IsPrimitive();
-
Handle<FixedArray> constant_elements() const { return constant_elements_; }
ZoneList<Expression*>* values() const { return values_; }
virtual void Accept(AstVisitor* v);
- virtual bool IsPrimitive();
-
Literal* key() const { return key_; }
VariableProxy* value() const { return value_; }
virtual Property* AsProperty() {
return var_ == NULL ? NULL : var_->AsProperty();
}
- virtual VariableProxy* AsVariableProxy() { return this; }
+
+ virtual VariableProxy* AsVariableProxy() {
+ return this;
+ }
Variable* AsVariable() {
return this == NULL || var_ == NULL ? NULL : var_->AsVariable();
return var_ == NULL ? true : var_->IsValidLeftHandSide();
}
- virtual bool IsLeaf() {
- ASSERT(var_ != NULL); // Variable must be resolved.
- return var()->is_global() || var()->rewrite()->IsLeaf();
+ virtual bool IsTrivial() {
+ // Reading from a mutable variable is a side effect, but the
+ // variable for 'this' is immutable.
+ return is_this_ || is_trivial_;
}
- // Reading from a mutable variable is a side effect, but 'this' is
- // immutable.
- virtual bool IsTrivial() { return is_trivial_; }
-
- virtual bool IsPrimitive();
- virtual bool IsCritical();
-
- void SetIsPrimitive(bool value) { is_primitive_ = value; }
-
bool IsVariable(Handle<String> n) {
return !is_this() && name().is_identical_to(n);
}
Variable* var() const { return var_; }
bool is_this() const { return is_this_; }
bool inside_with() const { return inside_with_; }
- bool is_trivial() { return is_trivial_; }
- void set_is_trivial(bool b) { is_trivial_ = b; }
- BitVector* reaching_definitions() { return reaching_definitions_; }
- void set_reaching_definitions(BitVector* rd) { reaching_definitions_ = rd; }
+ void MarkAsTrivial() { is_trivial_ = true; }
// Bind this proxy to the variable var.
void BindTo(Variable* var);
bool is_this_;
bool inside_with_;
bool is_trivial_;
- BitVector* reaching_definitions_;
- bool is_primitive_;
VariableProxy(Handle<String> name, bool is_this, bool inside_with);
explicit VariableProxy(bool is_this);
return &identifier_proxy_;
}
- virtual bool IsPrimitive() {
- UNREACHABLE();
- return false;
- }
-
private:
explicit VariableProxySentinel(bool is_this) : VariableProxy(is_this) { }
static VariableProxySentinel this_proxy_;
// Type testing & conversion
virtual Slot* AsSlot() { return this; }
- virtual bool IsLeaf() { return true; }
-
- virtual bool IsPrimitive() {
- UNREACHABLE();
- return false;
- }
-
bool IsStackAllocated() { return type_ == PARAMETER || type_ == LOCAL; }
// Accessors
Property(Expression* obj, Expression* key, int pos, Type type = NORMAL)
: obj_(obj), key_(key), pos_(pos), type_(type) { }
- Property(Property* other, Expression* obj, Expression* key);
-
virtual void Accept(AstVisitor* v);
// Type testing & conversion
virtual bool IsValidLeftHandSide() { return true; }
- virtual bool IsPrimitive();
- virtual bool IsCritical();
-
Expression* obj() const { return obj_; }
Expression* key() const { return key_; }
int position() const { return pos_; }
Call(Expression* expression, ZoneList<Expression*>* arguments, int pos)
: expression_(expression), arguments_(arguments), pos_(pos) { }
- Call(Call* other, Expression* expression, ZoneList<Expression*>* arguments);
-
virtual void Accept(AstVisitor* v);
// Type testing and conversion.
virtual Call* AsCall() { return this; }
- virtual bool IsPrimitive();
- virtual bool IsCritical();
-
Expression* expression() const { return expression_; }
ZoneList<Expression*>* arguments() const { return arguments_; }
int position() { return pos_; }
virtual void Accept(AstVisitor* v);
- virtual bool IsPrimitive();
-
Expression* expression() const { return expression_; }
ZoneList<Expression*>* arguments() const { return arguments_; }
int position() { return pos_; }
virtual void Accept(AstVisitor* v);
- virtual bool IsPrimitive();
-
Handle<String> name() const { return name_; }
Runtime::Function* function() const { return function_; }
ZoneList<Expression*>* arguments() const { return arguments_; }
ASSERT(Token::IsUnaryOp(op));
}
- UnaryOperation(UnaryOperation* other, Expression* expression);
-
virtual void Accept(AstVisitor* v);
// Type testing & conversion
virtual UnaryOperation* AsUnaryOperation() { return this; }
- virtual bool IsPrimitive();
- virtual bool IsCritical();
-
Token::Value op() const { return op_; }
Expression* expression() const { return expression_; }
ASSERT(Token::IsBinaryOp(op));
}
- // Construct a binary operation with a given operator and left and right
- // subexpressions. The rest of the expression state is copied from
- // another expression.
- BinaryOperation(Expression* other,
- Token::Value op,
- Expression* left,
- Expression* right);
-
virtual void Accept(AstVisitor* v);
// Type testing & conversion
virtual BinaryOperation* AsBinaryOperation() { return this; }
- virtual bool IsPrimitive();
- virtual bool IsCritical();
-
// True iff the result can be safely overwritten (to avoid allocation).
// False for operations that can return one of their operands.
bool ResultOverwriteAllowed() {
ASSERT(Token::IsCountOp(op));
}
- CountOperation(CountOperation* other, Expression* expression);
-
virtual void Accept(AstVisitor* v);
virtual CountOperation* AsCountOperation() { return this; }
- virtual Variable* AssignedVariable() {
- return expression()->AsVariableProxy()->AsVariable();
- }
-
- virtual bool IsPrimitive();
- virtual bool IsCritical();
-
bool is_prefix() const { return is_prefix_; }
bool is_postfix() const { return !is_prefix_; }
Token::Value op() const { return op_; }
ASSERT(Token::IsCompareOp(op));
}
- CompareOperation(CompareOperation* other,
- Expression* left,
- Expression* right);
-
virtual void Accept(AstVisitor* v);
- virtual bool IsPrimitive();
- virtual bool IsCritical();
-
Token::Value op() const { return op_; }
Expression* left() const { return left_; }
Expression* right() const { return right_; }
};
+class CompareToNull: public Expression {
+ public:
+ CompareToNull(bool is_strict, Expression* expression)
+ : is_strict_(is_strict), expression_(expression) { }
+
+ virtual void Accept(AstVisitor* v);
+
+ bool is_strict() const { return is_strict_; }
+ Token::Value op() const { return is_strict_ ? Token::EQ_STRICT : Token::EQ; }
+ Expression* expression() const { return expression_; }
+
+ private:
+ bool is_strict_;
+ Expression* expression_;
+};
+
+
class Conditional: public Expression {
public:
Conditional(Expression* condition,
virtual void Accept(AstVisitor* v);
- virtual bool IsPrimitive();
-
Expression* condition() const { return condition_; }
Expression* then_expression() const { return then_expression_; }
Expression* else_expression() const { return else_expression_; }
ASSERT(Token::IsAssignmentOp(op));
}
- Assignment(Assignment* other, Expression* target, Expression* value);
-
virtual void Accept(AstVisitor* v);
virtual Assignment* AsAssignment() { return this; }
- virtual bool IsPrimitive();
- virtual bool IsCritical();
-
Assignment* AsSimpleAssignment() { return !is_compound() ? this : NULL; }
- virtual Variable* AssignedVariable() {
- return target()->AsVariableProxy()->AsVariable();
- }
-
Token::Value binary_op() const;
Token::Value op() const { return op_; }
virtual void Accept(AstVisitor* v);
- virtual bool IsPrimitive();
-
Expression* exception() const { return exception_; }
int position() const { return pos_; }
// Type testing & conversion
virtual FunctionLiteral* AsFunctionLiteral() { return this; }
- virtual bool IsLeaf() { return true; }
-
- virtual bool IsPrimitive();
-
Handle<String> name() const { return name_; }
Scope* scope() const { return scope_; }
ZoneList<Statement*>* body() const { return body_; }
return shared_function_info_;
}
- virtual bool IsLeaf() { return true; }
-
virtual void Accept(AstVisitor* v);
- virtual bool IsPrimitive();
-
private:
Handle<SharedFunctionInfo> shared_function_info_;
};
class ThisFunction: public Expression {
public:
virtual void Accept(AstVisitor* v);
- virtual bool IsLeaf() { return true; }
- virtual bool IsPrimitive();
};
bool stack_overflow_;
};
-
-class CopyAstVisitor : public AstVisitor {
- public:
- Expression* DeepCopyExpr(Expression* expr);
-
- Statement* DeepCopyStmt(Statement* stmt);
-
- private:
- ZoneList<Expression*>* DeepCopyExprList(ZoneList<Expression*>* expressions);
-
- ZoneList<Statement*>* DeepCopyStmtList(ZoneList<Statement*>* statements);
-
- // AST node visit functions.
-#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
- AST_NODE_LIST(DECLARE_VISIT)
-#undef DECLARE_VISIT
-
- // Holds the result of copying an expression.
- Expression* expr_;
- // Holds the result of copying a statement.
- Statement* stmt_;
-};
-
} } // namespace v8::internal
#endif // V8_AST_H_
#include "compiler.h"
#include "data-flow.h"
#include "debug.h"
-#include "flow-graph.h"
#include "full-codegen.h"
#include "liveedit.h"
#include "oprofile-agent.h"
return Handle<Code>::null();
}
- if (function->scope()->num_parameters() > 0 ||
- function->scope()->num_stack_slots()) {
- AssignedVariablesAnalyzer ava(function);
- ava.Analyze();
- if (ava.HasStackOverflow()) {
- return Handle<Code>::null();
- }
- }
-
- if (FLAG_use_flow_graph) {
- FlowGraphBuilder builder;
- FlowGraph* graph = builder.Build(function);
- USE(graph);
-
-#ifdef DEBUG
- if (FLAG_print_graph_text && !builder.HasStackOverflow()) {
- graph->PrintAsText(function->name());
- }
-#endif
- }
-
// Generate code and return it. Code generator selection is governed by
// which backends are enabled and whether the function is considered
// run-once code or not:
}
}
+ AssignedVariablesAnalyzer ava(function);
+ if (!ava.Analyze()) return Handle<Code>::null();
return CodeGenerator::MakeCode(info);
}
return Handle<SharedFunctionInfo>::null();
}
- if (literal->scope()->num_parameters() > 0 ||
- literal->scope()->num_stack_slots()) {
- AssignedVariablesAnalyzer ava(literal);
- ava.Analyze();
- if (ava.HasStackOverflow()) {
- return Handle<SharedFunctionInfo>::null();
- }
- }
-
- if (FLAG_use_flow_graph) {
- FlowGraphBuilder builder;
- FlowGraph* graph = builder.Build(literal);
- USE(graph);
-
-#ifdef DEBUG
- if (FLAG_print_graph_text && !builder.HasStackOverflow()) {
- graph->PrintAsText(literal->name());
- }
-#endif
- }
-
// Generate code and return it. The way that the compilation mode
// is controlled by the command-line flags is described in
// the static helper function MakeCode.
if (!is_compiled) {
// We fall back to the classic V8 code generator.
+ AssignedVariablesAnalyzer ava(literal);
+ if (!ava.Analyze()) return Handle<SharedFunctionInfo>::null();
code = CodeGenerator::MakeCode(&info);
}
#endif
-void AstLabeler::Label(CompilationInfo* info) {
- info_ = info;
- VisitStatements(info_->function()->body());
-}
-
-
-void AstLabeler::VisitStatements(ZoneList<Statement*>* stmts) {
- for (int i = 0, len = stmts->length(); i < len; i++) {
- Visit(stmts->at(i));
- }
-}
-
-
-void AstLabeler::VisitDeclarations(ZoneList<Declaration*>* decls) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitBlock(Block* stmt) {
- VisitStatements(stmt->statements());
-}
-
-
-void AstLabeler::VisitExpressionStatement(
- ExpressionStatement* stmt) {
- Visit(stmt->expression());
-}
-
-
-void AstLabeler::VisitEmptyStatement(EmptyStatement* stmt) {
- // Do nothing.
-}
-
-
-void AstLabeler::VisitIfStatement(IfStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitContinueStatement(ContinueStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitBreakStatement(BreakStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitReturnStatement(ReturnStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitWithEnterStatement(
- WithEnterStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitWithExitStatement(WithExitStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitSwitchStatement(SwitchStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitDoWhileStatement(DoWhileStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitWhileStatement(WhileStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitForStatement(ForStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitForInStatement(ForInStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitTryCatchStatement(TryCatchStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitTryFinallyStatement(
- TryFinallyStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitDebuggerStatement(
- DebuggerStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitFunctionLiteral(FunctionLiteral* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitSharedFunctionInfoLiteral(
- SharedFunctionInfoLiteral* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitConditional(Conditional* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitSlot(Slot* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitVariableProxy(VariableProxy* expr) {
- expr->set_num(next_number_++);
- Variable* var = expr->var();
- if (var->is_global() && !var->is_this()) {
- info_->set_has_globals(true);
- }
-}
-
-
-void AstLabeler::VisitLiteral(Literal* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitRegExpLiteral(RegExpLiteral* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitObjectLiteral(ObjectLiteral* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitArrayLiteral(ArrayLiteral* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitCatchExtensionObject(
- CatchExtensionObject* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitAssignment(Assignment* expr) {
- Property* prop = expr->target()->AsProperty();
- ASSERT(prop != NULL);
- ASSERT(prop->key()->IsPropertyName());
- VariableProxy* proxy = prop->obj()->AsVariableProxy();
- USE(proxy);
- ASSERT(proxy != NULL && proxy->var()->is_this());
- info()->set_has_this_properties(true);
-
- prop->obj()->set_num(AstNode::kNoNumber);
- prop->key()->set_num(AstNode::kNoNumber);
- Visit(expr->value());
- expr->set_num(next_number_++);
-}
-
-
-void AstLabeler::VisitThrow(Throw* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitProperty(Property* expr) {
- ASSERT(expr->key()->IsPropertyName());
- VariableProxy* proxy = expr->obj()->AsVariableProxy();
- USE(proxy);
- ASSERT(proxy != NULL && proxy->var()->is_this());
- info()->set_has_this_properties(true);
-
- expr->obj()->set_num(AstNode::kNoNumber);
- expr->key()->set_num(AstNode::kNoNumber);
- expr->set_num(next_number_++);
-}
-
-
-void AstLabeler::VisitCall(Call* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitCallNew(CallNew* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitCallRuntime(CallRuntime* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitUnaryOperation(UnaryOperation* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitCountOperation(CountOperation* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitBinaryOperation(BinaryOperation* expr) {
- Visit(expr->left());
- Visit(expr->right());
- expr->set_num(next_number_++);
-}
-
-
-void AstLabeler::VisitCompareOperation(CompareOperation* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitThisFunction(ThisFunction* expr) {
- UNREACHABLE();
-}
-
-
-void AstLabeler::VisitDeclaration(Declaration* decl) {
- UNREACHABLE();
-}
-
-
-AssignedVariablesAnalyzer::AssignedVariablesAnalyzer(FunctionLiteral* fun)
- : fun_(fun),
- av_(fun->scope()->num_parameters() + fun->scope()->num_stack_slots()) {}
-
-
-void AssignedVariablesAnalyzer::Analyze() {
- ASSERT(av_.length() > 0);
+bool AssignedVariablesAnalyzer::Analyze() {
+ Scope* scope = fun_->scope();
+ int variables = scope->num_parameters() + scope->num_stack_slots();
+ if (variables == 0) return true;
+ av_.ExpandTo(variables);
VisitStatements(fun_->body());
+ return !HasStackOverflow();
}
!var->is_arguments() &&
var->mode() != Variable::CONST &&
(var->is_this() || !av_.Contains(BitIndex(var)))) {
- expr->AsVariableProxy()->set_is_trivial(true);
+ expr->AsVariableProxy()->MarkAsTrivial();
}
}
void AssignedVariablesAnalyzer::VisitForStatement(ForStatement* stmt) {
if (stmt->init() != NULL) Visit(stmt->init());
-
if (stmt->cond() != NULL) ProcessExpression(stmt->cond());
-
if (stmt->next() != NULL) Visit(stmt->next());
// Process loop body. After visiting the loop body av_ contains
if (var != NULL && !av_.Contains(BitIndex(var))) {
stmt->set_loop_variable(var);
}
-
av_.Union(saved_av);
}
void AssignedVariablesAnalyzer::VisitUnaryOperation(UnaryOperation* expr) {
ASSERT(av_.IsEmpty());
+ MarkIfTrivial(expr->expression());
Visit(expr->expression());
}
void AssignedVariablesAnalyzer::VisitCountOperation(CountOperation* expr) {
ASSERT(av_.IsEmpty());
-
+ if (expr->is_prefix()) MarkIfTrivial(expr->expression());
Visit(expr->expression());
Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
}
+void AssignedVariablesAnalyzer::VisitCompareToNull(CompareToNull* expr) {
+ ASSERT(av_.IsEmpty());
+ MarkIfTrivial(expr->expression());
+ Visit(expr->expression());
+}
+
+
void AssignedVariablesAnalyzer::VisitThisFunction(ThisFunction* expr) {
// Nothing to do.
ASSERT(av_.IsEmpty());
class BitVector: public ZoneObject {
public:
- explicit BitVector(int length)
- : length_(length),
- data_length_(SizeFor(length)),
- data_(Zone::NewArray<uint32_t>(data_length_)) {
- ASSERT(length > 0);
- Clear();
+ BitVector() : length_(0), data_length_(0), data_(NULL) { }
+
+ explicit BitVector(int length) {
+ ExpandTo(length);
}
BitVector(const BitVector& other)
CopyFrom(other);
}
- static int SizeFor(int length) {
- return 1 + ((length - 1) / 32);
+ void ExpandTo(int length) {
+ ASSERT(length > 0);
+ length_ = length;
+ data_length_ = SizeFor(length);
+ data_ = Zone::NewArray<uint32_t>(data_length_);
+ Clear();
}
BitVector& operator=(const BitVector& rhs) {
#endif
private:
+ static int SizeFor(int length) {
+ return 1 + ((length - 1) / 32);
+ }
+
int length_;
int data_length_;
uint32_t* data_;
};
-struct ReachingDefinitionsData BASE_EMBEDDED {
- public:
- ReachingDefinitionsData() : rd_in_(NULL), kill_(NULL), gen_(NULL) {}
-
- void Initialize(int definition_count) {
- rd_in_ = new BitVector(definition_count);
- kill_ = new BitVector(definition_count);
- gen_ = new BitVector(definition_count);
- }
-
- BitVector* rd_in() { return rd_in_; }
- BitVector* kill() { return kill_; }
- BitVector* gen() { return gen_; }
-
- private:
- BitVector* rd_in_;
- BitVector* kill_;
- BitVector* gen_;
-};
-
-
-// This class is used to number all expressions in the AST according to
-// their evaluation order (post-order left-to-right traversal).
-class AstLabeler: public AstVisitor {
- public:
- AstLabeler() : next_number_(0) {}
-
- void Label(CompilationInfo* info);
-
- private:
- CompilationInfo* info() { return info_; }
-
- void VisitDeclarations(ZoneList<Declaration*>* decls);
- void VisitStatements(ZoneList<Statement*>* stmts);
-
- // AST node visit functions.
-#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
- AST_NODE_LIST(DECLARE_VISIT)
-#undef DECLARE_VISIT
-
- // Traversal number for labelling AST nodes.
- int next_number_;
-
- CompilationInfo* info_;
-
- DISALLOW_COPY_AND_ASSIGN(AstLabeler);
-};
-
-
// Computes the set of assigned variables and annotates variables proxies
// that are trivial sub-expressions and for-loops where the loop variable
// is guaranteed to be a smi.
class AssignedVariablesAnalyzer : public AstVisitor {
public:
- explicit AssignedVariablesAnalyzer(FunctionLiteral* fun);
-
- void Analyze();
+ explicit AssignedVariablesAnalyzer(FunctionLiteral* fun) : fun_(fun) { }
+ bool Analyze();
private:
Variable* FindSmiLoopVariable(ForStatement* stmt);
+++ /dev/null
-// Copyright 2010 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.
-
-#include "flow-graph.h"
-#include "scopes.h"
-
-namespace v8 {
-namespace internal {
-
-void BasicBlock::BuildTraversalOrder(ZoneList<BasicBlock*>* preorder,
- ZoneList<BasicBlock*>* postorder,
- bool mark) {
- if (mark_ == mark) return;
- mark_ = mark;
- preorder->Add(this);
- if (right_successor_ != NULL) {
- right_successor_->BuildTraversalOrder(preorder, postorder, mark);
- }
- if (left_successor_ != NULL) {
- left_successor_->BuildTraversalOrder(preorder, postorder, mark);
- }
- postorder->Add(this);
-}
-
-
-FlowGraph* FlowGraphBuilder::Build(FunctionLiteral* lit) {
- // Create new entry and exit nodes. These will not change during
- // construction.
- entry_ = new BasicBlock(NULL);
- exit_ = new BasicBlock(NULL);
- // Begin accumulating instructions in the entry block.
- current_ = entry_;
-
- VisitDeclarations(lit->scope()->declarations());
- VisitStatements(lit->body());
- // In the event of stack overflow or failure to handle a syntactic
- // construct, return an invalid flow graph.
- if (HasStackOverflow()) return new FlowGraph(NULL, NULL);
-
- // If current is not the exit, add a link to the exit.
- if (current_ != exit_) {
- // If current already has a successor (i.e., will be a branch node) and
- // if the exit already has a predecessor, insert an empty block to
- // maintain edge split form.
- if (current_->HasSuccessor() && exit_->HasPredecessor()) {
- current_ = new BasicBlock(current_);
- }
- Literal* undefined = new Literal(Factory::undefined_value());
- current_->AddInstruction(new ReturnStatement(undefined));
- exit_->AddPredecessor(current_);
- }
-
- FlowGraph* graph = new FlowGraph(entry_, exit_);
- bool mark = !entry_->GetMark();
- entry_->BuildTraversalOrder(graph->preorder(), graph->postorder(), mark);
-
-#ifdef DEBUG
- // Number the nodes in reverse postorder.
- int n = 0;
- for (int i = graph->postorder()->length() - 1; i >= 0; --i) {
- graph->postorder()->at(i)->set_number(n++);
- }
-#endif
-
- return graph;
-}
-
-
-void FlowGraphBuilder::VisitDeclaration(Declaration* decl) {
- Variable* var = decl->proxy()->AsVariable();
- Slot* slot = var->slot();
- // We allow only declarations that do not require code generation.
- // The following all require code generation: global variables and
- // functions, variables with slot type LOOKUP, declarations with
- // mode CONST, and functions.
-
- if (var->is_global() ||
- (slot != NULL && slot->type() == Slot::LOOKUP) ||
- decl->mode() == Variable::CONST ||
- decl->fun() != NULL) {
- // Here and in the rest of the flow graph builder we indicate an
- // unsupported syntactic construct by setting the stack overflow
- // flag on the visitor. This causes bailout of the visitor.
- SetStackOverflow();
- }
-}
-
-
-void FlowGraphBuilder::VisitBlock(Block* stmt) {
- VisitStatements(stmt->statements());
-}
-
-
-void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
- Visit(stmt->expression());
-}
-
-
-void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
- // Nothing to do.
-}
-
-
-void FlowGraphBuilder::VisitIfStatement(IfStatement* stmt) {
- // Build a diamond in the flow graph. First accumulate the instructions
- // of the test in the current basic block.
- Visit(stmt->condition());
-
- // Remember the branch node and accumulate the true branch as its left
- // successor. This relies on the successors being added left to right.
- BasicBlock* branch = current_;
- current_ = new BasicBlock(branch);
- Visit(stmt->then_statement());
-
- // Construct a join node and then accumulate the false branch in a fresh
- // successor of the branch node.
- BasicBlock* join = new BasicBlock(current_);
- current_ = new BasicBlock(branch);
- Visit(stmt->else_statement());
- join->AddPredecessor(current_);
-
- current_ = join;
-}
-
-
-void FlowGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitForStatement(ForStatement* stmt) {
- // Build a loop in the flow graph. First accumulate the instructions of
- // the initializer in the current basic block.
- if (stmt->init() != NULL) Visit(stmt->init());
-
- // Create a new basic block for the test. This will be the join node.
- BasicBlock* join = new BasicBlock(current_);
- current_ = join;
- if (stmt->cond() != NULL) Visit(stmt->cond());
-
- // The current node is the branch node. Create a new basic block to begin
- // the body.
- BasicBlock* branch = current_;
- current_ = new BasicBlock(branch);
- Visit(stmt->body());
- if (stmt->next() != NULL) Visit(stmt->next());
-
- // Add the backward edge from the end of the body and continue with the
- // false arm of the branch.
- join->AddPredecessor(current_);
- current_ = new BasicBlock(branch);
-}
-
-
-void FlowGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitSharedFunctionInfoLiteral(
- SharedFunctionInfoLiteral* expr) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitConditional(Conditional* expr) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitSlot(Slot* expr) {
- // Slots do not appear in the AST.
- UNREACHABLE();
-}
-
-
-void FlowGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
- current_->AddInstruction(expr);
-}
-
-
-void FlowGraphBuilder::VisitLiteral(Literal* expr) {
- current_->AddInstruction(expr);
-}
-
-
-void FlowGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitAssignment(Assignment* expr) {
- // There are three basic kinds of assignment: variable assignments,
- // property assignments, and invalid left-hand sides (which are translated
- // to "throw ReferenceError" by the parser).
- Variable* var = expr->target()->AsVariableProxy()->AsVariable();
- Property* prop = expr->target()->AsProperty();
- ASSERT(var == NULL || prop == NULL);
- if (var != NULL) {
- if (expr->is_compound() && !expr->target()->IsTrivial()) {
- Visit(expr->target());
- }
- if (!expr->value()->IsTrivial()) Visit(expr->value());
- current_->AddInstruction(expr);
-
- } else if (prop != NULL) {
- if (!prop->obj()->IsTrivial()) Visit(prop->obj());
- if (!prop->key()->IsPropertyName() && !prop->key()->IsTrivial()) {
- Visit(prop->key());
- }
- if (!expr->value()->IsTrivial()) Visit(expr->value());
- current_->AddInstruction(expr);
-
- } else {
- Visit(expr->target());
- }
-}
-
-
-void FlowGraphBuilder::VisitThrow(Throw* expr) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitProperty(Property* expr) {
- if (!expr->obj()->IsTrivial()) Visit(expr->obj());
- if (!expr->key()->IsPropertyName() && !expr->key()->IsTrivial()) {
- Visit(expr->key());
- }
- current_->AddInstruction(expr);
-}
-
-
-void FlowGraphBuilder::VisitCall(Call* expr) {
- Visit(expr->expression());
- VisitExpressions(expr->arguments());
- current_->AddInstruction(expr);
-}
-
-
-void FlowGraphBuilder::VisitCallNew(CallNew* expr) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
- SetStackOverflow();
-}
-
-
-void FlowGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
- switch (expr->op()) {
- case Token::NOT:
- case Token::BIT_NOT:
- case Token::DELETE:
- case Token::TYPEOF:
- case Token::VOID:
- SetStackOverflow();
- break;
-
- case Token::ADD:
- case Token::SUB:
- Visit(expr->expression());
- current_->AddInstruction(expr);
- break;
-
- default:
- UNREACHABLE();
- }
-}
-
-
-void FlowGraphBuilder::VisitCountOperation(CountOperation* expr) {
- Visit(expr->expression());
- current_->AddInstruction(expr);
-}
-
-
-void FlowGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
- switch (expr->op()) {
- case Token::COMMA:
- case Token::OR:
- case Token::AND:
- SetStackOverflow();
- break;
-
- case Token::BIT_OR:
- case Token::BIT_XOR:
- case Token::BIT_AND:
- case Token::SHL:
- case Token::SAR:
- case Token::SHR:
- case Token::ADD:
- case Token::SUB:
- case Token::MUL:
- case Token::DIV:
- case Token::MOD:
- if (!expr->left()->IsTrivial()) Visit(expr->left());
- if (!expr->right()->IsTrivial()) Visit(expr->right());
- current_->AddInstruction(expr);
- break;
-
- default:
- UNREACHABLE();
- }
-}
-
-
-void FlowGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
- switch (expr->op()) {
- case Token::EQ:
- case Token::NE:
- case Token::EQ_STRICT:
- case Token::NE_STRICT:
- case Token::INSTANCEOF:
- case Token::IN:
- SetStackOverflow();
- break;
-
- case Token::LT:
- case Token::GT:
- case Token::LTE:
- case Token::GTE:
- if (!expr->left()->IsTrivial()) Visit(expr->left());
- if (!expr->right()->IsTrivial()) Visit(expr->right());
- current_->AddInstruction(expr);
- break;
-
- default:
- UNREACHABLE();
- }
-}
-
-
-void FlowGraphBuilder::VisitThisFunction(ThisFunction* expr) {
- SetStackOverflow();
-}
-
-
-#ifdef DEBUG
-
-// Print a textual representation of an instruction in a flow graph.
-class InstructionPrinter: public AstVisitor {
- public:
- InstructionPrinter() {}
-
- private:
- // Overridden from the base class.
- virtual void VisitExpressions(ZoneList<Expression*>* exprs);
-
- // AST node visit functions.
-#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
- AST_NODE_LIST(DECLARE_VISIT)
-#undef DECLARE_VISIT
-
- DISALLOW_COPY_AND_ASSIGN(InstructionPrinter);
-};
-
-
-static void PrintSubexpression(Expression* expr) {
- if (!expr->IsTrivial()) {
- PrintF("@%d", expr->num());
- } else if (expr->AsLiteral() != NULL) {
- expr->AsLiteral()->handle()->Print();
- } else if (expr->AsVariableProxy() != NULL) {
- PrintF("%s", *expr->AsVariableProxy()->name()->ToCString());
- } else {
- UNREACHABLE();
- }
-}
-
-
-void InstructionPrinter::VisitExpressions(ZoneList<Expression*>* exprs) {
- for (int i = 0; i < exprs->length(); ++i) {
- if (i != 0) PrintF(", ");
- PrintF("@%d", exprs->at(i)->num());
- }
-}
-
-
-// We only define printing functions for the node types that can occur as
-// instructions in a flow graph. The rest are unreachable.
-void InstructionPrinter::VisitDeclaration(Declaration* decl) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitBlock(Block* stmt) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitExpressionStatement(ExpressionStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitEmptyStatement(EmptyStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitIfStatement(IfStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitContinueStatement(ContinueStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitBreakStatement(BreakStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitReturnStatement(ReturnStatement* stmt) {
- PrintF("return ");
- PrintSubexpression(stmt->expression());
-}
-
-
-void InstructionPrinter::VisitWithEnterStatement(WithEnterStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitWithExitStatement(WithExitStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitSwitchStatement(SwitchStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitDoWhileStatement(DoWhileStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitWhileStatement(WhileStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitForStatement(ForStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitForInStatement(ForInStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitTryCatchStatement(TryCatchStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitDebuggerStatement(DebuggerStatement* stmt) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitFunctionLiteral(FunctionLiteral* expr) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitSharedFunctionInfoLiteral(
- SharedFunctionInfoLiteral* expr) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitConditional(Conditional* expr) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitSlot(Slot* expr) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitVariableProxy(VariableProxy* expr) {
- Variable* var = expr->AsVariable();
- if (var != NULL) {
- PrintF("%s", *var->name()->ToCString());
- } else {
- ASSERT(expr->AsProperty() != NULL);
- Visit(expr->AsProperty());
- }
-}
-
-
-void InstructionPrinter::VisitLiteral(Literal* expr) {
- expr->handle()->Print();
-}
-
-
-void InstructionPrinter::VisitRegExpLiteral(RegExpLiteral* expr) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitObjectLiteral(ObjectLiteral* expr) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitArrayLiteral(ArrayLiteral* expr) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitCatchExtensionObject(
- CatchExtensionObject* expr) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitAssignment(Assignment* expr) {
- Variable* var = expr->target()->AsVariableProxy()->AsVariable();
- Property* prop = expr->target()->AsProperty();
-
- // Print the left-hand side.
- Visit(expr->target());
- if (var == NULL && prop == NULL) return; // Throw reference error.
- PrintF(" = ");
- // For compound assignments, print the left-hand side again and the
- // corresponding binary operator.
- if (expr->is_compound()) {
- PrintSubexpression(expr->target());
- PrintF(" %s ", Token::String(expr->binary_op()));
- }
-
- // Print the right-hand side.
- PrintSubexpression(expr->value());
-}
-
-
-void InstructionPrinter::VisitThrow(Throw* expr) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitProperty(Property* expr) {
- PrintSubexpression(expr->obj());
- if (expr->key()->IsPropertyName()) {
- PrintF(".");
- ASSERT(expr->key()->AsLiteral() != NULL);
- expr->key()->AsLiteral()->handle()->Print();
- } else {
- PrintF("[");
- PrintSubexpression(expr->key());
- PrintF("]");
- }
-}
-
-
-void InstructionPrinter::VisitCall(Call* expr) {
- PrintF("@%d(", expr->expression()->num());
- VisitExpressions(expr->arguments());
- PrintF(")");
-}
-
-
-void InstructionPrinter::VisitCallNew(CallNew* expr) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitCallRuntime(CallRuntime* expr) {
- UNREACHABLE();
-}
-
-
-void InstructionPrinter::VisitUnaryOperation(UnaryOperation* expr) {
- PrintF("%s(@%d)", Token::String(expr->op()), expr->expression()->num());
-}
-
-
-void InstructionPrinter::VisitCountOperation(CountOperation* expr) {
- if (expr->is_prefix()) {
- PrintF("%s@%d", Token::String(expr->op()), expr->expression()->num());
- } else {
- PrintF("@%d%s", expr->expression()->num(), Token::String(expr->op()));
- }
-}
-
-
-void InstructionPrinter::VisitBinaryOperation(BinaryOperation* expr) {
- PrintSubexpression(expr->left());
- PrintF(" %s ", Token::String(expr->op()));
- PrintSubexpression(expr->right());
-}
-
-
-void InstructionPrinter::VisitCompareOperation(CompareOperation* expr) {
- PrintSubexpression(expr->left());
- PrintF(" %s ", Token::String(expr->op()));
- PrintSubexpression(expr->right());
-}
-
-
-void InstructionPrinter::VisitThisFunction(ThisFunction* expr) {
- UNREACHABLE();
-}
-
-
-int BasicBlock::PrintAsText(int instruction_number) {
- // Print a label for all blocks except the entry.
- if (HasPredecessor()) {
- PrintF("L%d:", number());
- }
-
- // Number and print the instructions. Since AST child nodes are visited
- // before their parents, the parent nodes can refer to them by number.
- InstructionPrinter printer;
- for (int i = 0; i < instructions_.length(); ++i) {
- PrintF("\n%d ", instruction_number);
- instructions_[i]->set_num(instruction_number++);
- instructions_[i]->Accept(&printer);
- }
-
- // If this is the exit, print "exit". If there is a single successor,
- // print "goto" successor on a separate line. If there are two
- // successors, print "goto" successor on the same line as the last
- // instruction in the block. There is a blank line between blocks (and
- // after the last one).
- if (left_successor_ == NULL) {
- PrintF("\nexit\n\n");
- } else if (right_successor_ == NULL) {
- PrintF("\ngoto L%d\n\n", left_successor_->number());
- } else {
- PrintF(", goto (L%d, L%d)\n\n",
- left_successor_->number(),
- right_successor_->number());
- }
-
- return instruction_number;
-}
-
-
-void FlowGraph::PrintAsText(Handle<String> name) {
- PrintF("\n==== name = \"%s\" ====\n", *name->ToCString());
- // Print nodes in reverse postorder. Note that AST node numbers are used
- // during printing of instructions and thus their current values are
- // destroyed.
- int number = 0;
- for (int i = postorder_.length() - 1; i >= 0; --i) {
- number = postorder_[i]->PrintAsText(number);
- }
-}
-
-#endif // DEBUG
-
-
-} } // namespace v8::internal
+++ /dev/null
-// Copyright 2010 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.
-
-#ifndef V8_FLOW_GRAPH_H_
-#define V8_FLOW_GRAPH_H_
-
-#include "v8.h"
-
-#include "data-flow.h"
-#include "zone.h"
-
-namespace v8 {
-namespace internal {
-
-// The nodes of a flow graph are basic blocks. Basic blocks consist of
-// instructions represented as pointers to AST nodes in the order that they
-// would be visited by the code generator. A block can have arbitrarily many
-// (even zero) predecessors and up to two successors. Blocks with multiple
-// predecessors are "join nodes" and blocks with multiple successors are
-// "branch nodes". A block can be both a branch and a join node.
-//
-// Flow graphs are in edge split form: a branch node is never the
-// predecessor of a merge node. Empty basic blocks are inserted to maintain
-// edge split form.
-class BasicBlock: public ZoneObject {
- public:
- // Construct a basic block with a given predecessor. NULL indicates no
- // predecessor or that the predecessor will be set later.
- explicit BasicBlock(BasicBlock* predecessor)
- : predecessors_(2),
- instructions_(8),
- left_successor_(NULL),
- right_successor_(NULL),
- mark_(false) {
- if (predecessor != NULL) AddPredecessor(predecessor);
- }
-
- bool HasPredecessor() { return !predecessors_.is_empty(); }
- bool HasSuccessor() { return left_successor_ != NULL; }
-
- // Add a given basic block as a predecessor of this block. This function
- // also adds this block as a successor of the given block.
- void AddPredecessor(BasicBlock* predecessor) {
- ASSERT(predecessor != NULL);
- predecessors_.Add(predecessor);
- predecessor->AddSuccessor(this);
- }
-
- // Add an instruction to the end of this block. The block must be "open"
- // by not having a successor yet.
- void AddInstruction(AstNode* instruction) {
- ASSERT(!HasSuccessor() && instruction != NULL);
- instructions_.Add(instruction);
- }
-
- // Perform a depth-first traversal of graph rooted at this node,
- // accumulating pre- and postorder traversal orders. Visited nodes are
- // marked with mark.
- void BuildTraversalOrder(ZoneList<BasicBlock*>* preorder,
- ZoneList<BasicBlock*>* postorder,
- bool mark);
- bool GetMark() { return mark_; }
-
-#ifdef DEBUG
- // In debug mode, blocks are numbered in reverse postorder to help with
- // printing.
- int number() { return number_; }
- void set_number(int n) { number_ = n; }
-
- // Print a basic block, given the number of the first instruction.
- // Returns the next number after the number of the last instruction.
- int PrintAsText(int instruction_number);
-#endif
-
- private:
- // Add a given basic block as successor to this block. This function does
- // not add this block as a predecessor of the given block so as to avoid
- // circularity.
- void AddSuccessor(BasicBlock* successor) {
- ASSERT(right_successor_ == NULL && successor != NULL);
- if (HasSuccessor()) {
- right_successor_ = successor;
- } else {
- left_successor_ = successor;
- }
- }
-
- ZoneList<BasicBlock*> predecessors_;
- ZoneList<AstNode*> instructions_;
- BasicBlock* left_successor_;
- BasicBlock* right_successor_;
-
- // Support for graph traversal. Before traversal, all nodes in the graph
- // have the same mark (true or false). Traversal marks already-visited
- // nodes with the opposite mark. After traversal, all nodes again have
- // the same mark. Traversal of the same graph is not reentrant.
- bool mark_;
-
-#ifdef DEBUG
- int number_;
-#endif
-
- DISALLOW_COPY_AND_ASSIGN(BasicBlock);
-};
-
-
-// A flow graph has distinguished entry and exit blocks. The entry block is
-// the only one with no predecessors and the exit block is the only one with
-// no successors.
-class FlowGraph: public ZoneObject {
- public:
- FlowGraph(BasicBlock* entry, BasicBlock* exit)
- : entry_(entry), exit_(exit), preorder_(8), postorder_(8) {
- }
-
- ZoneList<BasicBlock*>* preorder() { return &preorder_; }
- ZoneList<BasicBlock*>* postorder() { return &postorder_; }
-
-#ifdef DEBUG
- void PrintAsText(Handle<String> name);
-#endif
-
- private:
- BasicBlock* entry_;
- BasicBlock* exit_;
- ZoneList<BasicBlock*> preorder_;
- ZoneList<BasicBlock*> postorder_;
-};
-
-
-// The flow graph builder walks the AST adding reachable AST nodes to the
-// flow graph as instructions. It remembers the entry and exit nodes of the
-// graph, and keeps a pointer to the current block being constructed.
-class FlowGraphBuilder: public AstVisitor {
- public:
- FlowGraphBuilder() {}
-
- FlowGraph* Build(FunctionLiteral* lit);
-
- private:
- // AST node visit functions.
-#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
- AST_NODE_LIST(DECLARE_VISIT)
-#undef DECLARE_VISIT
-
- BasicBlock* entry_;
- BasicBlock* exit_;
- BasicBlock* current_;
-
- DISALLOW_COPY_AND_ASSIGN(FlowGraphBuilder);
-};
-
-
-} } // namespace v8::internal
-
-#endif // V8_FLOW_GRAPH_H_
}
+void FullCodeGenSyntaxChecker::VisitCompareToNull(CompareToNull* expr) {
+ Visit(expr->expression());
+}
+
+
void FullCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) {
// Supported.
}
}
+void BreakableStatementChecker::VisitCompareToNull(CompareToNull* expr) {
+ Visit(expr->expression());
+}
+
+
void BreakableStatementChecker::VisitCompareOperation(CompareOperation* expr) {
Visit(expr->left());
Visit(expr->right());
ConstantSmiComparison(cc, strict, dest, &left_side, &right_side,
left_side_constant_smi, right_side_constant_smi,
is_loop_condition);
- } else if (cc == equal &&
- (left_side_constant_null || right_side_constant_null)) {
- // To make null checks efficient, we check if either the left side or
- // the right side is the constant 'null'.
- // If so, we optimize the code by inlining a null check instead of
- // calling the (very) general runtime routine for checking equality.
- Result operand = left_side_constant_null ? right_side : left_side;
- right_side.Unuse();
- left_side.Unuse();
- operand.ToRegister();
- __ cmp(operand.reg(), Factory::null_value());
- if (strict) {
- operand.Unuse();
- dest->Split(equal);
- } else {
- // The 'null' value is only equal to 'undefined' if using non-strict
- // comparisons.
- dest->true_target()->Branch(equal);
- __ cmp(operand.reg(), Factory::undefined_value());
- dest->true_target()->Branch(equal);
- __ test(operand.reg(), Immediate(kSmiTagMask));
- dest->false_target()->Branch(equal);
-
- // It can be an undetectable object.
- // Use a scratch register in preference to spilling operand.reg().
- Result temp = allocator()->Allocate();
- ASSERT(temp.is_valid());
- __ mov(temp.reg(),
- FieldOperand(operand.reg(), HeapObject::kMapOffset));
- __ test_b(FieldOperand(temp.reg(), Map::kBitFieldOffset),
- 1 << Map::kIsUndetectable);
- temp.Unuse();
- operand.Unuse();
- dest->Split(not_zero);
- }
} else if (left_side_constant_1_char_string ||
right_side_constant_1_char_string) {
if (left_side_constant_1_char_string && right_side_constant_1_char_string) {
(node->value()->AsBinaryOperation() != NULL &&
node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
// Construct the implicit binary operation.
- BinaryOperation expr(node, node->binary_op(), node->target(),
- node->value());
+ BinaryOperation expr(node->binary_op(), node->target(), node->value());
+ expr.CopyAnalysisResultsFrom(node);
GenericBinaryOperation(&expr,
overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
} else {
(node->value()->AsBinaryOperation() != NULL &&
node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
// Construct the implicit binary operation.
- BinaryOperation expr(node, node->binary_op(), node->target(),
- node->value());
+ BinaryOperation expr(node->binary_op(), node->target(), node->value());
+ expr.CopyAnalysisResultsFrom(node);
GenericBinaryOperation(&expr,
overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
} else {
bool overwrite_value =
(node->value()->AsBinaryOperation() != NULL &&
node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
- BinaryOperation expr(node, node->binary_op(), node->target(),
- node->value());
+ BinaryOperation expr(node->binary_op(), node->target(), node->value());
+ expr.CopyAnalysisResultsFrom(node);
GenericBinaryOperation(&expr,
overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
} else {
}
+void CodeGenerator::VisitCompareToNull(CompareToNull* node) {
+ ASSERT(!in_safe_int32_mode());
+ Comment cmnt(masm_, "[ CompareToNull");
+
+ Load(node->expression());
+ Result operand = frame_->Pop();
+ operand.ToRegister();
+ __ cmp(operand.reg(), Factory::null_value());
+ if (node->is_strict()) {
+ operand.Unuse();
+ destination()->Split(equal);
+ } else {
+ // The 'null' value is only equal to 'undefined' if using non-strict
+ // comparisons.
+ destination()->true_target()->Branch(equal);
+ __ cmp(operand.reg(), Factory::undefined_value());
+ destination()->true_target()->Branch(equal);
+ __ test(operand.reg(), Immediate(kSmiTagMask));
+ destination()->false_target()->Branch(equal);
+
+ // It can be an undetectable object.
+ // Use a scratch register in preference to spilling operand.reg().
+ Result temp = allocator()->Allocate();
+ ASSERT(temp.is_valid());
+ __ mov(temp.reg(),
+ FieldOperand(operand.reg(), HeapObject::kMapOffset));
+ __ test_b(FieldOperand(temp.reg(), Map::kBitFieldOffset),
+ 1 << Map::kIsUndetectable);
+ temp.Unuse();
+ operand.Unuse();
+ destination()->Split(not_zero);
+ }
+}
+
+
#ifdef DEBUG
bool CodeGenerator::HasValidEntryRegisters() {
return (allocator()->count(eax) == (frame()->is_used(eax) ? 1 : 0))
}
+void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
+ Label materialize_true, materialize_false;
+ Label* if_true = NULL;
+ Label* if_false = NULL;
+ PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+
+ VisitForValue(expr->expression(), kAccumulator);
+ __ cmp(eax, Factory::null_value());
+ if (expr->is_strict()) {
+ Split(equal, if_true, if_false, NULL);
+ } else {
+ __ j(equal, if_true);
+ __ cmp(eax, Factory::undefined_value());
+ __ j(equal, if_true);
+ __ test(eax, Immediate(kSmiTagMask));
+ __ j(zero, if_false);
+ // It can be an undetectable object.
+ __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
+ __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset));
+ __ test(edx, Immediate(1 << Map::kIsUndetectable));
+ Split(not_zero, if_true, if_false, NULL);
+ }
+ Apply(context_, if_true, if_false);
+}
+
+
void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
__ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Apply(context_, eax);
ParserLog* log_;
bool is_pre_parsing_;
ScriptDataImpl* pre_data_;
- bool seen_loop_stmt_; // Used for inner loop detection.
FuncNameInferrer* fni_;
bool inside_with() const { return with_nesting_level_ > 0; }
ObjectLiteral::Property* ParseObjectLiteralGetSet(bool is_getter, bool* ok);
Expression* ParseRegExpLiteral(bool seen_equal, bool* ok);
+ Expression* NewCompareNode(Token::Value op, Expression* x, Expression* y);
+
// Populate the constant properties fixed array for a materialized object
// literal.
void BuildObjectLiteralConstantProperties(
log_(log),
is_pre_parsing_(is_pre_parsing == PREPARSE),
pre_data_(pre_data),
- seen_loop_stmt_(false),
fni_(NULL) {
}
if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON);
if (loop != NULL) loop->Initialize(cond, body);
-
- seen_loop_stmt_ = true;
-
return loop;
}
Statement* body = ParseStatement(NULL, CHECK_OK);
if (loop != NULL) loop->Initialize(cond, body);
-
- seen_loop_stmt_ = true;
-
return loop;
}
Block* result = NEW(Block(NULL, 2, false));
result->AddStatement(variable_statement);
result->AddStatement(loop);
-
- seen_loop_stmt_ = true;
-
// Parsed for-in loop w/ variable/const declaration.
return result;
}
Statement* body = ParseStatement(NULL, CHECK_OK);
if (loop) loop->Initialize(expression, enumerable, body);
-
- seen_loop_stmt_ = true;
-
// Parsed for-in loop.
return loop;
}
Expect(Token::RPAREN, CHECK_OK);
- seen_loop_stmt_ = false;
-
Statement* body = ParseStatement(NULL, CHECK_OK);
-
- // Mark this loop if it is an inner loop.
- if (loop && !seen_loop_stmt_) loop->set_peel_this_loop(true);
-
if (loop) loop->Initialize(init, cond, next, body);
-
- seen_loop_stmt_ = true;
-
return loop;
}
// For now we distinguish between comparisons and other binary
// operations. (We could combine the two and get rid of this
- // code an AST node eventually.)
+ // code and AST node eventually.)
if (Token::IsCompareOp(op)) {
// We have a comparison.
Token::Value cmp = op;
case Token::NE_STRICT: cmp = Token::EQ_STRICT; break;
default: break;
}
- x = NEW(CompareOperation(cmp, x, y));
+ x = NewCompareNode(cmp, x, y);
if (cmp != op) {
// The comparison was negated - add a NOT.
x = NEW(UnaryOperation(Token::NOT, x));
}
+Expression* Parser::NewCompareNode(Token::Value op,
+ Expression* x,
+ Expression* y) {
+ ASSERT(op != Token::NE && op != Token::NE_STRICT);
+ if (!is_pre_parsing_ && (op == Token::EQ || op == Token::EQ_STRICT)) {
+ bool is_strict = (op == Token::EQ_STRICT);
+ Literal* x_literal = x->AsLiteral();
+ if (x_literal != NULL && x_literal->IsNull()) {
+ return NEW(CompareToNull(is_strict, y));
+ }
+
+ Literal* y_literal = y->AsLiteral();
+ if (y_literal != NULL && y_literal->IsNull()) {
+ return NEW(CompareToNull(is_strict, x));
+ }
+ }
+ return NEW(CompareOperation(op, x, y));
+}
+
+
Expression* Parser::ParseUnaryExpression(bool* ok) {
// UnaryExpression ::
// PostfixExpression
bool* ok) {
// Function ::
// '(' FormalParameterList? ')' '{' FunctionBody '}'
-
- // Reset flag used for inner loop detection.
- seen_loop_stmt_ = false;
-
bool is_named = !var_name.is_null();
// The name associated with this function. If it's a function expression,
function_literal->set_function_token_position(function_token_position);
}
- // Set flag for inner loop detection. We treat loops that contain a function
- // literal not as inner loops because we avoid duplicating function literals
- // when peeling or unrolling such a loop.
- seen_loop_stmt_ = true;
-
if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal);
return function_literal;
}
}
+void PrettyPrinter::VisitCompareToNull(CompareToNull* node) {
+ Print("(");
+ Visit(node->expression());
+ Print("%s null)", Token::String(node->op()));
+}
+
+
void PrettyPrinter::VisitThisFunction(ThisFunction* node) {
Print("<this-function>");
}
ast_printer_->Print(StaticType::Type2String(expr->type()));
printed_first = true;
}
- if (expr->num() != AstNode::kNoNumber) {
- ast_printer_->Print(printed_first ? ", num = " : " (num = ");
- ast_printer_->Print("%d", expr->num());
- printed_first = true;
- }
if (printed_first) ast_printer_->Print(")");
}
ast_printer_->Print("\n");
void AstPrinter::PrintLiteralWithModeIndented(const char* info,
Variable* var,
Handle<Object> value,
- StaticType* type,
- int num,
- bool is_primitive) {
+ StaticType* type) {
if (var == NULL) {
PrintLiteralIndented(info, value, true);
} else {
pos += OS::SNPrintF(buf + pos, ", type = %s",
StaticType::Type2String(type));
}
- if (num != AstNode::kNoNumber) {
- pos += OS::SNPrintF(buf + pos, ", num = %d", num);
- }
- pos += OS::SNPrintF(buf + pos,
- is_primitive ? ", primitive" : ", non-primitive");
OS::SNPrintF(buf + pos, ")");
PrintLiteralIndented(buf.start(), value, true);
}
for (int i = 0; i < scope->num_parameters(); i++) {
PrintLiteralWithModeIndented("VAR", scope->parameter(i),
scope->parameter(i)->name(),
- scope->parameter(i)->type(),
- AstNode::kNoNumber,
- false);
+ scope->parameter(i)->type());
}
}
}
PrintLiteralWithModeIndented(Variable::Mode2String(node->mode()),
node->proxy()->AsVariable(),
node->proxy()->name(),
- node->proxy()->AsVariable()->type(),
- AstNode::kNoNumber,
- node->proxy()->IsPrimitive());
+ node->proxy()->AsVariable()->type());
} else {
// function declarations
PrintIndented("FUNCTION ");
void AstPrinter::VisitVariableProxy(VariableProxy* node) {
PrintLiteralWithModeIndented("VAR PROXY", node->AsVariable(), node->name(),
- node->type(), node->num(), node->IsPrimitive());
+ node->type());
Variable* var = node->var();
if (var != NULL && var->rewrite() != NULL) {
IndentedScope indent;
}
+void AstPrinter::VisitCompareToNull(CompareToNull* node) {
+ const char* name = node->is_strict()
+ ? "COMPARE-TO-NULL-STRICT"
+ : "COMPARE-TO-NULL";
+ IndentedScope indent(name, node);
+ Visit(node->expression());
+}
+
+
void AstPrinter::VisitThisFunction(ThisFunction* node) {
IndentedScope indent("THIS-FUNCTION");
}
}
+void JsonAstBuilder::VisitCompareToNull(CompareToNull* expr) {
+ TagScope tag(this, "CompareToNull");
+ {
+ AttributesScope attributes(this);
+ AddAttribute("is_strict", expr->is_strict());
+ }
+ Visit(expr->expression());
+}
+
+
void JsonAstBuilder::VisitThisFunction(ThisFunction* expr) {
TagScope tag(this, "ThisFunction");
}
void PrintLiteralWithModeIndented(const char* info,
Variable* var,
Handle<Object> value,
- StaticType* type,
- int num,
- bool is_primitive);
+ StaticType* type);
void PrintLabelsIndented(const char* info, ZoneStringList* labels);
void inc_indent() { indent_++; }
has_function_literal_ = false;
node->cond()->set_no_negative_zero(true);
Visit(node->cond());
- node->may_have_function_literal_ = has_function_literal_;
+ node->set_may_have_function_literal(has_function_literal_);
Visit(node->body());
}
has_function_literal_ = false;
node->cond()->set_no_negative_zero(true);
Visit(node->cond());
- node->may_have_function_literal_ = has_function_literal_;
+ node->set_may_have_function_literal(has_function_literal_);
}
Visit(node->body());
if (node->next() != NULL) {
}
+void AstOptimizer::VisitCompareToNull(CompareToNull* node) {
+ Visit(node->expression());
+}
+
+
void AstOptimizer::VisitThisFunction(ThisFunction* node) {
USE(node);
}
}
+void Processor::VisitCompareToNull(CompareToNull* node) {
+ USE(node);
+ UNREACHABLE();
+}
+
+
void Processor::VisitThisFunction(ThisFunction* node) {
USE(node);
UNREACHABLE();
ConstantSmiComparison(cc, strict, dest, &left_side, &right_side,
left_side_constant_smi, right_side_constant_smi,
is_loop_condition);
- } else if (cc == equal &&
- (left_side_constant_null || right_side_constant_null)) {
- // To make null checks efficient, we check if either the left side or
- // the right side is the constant 'null'.
- // If so, we optimize the code by inlining a null check instead of
- // calling the (very) general runtime routine for checking equality.
- Result operand = left_side_constant_null ? right_side : left_side;
- right_side.Unuse();
- left_side.Unuse();
- operand.ToRegister();
- __ CompareRoot(operand.reg(), Heap::kNullValueRootIndex);
- if (strict) {
- operand.Unuse();
- dest->Split(equal);
- } else {
- // The 'null' value is only equal to 'undefined' if using non-strict
- // comparisons.
- dest->true_target()->Branch(equal);
- __ CompareRoot(operand.reg(), Heap::kUndefinedValueRootIndex);
- dest->true_target()->Branch(equal);
- Condition is_smi = masm_->CheckSmi(operand.reg());
- dest->false_target()->Branch(is_smi);
-
- // It can be an undetectable object.
- // Use a scratch register in preference to spilling operand.reg().
- Result temp = allocator()->Allocate();
- ASSERT(temp.is_valid());
- __ movq(temp.reg(),
- FieldOperand(operand.reg(), HeapObject::kMapOffset));
- __ testb(FieldOperand(temp.reg(), Map::kBitFieldOffset),
- Immediate(1 << Map::kIsUndetectable));
- temp.Unuse();
- operand.Unuse();
- dest->Split(not_zero);
- }
} else if (left_side_constant_1_char_string ||
right_side_constant_1_char_string) {
if (left_side_constant_1_char_string && right_side_constant_1_char_string) {
(node->value()->AsBinaryOperation() != NULL &&
node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
// Construct the implicit binary operation.
- BinaryOperation expr(node, node->binary_op(), node->target(),
- node->value());
+ BinaryOperation expr(node->binary_op(), node->target(), node->value());
+ expr.CopyAnalysisResultsFrom(node);
GenericBinaryOperation(&expr,
overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
} else {
(node->value()->AsBinaryOperation() != NULL &&
node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
// Construct the implicit binary operation.
- BinaryOperation expr(node, node->binary_op(), node->target(),
- node->value());
+ BinaryOperation expr(node->binary_op(), node->target(), node->value());
+ expr.CopyAnalysisResultsFrom(node);
GenericBinaryOperation(&expr,
overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
} else {
bool overwrite_value =
(node->value()->AsBinaryOperation() != NULL &&
node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
- BinaryOperation expr(node, node->binary_op(), node->target(),
- node->value());
+ BinaryOperation expr(node->binary_op(), node->target(), node->value());
+ expr.CopyAnalysisResultsFrom(node);
GenericBinaryOperation(&expr,
overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
} else {
}
+void CodeGenerator::VisitCompareToNull(CompareToNull* node) {
+ Comment cmnt(masm_, "[ CompareToNull");
+
+ Load(node->expression());
+ Result operand = frame_->Pop();
+ operand.ToRegister();
+ __ CompareRoot(operand.reg(), Heap::kNullValueRootIndex);
+ if (node->is_strict()) {
+ operand.Unuse();
+ destination()->Split(equal);
+ } else {
+ // The 'null' value is only equal to 'undefined' if using non-strict
+ // comparisons.
+ destination()->true_target()->Branch(equal);
+ __ CompareRoot(operand.reg(), Heap::kUndefinedValueRootIndex);
+ destination()->true_target()->Branch(equal);
+ Condition is_smi = masm_->CheckSmi(operand.reg());
+ destination()->false_target()->Branch(is_smi);
+
+ // It can be an undetectable object.
+ // Use a scratch register in preference to spilling operand.reg().
+ Result temp = allocator()->Allocate();
+ ASSERT(temp.is_valid());
+ __ movq(temp.reg(),
+ FieldOperand(operand.reg(), HeapObject::kMapOffset));
+ __ testb(FieldOperand(temp.reg(), Map::kBitFieldOffset),
+ Immediate(1 << Map::kIsUndetectable));
+ temp.Unuse();
+ operand.Unuse();
+ destination()->Split(not_zero);
+ }
+}
+
+
#ifdef DEBUG
bool CodeGenerator::HasValidEntryRegisters() {
return (allocator()->count(rax) == (frame()->is_used(rax) ? 1 : 0))
}
+void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
+ Comment cmnt(masm_, "[ CompareToNull");
+ Label materialize_true, materialize_false;
+ Label* if_true = NULL;
+ Label* if_false = NULL;
+ PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+
+ VisitForValue(expr->expression(), kAccumulator);
+ __ CompareRoot(rax, Heap::kNullValueRootIndex);
+ if (expr->is_strict()) {
+ Split(equal, if_true, if_false, NULL);
+ } else {
+ __ j(equal, if_true);
+ __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
+ __ j(equal, if_true);
+ Condition is_smi = masm_->CheckSmi(rax);
+ __ j(is_smi, if_false);
+ // It can be an undetectable object.
+ __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
+ __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
+ Immediate(1 << Map::kIsUndetectable));
+ Split(not_zero, if_true, if_false, NULL);
+ }
+ Apply(context_, if_true, if_false);
+}
+
+
void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
__ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
Apply(context_, rax);
'../../src/fixed-dtoa.h',
'../../src/flags.cc',
'../../src/flags.h',
- '../../src/flow-graph.cc',
- '../../src/flow-graph.h',
'../../src/frame-element.cc',
'../../src/frame-element.h',
'../../src/frames-inl.h',
>
</File>
<File
- RelativePath="..\..\src\flow-graph.cc"
- >
- </File>
- <File
- RelativePath="..\..\src\flow-graph.h"
- >
- </File>
- <File
RelativePath="..\..\src\frame-element.cc"
>
</File>