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: 411 452 90.9 %
Date: 2019-02-13 22:28:58 Branches: 193 292 66.1 %

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
258
ModuleWrap::ModuleWrap(Environment* env,
50
                       Local<Object> object,
51
                       Local<Module> module,
52
                       Local<String> url) :
53
  BaseObject(env, object),
54
1032
  id_(env->get_next_module_id()) {
55
258
  module_.Reset(env->isolate(), module);
56
258
  url_.Reset(env->isolate(), url);
57
258
  env->id_to_module_map.emplace(id_, this);
58
258
}
59
60
1458
ModuleWrap::~ModuleWrap() {
61
243
  HandleScope scope(env()->isolate());
62
486
  Local<Module> module = module_.Get(env()->isolate());
63
243
  env()->id_to_module_map.erase(id_);
64
243
  auto range = env()->hash_to_module_map.equal_range(module->GetIdentityHash());
65
243
  for (auto it = range.first; it != range.second; ++it) {
66
243
    if (it->second == this) {
67
243
      env()->hash_to_module_map.erase(it);
68
243
      break;
69
    }
70
243
  }
71
486
}
72
73
205
ModuleWrap* ModuleWrap::GetFromModule(Environment* env,
74
                                      Local<Module> module) {
75
205
  auto range = env->hash_to_module_map.equal_range(module->GetIdentityHash());
76
205
  for (auto it = range.first; it != range.second; ++it) {
77
410
    if (it->second->module_ == module) {
78
205
      return it->second;
79
    }
80
  }
81
  return nullptr;
82
}
83
84
9
ModuleWrap* ModuleWrap::GetFromID(Environment* env, uint32_t id) {
85
9
  auto module_wrap_it = env->id_to_module_map.find(id);
86
9
  if (module_wrap_it == env->id_to_module_map.end()) {
87
    return nullptr;
88
  }
89
9
  return module_wrap_it->second;
90
}
91
92
260
void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
93
260
  Environment* env = Environment::GetCurrent(args);
94
260
  Isolate* isolate = env->isolate();
95
96
260
  CHECK(args.IsConstructCall());
97
260
  Local<Object> that = args.This();
98
99
260
  const int argc = args.Length();
100
260
  CHECK_GE(argc, 2);
101
102
780
  CHECK(args[0]->IsString());
103
520
  Local<String> source_text = args[0].As<String>();
104
105
780
  CHECK(args[1]->IsString());
106
520
  Local<String> url = args[1].As<String>();
107
108
  Local<Context> context;
109
  Local<Integer> line_offset;
110
  Local<Integer> column_offset;
111
112
260
  if (argc == 5) {
113
    // new ModuleWrap(source, url, context?, lineOffset, columnOffset)
114
165
    if (args[2]->IsUndefined()) {
115
49
      context = that->CreationContext();
116
    } else {
117
12
      CHECK(args[2]->IsObject());
118
      ContextifyContext* sandbox =
119
          ContextifyContext::ContextFromContextifiedSandbox(
120
12
              env, args[2].As<Object>());
121
6
      CHECK_NOT_NULL(sandbox);
122
6
      context = sandbox->context();
123
    }
124
125
110
    CHECK(args[3]->IsNumber());
126
110
    line_offset = args[3].As<Integer>();
127
128
110
    CHECK(args[4]->IsNumber());
129
110
    column_offset = args[4].As<Integer>();
130
  } else {
131
    // new ModuleWrap(source, url)
132
205
    context = that->CreationContext();
133
205
    line_offset = Integer::New(isolate, 0);
134
205
    column_offset = Integer::New(isolate, 0);
135
  }
136
137
260
  Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env);
138
518
  TryCatchScope try_catch(env);
139
  Local<Module> module;
140
141
  Local<PrimitiveArray> host_defined_options =
142
260
      PrimitiveArray::New(isolate, HostDefinedOptions::kLength);
143
  host_defined_options->Set(isolate, HostDefinedOptions::kType,
144
520
                            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
260
                        host_defined_options);
158
    Context::Scope context_scope(context);
159
258
    ScriptCompiler::Source source(source_text, origin);
160
520
    if (!ScriptCompiler::CompileModule(isolate, &source).ToLocal(&module)) {
161
2
      CHECK(try_catch.HasCaught());
162
4
      CHECK(!try_catch.Message().IsEmpty());
163
4
      CHECK(!try_catch.Exception().IsEmpty());
164
      AppendExceptionLine(env, try_catch.Exception(), try_catch.Message(),
165
2
                          ErrorHandlingMode::MODULE_ERROR);
166
2
      try_catch.ReThrow();
167
2
      return;
168
258
    }
169
  }
170
171
1032
  if (!that->Set(context, env->url_string(), url).FromMaybe(false)) {
172
    return;
173
  }
174
175
258
  ModuleWrap* obj = new ModuleWrap(env, that, module, url);
176
258
  obj->context_.Reset(isolate, context);
177
178
258
  env->hash_to_module_map.emplace(module->GetIdentityHash(), obj);
179
180
  host_defined_options->Set(isolate, HostDefinedOptions::kID,
181
516
                            Number::New(isolate, obj->id()));
182
183
258
  that->SetIntegrityLevel(context, IntegrityLevel::kFrozen);
184
774
  args.GetReturnValue().Set(that);
185
}
186
187
354
void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
188
354
  Environment* env = Environment::GetCurrent(args);
189
354
  Isolate* isolate = args.GetIsolate();
190
191
354
  CHECK_EQ(args.Length(), 1);
192
708
  CHECK(args[0]->IsFunction());
193
194
354
  Local<Object> that = args.This();
195
196
  ModuleWrap* obj;
197
467
  ASSIGN_OR_RETURN_UNWRAP(&obj, that);
198
199
354
  if (obj->linked_)
200
113
    return;
201
241
  obj->linked_ = true;
202
203
482
  Local<Function> resolver_arg = args[0].As<Function>();
204
205
482
  Local<Context> mod_context = obj->context_.Get(isolate);
206
482
  Local<Module> module = obj->module_.Get(isolate);
207
208
  Local<Array> promises = Array::New(isolate,
209
241
                                     module->GetModuleRequestsLength());
210
211
  // call the dependency resolve callbacks
212
750
  for (int i = 0; i < module->GetModuleRequestsLength(); i++) {
213
134
    Local<String> specifier = module->GetModuleRequest(i);
214
134
    Utf8Value specifier_utf8(env->isolate(), specifier);
215
268
    std::string specifier_std(*specifier_utf8, specifier_utf8.length());
216
217
    Local<Value> argv[] = {
218
      specifier
219
268
    };
220
221
    MaybeLocal<Value> maybe_resolve_return_value =
222
134
        resolver_arg->Call(mod_context, that, 1, argv);
223
134
    if (maybe_resolve_return_value.IsEmpty()) {
224
      return;
225
    }
226
    Local<Value> resolve_return_value =
227
134
        maybe_resolve_return_value.ToLocalChecked();
228
134
    if (!resolve_return_value->IsPromise()) {
229
      env->ThrowError("linking error, expected resolver to return a promise");
230
    }
231
134
    Local<Promise> resolve_promise = resolve_return_value.As<Promise>();
232
134
    obj->resolve_cache_[specifier_std].Reset(env->isolate(), resolve_promise);
233
234
402
    promises->Set(mod_context, i, resolve_promise).FromJust();
235
134
  }
236
237
482
  args.GetReturnValue().Set(promises);
238
}
239
240
192
void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
241
192
  Environment* env = Environment::GetCurrent(args);
242
192
  Isolate* isolate = args.GetIsolate();
243
  ModuleWrap* obj;
244
195
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
245
384
  Local<Context> context = obj->context_.Get(isolate);
246
384
  Local<Module> module = obj->module_.Get(isolate);
247
192
  TryCatchScope try_catch(env);
248
192
  Maybe<bool> ok = module->InstantiateModule(context, ResolveCallback);
249
250
  // clear resolve cache on instantiate
251
192
  obj->resolve_cache_.clear();
252
253
384
  if (!ok.FromMaybe(false)) {
254
3
    CHECK(try_catch.HasCaught());
255
6
    CHECK(!try_catch.Message().IsEmpty());
256
6
    CHECK(!try_catch.Exception().IsEmpty());
257
    AppendExceptionLine(env, try_catch.Exception(), try_catch.Message(),
258
3
                        ErrorHandlingMode::MODULE_ERROR);
259
3
    try_catch.ReThrow();
260
3
    return;
261
189
  }
262
}
263
264
84
void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
265
84
  Environment* env = Environment::GetCurrent(args);
266
84
  Isolate* isolate = env->isolate();
267
  ModuleWrap* obj;
268
91
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
269
168
  Local<Context> context = obj->context_.Get(isolate);
270
168
  Local<Module> module = obj->module_.Get(isolate);
271
272
  // module.evaluate(timeout, breakOnSigint)
273
84
  CHECK_EQ(args.Length(), 2);
274
275
168
  CHECK(args[0]->IsNumber());
276
336
  int64_t timeout = args[0]->IntegerValue(env->context()).FromJust();
277
278
168
  CHECK(args[1]->IsBoolean());
279
168
  bool break_on_sigint = args[1]->IsTrue();
280
281
84
  Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env);
282
160
  TryCatchScope try_catch(env);
283
284
84
  bool timed_out = false;
285
84
  bool received_signal = false;
286
  MaybeLocal<Value> result;
287

84
  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
84
  } else if (break_on_sigint) {
292
    SigintWatchdog swd(isolate, &received_signal);
293
    result = module->Evaluate(context);
294
84
  } else if (timeout != -1) {
295
1
    Watchdog wd(isolate, timeout, &timed_out);
296
1
    result = module->Evaluate(context);
297
  } else {
298
83
    result = module->Evaluate(context);
299
  }
300
301
  // Convert the termination exception into a regular exception.
302

83
  if (timed_out || received_signal) {
303
1
    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
1
    if (timed_out) {
308
1
      THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
309
    } else if (received_signal) {
310
      THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
311
    }
312
  }
313
314
83
  if (try_catch.HasCaught()) {
315
7
    try_catch.ReThrow();
316
7
    return;
317
  }
318
319
228
  args.GetReturnValue().Set(result.ToLocalChecked());
320
}
321
322
181
void ModuleWrap::Namespace(const FunctionCallbackInfo<Value>& args) {
323
181
  Environment* env = Environment::GetCurrent(args);
324
181
  Isolate* isolate = args.GetIsolate();
325
  ModuleWrap* obj;
326
181
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
327
328
362
  Local<Module> module = obj->module_.Get(isolate);
329
330
181
  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
181
      break;
338
  }
339
340
181
  Local<Value> result = module->GetModuleNamespace();
341
362
  args.GetReturnValue().Set(result);
342
}
343
344
104
void ModuleWrap::GetStatus(const FunctionCallbackInfo<Value>& args) {
345
104
  Isolate* isolate = args.GetIsolate();
346
  ModuleWrap* obj;
347
208
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
348
349
208
  Local<Module> module = obj->module_.Get(isolate);
350
351
312
  args.GetReturnValue().Set(module->GetStatus());
352
}
353
354
1
void ModuleWrap::GetStaticDependencySpecifiers(
355
    const FunctionCallbackInfo<Value>& args) {
356
1
  Environment* env = Environment::GetCurrent(args);
357
  ModuleWrap* obj;
358
2
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
359
360
2
  Local<Module> module = obj->module_.Get(env->isolate());
361
362
1
  int count = module->GetModuleRequestsLength();
363
364
1
  Local<Array> specifiers = Array::New(env->isolate(), count);
365
366
2
  for (int i = 0; i < count; i++)
367
4
    specifiers->Set(env->context(), i, module->GetModuleRequest(i)).FromJust();
368
369
2
  args.GetReturnValue().Set(specifiers);
370
}
371
372
1
void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
373
1
  Isolate* isolate = args.GetIsolate();
374
  ModuleWrap* obj;
375
2
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
376
377
2
  Local<Module> module = obj->module_.Get(isolate);
378
379
3
  args.GetReturnValue().Set(module->GetException());
380
}
381
382
125
MaybeLocal<Module> ModuleWrap::ResolveCallback(Local<Context> context,
383
                                               Local<String> specifier,
384
                                               Local<Module> referrer) {
385
125
  Environment* env = Environment::GetCurrent(context);
386
125
  CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
387
125
  Isolate* isolate = env->isolate();
388
389
125
  ModuleWrap* dependent = GetFromModule(env, referrer);
390
125
  if (dependent == nullptr) {
391
    env->ThrowError("linking error, null dep");
392
    return MaybeLocal<Module>();
393
  }
394
395
125
  Utf8Value specifier_utf8(isolate, specifier);
396
250
  std::string specifier_std(*specifier_utf8, specifier_utf8.length());
397
398
125
  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
250
      dependent->resolve_cache_[specifier_std].Get(isolate);
405
406
125
  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
250
  Local<Object> module_object = resolve_promise->Result().As<Object>();
413

250
  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
125
  ASSIGN_OR_RETURN_UNWRAP(&module, module_object, MaybeLocal<Module>());
421
375
  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
159
inline bool ShouldBeTreatedAsRelativeOrAbsolutePath(
430
    const std::string& specifier) {
431
159
  size_t len = specifier.length();
432
159
  if (len == 0)
433
    return false;
434
159
  if (specifier[0] == '/') {
435
50
    return true;
436
109
  } else if (specifier[0] == '.') {
437

107
    if (len == 1 || specifier[1] == '/')
438
61
      return true;
439
46
    if (specifier[1] == '.') {
440

46
      if (len == 2 || specifier[2] == '/')
441
46
        return true;
442
    }
443
  }
444
2
  return false;
445
}
446
447
1
std::string ReadFile(uv_file file) {
448
1
  std::string contents;
449
  uv_fs_t req;
450
  char buffer_memory[4096];
451
1
  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
2
                             contents.length(),  // offset
460
2
                             nullptr);
461
2
    uv_fs_req_cleanup(&req);
462
463
2
    if (r <= 0)
464
1
      break;
465
1
    contents.append(buf.base, r);
466
  } while (true);
467
1
  return contents;
468
}
469
470
enum CheckFileOptions {
471
  LEAVE_OPEN_AFTER_CHECK,
472
  CLOSE_AFTER_CHECK
473
};
474
475
515
Maybe<uv_file> CheckFile(const std::string& path,
476
                         CheckFileOptions opt = CLOSE_AFTER_CHECK) {
477
  uv_fs_t fs_req;
478
515
  if (path.empty()) {
479
2
    return Nothing<uv_file>();
480
  }
481
482
513
  uv_file fd = uv_fs_open(nullptr, &fs_req, path.c_str(), O_RDONLY, 0, nullptr);
483
513
  uv_fs_req_cleanup(&fs_req);
484
485
513
  if (fd < 0) {
486
350
    return Nothing<uv_file>();
487
  }
488
489
163
  uv_fs_fstat(nullptr, &fs_req, fd, nullptr);
490
163
  uint64_t is_directory = fs_req.statbuf.st_mode & S_IFDIR;
491
163
  uv_fs_req_cleanup(&fs_req);
492
493
163
  if (is_directory) {
494
26
    CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, fd, nullptr));
495
26
    uv_fs_req_cleanup(&fs_req);
496
26
    return Nothing<uv_file>();
497
  }
498
499
137
  if (opt == CLOSE_AFTER_CHECK) {
500
136
    CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, fd, nullptr));
501
136
    uv_fs_req_cleanup(&fs_req);
502
  }
503
504
137
  return Just(fd);
505
}
506
507
using Exists = PackageConfig::Exists;
508
using IsValid = PackageConfig::IsValid;
509
using HasMain = PackageConfig::HasMain;
510
511
47
const PackageConfig& GetPackageConfig(Environment* env,
512
                                      const std::string& path) {
513
47
  auto existing = env->package_json_cache.find(path);
514
47
  if (existing != env->package_json_cache.end()) {
515
1
    return existing->second;
516
  }
517
46
  Maybe<uv_file> check = CheckFile(path, LEAVE_OPEN_AFTER_CHECK);
518
46
  if (check.IsNothing()) {
519
    auto entry = env->package_json_cache.emplace(path,
520
45
        PackageConfig { Exists::No, IsValid::Yes, HasMain::No, "" });
521
45
    return entry.first->second;
522
  }
523
524
1
  Isolate* isolate = env->isolate();
525
1
  v8::HandleScope handle_scope(isolate);
526
527
2
  std::string pkg_src = ReadFile(check.FromJust());
528
  uv_fs_t fs_req;
529
1
  CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, check.FromJust(), nullptr));
