| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e24cd92 commit 2937a79
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -637,6 +637,34 @@ console.log(globalVar); | |||
| 637 | 637 | // 1000 | |
| 638 | 638 | ``` | |
| 639 | 639 | ||
| 640 | + ## vm.compileFunction(code[, params[, options]]) | ||
| 641 | + <!-- YAML | ||
| 642 | + added: REPLACEME | ||
| 643 | + --> | ||
| 644 | + * `code` {string} The body of the function to compile. | ||
| 645 | + * `params` {string[]} An array of strings containing all parameters for the | ||
| 646 | + function. | ||
| 647 | + * `options` {Object} | ||
| 648 | + * `filename` {string} Specifies the filename used in stack traces produced | ||
| 649 | + by this script. **Default:** `''`. | ||
| 650 | + * `lineOffset` {number} Specifies the line number offset that is displayed | ||
| 651 | + in stack traces produced by this script. **Default:** `0`. | ||
| 652 | + * `columnOffset` {number} Specifies the column number offset that is displayed | ||
| 653 | + in stack traces produced by this script. **Default:** `0`. | ||
| 654 | + * `cachedData` {Buffer} Provides an optional `Buffer` with V8's code cache | ||
| 655 | + data for the supplied source. | ||
| 656 | + * `produceCachedData` {boolean} Specifies whether to produce new cache data. | ||
| 657 | + **Default:** `false`. | ||
| 658 | + * `parsingContext` {Object} The sandbox/context in which the said function | ||
| 659 | + should be compiled in. | ||
| 660 | + * `contextExtensions` {Object[]} An array containing a collection of context | ||
| 661 | + extensions (objects wrapping the current scope) to be applied while | ||
| 662 | + compiling. **Default:** `[]`. | ||
| 663 | + | ||
| 664 | + Compiles the given code into the provided context/sandbox (if no context is | ||
| 665 | + supplied, the current context is used), and returns it wrapped inside a | ||
| 666 | + function with the given `params`. | ||
| 667 | + | ||
| 640 | 668 | ## vm.createContext([sandbox[, options]]) | |
| 641 | 669 | <!-- YAML | |
| 642 | 670 | added: v0.3.1 | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -25,14 +25,20 @@ const { | |||
| 25 | 25 | ContextifyScript, | |
| 26 | 26 | makeContext, | |
| 27 | 27 | isContext: _isContext, | |
| 28 | + compileFunction: _compileFunction | ||
| 28 | 29 | } = process.binding('contextify'); | |
| 30 | + | ||
| 29 | 31 | const { | |
| 30 | 32 | ERR_INVALID_ARG_TYPE, | |
| 31 | 33 | ERR_OUT_OF_RANGE | |
| 32 | 34 | } = require('internal/errors').codes; | |
| 33 | 35 | const { isUint8Array } = require('internal/util/types'); | |
| 36 | + const { validateUint32 } = require('internal/validators'); | ||
| 34 | 37 | const kParsingContext = Symbol('script parsing context'); | |
| 35 | 38 | ||
| 39 | + const ArrayForEach = Function.call.bind(Array.prototype.forEach); | ||
| 40 | + const ArrayIsArray = Array.isArray; | ||
| 41 | + | ||
| 36 | 42 | class Script extends ContextifyScript { | |
| 37 | 43 | constructor(code, options = {}) { | |
| 38 | 44 | code = `${code}`; | |
@@ -297,6 +303,94 @@ function runInThisContext(code, options) { | |||
| 297 | 303 | return createScript(code, options).runInThisContext(options); | |
| 298 | 304 | } | |
| 299 | 305 | ||
| 306 | + function compileFunction(code, params, options = {}) { | ||
| 307 | + if (typeof code !== 'string') { | ||
| 308 | + throw new ERR_INVALID_ARG_TYPE('code', 'string', code); | ||
| 309 | + } | ||
| 310 | + if (params !== undefined) { | ||
| 311 | + if (!ArrayIsArray(params)) { | ||
| 312 | + throw new ERR_INVALID_ARG_TYPE('params', 'Array', params); | ||
| 313 | + } | ||
| 314 | + ArrayForEach(params, (param, i) => { | ||
| 315 | + if (typeof param !== 'string') { | ||
| 316 | + throw new ERR_INVALID_ARG_TYPE(`params[${i}]`, 'string', param); | ||
| 317 | + } | ||
| 318 | + }); | ||
| 319 | + } | ||
| 320 | + | ||
| 321 | + const { | ||
| 322 | + filename = '', | ||
| 323 | + columnOffset = 0, | ||
| 324 | + lineOffset = 0, | ||
| 325 | + cachedData = undefined, | ||
| 326 | + produceCachedData = false, | ||
| 327 | + parsingContext = undefined, | ||
| 328 | + contextExtensions = [], | ||
| 329 | + } = options; | ||
| 330 | + | ||
| 331 | + if (typeof filename !== 'string') { | ||
| 332 | + throw new ERR_INVALID_ARG_TYPE('options.filename', 'string', filename); | ||
| 333 | + } | ||
| 334 | + validateUint32(columnOffset, 'options.columnOffset'); | ||
| 335 | + validateUint32(lineOffset, 'options.lineOffset'); | ||
| 336 | + if (cachedData !== undefined && !isUint8Array(cachedData)) { | ||
| 337 | + throw new ERR_INVALID_ARG_TYPE( | ||
| 338 | + 'options.cachedData', | ||
| 339 | + 'Uint8Array', | ||
| 340 | + cachedData | ||
| 341 | + ); | ||
| 342 | + } | ||
| 343 | + if (typeof produceCachedData !== 'boolean') { | ||
| 344 | + throw new ERR_INVALID_ARG_TYPE( | ||
| 345 | + 'options.produceCachedData', | ||
| 346 | + 'boolean', | ||
| 347 | + produceCachedData | ||
| 348 | + ); | ||
| 349 | + } | ||
| 350 | + if (parsingContext !== undefined) { | ||
| 351 | + if ( | ||
| 352 | + typeof parsingContext !== 'object' || | ||
| 353 | + parsingContext === null || | ||
| 354 | + !isContext(parsingContext) | ||
| 355 | + ) { | ||
| 356 | + throw new ERR_INVALID_ARG_TYPE( | ||
| 357 | + 'options.parsingContext', | ||
| 358 | + 'Context', | ||
| 359 | + parsingContext | ||
| 360 | + ); | ||
| 361 | + } | ||
| 362 | + } | ||
| 363 | + if (!ArrayIsArray(contextExtensions)) { | ||
| 364 | + throw new ERR_INVALID_ARG_TYPE( | ||
| 365 | + 'options.contextExtensions', | ||
| 366 | + 'Array', | ||
| 367 | + contextExtensions | ||
| 368 | + ); | ||
| 369 | + } | ||
| 370 | + ArrayForEach(contextExtensions, (extension, i) => { | ||
| 371 | + if (typeof extension !== 'object') { | ||
| 372 | + throw new ERR_INVALID_ARG_TYPE( | ||
| 373 | + `options.contextExtensions[${i}]`, | ||
| 374 | + 'object', | ||
| 375 | + extension | ||
| 376 | + ); | ||
| 377 | + } | ||
| 378 | + }); | ||
| 379 | + | ||
| 380 | + return _compileFunction( | ||
| 381 | + code, | ||
| 382 | + filename, | ||
| 383 | + lineOffset, | ||
| 384 | + columnOffset, | ||
| 385 | + cachedData, | ||
| 386 | + produceCachedData, | ||
| 387 | + parsingContext, | ||
| 388 | + contextExtensions, | ||
| 389 | + params | ||
| 390 | + ); | ||
| 391 | + } | ||
| 392 | + | ||
| 393 | + | ||
| 300 | 394 | module.exports = { | |
| 301 | 395 | Script, | |
| 302 | 396 | createContext, | |
@@ -305,6 +399,7 @@ module.exports = { | |||
| 305 | 399 | runInNewContext, | |
| 306 | 400 | runInThisContext, | |
| 307 | 401 | isContext, | |
| 402 | + compileFunction, | ||
| 308 | 403 | }; | |
| 309 | 404 | ||
| 310 | 405 | if (process.binding('config').experimentalVMModules) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -208,6 +208,7 @@ void ContextifyContext::Init(Environment* env, Local<Object> target) { | |||
| 208 | 208 | ||
| 209 | 209 | env->SetMethod(target, "makeContext", MakeContext); | |
| 210 | 210 | env->SetMethod(target, "isContext", IsContext); | |
| 211 | + env->SetMethod(target, "compileFunction", CompileFunction); | ||
| 211 | 212 | } | |
| 212 | 213 | ||
| 213 | 214 | ||
@@ -986,6 +987,144 @@ class ContextifyScript : public BaseObject { | |||
| 986 | 987 | }; | |
| 987 | 988 | ||
| 988 | 989 | ||
| 990 | + void ContextifyContext::CompileFunction( | ||
| 991 | + const FunctionCallbackInfo<Value>& args) { | ||
| 992 | + Environment* env = Environment::GetCurrent(args); | ||
| 993 | + Isolate* isolate = env->isolate(); | ||
| 994 | + Local<Context> context = env->context(); | ||
| 995 | + | ||
| 996 | + // Argument 1: source code | ||
| 997 | + CHECK(args[0]->IsString()); | ||
| 998 | + Local<String> code = args[0].As<String>(); | ||
| 999 | + | ||
| 1000 | + // Argument 2: filename | ||
| 1001 | + CHECK(args[1]->IsString()); | ||
| 1002 | + Local<String> filename = args[1].As<String>(); | ||
| 1003 | + | ||
| 1004 | + // Argument 3: line offset | ||
| 1005 | + CHECK(args[2]->IsNumber()); | ||
| 1006 | + Local<Integer> line_offset = args[2].As<Integer>(); | ||
| 1007 | + | ||
| 1008 | + // Argument 4: column offset | ||
| 1009 | + CHECK(args[3]->IsNumber()); | ||
| 1010 | + Local<Integer> column_offset = args[3].As<Integer>(); | ||
| 1011 | + | ||
| 1012 | + // Argument 5: cached data (optional) | ||
| 1013 | + Local<Uint8Array> cached_data_buf; | ||
| 1014 | + if (!args[4]->IsUndefined()) { | ||
| 1015 | + CHECK(args[4]->IsUint8Array()); | ||
| 1016 | + cached_data_buf = args[4].As<Uint8Array>(); | ||
| 1017 | + } | ||
| 1018 | + | ||
| 1019 | + // Argument 6: produce cache data | ||
| 1020 | + CHECK(args[5]->IsBoolean()); | ||
| 1021 | + bool produce_cached_data = args[5]->IsTrue(); | ||
| 1022 | + | ||
| 1023 | + // Argument 7: parsing context (optional) | ||
| 1024 | + Local<Context> parsing_context; | ||
| 1025 | + if (!args[6]->IsUndefined()) { | ||
| 1026 | + CHECK(args[6]->IsObject()); | ||
| 1027 | + ContextifyContext* sandbox = | ||
| 1028 | + ContextifyContext::ContextFromContextifiedSandbox( | ||
| 1029 | + env, args[6].As<Object>()); | ||
| 1030 | + CHECK_NOT_NULL(sandbox); | ||
| 1031 | + parsing_context = sandbox->context(); | ||
| 1032 | + } else { | ||
| 1033 | + parsing_context = context; | ||
| 1034 | + } | ||
| 1035 | + | ||
| 1036 | + // Argument 8: context extensions (optional) | ||
| 1037 | + Local<Array> context_extensions_buf; | ||
| 1038 | + if (!args[7]->IsUndefined()) { | ||
| 1039 | + CHECK(args[7]->IsArray()); | ||
| 1040 | + context_extensions_buf = args[7].As<Array>(); | ||
| 1041 | + } | ||
| 1042 | + | ||
| 1043 | + // Argument 9: params for the function (optional) | ||
| 1044 | + Local<Array> params_buf; | ||
| 1045 | + if (!args[8]->IsUndefined()) { | ||
| 1046 | + CHECK(args[8]->IsArray()); | ||
| 1047 | + params_buf = args[8].As<Array>(); | ||
| 1048 | + } | ||
| 1049 | + | ||
| 1050 | + // Read cache from cached data buffer | ||
| 1051 | + ScriptCompiler::CachedData* cached_data = nullptr; | ||
| 1052 | + if (!cached_data_buf.IsEmpty()) { | ||
| 1053 | + ArrayBuffer::Contents contents = cached_data_buf->Buffer()->GetContents(); | ||
| 1054 | + uint8_t* data = static_cast<uint8_t*>(contents.Data()); | ||
| 1055 | + cached_data = new ScriptCompiler::CachedData( | ||
| 1056 | + data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength()); | ||
| 1057 | + } | ||
| 1058 | + | ||
| 1059 | + ScriptOrigin origin(filename, line_offset, column_offset); | ||
| 1060 | + ScriptCompiler::Source source(code, origin, cached_data); | ||
| 1061 | + ScriptCompiler::CompileOptions options; | ||
| 1062 | + if (source.GetCachedData() == nullptr) { | ||
| 1063 | + options = ScriptCompiler::kNoCompileOptions; | ||
| 1064 | + } else { | ||
| 1065 | + options = ScriptCompiler::kConsumeCodeCache; | ||
| 1066 | + } | ||
| 1067 | + | ||
| 1068 | + TryCatch try_catch(isolate); | ||
| 1069 | + Context::Scope scope(parsing_context); | ||
| 1070 | + | ||
| 1071 | + // Read context extensions from buffer | ||
| 1072 | + std::vector<Local<Object>> context_extensions; | ||
| 1073 | + if (!context_extensions_buf.IsEmpty()) { | ||
| 1074 | + for (uint32_t n = 0; n < context_extensions_buf->Length(); n++) { | ||
| 1075 | + Local<Value> val; | ||
| 1076 | + if (!context_extensions_buf->Get(context, n).ToLocal(&val)) return; | ||
| 1077 | + CHECK(val->IsObject()); | ||
| 1078 | + context_extensions.push_back(val.As<Object>()); | ||
| 1079 | + } | ||
| 1080 | + } | ||
| 1081 | + | ||
| 1082 | + // Read params from params buffer | ||
| 1083 | + std::vector<Local<String>> params; | ||
| 1084 | + if (!params_buf.IsEmpty()) { | ||
| 1085 | + for (uint32_t n = 0; n < params_buf->Length(); n++) { | ||
| 1086 | + Local<Value> val; | ||
| 1087 | + if (!params_buf->Get(context, n).ToLocal(&val)) return; | ||
| 1088 | + CHECK(val->IsString()); | ||
| 1089 | + params.push_back(val.As<String>()); | ||
| 1090 | + } | ||
| 1091 | + } | ||
| 1092 | + | ||
| 1093 | + MaybeLocal<Function> maybe_fun = ScriptCompiler::CompileFunctionInContext( | ||
| 1094 | + context, &source, params.size(), params.data(), | ||
| 1095 | + context_extensions.size(), context_extensions.data(), options); | ||
| 1096 | + | ||
| 1097 | + Local<Function> fun; | ||
| 1098 | + if (maybe_fun.IsEmpty() || !maybe_fun.ToLocal(&fun)) { | ||
| 1099 | + ContextifyScript::DecorateErrorStack(env, try_catch); | ||
| 1100 | + try_catch.ReThrow(); | ||
| 1101 | + return; | ||
| 1102 | + } | ||
| 1103 | + | ||
| 1104 | + if (produce_cached_data) { | ||
| 1105 | + const std::unique_ptr<ScriptCompiler::CachedData> | ||
| 1106 | + cached_data(ScriptCompiler::CreateCodeCacheForFunction(fun, code)); | ||
| 1107 | + bool cached_data_produced = cached_data != nullptr; | ||
| 1108 | + if (cached_data_produced) { | ||
| 1109 | + MaybeLocal<Object> buf = Buffer::Copy( | ||
| 1110 | + env, | ||
| 1111 | + reinterpret_cast<const char*>(cached_data->data), | ||
| 1112 | + cached_data->length); | ||
| 1113 | + if (fun->Set( | ||
| 1114 | + parsing_context, | ||
| 1115 | + env->cached_data_string(), | ||
| 1116 | + buf.ToLocalChecked()).IsNothing()) return; | ||
| 1117 | + } | ||
| 1118 | + if (fun->Set( | ||
| 1119 | + parsing_context, | ||
| 1120 | + env->cached_data_produced_string(), | ||
| 1121 | + Boolean::New(isolate, cached_data_produced)).IsNothing()) return; | ||
| 1122 | + } | ||
| 1123 | + | ||
| 1124 | + args.GetReturnValue().Set(fun); | ||
| 1125 | + } | ||
| 1126 | + | ||
| 1127 | + | ||
| 989 | 1128 | void Initialize(Local<Object> target, | |
| 990 | 1129 | Local<Value> unused, | |
| 991 | 1130 | Local<Context> context) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -58,6 +58,8 @@ class ContextifyContext { | |||
| 58 | 58 | private: | |
| 59 | 59 | static void MakeContext(const v8::FunctionCallbackInfo<v8::Value>& args); | |
| 60 | 60 | static void IsContext(const v8::FunctionCallbackInfo<v8::Value>& args); | |
| 61 | + static void CompileFunction( | ||
| 62 | + const v8::FunctionCallbackInfo<v8::Value>& args); | ||
| 61 | 63 | static void WeakCallback( | |
| 62 | 64 | const v8::WeakCallbackInfo<ContextifyContext>& data); | |
| 63 | 65 | static void PropertyGetterCallback( | |
| Back | FazBrowse Home | New Git URL |
0 commit comments