Author: olehougaard
Date: Thu Nov 27 05:55:06 2008
New Revision: 860

Added:
    branches/bleeding_edge/test/mjsunit/eval.js
Modified:
    branches/bleeding_edge/src/ast.cc
    branches/bleeding_edge/src/ast.h
    branches/bleeding_edge/src/codegen-arm.cc
    branches/bleeding_edge/src/codegen-arm.h
    branches/bleeding_edge/src/codegen-ia32.cc
    branches/bleeding_edge/src/codegen-ia32.h
    branches/bleeding_edge/src/contexts.cc
    branches/bleeding_edge/src/debug-delay.js
    branches/bleeding_edge/src/globals.h
    branches/bleeding_edge/src/heap.h
    branches/bleeding_edge/src/parser.cc
    branches/bleeding_edge/src/prettyprinter.cc
    branches/bleeding_edge/src/prettyprinter.h
    branches/bleeding_edge/src/rewriter.cc
    branches/bleeding_edge/src/runtime.cc
    branches/bleeding_edge/src/runtime.h
    branches/bleeding_edge/src/scopes.cc
    branches/bleeding_edge/src/scopes.h
    branches/bleeding_edge/src/usage-analyzer.cc
    branches/bleeding_edge/src/v8natives.js
    branches/bleeding_edge/test/cctest/test-api.cc
    branches/bleeding_edge/test/mjsunit/function-caller.js
    branches/bleeding_edge/test/mjsunit/fuzz-natives.js
    branches/bleeding_edge/test/mozilla/mozilla.status

Log:
Change implementation of eval to make an exact distinction between direct  
eval and aliased eval.
Review URL: http://codereview.chromium.org/12673

Modified: branches/bleeding_edge/src/ast.cc
==============================================================================
--- branches/bleeding_edge/src/ast.cc   (original)
+++ branches/bleeding_edge/src/ast.cc   Thu Nov 27 05:55:06 2008
@@ -38,14 +38,15 @@
  VariableProxySentinel VariableProxySentinel::identifier_proxy_(false);
  ValidLeftHandSideSentinel ValidLeftHandSideSentinel::instance_;
  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.

  #define DECL_ACCEPT(type)                \
-  void type::Accept(Visitor* v) {        \
+  void type::Accept(AstVisitor* v) {        \
      if (v->CheckStackOverflow()) return; \
      v->Visit##type(this);                \
    }
@@ -158,17 +159,17 @@


  //  
----------------------------------------------------------------------------
-// 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++) {
      Visit(statements->at(i));
    }
  }


-void Visitor::VisitExpressions(ZoneList<Expression*>* expressions) {
+void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) {
    for (int i = 0; i < expressions->length(); i++) {
      // The variable statement visiting code may pass NULL expressions
      // to this code. Maybe this should be handled by introducing an

Modified: branches/bleeding_edge/src/ast.h
==============================================================================
--- branches/bleeding_edge/src/ast.h    (original)
+++ branches/bleeding_edge/src/ast.h    Thu Nov 27 05:55:06 2008
@@ -81,6 +81,7 @@
    V(Throw)                                      \
    V(Property)                                   \
    V(Call)                                       \
+  V(CallEval)                                    \
    V(CallNew)                                    \
    V(CallRuntime)                                \
    V(UnaryOperation)                             \
@@ -104,7 +105,7 @@
   public:
    Node(): statement_pos_(RelocInfo::kNoPosition) { }
    virtual ~Node() { }
-  virtual void Accept(Visitor* v) = 0;
+  virtual void Accept(AstVisitor* v) = 0;

    // Type testing & conversion.
    virtual Statement* AsStatement() { return NULL; }
@@ -168,7 +169,7 @@
  class ValidLeftHandSideSentinel: public Expression {
   public:
    virtual bool IsValidLeftHandSide() { return true; }
-  virtual void Accept(Visitor* v) { UNREACHABLE(); }
+  virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
    static ValidLeftHandSideSentinel* instance() { return &instance_; }
   private:
    static ValidLeftHandSideSentinel instance_;
@@ -221,7 +222,7 @@
          statements_(capacity),
          is_initializer_block_(is_initializer_block) { }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    void AddStatement(Statement* statement) { statements_.Add(statement); }

@@ -245,7 +246,7 @@
      ASSERT(fun == NULL || mode == Variable::VAR);
    }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    VariableProxy* proxy() const  { return proxy_; }
    Variable::Mode mode() const  { return mode_; }
@@ -302,7 +303,7 @@
      next_ = next;
    }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    Type type() const  { return type_; }
    Statement* init() const  { return init_; }
@@ -332,7 +333,7 @@
      enumerable_ = enumerable;
    }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    Expression* each() const { return each_; }
    Expression* enumerable() const { return enumerable_; }
@@ -348,7 +349,7 @@
    explicit ExpressionStatement(Expression* expression)
        : expression_(expression) { }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    // Type testing & conversion.
    virtual ExpressionStatement* AsExpressionStatement() { return this; }
@@ -366,7 +367,7 @@
    explicit ContinueStatement(IterationStatement* target)
        : target_(target) { }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    IterationStatement* target() const  { return target_; }

@@ -380,7 +381,7 @@
    explicit BreakStatement(BreakableStatement* target)
        : target_(target) { }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    BreakableStatement* target() const  { return target_; }

@@ -394,7 +395,7 @@
    explicit ReturnStatement(Expression* expression)
        : expression_(expression) { }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    // Type testing & conversion.
    virtual ReturnStatement* AsReturnStatement() { return this; }
@@ -411,7 +412,7 @@
    explicit WithEnterStatement(Expression* expression)
        : expression_(expression) { }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    Expression* expression() const  { return expression_; }

@@ -424,7 +425,7 @@
   public:
    WithExitStatement() { }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);
  };


@@ -457,7 +458,7 @@
      cases_ = cases;
    }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    Expression* tag() const  { return tag_; }
    ZoneList<CaseClause*>* cases() const  { return cases_; }
@@ -482,7 +483,7 @@
          then_statement_(then_statement),
          else_statement_(else_statement) { }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    bool HasThenStatement() const { return !then_statement()->IsEmpty(); }
    bool HasElseStatement() const { return !else_statement()->IsEmpty(); }
@@ -510,7 +511,7 @@
    void AddLabel(Label* label);

    // 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; }

    ZoneList<Label*>* labels() { return labels_; }
@@ -547,7 +548,7 @@
      ASSERT(catch_var->AsVariableProxy() != NULL);
    }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    Expression* catch_var() const  { return catch_var_; }
    Block* catch_block() const  { return catch_block_; }
@@ -564,7 +565,7 @@
        : TryStatement(try_block),
          finally_block_(finally_block) { }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    Block* finally_block() const { return finally_block_; }

