Commit 2b72eeed authored by olehougaard's avatar olehougaard

Change implementation of eval to make an exact distinction between direct eval and aliased eval.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@860 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 1a9e303e
...@@ -38,14 +38,15 @@ VariableProxySentinel VariableProxySentinel::this_proxy_(true); ...@@ -38,14 +38,15 @@ VariableProxySentinel VariableProxySentinel::this_proxy_(true);
VariableProxySentinel VariableProxySentinel::identifier_proxy_(false); VariableProxySentinel VariableProxySentinel::identifier_proxy_(false);
ValidLeftHandSideSentinel ValidLeftHandSideSentinel::instance_; ValidLeftHandSideSentinel ValidLeftHandSideSentinel::instance_;
Property Property::this_property_(VariableProxySentinel::this_proxy(), NULL, 0); Property Property::this_property_(VariableProxySentinel::this_proxy(), NULL, 0);
Call Call::sentinel_(NULL, NULL, false, 0); Call Call::sentinel_(NULL, NULL, 0);
CallEval CallEval::sentinel_(NULL, NULL, 0);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// All the Accept member functions for each syntax tree node type. // All the Accept member functions for each syntax tree node type.
#define DECL_ACCEPT(type) \ #define DECL_ACCEPT(type) \
void type::Accept(Visitor* v) { \ void type::Accept(AstVisitor* v) { \
if (v->CheckStackOverflow()) return; \ if (v->CheckStackOverflow()) return; \
v->Visit##type(this); \ v->Visit##type(this); \
} }
...@@ -158,17 +159,17 @@ void LabelCollector::AddLabel(Label* label) { ...@@ -158,17 +159,17 @@ void LabelCollector::AddLabel(Label* label) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Implementation of Visitor // Implementation of AstVisitor
void Visitor::VisitStatements(ZoneList<Statement*>* statements) { void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) {
for (int i = 0; i < statements->length(); i++) { for (int i = 0; i < statements->length(); i++) {
Visit(statements->at(i)); Visit(statements->at(i));
} }
} }
void Visitor::VisitExpressions(ZoneList<Expression*>* expressions) { void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) {
for (int i = 0; i < expressions->length(); i++) { for (int i = 0; i < expressions->length(); i++) {
// The variable statement visiting code may pass NULL expressions // The variable statement visiting code may pass NULL expressions
// to this code. Maybe this should be handled by introducing an // to this code. Maybe this should be handled by introducing an
......
...@@ -81,6 +81,7 @@ namespace v8 { namespace internal { ...@@ -81,6 +81,7 @@ namespace v8 { namespace internal {
V(Throw) \ V(Throw) \
V(Property) \ V(Property) \
V(Call) \ V(Call) \
V(CallEval) \
V(CallNew) \ V(CallNew) \
V(CallRuntime) \ V(CallRuntime) \
V(UnaryOperation) \ V(UnaryOperation) \
...@@ -104,7 +105,7 @@ class Node: public ZoneObject { ...@@ -104,7 +105,7 @@ class Node: public ZoneObject {
public: public:
Node(): statement_pos_(RelocInfo::kNoPosition) { } Node(): statement_pos_(RelocInfo::kNoPosition) { }
virtual ~Node() { } virtual ~Node() { }
virtual void Accept(Visitor* v) = 0; virtual void Accept(AstVisitor* v) = 0;
// Type testing & conversion. // Type testing & conversion.
virtual Statement* AsStatement() { return NULL; } virtual Statement* AsStatement() { return NULL; }
...@@ -168,7 +169,7 @@ class Expression: public Node { ...@@ -168,7 +169,7 @@ class Expression: public Node {
class ValidLeftHandSideSentinel: public Expression { class ValidLeftHandSideSentinel: public Expression {
public: public:
virtual bool IsValidLeftHandSide() { return true; } virtual bool IsValidLeftHandSide() { return true; }
virtual void Accept(Visitor* v) { UNREACHABLE(); } virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
static ValidLeftHandSideSentinel* instance() { return &instance_; } static ValidLeftHandSideSentinel* instance() { return &instance_; }
private: private:
static ValidLeftHandSideSentinel instance_; static ValidLeftHandSideSentinel instance_;
...@@ -221,7 +222,7 @@ class Block: public BreakableStatement { ...@@ -221,7 +222,7 @@ class Block: public BreakableStatement {
statements_(capacity), statements_(capacity),
is_initializer_block_(is_initializer_block) { } is_initializer_block_(is_initializer_block) { }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
void AddStatement(Statement* statement) { statements_.Add(statement); } void AddStatement(Statement* statement) { statements_.Add(statement); }
...@@ -245,7 +246,7 @@ class Declaration: public Node { ...@@ -245,7 +246,7 @@ class Declaration: public Node {
ASSERT(fun == NULL || mode == Variable::VAR); ASSERT(fun == NULL || mode == Variable::VAR);
} }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
VariableProxy* proxy() const { return proxy_; } VariableProxy* proxy() const { return proxy_; }
Variable::Mode mode() const { return mode_; } Variable::Mode mode() const { return mode_; }
...@@ -302,7 +303,7 @@ class LoopStatement: public IterationStatement { ...@@ -302,7 +303,7 @@ class LoopStatement: public IterationStatement {
next_ = next; next_ = next;
} }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
Type type() const { return type_; } Type type() const { return type_; }
Statement* init() const { return init_; } Statement* init() const { return init_; }
...@@ -332,7 +333,7 @@ class ForInStatement: public IterationStatement { ...@@ -332,7 +333,7 @@ class ForInStatement: public IterationStatement {
enumerable_ = enumerable; enumerable_ = enumerable;
} }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
Expression* each() const { return each_; } Expression* each() const { return each_; }
Expression* enumerable() const { return enumerable_; } Expression* enumerable() const { return enumerable_; }
...@@ -348,7 +349,7 @@ class ExpressionStatement: public Statement { ...@@ -348,7 +349,7 @@ class ExpressionStatement: public Statement {
explicit ExpressionStatement(Expression* expression) explicit ExpressionStatement(Expression* expression)
: expression_(expression) { } : expression_(expression) { }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
// Type testing & conversion. // Type testing & conversion.
virtual ExpressionStatement* AsExpressionStatement() { return this; } virtual ExpressionStatement* AsExpressionStatement() { return this; }
...@@ -366,7 +367,7 @@ class ContinueStatement: public Statement { ...@@ -366,7 +367,7 @@ class ContinueStatement: public Statement {
explicit ContinueStatement(IterationStatement* target) explicit ContinueStatement(IterationStatement* target)
: target_(target) { } : target_(target) { }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
IterationStatement* target() const { return target_; } IterationStatement* target() const { return target_; }
...@@ -380,7 +381,7 @@ class BreakStatement: public Statement { ...@@ -380,7 +381,7 @@ class BreakStatement: public Statement {
explicit BreakStatement(BreakableStatement* target) explicit BreakStatement(BreakableStatement* target)
: target_(target) { } : target_(target) { }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
BreakableStatement* target() const { return target_; } BreakableStatement* target() const { return target_; }
...@@ -394,7 +395,7 @@ class ReturnStatement: public Statement { ...@@ -394,7 +395,7 @@ class ReturnStatement: public Statement {
explicit ReturnStatement(Expression* expression) explicit ReturnStatement(Expression* expression)
: expression_(expression) { } : expression_(expression) { }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
// Type testing & conversion. // Type testing & conversion.
virtual ReturnStatement* AsReturnStatement() { return this; } virtual ReturnStatement* AsReturnStatement() { return this; }
...@@ -411,7 +412,7 @@ class WithEnterStatement: public Statement { ...@@ -411,7 +412,7 @@ class WithEnterStatement: public Statement {
explicit WithEnterStatement(Expression* expression) explicit WithEnterStatement(Expression* expression)
: expression_(expression) { } : expression_(expression) { }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
Expression* expression() const { return expression_; } Expression* expression() const { return expression_; }
...@@ -424,7 +425,7 @@ class WithExitStatement: public Statement { ...@@ -424,7 +425,7 @@ class WithExitStatement: public Statement {
public: public:
WithExitStatement() { } WithExitStatement() { }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
}; };
...@@ -457,7 +458,7 @@ class SwitchStatement: public BreakableStatement { ...@@ -457,7 +458,7 @@ class SwitchStatement: public BreakableStatement {
cases_ = cases; cases_ = cases;
} }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
Expression* tag() const { return tag_; } Expression* tag() const { return tag_; }
ZoneList<CaseClause*>* cases() const { return cases_; } ZoneList<CaseClause*>* cases() const { return cases_; }
...@@ -482,7 +483,7 @@ class IfStatement: public Statement { ...@@ -482,7 +483,7 @@ class IfStatement: public Statement {
then_statement_(then_statement), then_statement_(then_statement),
else_statement_(else_statement) { } else_statement_(else_statement) { }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
bool HasThenStatement() const { return !then_statement()->IsEmpty(); } bool HasThenStatement() const { return !then_statement()->IsEmpty(); }
bool HasElseStatement() const { return !else_statement()->IsEmpty(); } bool HasElseStatement() const { return !else_statement()->IsEmpty(); }
...@@ -510,7 +511,7 @@ class LabelCollector: public Node { ...@@ -510,7 +511,7 @@ class LabelCollector: public Node {
void AddLabel(Label* label); void AddLabel(Label* label);
// Virtual behaviour. LabelCollectors are never part of the AST. // Virtual behaviour. LabelCollectors are never part of the AST.
virtual void Accept(Visitor* v) { UNREACHABLE(); } virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
virtual LabelCollector* AsLabelCollector() { return this; } virtual LabelCollector* AsLabelCollector() { return this; }
ZoneList<Label*>* labels() { return labels_; } ZoneList<Label*>* labels() { return labels_; }
...@@ -547,7 +548,7 @@ class TryCatch: public TryStatement { ...@@ -547,7 +548,7 @@ class TryCatch: public TryStatement {
ASSERT(catch_var->AsVariableProxy() != NULL); ASSERT(catch_var->AsVariableProxy() != NULL);
} }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
Expression* catch_var() const { return catch_var_; } Expression* catch_var() const { return catch_var_; }
Block* catch_block() const { return catch_block_; } Block* catch_block() const { return catch_block_; }
...@@ -564,7 +565,7 @@ class TryFinally: public TryStatement { ...@@ -564,7 +565,7 @@ class TryFinally: public TryStatement {
: TryStatement(try_block), : TryStatement(try_block),
finally_block_(finally_block) { } finally_block_(finally_block) { }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
Block* finally_block() const { return finally_block_; } Block* finally_block() const { return finally_block_; }
...@@ -575,13 +576,13 @@ class TryFinally: public TryStatement { ...@@ -575,13 +576,13 @@ class TryFinally: public TryStatement {
class DebuggerStatement: public Statement { class DebuggerStatement: public Statement {
public: public:
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
}; };
class EmptyStatement: public Statement { class EmptyStatement: public Statement {
public: public:
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
// Type testing & conversion. // Type testing & conversion.
virtual EmptyStatement* AsEmptyStatement() { return this; } virtual EmptyStatement* AsEmptyStatement() { return this; }
...@@ -592,7 +593,7 @@ class Literal: public Expression { ...@@ -592,7 +593,7 @@ class Literal: public Expression {
public: public:
explicit Literal(Handle<Object> handle) : handle_(handle) { } explicit Literal(Handle<Object> handle) : handle_(handle) { }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
// Type testing & conversion. // Type testing & conversion.
virtual Literal* AsLiteral() { return this; } virtual Literal* AsLiteral() { return this; }
...@@ -665,7 +666,7 @@ class ObjectLiteral: public MaterializedLiteral { ...@@ -665,7 +666,7 @@ class ObjectLiteral: public MaterializedLiteral {
properties_(properties) { properties_(properties) {
} }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
Handle<FixedArray> constant_properties() const { Handle<FixedArray> constant_properties() const {
return constant_properties_; return constant_properties_;
...@@ -688,7 +689,7 @@ class RegExpLiteral: public MaterializedLiteral { ...@@ -688,7 +689,7 @@ class RegExpLiteral: public MaterializedLiteral {
pattern_(pattern), pattern_(pattern),
flags_(flags) {} flags_(flags) {}
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
Handle<String> pattern() const { return pattern_; } Handle<String> pattern() const { return pattern_; }
Handle<String> flags() const { return flags_; } Handle<String> flags() const { return flags_; }
...@@ -707,7 +708,7 @@ class ArrayLiteral: public Expression { ...@@ -707,7 +708,7 @@ class ArrayLiteral: public Expression {
: literals_(literals), values_(values) { : literals_(literals), values_(values) {
} }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
Handle<FixedArray> literals() const { return literals_; } Handle<FixedArray> literals() const { return literals_; }
ZoneList<Expression*>* values() const { return values_; } ZoneList<Expression*>* values() const { return values_; }
...@@ -720,7 +721,7 @@ class ArrayLiteral: public Expression { ...@@ -720,7 +721,7 @@ class ArrayLiteral: public Expression {
class VariableProxy: public Expression { class VariableProxy: public Expression {
public: public:
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
// Type testing & conversion // Type testing & conversion
virtual Property* AsProperty() { virtual Property* AsProperty() {
...@@ -816,7 +817,7 @@ class Slot: public Expression { ...@@ -816,7 +817,7 @@ class Slot: public Expression {
ASSERT(var != NULL); ASSERT(var != NULL);
} }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
// Type testing & conversion // Type testing & conversion
virtual Slot* AsSlot() { return this; } virtual Slot* AsSlot() { return this; }
...@@ -838,7 +839,7 @@ class Property: public Expression { ...@@ -838,7 +839,7 @@ class Property: public Expression {
Property(Expression* obj, Expression* key, int pos) Property(Expression* obj, Expression* key, int pos)
: obj_(obj), key_(key), pos_(pos) { } : obj_(obj), key_(key), pos_(pos) { }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
// Type testing & conversion // Type testing & conversion
virtual Property* AsProperty() { return this; } virtual Property* AsProperty() { return this; }
...@@ -867,21 +868,18 @@ class Call: public Expression { ...@@ -867,21 +868,18 @@ class Call: public Expression {
public: public:
Call(Expression* expression, Call(Expression* expression,
ZoneList<Expression*>* arguments, ZoneList<Expression*>* arguments,
bool is_eval,
int pos) int pos)
: expression_(expression), : expression_(expression),
arguments_(arguments), arguments_(arguments),
is_eval_(is_eval),
pos_(pos) { } pos_(pos) { }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
// Type testing and conversion. // Type testing and conversion.
virtual Call* AsCall() { return this; } virtual Call* AsCall() { return this; }
Expression* expression() const { return expression_; } Expression* expression() const { return expression_; }
ZoneList<Expression*>* arguments() const { return arguments_; } ZoneList<Expression*>* arguments() const { return arguments_; }
bool is_eval() { return is_eval_; }
int position() { return pos_; } int position() { return pos_; }
static Call* sentinel() { return &sentinel_; } static Call* sentinel() { return &sentinel_; }
...@@ -889,7 +887,6 @@ class Call: public Expression { ...@@ -889,7 +887,6 @@ class Call: public Expression {
private: private:
Expression* expression_; Expression* expression_;
ZoneList<Expression*>* arguments_; ZoneList<Expression*>* arguments_;
bool is_eval_;
int pos_; int pos_;
static Call sentinel_; static Call sentinel_;
...@@ -899,9 +896,27 @@ class Call: public Expression { ...@@ -899,9 +896,27 @@ class Call: public Expression {
class CallNew: public Call { class CallNew: public Call {
public: public:
CallNew(Expression* expression, ZoneList<Expression*>* arguments, int pos) CallNew(Expression* expression, ZoneList<Expression*>* arguments, int pos)
: Call(expression, arguments, false, pos) { } : Call(expression, arguments, pos) { }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
};
// The CallEval class represents a call of the form 'eval(...)' where eval
// cannot be seen to be overwritten at compile time. It is potentially a
// direct (i.e. not aliased) eval call. The real nature of the call is
// determined at runtime.
class CallEval: public Call {
public:
CallEval(Expression* expression, ZoneList<Expression*>* arguments, int pos)
: Call(expression, arguments, pos) { }
virtual void Accept(AstVisitor* v);
static CallEval* sentinel() { return &sentinel_; }
private:
static CallEval sentinel_;
}; };
...@@ -916,7 +931,7 @@ class CallRuntime: public Expression { ...@@ -916,7 +931,7 @@ class CallRuntime: public Expression {
ZoneList<Expression*>* arguments) ZoneList<Expression*>* arguments)
: name_(name), function_(function), arguments_(arguments) { } : name_(name), function_(function), arguments_(arguments) { }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
Handle<String> name() const { return name_; } Handle<String> name() const { return name_; }
Runtime::Function* function() const { return function_; } Runtime::Function* function() const { return function_; }
...@@ -936,7 +951,7 @@ class UnaryOperation: public Expression { ...@@ -936,7 +951,7 @@ class UnaryOperation: public Expression {
ASSERT(Token::IsUnaryOp(op)); ASSERT(Token::IsUnaryOp(op));
} }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
// Type testing & conversion // Type testing & conversion
virtual UnaryOperation* AsUnaryOperation() { return this; } virtual UnaryOperation* AsUnaryOperation() { return this; }
...@@ -957,7 +972,7 @@ class BinaryOperation: public Expression { ...@@ -957,7 +972,7 @@ class BinaryOperation: public Expression {
ASSERT(Token::IsBinaryOp(op)); ASSERT(Token::IsBinaryOp(op));
} }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
// Type testing & conversion // Type testing & conversion
virtual BinaryOperation* AsBinaryOperation() { return this; } virtual BinaryOperation* AsBinaryOperation() { return this; }
...@@ -1006,7 +1021,7 @@ class CountOperation: public Expression { ...@@ -1006,7 +1021,7 @@ class CountOperation: public Expression {
ASSERT(Token::IsCountOp(op)); ASSERT(Token::IsCountOp(op));
} }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
bool is_prefix() const { return is_prefix_; } bool is_prefix() const { return is_prefix_; }
bool is_postfix() const { return !is_prefix_; } bool is_postfix() const { return !is_prefix_; }
...@@ -1029,7 +1044,7 @@ class CompareOperation: public Expression { ...@@ -1029,7 +1044,7 @@ class CompareOperation: public Expression {
ASSERT(Token::IsCompareOp(op)); ASSERT(Token::IsCompareOp(op));
} }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
Token::Value op() const { return op_; } Token::Value op() const { return op_; }
Expression* left() const { return left_; } Expression* left() const { return left_; }
...@@ -1051,7 +1066,7 @@ class Conditional: public Expression { ...@@ -1051,7 +1066,7 @@ class Conditional: public Expression {
then_expression_(then_expression), then_expression_(then_expression),
else_expression_(else_expression) { } else_expression_(else_expression) { }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
Expression* condition() const { return condition_; } Expression* condition() const { return condition_; }
Expression* then_expression() const { return then_expression_; } Expression* then_expression() const { return then_expression_; }
...@@ -1071,7 +1086,7 @@ class Assignment: public Expression { ...@@ -1071,7 +1086,7 @@ class Assignment: public Expression {
ASSERT(Token::IsAssignmentOp(op)); ASSERT(Token::IsAssignmentOp(op));
} }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
virtual Assignment* AsAssignment() { return this; } virtual Assignment* AsAssignment() { return this; }
Token::Value binary_op() const; Token::Value binary_op() const;
...@@ -1094,7 +1109,7 @@ class Throw: public Expression { ...@@ -1094,7 +1109,7 @@ class Throw: public Expression {
Throw(Expression* exception, int pos) Throw(Expression* exception, int pos)
: exception_(exception), pos_(pos) {} : exception_(exception), pos_(pos) {}
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
Expression* exception() const { return exception_; } Expression* exception() const { return exception_; }
int position() const { return pos_; } int position() const { return pos_; }
...@@ -1130,7 +1145,7 @@ class FunctionLiteral: public Expression { ...@@ -1130,7 +1145,7 @@ class FunctionLiteral: public Expression {
function_token_position_(RelocInfo::kNoPosition) { function_token_position_(RelocInfo::kNoPosition) {
} }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
// Type testing & conversion // Type testing & conversion
virtual FunctionLiteral* AsFunctionLiteral() { return this; } virtual FunctionLiteral* AsFunctionLiteral() { return this; }
...@@ -1179,7 +1194,7 @@ class FunctionBoilerplateLiteral: public Expression { ...@@ -1179,7 +1194,7 @@ class FunctionBoilerplateLiteral: public Expression {
Handle<JSFunction> boilerplate() const { return boilerplate_; } Handle<JSFunction> boilerplate() const { return boilerplate_; }
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
private: private:
Handle<JSFunction> boilerplate_; Handle<JSFunction> boilerplate_;
...@@ -1188,7 +1203,7 @@ class FunctionBoilerplateLiteral: public Expression { ...@@ -1188,7 +1203,7 @@ class FunctionBoilerplateLiteral: public Expression {
class ThisFunction: public Expression { class ThisFunction: public Expression {
public: public:
virtual void Accept(Visitor* v); virtual void Accept(AstVisitor* v);
}; };
...@@ -1465,10 +1480,10 @@ class RegExpVisitor BASE_EMBEDDED { ...@@ -1465,10 +1480,10 @@ class RegExpVisitor BASE_EMBEDDED {
// Basic visitor // Basic visitor
// - leaf node visitors are abstract. // - leaf node visitors are abstract.
class Visitor BASE_EMBEDDED { class AstVisitor BASE_EMBEDDED {
public: public:
Visitor() : stack_overflow_(false) { } AstVisitor() : stack_overflow_(false) { }
virtual ~Visitor() { } virtual ~AstVisitor() { }
// Dispatch // Dispatch
void Visit(Node* node) { node->Accept(this); } void Visit(Node* node) { node->Accept(this); }
......
...@@ -2303,7 +2303,7 @@ void CodeGenerator::VisitCall(Call* node) { ...@@ -2303,7 +2303,7 @@ void CodeGenerator::VisitCall(Call* node) {
ZoneList<Expression*>* args = node->arguments(); ZoneList<Expression*>* args = node->arguments();
if (FLAG_debug_info) RecordStatementPosition(node); RecordStatementPosition(node);
// Standard function call. // Standard function call.
// Check if the function is a variable or a property. // Check if the function is a variable or a property.
...@@ -2430,6 +2430,58 @@ void CodeGenerator::VisitCall(Call* node) { ...@@ -2430,6 +2430,58 @@ void CodeGenerator::VisitCall(Call* node) {
} }
void CodeGenerator::VisitCallEval(CallEval* node) {
Comment cmnt(masm_, "[ CallEval");
// In a call to eval, we first call %ResolvePossiblyDirectEval to resolve
// the function we need to call and the receiver of the call.
// Then we call the resolved function using the given arguments.
ZoneList<Expression*>* args = node->arguments();
Expression* function = node->expression();
RecordStatementPosition(node);
// Prepare stack for call to resolved function.
Load(function);
__ mov(r2, Operand(Factory::undefined_value()));
__ push(r2); // Slot for receiver
for (int i = 0; i < args->length(); i++) {
Load(args->at(i));
}
// Prepare stack for call to ResolvePossiblyDirectEval.
__ ldr(r1, MemOperand(sp, args->length() * kPointerSize + kPointerSize));
__ push(r1);
if (args->length() > 0) {
__ ldr(r1, MemOperand(sp, args->length() * kPointerSize));
__ push(r1);
} else {
__ push(r2);
}
// Resolve the call.
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 2);
// Touch up stack with the right values for the function and the receiver.
__ ldr(r1, FieldMemOperand(r0, FixedArray::kHeaderSize));
__ str(r1, MemOperand(sp, (args->length() + 1) * kPointerSize));
__ ldr(r1, FieldMemOperand(r0, FixedArray::kHeaderSize + kPointerSize));
__ str(r1, MemOperand(sp, args->length() * kPointerSize));
// Call the function.
__ RecordPosition(node->position());
CallFunctionStub call_function(args->length());
__ CallStub(&call_function);
__ ldr(cp, frame_->Context());
// Remove the function from the stack.
frame_->Pop();
frame_->Push(r0);
}
void CodeGenerator::VisitCallNew(CallNew* node) { void CodeGenerator::VisitCallNew(CallNew* node) {
Comment cmnt(masm_, "[ CallNew"); Comment cmnt(masm_, "[ CallNew");
......
...@@ -187,7 +187,7 @@ class CodeGenState BASE_EMBEDDED { ...@@ -187,7 +187,7 @@ class CodeGenState BASE_EMBEDDED {
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// CodeGenerator // CodeGenerator
class CodeGenerator: public Visitor { class CodeGenerator: public AstVisitor {
public: public:
// Takes a function literal, generates code for it. This function should only // Takes a function literal, generates code for it. This function should only
// be called by compiler.cc. // be called by compiler.cc.
......
...@@ -2836,6 +2836,54 @@ void CodeGenerator::VisitCallNew(CallNew* node) { ...@@ -2836,6 +2836,54 @@ void CodeGenerator::VisitCallNew(CallNew* node) {
} }
void CodeGenerator::VisitCallEval(CallEval* node) {
Comment cmnt(masm_, "[ CallEval");
// In a call to eval, we first call %ResolvePossiblyDirectEval to resolve
// the function we need to call and the receiver of the call.
// Then we call the resolved function using the given arguments.
ZoneList<Expression*>* args = node->arguments();
Expression* function = node->expression();
RecordStatementPosition(node);
// Prepare stack for call to resolved function.
Load(function);
__ push(Immediate(Factory::undefined_value())); // Slot for receiver
for (int i = 0; i < args->length(); i++) {
Load(args->at(i));
}
// Prepare stack for call to ResolvePossiblyDirectEval.
__ push(Operand(esp, args->length() * kPointerSize + kPointerSize));
if (args->length() > 0) {
__ push(Operand(esp, args->length() * kPointerSize));
} else {
__ push(Immediate(Factory::undefined_value()));
}
// Resolve the call.
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 2);
// Touch up stack with the right values for the function and the receiver.
__ mov(edx, FieldOperand(eax, FixedArray::kHeaderSize));
__ mov(Operand(esp, (args->length() + 1) * kPointerSize), edx);
__ mov(edx, FieldOperand(eax, FixedArray::kHeaderSize + kPointerSize));
__ mov(Operand(esp, args->length() * kPointerSize), edx);
// Call the function.
__ RecordPosition(node->position());
CallFunctionStub call_function(args->length());
__ CallStub(&call_function);
// Restore context and pop function from the stack.
__ mov(esi, frame_->Context());
__ mov(frame_->Top(), eax);
}
void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1); ASSERT(args->length() == 1);
Load(args->at(0)); Load(args->at(0));
......
...@@ -193,7 +193,7 @@ class CodeGenState BASE_EMBEDDED { ...@@ -193,7 +193,7 @@ class CodeGenState BASE_EMBEDDED {
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// CodeGenerator // CodeGenerator
class CodeGenerator: public Visitor { class CodeGenerator: public AstVisitor {
public: public:
// Takes a function literal, generates code for it. This function should only // Takes a function literal, generates code for it. This function should only
// be called by compiler.cc. // be called by compiler.cc.
......
...@@ -74,14 +74,6 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags, ...@@ -74,14 +74,6 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
int* index_, PropertyAttributes* attributes) { int* index_, PropertyAttributes* attributes) {
Handle<Context> context(this); Handle<Context> context(this);
// The context must be in frame slot 0 (if not debugging).
if (kDebug && !Debug::InDebugger()) {
StackFrameLocator locator;
ASSERT(context->fcontext() ==
Context::cast(
locator.FindJavaScriptFrame(0)->context())->fcontext());
}
bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0; bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
*index_ = -1; *index_ = -1;
*attributes = ABSENT; *attributes = ABSENT;
......
...@@ -1012,7 +1012,7 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request, ...@@ -1012,7 +1012,7 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request,
try { try {
try { try {
// Convert the JSON string to an object. // Convert the JSON string to an object.
request = %CompileString('(' + json_request + ')', 0, false)(); request = %CompileString('(' + json_request + ')', 0)();
// Create an initial response. // Create an initial response.
response = this.createResponse(request); response = this.createResponse(request);
...@@ -1465,7 +1465,7 @@ DebugCommandProcessor.prototype.scriptsRequest_ = function(request, response) { ...@@ -1465,7 +1465,7 @@ DebugCommandProcessor.prototype.scriptsRequest_ = function(request, response) {
DebugCommandProcessor.prototype.isRunning = function(json_response) { DebugCommandProcessor.prototype.isRunning = function(json_response) {
try { try {
// Convert the JSON string to an object. // Convert the JSON string to an object.
response = %CompileString('(' + json_response + ')', 0, false)(); response = %CompileString('(' + json_response + ')', 0)();
// Return whether VM should be running after this request. // Return whether VM should be running after this request.
return response.running; return response.running;
......
...@@ -197,7 +197,7 @@ class Statement; ...@@ -197,7 +197,7 @@ class Statement;
class String; class String;
class Struct; class Struct;
class SwitchStatement; class SwitchStatement;
class Visitor; class AstVisitor;
class Variable; class Variable;
class VariableProxy; class VariableProxy;
class RelocInfo; class RelocInfo;
......
...@@ -193,7 +193,8 @@ namespace v8 { namespace internal { ...@@ -193,7 +193,8 @@ namespace v8 { namespace internal {
V(failure_symbol, "<failure>") \ V(failure_symbol, "<failure>") \
V(space_symbol, " ") \ V(space_symbol, " ") \
V(exec_symbol, "exec") \ V(exec_symbol, "exec") \
V(zero_symbol, "0") V(zero_symbol, "0") \
V(global_eval_symbol, "GlobalEval")
// Forward declaration of the GCTracer class. // Forward declaration of the GCTracer class.
......
...@@ -667,10 +667,16 @@ class ParserFactory BASE_EMBEDDED { ...@@ -667,10 +667,16 @@ class ParserFactory BASE_EMBEDDED {
virtual Expression* NewCall(Expression* expression, virtual Expression* NewCall(Expression* expression,
ZoneList<Expression*>* arguments, ZoneList<Expression*>* arguments,
bool is_eval, int pos) { int pos) {
return Call::sentinel(); return Call::sentinel();
} }
virtual Expression* NewCallEval(Expression* expression,
ZoneList<Expression*>* arguments,
int pos) {
return CallEval::sentinel();
}
virtual Statement* EmptyStatement() { virtual Statement* EmptyStatement() {
return NULL; return NULL;
} }
...@@ -717,8 +723,14 @@ class AstBuildingParserFactory : public ParserFactory { ...@@ -717,8 +723,14 @@ class AstBuildingParserFactory : public ParserFactory {
virtual Expression* NewCall(Expression* expression, virtual Expression* NewCall(Expression* expression,
ZoneList<Expression*>* arguments, ZoneList<Expression*>* arguments,
bool is_eval, int pos) { int pos) {
return new Call(expression, arguments, is_eval, pos); return new Call(expression, arguments, pos);
}
virtual Expression* NewCallEval(Expression* expression,
ZoneList<Expression*>* arguments,
int pos) {
return new CallEval(expression, arguments, pos);
} }
virtual Statement* EmptyStatement() { virtual Statement* EmptyStatement() {
...@@ -1343,7 +1355,7 @@ VariableProxy* AstBuildingParser::Declare(Handle<String> name, ...@@ -1343,7 +1355,7 @@ VariableProxy* AstBuildingParser::Declare(Handle<String> name,
// to the calling function context. // to the calling function context.
if (top_scope_->is_function_scope()) { if (top_scope_->is_function_scope()) {
// Declare the variable in the function scope. // Declare the variable in the function scope.
var = top_scope_->Lookup(name); var = top_scope_->LookupLocal(name);
if (var == NULL) { if (var == NULL) {
// Declare the name. // Declare the name.
var = top_scope_->Declare(name, mode); var = top_scope_->Declare(name, mode);
...@@ -2624,55 +2636,34 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) { ...@@ -2624,55 +2636,34 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
ZoneList<Expression*>* args = ParseArguments(CHECK_OK); ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
// Keep track of eval() calls since they disable all local variable // Keep track of eval() calls since they disable all local variable
// optimizations. We can ignore locally declared variables with // optimizations.
// name 'eval' since they override the global 'eval' function. We // The calls that need special treatment are the
// only need to look at unresolved variables (VariableProxies). // direct (i.e. not aliased) eval calls. These calls are all of the
// form eval(...) with no explicit receiver object where eval is not
// declared in the current scope chain. These calls are marked as
// potentially direct eval calls. Whether they are actually direct calls
// to eval is determined at run time.
bool is_potentially_direct_eval = false;
if (!is_pre_parsing_) { if (!is_pre_parsing_) {
// We assume that only a function called 'eval' can be used
// to invoke the global eval() implementation. This permits
// for massive optimizations.
VariableProxy* callee = result->AsVariableProxy(); VariableProxy* callee = result->AsVariableProxy();
if (callee != NULL && callee->IsVariable(Factory::eval_symbol())) { if (callee != NULL && callee->IsVariable(Factory::eval_symbol())) {
// We do not allow direct calls to 'eval' in our internal Handle<String> name = callee->name();
// JS files. Use builtin functions instead. Variable* var = top_scope_->Lookup(name);
ASSERT(!Bootstrapper::IsActive()); if (var == NULL) {
top_scope_->RecordEvalCall(); // We do not allow direct calls to 'eval' in our internal
} else { // JS files. Use builtin functions instead.
// This is rather convoluted code to check if we're calling ASSERT(!Bootstrapper::IsActive());
// a function named 'eval' through a property access. If so, top_scope_->RecordEvalCall();
// we mark it as a possible eval call (we don't know if the is_potentially_direct_eval = true;
// receiver will resolve to the global object or not), but
// we do not treat the call as an eval() call - we let the
// call get through to the JavaScript eval code defined in
// v8natives.js.
Property* property = result->AsProperty();
if (property != NULL) {
Literal* key = property->key()->AsLiteral();
if (key != NULL &&
key->handle().is_identical_to(Factory::eval_symbol())) {
// We do not allow direct calls to 'eval' in our
// internal JS files. Use builtin functions instead.
ASSERT(!Bootstrapper::IsActive());
top_scope_->RecordEvalCall();
}
} }
} }
} }
// Optimize the eval() case w/o arguments so we if (is_potentially_direct_eval) {
// don't need to handle it every time at runtime. result = factory()->NewCallEval(result, args, pos);
//
// Note: For now we don't do static eval analysis
// as it appears that we need to be able to call
// eval() via alias names. We leave the code as
// is, in case we want to enable this again in the
// future.
const bool is_eval = false;
if (is_eval && args->length() == 0) {
result = NEW(Literal(Factory::undefined_value()));
} else { } else {
result = factory()->NewCall(result, args, is_eval, pos); result = factory()->NewCall(result, args, pos);
} }
break; break;
} }
......
...@@ -348,6 +348,11 @@ void PrettyPrinter::VisitCall(Call* node) { ...@@ -348,6 +348,11 @@ void PrettyPrinter::VisitCall(Call* node) {
} }
void PrettyPrinter::VisitCallEval(CallEval* node) {
VisitCall(node);
}
void PrettyPrinter::VisitCallNew(CallNew* node) { void PrettyPrinter::VisitCallNew(CallNew* node) {
Print("new ("); Print("new (");
Visit(node->expression()); Visit(node->expression());
...@@ -1016,6 +1021,11 @@ void AstPrinter::VisitCall(Call* node) { ...@@ -1016,6 +1021,11 @@ void AstPrinter::VisitCall(Call* node) {
} }
void AstPrinter::VisitCallEval(CallEval* node) {
VisitCall(node);
}
void AstPrinter::VisitCallNew(CallNew* node) { void AstPrinter::VisitCallNew(CallNew* node) {
IndentedScope indent("CALL NEW"); IndentedScope indent("CALL NEW");
Visit(node->expression()); Visit(node->expression());
......
...@@ -34,7 +34,7 @@ namespace v8 { namespace internal { ...@@ -34,7 +34,7 @@ namespace v8 { namespace internal {
#ifdef DEBUG #ifdef DEBUG
class PrettyPrinter: public Visitor { class PrettyPrinter: public AstVisitor {
public: public:
PrettyPrinter(); PrettyPrinter();
virtual ~PrettyPrinter(); virtual ~PrettyPrinter();
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
namespace v8 { namespace internal { namespace v8 { namespace internal {
class AstOptimizer: public Visitor { class AstOptimizer: public AstVisitor {
public: public:
explicit AstOptimizer() { explicit AstOptimizer() {
} }
...@@ -344,6 +344,12 @@ void AstOptimizer::VisitCall(Call* node) { ...@@ -344,6 +344,12 @@ void AstOptimizer::VisitCall(Call* node) {
} }
void AstOptimizer::VisitCallEval(CallEval* node) {
Visit(node->expression());
OptimizeArguments(node->arguments());
}
void AstOptimizer::VisitCallNew(CallNew* node) { void AstOptimizer::VisitCallNew(CallNew* node) {
Visit(node->expression()); Visit(node->expression());
OptimizeArguments(node->arguments()); OptimizeArguments(node->arguments());
...@@ -469,7 +475,7 @@ void AstOptimizer::VisitThisFunction(ThisFunction* node) { ...@@ -469,7 +475,7 @@ void AstOptimizer::VisitThisFunction(ThisFunction* node) {
} }
class Processor: public Visitor { class Processor: public AstVisitor {
public: public:
explicit Processor(VariableProxy* result) explicit Processor(VariableProxy* result)
: result_(result), : result_(result),
...@@ -702,6 +708,12 @@ void Processor::VisitCall(Call* node) { ...@@ -702,6 +708,12 @@ void Processor::VisitCall(Call* node) {
} }
void Processor::VisitCallEval(CallEval* node) {
USE(node);
UNREACHABLE();
}
void Processor::VisitCallNew(CallNew* node) { void Processor::VisitCallNew(CallNew* node) {
USE(node); USE(node);
UNREACHABLE(); UNREACHABLE();
......
...@@ -3934,57 +3934,6 @@ static Object* Runtime_NumberIsFinite(Arguments args) { ...@@ -3934,57 +3934,6 @@ static Object* Runtime_NumberIsFinite(Arguments args) {
} }
static Object* EvalContext() {
// The topmost JS frame belongs to the eval function which called
// the CompileString runtime function. We need to unwind one level
// to get to the caller of eval.
StackFrameLocator locator;
JavaScriptFrame* frame = locator.FindJavaScriptFrame(1);
// TODO(900055): Right now we check if the caller of eval() supports
// eval to determine if it's an aliased eval or not. This may not be
// entirely correct in the unlikely case where a function uses both
// aliased and direct eval calls.
HandleScope scope;
if (!ScopeInfo<>::SupportsEval(frame->FindCode())) {
// Aliased eval: Evaluate in the global context of the eval
// function to support aliased, cross environment evals.
return *Top::global_context();
}
// Fetch the caller context from the frame.
Handle<Context> caller(Context::cast(frame->context()));
// Check for eval() invocations that cross environments. Use the
// context from the stack if evaluating in current environment.
Handle<Context> target = Top::global_context();
if (caller->global_context() == *target) return *caller;
// Otherwise, use the global context from the other environment.
return *target;
}
static Object* Runtime_EvalReceiver(Arguments args) {
ASSERT(args.length() == 1);
StackFrameLocator locator;
JavaScriptFrame* frame = locator.FindJavaScriptFrame(1);
// Fetch the caller context from the frame.
Context* caller = Context::cast(frame->context());
// Check for eval() invocations that cross environments. Use the
// top frames receiver if evaluating in current environment.
Context* global_context = Top::context()->global()->global_context();
if (caller->global_context() == global_context) {
return frame->receiver();
}
// Otherwise use the given argument (the global object of the
// receiving context).
return args[0];
}
static Object* Runtime_GlobalReceiver(Arguments args) { static Object* Runtime_GlobalReceiver(Arguments args) {
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
Object* global = args[0]; Object* global = args[0];
...@@ -3995,37 +3944,112 @@ static Object* Runtime_GlobalReceiver(Arguments args) { ...@@ -3995,37 +3944,112 @@ static Object* Runtime_GlobalReceiver(Arguments args) {
static Object* Runtime_CompileString(Arguments args) { static Object* Runtime_CompileString(Arguments args) {
HandleScope scope; HandleScope scope;
ASSERT(args.length() == 3); ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(String, source, 0); CONVERT_ARG_CHECKED(String, source, 0);
CONVERT_ARG_CHECKED(Smi, line_offset, 1); CONVERT_ARG_CHECKED(Smi, line_offset, 1);
bool contextual = args[2]->IsTrue();
RUNTIME_ASSERT(contextual || args[2]->IsFalse());
// Compute the eval context.
Handle<Context> context;
if (contextual) {
// Get eval context. May not be available if we are calling eval
// through an alias, and the corresponding frame doesn't have a
// proper eval context set up.
Object* eval_context = EvalContext();
if (eval_context->IsFailure()) return eval_context;
context = Handle<Context>(Context::cast(eval_context));
} else {
context = Handle<Context>(Top::context()->global_context());
}
// Compile source string. // Compile source string.
bool is_global = context->IsGlobalContext();
Handle<JSFunction> boilerplate = Handle<JSFunction> boilerplate =
Compiler::CompileEval(source, line_offset->value(), is_global); Compiler::CompileEval(source, line_offset->value(), true);
if (boilerplate.is_null()) return Failure::Exception(); if (boilerplate.is_null()) return Failure::Exception();
Handle<Context> context(Top::context()->global_context());
Handle<JSFunction> fun = Handle<JSFunction> fun =
Factory::NewFunctionFromBoilerplate(boilerplate, context); Factory::NewFunctionFromBoilerplate(boilerplate, context);
return *fun; return *fun;
} }
static Handle<JSFunction> GetBuiltinFunction(String* name) {
LookupResult result;
Top::global_context()->builtins()->LocalLookup(name, &result);
return Handle<JSFunction>(JSFunction::cast(result.GetValue()));
}
static Object* CompileDirectEval(Handle<String> source) {
// Compute the eval context.
HandleScope scope;
StackFrameLocator locator;
JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
Handle<Context> context(Context::cast(frame->context()));
bool is_global = context->IsGlobalContext();
// Compile source string.
Handle<JSFunction> boilerplate = Compiler::CompileEval(source, 0, is_global);
if (boilerplate.is_null()) return Failure::Exception();
Handle<JSFunction> fun =
Factory::NewFunctionFromBoilerplate(boilerplate, context);
return *fun;
}
static Object* Runtime_ResolvePossiblyDirectEval(Arguments args) {
ASSERT(args.length() == 2);
HandleScope scope;
CONVERT_ARG_CHECKED(JSFunction, callee, 0);
Handle<Object> receiver;
// Find where the 'eval' symbol is bound. It is unaliased only if
// it is bound in the global context.
StackFrameLocator locator;
JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
Handle<Context> context(Context::cast(frame->context()));
int index;
PropertyAttributes attributes;
while (!context.is_null()) {
receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
&index, &attributes);
if (attributes != ABSENT) break;
if (context->is_function_context()) {
context = Handle<Context>(Context::cast(context->closure()->context()));
} else {
context = Handle<Context>(context->previous());
}
}
if (context->IsGlobalContext()) {
// 'eval' is bound in the global context, but it may have been overwritten.
// Compare it to the builtin 'GlobalEval' function to make sure.
Handle<JSFunction> global_eval =
GetBuiltinFunction(Heap::global_eval_symbol());
if (global_eval.is_identical_to(callee)) {
// A direct eval call.
if (args[1]->IsString()) {
CONVERT_ARG_CHECKED(String, source, 1);
// A normal eval call on a string. Compile it and return the
// compiled function bound in the local context.
Object* compiled_source = CompileDirectEval(source);
if (compiled_source->IsFailure()) return compiled_source;
receiver = Handle<Object>(frame->receiver());
callee = Handle<JSFunction>(JSFunction::cast(compiled_source));
} else {
// An eval call that is not called on a string. Global eval
// deals better with this.
receiver = Handle<Object>(Top::global_context()->global());
}
} else {
// 'eval' is overwritten. Just call the function with the given arguments.
receiver = Handle<Object>(Top::global_context()->global());
}
} else {
// 'eval' is not bound in the global context. Just call the function
// with the given arguments. This is not necessarily the global eval.
if (receiver->IsContext()) {
context = Handle<Context>::cast(receiver);
receiver = Handle<Object>(context->get(index));
}
}
Handle<FixedArray> call = Factory::NewFixedArray(2);
call->set(0, *callee);
call->set(1, *receiver);
return *call;
}
static Object* Runtime_CompileScript(Arguments args) { static Object* Runtime_CompileScript(Arguments args) {
HandleScope scope; HandleScope scope;
ASSERT(args.length() == 4); ASSERT(args.length() == 4);
......
...@@ -190,13 +190,13 @@ namespace v8 { namespace internal { ...@@ -190,13 +190,13 @@ namespace v8 { namespace internal {
F(NumberIsFinite, 1) \ F(NumberIsFinite, 1) \
\ \
/* Globals */ \ /* Globals */ \
F(CompileString, 3) \ F(CompileString, 2) \
F(CompileScript, 4) \ F(CompileScript, 4) \
F(GlobalPrint, 1) \ F(GlobalPrint, 1) \
\ \
/* Eval */ \ /* Eval */ \
F(EvalReceiver, 1) \
F(GlobalReceiver, 1) \ F(GlobalReceiver, 1) \
F(ResolvePossiblyDirectEval, 2) \
\ \
F(SetProperty, -1 /* 3 or 4 */) \ F(SetProperty, -1 /* 3 or 4 */) \
F(IgnoreAttributesAndSetProperty, -1 /* 3 or 4 */) \ F(IgnoreAttributesAndSetProperty, -1 /* 3 or 4 */) \
......
...@@ -184,11 +184,22 @@ void Scope::Initialize(bool inside_with) { ...@@ -184,11 +184,22 @@ void Scope::Initialize(bool inside_with) {
Variable* Scope::Lookup(Handle<String> name) { Variable* Scope::LookupLocal(Handle<String> name) {
return locals_.Lookup(name); return locals_.Lookup(name);
} }
Variable* Scope::Lookup(Handle<String> name) {
for (Scope* scope = this;
scope != NULL;
scope = scope->outer_scope()) {
Variable* var = scope->LookupLocal(name);
if (var != NULL) return var;
}
return NULL;
}
Variable* Scope::DeclareFunctionVar(Handle<String> name) { Variable* Scope::DeclareFunctionVar(Handle<String> name) {
ASSERT(is_function_scope() && function_ == NULL); ASSERT(is_function_scope() && function_ == NULL);
function_ = new Variable(this, name, Variable::CONST, true, false); function_ = new Variable(this, name, Variable::CONST, true, false);
...@@ -207,7 +218,7 @@ Variable* Scope::Declare(Handle<String> name, Variable::Mode mode) { ...@@ -207,7 +218,7 @@ Variable* Scope::Declare(Handle<String> name, Variable::Mode mode) {
void Scope::AddParameter(Variable* var) { void Scope::AddParameter(Variable* var) {
ASSERT(is_function_scope()); ASSERT(is_function_scope());
ASSERT(Lookup(var->name()) == var); ASSERT(LookupLocal(var->name()) == var);
params_.Add(var); params_.Add(var);
} }
...@@ -258,7 +269,7 @@ void Scope::SetIllegalRedeclaration(Expression* expression) { ...@@ -258,7 +269,7 @@ void Scope::SetIllegalRedeclaration(Expression* expression) {
} }
void Scope::VisitIllegalRedeclaration(Visitor* visitor) { void Scope::VisitIllegalRedeclaration(AstVisitor* visitor) {
ASSERT(HasIllegalRedeclaration()); ASSERT(HasIllegalRedeclaration());
illegal_redecl_->Accept(visitor); illegal_redecl_->Accept(visitor);
} }
...@@ -513,7 +524,7 @@ Variable* Scope::LookupRecursive(Handle<String> name, bool inner_lookup) { ...@@ -513,7 +524,7 @@ Variable* Scope::LookupRecursive(Handle<String> name, bool inner_lookup) {
bool guess = scope_calls_eval_; bool guess = scope_calls_eval_;
// Try to find the variable in this scope. // Try to find the variable in this scope.
Variable* var = Lookup(name); Variable* var = LookupLocal(name);
if (var != NULL) { if (var != NULL) {
// We found a variable. If this is not an inner lookup, we are done. // We found a variable. If this is not an inner lookup, we are done.
...@@ -707,7 +718,7 @@ void Scope::AllocateHeapSlot(Variable* var) { ...@@ -707,7 +718,7 @@ void Scope::AllocateHeapSlot(Variable* var) {
void Scope::AllocateParameterLocals() { void Scope::AllocateParameterLocals() {
ASSERT(is_function_scope()); ASSERT(is_function_scope());
Variable* arguments = Lookup(Factory::arguments_symbol()); Variable* arguments = LookupLocal(Factory::arguments_symbol());
ASSERT(arguments != NULL); // functions have 'arguments' declared implicitly ASSERT(arguments != NULL); // functions have 'arguments' declared implicitly
if (MustAllocate(arguments) && !HasArgumentsParameter()) { if (MustAllocate(arguments) && !HasArgumentsParameter()) {
// 'arguments' is used. Unless there is also a parameter called // 'arguments' is used. Unless there is also a parameter called
......
...@@ -88,6 +88,10 @@ class Scope: public ZoneObject { ...@@ -88,6 +88,10 @@ class Scope: public ZoneObject {
// Declarations // Declarations
// Lookup a variable in this scope. Returns the variable or NULL if not found. // Lookup a variable in this scope. Returns the variable or NULL if not found.
virtual Variable* LookupLocal(Handle<String> name);
// Lookup a variable in this scope or outer scopes.
// Returns the variable or NULL if not found.
virtual Variable* Lookup(Handle<String> name); virtual Variable* Lookup(Handle<String> name);
// Declare the function variable for a function literal. This variable // Declare the function variable for a function literal. This variable
...@@ -138,7 +142,7 @@ class Scope: public ZoneObject { ...@@ -138,7 +142,7 @@ class Scope: public ZoneObject {
// Visit the illegal redeclaration expression. Do not call if the // Visit the illegal redeclaration expression. Do not call if the
// scope doesn't have an illegal redeclaration node. // scope doesn't have an illegal redeclaration node.
void VisitIllegalRedeclaration(Visitor* visitor); void VisitIllegalRedeclaration(AstVisitor* visitor);
// Check if the scope has (at least) one illegal redeclaration. // Check if the scope has (at least) one illegal redeclaration.
bool HasIllegalRedeclaration() const { return illegal_redecl_ != NULL; } bool HasIllegalRedeclaration() const { return illegal_redecl_ != NULL; }
......
...@@ -39,7 +39,7 @@ static const int MaxWeight = 1000000; ...@@ -39,7 +39,7 @@ static const int MaxWeight = 1000000;
static const int InitialWeight = 100; static const int InitialWeight = 100;
class UsageComputer: public Visitor { class UsageComputer: public AstVisitor {
public: public:
static bool Traverse(Node* node); static bool Traverse(Node* node);
...@@ -73,6 +73,7 @@ class UsageComputer: public Visitor { ...@@ -73,6 +73,7 @@ class UsageComputer: public Visitor {
void VisitThrow(Throw* node); void VisitThrow(Throw* node);
void VisitProperty(Property* node); void VisitProperty(Property* node);
void VisitCall(Call* node); void VisitCall(Call* node);
void VisitCallEval(CallEval* node);
void VisitCallNew(CallNew* node); void VisitCallNew(CallNew* node);
void VisitCallRuntime(CallRuntime* node); void VisitCallRuntime(CallRuntime* node);
void VisitUnaryOperation(UnaryOperation* node); void VisitUnaryOperation(UnaryOperation* node);
...@@ -321,6 +322,11 @@ void UsageComputer::VisitCall(Call* node) { ...@@ -321,6 +322,11 @@ void UsageComputer::VisitCall(Call* node) {
} }
void UsageComputer::VisitCallEval(CallEval* node) {
VisitCall(node);
}
void UsageComputer::VisitCallNew(CallNew* node) { void UsageComputer::VisitCallNew(CallNew* node) {
VisitCall(node); VisitCall(node);
} }
......
...@@ -105,15 +105,15 @@ function GlobalParseFloat(string) { ...@@ -105,15 +105,15 @@ function GlobalParseFloat(string) {
function GlobalEval(x) { function GlobalEval(x) {
if (!IS_STRING(x)) return x; if (!IS_STRING(x)) return x;
if (this !== %GlobalReceiver(global)) { if (this !== global && this !== %GlobalReceiver(global)) {
throw new $EvalError('The "this" object passed to eval must ' + throw new $EvalError('The "this" object passed to eval must ' +
'be the global object from which eval originated'); 'be the global object from which eval originated');
} }
var f = %CompileString(x, 0, true); var f = %CompileString(x, 0);
if (!IS_FUNCTION(f)) return f; if (!IS_FUNCTION(f)) return f;
return f.call(%EvalReceiver(this)); return f.call(this);
} }
...@@ -121,7 +121,7 @@ function GlobalEval(x) { ...@@ -121,7 +121,7 @@ function GlobalEval(x) {
function GlobalExecScript(expr, lang) { function GlobalExecScript(expr, lang) {
// NOTE: We don't care about the character casing. // NOTE: We don't care about the character casing.
if (!lang || /javascript/i.test(lang)) { if (!lang || /javascript/i.test(lang)) {
var f = %CompileString(ToString(expr), 0, false); var f = %CompileString(ToString(expr), 0);
f.call(%GlobalReceiver(global)); f.call(%GlobalReceiver(global));
} }
return null; return null;
...@@ -140,7 +140,7 @@ function SetupGlobal() { ...@@ -140,7 +140,7 @@ function SetupGlobal() {
// ECMA-262 - 15.1.1.3. // ECMA-262 - 15.1.1.3.
%SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE); %SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
// Setup non-enumerable function on the global object. // Setup non-enumerable function on the global object.
InstallFunctions(global, DONT_ENUM, $Array( InstallFunctions(global, DONT_ENUM, $Array(
"isNaN", GlobalIsNaN, "isNaN", GlobalIsNaN,
...@@ -521,7 +521,7 @@ function NewFunction(arg1) { // length == 1 ...@@ -521,7 +521,7 @@ function NewFunction(arg1) { // length == 1
// The call to SetNewFunctionAttributes will ensure the prototype // The call to SetNewFunctionAttributes will ensure the prototype
// property of the resulting function is enumerable (ECMA262, 15.3.5.2). // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
var f = %CompileString(source, -1, false)(); var f = %CompileString(source, -1)();
%FunctionSetName(f, "anonymous"); %FunctionSetName(f, "anonymous");
return %SetNewFunctionAttributes(f); return %SetNewFunctionAttributes(f);
} }
......
...@@ -4018,27 +4018,41 @@ THREADED_TEST(FunctionDescriptorException) { ...@@ -4018,27 +4018,41 @@ THREADED_TEST(FunctionDescriptorException) {
} }
THREADED_TEST(Eval) { THREADED_TEST(EvalAliasedDynamic) {
v8::HandleScope scope; v8::HandleScope scope;
LocalContext current; LocalContext current;
// Test that un-aliased eval uses local context. // This sets 'global' to the real global object (as opposed to the
// proxy). It is highly implementation dependent, so take care.
current->Global()->Set(v8_str("global"), current->Global()->GetPrototype());
// Tests where aliased eval can only be resolved dynamically.
Local<Script> script = Local<Script> script =
Script::Compile(v8_str("foo = 0;" Script::Compile(v8_str("function f(x) { "
"(function() {"
" var foo = 2;" " var foo = 2;"
" return eval('foo');" " with (x) { return eval('foo'); }"
"})();")); "}"
Local<Value> result = script->Run(); "foo = 0;"
CHECK_EQ(2, result->Int32Value()); "result1 = f(new Object());"
"result2 = f(global);"
"var x = new Object();"
"x.eval = function(x) { return 1; };"
"result3 = f(x);"));
script->Run();
CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
// Test that un-aliased eval has right this. v8::TryCatch try_catch;
script = script =
Script::Compile(v8_str("function MyObject() { this.self = eval('this'); }" Script::Compile(v8_str("function f(x) { "
"var o = new MyObject();" " var bar = 2;"
"o === o.self")); " with (x) { return eval('bar'); }"
result = script->Run(); "}"
CHECK(result->IsTrue()); "f(global)"));
script->Run();
CHECK(try_catch.HasCaught());
try_catch.Reset();
} }
......
// Copyright 2008 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.
assertEquals(void 0, eval());
assertEquals(4, eval(4));
function f() { return 'The f function'; };
assertTrue(f === eval(f));
function g(x, y) { return 4; };
count = 0;
assertEquals(4, eval('2 + 2', count++));
assertEquals(1, count);
try {
eval('hest 7 &*^*&^');
assertTrue(false, 'Did not throw on syntax error.');
} catch (e) {
assertEquals('SyntaxError', e.name);
}
// eval has special evaluation order for consistency with other browsers.
global_eval = eval;
assertEquals(void 0, eval(eval("var eval = function f(x) { return 'hest';}")))
eval = global_eval;
//Test eval with different number of parameters.
global_eval = eval;
eval = function(x, y) { return x + y; };
assertEquals(4, eval(2, 2));
eval = global_eval;
// Test that un-aliased eval reads from local context.
foo = 0;
result =
(function() {
var foo = 2;
return eval('foo');
})();
assertEquals(2, result);
//Test that un-aliased eval writes to local context.
foo = 0;
result =
(function() {
var foo = 1;
eval('foo = 2');
return foo;
})();
assertEquals(2, result);
assertEquals(0, foo);
// Test that un-aliased eval has right receiver.
function MyObject() { this.self = eval('this'); }
var o = new MyObject();
assertTrue(o === o.self);
// Test that aliased eval reads from global context.
var e = eval;
foo = 0;
result =
(function() {
var foo = 2;
return e('foo');
})();
assertEquals(0, result);
// Test that aliased eval writes to global context.
var e = eval;
foo = 0;
(function() { e('var foo = 2;'); })();
assertEquals(2, foo);
// Test that aliased eval has right receiver.
function MyOtherObject() { this.self = e('this'); }
var o = new MyOtherObject();
assertTrue(this === o.self);
// Try to cheat the 'aliased eval' detection.
var x = this;
foo = 0;
result =
(function() {
var foo = 2;
return x.eval('foo');
})();
assertEquals(0, result);
foo = 0;
result =
(function() {
var eval = function(x) { return x; };
var foo = eval(2);
return e('foo');
})();
assertEquals(0, result);
result =
(function() {
var eval = function(x) { return 2 * x; };
return (function() { return eval(2); })();
})();
assertEquals(4, result);
eval = function(x) { return 2 * x; };
result =
(function() {
return (function() { return eval(2); })();
})();
assertEquals(4, result);
...@@ -44,5 +44,5 @@ h(); ...@@ -44,5 +44,5 @@ h();
f(null); f(null);
// Check called from eval. // Check called from eval.
eval('f(eval)'); eval('f(null)');
...@@ -122,7 +122,8 @@ var knownProblems = { ...@@ -122,7 +122,8 @@ var knownProblems = {
"LazyCompile": true, "LazyCompile": true,
"CreateObjectLiteralBoilerplate": true, "CreateObjectLiteralBoilerplate": true,
"CloneObjectLiteralBoilerplate": true, "CloneObjectLiteralBoilerplate": true,
"IS_VAR": true "IS_VAR": true,
"ResolvePossiblyDirectEval": true
}; };
var currentlyUncallable = { var currentlyUncallable = {
......
...@@ -293,10 +293,6 @@ js1_5/Regress/regress-234389: FAIL_OK ...@@ -293,10 +293,6 @@ js1_5/Regress/regress-234389: FAIL_OK
js1_5/Regress/regress-320119: FAIL_OK js1_5/Regress/regress-320119: FAIL_OK
# We do not support explicit global evals through <global>.eval(...).
js1_5/Regress/regress-68498-003: FAIL_OK
# No support for toSource(). # No support for toSource().
js1_5/Regress/regress-248444: FAIL_OK js1_5/Regress/regress-248444: FAIL_OK
js1_5/Regress/regress-313967-01: FAIL_OK js1_5/Regress/regress-313967-01: FAIL_OK
...@@ -584,10 +580,6 @@ ecma_3/String/15.5.4.11: FAIL ...@@ -584,10 +580,6 @@ ecma_3/String/15.5.4.11: FAIL
# Marked as: Will not fix. V8 throws an acceptable RangeError. # Marked as: Will not fix. V8 throws an acceptable RangeError.
js1_5/Expressions/regress-394673: FAIL js1_5/Expressions/regress-394673: FAIL
# Bug 1202598: New mozilla test js1_5/Regress/regress-383682 fails.
js1_5/Regress/regress-383682: FAIL
##################### MOZILLA EXTENSION TESTS ##################### ##################### MOZILLA EXTENSION TESTS #####################
ecma/extensions/15.1.2.1-1: FAIL_OK ecma/extensions/15.1.2.1-1: FAIL_OK
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment