Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions JSTests/controlFlowProfiler/default-values.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
var basicBlockExecutionCount = $vm.basicBlockExecutionCount;

load("./driver/driver.js");

function foo() { return 1; }

function testParameter(a = foo(1), b = foo(2)) {
return a + b;
}
testParameter(1);
checkBasicBlock(testParameter, "foo(1)", ShouldNotHaveExecuted);
checkBasicBlock(testParameter, "foo(2)", ShouldHaveExecuted);
checkBasicBlock(testParameter, "return a", ShouldHaveExecuted);
testParameter();
checkBasicBlock(testParameter, "foo(1)", ShouldHaveExecuted);

var testArrowFunctionParameter = (a = foo()) => a;
testArrowFunctionParameter(1);
checkBasicBlock(testArrowFunctionParameter, "foo()", ShouldNotHaveExecuted);
checkBasicBlock(testArrowFunctionParameter, "=> a", ShouldHaveExecuted);

function testPatternParameter({ a = foo(1) }, [b = foo(2)] = [foo(3)]) {
return a + b;
}
testPatternParameter({ a: 1 }, [1]);
checkBasicBlock(testPatternParameter, "foo(1)", ShouldNotHaveExecuted);
checkBasicBlock(testPatternParameter, "foo(2)", ShouldNotHaveExecuted);
checkBasicBlock(testPatternParameter, "foo(3)", ShouldNotHaveExecuted);
checkBasicBlock(testPatternParameter, "return a", ShouldHaveExecuted);
testPatternParameter({ });
checkBasicBlock(testPatternParameter, "foo(1)", ShouldHaveExecuted);
checkBasicBlock(testPatternParameter, "foo(2)", ShouldNotHaveExecuted);
checkBasicBlock(testPatternParameter, "foo(3)", ShouldHaveExecuted);

function testDeclaration(o, l) {
const { a = foo(1), b: { c = foo(2) } = { c: foo(3) } } = o;
let [d = foo(4), e = foo(5)] = l;
return a + c + d + e;
}
testDeclaration({ a: 1 }, [1]);
checkBasicBlock(testDeclaration, "foo(1)", ShouldNotHaveExecuted);
checkBasicBlock(testDeclaration, "foo(2)", ShouldNotHaveExecuted);
checkBasicBlock(testDeclaration, "foo(3)", ShouldHaveExecuted);
checkBasicBlock(testDeclaration, "foo(4)", ShouldNotHaveExecuted);
checkBasicBlock(testDeclaration, "foo(5)", ShouldHaveExecuted);
checkBasicBlock(testDeclaration, "return a", ShouldHaveExecuted);

function testAssignment(o, l) {
let a, b;
({ a = foo(1) } = o);
[b = foo(2)] = l;
return a + b;
}
testAssignment({ a: 1 }, [1]);
checkBasicBlock(testAssignment, "foo(1)", ShouldNotHaveExecuted);
checkBasicBlock(testAssignment, "foo(2)", ShouldNotHaveExecuted);
checkBasicBlock(testAssignment, "return a", ShouldHaveExecuted);

function testForOfAndCatch(l) {
for (const { a = foo(1) } of l)
foo(2);
try {
throw { b: 1 };
} catch ({ b = foo(3) }) {
foo(4);
}
}
testForOfAndCatch([{ a: 1 }]);
checkBasicBlock(testForOfAndCatch, "foo(1)", ShouldNotHaveExecuted);
checkBasicBlock(testForOfAndCatch, "foo(2)", ShouldHaveExecuted);
checkBasicBlock(testForOfAndCatch, "foo(3)", ShouldNotHaveExecuted);
checkBasicBlock(testForOfAndCatch, "foo(4)", ShouldHaveExecuted);

// The basic block of the arrow function is not the one of the default value.
function testArrowFunction(a = () => foo()) {
return a;
}
var arrowFunction = testArrowFunction();
checkBasicBlock(testArrowFunction, "foo()", ShouldNotHaveExecuted);
arrowFunction();
arrowFunction();
assert(basicBlockExecutionCount(testArrowFunction, "foo()") === 2, "the arrow function ran twice");

function testArrowFunctionInAPattern({ a = () => foo() }) {
return a;
}
arrowFunction = testArrowFunctionInAPattern({ });
checkBasicBlock(testArrowFunctionInAPattern, "foo()", ShouldNotHaveExecuted);
arrowFunction();
arrowFunction();
assert(basicBlockExecutionCount(testArrowFunctionInAPattern, "foo()") === 2, "the arrow function ran twice");

// Not in the test of a `case`.
function testCaseTest(o) {
let a;
switch (2) {
case { a = foo(1) } = o: foo(2);
}
}
testCaseTest({ });
checkBasicBlock(testCaseTest, "foo(1)", ShouldNotHaveExecuted);
checkBasicBlock(testCaseTest, "foo(2)", ShouldNotHaveExecuted);

