Source/JavaScriptCore: GetScopedVar should have value profiling
authorbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 23 Sep 2011 07:18:48 +0000 (07:18 +0000)
committerbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 23 Sep 2011 07:18:48 +0000 (07:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=68676

Patch by Filip Pizlo <fpizlo@apple.com> on 2011-09-22
Reviewed by Oliver Hunt.

Added GetScopedVar value profiling and predictin propagation.
Added GetScopeChain to CSE.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::predict):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasPrediction):
* dfg/DFGPropagator.cpp:
(JSC::DFG::Propagator::propagateNodePredictions):
(JSC::DFG::Propagator::getScopeChainLoadElimination):
(JSC::DFG::Propagator::performNodeCSE):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_scoped_var):

LayoutTests: [Qt] Unreviewed gardening, update expected file after r95745.

Patch by Csaba Osztrogonác <ossy@webkit.org> on 2011-09-22

* platform/qt/editing/deleting/merge-whitespace-pre-expected.png:
* platform/qt/editing/deleting/merge-whitespace-pre-expected.txt:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@95787 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/js/array-prototype-properties-expected.txt
LayoutTests/fast/js/script-tests/strict-callback-this.js [new file with mode: 0644]
LayoutTests/fast/js/strict-callback-this-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/strict-callback-this.html [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/ArrayPrototype.cpp
Source/JavaScriptCore/runtime/JSArray.cpp
Source/JavaScriptCore/runtime/StringPrototype.cpp

index eb4e9ee..d39fd6c 100644 (file)
 
 2011-09-22  Gavin Barraclough  <barraclough@apple.com>
 
+        Incorrect this value passed to callbacks.
+        https://bugs.webkit.org/show_bug.cgi?id=68668
+
+        Reviewed by Oliver Hunt.
+
+        From Array/String prototype function.  Should be undefined, but
+        global object is passed instead (this is visible for strict callbacks).
+
+        * fast/js/array-prototype-properties-expected.txt:
+        * fast/js/script-tests/strict-callback-this.js: Added.
+        (strictThrowThisString):
+        (nonstrictThrowThisString):
+        (testArrayPrototypeSort):
+        (testArrayPrototypeFilter):
+        (testArrayPrototypeMap):
+        (testArrayPrototypeEvery):
+        (testArrayPrototypeForEach):
+        (testArrayPrototypeSome):
+        (testStringPrototypeReplace):
+        * fast/js/strict-callback-this-expected.txt: Added.
+        * fast/js/strict-callback-this.html: Added.
+        * ietestcenter/Javascript/15.3.4.5-0-2-expected.txt:
+
+2011-09-22  Gavin Barraclough  <barraclough@apple.com>
+
         Function.prototype.bind.length shoudl be 1.
 
         Rubber stamped by Olier Hunt.
index 60e1448..8cc2c35 100644 (file)
@@ -23,7 +23,7 @@ PASS Array.prototype.indlastIndexOfexOf.call(undefined, 0) threw exception TypeE
 FAIL Array.prototype.filter.call(undefined, toString) should throw an exception. Was [object Object].
 FAIL Array.prototype.reduce.call(undefined, toString) should throw an exception. Was [object Object].
 FAIL Array.prototype.reduceRight.call(undefined, toString) should throw an exception. Was [object Object].
-FAIL Array.prototype.map.call(undefined, toString) should throw an exception. Was [object DOMWindow].
+FAIL Array.prototype.map.call(undefined, toString) should throw an exception. Was [object Undefined].
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/LayoutTests/fast/js/script-tests/strict-callback-this.js b/LayoutTests/fast/js/script-tests/strict-callback-this.js
new file mode 100644 (file)
index 0000000..7dbd1b0
--- /dev/null
@@ -0,0 +1,105 @@
+description(
+"This tests that a call to array/string prototype methods pass the correct this value (undefined) to strict callees."
+);
+
+var undefinedString = String(undefined);
+var globalObjectString = String(this);
+
+function strictThrowThisString()
+{
+    "use strict";
+    throw String(this);
+}
+
+function nonstrictThrowThisString()
+{
+    throw String(this);
+}
+
+function testArrayPrototypeSort(callback)
+{
+    try {
+        [1,2].sort(callback);
+    } catch (e) {
+        return e;
+    }
+    return "FAILED";
+}
+
+function testArrayPrototypeFilter(callback)
+{
+    try {
+        [1,2].filter(callback);
+    } catch (e) {
+        return e;
+    }
+    return "FAILED";
+}
+
+function testArrayPrototypeMap(callback)
+{
+    try {
+        [1,2].map(callback);
+    } catch (e) {
+        return e;
+    }
+    return "FAILED";
+}
+
+function testArrayPrototypeEvery(callback)
+{
+    try {
+        [1,2].every(callback);
+    } catch (e) {
+        return e;
+    }
+    return "FAILED";
+}
+
+function testArrayPrototypeForEach(callback)
+{
+    try {
+        [1,2].forEach(callback);
+    } catch (e) {
+        return e;
+    }
+    return "FAILED";
+}
+
+function testArrayPrototypeSome(callback)
+{
+    try {
+        [1,2].some(callback);
+    } catch (e) {
+        return e;
+    }
+    return "FAILED";
+}
+
+function testStringPrototypeReplace(callback)
+{
+    try {
+        "1,2".replace('1', callback);
+    } catch (e) {
+        return e;
+    }
+    return "FAILED";
+}
+
+shouldBe('testArrayPrototypeSort(strictThrowThisString)', 'undefinedString');
+shouldBe('testArrayPrototypeFilter(strictThrowThisString)', 'undefinedString');
+shouldBe('testArrayPrototypeMap(strictThrowThisString)', 'undefinedString');
+shouldBe('testArrayPrototypeEvery(strictThrowThisString)', 'undefinedString');
+shouldBe('testArrayPrototypeForEach(strictThrowThisString)', 'undefinedString');
+shouldBe('testArrayPrototypeSome(strictThrowThisString)', 'undefinedString');
+shouldBe('testStringPrototypeReplace(strictThrowThisString)', 'undefinedString');
+
+shouldBe('testArrayPrototypeSort(nonstrictThrowThisString)', 'globalObjectString');
+shouldBe('testArrayPrototypeFilter(nonstrictThrowThisString)', 'globalObjectString');
+shouldBe('testArrayPrototypeMap(nonstrictThrowThisString)', 'globalObjectString');
+shouldBe('testArrayPrototypeEvery(nonstrictThrowThisString)', 'globalObjectString');
+shouldBe('testArrayPrototypeForEach(nonstrictThrowThisString)', 'globalObjectString');
+shouldBe('testArrayPrototypeSome(nonstrictThrowThisString)', 'globalObjectString');
+shouldBe('testStringPrototypeReplace(nonstrictThrowThisString)', 'globalObjectString');
+
+var successfullyParsed = true;
diff --git a/LayoutTests/fast/js/strict-callback-this-expected.txt b/LayoutTests/fast/js/strict-callback-this-expected.txt
new file mode 100644 (file)
index 0000000..d27990c
--- /dev/null
@@ -0,0 +1,23 @@
+This tests that a call to array/string prototype methods pass the correct this value (undefined) to strict callees.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS testArrayPrototypeSort(strictThrowThisString) is undefinedString
+PASS testArrayPrototypeFilter(strictThrowThisString) is undefinedString
+PASS testArrayPrototypeMap(strictThrowThisString) is undefinedString
+PASS testArrayPrototypeEvery(strictThrowThisString) is undefinedString
+PASS testArrayPrototypeForEach(strictThrowThisString) is undefinedString
+PASS testArrayPrototypeSome(strictThrowThisString) is undefinedString
+PASS testStringPrototypeReplace(strictThrowThisString) is undefinedString
+PASS testArrayPrototypeSort(nonstrictThrowThisString) is globalObjectString
+PASS testArrayPrototypeFilter(nonstrictThrowThisString) is globalObjectString
+PASS testArrayPrototypeMap(nonstrictThrowThisString) is globalObjectString
+PASS testArrayPrototypeEvery(nonstrictThrowThisString) is globalObjectString
+PASS testArrayPrototypeForEach(nonstrictThrowThisString) is globalObjectString
+PASS testArrayPrototypeSome(nonstrictThrowThisString) is globalObjectString
+PASS testStringPrototypeReplace(nonstrictThrowThisString) is globalObjectString
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/strict-callback-this.html b/LayoutTests/fast/js/strict-callback-this.html
new file mode 100644 (file)
index 0000000..2c22a3c
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="resources/js-test-style.css">
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/strict-callback-this.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
index 3d5f6f9..f33f654 100644 (file)
 
 2011-09-22  Gavin Barraclough  <barraclough@apple.com>
 
+        Incorrect this value passed to callbacks.
+        https://bugs.webkit.org/show_bug.cgi?id=68668
+
+        Reviewed by Oliver Hunt.
+
+        From Array/String prototype function.  Should be undefined, but
+        global object is passed instead (this is visible for strict callbacks).
+
+        * runtime/ArrayPrototype.cpp:
+        (JSC::arrayProtoFuncSort):
+        (JSC::arrayProtoFuncFilter):
+        (JSC::arrayProtoFuncMap):
+        (JSC::arrayProtoFuncEvery):
+        (JSC::arrayProtoFuncForEach):
+        (JSC::arrayProtoFuncSome):
+        * runtime/JSArray.cpp:
+        (JSC::AVLTreeAbstractorForArrayCompare::compare_key_key):
+        (JSC::JSArray::sort):
+        * runtime/StringPrototype.cpp:
+        (JSC::stringProtoFuncReplace):
+
+2011-09-22  Gavin Barraclough  <barraclough@apple.com>
+
         Function.prototype.bind.length shoudl be 1.
 
         Rubber stamped by Olier Hunt.
index c7655d3..3b4b446 100644 (file)
@@ -543,7 +543,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
                 MarkedArgumentBuffer l;
                 l.append(jObj);
                 l.append(minObj);
-                compareResult = call(exec, function, callType, callData, exec->globalThisValue(), l).toNumber(exec);
+                compareResult = call(exec, function, callType, callData, jsUndefined(), l).toNumber(exec);
             } else
                 compareResult = (jObj.toString(exec) < minObj.toString(exec)) ? -1 : 1;
 
