Diff
Modified: trunk/LayoutTests/ChangeLog (197814 => 197815)
--- trunk/LayoutTests/ChangeLog 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/LayoutTests/ChangeLog 2016-03-09 00:01:09 UTC (rev 197815)
@@ -1,3 +1,14 @@
+2016-03-08 Mark Lam <[email protected]>
+
+ Implement Function.name support for getters/setters and inferring name of function properties.
+ https://bugs.webkit.org/show_bug.cgi?id=154865
+
+ Reviewed by Geoffrey Garen.
+
+ * js/function-toString-vs-name-expected.txt: Added.
+ * js/function-toString-vs-name.html: Added.
+ * js/script-tests/function-toString-vs-name.js: Added.
+
2016-03-08 Myles C. Maxfield <[email protected]>
Font size computed style is innaccurate
Modified: trunk/LayoutTests/inspector/model/remote-object-get-properties-expected.txt (197814 => 197815)
--- trunk/LayoutTests/inspector/model/remote-object-get-properties-expected.txt 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/LayoutTests/inspector/model/remote-object-get-properties-expected.txt 2016-03-09 00:01:09 UTC (rev 197815)
@@ -220,7 +220,7 @@
-----------------------------------------------------
_expression_: window.boundFunction
type: function
-description: function () {
+description: function unboundFunction() {
[native code]
}
Added: trunk/LayoutTests/js/function-toString-vs-name-expected.txt (0 => 197815)
--- trunk/LayoutTests/js/function-toString-vs-name-expected.txt (rev 0)
+++ trunk/LayoutTests/js/function-toString-vs-name-expected.txt 2016-03-09 00:01:09 UTC (rev 197815)
@@ -0,0 +1,3 @@
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/js/function-toString-vs-name.html (0 => 197815)
--- trunk/LayoutTests/js/function-toString-vs-name.html (rev 0)
+++ trunk/LayoutTests/js/function-toString-vs-name.html 2016-03-09 00:01:09 UTC (rev 197815)
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/js/script-tests/function-toString-vs-name.js (0 => 197815)
--- trunk/LayoutTests/js/script-tests/function-toString-vs-name.js (rev 0)
+++ trunk/LayoutTests/js/script-tests/function-toString-vs-name.js 2016-03-09 00:01:09 UTC (rev 197815)
@@ -0,0 +1,419 @@
+// isWhiteSpace() and stripSpaces() are borrowed from
+// kde/script-tests/inbuilt_function_tostring.js and modified.
+
+let section;
+let failures = "";
+let failureCount = 0;
+
+function isWhiteSpace(string) {
+ let cc = string.charCodeAt(0);
+ switch (cc) {
+ case (0x0009):
+ case (0x000B):
+ case (0x000C):
+ case (0x0020):
+ case (0x000A):
+ case (0x000D):
+ case (59): // let's strip out semicolons, too
+ return true;
+ break;
+ default:
+ return false;
+ }
+}
+
+function minimizeSpaces(s) {
+ let currentChar;
+ let strippedString;
+ let previousCharIsWhiteSpace = false;
+ for (currentChar = 0, strippedString = ""; currentChar < s.length; currentChar++) {
+ let ch = s.charAt(currentChar);
+ if (!isWhiteSpace(ch)) {
+ if (previousCharIsWhiteSpace &&
+ (ch == '(' || ch == ')' || ch == '{' || ch == '}' || ch == '[' || ch == ']'))
+ strippedString = strippedString.slice(0, strippedString.length - 1);
+ strippedString += ch;
+ previousCharIsWhiteSpace = false;
+ } else if (!previousCharIsWhiteSpace) {
+ strippedString += ' ';
+ previousCharIsWhiteSpace = true;
+ }
+ }
+ return strippedString;
+}
+
+function shouldBe(desc, funcName, actual, expected) {
+ if (typeof(actual) !== typeof(expected)) {
+ failures += (" " + section + ": " + desc + "'" + funcName + "': typeof expected: " + typeof(expected) + ", typeof actual: " + typeof(actual) + "\n");
+ failures += (" expected: '" + expected + "', actual: '" + actual + "'\n");
+ failureCount++;
+ } else if (typeof(actual) !== typeof(expected) || actual !== expected) {
+ failures += (" " + section + ": " + desc + "'" + funcName + "': expected: '" + expected + "', actual: '" + actual + "'\n");
+ failureCount++;
+ }
+}
+
+function toString(x) {
+ if (typeof x === "symbol")
+ return x.toString();
+ return "" + x;
+}
+
+function test(func, expectedName, expectedToString) {
+ shouldBe("Function.name on ", expectedName, func.name, expectedName);
+
+ let str = func.toString();
+ shouldBe("Function#toString on ", expectedName, minimizeSpaces(str), minimizeSpaces(expectedToString));
+
+ let origDesc = Object.getOwnPropertyDescriptor(func, "name");
+ shouldBe("Function.name configurability of ", expectedName, origDesc.configurable, true);
+ shouldBe("Function.name writability of ", expectedName, origDesc.writable, false);
+ shouldBe("Function.name enumerability of ", expectedName, origDesc.enumerable, false);
+
+ // We should not be able to change Function.name while it is not writable.
+ let origFuncName = func.name;
+ let modifiedFuncName = "modified_" + toString(origFuncName);
+ func.name = modifiedFuncName;
+ shouldBe("Function.name (after attempted write) on ", expectedName, func.name, expectedName);
+
+ // We should be able to change Function.name after making it writable.
+ Object.defineProperty(func, "name", { writable: true });
+ let modifiedDesc = Object.getOwnPropertyDescriptor(func, "name");
+ shouldBe("Function.name writability (after made writable) of ", expectedName, modifiedDesc.writable, true);
+
+ func.name = modifiedFuncName;
+ shouldBe("Function.name (after attempted write again) on ", expectedName, func.name, modifiedFuncName);
+
+ // But the toString name should not have changed.
+ str = func.toString();
+ shouldBe("Function#toString (after attempted write) on ", expectedName, minimizeSpaces(str), minimizeSpaces(expectedToString));
+
+ // Put things back to the original state.
+ Object.defineProperty(func, "name", origDesc);
+}
+
+section = "builtin function";
+{
+ test(Array.prototype.every, "every", "function every() { [native code] }");
+ test(Array.prototype.forEach, "forEach", "function forEach() { [native code] }");
+ test(Array.prototype.some, "some", "function some() { [native code] }");
+
+ section = "bound builtin function";
+ {
+ let o = {}
+ let boundEvery = Array.prototype.every.bind(o);
+ test(boundEvery, "bound every", "function every() { [native code] }");
+ let boundForEach = Array.prototype.forEach.bind(o);
+ test(boundForEach, "bound forEach", "function forEach() { [native code] }");
+ }
+}
+
+section = "native function";
+{
+ test(Array.prototype.splice, "splice", "function splice() { [native code] }");
+ test(Array.prototype.unshift, "unshift", "function unshift() { [native code] }");
+ test(Array.prototype.indexOf, "indexOf", "function indexOf() { [native code] }");
+
+ section = "bound native function";
+ {
+ let o = {}
+ let boundSplice = Array.prototype.splice.bind(o);
+ test(boundSplice, "bound splice", "function splice() { [native code] }");
+ let boundUnshift = Array.prototype.unshift.bind(o);
+ test(boundUnshift, "bound unshift", "function unshift() { [native code] }");
+ }
+}
+
+section = "InternalFunction";
+{
+ test(Array, "Array", "function Array() { [native code] }");
+ test(Boolean, "Boolean", "function Boolean() { [native code] }");
+
+ section = "bound InternalFunction";
+ {
+ let o = {}
+ let boundArray = Array.bind(o);
+ test(boundArray, "bound Array", "function Array() { [native code] }");
+ let boundBoolean = Boolean.bind(o);
+ test(boundBoolean, "bound Boolean", "function Boolean() { [native code] }");
+ }
+}
+
+section = "JS function";
+{
+ function foo1() {}
+ test(foo1, "foo1", "function foo1() {}");
+
+ let foo2 = function() {}
+ test(foo2, "foo2", "function() {}");
+
+ let foo3 = (function() {
+ function goo3() {}
+ return goo3;
+ }) ();
+ test(foo3, "goo3", "function goo3() {}");
+
+ let foo4 = (function() {
+ return (function() {});
+ }) ();
+ test(foo4, "", "function() {}");
+
+ // Test functions in object properties.
+ section = "Object property";
+ let o = {
+ prop1: function() {},
+ prop2: function namedProp2() {}
+ };
+ test(o.prop1, "prop1", "function() {}");
+ test(o.prop2, "namedProp2", "function namedProp2() {}");
+
+ section = "bound JS function";
+ {
+ let o = {}
+ let boundFoo1 = foo1.bind(o);
+ test(boundFoo1, "bound foo1", "function foo1() { [native code] }");
+ let boundFoo2 = foo2.bind(o);
+ test(boundFoo2, "bound foo2", "function foo2() { [native code] }");
+ let boundFoo3 = foo3.bind(o);
+ test(boundFoo3, "bound goo3", "function goo3() { [native code] }");
+ let boundFoo4 = foo4.bind(o);
+ test(boundFoo4, "bound ", "function () { [native code] }");
+
+ test((function(){}).bind({}), "bound ", "function () { [native code] }");
+ }
+}
+
+section = "object shorthand method";
+{
+ let o = {
+ prop1() {},
+ prop2(x) {}
+ };
+ test(o.prop1, "prop1", "function prop1() {}");
+ test(o.prop2, "prop2", "function prop2(x) {}");
+
+ section = "bound object shorthand method";
+ {
+ let boundProp1 = o.prop1.bind(o);
+ test(boundProp1, "bound prop1", "function prop1() { [native code] }");
+ let boundProp2 = o.prop2.bind(o);
+ test(boundProp2, "bound prop2", "function prop2() { [native code] }");
+ }
+}
+
+// FIXME: Uncomment these when we've added support for Function.name of computed properties.
+// section = "Object computed string property";
+// {
+// let str1 = "foo";
+// let str2 = "";
+// let o = {
+// [str1]: function() {},
+// [str2]: function() {}
+// };
+// test(o[str1], "foo", "function() {}");
+// test(o[str2], "", "function() {}");
+// }
+//
+// let sym1 = Symbol("foo");
+// let sym2 = Symbol();
+
+// section = "Object computed symbol property";
+// {
+// let o = {
+// [sym1]: function() {},
+// [sym2]: function() {}
+// };
+// test(o[sym1], "[foo]", "function() {}");
+// test(o[sym2], "", "function() {}");
+// }
+
+// section = "Object computed symbol property with shorthand function";
+// {
+// let o = {
+// [sym1]() {},
+// [sym2]() {}
+// };
+// test(o[sym1], "[foo]", "function() {}");
+// test(o[sym2], "", "function() {}");
+// }
+
+// section = "Object computed symbol property with get/set function";
+// {
+// let o = {
+// get [sym1]() {},
+// set [sym1](x) {},
+// get [sym2]() {},
+// set [sym2](x) {}
+// };
+// let desc = Object.getOwnPropertyDescriptor(o, sym1);
+// test(desc.get, "get [foo]", "function() {}");
+// test(desc.set, "set [foo]", "function(x) {}");
+//
+// desc = Object.getOwnPropertyDescriptor(o, sym2);
+// test(desc.get, "get ", "function() {}");
+// test(desc.set, "set ", "function(x) {}");
+// }
+
+// Test functions in destructuring assignments.
+section = "destructuring assignment";
+{
+ let prop1;
+ let prop2;
+ { prop1 = function() {}, prop2 = function namedProp2() {} }
+ test(prop1, "prop1", "function() {}");
+ test(prop2, "namedProp2", "function namedProp2() {}");
+
+ section = "bound destructuring assignment";
+ {
+ let o = {}
+ let bound1 = prop1.bind(o);
+ test(bound1, "bound prop1", "function prop1() { [native code] }");
+
+ let bound2 = prop2.bind(o);
+ test(bound2, "bound namedProp2", "function namedProp2() { [native code] }");
+ }
+}
+
+section = "dynamically created function";
+{
+ let dynamic1 = new Function("");
+ test(dynamic1, "anonymous", "function anonymous() {}");
+
+ let dynamic2 = new Function("");
+ dynamic2.name = "Goo2";
+ test(dynamic2, "anonymous", "function anonymous() {}");
+
+ section = "bound dynamically created function";
+ {
+ let o = {}
+ let bound1 = dynamic1.bind(o);
+ test(bound1, "bound anonymous", "function anonymous() { [native code] }");
+
+ let bound2 = dynamic2.bind(o);
+ test(bound2, "bound anonymous", "function anonymous() { [native code] }");
+ }
+}
+
+section = "JSBoundSlotBaseFunction";
+{
+ if (typeof document !== "undefined") {
+ let desc = Object.getOwnPropertyDescriptor(document, "location");
+ test(desc.get, "get location", "function location() { [native code] }");
+ test(desc.set, "set location", "function location() { [native code] }");
+
+ section = "bound JSBoundSlotBaseFunction";
+ {
+ let o = {}
+ let bound1 = desc.get.bind(o);
+ test(bound1, "bound get location", "function get location() { [native code] }");
+
+ let bound2 = desc.set.bind(o);
+ test(bound2, "bound set location", "function set location() { [native code] }");
+ }
+ }
+}
+
+section = "get/set function";
+{
+ let o = { get foo() {}, set foo(x){} };
+ let desc = Object.getOwnPropertyDescriptor(o, "foo");
+ test(desc.get, "get foo", "function() {}");
+ test(desc.set, "set foo", "function(x) {}");
+
+ let o1 = { get "bar"() {}, set "bar"(x){} };
+ let desc1 = Object.getOwnPropertyDescriptor(o1, "bar");
+ test(desc1.get, "get bar", "function() {}");
+ test(desc1.set, "set bar", "function(x) {}");
+
+ let o2 = { get 100() {}, set 100(x){} };
+ let desc2 = Object.getOwnPropertyDescriptor(o2, 100);
+ test(desc2.get, "get ", "function() {}");
+ test(desc2.set, "set ", "function(x) {}");
+
+ let o3 = { get [100]() {}, set [100](x){} };
+ let desc3 = Object.getOwnPropertyDescriptor(o3, 100);
+ test(desc3.get, "get ", "function() {}");
+ test(desc3.set, "set ", "function(x) {}");
+
+ section = "bound get/set function";
+ {
+ let bound1;
+ let bound2;
+
+ bound1 = desc.get.bind(o);
+ test(bound1, "bound get foo", "function get foo() { [native code] }");
+ bound2 = desc.set.bind(o);
+ test(bound2, "bound set foo", "function set foo() { [native code] }");
+
+ bound1 = desc1.get.bind(o);
+ test(bound1, "bound get bar", "function get bar() { [native code] }");
+ bound2 = desc1.set.bind(o);
+ test(bound2, "bound set bar", "function set bar() { [native code] }");
+
+ bound1 = desc2.get.bind(o);
+ test(bound1, "bound get ", "function get () { [native code] }");
+ bound2 = desc2.set.bind(o);
+ test(bound2, "bound set ", "function set () { [native code] }");
+
+ bound1 = desc3.get.bind(o);
+ test(bound1, "bound get ", "function get () { [native code] }");
+ bound2 = desc3.set.bind(o);
+ test(bound2, "bound set ", "function set () { [native code] }");
+ }
+}
+
+// https://tc39.github.io/ecma262/#sec-function.prototype.bind
+// 9. Let targetName be ? Get(Target, "name").
+// 10. If Type(targetName) is not String, let targetName be the empty string.
+// 11. Perform SetFunctionName(F, targetName, "bound").
+section = "bound functions with non-string names";
+{
+ let foo = function() {};
+ let bound;
+
+ function setName(func, newName) {
+ Object.defineProperty(func, "name", { writable:true });
+ func.name = newName;
+ Object.defineProperty(func, "name", { writable:false });
+ }
+
+ setName(foo, undefined);
+ test(foo, undefined, "function() {}");
+ bound = foo.bind({});
+ test(bound, "bound ", "function () { [native code] }");
+
+ setName(foo, null);
+ test(foo, null, "function() {}");
+ bound = foo.bind({});
+ test(bound, "bound ", "function () { [native code] }");
+
+ setName(foo, true);
+ test(foo, true, "function() {}");
+ bound = foo.bind({});
+ test(bound, "bound ", "function () { [native code] }");
+
+ setName(foo, false);
+ test(foo, false, "function() {}");
+ bound = foo.bind({});
+ test(bound, "bound ", "function () { [native code] }");
+
+ setName(foo, 1234.567);
+ test(foo, 1234.567, "function() {}");
+ bound = foo.bind({});
+ test(bound, "bound ", "function () { [native code] }");
+
+ let anonSym = Symbol();
+ setName(foo, anonSym);
+ test(foo, anonSym, "function() {}");
+ bound = foo.bind({});
+ test(bound, "bound ", "function () { [native code] }");
+
+ let sym = Symbol("baz");
+ setName(foo, sym);
+ test(foo, sym, "function() {}");
+ bound = foo.bind({});
+ test(bound, "bound ", "function () { [native code] }");
+}
+
+if (failureCount)
+ throw Error("Found " + failureCount + " failures:\n" + failures);
Modified: trunk/LayoutTests/platform/mac/http/tests/media/media-source/SourceBuffer-abort-readyState-expected.txt (197814 => 197815)
--- trunk/LayoutTests/platform/mac/http/tests/media/media-source/SourceBuffer-abort-readyState-expected.txt 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/LayoutTests/platform/mac/http/tests/media/media-source/SourceBuffer-abort-readyState-expected.txt 2016-03-09 00:01:09 UTC (rev 197815)
@@ -4,7 +4,7 @@
http://127.0.0.1:8000/media/media-source/SourceBuffer-abort-readyState.html:20:29
step@http://127.0.0.1:8000/w3c/resources/testharness.js:1160:30
isTypeSupported@http://127.0.0.1:8000/media/media-source/SourceBuffer-abort-readyState.html:19:18
-bound isTypeSupported@[native code]
+isTypeSupported@[native code]
http://127.0.0.1:8000/media/media-source/SourceBuffer-abort-readyState.html:42:36
step@http://127.0.0.1:8000/w3c/resources/testharness.js:1160:30
async_test@http://127.0.0.1:8000/w3c/resources/testharness.js:460:26
Modified: trunk/LayoutTests/platform/mac/http/tests/media/media-source/SourceBuffer-abort-removed-expected.txt (197814 => 197815)
--- trunk/LayoutTests/platform/mac/http/tests/media/media-source/SourceBuffer-abort-removed-expected.txt 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/LayoutTests/platform/mac/http/tests/media/media-source/SourceBuffer-abort-removed-expected.txt 2016-03-09 00:01:09 UTC (rev 197815)
@@ -4,7 +4,7 @@
http://127.0.0.1:8000/media/media-source/SourceBuffer-abort-removed.html:19:29
step@http://127.0.0.1:8000/w3c/resources/testharness.js:1160:30
isTypeSupported@http://127.0.0.1:8000/media/media-source/SourceBuffer-abort-removed.html:18:18
-bound isTypeSupported@[native code]
+isTypeSupported@[native code]
http://127.0.0.1:8000/media/media-source/SourceBuffer-abort-removed.html:28:36
step@http://127.0.0.1:8000/w3c/resources/testharness.js:1160:30
async_test@http://127.0.0.1:8000/w3c/resources/testharness.js:460:26
Modified: trunk/LayoutTests/platform/mac/http/tests/media/media-source/SourceBuffer-abort-updating-expected.txt (197814 => 197815)
--- trunk/LayoutTests/platform/mac/http/tests/media/media-source/SourceBuffer-abort-updating-expected.txt 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/LayoutTests/platform/mac/http/tests/media/media-source/SourceBuffer-abort-updating-expected.txt 2016-03-09 00:01:09 UTC (rev 197815)
@@ -4,7 +4,7 @@
http://127.0.0.1:8000/media/media-source/SourceBuffer-abort-updating.html:33:29
step@http://127.0.0.1:8000/w3c/resources/testharness.js:1160:30
isTypeSupported@http://127.0.0.1:8000/media/media-source/SourceBuffer-abort-updating.html:32:18
-bound isTypeSupported@[native code]
+isTypeSupported@[native code]
http://127.0.0.1:8000/media/media-source/SourceBuffer-abort-updating.html:42:36
step@http://127.0.0.1:8000/w3c/resources/testharness.js:1160:30
async_test@http://127.0.0.1:8000/w3c/resources/testharness.js:460:26
Modified: trunk/LayoutTests/platform/mac/http/tests/media/media-source/mediasource-sourcebuffer-mode-expected.txt (197814 => 197815)
--- trunk/LayoutTests/platform/mac/http/tests/media/media-source/mediasource-sourcebuffer-mode-expected.txt 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/LayoutTests/platform/mac/http/tests/media/media-source/mediasource-sourcebuffer-mode-expected.txt 2016-03-09 00:01:09 UTC (rev 197815)
@@ -8,7 +8,7 @@
assert_throws@http://127.0.0.1:8000/w3c/resources/testharness.js:947:19
http://127.0.0.1:8000/media/media-source/mediasource-sourcebuffer-mode.html:114:32
handleWaitCallback_@http://127.0.0.1:8000/media/media-source/mediasource-util.js:97:17
-bound @[native code]
+handleWaitCallback_@[native code]
step@http://127.0.0.1:8000/w3c/resources/testharness.js:1160:30
http://127.0.0.1:8000/w3c/resources/testharness.js:1189:33)
Modified: trunk/Source/_javascript_Core/ChangeLog (197814 => 197815)
--- trunk/Source/_javascript_Core/ChangeLog 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-03-09 00:01:09 UTC (rev 197815)
@@ -1,3 +1,92 @@
+2016-03-08 Mark Lam <[email protected]>
+
+ Implement Function.name support for getters/setters and inferring name of function properties.
+ https://bugs.webkit.org/show_bug.cgi?id=154865
+
+ Reviewed by Geoffrey Garen.
+
+ 1. toString() no longer uses the value of Function.name as the name of the
+ function in the returned string, because ...
+
+ i. Function.name is supposed to be configurable. Hence, it can be made
+ writable and can be set to any JSValue, or deleted.
+ ii. Function.prototype.toString() is supposed to produce a string that can be
+ eval'ed. Hence, for JS functions, the function name in the produced
+ string must be a legal function name (and not some arbitrary value set in
+ Function.name). For example, while a number is a legal value for
+ Function.name, it is not legal as the function name in the toString()
+ string.
+
+ Instead, we'll always use the original name from the JS source that the
+ function was parsed from.
+
+ 2. JSFunction::name() now always return the original name, not the value of
+ the Function.name property. As a result, it also no longer needs an
+ ExecState* arg.
+
+ If the original name is an empty string, JSFunction::name() will use the
+ inferred name.
+
+ 3. For JS functions, the original name can be attained from their
+ FunctionExecutable object.
+
+ For host/native functions (which do not have a FunctionExecutable), we get the
+ "original" name from its NativeExecutable.
+
+ 4. The m_hostFunctionStubMap now keys its NativeExecutable pointers using the
+ original name, in addition to the native function and constructor pointers.
+
+ This is needed because we want a different NativeExecutable for functions with
+ a different name (to satisfy (3) above).
+
+ 5. Changed JSBoundFunction to store the name of its bound function in its
+ NativeExecutable. This will later be used to generate the toString() string.
+ It's Function.name value is eagerly initialized at construction time.
+
+ 6. Function.name for getters/setters are now prefixed with "get"/"set".
+ This was done both for the JSBoundSlotBaseFunctions and JS definable get/set
+ functions.
+
+ 7. Added InternalFunction::m_originalName so that we can use it to generate the
+ toString() string. We're storing it as a JSString instead of a WTF::String
+ only because we want InternalFunction to be continue to be trivially
+ destructible.
+
+ * inspector/JSInjectedScriptHost.cpp:
+ (Inspector::JSInjectedScriptHost::functionDetails):
+ * jit/JITThunks.cpp:
+ (JSC::JITThunks::finalize):
+ (JSC::JITThunks::hostFunctionStub):
+ * jit/JITThunks.h:
+ * runtime/Executable.h:
+ * runtime/FunctionPrototype.cpp:
+ (JSC::functionProtoFuncToString):
+ * runtime/InternalFunction.cpp:
+ (JSC::InternalFunction::finishCreation):
+ (JSC::InternalFunction::visitChildren):
+ (JSC::InternalFunction::name):
+ (JSC::InternalFunction::displayName):
+ * runtime/InternalFunction.h:
+ * runtime/JSBoundFunction.cpp:
+ (JSC::JSBoundFunction::create):
+ (JSC::JSBoundFunction::visitChildren):
+ (JSC::JSBoundFunction::toStringName): Deleted.
+ * runtime/JSBoundFunction.h:
+ (JSC::JSBoundFunction::boundThis):
+ (JSC::JSBoundFunction::boundArgs):
+ (JSC::JSBoundFunction::createStructure):
+ * runtime/JSBoundSlotBaseFunction.cpp:
+ (JSC::boundSlotBaseFunctionCall):
+ (JSC::JSBoundSlotBaseFunction::create):
+ * runtime/JSFunction.cpp:
+ (JSC::JSFunction::initializeRareData):
+ (JSC::JSFunction::name):
+ (JSC::JSFunction::displayName):
+ (JSC::JSFunction::calculatedDisplayName):
+ (JSC::JSFunction::reifyName):
+ * runtime/JSFunction.h:
+ * tests/es6.yaml:
+
2016-03-08 Commit Queue <[email protected]>
Unreviewed, rolling out r197793 and r197799.
Modified: trunk/Source/_javascript_Core/inspector/JSInjectedScriptHost.cpp (197814 => 197815)
--- trunk/Source/_javascript_Core/inspector/JSInjectedScriptHost.cpp 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/Source/_javascript_Core/inspector/JSInjectedScriptHost.cpp 2016-03-09 00:01:09 UTC (rev 197815)
@@ -203,7 +203,7 @@
JSObject* result = constructEmptyObject(exec);
result->putDirect(exec->vm(), Identifier::fromString(exec, "location"), location);
- String name = function->name(exec);
+ String name = function->name();
if (!name.isEmpty())
result->putDirect(exec->vm(), Identifier::fromString(exec, "name"), jsString(exec, name));
Modified: trunk/Source/_javascript_Core/jit/JITThunks.cpp (197814 => 197815)
--- trunk/Source/_javascript_Core/jit/JITThunks.cpp 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/Source/_javascript_Core/jit/JITThunks.cpp 2016-03-09 00:01:09 UTC (rev 197815)
@@ -79,14 +79,14 @@
void JITThunks::finalize(Handle<Unknown> handle, void*)
{
auto* nativeExecutable = jsCast<NativeExecutable*>(handle.get().asCell());
- weakRemove(*m_hostFunctionStubMap, std::make_pair(nativeExecutable->function(), nativeExecutable->constructor()), nativeExecutable);
+ weakRemove(*m_hostFunctionStubMap, std::make_tuple(nativeExecutable->function(), nativeExecutable->constructor(), nativeExecutable->name()), nativeExecutable);
}
NativeExecutable* JITThunks::hostFunctionStub(VM* vm, NativeFunction function, NativeFunction constructor, const String& name)
{
ASSERT(!isCompilationThread());
- if (NativeExecutable* nativeExecutable = m_hostFunctionStubMap->get(std::make_pair(function, constructor)))
+ if (NativeExecutable* nativeExecutable = m_hostFunctionStubMap->get(std::make_tuple(function, constructor, name)))
return nativeExecutable;
NativeExecutable* nativeExecutable = NativeExecutable::create(
@@ -95,7 +95,7 @@
function,
adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct(vm)), JITCode::HostCallThunk)),
constructor, NoIntrinsic, name);
- weakAdd(*m_hostFunctionStubMap, std::make_pair(function, constructor), Weak<NativeExecutable>(nativeExecutable, this));
+ weakAdd(*m_hostFunctionStubMap, std::make_tuple(function, constructor, name), Weak<NativeExecutable>(nativeExecutable, this));
return nativeExecutable;
}
@@ -104,7 +104,7 @@
ASSERT(!isCompilationThread());
ASSERT(vm->canUseJIT());
- if (NativeExecutable* nativeExecutable = m_hostFunctionStubMap->get(std::make_pair(function, &callHostFunctionAsConstructor)))
+ if (NativeExecutable* nativeExecutable = m_hostFunctionStubMap->get(std::make_tuple(function, &callHostFunctionAsConstructor, name)))
return nativeExecutable;
RefPtr<JITCode> forCall;
@@ -117,7 +117,7 @@
RefPtr<JITCode> forConstruct = adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct(vm)), JITCode::HostCallThunk));
NativeExecutable* nativeExecutable = NativeExecutable::create(*vm, forCall, function, forConstruct, callHostFunctionAsConstructor, intrinsic, name);
- weakAdd(*m_hostFunctionStubMap, std::make_pair(function, &callHostFunctionAsConstructor), Weak<NativeExecutable>(nativeExecutable, this));
+ weakAdd(*m_hostFunctionStubMap, std::make_tuple(function, &callHostFunctionAsConstructor, name), Weak<NativeExecutable>(nativeExecutable, this));
return nativeExecutable;
}
Modified: trunk/Source/_javascript_Core/jit/JITThunks.h (197814 => 197815)
--- trunk/Source/_javascript_Core/jit/JITThunks.h 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/Source/_javascript_Core/jit/JITThunks.h 2016-03-09 00:01:09 UTC (rev 197815)
@@ -36,6 +36,7 @@
#include "Weak.h"
#include "WeakHandleOwner.h"
#include "WeakInlines.h"
+#include <tuple>
#include <wtf/HashMap.h>
#include <wtf/RefPtr.h>
#include <wtf/ThreadingPrimitives.h>
@@ -67,7 +68,39 @@
typedef HashMap<ThunkGenerator, MacroAssemblerCodeRef> CTIStubMap;
CTIStubMap m_ctiStubMap;
- typedef HashMap<std::pair<NativeFunction, NativeFunction>, Weak<NativeExecutable>> HostFunctionStubMap;
+
+ typedef std::tuple<NativeFunction, NativeFunction, String> HostFunctionKey;
+
+ struct HostFunctionHash {
+ static unsigned hash(const HostFunctionKey& key)
+ {
+ unsigned hash = WTF::pairIntHash(hashPointer(std::get<0>(key)), hashPointer(std::get<1>(key)));
+ if (!std::get<2>(key).isNull())
+ hash = WTF::pairIntHash(hash, DefaultHash<String>::Hash::hash(std::get<2>(key)));
+ return hash;
+ }
+ static bool equal(const HostFunctionKey& a, const HostFunctionKey& b)
+ {
+ return (std::get<0>(a) == std::get<0>(b)) && (std::get<1>(a) == std::get<1>(b)) && (std::get<2>(a) == std::get<2>(b));
+ }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+
+ private:
+ static inline unsigned hashPointer(NativeFunction p)
+ {
+ return DefaultHash<NativeFunction>::Hash::hash(p);
+ }
+ };
+
+ struct HostFunctionHashTrait : WTF::GenericHashTraits<HostFunctionKey> {
+ static const bool emptyValueIsZero = true;
+ static EmptyValueType emptyValue() { return std::make_tuple(nullptr, nullptr, String()); }
+
+ static void constructDeletedValue(HostFunctionKey& slot) { std::get<0>(slot) = reinterpret_cast<NativeFunction>(-1); }
+ static bool isDeletedValue(const HostFunctionKey& value) { return std::get<0>(value) == reinterpret_cast<NativeFunction>(-1); }
+ };
+
+ typedef HashMap<HostFunctionKey, Weak<NativeExecutable>, HostFunctionHash, HostFunctionHashTrait> HostFunctionStubMap;
std::unique_ptr<HostFunctionStubMap> m_hostFunctionStubMap;
Lock m_lock;
};
Modified: trunk/Source/_javascript_Core/runtime/Executable.h (197814 => 197815)
--- trunk/Source/_javascript_Core/runtime/Executable.h 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/Source/_javascript_Core/runtime/Executable.h 2016-03-09 00:01:09 UTC (rev 197815)
@@ -663,10 +663,15 @@
bool isBuiltinFunction() const { return m_unlinkedExecutable->isBuiltinFunction(); }
ConstructAbility constructAbility() const { return m_unlinkedExecutable->constructAbility(); }
bool isArrowFunction() const { return parseMode() == SourceParseMode::ArrowFunctionMode; }
+ bool isGetter() const { return parseMode() == SourceParseMode::GetterMode; }
+ bool isSetter() const { return parseMode() == SourceParseMode::SetterMode; }
DerivedContextType derivedContextType() const { return m_unlinkedExecutable->derivedContextType(); }
bool isClassConstructorFunction() const { return m_unlinkedExecutable->isClassConstructorFunction(); }
const Identifier& name() { return m_unlinkedExecutable->name(); }
const Identifier& inferredName() { return m_unlinkedExecutable->inferredName(); }
+ // FIXME: ecmaName() needs to be reimplement to be based on ES6 rules of determining the inferred
+ // Function.name from non-computed names. https://bugs.webkit.org/show_bug.cgi?id=155203
+ const Identifier& ecmaName() { return inferredName(); }
size_t parameterCount() const { return m_unlinkedExecutable->parameterCount(); } // Excluding 'this'!
SourceParseMode parseMode() const { return m_unlinkedExecutable->parseMode(); }
Modified: trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp (197814 => 197815)
--- trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp 2016-03-09 00:01:09 UTC (rev 197815)
@@ -85,14 +85,8 @@
JSValue thisValue = exec->thisValue();
if (thisValue.inherits(JSFunction::info())) {
JSFunction* function = jsCast<JSFunction*>(thisValue);
- if (function->isHostOrBuiltinFunction()) {
- String name;
- if (JSBoundFunction* boundFunction = jsDynamicCast<JSBoundFunction*>(function))
- name = boundFunction->toStringName(exec);
- else
- name = function->name(exec);
- return JSValue::encode(jsMakeNontrivialString(exec, "function ", name, "() {\n [native code]\n}"));
- }
+ if (function->isHostOrBuiltinFunction())
+ return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(), "() {\n [native code]\n}"));
FunctionExecutable* executable = function->jsExecutable();
@@ -101,7 +95,7 @@
StringView source = executable->source().provider()->getRange(
executable->parametersStartOffset(),
executable->parametersStartOffset() + executable->source().length());
- return JSValue::encode(jsMakeNontrivialString(exec, functionHeader, function->name(exec), source));
+ return JSValue::encode(jsMakeNontrivialString(exec, functionHeader, function->name(), source));
}
if (thisValue.inherits(InternalFunction::info())) {
@@ -167,7 +161,8 @@
}
}
- JSString* name = target.get(exec, exec->propertyNames().name).toString(exec);
+ JSValue nameProp = target.get(exec, exec->propertyNames().name);
+ JSString* name = nameProp.isString() ? nameProp.toString(exec) : jsEmptyString(exec);
return JSValue::encode(JSBoundFunction::create(vm, exec, globalObject, targetObject, exec->argument(0), boundArgs, length, name->value(exec)));
}
Modified: trunk/Source/_javascript_Core/runtime/InternalFunction.cpp (197814 => 197815)
--- trunk/Source/_javascript_Core/runtime/InternalFunction.cpp 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/Source/_javascript_Core/runtime/InternalFunction.cpp 2016-03-09 00:01:09 UTC (rev 197815)
@@ -44,14 +44,27 @@
Base::finishCreation(vm);
ASSERT(inherits(info()));
ASSERT(methodTable()->getCallData != InternalFunction::info()->methodTable.getCallData);
- putDirect(vm, vm.propertyNames->name, jsString(&vm, name), DontDelete | ReadOnly | DontEnum);
+ JSString* nameString = jsString(&vm, name);
+ m_originalName.set(vm, this, nameString);
+ putDirect(vm, vm.propertyNames->name, nameString, ReadOnly | DontEnum);
}
-const String& InternalFunction::name(ExecState* exec)
+void InternalFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
- return asString(getDirect(exec->vm(), exec->vm().propertyNames->name))->tryGetValue();
+ InternalFunction* thisObject = jsCast<InternalFunction*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(&thisObject->m_originalName);
}
+const String& InternalFunction::name(ExecState*)
+{
+ const String& name = m_originalName->tryGetValue();
+ ASSERT(name); // m_originalName was built from a String, and hence, there is no rope to resolve.
+ return name;
+}
+
const String InternalFunction::displayName(ExecState* exec)
{
JSValue displayName = getDirect(exec->vm(), exec->vm().propertyNames->displayName);
Modified: trunk/Source/_javascript_Core/runtime/InternalFunction.h (197814 => 197815)
--- trunk/Source/_javascript_Core/runtime/InternalFunction.h 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/Source/_javascript_Core/runtime/InternalFunction.h 2016-03-09 00:01:09 UTC (rev 197815)
@@ -38,6 +38,8 @@
DECLARE_EXPORT_INFO;
+ JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
+
JS_EXPORT_PRIVATE const String& name(ExecState*);
const String displayName(ExecState*);
const String calculatedDisplayName(ExecState*);
@@ -55,6 +57,7 @@
JS_EXPORT_PRIVATE void finishCreation(VM&, const String& name);
static CallType getCallData(JSCell*, CallData&);
+ WriteBarrier<JSString> m_originalName;
};
InternalFunction* asInternalFunction(JSValue);
Modified: trunk/Source/_javascript_Core/runtime/JSBoundFunction.cpp (197814 => 197815)
--- trunk/Source/_javascript_Core/runtime/JSBoundFunction.cpp 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/Source/_javascript_Core/runtime/JSBoundFunction.cpp 2016-03-09 00:01:09 UTC (rev 197815)
@@ -124,7 +124,7 @@
ConstructData constructData;
ConstructType constructType = JSC::getConstructData(targetFunction, constructData);
bool canConstruct = constructType != ConstructType::None;
- NativeExecutable* executable = vm.getHostFunction(boundFunctionCall, canConstruct ? boundFunctionConstruct : callHostFunctionAsConstructor, ASCIILiteral("Function.prototype.bind result"));
+ NativeExecutable* executable = vm.getHostFunction(boundFunctionCall, canConstruct ? boundFunctionConstruct : callHostFunctionAsConstructor, name);
Structure* structure = getBoundFunctionStructure(vm, exec, globalObject, targetFunction);
if (UNLIKELY(vm.exception()))
return nullptr;
@@ -167,9 +167,4 @@
visitor.append(&thisObject->m_boundArgs);
}
-String JSBoundFunction::toStringName(ExecState* exec)
-{
- return m_targetFunction->get(exec, exec->vm().propertyNames->name).toWTFString(exec);
-}
-
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/JSBoundFunction.h (197814 => 197815)
--- trunk/Source/_javascript_Core/runtime/JSBoundFunction.h 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/Source/_javascript_Core/runtime/JSBoundFunction.h 2016-03-09 00:01:09 UTC (rev 197815)
@@ -40,7 +40,7 @@
typedef JSFunction Base;
const static unsigned StructureFlags = ~ImplementsDefaultHasInstance & Base::StructureFlags;
- static JSBoundFunction* create(VM&, ExecState*, JSGlobalObject*, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs, int, const String&);
+ static JSBoundFunction* create(VM&, ExecState*, JSGlobalObject*, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs, int, const String& name);
static bool customHasInstance(JSObject*, ExecState*, JSValue);
@@ -48,9 +48,7 @@
JSValue boundThis() { return m_boundThis.get(); }
JSValue boundArgs() { return m_boundArgs.get(); }
- String toStringName(ExecState*);
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
ASSERT(globalObject);
return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
@@ -64,7 +62,7 @@
private:
JSBoundFunction(VM&, JSGlobalObject*, Structure*, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs);
- void finishCreation(VM&, NativeExecutable*, int, const String&);
+ void finishCreation(VM&, NativeExecutable*, int length, const String& name);
WriteBarrier<JSObject> m_targetFunction;
WriteBarrier<Unknown> m_boundThis;
Modified: trunk/Source/_javascript_Core/runtime/JSBoundSlotBaseFunction.cpp (197814 => 197815)
--- trunk/Source/_javascript_Core/runtime/JSBoundSlotBaseFunction.cpp 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/Source/_javascript_Core/runtime/JSBoundSlotBaseFunction.cpp 2016-03-09 00:01:09 UTC (rev 197815)
@@ -50,7 +50,7 @@
if (!getter)
return JSValue::encode(jsUndefined());
- const String& name = boundSlotBaseFunction->name(exec);
+ const String& name = boundSlotBaseFunction->name();
return getter(exec, JSValue::encode(exec->thisValue()), PropertyName(Identifier::fromString(exec, name)));
}
@@ -67,7 +67,8 @@
JSBoundSlotBaseFunction* function = new (NotNull, allocateCell<JSBoundSlotBaseFunction>(vm.heap)) JSBoundSlotBaseFunction(vm, globalObject, globalObject->boundSlotBaseFunctionStructure(), type);
// Can't do this during initialization because getHostFunction might do a GC allocation.
- function->finishCreation(vm, executable, boundSlotBase, getterSetter, name);
+ String prefix = (type == Type::Getter) ? "get " : "set ";
+ function->finishCreation(vm, executable, boundSlotBase, getterSetter, makeString(prefix, name));
return function;
}
Modified: trunk/Source/_javascript_Core/runtime/JSCJSValue.cpp (197814 => 197815)
--- trunk/Source/_javascript_Core/runtime/JSCJSValue.cpp 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/Source/_javascript_Core/runtime/JSCJSValue.cpp 2016-03-09 00:01:09 UTC (rev 197815)
@@ -207,6 +207,7 @@
if (prototype->attemptToInterceptPutByIndexOnHoleForPrototype(exec, *this, propertyName, value, shouldThrow))
return;
+ if (shouldThrow && !exec->hadException())
if (shouldThrow)
throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
}
Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (197814 => 197815)
--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp 2016-03-09 00:01:09 UTC (rev 197815)
@@ -177,9 +177,13 @@
return m_rareData.get();
}
-String JSFunction::name(ExecState* exec)
+String JSFunction::name()
{
- return get(exec, exec->vm().propertyNames->name).toWTFString(exec);
+ if (isHostFunction()) {
+ NativeExecutable* executable = jsCast<NativeExecutable*>(this->executable());
+ return executable->name();
+ }
+ return jsExecutable()->name().string();
}
String JSFunction::displayName(ExecState* exec)
@@ -199,7 +203,7 @@
if (!explicitName.isEmpty())
return explicitName;
- const String actualName = name(exec);
+ const String actualName = name();
if (!actualName.isEmpty() || isHostOrBuiltinFunction())
return actualName;
@@ -589,9 +593,19 @@
ASSERT(!hasReifiedName());
ASSERT(!isHostFunction());
unsigned initialAttributes = DontEnum | ReadOnly;
- const Identifier& identifier = exec->propertyNames().name;
- putDirect(vm, identifier, jsString(exec, jsExecutable()->name().string()), initialAttributes);
+ const Identifier& propID = exec->propertyNames().name;
+ const Identifier& nameID = jsExecutable()->name();
+ String name = nameID.string();
+ if (name.isEmpty())
+ name = jsExecutable()->ecmaName().string();
+
+ if (jsExecutable()->isGetter())
+ name = makeString("get ", name);
+ else if (jsExecutable()->isSetter())
+ name = makeString("set ", name);
+
+ putDirect(vm, propID, jsString(exec, name), initialAttributes);
rareData->setHasReifiedName();
}
Modified: trunk/Source/_javascript_Core/runtime/JSFunction.h (197814 => 197815)
--- trunk/Source/_javascript_Core/runtime/JSFunction.h 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.h 2016-03-09 00:01:09 UTC (rev 197815)
@@ -81,7 +81,7 @@
JS_EXPORT_PRIVATE static JSFunction* createBuiltinFunction(VM&, FunctionExecutable*, JSGlobalObject*);
static JSFunction* createBuiltinFunction(VM&, FunctionExecutable*, JSGlobalObject*, const String& name);
- JS_EXPORT_PRIVATE String name(ExecState*);
+ JS_EXPORT_PRIVATE String name();
JS_EXPORT_PRIVATE String displayName(ExecState*);
const String calculatedDisplayName(ExecState*);
Modified: trunk/Source/_javascript_Core/tests/es6.yaml (197814 => 197815)
--- trunk/Source/_javascript_Core/tests/es6.yaml 2016-03-08 23:59:18 UTC (rev 197814)
+++ trunk/Source/_javascript_Core/tests/es6.yaml 2016-03-09 00:01:09 UTC (rev 197815)
@@ -791,7 +791,7 @@
- path: es6/Function_is_subclassable_Function.prototype.call.js
cmd: runES6 :normal
- path: es6/function_name_property_accessor_properties.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/function_name_property_bound_functions.js
cmd: runES6 :normal
- path: es6/function_name_property_class_expressions.js
@@ -811,7 +811,7 @@
- path: es6/function_name_property_variables_class.js
cmd: runES6 :fail
- path: es6/function_name_property_variables_function.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/generators_%GeneratorPrototype%.constructor.js
cmd: runES6 :normal
- path: es6/generators_%GeneratorPrototype%.js