LWNode_Release_220523_f4ad606 57/275357/1 accepted/tizen/unified/20220525.010114 submit/tizen/20220524.045310
authorRyan Hyun Choi <ryan.choi@samsung.com>
Mon, 23 May 2022 07:00:36 +0000 (16:00 +0900)
committerRyan Hyun Choi <ryan.choi@samsung.com>
Mon, 23 May 2022 07:00:57 +0000 (16:00 +0900)
Change-Id: Ic06bc6da70f07a0124171e9dfe926bed8e5fb78b
Signed-off-by: Ryan Choi <ryan.choi@samsung.com>
lib/internal/bootstrap/loaders.prod.js [new file with mode: 0644]
lwnode/code/escargotshim/src/api/stack-trace.cc
lwnode/code/escargotshim/src/api/utils/logger/logger-util.cc
node.gyp

diff --git a/lib/internal/bootstrap/loaders.prod.js b/lib/internal/bootstrap/loaders.prod.js
new file mode 100644 (file)
index 0000000..3419b7e
--- /dev/null
@@ -0,0 +1,339 @@
+// This file creates the internal module & binding loaders used by built-in
+// modules. In contrast, user land modules are loaded using
+// lib/internal/modules/cjs/loader.js (CommonJS Modules) or
+// lib/internal/modules/esm/* (ES Modules).
+//
+// This file is compiled and run by node.cc before bootstrap/node.js
+// was called, therefore the loaders are bootstraped before we start to
+// actually bootstrap Node.js. It creates the following objects:
+//
+// C++ binding loaders:
+// - process.binding(): the legacy C++ binding loader, accessible from user land
+//   because it is an object attached to the global process object.
+//   These C++ bindings are created using NODE_BUILTIN_MODULE_CONTEXT_AWARE()
+//   and have their nm_flags set to NM_F_BUILTIN. We do not make any guarantees
+//   about the stability of these bindings, but still have to take care of
+//   compatibility issues caused by them from time to time.
+// - process._linkedBinding(): intended to be used by embedders to add
+//   additional C++ bindings in their applications. These C++ bindings
+//   can be created using NODE_MODULE_CONTEXT_AWARE_CPP() with the flag
+//   NM_F_LINKED.
+// - internalBinding(): the private internal C++ binding loader, inaccessible
+//   from user land unless through `require('internal/test/binding')`.
+//   These C++ bindings are created using NODE_MODULE_CONTEXT_AWARE_INTERNAL()
+//   and have their nm_flags set to NM_F_INTERNAL.
+//
+// Internal JavaScript module loader:
+// - NativeModule: a minimal module system used to load the JavaScript core
+//   modules found in lib/**/*.js and deps/**/*.js. All core modules are
+//   compiled into the node binary via node_javascript.cc generated by js2c.py,
+//   so they can be loaded faster without the cost of I/O. This class makes the
+//   lib/internal/*, deps/internal/* modules and internalBinding() available by
+//   default to core modules, and lets the core modules require itself via
+//   require('internal/bootstrap/loaders') even when this file is not written in
+//   CommonJS style.
+//
+// Other objects:
+// - process.moduleLoadList: an array recording the bindings and the modules
+//   loaded in the process and the order in which they are loaded.
+
+'use strict';
+
+// This file is compiled as if it's wrapped in a function with arguments
+// passed by node::RunBootstrapping()
+/* global process, getLinkedBinding, getInternalBinding, primordials */
+
+const {
+  Error,
+  Map,
+  ObjectCreate,
+  ObjectDefineProperty,
+  ObjectKeys,
+  ObjectPrototypeHasOwnProperty,
+  ReflectGet,
+  SafeSet,
+  String,
+  TypeError,
+} = primordials;
+
+// Set up process.moduleLoadList.
+const moduleLoadList = [];
+ObjectDefineProperty(process, 'moduleLoadList', {
+  value: moduleLoadList,
+  configurable: true,
+  enumerable: true,
+  writable: false
+});
+
+
+// internalBindingWhitelist contains the name of internalBinding modules
+// that are whitelisted for access via process.binding()... This is used
+// to provide a transition path for modules that are being moved over to
+// internalBinding.
+const internalBindingWhitelist = new SafeSet([
+  'async_wrap',
+  'buffer',
+  'cares_wrap',
+  'config',
+  'constants',
+  'contextify',
+  'crypto',
+  'fs',
+  'fs_event_wrap',
+  'http_parser',
+  'icu',
+  'inspector',
+  'js_stream',
+  'natives',
+  'os',
+  'pipe_wrap',
+  'process_wrap',
+  'signal_wrap',
+  'spawn_sync',
+  'stream_wrap',
+  'tcp_wrap',
+  'tls_wrap',
+  'tty_wrap',
+  'udp_wrap',
+  'url',
+  'util',
+  'uv',
+  'v8',
+  'zlib'
+]);
+
+// @lwnode
+function testCodeGenerationFromStringsAllowed() {
+  // related to: --allow-code-generation-from-strings
+  try {
+    eval();
+  } catch (error) {
+    return false;
+  }
+  return true;
+};
+
+const userModuleBlacklist = [
+  'v8',
+  ...(testCodeGenerationFromStringsAllowed() ? [] : ['vm']),
+];
+
+// Set up process.binding() and process._linkedBinding().
+{
+  const bindingObj = ObjectCreate(null);
+
+  process.binding = function binding(module) {
+    module = String(module);
+    // Deprecated specific process.binding() modules, but not all, allow
+    // selective fallback to internalBinding for the deprecated ones.
+    if (internalBindingWhitelist.has(module)) {
+      return internalBinding(module);
+    }
+    // eslint-disable-next-line no-restricted-syntax
+    throw new Error(`No such module: ${module}`);
+  };
+
+  process._linkedBinding = function _linkedBinding(module) {
+    module = String(module);
+    let mod = bindingObj[module];
+    if (typeof mod !== 'object')
+      mod = bindingObj[module] = getLinkedBinding(module);
+    return mod;
+  };
+}
+
+// Set up internalBinding() in the closure.
+let internalBinding;
+{
+  const bindingObj = ObjectCreate(null);
+  // eslint-disable-next-line no-global-assign
+  internalBinding = function internalBinding(module) {
+    let mod = bindingObj[module];
+    if (typeof mod !== 'object') {
+      mod = bindingObj[module] = getInternalBinding(module);
+      moduleLoadList.push(`Internal Binding ${module}`);
+    }
+    return mod;
+  };
+}
+
+const loaderId = 'internal/bootstrap/loaders';
+const {
+  moduleIds,
+  compileFunction
+} = internalBinding('native_module');
+
+const getOwn = (target, property, receiver) => {
+  return ObjectPrototypeHasOwnProperty(target, property) ?
+    ReflectGet(target, property, receiver) :
+    undefined;
+};
+
+/**
+ * An internal abstraction for the built-in JavaScript modules of Node.js.
+ * Be careful not to expose this to user land unless --expose-internals is
+ * used, in which case there is no compatibility guarantee about this class.
+ */
+class NativeModule {
+  /**
+   * A map from the module IDs to the module instances.
+   * @type {Map<string, NativeModule>}
+  */
+  static map = new Map(moduleIds.map((id) => [id, new NativeModule(id)]));
+
+  constructor(id) {
+    this.filename = `${id}.js`;
+    this.id = id;
+    // this.canBeRequiredByUsers = !id.startsWith('internal/');
+    // @lwnode
+    this.canBeRequiredByUsers =
+      !id.startsWith("internal/") && !userModuleBlacklist.includes(id);
+
+    // The CJS exports object of the module.
+    this.exports = {};
+    // States used to work around circular dependencies.
+    this.loaded = false;
+    this.loading = false;
+
+    // The following properties are used by the ESM implementation and only
+    // initialized when the native module is loaded by users.
+    /**
+     * The C++ ModuleWrap binding used to interface with the ESM implementation.
+     * @type {ModuleWrap|undefined}
+     */
+    this.module = undefined;
+    /**
+     * Exported names for the ESM imports.
+     * @type {string[]|undefined}
+     */
+    this.exportKeys = undefined;
+  }
+
+  // To be called during pre-execution when --expose-internals is on.
+  // Enables the user-land module loader to access internal modules.
+  static exposeInternals() {
+    for (const [id, mod] of NativeModule.map) {
+      // Do not expose this to user land even with --expose-internals.
+      if (id !== loaderId) {
+        mod.canBeRequiredByUsers = true;
+      }
+    }
+  }
+
+  static exists(id) {
+    return NativeModule.map.has(id);
+  }
+
+  static canBeRequiredByUsers(id) {
+    const mod = NativeModule.map.get(id);
+    return mod && mod.canBeRequiredByUsers;
+  }
+
+  // Used by user-land module loaders to compile and load builtins.
+  compileForPublicLoader() {
+    if (!this.canBeRequiredByUsers) {
+      // No code because this is an assertion against bugs
+      // eslint-disable-next-line no-restricted-syntax
+      throw new Error(`Should not compile ${this.id} for public use`);
+    }
+    this.compileForInternalLoader();
+    if (!this.exportKeys) {
+      // When using --expose-internals, we do not want to reflect the named
+      // exports from core modules as this can trigger unnecessary getters.
+      const internal = this.id.startsWith('internal/');
+      this.exportKeys = internal ? [] : ObjectKeys(this.exports);
+    }
+    this.getESMFacade();
+    this.syncExports();
+    return this.exports;
+  }
+
+  getESMFacade() {
+    if (this.module) return this.module;
+    const { ModuleWrap } = internalBinding('module_wrap');
+    const url = `node:${this.id}`;
+    const nativeModule = this;
+    this.module = new ModuleWrap(
+      url, undefined, [...this.exportKeys, 'default'],
+      function() {
+        nativeModule.syncExports();
+        this.setExport('default', nativeModule.exports);
+      });
+    // Ensure immediate sync execution to capture exports now
+    this.module.instantiate();
+    this.module.evaluate(-1, false);
+    return this.module;
+  }
+
+  // Provide named exports for all builtin libraries so that the libraries
+  // may be imported in a nicer way for ESM users. The default export is left
+  // as the entire namespace (module.exports) and updates when this function is
+  // called so that APMs and other behavior are supported.
+  syncExports() {
+    const names = this.exportKeys;
+    if (this.module) {
+      for (let i = 0; i < names.length; i++) {
+        const exportName = names[i];
+        if (exportName === 'default') continue;
+        this.module.setExport(exportName,
+                              getOwn(this.exports, exportName, this.exports));
+      }
+    }
+  }
+
+  compileForInternalLoader() {
+    if (this.loaded || this.loading) {
+      return this.exports;
+    }
+
+    const id = this.id;
+    this.loading = true;
+
+    try {
+      const requireFn = this.id.startsWith('internal/deps/') ?
+        requireWithFallbackInDeps : nativeModuleRequire;
+
+      const fn = compileFunction(id);
+      fn(this.exports, requireFn, this, process, internalBinding, primordials);
+
+      this.loaded = true;
+    } finally {
+      this.loading = false;
+    }
+
+    moduleLoadList.push(`NativeModule ${id}`);
+    return this.exports;
+  }
+}
+
+// Think of this as module.exports in this file even though it is not
+// written in CommonJS style.
+const loaderExports = {
+  internalBinding,
+  NativeModule,
+  require: nativeModuleRequire
+};
+
+function nativeModuleRequire(id) {
+  if (id === loaderId) {
+    return loaderExports;
+  }
+
+  const mod = NativeModule.map.get(id);
+  // Can't load the internal errors module from here, have to use a raw error.
+  // eslint-disable-next-line no-restricted-syntax
+  if (!mod) throw new TypeError(`Missing internal module '${id}'`);
+  return mod.compileForInternalLoader();
+}
+
+// Allow internal modules from dependencies to require
+// other modules from dependencies by providing fallbacks.
+function requireWithFallbackInDeps(request) {
+  if (!NativeModule.map.has(request)) {
+    request = `internal/deps/${request}`;
+  }
+  return nativeModuleRequire(request);
+}
+
+// Pass the exports back to C++ land for C++ internals to use.
+return loaderExports;
index 4333a1a6facf22e9b535792060ffc125188670e1..509bb131c4850122328eb85f0be0f722d7a3bdb5 100644 (file)
@@ -138,9 +138,7 @@ ValueRef* StackTrace::captureStackTraceCallback(ExecutionStateRef* state,
   int stacktraceStartIdx = 1;
 
   double stackTraceLimit = 0;
-  if (!getStackTraceLimit(state, stackTraceLimit)) {
-    stackTraceVector = nullptr;
-  } else {
+  if (getStackTraceLimit(state, stackTraceLimit)) {
     size_t maxPrintStackSize =
         std::min(stackTraceLimit, (double)stackTraceData.size());
     for (size_t i = 0; i < maxPrintStackSize; i++) {
index ba4872f89f66df0be2b4cdcb45e1e2d16de36398..307ccbbbec5670b7f354cb4ec3712ae6b1b80e8e 100644 (file)
 #include "api/global.h"
 
 std::string getPrettyFunctionName(const std::string fullname) {
-  std::smatch match;
-  const std::regex re(R"(([\w\:~]+)\()");
+  try {
+    std::smatch match;
+    const std::regex re(R"(([\w\:~]+)\()");
 
-  if (std::regex_search(fullname, match, re) && match.size() > 1) {
-    return match.str(1);
+    if (std::regex_search(fullname, match, re) && match.size() > 1) {
+      return match.str(1);
+    }
+    return "";
+  } catch (std::regex_error& e) {
+    return "";
   }
-  return "";
 }
 
 std::string createCodeLocation(const char* functionName,
index 0889978d7a5ca826f4621c55c394d792c32a72fd..6995d4ef83b5b9347b586b342e17edfa5a8bf6cd 100644 (file)
--- a/node.gyp
+++ b/node.gyp
@@ -30,6 +30,7 @@
     'library_files': [
       'lib/internal/bootstrap/environment.js',
       'lib/internal/bootstrap/loaders.js',
+      # 'lib/internal/bootstrap/loaders.prod.js',
       'lib/internal/bootstrap/node.js',
       'lib/internal/bootstrap/pre_execution.js',
       'lib/internal/bootstrap/switches/does_own_process_state.js',