@@ -671,7 +671,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec)
     if (callType == CallTypeNone)
         return throwVMTypeError(exec);
 
-    JSObject* applyThis = exec->argument(1).isUndefinedOrNull() ? exec->globalThisValue() : exec->argument(1).toObject(exec);
+    JSValue applyThis = exec->argument(1);
     JSArray* resultArray = constructEmptyArray(exec);
 
     unsigned filterIndex = 0;
@@ -730,7 +730,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec)
     if (callType == CallTypeNone)
         return throwVMTypeError(exec);
 
-    JSObject* applyThis = exec->argument(1).isUndefinedOrNull() ? exec->globalThisValue() : exec->argument(1).toObject(exec);
+    JSValue applyThis = exec->argument(1);
 
     JSArray* resultArray = constructEmptyArray(exec, length);
     unsigned k = 0;
@@ -792,7 +792,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec)
     if (callType == CallTypeNone)
         return throwVMTypeError(exec);
 
-    JSObject* applyThis = exec->argument(1).isUndefinedOrNull() ? exec->globalThisValue() : exec->argument(1).toObject(exec);
+    JSValue applyThis = exec->argument(1);
 
     JSValue result = jsBoolean(true);
 
@@ -850,7 +850,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec)
     if (callType == CallTypeNone)
         return throwVMTypeError(exec);
 
