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: 414 456 90.8 %
Date: 2019-02-23 22:23:05 Branches: 203 308 65.9 %

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
260
ModuleWrap::ModuleWrap(Environment* env,
50
                       Local<Object> object,
51
                       Local<Module> module,
52
                       Local<String> url) :
53
  BaseObject(env, object),
54
1040
  id_(env->get_next_module_id()) {
55
260
  module_.Reset(env->isolate(), module);
56
260
  url_.Reset(env->isolate(), url);
57
260
  env->id_to_module_map.emplace(id_, this);
58
260
}
59
60
1470
ModuleWrap::~ModuleWrap() {
61
245
  HandleScope scope(env()->isolate());
62
490
  Local<Module> module = module_.Get(env()->isolate());
63
245
  env()->id_to_module_map.erase(id_);
64
245
  auto range = env()->hash_to_module_map.equal_range(module->GetIdentityHash());
65
245
  for (auto it = range.first; it != range.second; ++it) {
66
245
    if (it->second == this) {
67
245
      env()->hash_to_module_map.erase(it);
68
245
      break;
69
    }
70
245
  }
71
490
}
72
73
206
ModuleWrap* ModuleWrap::GetFromModule(Environment* env,
74
                                      Local<Module> module) {
75
206
  auto range = env->hash_to_module_map.equal_range(module->GetIdentityHash());
76
206
  for (auto it = range.first; it != range.second; ++it) {
77
412
    if (it->second->module_ == module) {
78
206
      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
262
void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
93
262
  Environment* env = Environment::GetCurrent(args);
94
262
  Isolate* isolate = env->isolate();
95
96
262
  CHECK(args.IsConstructCall());
97
262
  Local<Object> that = args.This();
98
99
262
  const int argc = args.Length();
100
262
  CHECK_GE(argc, 2);
101
102
786
  CHECK(args[0]->IsString());
103
524
  Local<String> source_text = args[0].As<String>();
104
105
786
  CHECK(args[1]->IsString());
106
524
  Local<String> url = args[1].As<String>();
107
108
  Local<Context> context;
109
  Local<Integer> line_offset;
110
  Local<Integer> column_offset;
111
112
262
  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
207
    context = that->CreationContext();
133
207
    line_offset = Integer::New(isolate, 0);
134
207
    column_offset = Integer::New(isolate, 0);
135
  }
136
137
262
  Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env);
138
522
  TryCatchScope try_catch(env);
139
  Local<Module> module;
140
141
  Local<PrimitiveArray> host_defined_options =
142
262
      PrimitiveArray::New(isolate, HostDefinedOptions::kLength);
143
  host_defined_options->Set(isolate, HostDefinedOptions::kType,
144
524
                            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
262
                        host_defined_options);
158
    Context::Scope context_scope(context);
159
260
    ScriptCompiler::Source source(source_text, origin);
160
524
    if (!ScriptCompiler::CompileModule(isolate, &source).ToLocal(&module)) {
161

2
      if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
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
      }
168
2
      return;
169
260
    }
170
  }
171
172
1040
  if (!that->Set(context, env->url_string(), url).FromMaybe(false)) {
173
    return;
174
  }
175
176
260
  ModuleWrap* obj = new ModuleWrap(env, that, module, url);
177
260
  obj->context_.Reset(isolate, context);
178
179
260
  env->hash_to_module_map.emplace(module->GetIdentityHash(), obj);
180
181
  host_defined_options->Set(isolate, HostDefinedOptions::kID,
182
520
                            Number::New(isolate, obj->id()));
183
184
260
  that->SetIntegrityLevel(context, IntegrityLevel::kFrozen);
185
780
  args.GetReturnValue().Set(that);
186
}
187
188
356
void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
189
356
  Environment* env = Environment::GetCurrent(args);
190
356
  Isolate* isolate = args.GetIsolate();
191
192
356
  CHECK_EQ(args.Length(), 1);
193
712
  CHECK(args[0]->IsFunction());
194
195
356
  Local<Object> that = args.This();
196
197
  ModuleWrap* obj;
198
469
  ASSIGN_OR_RETURN_UNWRAP(&obj, that);
199
200
356
  if (obj->linked_)
201
113
    return;
202
243
  obj->linked_ = true;
203
204
486
  Local<Function> resolver_arg = args[0].As<Function>();
