@@ -209,6 +209,7 @@ void ContextifyContext::Init(Environment* env, Local<Object> target) {
209209
210210 env->SetMethod (target, " makeContext" , MakeContext);
211211 env->SetMethod (target, " isContext" , IsContext);
212+ env->SetMethod (target, " compileFunction" , CompileFunction);
212213}
213214
214215
@@ -987,6 +988,144 @@ class ContextifyScript : public BaseObject {
987988};
988989
989990
991+ void ContextifyContext::CompileFunction (
992+ const FunctionCallbackInfo<Value>& args) {
993+ Environment* env = Environment::GetCurrent (args);
994+ Isolate* isolate = env->isolate ();
995+ Local<Context> context = env->context ();
996+
997+ // Argument 1: source code
998+ CHECK (args[0 ]->IsString ());
999+ Local<String> code = args[0 ].As <String>();
1000+
1001+ // Argument 2: filename
1002+ CHECK (args[1 ]->IsString ());
1003+ Local<String> filename = args[1 ].As <String>();
1004+
1005+ // Argument 3: line offset
1006+ CHECK (args[2 ]->IsNumber ());
1007+ Local<Integer> line_offset = args[2 ].As <Integer>();
1008+
1009+ // Argument 4: column offset
1010+ CHECK (args[3 ]->IsNumber ());
1011+ Local<Integer> column_offset = args[3 ].As <Integer>();
1012+
1013+ // Argument 5: cached data (optional)
1014+ Local<Uint8Array> cached_data_buf;
1015+ if (!args[4 ]->IsUndefined ()) {
1016+ CHECK (args[4 ]->IsUint8Array ());
1017+ cached_data_buf = args[4 ].As <Uint8Array>();
1018+ }
1019+
1020+ // Argument 6: produce cache data
1021+ CHECK (args[5 ]->IsBoolean ());
1022+ bool produce_cached_data = args[5 ]->IsTrue ();
1023+
1024+ // Argument 7: parsing context (optional)
1025+ Local<Context> parsing_context;
1026+ if (!args[6 ]->IsUndefined ()) {
1027+ CHECK (args[6 ]->IsObject ());
1028+ ContextifyContext* sandbox =
1029+ ContextifyContext::ContextFromContextifiedSandbox (
1030+ env, args[6 ].As <Object>());
1031+ CHECK_NOT_NULL (sandbox);
1032+ parsing_context = sandbox->context ();
1033+ } else {
1034+ parsing_context = context;
1035+ }
1036+
1037+ // Argument 8: context extensions (optional)
1038+ Local<Array> context_extensions_buf;
1039+ if (!args[7 ]->IsUndefined ()) {
1040+ CHECK (args[7 ]->IsArray ());
1041+ context_extensions_buf = args[7 ].As <Array>();
1042+ }
1043+
1044+ // Argument 9: params for the function (optional)
1045+ Local<Array> params_buf;
1046+ if (!args[8 ]->IsUndefined ()) {
1047+ CHECK (args[8 ]->IsArray ());
1048+ params_buf = args[8 ].As <Array>();
1049+ }
1050+
1051+ // Read cache from cached data buffer
1052+ ScriptCompiler::CachedData* cached_data = nullptr ;
1053+ if (!cached_data_buf.IsEmpty ()) {
1054+ ArrayBuffer::Contents contents = cached_data_buf->Buffer ()->GetContents ();
1055+ uint8_t * data = static_cast <uint8_t *>(contents.Data ());
1056+ cached_data = new ScriptCompiler::CachedData (
1057+ data + cached_data_buf->ByteOffset (), cached_data_buf->ByteLength ());
1058+ }
1059+
1060+ ScriptOrigin origin (filename, line_offset, column_offset);
1061+ ScriptCompiler::Source source (code, origin, cached_data);
1062+ ScriptCompiler::CompileOptions options;
1063+ if (source.GetCachedData () == nullptr ) {
1064+ options = ScriptCompiler::kNoCompileOptions ;
1065+ } else {
1066+ options = ScriptCompiler::kConsumeCodeCache ;
1067+ }
1068+
1069+ TryCatch try_catch (isolate);
1070+ Context::Scope scope (parsing_context);
1071+
1072+ // Read context extensions from buffer
1073+ std::vector<Local<Object>> context_extensions;
1074+ if (!context_extensions_buf.IsEmpty ()) {
1075+ for (uint32_t n = 0 ; n < context_extensions_buf->Length (); n++) {
1076+ Local<Value> val;
1077+ if (!context_extensions_buf->Get (context, n).ToLocal (&val)) return ;
1078+ CHECK (val->IsObject ());
1079+ context_extensions.push_back (val.As <Object>());
1080+ }
1081+ }
1082+
1083+ // Read params from params buffer
1084+ std::vector<Local<String>> params;
1085+ if (!params_buf.IsEmpty ()) {
1086+ for (uint32_t n = 0 ; n < params_buf->Length (); n++) {
1087+ Local<Value> val;
1088+ if (!params_buf->Get (context, n).ToLocal (&val)) return ;
1089+ CHECK (val->IsString ());
1090+ params.push_back (val.As <String>());
1091+ }
1092+ }
1093+
1094+ MaybeLocal<Function> maybe_fun = ScriptCompiler::CompileFunctionInContext (
1095+ context, &source, params.size (), params.data (),
1096+ context_extensions.size (), context_extensions.data (), options);
1097+
1098+ Local<Function> fun;
1099+ if (maybe_fun.IsEmpty () || !maybe_fun.ToLocal (&fun)) {
1100+ ContextifyScript::DecorateErrorStack (env, try_catch);
1101+ try_catch.ReThrow ();
1102+ return ;
1103+ }
1104+
1105+ if (produce_cached_data) {
1106+ const std::unique_ptr<ScriptCompiler::CachedData>
1107+ cached_data (ScriptCompiler::CreateCodeCacheForFunction (fun, code));
1108+ bool cached_data_produced = cached_data != nullptr ;
1109+ if (cached_data_produced) {
1110+ MaybeLocal<Object> buf = Buffer::Copy (
1111+ env,
1112+ reinterpret_cast <const char *>(cached_data->data ),
1113+ cached_data->length );
1114+ if (fun->Set (
1115+ parsing_context,
1116+ env->cached_data_string (),
1117+ buf.ToLocalChecked ()).IsNothing ()) return ;
1118+ }
1119+ if (fun->Set (
1120+ parsing_context,
1121+ env->cached_data_produced_string (),
1122+ Boolean::New (isolate, cached_data_produced)).IsNothing ()) return ;
1123+ }
1124+
1125+ args.GetReturnValue ().Set (fun);
1126+ }
1127+
1128+
9901129void Initialize (Local<Object> target,
9911130 Local<Value> unused,
9921131 Local<Context> context) {
0 commit comments