-    JSObject* applyThis = exec->argument(1).isUndefinedOrNull() ? exec->globalThisValue() : exec->argument(1).toObject(exec);
+    JSValue applyThis = exec->argument(1);
 
     unsigned k = 0;
     if (callType == CallTypeJS && isJSArray(&exec->globalData(), thisObj)) {
@@ -900,7 +900,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec)
     if (callType == CallTypeNone)
         return throwVMTypeError(exec);
 
-    JSObject* applyThis = exec->argument(1).isUndefinedOrNull() ? exec->globalThisValue() : exec->argument(1).toObject(exec);
+    JSValue applyThis = exec->argument(1);
 
     JSValue result = jsBoolean(false);
 
index 4b0caa2..d7be946 100644 (file)
@@ -1016,7 +1016,6 @@ struct AVLTreeAbstractorForArrayCompare {
     JSValue m_compareFunction;
     CallType m_compareCallType;
     const CallData* m_compareCallData;
-    JSValue m_globalThisValue;
     OwnPtr<CachedCall> m_cachedCall;
 
     handle get_less(handle h) { return m_nodes[h].lt & 0x7FFFFFFF; }
@@ -1055,7 +1054,7 @@ struct AVLTreeAbstractorForArrayCompare {
 
         double compareResult;
         if (m_cachedCall) {
-            m_cachedCall->setThis(m_globalThisValue);
+            m_cachedCall->setThis(jsUndefined());
             m_cachedCall->setArgument(0, va);
             m_cachedCall->setArgument(1, vb);
             compareResult = m_cachedCall->call().toNumber(m_cachedCall->newCallFrame(m_exec));
@@ -1063,7 +1062,7 @@ struct AVLTreeAbstractorForArrayCompare {
             MarkedArgumentBuffer arguments;
             arguments.append(va);
             arguments.append(vb);
-            compareResult = call(m_exec, m_compareFunction, m_compareCallType, *m_compareCallData, m_globalThisValue, arguments).toNumber(m_exec);
+            compareResult = call(m_exec, m_compareFunction, m_compareCallType, *m_compareCallData, jsUndefined(), arguments).toNumber(m_exec);
         }
         return (compareResult < 0) ? -1 : 1; // Not passing equality through, because we need to store all values, even if equivalent.
     }
@@ -1099,7 +1098,6 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType,
     tree.abstractor().m_compareFunction = compareFunction;
     tree.abstractor().m_compareCallType = callType;
     tree.abstractor().m_compareCallData = &callData;
-    tree.abstractor().m_globalThisValue = exec->globalThisValue();
     tree.abstractor().m_nodes.grow(nodeCount);
 
     if (callType == CallTypeJS)
index 76db0c8..2281efb 100644 (file)
@@ -448,7 +448,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
                 cachedCall.setArgument(i++, jsNumber(completeMatchStart));
                 cachedCall.setArgument(i++, sourceVal);
 
-                cachedCall.setThis(exec->globalThisValue());
+                cachedCall.setThis(jsUndefined());
                 JSValue result = cachedCall.call();
                 if (LIKELY(result.isString()))
                     replacements.append(asString(result)->value(exec));
@@ -495,7 +495,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
                     args.append(jsNumber(completeMatchStart));
                     args.append(sourceVal);
 
-                    replacements.append(call(exec, replacement, callType, callData, exec->globalThisValue(), args).toString(exec));
+                    replacements.append(call(exec, replacement, callType, callData, jsUndefined(), args).toString(exec));
                     if (exec->hadException())
                         break;
                 } else {
@@ -551,7 +551,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
         args.append(jsNumber(matchPos));
         args.append(sourceVal);
 
-        replacementString = call(exec, replacement, callType, callData, exec->globalThisValue(), args).toString(exec);
+        replacementString = call(exec, replacement, callType, callData, jsUndefined(), args).toString(exec);
     }
     
     size_t matchEnd = matchPos + matchLen;