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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 59fdae16925c182e3d86602153873a69f6a507d27d702a8405b70b191854a821
4
- data.tar.gz: faa6999fcdc0ffe5a294e975261b3a029227cd291554cd283d7e057a98b655dc
3
+ metadata.gz: 7b3ece9e49e7a5105aef77b28b04445e4d39e2f22d061bfd1f03e43a79e403eb
4
+ data.tar.gz: e3d57e156c9d1efa686a18ae784125cc8c9d553e9946cabfd0c1325f20a959f0
5
5
  SHA512:
6
- metadata.gz: '004933d5d91f7cb58bcdabe3a31ba3cf7b740dd8ebce97fe437d10c16e9e5874938db56f64520119ace1015b830b682bd552e5e9fd69dfa58f6766de14925c90'
7
- data.tar.gz: aaa36c20a56c37c462844b8b8e4e2df57224105939ae46a1159e91d59fe5c6bc9eafeb9a9cdccbcb0735623115b2f3e0440047b3ef55807b02fd9150e75786f6
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(:key: 'super') # will run the precompiled script in the context
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 16.14.0 on linux (ctx = using context, scsc = using precompiled scripts):
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
- user system total real
103
- Isomorfeus Speednode Node.js (V8): 0.086443 0.061089 0.147532 ( 0.567715)
104
- Isomorfeus Speednode Node.js (V8) ctx: 0.080821 0.047469 0.128290 ( 0.468664)
105
- Isomorfeus Speednode Node.js (V8) scsc: 0.089423 0.046541 0.135964 ( 0.381198) <- fastest
106
- mini_racer (V8): 0.723352 0.179944 0.903296 ( 0.513696)
107
- mini_racer (V8) ctx: 0.475681 0.226101 0.701782 ( 0.429463)
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
- user system total real
111
- Isomorfeus Speednode Node.js (V8): 0.028312 0.062895 0.091207 ( 0.199176)
112
- Isomorfeus Speednode Node.js (V8) ctx: 0.061245 0.027093 0.088338 ( 0.183092)
113
- Isomorfeus Speednode Node.js (V8) scsc: 0.061062 0.019203 0.080265 ( 0.107898) <- fastest
114
- mini_racer (V8): 0.103914 0.092251 0.196165 ( 0.125081)
115
- mini_racer (V8) ctx: 0.120440 0.060329 0.180769 ( 0.112695)
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 test`
129
+ - `bundle exec rake`
@@ -223,4 +223,4 @@ module Isomorfeus
223
223
  end
224
224
  end
225
225
  end
226
- end
226
+ end
@@ -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 + " = async function(...method_args) {\n\
137
- let context = \"" + context + "\";\n\
138
- let func = \"" + func +"\";\n\
139
- let request = [context, func, method_args];\n\
140
- let responder_path = '" + responder_path + "';\n\
141
- if (!global.__responder_socket) {\n\
142
- return new Promise(function(resolve, reject) {\n\
143
- setTimeout(function(){\n\
144
- if (os.platform().indexOf('win') == 0) {\n\
145
- let socket = net.connect(responder_path);\n\
146
- socket.on('connect', function(){\n\
147
- global.__responder_socket = true;\n\
148
- socket.destroy();\n\
149
- resolve(" + func + "(...method_args));\n\
150
- })\n\
151
- socket.on('error', function (err) {\n\
152
- resolve(" + func + "(...method_args));\n\
153
- });\n\
154
- } else {\n\
155
- if (fs.existsSync(responder_path)) { global.__responder_socket = true; }\n\
156
- resolve(" + func + "(...method_args));\n\
157
- }\n\
158
- }, 10)\n\
159
- });\n\
160
- }\n\
161
- return new Promise(function(resolve, reject) {\n\
162
- let request_json = JSON.stringify(request);\n\
163
- let buffer = Buffer.alloc(0);\n\
164
- let socket = net.connect(responder_path);\n\
165
- socket.setTimeout(2000);\n\
166
- socket.on('error', function (err) {\n\
167
- if (err.syscall === 'connect') {\n\
168
- // ignore, close will handle\n\
169
- } else if ((os.platform().indexOf('win') == 0) && err.message.includes('read EPIPE')) {\n\
170
- // ignore, close will handle\n\
171
- } else if ((os.platform().indexOf('win') == 0) && err.message.includes('write EPIPE')) {\n\
172
- // ignore, close will handle\n\
173
- } else { reject(err); }\n\
174
- });\n\
175
- socket.on('ready', function () {\n\
176
- socket.write(request_json + \"\x04\");\n\
177
- });\n\
178
- socket.on('data', function (data) {\n\
179
- buffer = Buffer.concat([buffer, data]);\n\
180
- });\n\
181
- socket.on('timeout', function() {\n\
182
- socket.destroy();\n\
183
- reject();\n\
184
- });\n\
185
- socket.on('close', function() {\n\
186
- if (buffer.length > 0) {\n\
187
- let method_result = JSON.parse(buffer.toString('utf8'));\n\
188
- if (method_result[0] == 'err') {\n\
189
- reject(method_result);\n\
190
- } else {\n\
191
- resolve(method_result[1]);\n\
192
- }\n\
193
- } else {\n\
194
- resolve(null);\n\
195
- }\n\
196
- });\n\
197
- });\n\
198
- }\n";
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
- } else {
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 (os.platform().indexOf('win') == 0) { responder_path = '\\\\\\\\.\\\\pipe\\\\' + socket_path + '_responder'; }
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 = "(" + input.source + ")"; }
323
- else if (input.source.match(/^\s*function\s*\(/)) { input.source = "(" + 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 = "(" + input.source + ")"; }
330
- else if (input.source.match(/^\s*function\s*\(/)) { input.source = "(" + 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 (os.platform().indexOf('win') == 0) { server.listen('\\\\.\\pipe\\' + socket_path); }
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
@@ -15,7 +15,7 @@ module Isomorfeus
15
15
  bytes_to_send = message.bytesize
16
16
  sent_bytes = 0
17
17
 
18
- if ExecJS.windows?
18
+ if ::ExecJS.windows?
19
19
  @socket.write(message)
20
20
  begin
21
21
  result << @socket.read
@@ -1,5 +1,5 @@
1
1
  module Isomorfeus
2
2
  module Speednode
3
- VERSION = '0.6.1'
3
+ VERSION = '0.6.3'
4
4
  end
5
5
  end
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.1
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-03-18 00:00:00.000000000 Z
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.15.0
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.15.0
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.0
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.0
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.6
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.