Changeset 90938 in webkit


Ignore:
Timestamp:
Jul 13, 2011 11:59:34 AM (13 years ago)
Author:
barraclough@apple.com
Message:

https://bugs.webkit.org/show_bug.cgi?id=64424
Our direct eval behaviour deviates slightly from the spec.

Reviewed by Oliver Hunt.

Source/JavaScriptCore:

The ES5 spec defines a concept of 'Direct Call to Eval' (see section 15.1.2.1.1), where
behaviour will differ from that of an indirect call (e.g. " { eval: window.eval }.eval();"
or "var a = eval; a();" are indirect calls), particularly in non-strict scopes variables
may be introduced into the caller's environment.

ES5 direct calls are any call where the callee function is provided by a reference, a base
of that Reference is an EnvironmentRecord (this corresponds to all productions
"PrimaryExpression: Identifier", see 10.2.2.1 GetIdentifierReference), and where the name
of the reference is "eval". This means any expression of the form "eval(...)", and that
calls the standard built in eval method from on the Global Object, is considered to be
direct.

In JavaScriptCore we are currently overly restrictive. We also check that the
EnvironmentRecord that is the base of the reference is the Declaractive Environment Record
at the root of the scope chain, corresponding to the Global Object - an "eval(..)" statement
that hits a var eval in a nested scope is not considered to be direct. This behaviour does
not emanate from the spec, and is incorrect.

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::privateExecute):

  • Fixed direct eval check in op_call_eval.
  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • Fixed direct eval check in op_call_eval.
  • runtime/Executable.h:

(JSC::isHostFunction):

  • Added check for host function with specific NativeFunction.

LayoutTests:

Correct expected results.

  • fast/js/eval-keyword-vs-function-expected.txt:
  • fast/js/eval-keyword-vs-function.html:
Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r90936 r90938  
     12011-07-12  Gavin Barraclough  <barraclough@apple.com>
     2
     3        https://bugs.webkit.org/show_bug.cgi?id=64424
     4        Our direct eval behaviour deviates slightly from the spec.
     5
     6        Reviewed by Oliver Hunt.
     7
     8        Correct expected results.
     9
     10        * fast/js/eval-keyword-vs-function-expected.txt:
     11        * fast/js/eval-keyword-vs-function.html:
     12
    1132011-07-13  Abhishek Arya  <inferno@chromium.org>
    214
  • trunk/LayoutTests/fast/js/eval-keyword-vs-function-expected.txt

    r30871 r90938  
    1313PASS: globalEval("x") should be 0 and is.
    1414PASS: localEval("x") should be 0 and is.
    15 PASS: (function() { var eval = window.eval; return eval("x"); })() should be 0 and is.
     15PASS: (function() { var eval = window.eval; return eval("x"); })() should be 1 and is.
    1616
    1717----- Variable Object: -----
     
    2121PASS: globalEval("var y; "y" in window") should be true and is.
    2222PASS: localEval("var y; "y" in window") should be true and is.
    23 PASS: (function() { var eval = window.eval; return eval("var y; "y" in window"); })() should be true and is.
     23PASS: (function() { var eval = window.eval; return eval("var y; "y" in window"); })() should be false and is.
    2424
    2525----- Scope Chain for Setters: -----
     
    2929PASS: globalEval("z = 3; window.z") should be 3 and is.
    3030PASS: localEval("z = 4; window.z") should be 4 and is.
    31 PASS: (function() { var eval = window.eval; return eval("z = 5; window.z"); })() should be 5 and is.
     31PASS: (function() { var eval = window.eval; return eval("z = 5; window.z"); })() should be 4 and is.
    3232
    3333----- This Object: -----
  • trunk/LayoutTests/fast/js/eval-keyword-vs-function.html

    r30871 r90938  
    4444    shouldBe('globalEval("x")', globalEval("x"), 0);
    4545    shouldBe('localEval("x")', localEval("x"), 0);
    46     shouldBe('(function() { var eval = window.eval; return eval("x"); })()', (function() { var eval = window.eval; return eval("x"); })(), 0);
     46
     47    // Per ES5 15.1.2.11 & 10.2.2.1 any reference that hits an enviromment record (i.e. does not have a base)
     48    // and has a reference name of "eval" is treated as a direct eval - the assignment to a var makes no difference.
     49    shouldBe('(function() { var eval = window.eval; return eval("x"); })()', (function() { var eval = window.eval; return eval("x"); })(), 1);
    4750}
    4851
     
    6366    delete window.y;
    6467   
    65     shouldBe('(function() { var eval = window.eval; return eval("var y; \"y\" in window"); })()', (function() { var eval = window.eval; return eval("var y; \"y\" in window"); })(), true);
     68    // Per ES5 15.1.2.11 & 10.2.2.1 any reference that hits an enviromment record (i.e. does not have a base)
     69    // and has a reference name of "eval" is treated as a direct eval - the assignment to a var makes no difference.
     70    shouldBe('(function() { var eval = window.eval; return eval("var y; \"y\" in window"); })()', (function() { var eval = window.eval; return eval("var y; \"y\" in window"); })(), false);
    6671}
    6772
     
    8085    shouldBe('localEval("z = 4; window.z")', localEval("z = 4; window.z"), 4);
    8186
    82     shouldBe('(function() { var eval = window.eval; return eval("z = 5; window.z"); })()', (function() { var eval = window.eval; return eval("z = 5; window.z"); })(), 5);
     87    // Per ES5 15.1.2.11 & 10.2.2.1 any reference that hits an enviromment record (i.e. does not have a base)
     88    // and has a reference name of "eval" is treated as a direct eval - the assignment to a var makes no difference.
     89    shouldBe('(function() { var eval = window.eval; return eval("z = 5; window.z"); })()', (function() { var eval = window.eval; return eval("z = 5; window.z"); })(), 4);
    8390}
    8491
  • trunk/Source/JavaScriptCore/ChangeLog

    r90916 r90938  
     12011-07-12  Gavin Barraclough  <barraclough@apple.com>
     2
     3        https://bugs.webkit.org/show_bug.cgi?id=64424
     4        Our direct eval behaviour deviates slightly from the spec.
     5
     6        Reviewed by Oliver Hunt.
     7
     8        The ES5 spec defines a concept of 'Direct Call to Eval' (see section 15.1.2.1.1), where
     9        behaviour will differ from that of an indirect call (e.g. " { eval: window.eval }.eval();"
     10        or "var a = eval; a();" are indirect calls), particularly in non-strict scopes variables
     11        may be introduced into the caller's environment.
     12
     13        ES5 direct calls are any call where the callee function is provided by a reference, a base
     14        of that Reference is an EnvironmentRecord (this corresponds to all productions
     15        "PrimaryExpression: Identifier", see 10.2.2.1 GetIdentifierReference), and where the name
     16        of the reference is "eval". This means any expression of the form "eval(...)", and that
     17        calls the standard built in eval method from on the Global Object, is considered to be
     18        direct.
     19
     20        In JavaScriptCore we are currently overly restrictive. We also check that the
     21        EnvironmentRecord that is the base of the reference is the Declaractive Environment Record
     22        at the root of the scope chain, corresponding to the Global Object - an "eval(..)" statement
     23        that hits a var eval in a nested scope is not considered to be direct. This behaviour does
     24        not emanate from the spec, and is incorrect.
     25
     26        * interpreter/Interpreter.cpp:
     27        (JSC::Interpreter::privateExecute):
     28            - Fixed direct eval check in op_call_eval.
     29        * jit/JITStubs.cpp:
     30        (JSC::DEFINE_STUB_FUNCTION):
     31            - Fixed direct eval check in op_call_eval.
     32        * runtime/Executable.h:
     33        (JSC::isHostFunction):
     34            - Added check for host function with specific NativeFunction.
     35
    1362011-07-13  Ademar de Souza Reis Jr.  <ademar.reis@openbossa.org>
    237
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r90401 r90938  
    41004100        JSValue funcVal = callFrame->r(func).jsValue();
    41014101
    4102         Register* newCallFrame = callFrame->registers() + registerOffset;
    4103         Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
    4104         JSValue thisValue = argv[0].jsValue();
    4105         JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject.get();
    4106 
    4107         if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
     4102        if (isHostFunction(callFrame->globalData(), funcVal, globalFuncEval)) {
     4103            Register* newCallFrame = callFrame->registers() + registerOffset;
     4104            Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
     4105
    41084106            JSValue result = callEval(callFrame, registerFile, argv, argCount, registerOffset);
    41094107            if ((exceptionValue = globalData->exception))
  • trunk/Source/JavaScriptCore/jit/JITStubs.cpp

    r90875 r90938  
    31603160    int argCount = stackFrame.args[2].int32();
    31613161
     3162    if (!isHostFunction(callFrame->globalData(), funcVal, globalFuncEval))
     3163        return JSValue::encode(JSValue());
     3164
    31623165    Register* newCallFrame = callFrame->registers() + registerOffset;
    31633166    Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
    3164     JSValue baseValue = argv[0].jsValue();
    3165     JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject.get();
    3166 
    3167     if (baseValue == globalObject && funcVal == globalObject->evalFunction()) {
    3168         JSValue result = interpreter->callEval(callFrame, registerFile, argv, argCount, registerOffset);
    3169         CHECK_FOR_EXCEPTION_AT_END();
    3170         return JSValue::encode(result);
    3171     }
    3172 
    3173     return JSValue::encode(JSValue());
     3167
     3168    JSValue result = interpreter->callEval(callFrame, registerFile, argv, argCount, registerOffset);
     3169    CHECK_FOR_EXCEPTION_AT_END();
     3170    return JSValue::encode(result);
    31743171}
    31753172
  • trunk/Source/JavaScriptCore/runtime/Executable.h

    r90437 r90938  
    515515        return static_cast<NativeExecutable*>(m_executable.get())->function();
    516516    }
     517
     518    inline bool isHostFunction(JSGlobalData& globalData, JSValue value, NativeFunction nativeFunction)
     519    {
     520        JSFunction* function = static_cast<JSFunction*>(getJSFunction(globalData, value));
     521        if (!function || !function->isHostFunction())
     522            return false;
     523        return function->nativeFunction() == nativeFunction;
     524    }
     525
    517526}
    518527
Note: See TracChangeset for help on using the changeset viewer.