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 <trev.norris@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
This commit is contained in:
Vladimir Kurchatkin 2015-02-14 22:53:34 +03:00
parent 45814216ee
commit 2db758c562
12 changed files with 91 additions and 35 deletions

View File

@ -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');

View File

@ -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');

24
lib/internal/freelist.js Normal file
View File

@ -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;
};

View File

@ -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;
}

View File

@ -69,6 +69,8 @@
'lib/v8.js',
'lib/vm.js',
'lib/zlib.js',
'lib/internal/freelist.js',
],
},

View File

@ -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;

View File

@ -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];
};

View File

@ -0,0 +1 @@
module.exports = require('internal/freelist');

View File

@ -0,0 +1 @@
module.exports = 42;

View File

@ -0,0 +1,6 @@
// Flags: --expose_internals
var common = require('../common');
var assert = require('assert');
assert.equal(typeof require('internal/freelist').FreeList, 'function');

View File

@ -0,0 +1,8 @@
var common = require('../common');
var assert = require('assert');
assert.throws(function() {
require('internal/freelist');
});
assert(require('../fixtures/internal-modules') === 42);

View File

@ -238,11 +238,11 @@ static const struct _native natives[] = {
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 = [ ]