| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 83e43fb commit 96934cb
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -38,6 +38,12 @@ The options when creating a script are: | |||
| 38 | 38 | code are controlled by the options to the script's methods. | |
| 39 | 39 | - `timeout`: a number of milliseconds to execute `code` before terminating | |
| 40 | 40 | execution. If execution is terminated, an [`Error`][] will be thrown. | |
| 41 | + - `cachedData`: an optional `Buffer` with V8's code cache data for the supplied | ||
| 42 | + source. When supplied `cachedDataRejected` value will be set to either | ||
| 43 | + `true` or `false` depending on acceptance of the data by V8. | ||
| 44 | + - `produceCachedData`: if `true` and no `cachedData` is present - a `Buffer` | ||
| 45 | + with V8's code cache data will be produced and stored in `cachedData` property | ||
| 46 | + of the returned `vm.Script` instance. | ||
| 41 | 47 | ||
| 42 | 48 | ### script.runInContext(contextifiedSandbox[, options]) | |
| 43 | 49 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -61,6 +61,8 @@ namespace node { | |||
| 61 | 61 | V(buffer_string, "buffer") \ | |
| 62 | 62 | V(bytes_string, "bytes") \ | |
| 63 | 63 | V(bytes_parsed_string, "bytesParsed") \ | |
| 64 | + V(cached_data_string, "cachedData") \ | ||
| 65 | + V(cached_data_rejected_string, "cachedDataRejected") \ | ||
| 64 | 66 | V(callback_string, "callback") \ | |
| 65 | 67 | V(change_string, "change") \ | |
| 66 | 68 | V(oncertcb_string, "oncertcb") \ | |
@@ -175,6 +177,7 @@ namespace node { | |||
| 175 | 177 | V(preference_string, "preference") \ | |
| 176 | 178 | V(priority_string, "priority") \ | |
| 177 | 179 | V(processed_string, "processed") \ | |
| 180 | + V(produce_cached_data_string, "produceCachedData") \ | ||
| 178 | 181 | V(prototype_string, "prototype") \ | |
| 179 | 182 | V(raw_string, "raw") \ | |
| 180 | 183 | V(rdev_string, "rdev") \ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -13,6 +13,7 @@ namespace node { | |||
| 13 | 13 | ||
| 14 | 14 | using v8::AccessType; | |
| 15 | 15 | using v8::Array; | |
| 16 | + using v8::ArrayBuffer; | ||
| 16 | 17 | using v8::Boolean; | |
| 17 | 18 | using v8::Context; | |
| 18 | 19 | using v8::Debug; | |
@@ -40,6 +41,7 @@ using v8::ScriptCompiler; | |||
| 40 | 41 | using v8::ScriptOrigin; | |
| 41 | 42 | using v8::String; | |
| 42 | 43 | using v8::TryCatch; | |
| 44 | + using v8::Uint8Array; | ||
| 43 | 45 | using v8::UnboundScript; | |
| 44 | 46 | using v8::V8; | |
| 45 | 47 | using v8::Value; | |
@@ -507,15 +509,35 @@ class ContextifyScript : public BaseObject { | |||
| 507 | 509 | Local<Integer> lineOffset = GetLineOffsetArg(args, 1); | |
| 508 | 510 | Local<Integer> columnOffset = GetColumnOffsetArg(args, 1); | |
| 509 | 511 | bool display_errors = GetDisplayErrorsArg(args, 1); | |
| 512 | + MaybeLocal<Uint8Array> cached_data_buf = GetCachedData(env, args, 1); | ||
| 513 | + bool produce_cached_data = GetProduceCachedData(env, args, 1); | ||
| 510 | 514 | if (try_catch.HasCaught()) { | |
| 511 | 515 | try_catch.ReThrow(); | |
| 512 | 516 | return; | |
| 513 | 517 | } | |
| 514 | 518 | ||
| 519 | + ScriptCompiler::CachedData* cached_data = nullptr; | ||
| 520 | + if (!cached_data_buf.IsEmpty()) { | ||
| 521 | + ArrayBuffer::Contents contents = | ||
| 522 | + cached_data_buf.ToLocalChecked()->Buffer()->GetContents(); | ||
| 523 | + cached_data = new ScriptCompiler::CachedData( | ||
| 524 | + static_cast<uint8_t*>(contents.Data()), contents.ByteLength()); | ||
| 525 | + } | ||
| 526 | + | ||
| 515 | 527 | ScriptOrigin origin(filename, lineOffset, columnOffset); | |
| 516 | - ScriptCompiler::Source source(code, origin); | ||
| 517 | - Local<UnboundScript> v8_script = | ||
| 518 | - ScriptCompiler::CompileUnbound(env->isolate(), &source); | ||
| 528 | + ScriptCompiler::Source source(code, origin, cached_data); | ||
| 529 | + ScriptCompiler::CompileOptions compile_options = | ||
| 530 | + ScriptCompiler::kNoCompileOptions; | ||
| 531 | + | ||
| 532 | + if (source.GetCachedData() != nullptr) | ||
| 533 | + compile_options = ScriptCompiler::kConsumeCodeCache; | ||
| 534 | + else if (produce_cached_data) | ||
| 535 | + compile_options = ScriptCompiler::kProduceCodeCache; | ||
| 536 | + | ||
| 537 | + Local<UnboundScript> v8_script = ScriptCompiler::CompileUnbound( | ||
| 538 | + env->isolate(), | ||
| 539 | + &source, | ||
| 540 | + compile_options); | ||
| 519 | 541 | ||
| 520 | 542 | if (v8_script.IsEmpty()) { | |
| 521 | 543 | if (display_errors) { | |
@@ -525,6 +547,19 @@ class ContextifyScript : public BaseObject { | |||
| 525 | 547 | return; | |
| 526 | 548 | } | |
| 527 | 549 | contextify_script->script_.Reset(env->isolate(), v8_script); | |
| 550 | + | ||
| 551 | + if (compile_options == ScriptCompiler::kConsumeCodeCache) { | ||
| 552 | + args.This()->Set( | ||
| 553 | + env->cached_data_rejected_string(), | ||
| 554 | + Boolean::New(env->isolate(), source.GetCachedData()->rejected)); | ||
| 555 | + } else if (compile_options == ScriptCompiler::kProduceCodeCache) { | ||
| 556 | + const ScriptCompiler::CachedData* cached_data = source.GetCachedData(); | ||
| 557 | + MaybeLocal<Object> buf = Buffer::Copy( | ||
| 558 | + env, | ||
| 559 | + reinterpret_cast<const char*>(cached_data->data), | ||
| 560 | + cached_data->length); | ||
| 561 | + args.This()->Set(env->cached_data_string(), buf.ToLocalChecked()); | ||
| 562 | + } | ||
| 528 | 563 | } | |
| 529 | 564 | ||
| 530 | 565 | ||
@@ -677,6 +712,43 @@ class ContextifyScript : public BaseObject { | |||
| 677 | 712 | } | |
| 678 | 713 | ||
| 679 | 714 | ||
| 715 | + static MaybeLocal<Uint8Array> GetCachedData( | ||
| 716 | + Environment* env, | ||
| 717 | + const FunctionCallbackInfo<Value>& args, | ||
| 718 | + const int i) { | ||
| 719 | + if (!args[i]->IsObject()) { | ||
| 720 | + return MaybeLocal<Uint8Array>(); | ||
| 721 | + } | ||
| 722 | + Local<Value> value = args[i].As<Object>()->Get(env->cached_data_string()); | ||
| 723 | + if (value->IsUndefined()) { | ||
| 724 | + return MaybeLocal<Uint8Array>(); | ||
| 725 | + } | ||
| 726 | + | ||
| 727 | + if (!value->IsUint8Array()) { | ||
| 728 | + Environment::ThrowTypeError( | ||
| 729 | + args.GetIsolate(), | ||
| 730 | + "options.cachedData must be a Buffer instance"); | ||
| 731 | + return MaybeLocal<Uint8Array>(); | ||
| 732 | + } | ||
| 733 | + | ||
| 734 | + return value.As<Uint8Array>(); | ||
| 735 | + } | ||
| 736 | + | ||
| 737 | + | ||
| 738 | + static bool GetProduceCachedData( | ||
| 739 | + Environment* env, | ||
| 740 | + const FunctionCallbackInfo<Value>& args, | ||
| 741 | + const int i) { | ||
| 742 | + if (!args[i]->IsObject()) { | ||
| 743 | + return false; | ||
| 744 | + } | ||
| 745 | + Local<Value> value = | ||
| 746 | + args[i].As<Object>()->Get(env->produce_cached_data_string()); | ||
| 747 | + | ||
| 748 | + return value->IsTrue(); | ||
| 749 | + } | ||
| 750 | + | ||
| 751 | + | ||
| 680 | 752 | static Local<Integer> GetLineOffsetArg( | |
| 681 | 753 | const FunctionCallbackInfo<Value>& args, | |
| 682 | 754 | const int i) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,37 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + require('../common'); | ||
| 3 | + const assert = require('assert'); | ||
| 4 | + const vm = require('vm'); | ||
| 5 | + const Buffer = require('buffer').Buffer; | ||
| 6 | + | ||
| 7 | + const originalSource = '(function bcd() { return \'original\'; })'; | ||
| 8 | + | ||
| 9 | + // It should produce code cache | ||
| 10 | + const original = new vm.Script(originalSource, { | ||
| 11 | + produceCachedData: true | ||
| 12 | + }); | ||
| 13 | + assert(original.cachedData instanceof Buffer); | ||
| 14 | + | ||
| 15 | + assert.equal(original.runInThisContext()(), 'original'); | ||
| 16 | + | ||
| 17 | + // It should consume code cache | ||
| 18 | + const success = new vm.Script(originalSource, { | ||
| 19 | + cachedData: original.cachedData | ||
| 20 | + }); | ||
| 21 | + assert(!success.cachedDataRejected); | ||
| 22 | + | ||
| 23 | + assert.equal(success.runInThisContext()(), 'original'); | ||
| 24 | + | ||
| 25 | + // It should reject invalid code cache | ||
| 26 | + const reject = new vm.Script('(function abc() { return \'invalid\'; })', { | ||
| 27 | + cachedData: original.cachedData | ||
| 28 | + }); | ||
| 29 | + assert(reject.cachedDataRejected); | ||
| 30 | + assert.equal(reject.runInThisContext()(), 'invalid'); | ||
| 31 | + | ||
| 32 | + // It should throw on non-Buffer cachedData | ||
| 33 | + assert.throws(() => { | ||
| 34 | + new vm.Script('function abc() {}', { | ||
| 35 | + cachedData: 'ohai' | ||
| 36 | + }); | ||
| 37 | + }); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments