Changeset 91164 in webkit


Ignore:
Timestamp:
Jul 16, 2011 10:04:36 PM (13 years ago)
Author:
barraclough@apple.com
Message:

https://bugs.webkit.org/show_bug.cgi?id=64657
Converted this value not preserved when accessed via direct eval.

Reviewed by Oliver Hunt.

Source/JavaScriptCore:

Upon entry into a non-strict function, primitive this values should be boxed as Object types
(or substituted with the global object) - which is done by op_convert_this. However we only
do so where this is used lexically within the function (we omit the conversion op if not).
The problem comes if a direct eval (running within the function's scope) accesses the this
value.

We are safe in the case of a single eval, since the this object will be converted within
callEval, however the converted value is not preserved, and a new wrapper object is allocated
each time eval is invoked. This is inefficient and incorrect, since any changes to the wrapper
object will be lost between eval statements.

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator):

  • If a function uses eval, we always need to convert this.
  • interpreter/Interpreter.cpp:

(JSC::Interpreter::execute):

  • Don't convert primitive values here - this is too late!

(JSC::Interpreter::privateExecute):

  • Changed op_convert_this to call new isPrimitive method.
  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • Changed op_convert_this to call new isPrimitive method.
  • runtime/JSCell.h:

(JSC::JSCell::JSValue::isPrimitive):

  • Added JSValue::isPrimitive.
  • runtime/JSValue.h:
    • Added JSValue::isPrimitive.

LayoutTests:

Added test case.

  • fast/js/read-modify-eval-expected.txt:
  • fast/js/script-tests/read-modify-eval.js:

