Revision: 4116
Author: [email protected]
Date: Fri Mar 12 05:10:42 2010
Log: 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
http://code.google.com/p/v8/source/detail?r=4116
Modified:
/branches/bleeding_edge/src/ast.cc
/branches/bleeding_edge/src/ast.h
=======================================
--- /branches/bleeding_edge/src/ast.cc Thu Mar 11 02:28:40 2010
+++ /branches/bleeding_edge/src/ast.cc Fri Mar 12 05:10:42 2010
@@ -497,6 +497,97 @@
}
}
}
+
+// 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
=======================================
--- /branches/bleeding_edge/src/ast.h Thu Mar 11 08:24:05 2010
+++ /branches/bleeding_edge/src/ast.h Fri Mar 12 05:10:42 2010
@@ -219,6 +219,10 @@
// 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
@@ -280,6 +284,12 @@
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 @@
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()); }
@@ -884,6 +895,8 @@
virtual void Accept(AstVisitor* v);
virtual bool IsLeaf() { return properties()->is_empty(); }
+
+ virtual bool IsPrimitive();
Handle<FixedArray> constant_properties() const {
return constant_properties_;
@@ -912,6 +925,8 @@
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_; }
@@ -938,6 +953,8 @@
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_; }
@@ -959,6 +976,8 @@
virtual void Accept(AstVisitor* v);
+ virtual bool IsPrimitive();
+
Literal* key() const { return key_; }
VariableProxy* value() const { return value_; }
@@ -994,6 +1013,8 @@
// Reading from a mutable variable is a side effect, but 'this' is
// immutable.
virtual bool IsTrivial() { return is_trivial_; }
+
+ virtual bool IsPrimitive();
bool IsVariable(Handle<String> n) {
return !is_this() && name().is_identical_to(n);
@@ -1035,6 +1056,11 @@
static VariableProxySentinel* identifier_proxy() {
return &identifier_proxy_;
}
+
+ virtual bool IsPrimitive() {
+ UNREACHABLE();
+ return false;
+ }
private:
explicit VariableProxySentinel(bool is_this) : VariableProxy(is_this) { }
@@ -1078,6 +1104,11 @@
virtual Slot* AsSlot() { return this; }
virtual bool IsLeaf() { return true; }
+
+ virtual bool IsPrimitive() {
+ UNREACHABLE();
+ return false;
+ }
bool IsStackAllocated() { return type_ == PARAMETER || type_ == LOCAL; }
@@ -1110,6 +1141,8 @@
virtual Property* AsProperty() { return this; }
virtual bool IsValidLeftHandSide() { return true; }
+
+ virtual bool IsPrimitive();
Expression* obj() const { return obj_; }
Expression* key() const { return key_; }
@@ -1140,6 +1173,8 @@
// Type testing and conversion.
virtual Call* AsCall() { return this; }
+
+ virtual bool IsPrimitive();
Expression* expression() const { return expression_; }
ZoneList<Expression*>* arguments() const { return arguments_; }
@@ -1163,6 +1198,8 @@
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 @@
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_; }
@@ -1210,6 +1249,8 @@
// Type testing & conversion
virtual UnaryOperation* AsUnaryOperation() { return this; }
+
+ virtual bool IsPrimitive();
Token::Value op() const { return op_; }
Expression* expression() const { return expression_; }
@@ -1231,6 +1272,8 @@
// 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.
@@ -1283,6 +1326,8 @@
virtual Variable* AssignedVar() {
return expression()->AsVariableProxy()->AsVariable();
}
+
+ virtual bool IsPrimitive();
bool is_prefix() const { return is_prefix_; }
bool is_postfix() const { return !is_prefix_; }
@@ -1310,6 +1355,8 @@
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 @@
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_; }
@@ -1361,6 +1410,8 @@
virtual void Accept(AstVisitor* v);
virtual Assignment* AsAssignment() { return this; }
+
+ virtual bool IsPrimitive();
Assignment* AsSimpleAssignment() { return !is_compound() ? this : NULL; }
@@ -1402,6 +1453,9 @@
: exception_(exception), pos_(pos) {}
virtual void Accept(AstVisitor* v);
+
+ virtual bool IsPrimitive();
+
Expression* exception() const { return exception_; }
int position() const { return pos_; }
@@ -1450,6 +1504,8 @@
virtual FunctionLiteral* AsFunctionLiteral() { return this; }
virtual bool IsLeaf() { return true; }
+
+ virtual bool IsPrimitive();
Handle<String> name() const { return name_; }
Scope* scope() const { return scope_; }
@@ -1521,6 +1577,8 @@
virtual void Accept(AstVisitor* v);
+ virtual bool IsPrimitive();
+
private:
Handle<JSFunction> boilerplate_;
};
@@ -1530,6 +1588,7 @@
public:
virtual void Accept(AstVisitor* v);
virtual bool IsLeaf() { return true; }
+ virtual bool IsPrimitive();
};
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev