Title: [91164] trunk
Revision
91164
Author
[email protected]
Date
2011-07-16 22:04:36 -0700 (Sat, 16 Jul 2011)

Log 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/_javascript_Core: 

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):

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (91163 => 91164)


--- trunk/LayoutTests/ChangeLog	2011-07-17 04:56:20 UTC (rev 91163)
+++ trunk/LayoutTests/ChangeLog	2011-07-17 05:04:36 UTC (rev 91164)
@@ -1,3 +1,16 @@
+2011-07-16  Gavin Barraclough  <[email protected]>
+
+        https://bugs.webkit.org/show_bug.cgi?id=64657
+        Converted this value not preserved when accessed via direct eval.
+
+        Reviewed by Oliver Hunt.
+
+        Added test case.
+
+        * fast/js/read-modify-eval-expected.txt:
+        * fast/js/script-tests/read-modify-eval.js:
+        (primitiveThisTest):
+
 2011-07-16  Enrica Casucci  <[email protected]>
 
         REGRESSION: Pressing return in a particular document sends the cursor to the end of the document.

Modified: trunk/LayoutTests/fast/js/read-modify-eval-expected.txt (91163 => 91164)


--- trunk/LayoutTests/fast/js/read-modify-eval-expected.txt	2011-07-17 04:56:20 UTC (rev 91163)
+++ trunk/LayoutTests/fast/js/read-modify-eval-expected.txt	2011-07-17 05:04:36 UTC (rev 91164)
@@ -18,6 +18,8 @@
 PASS preDecTest(); is true
 PASS postIncTest(); is true
 PASS postDecTest(); is true
+PASS primitiveThisTest.call(1); is true
+PASS strictThisTest.call(1); is true
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/fast/js/script-tests/read-modify-eval.js (91163 => 91164)


--- trunk/LayoutTests/fast/js/script-tests/read-modify-eval.js	2011-07-17 04:56:20 UTC (rev 91163)
+++ trunk/LayoutTests/fast/js/script-tests/read-modify-eval.js	2011-07-17 05:04:36 UTC (rev 91164)
@@ -107,6 +107,24 @@
     return x.value == -1;
 }
 
+function primitiveThisTest()
+{
+    // Test that conversion of this is persistant over multiple calls to eval,
+    // even where 'this' is not directly used within the function.
+    eval('this.value = "Seekrit message";');
+    return eval('this.value') === "Seekrit message";
+}
+
+function strictThisTest()
+{
+    // In a strict mode function primitive this values are not converted, so
+    // the property access in the first eval is writing a value to a temporary
+    // object, and should not be observed by the second eval.
+    "use strict";
+    eval('this.value = "Seekrit message";');
+    return eval('this.value') === undefined;
+}
+
 shouldBeTrue('multTest();');
 shouldBeTrue('divTest();');
 shouldBeTrue('addTest();');
@@ -124,4 +142,7 @@
 shouldBeTrue('postIncTest();');
 shouldBeTrue('postDecTest();');
 
+shouldBeTrue('primitiveThisTest.call(1);');
+shouldBeTrue('strictThisTest.call(1);');
+
 successfullyParsed = true;

Modified: trunk/Source/_javascript_Core/ChangeLog (91163 => 91164)


--- trunk/Source/_javascript_Core/ChangeLog	2011-07-17 04:56:20 UTC (rev 91163)
+++ trunk/Source/_javascript_Core/ChangeLog	2011-07-17 05:04:36 UTC (rev 91164)
@@ -1,3 +1,38 @@
+2011-07-16  Gavin Barraclough  <[email protected]>
+
+        https://bugs.webkit.org/show_bug.cgi?id=64657
+        Converted this value not preserved when accessed via direct eval.
+
+        Reviewed by Oliver Hunt.
+
+        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.
+
 2011-07-16  Filip Pizlo  <[email protected]>
 
         DFG JIT compare/branch code emits is-integer tests even when a value is

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (91163 => 91164)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2011-07-17 04:56:20 UTC (rev 91163)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2011-07-17 05:04:36 UTC (rev 91164)
@@ -413,11 +413,9 @@
         emitOpcode(op_create_this);
         instructions().append(m_thisRegister.index());
         instructions().append(funcProto->index());
-    } else if (functionBody->usesThis() || m_shouldEmitDebugHooks) {
-        if (!codeBlock->isStrictMode()) {
-            emitOpcode(op_convert_this);
-            instructions().append(m_thisRegister.index());
-        }
+    } else if (!codeBlock->isStrictMode() && (functionBody->usesThis() || codeBlock->usesEval() || m_shouldEmitDebugHooks)) {
+        emitOpcode(op_convert_this);
+        instructions().append(m_thisRegister.index());
     }
 }
 

Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (91163 => 91164)


--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2011-07-17 04:56:20 UTC (rev 91163)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2011-07-17 05:04:36 UTC (rev 91164)
@@ -1240,7 +1240,7 @@
 
     ASSERT(codeBlock->m_numParameters == 1); // 1 parameter for 'this'.
     newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), codeBlock->m_numParameters, 0);
-    newCallFrame->uncheckedR(newCallFrame->hostThisRegister()) = thisValue.toThisObject(newCallFrame);
+    newCallFrame->uncheckedR(newCallFrame->hostThisRegister()) = thisValue;
 
     Profiler** profiler = Profiler::enabledProfilerReference();
     if (*profiler)
@@ -4621,7 +4621,7 @@
 
         int thisRegister = vPC[1].u.operand;
         JSValue thisVal = callFrame->r(thisRegister).jsValue();
-        if (!thisVal.isCell() || thisVal.isString())
+        if (thisVal.isPrimitive())
             callFrame->uncheckedR(thisRegister) = JSValue(thisVal.toThisObject(callFrame));
 
         vPC += OPCODE_LENGTH(op_convert_this);

Modified: trunk/Source/_javascript_Core/jit/JITStubs.cpp (91163 => 91164)


--- trunk/Source/_javascript_Core/jit/JITStubs.cpp	2011-07-17 04:56:20 UTC (rev 91163)
+++ trunk/Source/_javascript_Core/jit/JITStubs.cpp	2011-07-17 05:04:36 UTC (rev 91164)
@@ -1280,7 +1280,7 @@
     JSValue v1 = stackFrame.args[0].jsValue();
     CallFrame* callFrame = stackFrame.callFrame;
 
-    ASSERT(!v1.isCell() || v1.isString());
+    ASSERT(v1.isPrimitive());
 
     JSObject* result = v1.toThisObject(callFrame);
     CHECK_FOR_EXCEPTION_AT_END();

Modified: trunk/Source/_javascript_Core/runtime/JSCell.h (91163 => 91164)


--- trunk/Source/_javascript_Core/runtime/JSCell.h	2011-07-17 04:56:20 UTC (rev 91163)
+++ trunk/Source/_javascript_Core/runtime/JSCell.h	2011-07-17 05:04:36 UTC (rev 91164)
@@ -208,6 +208,11 @@
         return isCell() && asCell()->isString();
     }
 
+    inline bool JSValue::isPrimitive() const
+    {
+        return !isCell() || asCell()->isString();
+    }
+
     inline bool JSValue::isGetterSetter() const
     {
         return isCell() && asCell()->isGetterSetter();

Modified: trunk/Source/_javascript_Core/runtime/JSValue.h (91163 => 91164)


--- trunk/Source/_javascript_Core/runtime/JSValue.h	2011-07-17 04:56:20 UTC (rev 91163)
+++ trunk/Source/_javascript_Core/runtime/JSValue.h	2011-07-17 05:04:36 UTC (rev 91164)
@@ -152,6 +152,7 @@
         bool isBoolean() const;
         bool isNumber() const;
         bool isString() const;
+        bool isPrimitive() const;
         bool isGetterSetter() const;
         bool isObject() const;
         bool inherits(const ClassInfo*) const;
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to