Skip to content

Commit 67cfc6e

Browse files
authored
Add Scripts helper classes (#109)
- Add ShellScripts and BrowserScripts helper classes - Use temp array for scripts in both cases - Directly add promise error handler for browser scripts - Move runCode to the corresponding scripts class
1 parent d84d311 commit 67cfc6e

File tree

1 file changed

+145
-121
lines changed

1 file changed

+145
-121
lines changed

JetStreamDriver.js

Lines changed: 145 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -312,56 +312,6 @@ class Driver {
312312
}
313313
}
314314

315-
runCode(string) {
316-
if (!isInBrowser) {
317-
const scripts = string;
318-
let globalObject;
319-
let realm;
320-
if (isD8) {
321-
realm = Realm.createAllowCrossRealmAccess();
322-
globalObject = Realm.global(realm);
323-
globalObject.loadString = function(s) {
324-
return Realm.eval(realm, s);
325-
};
326-
globalObject.readFile = read;
327-
} else if (isSpiderMonkey) {
328-
globalObject = newGlobal();
329-
globalObject.loadString = globalObject.evaluate;
330-
globalObject.readFile = globalObject.readRelativeToScript;
331-
} else
332-
globalObject = runString("");
333-
334-
globalObject.console = {
335-
log: globalObject.print,
336-
warn: (e) => { print("Warn: " + e); },
337-
error: (e) => { print("Error: " + e); },
338-
debug: (e) => { print("Debug: " + e); },
339-
};
340-
341-
globalObject.self = globalObject;
342-
globalObject.top = {
343-
currentResolve,
344-
currentReject
345-
};
346-
347-
globalObject.performance ??= performance;
348-
for (const script of scripts)
349-
globalObject.loadString(script);
350-
351-
return isD8 ? realm : globalObject;
352-
}
353-
354-
const magic = document.getElementById("magic");
355-
magic.contentDocument.body.textContent = "";
356-
magic.contentDocument.body.innerHTML = "<iframe id=\"magicframe\" frameborder=\"0\">";
357-
358-
const magicFrame = magic.contentDocument.getElementById("magicframe");
359-
magicFrame.contentDocument.open();
360-
magicFrame.contentDocument.write(`<!DOCTYPE html><head><title>benchmark payload</title></head><body>\n${string}</body></html>`);
361-
362-
return magicFrame;
363-
}
364-
365315
prepareToRun() {
366316
this.benchmarks.sort((a, b) => a.plan.name.toLowerCase() < b.plan.name.toLowerCase() ? 1 : -1);
367317

@@ -578,6 +528,140 @@ const BenchmarkState = Object.freeze({
578528
DONE: "DONE"
579529
})
580530

531+
532+
class Scripts {
533+
constructor() {
534+
this.scripts = [];
535+
this.add(`
536+
const isInBrowser = ${isInBrowser};
537+
const isD8 = ${isD8};
538+
if (typeof performance.mark === 'undefined') {
539+
performance.mark = function(name) { return { name }};
540+
}
541+
if (typeof performance.measure === 'undefined') {
542+
performance.measure = function() {};
543+
}
544+
`);
545+
}
546+
547+
run() {
548+
throw new Error("Subclasses need to implement this");
549+
}
550+
551+
add(text) {
552+
throw new Error("Subclasses need to implement this");
553+
}
554+
555+
addWithURL(url) {
556+
throw new Error("addWithURL not supported");
557+
}
558+
559+
addDeterministicRandom() {
560+
this.add(`(() => {
561+
const initialSeed = 49734321;
562+
let seed = initialSeed;
563+
564+
Math.random = () => {
565+
// Robert Jenkins' 32 bit integer hash function.
566+
seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffff_ffff;
567+
seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffff_ffff;
568+
seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffff_ffff;
569+
seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffff_ffff;
570+
seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffff_ffff;
571+
seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffff_ffff;
572+
// Note that Math.random should return a value that is
573+
// greater than or equal to 0 and less than 1. Here, we
574+
// cast to uint32 first then divided by 2^32 for double.
575+
return (seed >>> 0) / 0x1_0000_0000;
576+
};
577+
578+
Math.random.__resetSeed = () => {
579+
seed = initialSeed;
580+
};
581+
})();`);
582+
}
583+
}
584+
585+
class ShellScripts extends Scripts {
586+
run() {
587+
let globalObject;
588+
let realm;
589+
if (isD8) {
590+
realm = Realm.createAllowCrossRealmAccess();
591+
globalObject = Realm.global(realm);
592+
globalObject.loadString = function(s) {
593+
return Realm.eval(realm, s);
594+
};
595+
globalObject.readFile = read;
596+
} else if (isSpiderMonkey) {
597+
globalObject = newGlobal();
598+
globalObject.loadString = globalObject.evaluate;
599+
globalObject.readFile = globalObject.readRelativeToScript;
600+
} else
601+
globalObject = runString("");
602+
603+
globalObject.console = {
604+
log: globalObject.print,
605+
warn: (e) => { print("Warn: " + e); },
606+
error: (e) => { print("Error: " + e); },
607+
debug: (e) => { print("Debug: " + e); },
608+
};
609+
610+
globalObject.self = globalObject;
611+
globalObject.top = {
612+
currentResolve,
613+
currentReject
614+
};
615+
616+
globalObject.performance ??= performance;
617+
for (const script of this.scripts)
618+
globalObject.loadString(script);
619+
620+
return isD8 ? realm : globalObject;
621+
}
622+
623+
add(text) {
624+
this.scripts.push(text);
625+
}
626+
627+
addWithURL(url) {
628+
assert(false, "Should not reach here in CLI");
629+
}
630+
}
631+
632+
class BrowserScripts extends Scripts {
633+
constructor() {
634+
super();
635+
this.add("window.onerror = top.currentReject;");
636+
}
637+
638+
run() {
639+
const string = this.scripts.join("\n");
640+
const magic = document.getElementById("magic");
641+
magic.contentDocument.body.textContent = "";
642+
magic.contentDocument.body.innerHTML = `<iframe id="magicframe" frameborder="0">`;
643+
644+
const magicFrame = magic.contentDocument.getElementById("magicframe");
645+
magicFrame.contentDocument.open();
646+
magicFrame.contentDocument.write(`<!DOCTYPE html>
647+
<head>
648+
<title>benchmark payload</title>
649+
</head>
650+
<body>${string}</body>
651+
</html>`);
652+
return magicFrame;
653+
}
654+
655+
656+
add(text) {
657+
this.scripts.push(`<script>${text}</script>`);
658+
}
659+
660+
addWithURL(url) {
661+
this.scripts.push(`<script src="${url}"></script>`);
662+
}
663+
}
664+
581665
class Benchmark {
582666
constructor(plan)
583667
{
@@ -682,98 +766,38 @@ class Benchmark {
682766
if (this.isDone)
683767
throw new Error(`Cannot run Benchmark ${this.name} twice`);
684768
this._state = BenchmarkState.PREPARE;
685-
let code;
686-
if (isInBrowser)
687-
code = "";
688-
else
689-
code = [];
690-
691-
const addScript = (text) => {
692-
if (isInBrowser)
693-
code += `<script>${text}</script>`;
694-
else
695-
code.push(text);
696-
};
697-
698-
const addScriptWithURL = (url) => {
699-
if (isInBrowser)
700-
code += `<script src="${url}"></script>`;
701-
else
702-
assert(false, "Should not reach here in CLI");
703-
};
704-
705-
addScript(`
706-
const isInBrowser = ${isInBrowser};
707-
const isD8 = ${isD8};
708-
if (typeof performance.mark === 'undefined') {
709-
performance.mark = function(name) { return { name }};
710-
}
711-
if (typeof performance.measure === 'undefined') {
712-
performance.measure = function() {};
713-
}
714-
`);
769+
const scripts = isInBrowser ? new BrowserScripts() : new ShellScripts();
715770

716-
if (!!this.plan.deterministicRandom) {
717-
addScript(`
718-
(() => {
719-
const initialSeed = 49734321;
720-
let seed = initialSeed;
721-
722-
Math.random = () => {
723-
// Robert Jenkins' 32 bit integer hash function.
724-
seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffff_ffff;
725-
seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffff_ffff;
726-
seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffff_ffff;
727-
seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffff_ffff;
728-
seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffff_ffff;
729-
seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffff_ffff;
730-
// Note that Math.random should return a value that is
731-
// greater than or equal to 0 and less than 1. Here, we
732-
// cast to uint32 first then divided by 2^32 for double.
733-
return (seed >>> 0) / 0x1_0000_0000;
734-
};
735-
736-
Math.random.__resetSeed = () => {
737-
seed = initialSeed;
738-
};
739-
})();
740-
`);
741-
}
771+
if (!!this.plan.deterministicRandom)
772+
scripts.addDeterministicRandom()
742773

743774
if (this.plan.preload) {
744-
let str = "";
775+
let preloadCode = "";
745776
for (let [ variableName, blobURLOrPath ] of this.preloads)
746-
str += `const ${variableName} = "${blobURLOrPath}";\n`;
747-
addScript(str);
777+
preloadCode += `const ${variableName} = "${blobURLOrPath}";\n`;
778+
scripts.add(preloadCode);
748779
}
749780

750781
const prerunCode = this.prerunCode;
751782
if (prerunCode)
752-
addScript(prerunCode);
783+
scripts.add(prerunCode);
753784

754785
if (!isInBrowser) {
755786
assert(this.scripts && this.scripts.length === this.plan.files.length);
756-
757787
for (const text of this.scripts)
758-
addScript(text);
788+
scripts.add(text);
759789
} else {
760790
const cache = JetStream.blobDataCache;
761791
for (const file of this.plan.files)
762-
addScriptWithURL(cache[file].blobURL);
792+
scripts.addWithURL(cache[file].blobURL);
763793
}
764794

765795
const promise = new Promise((resolve, reject) => {
766796
currentResolve = resolve;
767797
currentReject = reject;
768798
});
769799

770-
if (isInBrowser) {
771-
code = `
772-
<script> window.onerror = top.currentReject; </script>
773-
${code}
774-
`;
775-
}
776-
addScript(this.runnerCode);
800+
scripts.add(this.runnerCode);
777801

778802
performance.mark(this.name);
779803
this.startTime = performance.now();
@@ -784,7 +808,7 @@ class Benchmark {
784808
let magicFrame;
785809
try {
786810
this._state = BenchmarkState.RUNNING;
787-
magicFrame = JetStream.runCode(code);
811+
magicFrame = scripts.run();
788812
} catch(e) {
789813
this._state = BenchmarkState.ERROR;
790814
console.log("Error in runCode: ", e);

0 commit comments

Comments
 (0)