@@ -206,6 +206,7 @@ void ContextifyContext::Init(Environment* env, Local<Object> target) {
206206
207207 env->SetMethod (target, " makeContext" , MakeContext);
208208 env->SetMethod (target, " isContext" , IsContext);
209+ env->SetMethod (target, " compileFunction" , CompileFunction);
209210}
210211
211212
@@ -948,6 +949,144 @@ class ContextifyScript : public BaseObject {
948949};
949950
950951
952+ void ContextifyContext::CompileFunction (
953+ const FunctionCallbackInfo<Value>& args) {
954+ Environment* env = Environment::GetCurrent (args);
955+ Isolate* isolate = env->isolate ();
956+ Local<Context> context = env->context ();
957+
958+ // Argument 1: source code
959+ CHECK (args[0 ]->IsString ());
960+ Local<String> code = args[0 ].As <String>();
961+
962+ // Argument 2: filename
963+ CHECK (args[1 ]->IsString ());
964+ Local<String> filename = args[1 ].As <String>();
965+
966+ // Argument 3: line offset
967+ CHECK (args[2 ]->IsNumber ());
968+ Local<Integer> line_offset = args[2 ].As <Integer>();
969+
970+ // Argument 4: column offset
971+ CHECK (args[3 ]->IsNumber ());
972+ Local<Integer> column_offset = args[3 ].As <Integer>();
973+
974+ // Argument 5: cached data (optional)
975+ Local<Uint8Array> cached_data_buf;
976+ if (!args[4 ]->IsUndefined ()) {
977+ CHECK (args[4 ]->IsUint8Array ());
978+ cached_data_buf = args[4 ].As <Uint8Array>();
979+ }
980+
981+ // Argument 6: produce cache data
982+ CHECK (args[5 ]->IsBoolean ());
983+ bool produce_cached_data = args[5 ]->IsTrue ();
984+
985+ // Argument 7: parsing context (optional)
986+ Local<Context> parsing_context;
987+ if (!args[6 ]->IsUndefined ()) {
988+ CHECK (args[6 ]->IsObject ());
989+ ContextifyContext* sandbox =
990+ ContextifyContext::ContextFromContextifiedSandbox (
991+ env, args[6 ].As <Object>());
992+ CHECK_NOT_NULL (sandbox);
993+ parsing_context = sandbox->context ();
994+ } else {
995+ parsing_context = context;
996+ }
997+
998+ // Argument 8: context extensions (optional)
999+ Local<Array> context_extensions_buf;
1000+ if (!args[7 ]->IsUndefined ()) {
1001+ CHECK (args[7 ]->IsArray ());
1002+ context_extensions_buf = args[7 ].As <Array>();
1003+ }
1004+
1005+ // Argument 9: params for the function (optional)
1006+ Local<Array> params_buf;
1007+ if (!args[8 ]->IsUndefined ()) {
1008+ CHECK (args[8 ]->IsArray ());
1009+ params_buf = args[8 ].As <Array>();
1010+ }
1011+
1012+ // Read cache from cached data buffer
1013+ ScriptCompiler::CachedData* cached_data = nullptr ;
1014+ if (!cached_data_buf.IsEmpty ()) {
1015+ ArrayBuffer::Contents contents = cached_data_buf->Buffer ()->GetContents ();
1016+ uint8_t * data = static_cast <uint8_t *>(contents.Data ());
1017+ cached_data = new ScriptCompiler::CachedData (
1018+ data + cached_data_buf->ByteOffset (), cached_data_buf->ByteLength ());
1019+ }
1020+
1021+ ScriptOrigin origin (filename, line_offset, column_offset);
1022+ ScriptCompiler::Source source (code, origin, cached_data);
1023+ ScriptCompiler::CompileOptions options;
1024+ if (source.GetCachedData () == nullptr ) {
1025+ options = ScriptCompiler::kNoCompileOptions ;
1026+ } else {
1027+ options = ScriptCompiler::kConsumeCodeCache ;
1028+ }
1029+
1030+ TryCatch try_catch (isolate);
1031+ Context::Scope scope (parsing_context);
1032+
1033+ // Read context extensions from buffer
1034+ std::vector<Local<Object>> context_extensions;
1035+ if (!context_extensions_buf.IsEmpty ()) {
1036+ for (uint32_t n = 0 ; n < context_extensions_buf->Length (); n++) {
1037+ Local<Value> val;
1038+ if (!context_extensions_buf->Get (context, n).ToLocal (&val)) return ;
1039+ CHECK (val->IsObject ());
1040+ context_extensions.push_back (val.As <Object>());
1041+ }
1042+ }
1043+
1044+ // Read params from params buffer
1045+ std::vector<Local<String>> params;
1046+ if (!params_buf.IsEmpty ()) {
1047+ for (uint32_t n = 0 ; n < params_buf->Length (); n++) {
1048+ Local<Value> val;
1049+ if (!params_buf->Get (context, n).ToLocal (&val)) return ;
1050+ CHECK (val->IsString ());
1051+ params.push_back (val.As <String>());
1052+ }
1053+ }
1054+
1055+ MaybeLocal<Function> maybe_fun = ScriptCompiler::CompileFunctionInContext (
1056+ context, &source, params.size (), params.data (),
1057+ context_extensions.size (), context_extensions.data (), options);
1058+
1059+ Local<Function> fun;
1060+ if (maybe_fun.IsEmpty () || !maybe_fun.ToLocal (&fun)) {
1061+ ContextifyScript::DecorateErrorStack (env, try_catch);
1062+ try_catch.ReThrow ();
1063+ return ;
1064+ }
1065+
1066+ if (produce_cached_data) {
1067+ const std::unique_ptr<ScriptCompiler::CachedData>
1068+ cached_data (ScriptCompiler::CreateCodeCacheForFunction (fun, code));
1069+ bool cached_data_produced = cached_data != nullptr ;
1070+ if (cached_data_produced) {
1071+ MaybeLocal<Object> buf = Buffer::Copy (
1072+ env,
1073+ reinterpret_cast <const char *>(cached_data->data ),
1074+ cached_data->length );
1075+ if (fun->Set (
1076+ parsing_context,
1077+ env->cached_data_string (),
1078+ buf.ToLocalChecked ()).IsNothing ()) return ;
1079+ }
1080+ if (fun->Set (
1081+ parsing_context,
1082+ env->cached_data_produced_string (),
1083+ Boolean::New (isolate, cached_data_produced)).IsNothing ()) return ;
1084+ }
1085+
1086+ args.GetReturnValue ().Set (fun);
1087+ }
1088+
1089+
9511090void Initialize (Local<Object> target,
9521091 Local<Value> unused,
9531092 Local<Context> context) {
0 commit comments