function testCount(a = foo()) {
return a;
}
testCount();
testCount(1);
testCount(undefined);
assert(basicBlockExecutionCount(testCount, "foo()") === 2, "the default value runs when there is no argument");
assert(basicBlockExecutionCount(testCount, "return a") === 3, "the body runs each time");
117 changes: 117 additions & 0 deletions JSTests/controlFlowProfiler/logical-assignment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
var basicBlockExecutionCount = $vm.basicBlockExecutionCount;

load("./driver/driver.js");

function foo() { return 1; }
var global = 1;

function testOr(x) {
x ||= foo();
return x;
}
testOr(1);
checkBasicBlock(testOr, "x ||=", ShouldHaveExecuted);
checkBasicBlock(testOr, "foo()", ShouldNotHaveExecuted);
checkBasicBlock(testOr, "return x", ShouldHaveExecuted);
testOr(0);
checkBasicBlock(testOr, "foo()", ShouldHaveExecuted);

function testAnd(x) {
x &&= foo();
return x;
}
testAnd(0);
checkBasicBlock(testAnd, "foo()", ShouldNotHaveExecuted);
checkBasicBlock(testAnd, "return x", ShouldHaveExecuted);
testAnd(1);
checkBasicBlock(testAnd, "foo()", ShouldHaveExecuted);

function testCoalesce(x) {
x ??= foo();
return x;
}
testCoalesce(0);
checkBasicBlock(testCoalesce, "foo()", ShouldNotHaveExecuted);
checkBasicBlock(testCoalesce, "return x", ShouldHaveExecuted);
testCoalesce(null);
checkBasicBlock(testCoalesce, "foo()", ShouldHaveExecuted);

function testMember(o) {
o.a ||= foo(1);
o["a"] &&= foo(2);
o.b ??= foo(3);
return o;
}
testMember({ a: 0, b: 0 });
checkBasicBlock(testMember, "foo(1)", ShouldHaveExecuted);
checkBasicBlock(testMember, "foo(2)", ShouldHaveExecuted);
checkBasicBlock(testMember, "foo(3)", ShouldNotHaveExecuted);
checkBasicBlock(testMember, "return o", ShouldHaveExecuted);

function testSubscript(o) {
o[foo(1)] ||= foo(2);
return o;
}
testSubscript([0, 1]);
checkBasicBlock(testSubscript, "foo(1)", ShouldHaveExecuted);
checkBasicBlock(testSubscript, "foo(2)", ShouldNotHaveExecuted);

function testKindsOfVariable() {
let captured = 1;
const constant = 1;
let assignedOnTheRight = 1;
(() => captured);
captured ||= foo(1);
constant ||= foo(2);
global ||= foo(3);
assignedOnTheRight ||= (assignedOnTheRight = foo(4));
return captured;
}
testKindsOfVariable();
checkBasicBlock(testKindsOfVariable, "foo(1)", ShouldNotHaveExecuted);
checkBasicBlock(testKindsOfVariable, "foo(2)", ShouldNotHaveExecuted);
checkBasicBlock(testKindsOfVariable, "foo(3)", ShouldNotHaveExecuted);
checkBasicBlock(testKindsOfVariable, "foo(4)", ShouldNotHaveExecuted);
checkBasicBlock(testKindsOfVariable, "return captured", ShouldHaveExecuted);

function testChain(x, y) {
x ||= y &&= foo(1) + foo(2);
return x;
}
testChain(0, 0);
checkBasicBlock(testChain, "y &&=", ShouldHaveExecuted);
checkBasicBlock(testChain, "foo(1)", ShouldNotHaveExecuted);
checkBasicBlock(testChain, "foo(2)", ShouldNotHaveExecuted);
checkBasicBlock(testChain, "return x", ShouldHaveExecuted);

// The basic block of the arrow function is not the one of the right side.
function testArrowFunction(x) {
x ||= () => foo();
return x;
}
var arrowFunction = testArrowFunction(0);
checkBasicBlock(testArrowFunction, "foo()", ShouldNotHaveExecuted);
arrowFunction();
arrowFunction();
assert(basicBlockExecutionCount(testArrowFunction, "foo()") === 2, "the arrow function ran twice");

// Not in the test of a `case`.
function testCaseTest(x) {
switch (2) {
case x ||= foo(1): foo(2);
}
}
testCaseTest(0);
checkBasicBlock(testCaseTest, "foo(1)", ShouldNotHaveExecuted);
checkBasicBlock(testCaseTest, "foo(2)", ShouldNotHaveExecuted);

function testCount(x) {
x ||= foo();
return x;
}
testCount(0);
testCount(1);
testCount(0);
assert(basicBlockExecutionCount(testCount, "x ||=") === 3, "the left side runs each time");
assert(basicBlockExecutionCount(testCount, "foo()") === 2, "the right side runs when the left side is falsy");
assert(basicBlockExecutionCount(testCount, "return x") === 3, "what is after it runs each time");
Loading
Loading