This is a second part to this other post.
The process of loading/streaming, parse, compile and run is complicated enough to handle optimally. Worse enough, when you run the same scripts over and over, it will turn quite inefficient too, since this process has to be performed every time for the same scripts.
There is something we can do for this situation though. We can obtain the parsed javascript bytecode contents and reuse it over and over again. The default script execution process, non streamed, would be something like:
ScriptOrigin origin(String::NewFromUtf8( isolate, constCharPtrToString)); v8::MaybeLocal<v8::Script> maybescript = v8::Script::Compile( v8Context, v8StringSource, // Local<String> object with source contents. &origin); if (!maybescript.IsEmpty()) { Local<Script> script = maybescript.ToLocalChecked(); if (script.IsEmpty()) { // report exception here } else { Local<Value> result = script->Run(v8Context).ToLocalChecked(); ... } }
But, on the first script execution, we can change this run process to something like:
// source is a Local<String> ScriptCompiler::Source source(source, ...); // create unbounded script (see v8.h) auto unboundedScript = ScriptCompiler::CompileUnboundScript( isolate, &source, ScriptCompiler::CompileOptions::kNoCompileOptions).ToLocalChecked(); // obtain parsed bytecode for resusability. // Store for reusability and profit auto bytecode = new BytecodeCacheEntry( ScriptCompiler::CreateCodeCache(unbounded_script)); // if you want to run this script, you must: unboundedScript->BindToCurrentContext(); // and just auto result = script->Run(context).ToLocalChecked(); // check for result, etc.
Successive executions of this script could benefit from the bytecode like:
// build a BytecodeCacheData from a uint8_t* contents and size auto cache_entry = new BytecodeCacheEntry(contents, size) // Once we have the BytecodeCacheEntry contents: ScriptCompiler::Source sc_source(source, origin, cache_entry); // Create compiler script = ScriptCompiler::Compile( context, &sc_source, ScriptCompiler::CompileOptions::kConsumeCodeCache) .ToLocalChecked(); // check is script is valid, etc, and run: auto result = script->Run(context).ToLocalChecked();
Saving the loading andparsing stages that could be quite time costly. The profit is around 30-50% smaller first frame times.