From 2db758c562b4e480acc2d1a654e2c471a653a039 Mon Sep 17 00:00:00 2001 From: Vladimir Kurchatkin Date: Sat, 14 Feb 2015 22:53:34 +0300 Subject: [PATCH] iojs: introduce internal modules Internal modules can be used to share private code between public modules without risk to expose private APIs to the user. PR-URL: https://github.com/iojs/io.js/pull/848 Reviewed-By: Trevor Norris Reviewed-By: Ben Noordhuis --- lib/_http_common.js | 2 +- lib/freelist.js | 25 +---------------- lib/internal/freelist.js | 24 +++++++++++++++++ lib/module.js | 6 ++--- node.gyp | 2 ++ src/node.cc | 3 +++ src/node.js | 21 +++++++++++++++ test/fixtures/internal-modules/index.js | 1 + .../node_modules/internal/freelist.js | 1 + test/parallel/test-internal-modules-expose.js | 6 +++++ test/parallel/test-internal-modules.js | 8 ++++++ tools/js2c.py | 27 ++++++++++++++----- 12 files changed, 91 insertions(+), 35 deletions(-) create mode 100644 lib/internal/freelist.js create mode 100644 test/fixtures/internal-modules/index.js create mode 100644 test/fixtures/internal-modules/node_modules/internal/freelist.js create mode 100644 test/parallel/test-internal-modules-expose.js create mode 100644 test/parallel/test-internal-modules.js diff --git a/lib/_http_common.js b/lib/_http_common.js index 209bd77bf452cc..7861848b46a9d4 100644 --- a/lib/_http_common.js +++ b/lib/_http_common.js @@ -1,6 +1,6 @@ 'use strict'; -const FreeList = require('freelist').FreeList; +const FreeList = require('internal/freelist').FreeList; const HTTPParser = process.binding('http_parser').HTTPParser; const incoming = require('_http_incoming'); diff --git a/lib/freelist.js b/lib/freelist.js index 78a581d6acb37b..9300c1148754c4 100644 --- a/lib/freelist.js +++ b/lib/freelist.js @@ -1,26 +1,3 @@ 'use strict'; -// This is a free list to avoid creating so many of the same object. -exports.FreeList = function(name, max, constructor) { - this.name = name; - this.constructor = constructor; - this.max = max; - this.list = []; -}; - - -exports.FreeList.prototype.alloc = function() { - //debug("alloc " + this.name + " " + this.list.length); - return this.list.length ? this.list.shift() : - this.constructor.apply(this, arguments); -}; - - -exports.FreeList.prototype.free = function(obj) { - //debug("free " + this.name + " " + this.list.length); - if (this.list.length < this.max) { - this.list.push(obj); - return true; - } - return false; -}; +module.exports = require('internal/freelist'); diff --git a/lib/internal/freelist.js b/lib/internal/freelist.js new file mode 100644 index 00000000000000..4b17d154d4acef --- /dev/null +++ b/lib/internal/freelist.js @@ -0,0 +1,24 @@ +'use strict'; + +// This is a free list to avoid creating so many of the same object. +exports.FreeList = function(name, max, constructor) { + this.name = name; + this.constructor = constructor; + this.max = max; + this.list = []; +}; + + +exports.FreeList.prototype.alloc = function() { + return this.list.length ? this.list.shift() : + this.constructor.apply(this, arguments); +}; + + +exports.FreeList.prototype.free = function(obj) { + if (this.list.length < this.max) { + this.list.push(obj); + return true; + } + return false; +}; diff --git a/lib/module.js b/lib/module.js index b2ddbd80c31913..719f8bd50c5716 100644 --- a/lib/module.js +++ b/lib/module.js @@ -200,7 +200,7 @@ Module._nodeModulePaths = function(from) { Module._resolveLookupPaths = function(request, parent) { - if (NativeModule.exists(request)) { + if (NativeModule.nonInternalExists(request)) { return [request, []]; } @@ -262,7 +262,7 @@ Module._load = function(request, parent, isMain) { return cachedModule.exports; } - if (NativeModule.exists(filename)) { + if (NativeModule.nonInternalExists(filename)) { // REPL is a special case, because it needs the real require. if (filename == 'repl') { var replModule = new Module('repl'); @@ -299,7 +299,7 @@ Module._load = function(request, parent, isMain) { }; Module._resolveFilename = function(request, parent) { - if (NativeModule.exists(request)) { + if (NativeModule.nonInternalExists(request)) { return request; } diff --git a/node.gyp b/node.gyp index cae5340b273a48..dab7f6b28f1c56 100644 --- a/node.gyp +++ b/node.gyp @@ -69,6 +69,8 @@ 'lib/v8.js', 'lib/vm.js', 'lib/zlib.js', + + 'lib/internal/freelist.js', ], }, diff --git a/src/node.cc b/src/node.cc index 92ace4fe3ec8b7..e82ea37c1abef8 100644 --- a/src/node.cc +++ b/src/node.cc @@ -3133,6 +3133,9 @@ static void ParseArgs(int* argc, } else if (strncmp(arg, "--icu-data-dir=", 15) == 0) { icu_data_dir = arg + 15; #endif + } else if (strcmp(arg, "--expose-internals") == 0 || + strcmp(arg, "--expose_internals") == 0) { + // consumed in js } else { // V8 option. Pass through as-is. new_v8_argv[new_v8_argc] = arg; diff --git a/src/node.js b/src/node.js index dbadc6637307e4..8ad727b7822ebf 100644 --- a/src/node.js +++ b/src/node.js @@ -838,6 +838,27 @@ return NativeModule._source.hasOwnProperty(id); }; + const EXPOSE_INTERNALS = process.execArgv.some(function(arg) { + return arg.match(/^--expose[-_]internals$/); + }); + + if (EXPOSE_INTERNALS) { + NativeModule.nonInternalExists = NativeModule.exists; + + NativeModule.isInternal = function(id) { + return false; + }; + } else { + NativeModule.nonInternalExists = function(id) { + return NativeModule.exists(id) && !NativeModule.isInternal(id); + }; + + NativeModule.isInternal = function(id) { + return id.startsWith('internal/'); + }; + } + + NativeModule.getSource = function(id) { return NativeModule._source[id]; }; diff --git a/test/fixtures/internal-modules/index.js b/test/fixtures/internal-modules/index.js new file mode 100644 index 00000000000000..7543c9b7376ff7 --- /dev/null +++ b/test/fixtures/internal-modules/index.js @@ -0,0 +1 @@ +module.exports = require('internal/freelist'); diff --git a/test/fixtures/internal-modules/node_modules/internal/freelist.js b/test/fixtures/internal-modules/node_modules/internal/freelist.js new file mode 100644 index 00000000000000..888cae37af95c5 --- /dev/null +++ b/test/fixtures/internal-modules/node_modules/internal/freelist.js @@ -0,0 +1 @@ +module.exports = 42; diff --git a/test/parallel/test-internal-modules-expose.js b/test/parallel/test-internal-modules-expose.js new file mode 100644 index 00000000000000..4ea79dbbf73512 --- /dev/null +++ b/test/parallel/test-internal-modules-expose.js @@ -0,0 +1,6 @@ +// Flags: --expose_internals + +var common = require('../common'); +var assert = require('assert'); + +assert.equal(typeof require('internal/freelist').FreeList, 'function'); diff --git a/test/parallel/test-internal-modules.js b/test/parallel/test-internal-modules.js new file mode 100644 index 00000000000000..ebba2500d568b2 --- /dev/null +++ b/test/parallel/test-internal-modules.js @@ -0,0 +1,8 @@ +var common = require('../common'); +var assert = require('assert'); + +assert.throws(function() { + require('internal/freelist'); +}); + +assert(require('../fixtures/internal-modules') === 42); diff --git a/tools/js2c.py b/tools/js2c.py index bbbccb289ad67e..cc2c3045d07369 100755 --- a/tools/js2c.py +++ b/tools/js2c.py @@ -238,11 +238,11 @@ def ReadMacros(lines): NATIVE_DECLARATION = """\ - { "%(id)s", %(id)s_native, sizeof(%(id)s_native)-1 }, + { "%(id)s", %(escaped_id)s_native, sizeof(%(escaped_id)s_native)-1 }, """ SOURCE_DECLARATION = """\ - const char %(id)s_native[] = { %(data)s }; + const char %(escaped_id)s_native[] = { %(data)s }; """ @@ -293,16 +293,29 @@ def JS2C(source, target): lines = ExpandMacros(lines, macros) lines = CompressScript(lines, do_jsmin) data = ToCArray(s, lines) - id = os.path.basename(str(s)).split('.')[0] + id = '/'.join(re.split('/|\\\\', s)[1:]).split('.')[0] if delay: id = id[:-6] if delay: delay_ids.append((id, len(lines))) else: ids.append((id, len(lines))) - source_lines.append(SOURCE_DECLARATION % { 'id': id, 'data': data }) - source_lines_empty.append(SOURCE_DECLARATION % { 'id': id, 'data': 0 }) - native_lines.append(NATIVE_DECLARATION % { 'id': id }) - + + escaped_id = id.replace('/', '$') + source_lines.append(SOURCE_DECLARATION % { + 'id': id, + 'escaped_id': escaped_id, + 'data': data + }) + source_lines_empty.append(SOURCE_DECLARATION % { + 'id': id, + 'escaped_id': escaped_id, + 'data': 0 + }) + native_lines.append(NATIVE_DECLARATION % { + 'id': id, + 'escaped_id': escaped_id + }) + # Build delay support functions get_index_cases = [ ] get_script_source_cases = [ ]