@@ -575,13 +576,13 @@

  class DebuggerStatement: public Statement {
   public:
-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);
  };


  class EmptyStatement: public Statement {
   public:
-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    // Type testing & conversion.
    virtual EmptyStatement* AsEmptyStatement() { return this; }
@@ -592,7 +593,7 @@
   public:
    explicit Literal(Handle<Object> handle) : handle_(handle) { }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    // Type testing & conversion.
    virtual Literal* AsLiteral() { return this; }
@@ -665,7 +666,7 @@
          properties_(properties) {
    }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    Handle<FixedArray> constant_properties() const {
      return constant_properties_;
@@ -688,7 +689,7 @@
          pattern_(pattern),
          flags_(flags) {}

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    Handle<String> pattern() const { return pattern_; }
    Handle<String> flags() const { return flags_; }
@@ -707,7 +708,7 @@
        : literals_(literals), values_(values) {
    }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    Handle<FixedArray> literals() const { return literals_; }
    ZoneList<Expression*>* values() const { return values_; }
@@ -720,7 +721,7 @@

  class VariableProxy: public Expression {
   public:
-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    // Type testing & conversion
    virtual Property* AsProperty() {
@@ -816,7 +817,7 @@
      ASSERT(var != NULL);
    }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    // Type testing & conversion
    virtual Slot* AsSlot()  { return this; }
@@ -838,7 +839,7 @@
    Property(Expression* obj, Expression* key, int pos)
        : obj_(obj), key_(key), pos_(pos) { }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    // Type testing & conversion
    virtual Property* AsProperty() { return this; }
@@ -867,21 +868,18 @@
   public:
    Call(Expression* expression,
         ZoneList<Expression*>* arguments,
-       bool is_eval,
         int pos)
        : expression_(expression),
          arguments_(arguments),
-        is_eval_(is_eval),
          pos_(pos) { }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    // Type testing and conversion.
    virtual Call* AsCall() { return this; }

    Expression* expression() const { return expression_; }
    ZoneList<Expression*>* arguments() const { return arguments_; }
-  bool is_eval()  { return is_eval_; }
    int position() { return pos_; }

    static Call* sentinel() { return &sentinel_; }
@@ -889,7 +887,6 @@
   private:
    Expression* expression_;
    ZoneList<Expression*>* arguments_;
-  bool is_eval_;
    int pos_;

    static Call sentinel_;
@@ -899,9 +896,27 @@
  class CallNew: public Call {
   public:
    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 @@
                ZoneList<Expression*>* arguments)
        : name_(name), function_(function), arguments_(arguments) { }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    Handle<String> name() const { return name_; }
    Runtime::Function* function() const { return function_; }
@@ -936,7 +951,7 @@
      ASSERT(Token::IsUnaryOp(op));
    }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    // Type testing & conversion
    virtual UnaryOperation* AsUnaryOperation() { return this; }
@@ -957,7 +972,7 @@
      ASSERT(Token::IsBinaryOp(op));
    }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    // Type testing & conversion
    virtual BinaryOperation* AsBinaryOperation() { return this; }
@@ -1006,7 +1021,7 @@
      ASSERT(Token::IsCountOp(op));
    }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    bool is_prefix() const { return is_prefix_; }
    bool is_postfix() const { return !is_prefix_; }
@@ -1029,7 +1044,7 @@
      ASSERT(Token::IsCompareOp(op));
    }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    Token::Value op() const { return op_; }
    Expression* left() const { return left_; }
@@ -1051,7 +1066,7 @@
          then_expression_(then_expression),
          else_expression_(else_expression) { }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    Expression* condition() const { return condition_; }
    Expression* then_expression() const { return then_expression_; }
@@ -1071,7 +1086,7 @@
      ASSERT(Token::IsAssignmentOp(op));
    }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);
    virtual Assignment* AsAssignment() { return this; }

    Token::Value binary_op() const;
@@ -1094,7 +1109,7 @@
    Throw(Expression* exception, int pos)
        : exception_(exception), pos_(pos) {}

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);
    Expression* exception() const { return exception_; }
    int position() const { return pos_; }

@@ -1130,7 +1145,7 @@
          function_token_position_(RelocInfo::kNoPosition) {
    }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

    // Type testing & conversion
    virtual FunctionLiteral* AsFunctionLiteral()  { return this; }
@@ -1179,7 +1194,7 @@

    Handle<JSFunction> boilerplate() const { return boilerplate_; }

-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);

   private:
    Handle<JSFunction> boilerplate_;
@@ -1188,7 +1203,7 @@

  class ThisFunction: public Expression {
   public:
-  virtual void Accept(Visitor* v);
+  virtual void Accept(AstVisitor* v);
  };


@@ -1465,10 +1480,10 @@
  // Basic visitor
  // - leaf node visitors are abstract.

