GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/module_wrap.cc Lines: 25 442 5.7 %
Date: 2019-02-01 22:03:38 Branches: 0 292 0.0 %

Line Branch Exec Source
1
#include <algorithm>
2
#include <limits.h>  // PATH_MAX
3
#include <sys/stat.h>  // S_IFDIR
4
#include "module_wrap.h"
5
6
#include "env.h"
7
#include "node_errors.h"
8
#include "node_url.h"
9
#include "util-inl.h"
10
#include "node_contextify.h"
11
#include "node_watchdog.h"
12
13
namespace node {
14
namespace loader {
15
16
using errors::TryCatchScope;
17
18
using node::contextify::ContextifyContext;
19
using node::url::URL;
20
using node::url::URL_FLAGS_FAILED;
21
using v8::Array;
22
using v8::Context;
23
using v8::Function;
24
using v8::FunctionCallbackInfo;
25
using v8::FunctionTemplate;
26
using v8::HandleScope;
27
using v8::Integer;
28
using v8::IntegrityLevel;
29
using v8::Isolate;
30
using v8::JSON;
31
using v8::Just;
32
using v8::Local;
33
using v8::Maybe;
34
using v8::MaybeLocal;
35
using v8::Module;
36
using v8::Nothing;
37
using v8::Number;
38
using v8::Object;
39
using v8::PrimitiveArray;
40
using v8::Promise;
41
using v8::ScriptCompiler;
42
using v8::ScriptOrigin;
43
using v8::String;
44
using v8::Undefined;
45
using v8::Value;
46
47
static const char* const EXTENSIONS[] = {".mjs", ".js", ".json", ".node"};
48
49
ModuleWrap::ModuleWrap(Environment* env,
50
                       Local<Object> object,
51
                       Local<Module> module,
52
                       Local<String> url) :
53
  BaseObject(env, object),
54
  id_(env->get_next_module_id()) {
55
  module_.Reset(env->isolate(), module);
56
  url_.Reset(env->isolate(), url);
57
  env->id_to_module_map.emplace(id_, this);
58
}
59
60
ModuleWrap::~ModuleWrap() {
61
  HandleScope scope(env()->isolate());
62
  Local<Module> module = module_.Get(env()->isolate());
63
  env()->id_to_module_map.erase(id_);
64
  auto range = env()->hash_to_module_map.equal_range(module->GetIdentityHash());
65
  for (auto it = range.first; it != range.second; ++it) {
66
    if (it->second == this) {
67
      env()->hash_to_module_map.erase(it);
68
      break;
69
    }
70
  }
71
}
72
73
ModuleWrap* ModuleWrap::GetFromModule(Environment* env,
74
                                      Local<Module> module) {
75
  auto range = env->hash_to_module_map.equal_range(module->GetIdentityHash());
76
  for (auto it = range.first; it != range.second; ++it) {
77
    if (it->second->module_ == module) {
78
      return it->second;
79
    }
80
  }
81
  return nullptr;
82
}
83
84
ModuleWrap* ModuleWrap::GetFromID(Environment* env, uint32_t id) {
85
  auto module_wrap_it = env->id_to_module_map.find(id);
86
  if (module_wrap_it == env->id_to_module_map.end()) {
87
    return nullptr;
88
  }
89
  return module_wrap_it->second;
90
}
91
92
void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
93
  Environment* env = Environment::GetCurrent(args);
94
  Isolate* isolate = env->isolate();
95
96
  CHECK(args.IsConstructCall());
97
  Local<Object> that = args.This();
98
99
  const int argc = args.Length();
100
  CHECK_GE(argc, 2);
101
102
  CHECK(args[0]->IsString());
103
  Local<String> source_text = args[0].As<String>();
104
105
  CHECK(args[1]->IsString());
106
  Local<String> url = args[1].As<String>();
107
108
  Local<Context> context;
109
  Local<Integer> line_offset;
110
  Local<Integer> column_offset;
111
112
  if (argc == 5) {
113
    // new ModuleWrap(source, url, context?, lineOffset, columnOffset)
114
    if (args[2]->IsUndefined()) {
115
      context = that->CreationContext();
116
    } else {
117
      CHECK(args[2]->IsObject());
118
      ContextifyContext* sandbox =
119
          ContextifyContext::ContextFromContextifiedSandbox(
120
              env, args[2].As<Object>());
121
      CHECK_NOT_NULL(sandbox);
122
      context = sandbox->context();
123
    }
124
125
    CHECK(args[3]->IsNumber());
126
    line_offset = args[3].As<Integer>();
127
128
    CHECK(args[4]->IsNumber());
129
    column_offset = args[4].As<Integer>();
130
  } else {
131
    // new ModuleWrap(source, url)
132
    context = that->CreationContext();
133
    line_offset = Integer::New(isolate, 0);
134
    column_offset = Integer::New(isolate, 0);
135
  }
136
137
  Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env);
138
  TryCatchScope try_catch(env);
139
  Local<Module> module;
140
141
  Local<PrimitiveArray> host_defined_options =
142
      PrimitiveArray::New(isolate, HostDefinedOptions::kLength);
143
  host_defined_options->Set(isolate, HostDefinedOptions::kType,
144
                            Number::New(isolate, ScriptType::kModule));
145
146
  // compile
147
  {
148
    ScriptOrigin origin(url,
149
                        line_offset,                          // line offset
150
                        column_offset,                        // column offset
151
                        True(isolate),                        // is cross origin
152
                        Local<Integer>(),                     // script id
153
                        Local<Value>(),                       // source map URL
154
                        False(isolate),                       // is opaque (?)
155
                        False(isolate),                       // is WASM
156
                        True(isolate),                        // is ES Module
157
                        host_defined_options);
158
    Context::Scope context_scope(context);
159
    ScriptCompiler::Source source(source_text, origin);
160
    if (!ScriptCompiler::CompileModule(isolate, &source).ToLocal(&module)) {
161
      CHECK(try_catch.HasCaught());
162
      CHECK(!try_catch.Message().IsEmpty());
163
      CHECK(!try_catch.Exception().IsEmpty());
164
      AppendExceptionLine(env, try_catch.Exception(), try_catch.Message(),
165
                          ErrorHandlingMode::MODULE_ERROR);
166
      try_catch.ReThrow();
167
      return;
168
    }
169
  }
170
171
  if (!that->Set(context, env->url_string(), url).FromMaybe(false)) {
172
    return;
173
  }
174
175
  ModuleWrap* obj = new ModuleWrap(env, that, module, url);
176
  obj->context_.Reset(isolate, context);
177
178
  env->hash_to_module_map.emplace(module->GetIdentityHash(), obj);
179
180
  host_defined_options->Set(isolate, HostDefinedOptions::kID,
181
                            Number::New(isolate, obj->id()));
182
183
  that->SetIntegrityLevel(context, IntegrityLevel::kFrozen);
184
  args.GetReturnValue().Set(that);
185
}
186
187
void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
188
  Environment* env = Environment::GetCurrent(args);
189
  Isolate* isolate = args.GetIsolate();
190
191
  CHECK_EQ(args.Length(), 1);
192
  CHECK(args[0]->IsFunction());
193
194
  Local<Object> that = args.This();
195
196
  ModuleWrap* obj;
197
  ASSIGN_OR_RETURN_UNWRAP(&obj, that);
198
199
  if (obj->linked_)
200
    return;
201
  obj->linked_ = true;
202
203
  Local<Function> resolver_arg = args[0].As<Function>();
204
205
  Local<Context> mod_context = obj->context_.Get(isolate);
206
  Local<Module> module = obj->module_.Get(isolate);
207
208
  Local<Array> promises = Array::New(isolate,
209
                                     module->GetModuleRequestsLength());
210
211
  // call the dependency resolve callbacks
212
  for (int i = 0; i < module->GetModuleRequestsLength(); i++) {
213
    Local<String> specifier = module->GetModuleRequest(i);
214
    Utf8Value specifier_utf8(env->isolate(), specifier);
215
    std::string specifier_std(*specifier_utf8, specifier_utf8.length());
216
217
    Local<Value> argv[] = {
218
      specifier
219
    };
220
221
    MaybeLocal<Value> maybe_resolve_return_value =
222
        resolver_arg->Call(mod_context, that, 1, argv);
223
    if (maybe_resolve_return_value.IsEmpty()) {
224
      return;
225
    }
226
    Local<Value> resolve_return_value =
227
        maybe_resolve_return_value.ToLocalChecked();
228
    if (!resolve_return_value->IsPromise()) {
229
      env->ThrowError("linking error, expected resolver to return a promise");
230
    }
231
    Local<Promise> resolve_promise = resolve_return_value.As<Promise>();
232
    obj->resolve_cache_[specifier_std].Reset(env->isolate(), resolve_promise);
233
234
    promises->Set(mod_context, i, resolve_promise).FromJust();
235
  }
236
237
  args.GetReturnValue().Set(promises);
238
}
239
240
void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
241
  Environment* env = Environment::GetCurrent(args);
242
  Isolate* isolate = args.GetIsolate();
243
  ModuleWrap* obj;
244
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
245
  Local<Context> context = obj->context_.Get(isolate);
246
  Local<Module> module = obj->module_.Get(isolate);
247
  TryCatchScope try_catch(env);
248
  Maybe<bool> ok = module->InstantiateModule(context, ResolveCallback);
249
250
  // clear resolve cache on instantiate
251
  obj->resolve_cache_.clear();
252
253
  if (!ok.FromMaybe(false)) {
254
    CHECK(try_catch.HasCaught());
255
    CHECK(!try_catch.Message().IsEmpty());
256
    CHECK(!try_catch.Exception().IsEmpty());
257
    AppendExceptionLine(env, try_catch.Exception(), try_catch.Message(),
258
                        ErrorHandlingMode::MODULE_ERROR);
259
    try_catch.ReThrow();
260
    return;
261
  }
262
}
263
264
void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
265
  Environment* env = Environment::GetCurrent(args);
266
  Isolate* isolate = env->isolate();
267
  ModuleWrap* obj;
268
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
269
  Local<Context> context = obj->context_.Get(isolate);
270
  Local<Module> module = obj->module_.Get(isolate);
271
272
  // module.evaluate(timeout, breakOnSigint)
273
  CHECK_EQ(args.Length(), 2);
274
275
  CHECK(args[0]->IsNumber());
276
  int64_t timeout = args[0]->IntegerValue(env->context()).FromJust();
277
278
  CHECK(args[1]->IsBoolean());
279
  bool break_on_sigint = args[1]->IsTrue();
280
281
  Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env);
282
  TryCatchScope try_catch(env);
283
284
  bool timed_out = false;
285
  bool received_signal = false;
286
  MaybeLocal<Value> result;
287
  if (break_on_sigint && timeout != -1) {
288
    Watchdog wd(isolate, timeout, &timed_out);
289
    SigintWatchdog swd(isolate, &received_signal);
290
    result = module->Evaluate(context);
291
  } else if (break_on_sigint) {
292
    SigintWatchdog swd(isolate, &received_signal);
293
    result = module->Evaluate(context);
294
  } else if (timeout != -1) {
295
    Watchdog wd(isolate, timeout, &timed_out);
296
    result = module->Evaluate(context);
297
  } else {
298
    result = module->Evaluate(context);
299
  }
300
301
  // Convert the termination exception into a regular exception.
302
  if (timed_out || received_signal) {
303
    env->isolate()->CancelTerminateExecution();
304
    // It is possible that execution was terminated by another timeout in
305
    // which this timeout is nested, so check whether one of the watchdogs
306
    // from this invocation is responsible for termination.
307
    if (timed_out) {
308
      THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
309
    } else if (received_signal) {
310
      THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
311
    }
312
  }
313
314
  if (try_catch.HasCaught()) {
315
    try_catch.ReThrow();
316
    return;
317
  }
318
319
  args.GetReturnValue().Set(result.ToLocalChecked());