205
206
486
  Local<Context> mod_context = obj->context_.Get(isolate);
207
486
  Local<Module> module = obj->module_.Get(isolate);
208
209
  Local<Array> promises = Array::New(isolate,
210
243
                                     module->GetModuleRequestsLength());
211
212
  // call the dependency resolve callbacks
213
756
  for (int i = 0; i < module->GetModuleRequestsLength(); i++) {
214
135
    Local<String> specifier = module->GetModuleRequest(i);
215
135
    Utf8Value specifier_utf8(env->isolate(), specifier);
216
270
    std::string specifier_std(*specifier_utf8, specifier_utf8.length());
217
218
    Local<Value> argv[] = {
219
      specifier
220
270
    };
221
222
    MaybeLocal<Value> maybe_resolve_return_value =
223
135
        resolver_arg->Call(mod_context, that, 1, argv);
224
135
    if (maybe_resolve_return_value.IsEmpty()) {
225
      return;
226
    }
227
    Local<Value> resolve_return_value =
228
135
        maybe_resolve_return_value.ToLocalChecked();
229
135
    if (!resolve_return_value->IsPromise()) {
230
      env->ThrowError("linking error, expected resolver to return a promise");
231
    }
232
135
    Local<Promise> resolve_promise = resolve_return_value.As<Promise>();
233
135
    obj->resolve_cache_[specifier_std].Reset(env->isolate(), resolve_promise);
234
235
405
    promises->Set(mod_context, i, resolve_promise).FromJust();
236
135
  }
237
238
486
  args.GetReturnValue().Set(promises);
239
}
240
241
193
void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
242
193
  Environment* env = Environment::GetCurrent(args);
243
193
  Isolate* isolate = args.GetIsolate();
244
  ModuleWrap* obj;
245
196
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
246
386
  Local<Context> context = obj->context_.Get(isolate);
247
386
  Local<Module> module = obj->module_.Get(isolate);
248
193
  TryCatchScope try_catch(env);
249
193
  USE(module->InstantiateModule(context, ResolveCallback));
250
251
  // clear resolve cache on instantiate
252
193
  obj->resolve_cache_.clear();
253
254

193
  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
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
190
  }
262
}
263
264
85
void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
265
85
  Environment* env = Environment::GetCurrent(args);
266
85
  Isolate* isolate = env->isolate();
267
  ModuleWrap* obj;
268
93
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
269
170
  Local<Context> context = obj->context_.Get(isolate);
270
170
  Local<Module> module = obj->module_.Get(isolate);
271
272
  // module.evaluate(timeout, breakOnSigint)
273
85
  CHECK_EQ(args.Length(), 2);
274
275
170
  CHECK(args[0]->IsNumber());
276
340
  int64_t timeout = args[0]->IntegerValue(env->context()).FromJust();
277
278
170
  CHECK(args[1]->IsBoolean());
279
170
  bool break_on_sigint = args[1]->IsTrue();
280
281
85
  Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env);
282
161
  TryCatchScope try_catch(env);
283
284
85
  bool timed_out = false;
285
85
  bool received_signal = false;
286
  MaybeLocal<Value> result;
287

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

84
  if (timed_out || received_signal) {
303

1
    if (!env->is_main_thread() && env->is_stopping_worker())
304
      return;
305
1
    env->isolate()->CancelTerminateExecution();
306
    // It is possible that execution was terminated by another timeout in
307
    // which this timeout is nested, so check whether one of the watchdogs
308
    // from this invocation is responsible for termination.
309
1
    if (timed_out) {
310
1
      THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
311
    } else if (received_signal) {
312
      THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
313
    }
314
  }
315
316
84
  if (try_catch.HasCaught()) {
317
8
    if (!try_catch.HasTerminated())
318
7
      try_catch.ReThrow();
319
8
    return;
320
  }
321
322
228
  args.GetReturnValue().Set(result.ToLocalChecked());
323
}
324
325
181
void ModuleWrap::Namespace(const FunctionCallbackInfo<Value>& args) {
326
181
  Environment* env = Environment::GetCurrent(args);
327
181
  Isolate* isolate = args.GetIsolate();
328
  ModuleWrap* obj;
329
181
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
330
331
362
  Local<Module> module = obj->module_.Get(isolate);
332
333
181
  switch (module->GetStatus()) {
334
    default:
335
      return env->ThrowError(
336
          "cannot get namespace, Module has not been instantiated");
337
    case v8::Module::Status::kInstantiated:
338
    case v8::Module::Status::kEvaluating:
339
    case v8::Module::Status::kEvaluated:
340
181
      break;
341
  }
342
343
181
  Local<Value> result = module->GetModuleNamespace();
344
362
  args.GetReturnValue().Set(result);
345
}
346
347
104
void ModuleWrap::GetStatus(const FunctionCallbackInfo<Value>& args) {
348
104
  Isolate* isolate = args.GetIsolate();
349
  ModuleWrap* obj;
350
208
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
351
352
208
  Local<Module> module = obj->module_.Get(isolate);
353
354
312
  args.GetReturnValue().Set(module->GetStatus());
355
}
356
357
1
void ModuleWrap::GetStaticDependencySpecifiers(
358
    const FunctionCallbackInfo<Value>& args) {
359
1
  Environment* env = Environment::GetCurrent(args);
360
  ModuleWrap* obj;
361
2
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
362
363
2
  Local<Module> module = obj->module_.Get(env->isolate());
364
365
1
  int count = module->GetModuleRequestsLength();
366
367
1
  Local<Array> specifiers = Array::New(env->isolate(), count);
368
369
2
  for (int i = 0; i < count; i++)
370
4
    specifiers->Set(env->context(), i, module->GetModuleRequest(i)).FromJust();
371
372
2
  args.GetReturnValue().Set(specifiers);
373
}
374
375
1
void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
376
1
  Isolate* isolate = args.GetIsolate();
377
  ModuleWrap* obj;
378
2
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
379
380
2
  Local<Module> module = obj->module_.Get(isolate);
381
3
  args.GetReturnValue().Set(module->GetException());
