From 4322385477f9d0e8f90d3bac8a0ab7120f55ba0e Mon Sep 17 00:00:00 2001 From: Ajai Date: Tue, 19 Feb 2019 23:01:59 -0800 Subject: [PATCH 1/8] Converts _createBranchConstructor in Types prototype chain --- lib/types.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/types.js b/lib/types.js index 8c3dd992..f8847092 100644 --- a/lib/types.js +++ b/lib/types.js @@ -715,11 +715,18 @@ Type.prototype._createBranchConstructor = function () { if (name === 'null') { return null; } - var attr = ~name.indexOf('.') ? 'this[\'' + name + '\']' : 'this.' + name; - var body = 'return function Branch$(val) { ' + attr + ' = val; };'; - var Branch = (new Function(body))(); + function ConstructorFunction() { + return function Branch$(val) { + if (~name.indexOf('.')) { + this[`${name}`] = val; + } else { + this[name] = val; + } + }; + } + var Branch = ConstructorFunction(); Branch.type = this; - Branch.prototype.unwrap = new Function('return ' + attr + ';'); + Branch.prototype.unwrap = function() { return this[`${name}`]; }; Branch.prototype.unwrapped = Branch.prototype.unwrap; // Deprecated. return Branch; }; From 217b3f52f91fcf5f6229f171adabadb617399207 Mon Sep 17 00:00:00 2001 From: Ajai Date: Wed, 20 Feb 2019 00:28:38 -0800 Subject: [PATCH 2/8] Converts _createConstructor function in RecordType to be simple function --- lib/types.js | 64 ++++++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/lib/types.js b/lib/types.js index f8847092..8cd1f7ff 100644 --- a/lib/types.js +++ b/lib/types.js @@ -2131,11 +2131,9 @@ RecordType.prototype._getConstructorName = function () { RecordType.prototype._createConstructor = function (errorStackTraces) { // jshint -W054 - var outerArgs = []; - var innerArgs = []; - var ds = []; // Defaults. - var innerBody = ''; + var ds = {}; // Defaults. var i, l, field, name, defaultValue, hasDefault, stackField; + for (i = 0, l = this.fields.length; i < l; i++) { field = this.fields[i]; defaultValue = field.defaultValue; @@ -2149,36 +2147,42 @@ RecordType.prototype._createConstructor = function (errorStackTraces) { // particular, without a default) to populate a stack trace below. stackField = field; } - innerArgs.push('v' + i); - innerBody += ' '; - if (!hasDefault) { - innerBody += 'this.' + name + ' = v' + i + ';\n'; - } else { - innerBody += 'if (v' + i + ' === undefined) { '; - innerBody += 'this.' + name + ' = d' + ds.length + '(); '; - innerBody += '} else { this.' + name + ' = v' + i + '; }\n'; - outerArgs.push('d' + ds.length); - ds.push(defaultValue); - } - } - if (stackField) { - // We should populate a stack trace. - innerBody += ' if (this.stack === undefined) { '; - /* istanbul ignore else */ - if (typeof Error.captureStackTrace == 'function') { - // v8 runtimes, the easy case. - innerBody += 'Error.captureStackTrace(this, this.constructor);'; - } else { - // A few other runtimes (e.g. SpiderMonkey), might not work everywhere. - innerBody += 'this.stack = Error().stack;'; + if (hasDefault) { + ds[i] = defaultValue; } - innerBody += ' }\n'; } - var outerBody = 'return function ' + this._getConstructorName() + '('; - outerBody += innerArgs.join() + ') {\n' + innerBody + '};'; - var Record = new Function(outerArgs.join(), outerBody).apply(undefined, ds); var self = this; + function ConstructorFunction(outerArgs) { + const constructorName = self._getConstructorName(); + var innerFunction = ({ + [constructorName]: function(...innerArgs) { + for(var i = 0, l = self.fields.length; i < l; i++) { + let f = self.fields[i]; + if (f.defaultValue() === undefined) { + this[f.name] = innerArgs[i]; + } else { + if (innerArgs[i] === undefined) { + this[f.name] = outerArgs[i](); + } else { + this[f.name] = innerArgs[i]; + } + } + } + if (stackField) { + if (this.stack === undefined) { + if (typeof Error.captureStackTrace === 'function') { + Error.captureStackTrace(this, this.constructor); + } else { + this.stack = Error().stack; + } + } + } + } + })[constructorName]; + return innerFunction; + } + var Record = ConstructorFunction(ds); Record.getType = function () { return self; }; Record.type = self; if (this._isError) { From 1fe8924cd6c2027a90fdeb20a21edda619f58f2b Mon Sep 17 00:00:00 2001 From: Ajai Date: Wed, 20 Feb 2019 00:55:56 -0800 Subject: [PATCH 3/8] Converts _createChecker in RecordType prototype chain --- lib/types.js | 105 ++++++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 51 deletions(-) diff --git a/lib/types.js b/lib/types.js index 8cd1f7ff..0fde41e6 100644 --- a/lib/types.js +++ b/lib/types.js @@ -2201,58 +2201,61 @@ RecordType.prototype._createConstructor = function (errorStackTraces) { RecordType.prototype._createChecker = function () { // jshint -W054 - var names = []; - var values = []; - var name = this._getConstructorName(); - var body = 'return function check' + name + '(v, f, h, p) {\n'; - body += ' if (\n'; - body += ' v === null ||\n'; - body += ' typeof v != \'object\' ||\n'; - body += ' (f && !this._checkFields(v))\n'; - body += ' ) {\n'; - body += ' if (h) { h(v, this); }\n'; - body += ' return false;\n'; - body += ' }\n'; - if (!this.fields.length) { - // Special case, empty record. We handle this directly. - body += ' return true;\n'; - } else { - for (i = 0, l = this.fields.length; i < l; i++) { - field = this.fields[i]; - names.push('t' + i); - values.push(field.type); - if (field.defaultValue() !== undefined) { - body += ' var v' + i + ' = v.' + field.name + ';\n'; - } - } - body += ' if (h) {\n'; - body += ' var b = 1;\n'; - body += ' var j = p.length;\n'; - body += ' p.push(\'\');\n'; - var i, l, field; - for (i = 0, l = this.fields.length; i < l; i++) { - field = this.fields[i]; - body += ' p[j] = \'' + field.name + '\';\n'; - body += ' b &= '; - if (field.defaultValue() === undefined) { - body += 't' + i + '._check(v.' + field.name + ', f, h, p);\n'; - } else { - body += 'v' + i + ' === undefined || '; - body += 't' + i + '._check(v' + i + ', f, h, p);\n'; + const values = []; + this.fields.forEach(field => { + values.push(field.type); + }); + var self = this; + function ConstructorFunction(outerArgs) { + var constructorName = self._getConstructorName(); + var innerFunction = ({ + [constructorName]: function (v, f, h, p) { + if (v === null || typeof v !== 'object' || (f && !this._checkFields(v))) { + if (h) { + h(v, this); + } + return false; + } + const vArray = []; + if (!self.fields.length) { + return true; + } else { + for (var i =0, l = self.fields.length; i < l; i++) { + let f = self.fields[i]; + if (f.defaultValue() !== undefined) { + vArray.push(v[f.name]); + } + } + } + if (h) { + var b = 1; + var j = p.length; + p.push(''); + for (var i =0, l = self.fields.length; i < l; i++) { + let f = self.fields[i]; + p[j] = f.name; + b &= f.defaultValue() === undefined ? + outerArgs[i]._check(v[f.name], f, h, p) + : + vArray[i] === undefined || outerArgs[i]._check(vArray[i], f, h, p); + } + p.pop(); + return !!b; + } else { + return self.fields.reduce((prevVal, currentVal, i) => { + return prevVal && ( + currentVal.defaultValue() === undefined ? + outerArgs[i]._check(v[currentVal.name]) + : + vArray[i] === undefined || outerArgs[i]._check(vArray[i], f) + ); + }, true); + } } - } - body += ' p.pop();\n'; - body += ' return !!b;\n'; - body += ' } else {\n return (\n '; - body += this.fields.map(function (field, i) { - return field.defaultValue() === undefined ? - 't' + i + '._check(v.' + field.name + ', f)' : - '(v' + i + ' === undefined || t' + i + '._check(v' + i + ', f))'; - }).join(' &&\n '); - body += '\n );\n }\n'; - } - body += '};'; - return new Function(names.join(), body).apply(undefined, values); + })[constructorName]; + return innerFunction; + } + return ConstructorFunction(values); }; RecordType.prototype._createReader = function () { From 07ab8db895a2699ab559a48e1057cff808023112 Mon Sep 17 00:00:00 2001 From: Ajai Date: Wed, 20 Feb 2019 00:59:56 -0800 Subject: [PATCH 4/8] Converts _createReader in RecordType prototype chain --- lib/types.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/types.js b/lib/types.js index 0fde41e6..d7e14f28 100644 --- a/lib/types.js +++ b/lib/types.js @@ -2260,22 +2260,22 @@ RecordType.prototype._createChecker = function () { RecordType.prototype._createReader = function () { // jshint -W054 - var names = []; var values = [this.recordConstructor]; var i, l; for (i = 0, l = this.fields.length; i < l; i++) { - names.push('t' + i); values.push(this.fields[i].type); } - var name = this._getConstructorName(); - var body = 'return function read' + name + '(t) {\n'; - body += ' return new ' + name + '(\n '; - body += names.map(function (s) { return s + '._read(t)'; }).join(',\n '); - body += '\n );\n};'; - names.unshift(name); - // We can do this since the JS spec guarantees that function arguments are - // evaluated from left to right. - return new Function(names.join(), body).apply(undefined, values); + var self = this; + function ConstructorFunction(outerArgs) { + var constructorName = self._getConstructorName(); + var innerFunction = ({ + [constructorName]: function (t) { + return new outerArgs[0](...outerArgs.slice(1).map(ftype => ftype['_read'](t))); + } + })[constructorName]; + return innerFunction; + } + return ConstructorFunction(values); }; RecordType.prototype._createSkipper = function () { From 8a51f05f5b701171fcb0689c6352b4db8abdfc12 Mon Sep 17 00:00:00 2001 From: Ajai Date: Wed, 20 Feb 2019 01:01:46 -0800 Subject: [PATCH 5/8] Converts _createSkipper in RecordType prototype chain --- lib/types.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/types.js b/lib/types.js index d7e14f28..2c1524f8 100644 --- a/lib/types.js +++ b/lib/types.js @@ -2280,17 +2280,21 @@ RecordType.prototype._createReader = function () { RecordType.prototype._createSkipper = function () { // jshint -W054 - var args = []; - var body = 'return function skip' + this._getConstructorName() + '(t) {\n'; var values = []; - var i, l; - for (i = 0, l = this.fields.length; i < l; i++) { - args.push('t' + i); - values.push(this.fields[i].type); - body += ' t' + i + '._skip(t);\n'; + this.fields.forEach((field) => { + values.push(field.type); + }); + var self = this; + function ConstructorFunction(outerArgs) { + var constructorName = self._getConstructorName(); + var innerFunction = ({ + [constructorName]: function (t) { + outerArgs.forEach(arg => arg._skip(t)); + } + })[constructorName]; + return innerFunction; } - body += '}'; - return new Function(args.join(), body).apply(undefined, values); + return ConstructorFunction(values); }; RecordType.prototype._createWriter = function () { From d4d3f70a21630f138c7077fbb4f3fa681106b25c Mon Sep 17 00:00:00 2001 From: Ajai Date: Wed, 20 Feb 2019 01:08:29 -0800 Subject: [PATCH 6/8] Converts _createWriter in RecordType prototype chain --- lib/types.js | 54 ++++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/lib/types.js b/lib/types.js index 2c1524f8..2ab3d0e7 100644 --- a/lib/types.js +++ b/lib/types.js @@ -2300,33 +2300,37 @@ RecordType.prototype._createSkipper = function () { RecordType.prototype._createWriter = function () { // jshint -W054 // We still do default handling here, in case a normal JS object is passed. - var args = []; - var name = this._getConstructorName(); - var body = 'return function write' + name + '(t, v) {\n'; + var values = []; - var i, l, field, value; - for (i = 0, l = this.fields.length; i < l; i++) { - field = this.fields[i]; - args.push('t' + i); + var dValues = {}; + this.fields.forEach((field, i) => { values.push(field.type); - body += ' '; - if (field.defaultValue() === undefined) { - body += 't' + i + '._write(t, v.' + field.name + ');\n'; - } else { - value = field.type.toBuffer(field.defaultValue()).toString('binary'); - // Convert the default value to a binary string ahead of time. We aren't - // converting it to a buffer to avoid retaining too much memory. If we - // had our own buffer pool, this could be an idea in the future. - args.push('d' + i); - values.push(value); - body += 'var v' + i + ' = v.' + field.name + ';\n'; - body += 'if (v' + i + ' === undefined) {\n'; - body += ' t.writeBinary(d' + i + ', ' + value.length + ');\n'; - body += ' } else {\n t' + i + '._write(t, v' + i + ');\n }\n'; - } - } - body += '}'; - return new Function(args.join(), body).apply(undefined, values); + if (field.defaultValue() !== undefined) { + dValues[i] = field.type.toBuffer(field.defaultValue()).toString('binary'); + } + }); + var self = this; + function ConstructorFunction(vv, dv) { + var constructorName = self._getConstructorName(); + var innerFunction = ({ + [constructorName]: function (t, v) { + for (var i=0, l = self.fields.length; i Date: Sat, 23 Feb 2019 22:37:41 -0800 Subject: [PATCH 7/8] Converts _update in RecordType prototype chain --- lib/types.js | 83 +++++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/lib/types.js b/lib/types.js index 2ab3d0e7..0aee11d8 100644 --- a/lib/types.js +++ b/lib/types.js @@ -2342,8 +2342,6 @@ RecordType.prototype._update = function (resolver, type, opts) { var rFields = this.fields; var wFields = type.fields; var wFieldsMap = utils.toMap(wFields, function (f) { return f.name; }); - - var innerArgs = []; // Arguments for reader constructor. var resolvers = {}; // Resolvers keyed by writer field name. var i, j, field, name, names, matches, fieldResolver; for (i = 0; i < rFields.length; i++) { @@ -2367,62 +2365,61 @@ RecordType.prototype._update = function (resolver, type, opts) { f('no matching field for default-less %s.%s', type.name, field.name) ); } - innerArgs.push('undefined'); } else { name = matches[0]; fieldResolver = { resolver: field.type.createResolver(wFieldsMap[name].type, opts), - name: '_' + field.name, // Reader field name. + name: '_' + field.name // Reader field name. }; if (!resolvers[name]) { resolvers[name] = [fieldResolver]; } else { resolvers[name].push(fieldResolver); } - innerArgs.push(fieldResolver.name); } } - // See if we can add a bypass for unused fields at the end of the record. - var lazyIndex = -1; - i = wFields.length; - while (i && resolvers[wFields[--i].name] === undefined) { - lazyIndex = i; - } - - var uname = this._getConstructorName(); - var args = [uname]; - var values = [this.recordConstructor]; - var body = ' return function read' + uname + '(t, b) {\n'; - for (i = 0; i < wFields.length; i++) { - if (i === lazyIndex) { - body += ' if (!b) {\n'; - } - field = type.fields[i]; - name = field.name; - if (resolvers[name] === undefined) { - body += (~lazyIndex && i >= lazyIndex) ? ' ' : ' '; - args.push('r' + i); - values.push(field.type); - body += 'r' + i + '._skip(t);\n'; - } else { - j = resolvers[name].length; - while (j--) { - body += (~lazyIndex && i >= lazyIndex) ? ' ' : ' '; - args.push('r' + i + 'f' + j); - fieldResolver = resolvers[name][j]; - values.push(fieldResolver.resolver); - body += 'var ' + fieldResolver.name + ' = '; - body += 'r' + i + 'f' + j + '._' + (j ? 'peek' : 'read') + '(t);\n'; + var self = this; + function ConstructorFunction() { + var constructorName = self._getConstructorName(); + var innerFunction = ({ + [constructorName]: function (t, b) { + if (b) return; + var innerArgs = []; // Arguments for reader constructor. + for (i = 0; i < rFields.length; i++) { + field = rFields[i]; + names = getAliases(field); + matches = []; + for (j = 0; j < names.length; j++) { + name = names[j]; + if (wFieldsMap[name]) { + matches.push(name); + } + } + if (!matches.length) { + innerArgs.push(undefined); + } + } + for (var i = 0; i < wFields.length; i++) { + let wf = type.fields[i]; + name = wf.name; + if (resolvers[name] === undefined) { + wf.type._skip(t); + } else { + var j = resolvers[name].length; + while (j--) { + innerArgs.unshift(j ? resolvers[name][j].resolver._peek(t) : resolvers[name][j].resolver._read(t)) + } + } + } + console.log('Something: ', ...innerArgs); + return new self.recordConstructor(...innerArgs); } - } - } - if (~lazyIndex) { - body += ' }\n'; + })[constructorName]; + return innerFunction; } - body += ' return new ' + uname + '(' + innerArgs.join() + ');\n};'; - - resolver._read = new Function(args.join(), body).apply(undefined, values); + resolver._read = ConstructorFunction(); + }; RecordType.prototype._match = function (tap1, tap2) { From a730cc8018b79e114b6a3381bbb57760a24c6cef Mon Sep 17 00:00:00 2001 From: Ajai Date: Sun, 24 Feb 2019 10:54:27 -0800 Subject: [PATCH 8/8] Removes console.log statement --- lib/types.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/types.js b/lib/types.js index 0aee11d8..43f3e7d7 100644 --- a/lib/types.js +++ b/lib/types.js @@ -2412,7 +2412,6 @@ RecordType.prototype._update = function (resolver, type, opts) { } } } - console.log('Something: ', ...innerArgs); return new self.recordConstructor(...innerArgs); } })[constructorName];