320
}
321
322
void ModuleWrap::Namespace(const FunctionCallbackInfo<Value>& args) {
323
  Environment* env = Environment::GetCurrent(args);
324
  Isolate* isolate = args.GetIsolate();
325
  ModuleWrap* obj;
326
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
327
328
  Local<Module> module = obj->module_.Get(isolate);
329
330
  switch (module->GetStatus()) {
331
    default:
332
      return env->ThrowError(
333
          "cannot get namespace, Module has not been instantiated");
334
    case v8::Module::Status::kInstantiated:
335
    case v8::Module::Status::kEvaluating:
336
    case v8::Module::Status::kEvaluated:
337
      break;
338
  }
339
340
  Local<Value> result = module->GetModuleNamespace();
341
  args.GetReturnValue().Set(result);
342
}
343
344
void ModuleWrap::GetStatus(const FunctionCallbackInfo<Value>& args) {
345
  Isolate* isolate = args.GetIsolate();
346
  ModuleWrap* obj;
347
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
348
349
  Local<Module> module = obj->module_.Get(isolate);
350
351
  args.GetReturnValue().Set(module->GetStatus());
352
}
353
354
void ModuleWrap::GetStaticDependencySpecifiers(
355
    const FunctionCallbackInfo<Value>& args) {
356
  Environment* env = Environment::GetCurrent(args);
357
  ModuleWrap* obj;
358
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
359
360
  Local<Module> module = obj->module_.Get(env->isolate());
361
362
  int count = module->GetModuleRequestsLength();
363
364
  Local<Array> specifiers = Array::New(env->isolate(), count);
365
366
  for (int i = 0; i < count; i++)
367
    specifiers->Set(env->context(), i, module->GetModuleRequest(i)).FromJust();
368
369
  args.GetReturnValue().Set(specifiers);
370
}
371
372
void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
373
  Isolate* isolate = args.GetIsolate();
374
  ModuleWrap* obj;
375
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
376
377
  Local<Module> module = obj->module_.Get(isolate);
378
379
  args.GetReturnValue().Set(module->GetException());
380
}
381
382
MaybeLocal<Module> ModuleWrap::ResolveCallback(Local<Context> context,
383
                                               Local<String> specifier,
384
                                               Local<Module> referrer) {
385
  Environment* env = Environment::GetCurrent(context);
386
  CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
387
  Isolate* isolate = env->isolate();
388
389
  ModuleWrap* dependent = GetFromModule(env, referrer);
390
  if (dependent == nullptr) {
391
    env->ThrowError("linking error, null dep");
392
    return MaybeLocal<Module>();
393
  }
394
395
  Utf8Value specifier_utf8(isolate, specifier);
396
  std::string specifier_std(*specifier_utf8, specifier_utf8.length());
397
398
  if (dependent->resolve_cache_.count(specifier_std) != 1) {
399
    env->ThrowError("linking error, not in local cache");
400
    return MaybeLocal<Module>();
401
  }
402
403
  Local<Promise> resolve_promise =
404
      dependent->resolve_cache_[specifier_std].Get(isolate);
405
406
  if (resolve_promise->State() != Promise::kFulfilled) {
407
    env->ThrowError("linking error, dependency promises must be resolved on "
408
                    "instantiate");
409
    return MaybeLocal<Module>();
410
  }
411
412
  Local<Object> module_object = resolve_promise->Result().As<Object>();
413
  if (module_object.IsEmpty() || !module_object->IsObject()) {
414
    env->ThrowError("linking error, expected a valid module object from "
415
                    "resolver");
416
    return MaybeLocal<Module>();
417
  }
418
419
  ModuleWrap* module;
420
  ASSIGN_OR_RETURN_UNWRAP(&module, module_object, MaybeLocal<Module>());
421
  return module->module_.Get(isolate);
422
}
423
424
namespace {
425
426
// Tests whether a path starts with /, ./ or ../
427
// In WhatWG terminology, the alternative case is called a "bare" specifier
428
// (e.g. in `import "jquery"`).
429
inline bool ShouldBeTreatedAsRelativeOrAbsolutePath(
430
    const std::string& specifier) {
431
  size_t len = specifier.length();
432
  if (len == 0)
433
    return false;
434
  if (specifier[0] == '/') {
435
    return true;
436
  } else if (specifier[0] == '.') {
437
    if (len == 1 || specifier[1] == '/')
438
      return true;
439
    if (specifier[1] == '.') {
440
      if (len == 2 || specifier[2] == '/')
441
        return true;
442
    }
443
  }
444
  return false;
445
}
446
447
std::string ReadFile(uv_file file) {
448
  std::string contents;
449
  uv_fs_t req;
450
  char buffer_memory[4096];
451
  uv_buf_t buf = uv_buf_init(buffer_memory, sizeof(buffer_memory));
452
453
  do {
454
    const int r = uv_fs_read(uv_default_loop(),
455
                             &req,
456
                             file,
457
                             &buf,
458
                             1,
459
                             contents.length(),  // offset
460
                             nullptr);
461
    uv_fs_req_cleanup(&req);
462
463
    if (r <= 0)
464
      break;
465
    contents.append(buf.base, r);
466
  } while (true);
467
  return contents;
468
}
469
470
enum CheckFileOptions {
471
  LEAVE_OPEN_AFTER_CHECK,
472
  CLOSE_AFTER_CHECK
473
};
474
475
Maybe<uv_file> CheckFile(const std::string& path,
476
                         CheckFileOptions opt = CLOSE_AFTER_CHECK) {
477
  uv_fs_t fs_req;
478
  if (path.empty()) {
479
    return Nothing<uv_file>();
480
  }
481
482
  uv_file fd = uv_fs_open(nullptr, &fs_req, path.c_str(), O_RDONLY, 0, nullptr);
483
  uv_fs_req_cleanup(&fs_req);
484
485
  if (fd < 0) {
486
    return Nothing<uv_file>();
487
  }
488
489
  uv_fs_fstat(nullptr, &fs_req, fd, nullptr);
490
  uint64_t is_directory = fs_req.statbuf.st_mode & S_IFDIR;
491
  uv_fs_req_cleanup(&fs_req);
492
493
  if (is_directory) {
494
    CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, fd, nullptr));
495
    uv_fs_req_cleanup(&fs_req);
496
    return Nothing<uv_file>();
497
  }