530
1
  uv_fs_req_cleanup(&fs_req);
531
532
  Local<String> src;
533
2
  if (!String::NewFromUtf8(isolate,
534
                           pkg_src.c_str(),
535
                           v8::NewStringType::kNormal,
536
3
                           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


5
  if (!JSON::Parse(env->context(), src).ToLocal(&pkg_json_v) ||
546
4
      !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
1
  HasMain has_main = HasMain::No;
554
2
  std::string main_std;
555
4
  if (pkg_json->Get(env->context(), env->main_string()).ToLocal(&pkg_main)) {
556
1
    has_main = HasMain::Yes;
557
1
    Utf8Value main_utf8(isolate, pkg_main);
558
1
    main_std.assign(std::string(*main_utf8, main_utf8.length()));
559
  }
560
561
  auto entry = env->package_json_cache.emplace(path,
562
1
      PackageConfig { Exists::Yes, IsValid::Yes, has_main, main_std });
563
2
  return entry.first->second;
564
}
565
566
enum ResolveExtensionsOptions {
567
  TRY_EXACT_NAME,
568
  ONLY_VIA_EXTENSIONS
569
};
570
571
template <ResolveExtensionsOptions options>
572
203
Maybe<URL> ResolveExtensions(const URL& search) {
573
  if (options == TRY_EXACT_NAME) {
574
157
    std::string filePath = search.ToFilePath();
575
157
    Maybe<uv_file> check = CheckFile(filePath);
576
157
    if (!check.IsNothing()) {
577
100
      return Just(search);
578
57
    }
579
  }
580
581

377
  for (const char* extension : EXTENSIONS) {
582
309
    URL guess(search.path() + extension, &search);
583
309
    Maybe<uv_file> check = CheckFile(guess.ToFilePath());
584

309
    if (!check.IsNothing()) {
585

35
      return Just(guess);
586
    }
587
  }
588
589
68
  return Nothing<URL>();
590
}
591
592
46
inline Maybe<URL> ResolveIndex(const URL& search) {
593
46
  return ResolveExtensions<ONLY_VIA_EXTENSIONS>(URL("index", search));
594
}
595
596
47
Maybe<URL> ResolveMain(Environment* env, const URL& search) {
597
47
  URL pkg("package.json", &search);
598
599
  const PackageConfig& pjson =
600
47
      GetPackageConfig(env, pkg.ToFilePath());
601
  // Note invalid package.json should throw in resolver
602
  // currently we silently ignore which is incorrect
603

48
  if (pjson.exists == Exists::No ||
604
2
      pjson.is_valid == IsValid::No ||
605
1
      pjson.has_main == HasMain::No) {
606
46
    return Nothing<URL>();
607
  }
608
1
  if (!ShouldBeTreatedAsRelativeOrAbsolutePath(pjson.main)) {
609
1
    return Resolve(env, "./" + pjson.main, search, IgnoreMain);
610
  }
611
  return Resolve(env, pjson.main, search, IgnoreMain);
612
}
613
614
1
Maybe<URL> ResolveModule(Environment* env,
615
                         const std::string& specifier,
616
                         const URL& base) {
617
1
  URL parent(".", base);
618
2
  URL dir("");
619
22
  do {
620
11
    dir = parent;
621
    Maybe<URL> check =
622
11
        Resolve(env, "./node_modules/" + specifier, dir, CheckMain);
623
11
    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
11
    parent = URL("..", &dir);
638
22
  } while (parent.path() != dir.path());
639
2
  return Nothing<URL>();
640
}
641
642
47
Maybe<URL> ResolveDirectory(Environment* env,
643
                            const URL& search,
644
                            PackageMainCheck check_pjson_main) {
645
47
  if (check_pjson_main) {
646
47
    Maybe<URL> main = ResolveMain(env, search);
647
47
    if (!main.IsNothing())
648
1
      return main;
649
  }
650
46
  return ResolveIndex(search);
651
}
652
653
}  // anonymous namespace
654
655
161
Maybe<URL> Resolve(Environment* env,
656
                   const std::string& specifier,
657
                   const URL& base,
658
                   PackageMainCheck check_pjson_main) {
659
161
  URL pure_url(specifier);
660
161
  if (!(pure_url.flags() & URL_FLAGS_FAILED)) {
661
    // just check existence, without altering
662
3
    Maybe<uv_file> check = CheckFile(pure_url.ToFilePath());
663
3
    if (check.IsNothing()) {
664
2
      return Nothing<URL>();
665
    }
666
1
    return Just(pure_url);
667
  }
668
158
  if (specifier.length() == 0) {
669
    return Nothing<URL>();
670
  }
671
158
  if (ShouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
672
157
    URL resolved(specifier, base);
673
314
    Maybe<URL> file = ResolveExtensions<TRY_EXACT_NAME>(resolved);
674
157
    if (!file.IsNothing())
675
110
      return file;
676
47
    if (specifier.back() != '/') {
677
47
      resolved = URL(specifier + "/", base);
678
    }
679
204
    return ResolveDirectory(env, resolved, check_pjson_main);
680
  } else {
681
1
    return ResolveModule(env, specifier, base);
682
161
  }
683
}
684
685
149
void ModuleWrap::Resolve(const FunctionCallbackInfo<Value>& args) {
686
149
  Environment* env = Environment::GetCurrent(args);
687
688
  // module.resolve(specifier, url)
689
149
  CHECK_EQ(args.Length(), 2);
690
691
447
  CHECK(args[0]->IsString());
692
149
  Utf8Value specifier_utf8(env->isolate(), args[0]);
693
285
  std::string specifier_std(*specifier_utf8, specifier_utf8.length());
694
695
447
  CHECK(args[1]->IsString());
696
285
  Utf8Value url_utf8(env->isolate(), args[1]);
697
285
  URL url(*url_utf8, url_utf8.length());
698
699
149
  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
285
  Maybe<URL> result = node::loader::Resolve(env, specifier_std, url);
705


434
  if (result.IsNothing() || (result.FromJust().flags() & URL_FLAGS_FAILED)) {
706
13
    std::string msg = "Cannot find module " + specifier_std;
707
13
    return node::THROW_ERR_MISSING_MODULE(env, msg.c_str());
708
  }
709
710
136
  MaybeLocal<Value> obj = result.FromJust().ToObject(env);
711
136
  if (!obj.IsEmpty())
712
408
    args.GetReturnValue().Set(obj.ToLocalChecked());
713
}
714
715
22
static MaybeLocal<Promise> ImportModuleDynamically(
716
    Local<Context> context,
717
    Local<v8::ScriptOrModule> referrer,
718
    Local<String> specifier) {
719
22
  Isolate* iso = context->GetIsolate();
720
22
  Environment* env = Environment::GetCurrent(context);
721
22
  CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
722
22
  v8::EscapableHandleScope handle_scope(iso);
723
724
  Local<Function> import_callback =
725
22
    env->host_import_module_dynamically_callback();
726
727
22
  Local<PrimitiveArray> options = referrer->GetHostDefinedOptions();
728
22
  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
22
  int type = options->Get(iso, HostDefinedOptions::kType)
742
44
                 .As<Number>()
743
66
                 ->Int32Value(context)
744
44
                 .ToChecked();
745
22
  uint32_t id = options->Get(iso, HostDefinedOptions::kID)
746
44
                    .As<Number>()
747
66
                    ->Uint32Value(context)
748
44
                    .ToChecked();
749
22
  if (type == ScriptType::kScript) {
750
13
    contextify::ContextifyScript* wrap = env->id_to_script_map.find(id)->second;
751
26
    object = wrap->object();
752
9
  } else if (type == ScriptType::kModule) {
753
9
    ModuleWrap* wrap = ModuleWrap::GetFromID(env, id);
754
18
    object = wrap->object();
755
  } else {
756
    UNREACHABLE();
757
  }
758
759
  Local<Value> import_args[] = {
760
    object,
761
    Local<Value>(specifier),
762
44
  };
763
764
  Local<Value> result;
765
44
  if (import_callback->Call(
766
        context,
767
        v8::Undefined(iso),
768
22
        arraysize(import_args),
769
66
        import_args).ToLocal(&result)) {
770
22
    CHECK(result->IsPromise());
771
22
    return handle_scope.Escape(result.As<Promise>());
772
  }
773
774
  return MaybeLocal<Promise>();
775
}
776
777
59
void ModuleWrap::SetImportModuleDynamicallyCallback(
778
    const FunctionCallbackInfo<Value>& args) {
779
59
  Isolate* iso = args.GetIsolate();
780
59
  Environment* env = Environment::GetCurrent(args);
781
59
  HandleScope handle_scope(iso);
782
783
59
  CHECK_EQ(args.Length(), 1);
784
118
  CHECK(args[0]->IsFunction());
785
118
  Local<Function> import_callback = args[0].As<Function>();
786
59
  env->set_host_import_module_dynamically_callback(import_callback);
787
788
59
  iso->SetHostImportModuleDynamicallyCallback(ImportModuleDynamically);
789
59
}
790
791
80
void ModuleWrap::HostInitializeImportMetaObjectCallback(
792
    Local<Context> context, Local<Module> module, Local<Object> meta) {
793
80
  Environment* env = Environment::GetCurrent(context);
794
80
  CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
795
80
  ModuleWrap* module_wrap = GetFromModule(env, module);
796
797
80
  if (module_wrap == nullptr) {
798
80
    return;
799
  }
800
801
80
  Local<Object> wrap = module_wrap->object();
802
  Local<Function> callback =
803
80
      env->host_initialize_import_meta_object_callback();
804
240
  Local<Value> args[] = { wrap, meta };
805
240
  callback->Call(context, Undefined(env->isolate()), arraysize(args), args)
806
160
      .ToLocalChecked();
807
}
808
809
59
void ModuleWrap::SetInitializeImportMetaObjectCallback(
810
    const FunctionCallbackInfo<Value>& args) {
811
59
  Environment* env = Environment::GetCurrent(args);
812
59
  Isolate* isolate = env->isolate();
813
814
59
  CHECK_EQ(args.Length(), 1);
815
118
  CHECK(args[0]->IsFunction());
816
118
  Local<Function> import_meta_callback = args[0].As<Function>();
817
59
  env->set_host_initialize_import_meta_object_callback(import_meta_callback);
818
819
  isolate->SetHostInitializeImportMetaObjectCallback(
820
59
      HostInitializeImportMetaObjectCallback);
821
59
}
822
823
4416
void ModuleWrap::Initialize(Local<Object> target,
824
                            Local<Value> unused,
825
                            Local<Context> context,
826
                            void* priv) {
827
4416
  Environment* env = Environment::GetCurrent(context);
828
4416
  Isolate* isolate = env->isolate();
829
830
4416
  Local<FunctionTemplate> tpl = env->NewFunctionTemplate(New);
831
8832
  tpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"));
832
8832
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
833
834
4416
  env->SetProtoMethod(tpl, "link", Link);
835
4416
  env->SetProtoMethod(tpl, "instantiate", Instantiate);
836
4416
  env->SetProtoMethod(tpl, "evaluate", Evaluate);
837
4416
  env->SetProtoMethodNoSideEffect(tpl, "namespace", Namespace);
838
4416
  env->SetProtoMethodNoSideEffect(tpl, "getStatus", GetStatus);
839
4416
  env->SetProtoMethodNoSideEffect(tpl, "getError", GetError);
840
  env->SetProtoMethodNoSideEffect(tpl, "getStaticDependencySpecifiers",
841
4416
                                  GetStaticDependencySpecifiers);
842
843
  target->Set(env->context(), FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"),
844
22080
              tpl->GetFunction(context).ToLocalChecked()).FromJust();
845
4416
  env->SetMethod(target, "resolve", Resolve);
846
  env->SetMethod(target,
847
                 "setImportModuleDynamicallyCallback",
848
4416
                 SetImportModuleDynamicallyCallback);
849
  env->SetMethod(target,
850
                 "setInitializeImportMetaObjectCallback",
851
4416
                 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
17664
    V(kUninstantiated);
859
17664
    V(kInstantiating);
860
17664
    V(kInstantiated);
861
17664
    V(kEvaluating);
862
17664
    V(kEvaluated);
863
17664
    V(kErrored);
864
#undef V
865
4416
}
866
867
}  // namespace loader
868
}  // namespace node
869
870
4314
NODE_MODULE_CONTEXT_AWARE_INTERNAL(module_wrap,
871
                                   node::loader::ModuleWrap::Initialize)