isomorfeus-speednode 0.6.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +16 -27
- data/lib/isomorfeus/speednode/attach_pipe.rb +1 -1
- data/lib/isomorfeus/speednode/runner.js +86 -77
- data/lib/isomorfeus/speednode/runtime/context.rb +2 -2
- data/lib/isomorfeus/speednode/runtime/vm.rb +2 -2
- data/lib/isomorfeus/speednode/runtime/vm_command.rb +1 -1
- data/lib/isomorfeus/speednode/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7b3ece9e49e7a5105aef77b28b04445e4d39e2f22d061bfd1f03e43a79e403eb
|
4
|
+
data.tar.gz: e3d57e156c9d1efa686a18ae784125cc8c9d553e9946cabfd0c1325f20a959f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67a6b031a66b5b29a9db16924087dc013a4c0ce360edbc8c4db3c076766c6c31d00783472a7b6f4d6bde526c61602ff1a78cc4e343c142016ef183005dcb339c
|
7
|
+
data.tar.gz: c4600a01abe22631455c4dce5209f656409a7931b5295116a551420c03c78906b3d6733afac90ebc87ce3835c9af2228b35c1e3bdb86296dc5aac2ce93b4ecdd
|
data/README.md
CHANGED
@@ -59,7 +59,7 @@ Scripts can be precompiled and stored for repeated execution, which leads to a s
|
|
59
59
|
```ruby
|
60
60
|
context = ExecJS.compile('Test = "test"')
|
61
61
|
context.add_script(key: 'super', source: some_large_javascript) # will compile and store the script
|
62
|
-
context.eval_script(
|
62
|
+
context.eval_script(key: 'super') # will run the precompiled script in the context
|
63
63
|
```
|
64
64
|
For the actual performance benefit see below.
|
65
65
|
|
@@ -96,38 +96,28 @@ Attaching and calling ruby methods to/from permissive contexts is not that fast.
|
|
96
96
|
|
97
97
|
Highly scientific, maybe.
|
98
98
|
|
99
|
-
1000 rounds using node
|
99
|
+
1000 rounds using isomorfeus-speednode 0.6.1 with node 18.15.0 on a older CPU on Linux
|
100
|
+
(ctx = using context, scsc = using precompiled scripts):
|
100
101
|
```
|
101
102
|
standard ExecJS CoffeeScript eval benchmark:
|
102
|
-
|
103
|
-
Isomorfeus Speednode Node.js (V8):
|
104
|
-
Isomorfeus Speednode Node.js (V8) ctx:
|
105
|
-
Isomorfeus Speednode Node.js (V8) scsc:
|
106
|
-
mini_racer (
|
107
|
-
mini_racer (
|
103
|
+
user system total real
|
104
|
+
Isomorfeus Speednode Node.js (V8): 0.107551 0.024227 0.131778 ( 1.034893)
|
105
|
+
Isomorfeus Speednode Node.js (V8) ctx: 0.081142 0.064432 0.145574 ( 0.878249)
|
106
|
+
Isomorfeus Speednode Node.js (V8) scsc: 0.058941 0.040266 0.099207 ( 0.525479)
|
107
|
+
mini_racer (0.6.3, libv8-node 16.10.0): 0.563453 0.416156 0.979609 ( 0.628226)
|
108
|
+
mini_racer (0.6.3, libv8-node 16.10.0) ctx: 0.393274 0.187259 0.580533 ( 0.434056)
|
108
109
|
|
109
110
|
eval overhead benchmark:
|
110
|
-
|
111
|
-
Isomorfeus Speednode Node.js (V8):
|
112
|
-
Isomorfeus Speednode Node.js (V8) ctx:
|
113
|
-
Isomorfeus Speednode Node.js (V8) scsc:
|
114
|
-
mini_racer (
|
115
|
-
mini_racer (
|
116
|
-
|
117
|
-
```
|
118
|
-
minify discourse benchmark from mini_racer:
|
119
|
-
```
|
120
|
-
minify discourse_app_minified.js:
|
121
|
-
user system total real
|
122
|
-
isomorfeus-speednode Windows 0.016000 0.078000 0.094000 ( 11.828518)
|
123
|
-
isomorfeus-speednode Linux 0.043747 0.000000 15.931284 ( 11.860528)
|
124
|
-
mini_racer 0.043471 0.000000 15.974214 ( 11.923735)
|
125
|
-
node 0.043695 0.000000 15.812040 ( 11.781835)
|
111
|
+
user system total real
|
112
|
+
Isomorfeus Speednode Node.js (V8): 0.065491 0.026181 0.091672 ( 0.196204)
|
113
|
+
Isomorfeus Speednode Node.js (V8) ctx: 0.060876 0.029535 0.090411 ( 0.197763)
|
114
|
+
Isomorfeus Speednode Node.js (V8) scsc: 0.036967 0.045451 0.082418 ( 0.133337)
|
115
|
+
mini_racer (0.6.3, libv8-node 16.10.0): 0.070333 0.056378 0.126711 ( 0.100380)
|
116
|
+
mini_racer (0.6.3, libv8-node 16.10.0) ctx: 0.072719 0.049049 0.121768 ( 0.095643)
|
126
117
|
```
|
127
118
|
|
128
119
|
To run benchmarks:
|
129
120
|
- clone repo
|
130
|
-
- `cd ruby`
|
131
121
|
- `bundle install`
|
132
122
|
- `bundle exec rake bench`
|
133
123
|
|
@@ -135,6 +125,5 @@ To run benchmarks:
|
|
135
125
|
|
136
126
|
To run tests:
|
137
127
|
- clone repo
|
138
|
-
- `cd ruby`
|
139
128
|
- `bundle install`
|
140
|
-
- `bundle exec rake
|
129
|
+
- `bundle exec rake`
|
@@ -132,70 +132,82 @@ CircularJSON.stringify = function stringify(value, replacer, space, doNotResolve
|
|
132
132
|
};
|
133
133
|
/*** end of circular-json ***/
|
134
134
|
|
135
|
+
// serialize Map as Object, also below in attach
|
136
|
+
function simple_map_replacer(key, value) {
|
137
|
+
if (value && typeof value === 'object' && value.constructor.name === "Map")
|
138
|
+
return Object.fromEntries(value);
|
139
|
+
return value;
|
140
|
+
}
|
141
|
+
|
135
142
|
function attachFunctionSource(responder_path, context, func) {
|
136
|
-
return func
|
137
|
-
let context =
|
138
|
-
let func =
|
139
|
-
let request = [context, func, method_args]
|
140
|
-
let responder_path = '
|
141
|
-
if (!global.__responder_socket) {
|
142
|
-
return new Promise(function(resolve, reject) {
|
143
|
-
setTimeout(function(){
|
144
|
-
if (os.platform()
|
145
|
-
let socket = net.connect(responder_path)
|
146
|
-
socket.on('connect', function(){
|
147
|
-
global.__responder_socket = true
|
148
|
-
socket.destroy()
|
149
|
-
resolve(
|
150
|
-
})
|
151
|
-
socket.on('error', function (err) {
|
152
|
-
resolve(
|
153
|
-
})
|
154
|
-
} else {
|
155
|
-
if (fs.existsSync(responder_path)) { global.__responder_socket = true; }
|
156
|
-
resolve(
|
157
|
-
}
|
158
|
-
}, 10)
|
159
|
-
})
|
160
|
-
}
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
143
|
+
return `${func} = async function(...method_args) {
|
144
|
+
let context = '${context}';
|
145
|
+
let func = '${func}';
|
146
|
+
let request = [context, func, method_args];
|
147
|
+
let responder_path = '${responder_path}';
|
148
|
+
if (!global.__responder_socket) {
|
149
|
+
return new Promise(function(resolve, reject) {
|
150
|
+
setTimeout(function(){
|
151
|
+
if (os.platform() == 'win32') {
|
152
|
+
let socket = net.connect(responder_path);
|
153
|
+
socket.on('connect', function(){
|
154
|
+
global.__responder_socket = true;
|
155
|
+
socket.destroy();
|
156
|
+
resolve(${func}(...method_args));
|
157
|
+
})
|
158
|
+
socket.on('error', function (err) {
|
159
|
+
resolve(${func}(...method_args));
|
160
|
+
});
|
161
|
+
} else {
|
162
|
+
if (fs.existsSync(responder_path)) { global.__responder_socket = true; }
|
163
|
+
resolve(${func}(...method_args));
|
164
|
+
}
|
165
|
+
}, 10)
|
166
|
+
});
|
167
|
+
}
|
168
|
+
function simple_map_replacer(key, value) {
|
169
|
+
if (value && typeof value === 'object' && value.constructor.name === "Map")
|
170
|
+
return Object.fromEntries(value);
|
171
|
+
return value;
|
172
|
+
}
|
173
|
+
return new Promise(function(resolve, reject) {
|
174
|
+
let request_json = JSON.stringify(request, simple_map_replacer);
|
175
|
+
let buffer = Buffer.alloc(0);
|
176
|
+
let socket = net.connect(responder_path);
|
177
|
+
socket.setTimeout(2000);
|
178
|
+
socket.on('error', function (err) {
|
179
|
+
if (err.syscall === 'connect') {
|
180
|
+
// ignore, close will handle
|
181
|
+
} else if ((os.platform() == 'win32') && err.message.includes('read EPIPE')) {
|
182
|
+
// ignore, close will handle
|
183
|
+
} else if ((os.platform() == 'win32') && err.message.includes('write EPIPE')) {
|
184
|
+
// ignore, close will handle
|
185
|
+
} else { reject(err); }
|
186
|
+
});
|
187
|
+
socket.on('ready', function () {
|
188
|
+
socket.write(request_json + "\x04");
|
189
|
+
});
|
190
|
+
socket.on('data', function (data) {
|
191
|
+
buffer = Buffer.concat([buffer, data]);
|
192
|
+
});
|
193
|
+
socket.on('timeout', function() {
|
194
|
+
socket.destroy();
|
195
|
+
reject();
|
196
|
+
});
|
197
|
+
socket.on('close', function() {
|
198
|
+
if (buffer.length > 0) {
|
199
|
+
let method_result = JSON.parse(buffer.toString('utf8'));
|
200
|
+
if (method_result[0] == 'err') {
|
201
|
+
reject(method_result);
|
202
|
+
} else {
|
203
|
+
resolve(method_result[1]);
|
204
|
+
}
|
205
|
+
} else {
|
206
|
+
resolve(null);
|
207
|
+
}
|
208
|
+
});
|
209
|
+
});
|
210
|
+
}`;
|
199
211
|
}
|
200
212
|
|
201
213
|
function createCompatibleContext(uuid, options) {
|
@@ -228,18 +240,15 @@ function getContext(uuid) {
|
|
228
240
|
|
229
241
|
function getContextOptions(uuid) {
|
230
242
|
let options = { filename: "(execjs)", displayErrors: true };
|
231
|
-
if (contexts[uuid].options.timeout)
|
243
|
+
if (contexts[uuid].options.timeout)
|
232
244
|
options.timeout = contexts[uuid].options.timeout;
|
233
|
-
}
|
234
245
|
return options;
|
235
246
|
}
|
236
247
|
|
237
248
|
function massageStackTrace(stack) {
|
238
|
-
if (stack && stack.indexOf("SyntaxError") == 0)
|
249
|
+
if (stack && stack.indexOf("SyntaxError") == 0)
|
239
250
|
return "(execjs):1\n" + stack;
|
240
|
-
|
241
|
-
return stack;
|
242
|
-
}
|
251
|
+
return stack;
|
243
252
|
}
|
244
253
|
|
245
254
|
let socket_path = process.env.SOCKET_PATH;
|
@@ -261,7 +270,7 @@ let commands = {
|
|
261
270
|
attach: function(input) {
|
262
271
|
let context = getContext(input.context);
|
263
272
|
let responder_path;
|
264
|
-
if (
|
273
|
+
if (process.platform == 'win32') { responder_path = '\\\\\\\\.\\\\pipe\\\\' + socket_path + '_responder'; }
|
265
274
|
else { responder_path = socket_path + '_responder' }
|
266
275
|
let result = vm.runInContext(attachFunctionSource(responder_path, input.context, input.func), context, { filename: "(execjs)", displayErrors: true });
|
267
276
|
return formatResult(result);
|
@@ -319,15 +328,15 @@ let commands = {
|
|
319
328
|
}
|
320
329
|
},
|
321
330
|
eval: function (input) {
|
322
|
-
if (input.source.match(/^\s*{/)) { input.source =
|
323
|
-
else if (input.source.match(/^\s*function\s*\(/)) { input.source =
|
331
|
+
if (input.source.match(/^\s*{/)) { input.source = `(${input.source})`; }
|
332
|
+
else if (input.source.match(/^\s*function\s*\(/)) { input.source = `(${input.source})`; }
|
324
333
|
let result = vm.runInContext(input.source, getContext(input.context), getContextOptions(input.context));
|
325
334
|
return formatResult(result);
|
326
335
|
},
|
327
336
|
evald: function(input) {
|
328
337
|
if (debug_contexts.includes(input.context)) {
|
329
|
-
if (input.source.match(/^\s*{/)) { input.source =
|
330
|
-
else if (input.source.match(/^\s*function\s*\(/)) { input.source =
|
338
|
+
if (input.source.match(/^\s*{/)) { input.source = `(${input.source})`; }
|
339
|
+
else if (input.source.match(/^\s*function\s*\(/)) { input.source = `(${input.source})`; }
|
331
340
|
let result = eval(input.source);
|
332
341
|
return formatResult(result);
|
333
342
|
} else {
|
@@ -384,9 +393,9 @@ let server = net.createServer(function(s) {
|
|
384
393
|
return;
|
385
394
|
}
|
386
395
|
|
387
|
-
try { outputJSON = JSON.stringify(result); }
|
396
|
+
try { outputJSON = JSON.stringify(result, simple_map_replacer); }
|
388
397
|
catch(err) {
|
389
|
-
if (err.message.includes('circular')) { outputJSON = CircularJSON.stringify(result); }
|
398
|
+
if (err.message.includes('circular')) { outputJSON = CircularJSON.stringify(result, simple_map_replacer); }
|
390
399
|
else { outputJSON = JSON.stringify([['', err].join(''), err.stack]); }
|
391
400
|
s.write([outputJSON, "\x04"].join(''));
|
392
401
|
if (process_exit !== false) { process.exit(process_exit); }
|
@@ -399,5 +408,5 @@ let server = net.createServer(function(s) {
|
|
399
408
|
});
|
400
409
|
});
|
401
410
|
|
402
|
-
if (
|
411
|
+
if (process.platform == 'win32') { server.listen('\\\\.\\pipe\\' + socket_path); }
|
403
412
|
else { server.listen(socket_path); }
|
@@ -165,7 +165,7 @@ module Isomorfeus
|
|
165
165
|
end
|
166
166
|
|
167
167
|
def await_result
|
168
|
-
start_time = Time.now
|
168
|
+
start_time = ::Time.now
|
169
169
|
while eval_script(key: :_internal_exec_fin) && !timed_out?(start_time)
|
170
170
|
sleep 0.005
|
171
171
|
end
|
@@ -193,7 +193,7 @@ module Isomorfeus
|
|
193
193
|
end
|
194
194
|
|
195
195
|
def timed_out?(start_time)
|
196
|
-
if (Time.now - start_time) > @timeout
|
196
|
+
if (::Time.now - start_time) > @timeout
|
197
197
|
raise "IsomorfeusSpeednode: Command Execution timed out!"
|
198
198
|
end
|
199
199
|
false
|
@@ -5,7 +5,7 @@ if Gem.win_platform?
|
|
5
5
|
module Win32
|
6
6
|
class Pipe
|
7
7
|
def write(data)
|
8
|
-
bytes = FFI::MemoryPointer.new(:ulong)
|
8
|
+
bytes = ::FFI::MemoryPointer.new(:ulong)
|
9
9
|
|
10
10
|
raise Error, "no pipe created" unless @pipe
|
11
11
|
|
@@ -44,7 +44,7 @@ module Isomorfeus
|
|
44
44
|
attr_reader :responder
|
45
45
|
|
46
46
|
def initialize(options)
|
47
|
-
@mutex = Thread::Mutex.new
|
47
|
+
@mutex = ::Thread::Mutex.new
|
48
48
|
@socket_path = nil
|
49
49
|
@options = options
|
50
50
|
@started = false
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: isomorfeus-speednode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Biedermann
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: execjs
|
@@ -33,7 +33,7 @@ dependencies:
|
|
33
33
|
version: 3.13.23
|
34
34
|
- - "<"
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version: 3.
|
36
|
+
version: 3.16.0
|
37
37
|
type: :runtime
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: 3.13.23
|
44
44
|
- - "<"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: 3.
|
46
|
+
version: 3.16.0
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: win32-pipe
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -78,14 +78,14 @@ dependencies:
|
|
78
78
|
requirements:
|
79
79
|
- - "~>"
|
80
80
|
- !ruby/object:Gem::Version
|
81
|
-
version: 5.18.
|
81
|
+
version: 5.18.1
|
82
82
|
type: :development
|
83
83
|
prerelease: false
|
84
84
|
version_requirements: !ruby/object:Gem::Requirement
|
85
85
|
requirements:
|
86
86
|
- - "~>"
|
87
87
|
- !ruby/object:Gem::Version
|
88
|
-
version: 5.18.
|
88
|
+
version: 5.18.1
|
89
89
|
- !ruby/object:Gem::Dependency
|
90
90
|
name: rake
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
@@ -157,7 +157,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
157
|
- !ruby/object:Gem::Version
|
158
158
|
version: '0'
|
159
159
|
requirements: []
|
160
|
-
rubygems_version: 3.4.
|
160
|
+
rubygems_version: 3.4.10
|
161
161
|
signing_key:
|
162
162
|
specification_version: 4
|
163
163
|
summary: A fast ExecJS runtime based on nodejs, tuned for Isomorfeus.
|