498
499
  if (opt == CLOSE_AFTER_CHECK) {
500
    CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, fd, nullptr));
501
    uv_fs_req_cleanup(&fs_req);
502
  }
503
504
  return Just(fd);
505
}
506
507
using Exists = PackageConfig::Exists;
508
using IsValid = PackageConfig::IsValid;
509
using HasMain = PackageConfig::HasMain;
510
511
const PackageConfig& GetPackageConfig(Environment* env,
512
                                      const std::string& path) {
513
  auto existing = env->package_json_cache.find(path);
514
  if (existing != env->package_json_cache.end()) {
515
    return existing->second;
516
  }
517
  Maybe<uv_file> check = CheckFile(path, LEAVE_OPEN_AFTER_CHECK);
518
  if (check.IsNothing()) {
519
    auto entry = env->package_json_cache.emplace(path,
520
        PackageConfig { Exists::No, IsValid::Yes, HasMain::No, "" });
521
    return entry.first->second;
522
  }
523
524
  Isolate* isolate = env->isolate();
525
  v8::HandleScope handle_scope(isolate);
526
527
  std::string pkg_src = ReadFile(check.FromJust());
528
  uv_fs_t fs_req;
529
  CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, check.FromJust(), nullptr));
530
  uv_fs_req_cleanup(&fs_req);
531
532
  Local<String> src;
533
  if (!String::NewFromUtf8(isolate,
534
                           pkg_src.c_str(),
535
                           v8::NewStringType::kNormal,
536
                           pkg_src.length()).ToLocal(&src)) {
537
    auto entry = env->package_json_cache.emplace(path,
538
        PackageConfig { Exists::No, IsValid::Yes, HasMain::No, "" });
539
    return entry.first->second;
540
  }
541
542
  Local<Value> pkg_json_v;
543
  Local<Object> pkg_json;
544
545
  if (!JSON::Parse(env->context(), src).ToLocal(&pkg_json_v) ||
546
      !pkg_json_v->ToObject(env->context()).ToLocal(&pkg_json)) {
547
    auto entry = env->package_json_cache.emplace(path,
548
        PackageConfig { Exists::Yes, IsValid::No, HasMain::No, "" });
549
    return entry.first->second;
550
  }
551
552
  Local<Value> pkg_main;
553
  HasMain has_main = HasMain::No;
554
  std::string main_std;
555
  if (pkg_json->Get(env->context(), env->main_string()).ToLocal(&pkg_main)) {
556
    has_main = HasMain::Yes;
557
    Utf8Value main_utf8(isolate, pkg_main);
558
    main_std.assign(std::string(*main_utf8, main_utf8.length()));
559
  }
