From d1cacb814f6d42395184beaaba906ba930e711eb Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Wed, 20 Jan 2016 19:34:19 -0500 Subject: vm: introduce `cachedData`/`produceCachedData` Introduce `cachedData`/`produceCachedData` options for `v8.Script`. Could be used to consume/produce V8's code cache for speeding up compilation of known code. PR-URL: https://github.com/nodejs/node/pull/4777 Reviewed-By: Ben Noordhuis diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 2e8fd2c..1b3d618 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -18,10 +18,11 @@ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. #include "node.h" +#include "node_buffer.h" #include "node_internals.h" #include "node_watchdog.h" #include "base-object.h" #include "base-object-inl.h" #include "env.h" @@ -484,28 +485,60 @@ class ContextifyScript : public BaseObject { TryCatch try_catch; Local code = args[0]->ToString(); Local filename = GetFilenameArg(args, 1); bool display_errors = GetDisplayErrorsArg(args, 1); + Local cached_data_buf = GetCachedData(args, 1); + bool produce_cached_data = GetProduceCachedData(args, 1); if (try_catch.HasCaught()) { try_catch.ReThrow(); return; } + ScriptCompiler::CachedData* cached_data = NULL; + if (!cached_data_buf.IsEmpty()) { + cached_data = new ScriptCompiler::CachedData( + reinterpret_cast(Buffer::Data(cached_data_buf)), + Buffer::Length(cached_data_buf)); + } + ScriptOrigin origin(filename); - ScriptCompiler::Source source(code, origin); - Local v8_script = - ScriptCompiler::CompileUnbound(env->isolate(), &source); + ScriptCompiler::Source source(code, origin, cached_data); + ScriptCompiler::CompileOptions compile_options = + ScriptCompiler::kNoCompileOptions; + + if (source.GetCachedData() != NULL) + compile_options = ScriptCompiler::kConsumeCodeCache; + else if (produce_cached_data) + compile_options = ScriptCompiler::kProduceCodeCache; + + Local v8_script = ScriptCompiler::CompileUnbound( + env->isolate(), + &source, + compile_options); if (v8_script.IsEmpty()) { if (display_errors) { AppendExceptionLine(env, try_catch.Exception(), try_catch.Message()); } try_catch.ReThrow(); return; } contextify_script->script_.Reset(env->isolate(), v8_script); + + if (compile_options == ScriptCompiler::kConsumeCodeCache) { + // no 'rejected' field in cachedData + } else if (compile_options == ScriptCompiler::kProduceCodeCache) { + const ScriptCompiler::CachedData* cached_data = source.GetCachedData(); + Local buf = Buffer::New( + env, + reinterpret_cast(cached_data->data), + cached_data->length); + Local cached_data_string = FIXED_ONE_BYTE_STRING( + args.GetIsolate(), "cachedData"); + args.This()->Set(cached_data_string, buf); + } } static bool InstanceOf(Environment* env, const Local& value) { return !value.IsEmpty() && @@ -656,10 +689,46 @@ class ContextifyScript : public BaseObject { return value->IsUndefined() ? defaultFilename : value->ToString(); } + static Local GetCachedData( + const FunctionCallbackInfo& args, + const int i) { + if (!args[i]->IsObject()) { + return Local(); + } + Local key = FIXED_ONE_BYTE_STRING(args.GetIsolate(), "cachedData"); + Local value = args[i].As()->Get(key); + if (value->IsUndefined()) { + return Local(); + } + + if (!Buffer::HasInstance(value)) { + Environment::ThrowTypeError( + args.GetIsolate(), + "options.cachedData must be a Buffer instance"); + return Local(); + } + + return value; + } + + + static bool GetProduceCachedData( + const FunctionCallbackInfo& args, + const int i) { + if (!args[i]->IsObject()) { + return false; + } + Local key = FIXED_ONE_BYTE_STRING(args.GetIsolate(), "produceCachedData"); + Local value = args[i].As()->Get(key); + + return value->IsTrue(); + } + + static bool EvalMachine(Environment* env, const int64_t timeout, const bool display_errors, const FunctionCallbackInfo& args, TryCatch& try_catch) {