-class Visitor BASE_EMBEDDED {
+class AstVisitor BASE_EMBEDDED {
   public:
-  Visitor() : stack_overflow_(false) { }
-  virtual ~Visitor() { }
+  AstVisitor() : stack_overflow_(false) { }
+  virtual ~AstVisitor() { }

    // Dispatch
    void Visit(Node* node) { node->Accept(this); }

Modified: branches/bleeding_edge/src/codegen-arm.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-arm.cc   (original)
+++ branches/bleeding_edge/src/codegen-arm.cc   Thu Nov 27 05:55:06 2008
@@ -2303,7 +2303,7 @@

    ZoneList<Expression*>* args = node->arguments();

-  if (FLAG_debug_info) RecordStatementPosition(node);
+  RecordStatementPosition(node);
    // Standard function call.

    // Check if the function is a variable or a property.
@@ -2427,6 +2427,58 @@
      CallWithArguments(args, node->position());
      frame_->Push(r0);
    }
+}
+
+
+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);
  }



Modified: branches/bleeding_edge/src/codegen-arm.h
==============================================================================
--- branches/bleeding_edge/src/codegen-arm.h    (original)
+++ branches/bleeding_edge/src/codegen-arm.h    Thu Nov 27 05:55:06 2008
@@ -187,7 +187,7 @@
  //  
-------------------------------------------------------------------------
  // CodeGenerator