560
561
  auto entry = env->package_json_cache.emplace(path,
562
      PackageConfig { Exists::Yes, IsValid::Yes, has_main, main_std });
563
  return entry.first->second;
564
}
565
566
enum ResolveExtensionsOptions {
567
  TRY_EXACT_NAME,
568
  ONLY_VIA_EXTENSIONS
569
};
570
571
template <ResolveExtensionsOptions options>
572
Maybe<URL> ResolveExtensions(const URL& search) {
573
  if (options == TRY_EXACT_NAME) {
574
    std::string filePath = search.ToFilePath();
575
    Maybe<uv_file> check = CheckFile(filePath);
576
    if (!check.IsNothing()) {
577
      return Just(search);
578
    }
579
  }
580
581
  for (const char* extension : EXTENSIONS) {
582
    URL guess(search.path() + extension, &search);
583
    Maybe<uv_file> check = CheckFile(guess.ToFilePath());
584
    if (!check.IsNothing()) {
585
      return Just(guess);
586
    }
587
  }
588
589
  return Nothing<URL>();
590
}
591
592
inline Maybe<URL> ResolveIndex(const URL& search) {
593
  return ResolveExtensions<ONLY_VIA_EXTENSIONS>(URL("index", search));
594
}
595
596
Maybe<URL> ResolveMain(Environment* env, const URL& search) {
597
  URL pkg("package.json", &search);
598
599
  const PackageConfig& pjson =
600
      GetPackageConfig(env, pkg.ToFilePath());
601
  // Note invalid package.json should throw in resolver
602
  // currently we silently ignore which is incorrect
603
  if (pjson.exists == Exists::No ||
604
      pjson.is_valid == IsValid::No ||
605
      pjson.has_main == HasMain::No) {
606
    return Nothing<URL>();
607
  }
608
  if (!ShouldBeTreatedAsRelativeOrAbsolutePath(pjson.main)) {
609
    return Resolve(env, "./" + pjson.main, search, IgnoreMain);
610
  }
611
  return Resolve(env, pjson.main, search, IgnoreMain);
612
}
613
614
Maybe<URL> ResolveModule(Environment* env,
615
                         const std::string& specifier,
616
                         const URL& base) {
617
  URL parent(".", base);
618
  URL dir("");
619
  do {
620
    dir = parent;
621
    Maybe<URL> check =
622
        Resolve(env, "./node_modules/" + specifier, dir, CheckMain);
623
    if (!check.IsNothing()) {
624
      const size_t limit = specifier.find('/');
625
      const size_t spec_len =
626
          limit == std::string::npos ? specifier.length() :
627
                                       limit + 1;
628
      std::string chroot =
629
          dir.path() + "node_modules/" + specifier.substr(0, spec_len);
630
      if (check.FromJust().path().substr(0, chroot.length()) != chroot) {
631
        return Nothing<URL>();
632
      }
633
      return check;
634
    } else {
635
      // TODO(bmeck) PREVENT FALLTHROUGH
636
    }
637
    parent = URL("..", &dir);
638
  } while (parent.path() != dir.path());
639
  return Nothing<URL>();
640
}
641
642
Maybe<URL> ResolveDirectory(Environment* env,
643
                            const URL& search,
644
                            PackageMainCheck check_pjson_main) {
645
  if (check_pjson_main) {
646
    Maybe<URL> main = ResolveMain(env, search);
647
    if (!main.IsNothing())
648
      return main;
649
  }
650
  return ResolveIndex(search);
651
}
652
653
}  // anonymous namespace
654
655
Maybe<URL> Resolve(Environment* env,
656
                   const std::string& specifier,
657
                   const URL& base,
658
                   PackageMainCheck check_pjson_main) {
659
  URL pure_url(specifier);
660
  if (!(pure_url.flags() & URL_FLAGS_FAILED)) {
661
    // just check existence, without altering
662
    Maybe<uv_file> check = CheckFile(pure_url.ToFilePath());
663
    if (check.IsNothing()) {
664
      return Nothing<URL>();
665
    }
666
    return Just(pure_url);
667
  }
668
  if (specifier.length() == 0) {
669
    return Nothing<URL>();
670
  }
671
  if (ShouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
672
    URL resolved(specifier, base);
673
    Maybe<URL> file = ResolveExtensions<TRY_EXACT_NAME>(resolved);
674
    if (!file.IsNothing())
675
      return file;
676
    if (specifier.back() != '/') {
677
      resolved = URL(specifier + "/", base);
678
    }
679
    return ResolveDirectory(env, resolved, check_pjson_main);
680
  } else {
681
    return ResolveModule(env, specifier, base);
682
  }
683
}
684
685
void ModuleWrap::Resolve(const FunctionCallbackInfo<Value>& args) {
686
  Environment* env = Environment::GetCurrent(args);
687
688
  // module.resolve(specifier, url)
689
  CHECK_EQ(args.Length(), 2);
690
691
  CHECK(args[0]->IsString());
692
  Utf8Value specifier_utf8(env->isolate(), args[0]);
693
  std::string specifier_std(*specifier_utf8, specifier_utf8.length());
694
695
  CHECK(args[1]->IsString());
696
  Utf8Value url_utf8(env->isolate(), args[1]);
697
  URL url(*url_utf8, url_utf8.length());
698
699
  if (url.flags() & URL_FLAGS_FAILED) {
700
    return node::THROW_ERR_INVALID_ARG_TYPE(
701
        env, "second argument is not a URL string");
702
  }
703
704
  Maybe<URL> result = node::loader::Resolve(env, specifier_std, url);
705
  if (result.IsNothing() || (result.FromJust().flags() & URL_FLAGS_FAILED)) {
706
    std::string msg = "Cannot find module " + specifier_std;
707
    return node::THROW_ERR_MISSING_MODULE(env, msg.c_str());
708
  }
709
710
  MaybeLocal<Value> obj = result.FromJust().ToObject(env);
711
  if (!obj.IsEmpty())
712
    args.GetReturnValue().Set(obj.ToLocalChecked());
713
}
714
715
static MaybeLocal<Promise> ImportModuleDynamically(
716
    Local<Context> context,
717
    Local<v8::ScriptOrModule> referrer,
718
    Local<String> specifier) {
719
  Isolate* iso = context->GetIsolate();
720
  Environment* env = Environment::GetCurrent(context);
721
  CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
722
  v8::EscapableHandleScope handle_scope(iso);
723
724
  Local<Function> import_callback =
725
    env->host_import_module_dynamically_callback();
726
727
  Local<PrimitiveArray> options = referrer->GetHostDefinedOptions();
728
  if (options->Length() != HostDefinedOptions::kLength) {
729
    Local<Promise::Resolver> resolver =
730
        Promise::Resolver::New(context).ToLocalChecked();
731
    resolver
732
        ->Reject(context,
733
                 v8::Exception::TypeError(FIXED_ONE_BYTE_STRING(
734
                     context->GetIsolate(), "Invalid host defined options")))
735
        .ToChecked();
736
    return handle_scope.Escape(resolver->GetPromise());
737
  }
738
739
  Local<Value> object;
740
741
  int type = options->Get(iso, HostDefinedOptions::kType)
742
                 .As<Number>()
743
                 ->Int32Value(context)
744
                 .ToChecked();
745
  uint32_t id = options->Get(iso, HostDefinedOptions::kID)
746
                    .As<Number>()
747
                    ->Uint32Value(context)
748
                    .ToChecked();
749
  if (type == ScriptType::kScript) {
750
    contextify::ContextifyScript* wrap = env->id_to_script_map.find(id)->second;
751
    object = wrap->object();
752
  } else if (type == ScriptType::kModule) {
753
    ModuleWrap* wrap = ModuleWrap::GetFromID(env, id);
754
    object = wrap->object();
755
  } else {
756
    UNREACHABLE();
757
  }
758
759
  Local<Value> import_args[] = {
760
    object,
761
    Local<Value>(specifier),
762
  };
763
764
  Local<Value> result;
765
  if (import_callback->Call(
766
        context,
767
        v8::Undefined(iso),
768
        arraysize(import_args),
769
        import_args).ToLocal(&result)) {
770
    CHECK(result->IsPromise());
771
    return handle_scope.Escape(result.As<Promise>());
772
  }
773
774
  return MaybeLocal<Promise>();
775
}
776
777
void ModuleWrap::SetImportModuleDynamicallyCallback(
778
    const FunctionCallbackInfo<Value>& args) {
779
  Isolate* iso = args.GetIsolate();
780
  Environment* env = Environment::GetCurrent(args);
781
  HandleScope handle_scope(iso);
782
783
  CHECK_EQ(args.Length(), 1);
784
  CHECK(args[0]->IsFunction());
785
  Local<Function> import_callback = args[0].As<Function>();
786
  env->set_host_import_module_dynamically_callback(import_callback);
787
788
  iso->SetHostImportModuleDynamicallyCallback(ImportModuleDynamically);
789
}
790
791
void ModuleWrap::HostInitializeImportMetaObjectCallback(
792
    Local<Context> context, Local<Module> module, Local<Object> meta) {
793
  Environment* env = Environment::GetCurrent(context);
794
  CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
795
  ModuleWrap* module_wrap = GetFromModule(env, module);
796
797
  if (module_wrap == nullptr) {
798
    return;
799
  }
800
801
  Local<Object> wrap = module_wrap->object();
802
  Local<Function> callback =
803
      env->host_initialize_import_meta_object_callback();
804
  Local<Value> args[] = { wrap, meta };
805
  callback->Call(context, Undefined(env->isolate()), arraysize(args), args)
806
      .ToLocalChecked();
807
}
808
809
void ModuleWrap::SetInitializeImportMetaObjectCallback(
810
    const FunctionCallbackInfo<Value>& args) {
811
  Environment* env = Environment::GetCurrent(args);
812
  Isolate* isolate = env->isolate();
813
814
  CHECK_EQ(args.Length(), 1);
815
  CHECK(args[0]->IsFunction());
816
  Local<Function> import_meta_callback = args[0].As<Function>();
817
  env->set_host_initialize_import_meta_object_callback(import_meta_callback);
818
819
  isolate->SetHostInitializeImportMetaObjectCallback(
820
      HostInitializeImportMetaObjectCallback);
821
}
822
823
164
void ModuleWrap::Initialize(Local<Object> target,
824
                            Local<Value> unused,
825
                            Local<Context> context,
826
                            void* priv) {
827
164
  Environment* env = Environment::GetCurrent(context);
828
164
  Isolate* isolate = env->isolate();
829
830
164
  Local<FunctionTemplate> tpl = env->NewFunctionTemplate(New);
831
328
  tpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"));
832
328
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
833
834
164
  env->SetProtoMethod(tpl, "link", Link);
835
164
  env->SetProtoMethod(tpl, "instantiate", Instantiate);
836
164
  env->SetProtoMethod(tpl, "evaluate", Evaluate);
837
164
  env->SetProtoMethodNoSideEffect(tpl, "namespace", Namespace);
838
164
  env->SetProtoMethodNoSideEffect(tpl, "getStatus", GetStatus);
839
164
  env->SetProtoMethodNoSideEffect(tpl, "getError", GetError);
840
  env->SetProtoMethodNoSideEffect(tpl, "getStaticDependencySpecifiers",
841
164
                                  GetStaticDependencySpecifiers);
842
843
  target->Set(env->context(), FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"),
844
820
              tpl->GetFunction(context).ToLocalChecked()).FromJust();
845
164
  env->SetMethod(target, "resolve", Resolve);
846
  env->SetMethod(target,
847
                 "setImportModuleDynamicallyCallback",
848
164
                 SetImportModuleDynamicallyCallback);
849
  env->SetMethod(target,
850
                 "setInitializeImportMetaObjectCallback",
851
164
                 SetInitializeImportMetaObjectCallback);
852
853
#define V(name)                                                                \
854
    target->Set(context,                                                       \
855
      FIXED_ONE_BYTE_STRING(env->isolate(), #name),                            \
856
      Integer::New(env->isolate(), Module::Status::name))                      \
857
        .FromJust()
858
656
    V(kUninstantiated);
859
656
    V(kInstantiating);
860
656
    V(kInstantiated);
861
656
    V(kEvaluating);
862
656
    V(kEvaluated);
863
656
    V(kErrored);
864
#undef V
865
164
}
866
867
}  // namespace loader
868
}  // namespace node
869
870
164
NODE_MODULE_CONTEXT_AWARE_INTERNAL(module_wrap,
871
                                   node::loader::ModuleWrap::Initialize)