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/env.h b/src/env.h index 7b6ffc8..5c99f80 100644 --- a/src/env.h +++ b/src/env.h @@ -53,10 +53,12 @@ namespace node { V(blocks_string, "blocks") \ V(buffer_string, "buffer") \ V(bytes_string, "bytes") \ V(bytes_parsed_string, "bytesParsed") \ V(bytes_read_string, "bytesRead") \ + V(cached_data_string, "cachedData") \ + V(cached_data_rejected_string, "cachedDataRejected") \ V(callback_string, "callback") \ V(change_string, "change") \ V(oncertcb_string, "oncertcb") \ V(onclose_string, "_onclose") \ V(code_string, "code") \ @@ -165,10 +167,11 @@ namespace node { V(pipe_string, "pipe") \ V(port_string, "port") \ V(preference_string, "preference") \ V(priority_string, "priority") \ V(processed_string, "processed") \ + V(produce_cached_data_string, "produceCachedData") \ V(prototype_string, "prototype") \ V(raw_string, "raw") \ V(rdev_string, "rdev") \ V(readable_string, "readable") \ V(received_shutdown_string, "receivedShutdown") \ diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 7404bbb..ecf9444 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -1,6 +1,7 @@ #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" @@ -11,10 +12,11 @@ namespace node { using v8::AccessType; using v8::Array; +using v8::ArrayBuffer; using v8::Boolean; using v8::Context; using v8::Debug; using v8::EscapableHandleScope; using v8::External; @@ -474,28 +476,61 @@ class ContextifyScript : public BaseObject { Local code = args[0]->ToString(env->isolate()); Local filename = GetFilenameArg(args, 1); Local lineOffset = GetLineOffsetArg(args, 1); Local columnOffset = GetColumnOffsetArg(args, 1); bool display_errors = GetDisplayErrorsArg(args, 1); + MaybeLocal cached_data_buf = GetCachedData(env, args, 1); + bool produce_cached_data = GetProduceCachedData(env, args, 1); if (try_catch.HasCaught()) { try_catch.ReThrow(); return; } + ScriptCompiler::CachedData* cached_data = nullptr; + if (!cached_data_buf.IsEmpty()) { + auto cached_data_local = cached_data_buf.ToLocalChecked(); + cached_data = new ScriptCompiler::CachedData( + reinterpret_cast(Buffer::Data(cached_data_local)), + Buffer::Length(cached_data_local)); + } + ScriptOrigin origin(filename, lineOffset, columnOffset); - 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() != nullptr) + 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) { + args.This()->Set( + env->cached_data_rejected_string(), + Boolean::New(env->isolate(), source.GetCachedData()->rejected)); + } else if (compile_options == ScriptCompiler::kProduceCodeCache) { + const ScriptCompiler::CachedData* cached_data = source.GetCachedData(); + MaybeLocal buf = Buffer::Copy( + env, + reinterpret_cast(cached_data->data), + cached_data->length); + args.This()->Set(env->cached_data_string(), buf.ToLocalChecked()); + } } static bool InstanceOf(Environment* env, const Local& value) { return !value.IsEmpty() && @@ -644,10 +679,47 @@ class ContextifyScript : public BaseObject { return defaultFilename; return value->ToString(args.GetIsolate()); } + static MaybeLocal GetCachedData( + Environment* env, + const FunctionCallbackInfo& args, + const int i) { + if (!args[i]->IsObject()) { + return MaybeLocal(); + } + Local value = args[i].As()->Get(env->cached_data_string()); + if (value->IsUndefined()) { + return MaybeLocal(); + } + + if (!Buffer::HasInstance(value)) { + Environment::ThrowTypeError( + args.GetIsolate(), + "options.cachedData must be a Buffer instance"); + return MaybeLocal(); + } + + return value; + } + + + static bool GetProduceCachedData( + Environment* env, + const FunctionCallbackInfo& args, + const int i) { + if (!args[i]->IsObject()) { + return false; + } + Local value = + args[i].As()->Get(env->produce_cached_data_string()); + + return value->IsTrue(); + } + + static Local GetLineOffsetArg( const FunctionCallbackInfo& args, const int i) { Local defaultLineOffset = Integer::New(args.GetIsolate(), 0);