Add a predicate IsPrimitive to AST Expression nodes.

IsPrimitive reflects that an expression's value is known statically to
be one of the ECMA-262-3 JS types other than Object (e.g., Undefined,
Null, Boolean, String, or Number).

The type conversions ToPrimitive, ToNumber, ToInteger, ToInt32,
ToUInt32, ToUint16, ToString, or ToObject cannot invoke user code for
primitive input values.  ToObject throws a TypeError if its input is
Undefined or Null.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4116 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kmillikin@chromium.org 2010-03-12 13:10:42 +00:00
parent 5f75b01bb1
commit ac896bb5a0
2 changed files with 150 additions and 0 deletions

View File

@ -498,5 +498,96 @@ RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes)
}
}
// 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 FunctionBoilerplateLiteral::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 VariableProxy::IsPrimitive() { return false; }
bool Property::IsPrimitive() { return false; }
bool Call::IsPrimitive() { return false; }
bool CallRuntime::IsPrimitive() { return false; }
// 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; }
} } // namespace v8::internal

View File

@ -220,6 +220,10 @@ class Expression: public AstNode {
// 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.
@ -280,6 +284,12 @@ class ValidLeftHandSideSentinel: public Expression {
virtual bool IsValidLeftHandSide() { return true; }
virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
static ValidLeftHandSideSentinel* instance() { return &instance_; }
virtual bool IsPrimitive() {
UNREACHABLE();
return false;
}
private:
static ValidLeftHandSideSentinel instance_;
};
@ -798,6 +808,7 @@ class Literal: public Expression {
virtual bool IsLeaf() { return true; }
virtual bool IsTrivial() { return true; }
virtual bool IsPrimitive();
// Identity testers.
bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
@ -885,6 +896,8 @@ class ObjectLiteral: public MaterializedLiteral {
virtual bool IsLeaf() { return properties()->is_empty(); }
virtual bool IsPrimitive();
Handle<FixedArray> constant_properties() const {
return constant_properties_;
}
@ -913,6 +926,8 @@ class RegExpLiteral: public MaterializedLiteral {
virtual bool IsLeaf() { return true; }
virtual bool IsPrimitive();
Handle<String> pattern() const { return pattern_; }
Handle<String> flags() const { return flags_; }
@ -939,6 +954,8 @@ class ArrayLiteral: public MaterializedLiteral {
virtual bool IsLeaf() { return values()->is_empty(); }
virtual bool IsPrimitive();
Handle<FixedArray> constant_elements() const { return constant_elements_; }
ZoneList<Expression*>* values() const { return values_; }
@ -959,6 +976,8 @@ class CatchExtensionObject: public Expression {
virtual void Accept(AstVisitor* v);
virtual bool IsPrimitive();
Literal* key() const { return key_; }
VariableProxy* value() const { return value_; }
@ -995,6 +1014,8 @@ class VariableProxy: public Expression {
// immutable.
virtual bool IsTrivial() { return is_trivial_; }
virtual bool IsPrimitive();
bool IsVariable(Handle<String> n) {
return !is_this() && name().is_identical_to(n);
}
@ -1036,6 +1057,11 @@ class VariableProxySentinel: public VariableProxy {
return &identifier_proxy_;
}
virtual bool IsPrimitive() {
UNREACHABLE();
return false;
}
private:
explicit VariableProxySentinel(bool is_this) : VariableProxy(is_this) { }
static VariableProxySentinel this_proxy_;
@ -1079,6 +1105,11 @@ class Slot: public Expression {
virtual bool IsLeaf() { return true; }
virtual bool IsPrimitive() {
UNREACHABLE();
return false;
}
bool IsStackAllocated() { return type_ == PARAMETER || type_ == LOCAL; }
// Accessors
@ -1111,6 +1142,8 @@ class Property: public Expression {
virtual bool IsValidLeftHandSide() { return true; }
virtual bool IsPrimitive();
Expression* obj() const { return obj_; }
Expression* key() const { return key_; }
int position() const { return pos_; }
@ -1141,6 +1174,8 @@ class Call: public Expression {
// Type testing and conversion.
virtual Call* AsCall() { return this; }
virtual bool IsPrimitive();
Expression* expression() const { return expression_; }
ZoneList<Expression*>* arguments() const { return arguments_; }
int position() { return pos_; }
@ -1163,6 +1198,8 @@ class CallNew: public Expression {
virtual void Accept(AstVisitor* v);
virtual bool IsPrimitive();
Expression* expression() const { return expression_; }
ZoneList<Expression*>* arguments() const { return arguments_; }
int position() { return pos_; }
@ -1187,6 +1224,8 @@ class CallRuntime: public Expression {
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_; }
@ -1211,6 +1250,8 @@ class UnaryOperation: public Expression {
// Type testing & conversion
virtual UnaryOperation* AsUnaryOperation() { return this; }
virtual bool IsPrimitive();
Token::Value op() const { return op_; }
Expression* expression() const { return expression_; }
@ -1232,6 +1273,8 @@ class BinaryOperation: public Expression {
// Type testing & conversion
virtual BinaryOperation* AsBinaryOperation() { return this; }
virtual bool IsPrimitive();
// True iff the result can be safely overwritten (to avoid allocation).
// False for operations that can return one of their operands.
bool ResultOverwriteAllowed() {
@ -1284,6 +1327,8 @@ class CountOperation: public Expression {
return expression()->AsVariableProxy()->AsVariable();
}
virtual bool IsPrimitive();
bool is_prefix() const { return is_prefix_; }
bool is_postfix() const { return !is_prefix_; }
Token::Value op() const { return op_; }
@ -1310,6 +1355,8 @@ class CompareOperation: public Expression {
virtual void Accept(AstVisitor* v);
virtual bool IsPrimitive();
Token::Value op() const { return op_; }
Expression* left() const { return left_; }
Expression* right() const { return right_; }
@ -1340,6 +1387,8 @@ class Conditional: public Expression {
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_; }
@ -1362,6 +1411,8 @@ class Assignment: public Expression {
virtual void Accept(AstVisitor* v);
virtual Assignment* AsAssignment() { return this; }
virtual bool IsPrimitive();
Assignment* AsSimpleAssignment() { return !is_compound() ? this : NULL; }
virtual Variable* AssignedVar() {
@ -1402,6 +1453,9 @@ class Throw: public Expression {
: exception_(exception), pos_(pos) {}
virtual void Accept(AstVisitor* v);
virtual bool IsPrimitive();
Expression* exception() const { return exception_; }
int position() const { return pos_; }
@ -1451,6 +1505,8 @@ class FunctionLiteral: public Expression {
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_; }
@ -1521,6 +1577,8 @@ class FunctionBoilerplateLiteral: public Expression {
virtual void Accept(AstVisitor* v);
virtual bool IsPrimitive();
private:
Handle<JSFunction> boilerplate_;
};
@ -1530,6 +1588,7 @@ class ThisFunction: public Expression {
public:
virtual void Accept(AstVisitor* v);
virtual bool IsLeaf() { return true; }
virtual bool IsPrimitive();
};