(primitiveThisTest):

Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r91158 r91164  
     12011-07-16  Gavin Barraclough  <barraclough@apple.com>
     2
     3        https://bugs.webkit.org/show_bug.cgi?id=64657
     4        Converted this value not preserved when accessed via direct eval.
     5
     6        Reviewed by Oliver Hunt.
     7
     8        Added test case.
     9
     10        * fast/js/read-modify-eval-expected.txt:
     11        * fast/js/script-tests/read-modify-eval.js:
     12        (primitiveThisTest):
     13
    1142011-07-16  Enrica Casucci  <enrica@apple.com>
    215
  • trunk/LayoutTests/fast/js/read-modify-eval-expected.txt

    r29997 r91164  
    1919PASS postIncTest(); is true
    2020PASS postDecTest(); is true
     21PASS primitiveThisTest.call(1); is true
     22PASS strictThisTest.call(1); is true
    2123PASS successfullyParsed is true
    2224
  • trunk/LayoutTests/fast/js/script-tests/read-modify-eval.js

    r48651 r91164  
    108108}
    109109
     110function primitiveThisTest()
     111{
     112    // Test that conversion of this is persistant over multiple calls to eval,
     113    // even where 'this' is not directly used within the function.
     114    eval('this.value = "Seekrit message";');
     115    return eval('this.value') === "Seekrit message";
     116}
     117
     118function strictThisTest()
     119{
     120    // In a strict mode function primitive this values are not converted, so
     121    // the property access in the first eval is writing a value to a temporary
     122    // object, and should not be observed by the second eval.
     123    "use strict";
     124    eval('this.value = "Seekrit message";');
     125    return eval('this.value') === undefined;
     126}
     127
    110128shouldBeTrue('multTest();');
    111129shouldBeTrue('divTest();');
     
    125143shouldBeTrue('postDecTest();');
    126144
     145shouldBeTrue('primitiveThisTest.call(1);');
     146shouldBeTrue('strictThisTest.call(1);');
     147
    127148successfullyParsed = true;
  • trunk/Source/JavaScriptCore/ChangeLog

    r91160 r91164  
     12011-07-16  Gavin Barraclough  <barraclough@apple.com>
     2
     3        https://bugs.webkit.org/show_bug.cgi?id=64657
     4        Converted this value not preserved when accessed via direct eval.
     5
     6        Reviewed by Oliver Hunt.
     7
     8        Upon entry into a non-strict function, primitive this values should be boxed as Object types
     9        (or substituted with the global object) - which is done by op_convert_this. However we only
     10        do so where this is used lexically within the function (we omit the conversion op if not).
     11        The problem comes if a direct eval (running within the function's scope) accesses the this
     12        value.
     13
     14        We are safe in the case of a single eval, since the this object will be converted within
     15        callEval, however the converted value is not preserved, and a new wrapper object is allocated
     16        each time eval is invoked. This is inefficient and incorrect, since any changes to the wrapper
     17        object will be lost between eval statements.
     18
     19        * bytecompiler/BytecodeGenerator.cpp:
     20        (JSC::BytecodeGenerator::BytecodeGenerator):
     21            - If a function uses eval, we always need to convert this.
     22        * interpreter/Interpreter.cpp:
     23        (JSC::Interpreter::execute):
     24            - Don't convert primitive values here - this is too late!
     25        (JSC::Interpreter::privateExecute):
     26            - Changed op_convert_this to call new isPrimitive method.
     27        * jit/JITStubs.cpp:
     28        (JSC::DEFINE_STUB_FUNCTION):
     29            - Changed op_convert_this to call new isPrimitive method.
     30        * runtime/JSCell.h:
     31        (JSC::JSCell::JSValue::isPrimitive):
     32            - Added JSValue::isPrimitive.
     33        * runtime/JSValue.h:
     34            - Added JSValue::isPrimitive.
     35
    1362011-07-16  Filip Pizlo  <fpizlo@apple.com>
    237
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r91095 r91164  
    414414        instructions().append(m_thisRegister.index());
    415415        instructions().append(funcProto->index());
    416     } else if (functionBody->usesThis() || m_shouldEmitDebugHooks) {
    417         if (!codeBlock->isStrictMode()) {
    418             emitOpcode(op_convert_this);
    419             instructions().append(m_thisRegister.index());
    420         }
     416    } else if (!codeBlock->isStrictMode() && (functionBody->usesThis() || codeBlock->usesEval() || m_shouldEmitDebugHooks)) {
     417        emitOpcode(op_convert_this);
     418        instructions().append(m_thisRegister.index());
    421419    }
    422420}
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r91095 r91164  
    12411241    ASSERT(codeBlock->m_numParameters == 1); // 1 parameter for 'this'.
    12421242    newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), codeBlock->m_numParameters, 0);
    1243     newCallFrame->uncheckedR(newCallFrame->hostThisRegister()) = thisValue.toThisObject(newCallFrame);
     1243    newCallFrame->uncheckedR(newCallFrame->hostThisRegister()) = thisValue;
    12441244
    12451245    Profiler** profiler = Profiler::enabledProfilerReference();
     
    46224622        int thisRegister = vPC[1].u.operand;
    46234623        JSValue thisVal = callFrame->r(thisRegister).jsValue();
    4624         if (!thisVal.isCell() || thisVal.isString())
     4624        if (thisVal.isPrimitive())
    46254625            callFrame->uncheckedR(thisRegister) = JSValue(thisVal.toThisObject(callFrame));
    46264626
  • trunk/Source/JavaScriptCore/jit/JITStubs.cpp

    r91095 r91164  
    12811281    CallFrame* callFrame = stackFrame.callFrame;
    12821282
    1283     ASSERT(!v1.isCell() || v1.isString());
     1283    ASSERT(v1.isPrimitive());
    12841284
    12851285    JSObject* result = v1.toThisObject(callFrame);
  • trunk/Source/JavaScriptCore/runtime/JSCell.h

    r90273 r91164  
    209209    }
    210210
     211    inline bool JSValue::isPrimitive() const
     212    {
     213        return !isCell() || asCell()->isString();
     214    }
     215
    211216    inline bool JSValue::isGetterSetter() const
    212217    {
  • trunk/Source/JavaScriptCore/runtime/JSValue.h

    r91095 r91164  
    153153        bool isNumber() const;
    154154        bool isString() const;
     155        bool isPrimitive() const;
    155156        bool isGetterSetter() const;
    156157        bool isObject() const;
Note: See TracChangeset for help on using the changeset viewer.