Skip to content

Commit d1e50e3

Browse files
committed
Introduce OpIsCallable bytecode and intrinsic
https://bugs.webkit.org/show_bug.cgi?id=215572 Reviewed by Ross Kirsling and Saam Barati. JSTests: * stress/type-of-functions-and-objects.js: * test262/expectations.yaml: Mark 2 test cases as passing. Source/JavaScriptCore: This patch: 1. Aligns slow_path_is_function with DFG/FTL implementations by introducing jsTypeofIsFunction() helper. This fixes `typeof document.all === "function"` to return `false` instead of `true`. 2. Renames is_function bytecode op to typeof_is_function, aligning it with typeof_is_undefined and typeof_is_object. New name offers better semantics and clearly communicates the op should be avoided when implementing new features because of `typeof` behavior with [[IsHTMLDDA]] objects [1]. 3. Adds is_callable bytecode op and utilizes it in built-ins via intrinsic, removing `typeof callback === "function"` checks. This prevents [[IsHTMLDDA]] objects from being considered non-callable [2]. To preserve the fast path for JSFunctionType, createFunctionThatMasqueradesAsUndefined() is relocated to InternalFunction. `typeof` microbenchmarks are neutral. [1]: https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot-typeof [2]: https://tc39.es/ecma262/#sec-array.prototype.map (step 3) * builtins/ArrayConstructor.js: * builtins/ArrayPrototype.js: (reduce): (reduceRight): (every): (forEach): (filter): (map): (some): (find): (findIndex): (sort): (flatMap): * builtins/FunctionPrototype.js: (overriddenName.string_appeared_here.symbolHasInstance): (bind): * builtins/MapPrototype.js: (forEach): * builtins/PromiseConstructor.js: (all): (allSettled): (any): (race): (nakedConstructor.Promise): (nakedConstructor.InternalPromise): * builtins/PromiseOperations.js: (globalPrivate.newPromiseCapabilitySlow): (globalPrivate.resolvePromise): (globalPrivate.resolveWithoutPromise): * builtins/PromisePrototype.js: (finally): (globalPrivate.getThenFinally): (globalPrivate.getCatchFinally): * builtins/ReflectObject.js: (apply): * builtins/RegExpPrototype.js: (globalPrivate.regExpExec): (overriddenName.string_appeared_here.replace): * builtins/SetPrototype.js: (forEach): * builtins/TypedArrayConstructor.js: * builtins/TypedArrayPrototype.js: (every): (find): (findIndex): (forEach): (some): (sort): (reduce): (reduceRight): (map): (filter): * bytecode/BytecodeIntrinsicRegistry.h: * bytecode/BytecodeList.rb: * bytecode/BytecodeUseDef.cpp: (JSC::computeUsesForBytecodeIndexImpl): (JSC::computeDefsForBytecodeIndexImpl): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitEqualityOpImpl): (JSC::BytecodeGenerator::emitIsCallable): * bytecompiler/BytecodeGenerator.h: * bytecompiler/NodesCodegen.cpp: * dfg/DFGAbstractInterpreterInlines.h: (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGCapabilities.cpp: (JSC::DFG::capabilityLevel): * dfg/DFGClobberize.h: (JSC::DFG::clobberize): * dfg/DFGDoesGC.cpp: (JSC::DFG::doesGC): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGHeapLocation.cpp: (WTF::printInternal): * dfg/DFGHeapLocation.h: * dfg/DFGNodeType.h: * dfg/DFGOperations.cpp: * dfg/DFGOperations.h: * dfg/DFGPredictionPropagationPhase.cpp: * dfg/DFGSafeToExecute.h: (JSC::DFG::safeToExecute): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::compileIsCallable): (JSC::DFG::SpeculativeJIT::compileIsFunction): Deleted. * dfg/DFGSpeculativeJIT.h: * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * ftl/FTLCapabilities.cpp: (JSC::FTL::canCompile): * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileNode): (JSC::FTL::DFG::LowerDFGToB3::compileIsCallable): (JSC::FTL::DFG::LowerDFGToB3::compileIsFunction): Deleted. * jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): * jit/JITOperations.h: * jsc.cpp: (functionMakeMasquerader): * llint/LowLevelInterpreter.asm: * runtime/CommonSlowPaths.cpp: (JSC::SLOW_PATH_DECL): * runtime/CommonSlowPaths.h: * runtime/InternalFunction.cpp: (JSC::InternalFunction::createFunctionThatMasqueradesAsUndefined): * runtime/InternalFunction.h: * runtime/JSFunction.cpp: (JSC::JSFunction::createFunctionThatMasqueradesAsUndefined): Deleted. * runtime/JSFunction.h: * runtime/Operations.h: (JSC::jsTypeofIsFunction): Source/WebCore: No new tests, no behavior change. * bindings/js/JSDOMWindowCustom.cpp: (WebCore::JSDOMWindow::openDatabase const): LayoutTests: * js/dom/document-all-is-callable-builtins-expected.txt: Added. * js/dom/document-all-is-callable-builtins.html: Added. * js/dom/document-all-typeof-is-function-fold-expected.txt: Added. * js/dom/document-all-typeof-is-function-fold.html: Added. * js/dom/script-tests/document-all-is-callable-builtins.js: Added. * js/dom/script-tests/document-all-typeof-is-function-fold.js: Added. Canonical link: https://commits.webkit.org/228428@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@265907 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent e2dcdaa commit d1e50e3

61 files changed

Lines changed: 513 additions & 123 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

JSTests/ChangeLog

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
2020-08-19 Alexey Shvayka <shvaikalesh@gmail.com>
2+
3+
Introduce OpIsCallable bytecode and intrinsic
4+
https://bugs.webkit.org/show_bug.cgi?id=215572
5+
6+
Reviewed by Ross Kirsling and Saam Barati.
7+
8+
* stress/type-of-functions-and-objects.js:
9+
* test262/expectations.yaml: Mark 2 test cases as passing.
10+
111
2020-08-17 Saam Barati <sbarati@apple.com>
212

313
Have an OOB+SaneChain Array::Speculation

JSTests/stress/type-of-functions-and-objects.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ function test() {
7272
testValue(Map, "function");
7373
testValue(Date, "function");
7474
testValue(Map.prototype, "object");
75+
testValue(makeMasquerader(), "other");
7576

7677
if (!errors.length)
7778
return;

JSTests/test262/expectations.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -295,9 +295,6 @@ test/annexB/language/eval-code/indirect/global-switch-dflt-eval-global-skip-earl
295295
default: 'Test262Error: An initialized binding is not created following evaluation Expected a ReferenceError to be thrown but no exception was thrown at all'
296296
test/annexB/language/eval-code/indirect/global-switch-dflt-eval-global-skip-early-err-try.js:
297297
default: 'Test262Error: An initialized binding is not created prior to evaluation Expected a ReferenceError to be thrown but no exception was thrown at all'
298-
test/annexB/language/expressions/typeof/emulates-undefined.js:
299-
default: 'Test262Error: !== "function"'
300-
strict mode: 'Test262Error: !== "function"'
301298
test/annexB/language/function-code/block-decl-func-skip-arguments.js:
302299
default: 'Test262Error: Expected SameValue(«function arguments() {}», «[object Arguments]») to be true'
303300
test/annexB/language/function-code/block-decl-func-skip-early-err-block.js:

LayoutTests/ChangeLog

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
2020-08-19 Alexey Shvayka <shvaikalesh@gmail.com>
2+
3+
Introduce OpIsCallable bytecode and intrinsic
4+
https://bugs.webkit.org/show_bug.cgi?id=215572
5+
6+
Reviewed by Ross Kirsling and Saam Barati.
7+
8+
* js/dom/document-all-is-callable-builtins-expected.txt: Added.
9+
* js/dom/document-all-is-callable-builtins.html: Added.
10+
* js/dom/document-all-typeof-is-function-fold-expected.txt: Added.
11+
* js/dom/document-all-typeof-is-function-fold.html: Added.
12+
* js/dom/script-tests/document-all-is-callable-builtins.js: Added.
13+
* js/dom/script-tests/document-all-typeof-is-function-fold.js: Added.
14+
115
2020-08-19 Peng Liu <peng.liu6@apple.com>
216

317
A PiP window is closed when the video element is removed from DOM
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
document.all is callable (builtins)
2+
3+
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
4+
5+
6+
PASS testArray() is true
7+
PASS testTypedArray() is true
8+
PASS testRegExp() is true
9+
PASS testOtherBuiltins() is true
10+
PASS successfullyParsed is true
11+
12+
TEST COMPLETE
13+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE HTML>
2+
<html>
3+
<head>
4+
<script src="../../resources/js-test-pre.js"></script>
5+
</head>
6+
<body>
7+
<script src="script-tests/document-all-is-callable-builtins.js"></script>
8+
<script src="../../resources/js-test-post.js"></script>
9+
</body>
10+
</html>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
typeof document.all is never 'function'
2+
3+
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
4+
5+
6+
PASS testTypeofIsFunction() is false
7+
PASS testTypeofIsNotFunction() is true
8+
PASS successfullyParsed is true
9+
10+
TEST COMPLETE
11+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE HTML>
2+
<html>
3+
<head>
4+
<script src="../../resources/js-test-pre.js"></script>
5+
</head>
6+
<body>
7+
<script src="script-tests/document-all-typeof-is-function-fold.js"></script>
8+
<script src="../../resources/js-test-post.js"></script>
9+
</body>
10+
</html>
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
description("document.all is callable (builtins)");
2+
const documentAll = document.all;
3+
4+
function testArray() {
5+
for (var i = 0; i < 1e4; ++i) {
6+
Array.from([], documentAll);
7+
[].reduce(documentAll, null);
8+
[].reduceRight(documentAll, null);
9+
[].every(documentAll);
10+
[].forEach(documentAll);
11+
[].filter(documentAll);
12+
[].map(documentAll);
13+
[].some(documentAll);
14+
[].find(documentAll);
15+
[].findIndex(documentAll);
16+
[].sort(documentAll);
17+
[].flatMap(documentAll);
18+
}
19+
return true;
20+
}
21+
22+
function testTypedArray() {
23+
for (var i = 0; i < 1e4; ++i) {
24+
Float64Array.from([], documentAll);
25+
(new Float32Array).every(documentAll);
26+
(new Int32Array).find(documentAll);
27+
(new Int16Array).findIndex(documentAll);
28+
(new Int8Array).forEach(documentAll);
29+
(new Uint32Array).some(documentAll);
30+
(new Uint16Array).sort(documentAll);
31+
(new Uint8Array).reduce(documentAll, null);
32+
(new Uint8ClampedArray).reduceRight(documentAll, null);
33+
(new Float64Array).map(documentAll);
34+
(new Float32Array).filter(documentAll);
35+
}
36+
return true;
37+
}
38+
39+
function testRegExp() {
40+
var test = RegExp.prototype.test;
41+
var replace = RegExp.prototype[Symbol.replace];
42+
43+
for (var i = 0; i < 1e4; ++i) {
44+
if (test.call({exec: documentAll}, "x") !== false)
45+
return false;
46+
47+
if (replace.call(/./, "x", documentAll) !== "null")
48+
return false;
49+
}
50+
return true;
51+
}
52+
53+
function testOtherBuiltins() {
54+
Promise.resolve = documentAll;
55+
56+
for (var i = 0; i < 1e4; ++i) {
57+
Promise.all([]);
58+
Promise.allSettled([]);
59+
Promise.any([]);
60+
Promise.race([]);
61+
new Promise(documentAll);
62+
63+
Reflect.apply(documentAll, null, []);
64+
Function.prototype.bind.call(documentAll);
65+
(new Map).forEach(documentAll);
66+
(new Set).forEach(documentAll);
67+
}
68+
return true;
69+
}
70+
71+
shouldBeTrue("testArray()");
72+
shouldBeTrue("testTypedArray()");
73+
shouldBeTrue("testRegExp()");
74+
shouldBeTrue("testOtherBuiltins()");
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
description("typeof document.all is never 'function'");
2+
const documentAll = document.all;
3+
4+
function testTypeofIsFunction() {
5+
let acc = 0;
6+
for (let i = 0; i < 1e6; ++i)
7+
acc += (typeof documentAll === "function");
8+
return acc === 1e6;
9+
}
10+
11+
function testTypeofIsNotFunction() {
12+
let acc = 0;
13+
for (let i = 0; i < 1e6; ++i)
14+
acc += (typeof documentAll !== "function");
15+
return acc === 1e6;
16+
}
17+
18+
shouldBeFalse("testTypeofIsFunction()");
19+
shouldBeTrue("testTypeofIsNotFunction()");

0 commit comments

Comments
 (0)