// Currently reduces performance significantly :(
DEFINE_BOOL(jiterpreter_use_constants, "jiterpreter-use-constants", FALSE, "Use runtime imports for pointer constants")
// any trace that doesn't have at least this many meaningful (non-nop) opcodes in it will be rejected
-DEFINE_INT(jiterpreter_minimum_trace_length, "jiterpreter-minimum-trace-length", 8, "Reject traces shorter than this number of meaningful opcodes")
+DEFINE_INT(jiterpreter_minimum_trace_length, "jiterpreter-minimum-trace-length", 10, "Reject traces shorter than this number of meaningful opcodes")
// once a trace entry point is inserted, we only actually JIT code for it once it's been hit this many times
DEFINE_INT(jiterpreter_minimum_trace_hit_count, "jiterpreter-minimum-trace-hit-count", 5000, "JIT trace entry points once they are hit this many times")
// After a do_jit_call call site is hit this many times, we will queue it to be jitted
-DEFINE_INT(jiterpreter_jit_call_trampoline_hit_count, "jiterpreter-jit-call-hit-count", 2000, "Queue specialized do_jit_call trampoline for JIT after this many hits")
+DEFINE_INT(jiterpreter_jit_call_trampoline_hit_count, "jiterpreter-jit-call-hit-count", 1000, "Queue specialized do_jit_call trampoline for JIT after this many hits")
// After a do_jit_call call site is hit this many times without being jitted, we will flush the JIT queue
-DEFINE_INT(jiterpreter_jit_call_queue_flush_threshold, "jiterpreter-jit-call-queue-flush-threshold", 8000, "Flush the do_jit_call JIT queue after an unJITted call site has this many hits")
+DEFINE_INT(jiterpreter_jit_call_queue_flush_threshold, "jiterpreter-jit-call-queue-flush-threshold", 6000, "Flush the do_jit_call JIT queue after an unJITted call site has this many hits")
// After a generic interp_entry wrapper is hit this many times, we will queue it to be jitted
-DEFINE_INT(jiterpreter_interp_entry_trampoline_hit_count, "jiterpreter-interp-entry-hit-count", 250, "Queue specialized interp_entry wrapper for JIT after this many hits")
+DEFINE_INT(jiterpreter_interp_entry_trampoline_hit_count, "jiterpreter-interp-entry-hit-count", 1000, "Queue specialized interp_entry wrapper for JIT after this many hits")
// After a generic interp_entry wrapper is hit this many times without being jitted, we will flush the JIT queue
-DEFINE_INT(jiterpreter_interp_entry_queue_flush_threshold, "jiterpreter-interp-entry-queue-flush-threshold", 1000, "Flush the interp_entry JIT queue after an unJITted call site has this many hits")
+DEFINE_INT(jiterpreter_interp_entry_queue_flush_threshold, "jiterpreter-interp-entry-queue-flush-threshold", 3000, "Flush the interp_entry JIT queue after an unJITted call site has this many hits")
+// In degenerate cases the jiterpreter could end up generating lots of WASM, so shut off jitting once it reaches this limit
+// Each wasm byte likely maps to multiple bytes of native code, so it's important for this limit not to be too high
+DEFINE_INT(jiterpreter_wasm_bytes_limit, "jiterpreter-wasm-bytes-limit", 6 * 1024 * 1024, "Disable jiterpreter code generation once this many bytes of WASM have been generated")
#endif // HOST_BROWSER
/* Cleanup */
trampBuilder = builder = new WasmBuilder(constantSlots);
else
builder.clear(constantSlots);
+
+ if (builder.options.wasmBytesLimit <= counters.bytesGenerated) {
+ jitQueue.length = 0;
+ return;
+ }
+
const started = _now();
let compileStarted = 0;
let rejected = true, threw = false;
const buffer = builder.getArrayView();
if (trace > 0)
console.log(`jit queue generated ${buffer.length} byte(s) of wasm`);
+ counters.bytesGenerated += buffer.length;
const traceModule = new WebAssembly.Module(buffer);
const imports : any = {
for (let i = 0; i < doJitCall16.length; i += 2)
bytes[i / 2] = parseInt(doJitCall16.substring(i, i + 2), 16);
+ counters.bytesGenerated += bytes.length;
doJitCallModule = new WebAssembly.Module(bytes);
wasmEhSupported = true;
} catch (exc) {
else
builder.clear(0);
+ if (builder.options.wasmBytesLimit <= counters.bytesGenerated) {
+ jitQueue.length = 0;
+ return;
+ }
+
if (builder.options.enableWasmEh) {
if (!getIsWasmEhSupported()) {
// The user requested to enable wasm EH but it's not supported, so turn the option back off
const buffer = builder.getArrayView();
if (trace > 0)
console.log(`do_jit_call queue flush generated ${buffer.length} byte(s) of wasm`);
+ counters.bytesGenerated += buffer.length;
const traceModule = new WebAssembly.Module(buffer);
const imports : any = {
tracesCompiled: 0,
entryWrappersCompiled: 0,
jitCallsCompiled: 0,
- failures: 0
+ failures: 0,
+ bytesGenerated: 0
};
export const _now = (globalThis.performance && globalThis.performance.now)
jitCallFlushThreshold: number;
interpEntryHitCount: number;
interpEntryFlushThreshold: number;
+ // Maximum total number of wasm bytes to generate
+ wasmBytesLimit: number;
}
const optionNames : { [jsName: string] : string } = {
"jitCallFlushThreshold": "jiterpreter-jit-call-queue-flush-threshold",
"interpEntryHitCount": "jiterpreter-interp-entry-hit-count",
"interpEntryFlushThreshold": "jiterpreter-interp-entry-queue-flush-threshold",
+ "wasmBytesLimit": "jiterpreter-wasm-bytes-limit",
};
let optionsVersion = -1;
const buffer = builder.getArrayView();
if (trace > 0)
console.log(`${traceName} generated ${buffer.length} byte(s) of wasm`);
+ counters.bytesGenerated += buffer.length;
const traceModule = new WebAssembly.Module(buffer);
const imports : any = {
// FIXME: We shouldn't need this check
if (!mostRecentOptions.enableTraces)
return JITERPRETER_NOT_JITTED;
+ else if (mostRecentOptions.wasmBytesLimit <= counters.bytesGenerated)
+ return JITERPRETER_NOT_JITTED;
let info = traceInfo[<any>ip];
if (!mostRecentOptions.enableStats && (b !== undefined))
return;
- console.log(`// jiterpreter produced ${counters.tracesCompiled} traces from ${counters.traceCandidates} candidates (${(counters.tracesCompiled / counters.traceCandidates * 100).toFixed(1)}%), ${counters.jitCallsCompiled} jit_call trampolines, and ${counters.entryWrappersCompiled} interp_entry wrappers`);
+ console.log(`// generated: ${counters.bytesGenerated} wasm bytes; ${counters.tracesCompiled} traces (${counters.traceCandidates} candidates, ${(counters.tracesCompiled / counters.traceCandidates * 100).toFixed(1)}%); ${counters.jitCallsCompiled} jit_calls; ${counters.entryWrappersCompiled} interp_entries`);
console.log(`// time spent: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm`);
if (mostRecentOptions.countBailouts) {
for (let i = 0; i < BailoutReasonNames.length; i++) {