From 48864f6d8fc7a8fb803058b2cf210323d54fe89e Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Tue, 21 Jan 2014 19:59:12 +0200 Subject: [PATCH] first draft of 'initjs' code which would allow compatibility cruft to be implemented in JS and executed in init --- make_dist.sh | 11 +++++++++++ src/duk_features.h | 6 ++++++ src/duk_hthread_builtins.c | 16 ++++++++++++++++ src/duk_initjs_legacy.js | 19 +++++++++++++++++++ src/genbuiltins.py | 32 +++++++++++++++++++++++++------- 5 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 src/duk_initjs_legacy.js diff --git a/make_dist.sh b/make_dist.sh index e2818a97..a3b3e9f2 100644 --- a/make_dist.sh +++ b/make_dist.sh @@ -211,6 +211,16 @@ for i in \ cp licenses/$i $DIST/licenses/ done +# Initjs code: built-in Ecmascript code snippets which are evaluated when +# a new global context is created. UglifyJS is used to compact the source, +# not to obfuscate it (although that happens as an unwanted side effect). + +cat \ + src/duk_initjs_legacy.js \ + | UglifyJS/bin/uglifyjs --ascii --no-dead-code --no-copyright \ + > $DISTSRCSEP/duk_initjs_min.js.tmp +cp $DISTSRCSEP/duk_initjs_min.js.tmp $DISTSRCSEP/duk_initjs_min.js + # Autogenerated strings and built-in files # # There are currently no profile specific variants of strings/builtins, but @@ -225,6 +235,7 @@ python src/genbuildparams.py \ python src/genbuiltins.py \ --buildinfo=$DISTSRCSEP/buildparams.json.tmp \ + --initjs-data=$DISTSRCSEP/duk_initjs_min.js.tmp \ --out-header=$DISTSRCSEP/duk_builtins.h \ --out-source=$DISTSRCSEP/duk_builtins.c \ diff --git a/src/duk_features.h b/src/duk_features.h index d7e55847..67c84689 100644 --- a/src/duk_features.h +++ b/src/duk_features.h @@ -1304,6 +1304,12 @@ extern double duk_computed_nan; #undef DUK_USE_JSONC #endif +/* + * InitJS code + */ + +#define DUK_USE_INITJS + /* * Miscellaneous */ diff --git a/src/duk_hthread_builtins.c b/src/duk_hthread_builtins.c index 2bcb372b..6120b133 100644 --- a/src/duk_hthread_builtins.c +++ b/src/duk_hthread_builtins.c @@ -482,6 +482,22 @@ void duk_hthread_create_builtin_objects(duk_hthread *thr) { DUK_USE_ARCH_STRING); duk_def_prop_stridx(ctx, DUK_BIDX_DUK, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC); + /* + * InitJS code - Ecmascript code evaluated from a built-in source + * which provides e.g. backward compatibility. User can also provide + * JS code to be evaluated at startup. + */ + +#ifdef DUK_USE_INITJS + /* FIXME: compression */ + duk_eval_string(ctx, duk_initjs_data); /* initjs data is NUL terminated */ +#endif /* DUK_USE_INITJS */ + +#ifdef DUK_USE_USER_INITJS + /* FIXME: compression, at least as an option? */ + duk_eval_string(ctx, DUK_USE_USER_INITJS); +#endif /* DUK_USE_USER_INITJS */ + /* * Since built-ins are not often extended, compact them. */ diff --git a/src/duk_initjs_legacy.js b/src/duk_initjs_legacy.js new file mode 100644 index 00000000..19d75192 --- /dev/null +++ b/src/duk_initjs_legacy.js @@ -0,0 +1,19 @@ +/* + * Init code for legacy compatibility. + * + * Compatibility properties / wrapper functions here allow Duktape to remain + * compatible for user code when core features are changed, without burdening + * the main C code with compatibility stuff. + */ + +(function(D) { + function def(name, value) { + Object.defineProperty(D, name, { + value: value, + writable: true, + enumerable: false, + configurable: true + }); + } + def('build', ''); // removed in Duktape 0.9.0 +})(Duktape); diff --git a/src/genbuiltins.py b/src/genbuiltins.py index 24021ee5..414503f3 100644 --- a/src/genbuiltins.py +++ b/src/genbuiltins.py @@ -1294,6 +1294,7 @@ class GenBuiltins: builtins = None gs = None init_data = None + initjs_data = None native_func_hash = None native_func_list = None builtin_indexes = None @@ -1302,7 +1303,7 @@ class GenBuiltins: count_normal_props = None count_function_props = None - def __init__(self, build_info = None, byte_order=None, ext_section_b=None, ext_browser_like=None): + def __init__(self, build_info=None, initjs_data=None, byte_order=None, ext_section_b=None, ext_browser_like=None): self.build_info = build_info self.byte_order = byte_order self.ext_section_b = ext_section_b @@ -1311,6 +1312,10 @@ class GenBuiltins: self.builtins = copy.deepcopy(builtins_orig) self.gs = None self.init_data = None + self.initjs_data = initjs_data + if len(self.initjs_data) > 1 and self.initjs_data[-1] != '\0': + # force NUL termination, init code now expects that + self.initjs_data += '\0' self.native_func_hash = {} self.native_func_list = [] self.builtin_indexes = {} @@ -1676,8 +1681,8 @@ class GenBuiltins: self.init_data = be.getByteString() - print '%d bytes of built-in init data, %d built-in objects, %d normal props, %d func props' % \ - (len(self.init_data), self.count_builtins, self.count_normal_props, self.count_function_props) + print '%d bytes of built-in init data, %d built-in objects, %d normal props, %d func props, %d initjs data bytes' % \ + (len(self.init_data), self.count_builtins, self.count_normal_props, self.count_function_props, len(self.initjs_data)) def emitSource(self, genc): self.gs.emitStringsData(genc) @@ -1686,16 +1691,24 @@ class GenBuiltins: self.writeNativeFuncArray(genc) genc.emitLine('') genc.emitArray(self.init_data, 'duk_builtins_data', typename='duk_uint8_t', intvalues=True, const=True) + genc.emitLine('#ifdef DUK_USE_INITJS') + genc.emitArray(self.initjs_data, 'duk_initjs_data', typename='duk_uint8_t', intvalues=True, const=True) + genc.emitLine('#endif /* DUK_USE_INITJS */') def emitHeader(self, genc): self.gs.emitStringsHeader(genc) genc.emitLine('') genc.emitLine('extern const duk_c_function duk_bi_native_functions[];') - genc.emitLine('') genc.emitLine('extern const duk_uint8_t duk_builtins_data[];') + genc.emitLine('#ifdef DUK_USE_INITJS') + genc.emitLine('extern const duk_uint8_t duk_initjs_data[];') + genc.emitLine('#endif /* DUK_USE_INITJS */') genc.emitLine('') genc.emitDefine('DUK_BUILTINS_DATA_LENGTH', len(self.init_data)) + genc.emitLine('#ifdef DUK_USE_INITJS') + genc.emitDefine('DUK_INITJS_DATA_LENGTH', len(self.initjs_data)) + genc.emitLine('#endif /* DUK_USE_INITJS */') genc.emitLine('') for idx,t in enumerate(self.builtins): def_name1, def_name2 = self.generateDefineNames(t['id']) @@ -1711,6 +1724,7 @@ class GenBuiltins: if __name__ == '__main__': parser = optparse.OptionParser() parser.add_option('--buildinfo', dest='buildinfo') + parser.add_option('--initjs-data', dest='initjs_data') parser.add_option('--out-header', dest='out_header') parser.add_option('--out-source', dest='out_source') (opts, args) = parser.parse_args() @@ -1719,12 +1733,16 @@ if __name__ == '__main__': build_info = dukutil.json_decode(f.read().strip()) f.close() + f = open(opts.initjs_data, 'rb') + initjs_data = f.read(); + f.close() + # genbuiltins for different profiles - gb_little = GenBuiltins(build_info = build_info, byte_order='little', ext_section_b=True, ext_browser_like=True) + gb_little = GenBuiltins(build_info = build_info, initjs_data = initjs_data, byte_order='little', ext_section_b=True, ext_browser_like=True) gb_little.processBuiltins() - gb_big = GenBuiltins(build_info = build_info, byte_order='big', ext_section_b=True, ext_browser_like=True) + gb_big = GenBuiltins(build_info = build_info, initjs_data = initjs_data, byte_order='big', ext_section_b=True, ext_browser_like=True) gb_big.processBuiltins() - gb_middle = GenBuiltins(build_info = build_info, byte_order='middle', ext_section_b=True, ext_browser_like=True) + gb_middle = GenBuiltins(build_info = build_info, initjs_data = initjs_data, byte_order='middle', ext_section_b=True, ext_browser_like=True) gb_middle.processBuiltins() # write C source file containing both strings and builtins