-class CodeGenerator: public Visitor {
+class CodeGenerator: public AstVisitor {
   public:
    // Takes a function literal, generates code for it. This function should  
only
    // be called by compiler.cc.

Modified: branches/bleeding_edge/src/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-ia32.cc  (original)
+++ branches/bleeding_edge/src/codegen-ia32.cc  Thu Nov 27 05:55:06 2008
@@ -2836,6 +2836,54 @@
  }


+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) {
    ASSERT(args->length() == 1);
    Load(args->at(0));

Modified: branches/bleeding_edge/src/codegen-ia32.h
==============================================================================
--- branches/bleeding_edge/src/codegen-ia32.h   (original)
+++ branches/bleeding_edge/src/codegen-ia32.h   Thu Nov 27 05:55:06 2008
@@ -193,7 +193,7 @@
  //  
-------------------------------------------------------------------------
  // CodeGenerator

-class CodeGenerator: public Visitor {
+class CodeGenerator: public AstVisitor {
   public:
    // Takes a function literal, generates code for it. This function should  
only
    // be called by compiler.cc.

Modified: branches/bleeding_edge/src/contexts.cc
==============================================================================
--- branches/bleeding_edge/src/contexts.cc      (original)
+++ branches/bleeding_edge/src/contexts.cc      Thu Nov 27 05:55:06 2008
@@ -74,14 +74,6 @@
                                 int* index_, PropertyAttributes*  
attributes) {
    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;
    *index_ = -1;
    *attributes = ABSENT;

Modified: branches/bleeding_edge/src/debug-delay.js
==============================================================================
--- branches/bleeding_edge/src/debug-delay.js   (original)
+++ branches/bleeding_edge/src/debug-delay.js   Thu Nov 27 05:55:06 2008
@@ -1012,7 +1012,7 @@
    try {
      try {
        // Convert the JSON string to an object.
-      request = %CompileString('(' + json_request + ')', 0, false)();
+      request = %CompileString('(' + json_request + ')', 0)();

        // Create an initial response.
        response = this.createResponse(request);
@@ -1465,7 +1465,7 @@
  DebugCommandProcessor.prototype.isRunning = function(json_response) {
    try {
      // 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 response.running;

Modified: branches/bleeding_edge/src/globals.h
==============================================================================
--- branches/bleeding_edge/src/globals.h        (original)
+++ branches/bleeding_edge/src/globals.h        Thu Nov 27 05:55:06 2008
@@ -197,7 +197,7 @@
  class String;
  class Struct;
  class SwitchStatement;
-class Visitor;
+class AstVisitor;
  class Variable;
  class VariableProxy;
  class RelocInfo;

Modified: branches/bleeding_edge/src/heap.h
==============================================================================
--- branches/bleeding_edge/src/heap.h   (original)
+++ branches/bleeding_edge/src/heap.h   Thu Nov 27 05:55:06 2008
@@ -193,7 +193,8 @@
    V(failure_symbol, "<failure>")                                         \
    V(space_symbol, " ")                                                   \
    V(exec_symbol, "exec")                                                 \
-  V(zero_symbol, "0")
+  V(zero_symbol, "0")                                                    \
+  V(global_eval_symbol, "GlobalEval")


  // Forward declaration of the GCTracer class.

Modified: branches/bleeding_edge/src/parser.cc
==============================================================================
--- branches/bleeding_edge/src/parser.cc        (original)
+++ branches/bleeding_edge/src/parser.cc        Thu Nov 27 05:55:06 2008
@@ -667,10 +667,16 @@

    virtual Expression* NewCall(Expression* expression,
                                ZoneList<Expression*>* arguments,
-                              bool is_eval, int pos) {
+                              int pos) {
      return Call::sentinel();
    }

+  virtual Expression* NewCallEval(Expression* expression,
+                                  ZoneList<Expression*>* arguments,
+                                  int pos) {
+    return CallEval::sentinel();
+  }
+
    virtual Statement* EmptyStatement() {
      return NULL;
    }
@@ -717,8 +723,14 @@

    virtual Expression* NewCall(Expression* expression,
                                ZoneList<Expression*>* arguments,
-                              bool is_eval, int pos) {
-    return new Call(expression, arguments, is_eval, pos);
+                              int 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() {
@@ -1343,7 +1355,7 @@
    // to the calling function context.
    if (top_scope_->is_function_scope()) {
      // Declare the variable in the function scope.
-    var = top_scope_->Lookup(name);
+    var = top_scope_->LookupLocal(name);
      if (var == NULL) {
        // Declare the name.
        var = top_scope_->Declare(name, mode);
@@ -2624,55 +2636,34 @@
          ZoneList<Expression*>* args = ParseArguments(CHECK_OK);

          // Keep track of eval() calls since they disable all local variable
-        // optimizations. We can ignore locally declared variables with
-        // name 'eval' since they override the global 'eval' function. We
-        // only need to look at unresolved variables (VariableProxies).
+        // optimizations.
+        // The calls that need special treatment are the
+        // 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_) {
-          // 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();
            if (callee != NULL &&  
callee->IsVariable(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();
-          } else {
-            // This is rather convoluted code to check if we're calling
-            // a function named 'eval' through a property access. If so,
-            // we mark it as a possible eval call (we don't know if the
-            // 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();
-              }
+            Handle<String> name = callee->name();
+            Variable* var = top_scope_->Lookup(name);
+            if (var == NULL) {
+              // We do not allow direct calls to 'eval' in our internal
+              // JS files. Use builtin functions instead.
+              ASSERT(!Bootstrapper::IsActive());
+              top_scope_->RecordEvalCall();
+              is_potentially_direct_eval = true;
              }
            }
          }

-        // Optimize the eval() case w/o arguments so we
-        // don't need to handle it every time at runtime.
-        //
-        // 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()));
+        if (is_potentially_direct_eval) {
+          result = factory()->NewCallEval(result, args, pos);
          } else {
-          result = factory()->NewCall(result, args, is_eval, pos);
+          result = factory()->NewCall(result, args, pos);
          }
          break;
        }

Modified: branches/bleeding_edge/src/prettyprinter.cc
==============================================================================
--- branches/bleeding_edge/src/prettyprinter.cc (original)
+++ branches/bleeding_edge/src/prettyprinter.cc Thu Nov 27 05:55:06 2008
@@ -348,6 +348,11 @@
  }


+void PrettyPrinter::VisitCallEval(CallEval* node) {
+  VisitCall(node);
+}
+
+
  void PrettyPrinter::VisitCallNew(CallNew* node) {
    Print("new (");
    Visit(node->expression());
@@ -1013,6 +1018,11 @@
    IndentedScope indent("CALL");
    Visit(node->expression());
    PrintArguments(node->arguments());
+}
+
+
+void AstPrinter::VisitCallEval(CallEval* node) {
+  VisitCall(node);
  }



Modified: branches/bleeding_edge/src/prettyprinter.h
==============================================================================
--- branches/bleeding_edge/src/prettyprinter.h  (original)
+++ branches/bleeding_edge/src/prettyprinter.h  Thu Nov 27 05:55:06 2008
@@ -34,7 +34,7 @@

  #ifdef DEBUG

-class PrettyPrinter: public Visitor {
+class PrettyPrinter: public AstVisitor {
   public:
    PrettyPrinter();
    virtual ~PrettyPrinter();

Modified: branches/bleeding_edge/src/rewriter.cc
==============================================================================
--- branches/bleeding_edge/src/rewriter.cc      (original)
+++ branches/bleeding_edge/src/rewriter.cc      Thu Nov 27 05:55:06 2008
@@ -34,7 +34,7 @@
  namespace v8 { namespace internal {


-class AstOptimizer: public Visitor {
+class AstOptimizer: public AstVisitor {
   public:
    explicit AstOptimizer() {
    }
@@ -344,6 +344,12 @@
  }


+void AstOptimizer::VisitCallEval(CallEval* node) {
+  Visit(node->expression());
+  OptimizeArguments(node->arguments());
+}
+
+
  void AstOptimizer::VisitCallNew(CallNew* node) {
    Visit(node->expression());
    OptimizeArguments(node->arguments());
@@ -469,7 +475,7 @@
  }


-class Processor: public Visitor {
+class Processor: public AstVisitor {
   public:
    explicit Processor(VariableProxy* result)
        : result_(result),
@@ -697,6 +703,12 @@


  void Processor::VisitCall(Call* node) {
+  USE(node);
+  UNREACHABLE();
+}
+
+
+void Processor::VisitCallEval(CallEval* node) {
    USE(node);
    UNREACHABLE();
  }

Modified: branches/bleeding_edge/src/runtime.cc
==============================================================================
--- branches/bleeding_edge/src/runtime.cc       (original)
+++ branches/bleeding_edge/src/runtime.cc       Thu Nov 27 05:55:06 2008
@@ -3934,57 +3934,6 @@
  }


-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) {
    ASSERT(args.length() == 1);
    Object* global = args[0];
@@ -3995,34 +3944,109 @@

  static Object* Runtime_CompileString(Arguments args) {
    HandleScope scope;
-  ASSERT(args.length() == 3);
+  ASSERT(args.length() == 2);
    CONVERT_ARG_CHECKED(String, source, 0);
    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.
-  bool is_global = context->IsGlobalContext();
    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();
+  Handle<Context> context(Top::context()->global_context());
    Handle<JSFunction> fun =
        Factory::NewFunctionFromBoilerplate(boilerplate, context);
    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;
  }



Modified: branches/bleeding_edge/src/runtime.h
==============================================================================
--- branches/bleeding_edge/src/runtime.h        (original)
+++ branches/bleeding_edge/src/runtime.h        Thu Nov 27 05:55:06 2008
@@ -190,13 +190,13 @@
    F(NumberIsFinite, 1) \
    \
    /* Globals */ \
-  F(CompileString, 3) \
+  F(CompileString, 2) \
    F(CompileScript, 4) \
    F(GlobalPrint, 1) \
    \
    /* Eval */ \
-  F(EvalReceiver, 1) \
    F(GlobalReceiver, 1) \
+  F(ResolvePossiblyDirectEval, 2) \
    \
    F(SetProperty, -1 /* 3 or 4 */) \
    F(IgnoreAttributesAndSetProperty, -1 /* 3 or 4 */) \

Modified: branches/bleeding_edge/src/scopes.cc
==============================================================================
--- branches/bleeding_edge/src/scopes.cc        (original)
+++ branches/bleeding_edge/src/scopes.cc        Thu Nov 27 05:55:06 2008
@@ -184,11 +184,22 @@



-Variable* Scope::Lookup(Handle<String> name) {
+Variable* Scope::LookupLocal(Handle<String> 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) {
    ASSERT(is_function_scope() && function_ == NULL);
    function_ = new Variable(this, name, Variable::CONST, true, false);
@@ -207,7 +218,7 @@

  void Scope::AddParameter(Variable* var) {
    ASSERT(is_function_scope());
-  ASSERT(Lookup(var->name()) == var);
+  ASSERT(LookupLocal(var->name()) == var);
    params_.Add(var);
  }

@@ -258,7 +269,7 @@
  }


-void Scope::VisitIllegalRedeclaration(Visitor* visitor) {
+void Scope::VisitIllegalRedeclaration(AstVisitor* visitor) {
    ASSERT(HasIllegalRedeclaration());
    illegal_redecl_->Accept(visitor);
  }
@@ -513,7 +524,7 @@
    bool guess = scope_calls_eval_;

    // Try to find the variable in this scope.
-  Variable* var = Lookup(name);
+  Variable* var = LookupLocal(name);

    if (var != NULL) {
      // We found a variable. If this is not an inner lookup, we are done.
@@ -707,7 +718,7 @@

  void Scope::AllocateParameterLocals() {
    ASSERT(is_function_scope());
-  Variable* arguments = Lookup(Factory::arguments_symbol());
+  Variable* arguments = LookupLocal(Factory::arguments_symbol());
    ASSERT(arguments != NULL);  // functions have 'arguments' declared  
implicitly
    if (MustAllocate(arguments) && !HasArgumentsParameter()) {
      // 'arguments' is used. Unless there is also a parameter called

Modified: branches/bleeding_edge/src/scopes.h
==============================================================================
--- branches/bleeding_edge/src/scopes.h (original)
+++ branches/bleeding_edge/src/scopes.h Thu Nov 27 05:55:06 2008
@@ -88,6 +88,10 @@
    // Declarations

    // 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);

    // Declare the function variable for a function literal. This variable
@@ -138,7 +142,7 @@

    // Visit the illegal redeclaration expression. Do not call if the
    // 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.
    bool HasIllegalRedeclaration() const { return illegal_redecl_ != NULL; }

Modified: branches/bleeding_edge/src/usage-analyzer.cc
==============================================================================
--- branches/bleeding_edge/src/usage-analyzer.cc        (original)
+++ branches/bleeding_edge/src/usage-analyzer.cc        Thu Nov 27 05:55:06 2008
@@ -39,7 +39,7 @@
  static const int InitialWeight = 100;


-class UsageComputer: public Visitor {
+class UsageComputer: public AstVisitor {
   public:
    static bool Traverse(Node* node);

@@ -73,6 +73,7 @@
    void VisitThrow(Throw* node);
    void VisitProperty(Property* node);
    void VisitCall(Call* node);
+  void VisitCallEval(CallEval* node);
    void VisitCallNew(CallNew* node);
    void VisitCallRuntime(CallRuntime* node);
    void VisitUnaryOperation(UnaryOperation* node);
@@ -318,6 +319,11 @@
  void UsageComputer::VisitCall(Call* node) {
    Read(node->expression());
    ReadList(node->arguments());
+}
+
+
+void UsageComputer::VisitCallEval(CallEval* node) {
+  VisitCall(node);
  }



Modified: branches/bleeding_edge/src/v8natives.js
==============================================================================
--- branches/bleeding_edge/src/v8natives.js     (original)
+++ branches/bleeding_edge/src/v8natives.js     Thu Nov 27 05:55:06 2008
@@ -105,15 +105,15 @@
  function GlobalEval(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 ' +
                           '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;

-  return f.call(%EvalReceiver(this));
+  return f.call(this);
  }


@@ -121,7 +121,7 @@
  function GlobalExecScript(expr, lang) {
    // NOTE: We don't care about the character casing.
    if (!lang || /javascript/i.test(lang)) {
-    var f = %CompileString(ToString(expr), 0, false);
+    var f = %CompileString(ToString(expr), 0);
      f.call(%GlobalReceiver(global));
    }
    return null;
@@ -140,7 +140,7 @@

    // ECMA-262 - 15.1.1.3.
    %SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
-
+
    // Setup non-enumerable function on the global object.
    InstallFunctions(global, DONT_ENUM, $Array(
      "isNaN", GlobalIsNaN,
@@ -521,7 +521,7 @@

    // The call to SetNewFunctionAttributes will ensure the prototype
    // 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");
    return %SetNewFunctionAttributes(f);
  }

Modified: branches/bleeding_edge/test/cctest/test-api.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-api.cc      (original)
+++ branches/bleeding_edge/test/cctest/test-api.cc      Thu Nov 27 05:55:06 2008
@@ -4018,27 +4018,41 @@
  }


-THREADED_TEST(Eval) {
+THREADED_TEST(EvalAliasedDynamic) {
    v8::HandleScope scope;
    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 =
-      Script::Compile(v8_str("foo = 0;"
-                             "(function() {"
+      Script::Compile(v8_str("function f(x) { "
                               "  var foo = 2;"
-                             "  return eval('foo');"
-                             "})();"));
-  Local<Value> result = script->Run();
-  CHECK_EQ(2, result->Int32Value());
+                             "  with (x) { return eval('foo'); }"
+                             "}"
+                             "foo = 0;"
+                             "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::Compile(v8_str("function MyObject() { this.self =  
eval('this'); }"
-                             "var o = new MyObject();"
-                             "o === o.self"));
-  result = script->Run();
-  CHECK(result->IsTrue());
+    Script::Compile(v8_str("function f(x) { "
+                           "  var bar = 2;"
+                           "  with (x) { return eval('bar'); }"
+                           "}"
+                           "f(global)"));
+  script->Run();
+  CHECK(try_catch.HasCaught());
+  try_catch.Reset();
  }



Added: branches/bleeding_edge/test/mjsunit/eval.js
==============================================================================
--- (empty file)
+++ branches/bleeding_edge/test/mjsunit/eval.js Thu Nov 27 05:55:06 2008
@@ -0,0 +1,136 @@
+// 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);

Modified: branches/bleeding_edge/test/mjsunit/function-caller.js
==============================================================================
--- branches/bleeding_edge/test/mjsunit/function-caller.js      (original)
+++ branches/bleeding_edge/test/mjsunit/function-caller.js      Thu Nov 27  
05:55:06 2008
@@ -44,5 +44,5 @@
  f(null);

  // Check called from eval.
-eval('f(eval)');
+eval('f(null)');


Modified: branches/bleeding_edge/test/mjsunit/fuzz-natives.js
==============================================================================
--- branches/bleeding_edge/test/mjsunit/fuzz-natives.js (original)
+++ branches/bleeding_edge/test/mjsunit/fuzz-natives.js Thu Nov 27 05:55:06  
2008
@@ -122,7 +122,8 @@
    "LazyCompile": true,
    "CreateObjectLiteralBoilerplate": true,
    "CloneObjectLiteralBoilerplate": true,
-  "IS_VAR": true
+  "IS_VAR": true,
+  "ResolvePossiblyDirectEval": true
  };

  var currentlyUncallable = {

Modified: branches/bleeding_edge/test/mozilla/mozilla.status
==============================================================================
--- branches/bleeding_edge/test/mozilla/mozilla.status  (original)
+++ branches/bleeding_edge/test/mozilla/mozilla.status  Thu Nov 27 05:55:06  
2008
@@ -293,10 +293,6 @@
  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().
  js1_5/Regress/regress-248444: FAIL_OK
  js1_5/Regress/regress-313967-01: FAIL_OK
@@ -583,10 +579,6 @@
  # Bug 1202597: New js1_5/Expressions/regress-394673 is failing.
  # Marked as: Will not fix. V8 throws an acceptable RangeError.
  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 #####################


--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to