382
}
383
384
126
MaybeLocal<Module> ModuleWrap::ResolveCallback(Local<Context> context,
385
                                               Local<String> specifier,
386
                                               Local<Module> referrer) {
387
126
  Environment* env = Environment::GetCurrent(context);
388
126
  CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
389
126
  Isolate* isolate = env->isolate();
390
391
126
  ModuleWrap* dependent = GetFromModule(env, referrer);
392
126
  if (dependent == nullptr) {
393
    env->ThrowError("linking error, null dep");
394
    return MaybeLocal<Module>();
395
  }
396
397
126
  Utf8Value specifier_utf8(isolate, specifier);
398
252
  std::string specifier_std(*specifier_utf8, specifier_utf8.length());
399
400
126
  if (dependent->resolve_cache_.count(specifier_std) != 1) {
401
    env->ThrowError("linking error, not in local cache");
402
    return MaybeLocal<Module>();
403
  }
404
405
  Local<Promise> resolve_promise =
406
252
      dependent->resolve_cache_[specifier_std].Get(isolate);
407
408
126
  if (resolve_promise->State() != Promise::kFulfilled) {
409
    env->ThrowError("linking error, dependency promises must be resolved on "
410
                    "instantiate");
411
    return MaybeLocal<Module>();
412
  }
413
414
252
  Local<Object> module_object = resolve_promise->Result().As<Object>();
415

252
  if (module_object.IsEmpty() || !module_object->IsObject()) {
416
    env->ThrowError("linking error, expected a valid module object from "
417
                    "resolver");
418
    return MaybeLocal<Module>();
419
  }
420
421
  ModuleWrap* module;
422
126
  ASSIGN_OR_RETURN_UNWRAP(&module, module_object, MaybeLocal<Module>());
423
378
  return module->module_.Get(isolate);
424
}
425
426
namespace {
427
428
// Tests whether a path starts with /, ./ or ../
429
// In WhatWG terminology, the alternative case is called a "bare" specifier
430
// (e.g. in `import "jquery"`).
431
161
inline bool ShouldBeTreatedAsRelativeOrAbsolutePath(
432
    const std::string& specifier) {
433
161
  size_t len = specifier.length();
434
161
  if (len == 0)
435
    return false;
436
161
  if (specifier[0] == '/') {
437
51
    return true;
438
110
  } else if (specifier[0] == '.') {
439

108
    if (len == 1 || specifier[1] == '/')
440
62
      return true;
441
46
    if (specifier[1] == '.') {
442

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


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

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

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

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

48
  if (pjson.exists == Exists::No ||
606
2
      pjson.is_valid == IsValid::No ||
607
1
      pjson.has_main == HasMain::No) {
608
46
    return Nothing<URL>();
609
  }
610
1
  if (!ShouldBeTreatedAsRelativeOrAbsolutePath(pjson.main)) {
611
1
    return Resolve(env, "./" + pjson.main, search, IgnoreMain);
612
  }
613
  return Resolve(env, pjson.main, search, IgnoreMain);
614
}
615
616
1
Maybe<URL> ResolveModule(Environment* env,
617
                         const std::string& specifier,
618
                         const URL& base) {
619
1
  URL parent(".", base);
620
2
  URL dir("");
621
22
  do {
622
11
    dir = parent;
623
    Maybe<URL> check =
624
11
        Resolve(env, "./node_modules/" + specifier, dir, CheckMain);
625
11
    if (!check.IsNothing()) {
626
      const size_t limit = specifier.find('/');
627
      const size_t spec_len =
628
          limit == std::string::npos ? specifier.length() :
629
                                       limit + 1;
630
      std::string chroot =
631
          dir.path() + "node_modules/" + specifier.substr(0, spec_len);
632
      if (check.FromJust().path().substr(0, chroot.length()) != chroot) {
633
        return Nothing<URL>();
634
      }
635
      return check;
636
    } else {
637
      // TODO(bmeck) PREVENT FALLTHROUGH
638
    }
639
11
    parent = URL("..", &dir);
640
22
  } while (parent.path() != dir.path());
641
2
  return Nothing<URL>();
642
}
643
644
47
Maybe<URL> ResolveDirectory(Environment* env,
645
                            const URL& search,
646
                            PackageMainCheck check_pjson_main) {
647
47
  if (check_pjson_main) {
648
47
    Maybe<URL> main = ResolveMain(env, search);
649
47
    if (!main.IsNothing())
650
1
      return main;
651
  }
652
46
  return ResolveIndex(search);
653
}
654
655
}  // anonymous namespace
656
657
163
Maybe<URL> Resolve(Environment* env,
658
                   const std::string& specifier,
659
                   const URL& base,
660
                   PackageMainCheck check_pjson_main) {
661
163
  URL pure_url(specifier);
662
163
  if (!(pure_url.flags() & URL_FLAGS_FAILED)) {
663
    // just check existence, without altering
664
3
    Maybe<uv_file> check = CheckFile(pure_url.ToFilePath());
665
3
    if (check.IsNothing()) {
666
2
      return Nothing<URL>();
667
    }
668
1
    return Just(pure_url);
669
  }
670
160
  if (specifier.length() == 0) {
671
    return Nothing<URL>();
672
  }
673
160
  if (ShouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
674
159
    URL resolved(specifier, base);
675
318
    Maybe<URL> file = ResolveExtensions<TRY_EXACT_NAME>(resolved);
676
159
    if (!file.IsNothing())
677
112
      return file;
678
47
    if (specifier.back() != '/') {
679
47
      resolved = URL(specifier + "/", base);
680
    }
681
206
    return ResolveDirectory(env, resolved, check_pjson_main);
682
  } else {
683
1
    return ResolveModule(env, specifier, base);
684
163
  }
685
}
686
687
151
void ModuleWrap::Resolve(const FunctionCallbackInfo<Value>& args) {
688
151
  Environment* env = Environment::GetCurrent(args);
689
690
  // module.resolve(specifier, url)
691
151
  CHECK_EQ(args.Length(), 2);
692
693
453
  CHECK(args[0]->IsString());
694
151
  Utf8Value specifier_utf8(env->isolate(), args[0]);
695
289
  std::string specifier_std(*specifier_utf8, specifier_utf8.length());
696
697
453
  CHECK(args[1]->IsString());
698
289
  Utf8Value url_utf8(env->isolate(), args[1]);
699
289
  URL url(*url_utf8, url_utf8.length());
700
701
151
  if (url.flags() & URL_FLAGS_FAILED) {
702
    return node::THROW_ERR_INVALID_ARG_TYPE(
703
        env, "second argument is not a URL string");
704
  }
705
706
289
  Maybe<URL> result = node::loader::Resolve(env, specifier_std, url);
707


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