mini_racer-csim 0.21.1.0
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 +7 -0
- data/CHANGELOG +351 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/LICENSE.txt +21 -0
- data/README.md +687 -0
- data/ext/mini_racer_extension/extconf.rb +75 -0
- data/ext/mini_racer_extension/mini_racer_extension.c +2899 -0
- data/ext/mini_racer_extension/mini_racer_v8.cc +2692 -0
- data/ext/mini_racer_extension/mini_racer_v8.h +70 -0
- data/ext/mini_racer_extension/serde.c +782 -0
- data/ext/mini_racer_loader/extconf.rb +13 -0
- data/ext/mini_racer_loader/mini_racer_loader.c +123 -0
- data/lib/mini_racer/shared.rb +395 -0
- data/lib/mini_racer/truffleruby.rb +479 -0
- data/lib/mini_racer/version.rb +9 -0
- data/lib/mini_racer-csim.rb +4 -0
- data/lib/mini_racer.rb +117 -0
- metadata +168 -0
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'shared'
|
|
4
|
+
|
|
5
|
+
module MiniRacer
|
|
6
|
+
# GraalJS has no equivalent of V8's per-script bytecode cache reachable
|
|
7
|
+
# from Polyglot::InnerContext#eval, so the version tag is meaningless
|
|
8
|
+
# here. Define 0 as a sentinel callers can detect to skip cache logic.
|
|
9
|
+
V8_CACHED_DATA_VERSION_TAG = 0
|
|
10
|
+
|
|
11
|
+
class Context
|
|
12
|
+
|
|
13
|
+
class ExternalFunction
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def notify_v8
|
|
17
|
+
name = @name.encode(::Encoding::UTF_8)
|
|
18
|
+
wrapped = lambda do |*args|
|
|
19
|
+
converted = @parent.send(:convert_js_to_ruby, args)
|
|
20
|
+
begin
|
|
21
|
+
result = @callback.call(*converted)
|
|
22
|
+
rescue Polyglot::ForeignException => e
|
|
23
|
+
e = RuntimeError.new(e.message)
|
|
24
|
+
e.set_backtrace(e.backtrace)
|
|
25
|
+
@parent.instance_variable_set(:@current_exception, e)
|
|
26
|
+
raise e
|
|
27
|
+
rescue => e
|
|
28
|
+
@parent.instance_variable_set(:@current_exception, e)
|
|
29
|
+
raise e
|
|
30
|
+
end
|
|
31
|
+
@parent.send(:convert_ruby_to_js, result)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
if @parent_object.nil?
|
|
35
|
+
# set global name to proc
|
|
36
|
+
result = @parent.eval_in_context('this')
|
|
37
|
+
result[name] = wrapped
|
|
38
|
+
else
|
|
39
|
+
parent_object_eval = @parent_object_eval.encode(::Encoding::UTF_8)
|
|
40
|
+
begin
|
|
41
|
+
result = @parent.eval_in_context(parent_object_eval)
|
|
42
|
+
rescue Polyglot::ForeignException, StandardError => e
|
|
43
|
+
raise ParseError, "Was expecting #{@parent_object} to be an object", e.backtrace
|
|
44
|
+
end
|
|
45
|
+
result[name] = wrapped
|
|
46
|
+
# set evaluated object results name to proc
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def heap_stats
|
|
52
|
+
raise ContextDisposedError if @disposed
|
|
53
|
+
{
|
|
54
|
+
total_physical_size: 0,
|
|
55
|
+
total_heap_size_executable: 0,
|
|
56
|
+
total_heap_size: 0,
|
|
57
|
+
used_heap_size: 0,
|
|
58
|
+
heap_size_limit: 0,
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def stop
|
|
63
|
+
if @entered
|
|
64
|
+
@context.stop
|
|
65
|
+
@stopped = true
|
|
66
|
+
stop_attached
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def low_memory_notification
|
|
71
|
+
GC.start
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
@context_initialized = false
|
|
77
|
+
@use_strict = false
|
|
78
|
+
|
|
79
|
+
def init_unsafe(isolate, snapshot)
|
|
80
|
+
unless defined?(Polyglot::InnerContext)
|
|
81
|
+
raise "TruffleRuby #{RUBY_ENGINE_VERSION} does not have support for inner contexts, use a more recent version"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
if TruffleRuby.native?
|
|
86
|
+
raise "You need the TruffleRuby JVM Standalone for mini_racer because it is not possible to install the js component in the the Native standalone"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
unless Polyglot.languages.include? "js"
|
|
90
|
+
raise "The language 'js' is not available, you need to install the 'js' component.\nSee https://github.com/oracle/truffleruby/blob/master/doc/user/polyglot.md#installing-other-languages"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
@context = Polyglot::InnerContext.new(on_cancelled: -> {
|
|
94
|
+
raise ScriptTerminatedError, 'JavaScript was terminated (either by timeout or explicitly)'
|
|
95
|
+
})
|
|
96
|
+
Context.instance_variable_set(:@context_initialized, true)
|
|
97
|
+
@js_object = @context.eval('js', 'Object')
|
|
98
|
+
@isolate_mutex = Mutex.new
|
|
99
|
+
@stopped = false
|
|
100
|
+
@entered = false
|
|
101
|
+
@has_entered = false
|
|
102
|
+
@current_exception = nil
|
|
103
|
+
if isolate && snapshot
|
|
104
|
+
isolate.instance_variable_set(:@snapshot, snapshot)
|
|
105
|
+
end
|
|
106
|
+
if snapshot
|
|
107
|
+
@snapshot = snapshot
|
|
108
|
+
elsif isolate
|
|
109
|
+
@snapshot = isolate.instance_variable_get(:@snapshot)
|
|
110
|
+
else
|
|
111
|
+
@snapshot = nil
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
@is_object_or_array_func = eval_in_context "(x) => { return (x instanceof Object || x instanceof Array) && !(x instanceof Date) && !(x instanceof Function) }"
|
|
115
|
+
@is_map_func = eval_in_context "(x) => { return x instanceof Map }"
|
|
116
|
+
@is_map_iterator_func = eval_in_context "(x) => { return x[Symbol.toStringTag] === 'Map Iterator' }"
|
|
117
|
+
@is_time_func = eval_in_context "(x) => { return x instanceof Date }"
|
|
118
|
+
@is_symbol_func = eval_in_context "(x) => { return typeof x === 'symbol' }"
|
|
119
|
+
@is_uint8_array_func = eval_in_context "(x) => { return x instanceof Uint8Array }"
|
|
120
|
+
|
|
121
|
+
@js_date_to_time_func = eval_in_context "(x) => { return x.getTime(x) }"
|
|
122
|
+
@js_symbol_to_symbol_func = eval_in_context "(x) => { var r = x.description; return r === undefined ? 'undefined' : r }"
|
|
123
|
+
@js_new_date_func = eval_in_context "(x) => { return new Date(x) }"
|
|
124
|
+
@js_new_array_func = eval_in_context "(x) => { return new Array(x) }"
|
|
125
|
+
@js_new_uint8array_func = eval_in_context "(x) => { return new Uint8Array(x) }"
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def dispose_unsafe
|
|
129
|
+
@context.close
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def eval_unsafe(str, filename)
|
|
133
|
+
@entered = true
|
|
134
|
+
if !@has_entered && @snapshot
|
|
135
|
+
snapshot_src = encode(@snapshot.instance_variable_get(:@source))
|
|
136
|
+
begin
|
|
137
|
+
eval_in_context(snapshot_src, filename)
|
|
138
|
+
rescue Polyglot::ForeignException => e
|
|
139
|
+
raise RuntimeError, e.message, e.backtrace
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
@has_entered = true
|
|
143
|
+
raise RuntimeError, "TruffleRuby does not support eval after stop" if @stopped
|
|
144
|
+
raise TypeError, "wrong type argument #{str.class} (should be a string)" unless str.is_a?(String)
|
|
145
|
+
raise TypeError, "wrong type argument #{filename.class} (should be a string)" unless filename.nil? || filename.is_a?(String)
|
|
146
|
+
|
|
147
|
+
str = encode(str)
|
|
148
|
+
begin
|
|
149
|
+
translate do
|
|
150
|
+
eval_in_context(str, filename)
|
|
151
|
+
end
|
|
152
|
+
rescue Polyglot::ForeignException => e
|
|
153
|
+
raise RuntimeError, e.message, e.backtrace
|
|
154
|
+
rescue ::RuntimeError => e
|
|
155
|
+
if @current_exception
|
|
156
|
+
e = @current_exception
|
|
157
|
+
@current_exception = nil
|
|
158
|
+
raise e
|
|
159
|
+
else
|
|
160
|
+
raise e, e.message
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
ensure
|
|
164
|
+
@entered = false
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def call_unsafe(function_name, *arguments)
|
|
168
|
+
@entered = true
|
|
169
|
+
if !@has_entered && @snapshot
|
|
170
|
+
src = encode(@snapshot.instance_variable_get(:source))
|
|
171
|
+
begin
|
|
172
|
+
eval_in_context(src)
|
|
173
|
+
rescue Polyglot::ForeignException => e
|
|
174
|
+
raise RuntimeError, e.message, e.backtrace
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
@has_entered = true
|
|
178
|
+
raise RuntimeError, "TruffleRuby does not support call after stop" if @stopped
|
|
179
|
+
begin
|
|
180
|
+
translate do
|
|
181
|
+
function = eval_in_context(function_name)
|
|
182
|
+
function.call(*convert_ruby_to_js(arguments))
|
|
183
|
+
end
|
|
184
|
+
rescue Polyglot::ForeignException => e
|
|
185
|
+
raise RuntimeError, e.message, e.backtrace
|
|
186
|
+
end
|
|
187
|
+
ensure
|
|
188
|
+
@entered = false
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def create_isolate_value
|
|
192
|
+
# Returning a dummy object since TruffleRuby does not have a 1-1 concept with isolate.
|
|
193
|
+
# However, code and ASTs are shared between contexts.
|
|
194
|
+
Isolate.new
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def isolate_mutex
|
|
198
|
+
@isolate_mutex
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def translate
|
|
202
|
+
convert_js_to_ruby yield
|
|
203
|
+
rescue Object => e
|
|
204
|
+
message = e.message
|
|
205
|
+
if @current_exception
|
|
206
|
+
raise @current_exception
|
|
207
|
+
elsif e.message && e.message.start_with?('SyntaxError:')
|
|
208
|
+
error_class = MiniRacer::ParseError
|
|
209
|
+
elsif e.is_a?(MiniRacer::ScriptTerminatedError)
|
|
210
|
+
error_class = MiniRacer::ScriptTerminatedError
|
|
211
|
+
else
|
|
212
|
+
error_class = MiniRacer::RuntimeError
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
if error_class == MiniRacer::RuntimeError
|
|
216
|
+
bls = e.backtrace_locations&.select { |bl| bl&.source_location&.language == 'js' }
|
|
217
|
+
if bls && !bls.empty?
|
|
218
|
+
if '(eval)' != bls[0].path
|
|
219
|
+
message = "#{e.message}\n at #{bls[0]}\n" + bls[1..].map(&:to_s).join("\n")
|
|
220
|
+
else
|
|
221
|
+
message = "#{e.message}\n" + bls.map(&:to_s).join("\n")
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
raise error_class, message
|
|
225
|
+
else
|
|
226
|
+
raise error_class, message, e.backtrace
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def convert_js_to_ruby(value)
|
|
231
|
+
case value
|
|
232
|
+
when true, false, Integer, Float
|
|
233
|
+
value
|
|
234
|
+
else
|
|
235
|
+
if value.nil?
|
|
236
|
+
nil
|
|
237
|
+
elsif value.respond_to?(:call)
|
|
238
|
+
MiniRacer::JavaScriptFunction.new
|
|
239
|
+
elsif value.respond_to?(:to_str)
|
|
240
|
+
value.to_str.dup
|
|
241
|
+
elsif value.respond_to?(:to_ary)
|
|
242
|
+
if uint8_array?(value)
|
|
243
|
+
return value.to_a.pack('C*')
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
value.to_ary.map do |e|
|
|
247
|
+
if e.respond_to?(:call)
|
|
248
|
+
nil
|
|
249
|
+
else
|
|
250
|
+
convert_js_to_ruby(e)
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
elsif time?(value)
|
|
254
|
+
js_date_to_time(value)
|
|
255
|
+
elsif symbol?(value)
|
|
256
|
+
js_symbol_to_symbol(value)
|
|
257
|
+
elsif map?(value)
|
|
258
|
+
js_map_to_hash(value)
|
|
259
|
+
elsif map_iterator?(value)
|
|
260
|
+
value.map { |e| convert_js_to_ruby(e) }
|
|
261
|
+
elsif Polyglot::ForeignException === value
|
|
262
|
+
exc = MiniRacer::ScriptError.new(value.message)
|
|
263
|
+
exc.set_backtrace(value.backtrace)
|
|
264
|
+
exc
|
|
265
|
+
else
|
|
266
|
+
object = value
|
|
267
|
+
h = {}
|
|
268
|
+
object.instance_variables.each do |member|
|
|
269
|
+
v = object[member]
|
|
270
|
+
unless v.respond_to?(:call)
|
|
271
|
+
h[member.to_s] = convert_js_to_ruby(v)
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
h
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def object_or_array?(val)
|
|
280
|
+
@is_object_or_array_func.call(val)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def map?(value)
|
|
284
|
+
@is_map_func.call(value)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def map_iterator?(value)
|
|
288
|
+
@is_map_iterator_func.call(value)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def time?(value)
|
|
292
|
+
@is_time_func.call(value)
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def symbol?(value)
|
|
296
|
+
@is_symbol_func.call(value)
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def uint8_array?(value)
|
|
300
|
+
@is_uint8_array_func.call(value)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def js_date_to_time(value)
|
|
304
|
+
millis = @js_date_to_time_func.call(value)
|
|
305
|
+
Time.at(Rational(millis, 1000))
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def js_symbol_to_symbol(value)
|
|
309
|
+
@js_symbol_to_symbol_func.call(value).to_s.to_sym
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def js_map_to_hash(map)
|
|
313
|
+
map.to_a.to_h do |key, value|
|
|
314
|
+
[convert_js_to_ruby(key), convert_js_to_ruby(value)]
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def js_new_date(value)
|
|
319
|
+
@js_new_date_func.call(value)
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def js_new_array(size)
|
|
323
|
+
@js_new_array_func.call(size)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def convert_ruby_to_js(value)
|
|
327
|
+
case value
|
|
328
|
+
when nil, true, false, Integer, Float
|
|
329
|
+
value
|
|
330
|
+
when Array
|
|
331
|
+
ary = js_new_array(value.size)
|
|
332
|
+
value.each_with_index do |v, i|
|
|
333
|
+
ary[i] = convert_ruby_to_js(v)
|
|
334
|
+
end
|
|
335
|
+
ary
|
|
336
|
+
when Hash
|
|
337
|
+
h = @js_object.new
|
|
338
|
+
value.each_pair do |k, v|
|
|
339
|
+
h[convert_ruby_to_js(k.to_s)] = convert_ruby_to_js(v)
|
|
340
|
+
end
|
|
341
|
+
h
|
|
342
|
+
when String, Symbol
|
|
343
|
+
Truffle::Interop.as_truffle_string value
|
|
344
|
+
when Time
|
|
345
|
+
js_new_date(value.to_f * 1000)
|
|
346
|
+
when DateTime
|
|
347
|
+
js_new_date(value.to_time.to_f * 1000)
|
|
348
|
+
when MiniRacer::Binary
|
|
349
|
+
@js_new_uint8array_func.call(value.data.bytes)
|
|
350
|
+
else
|
|
351
|
+
"Undefined Conversion"
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def encode(string)
|
|
356
|
+
raise ArgumentError unless string
|
|
357
|
+
string.encode(::Encoding::UTF_8)
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
class_eval <<-'RUBY', "(mini_racer)", 1
|
|
361
|
+
def eval_in_context(code, file = nil); code = ('"use strict";' + code) if Context.instance_variable_get(:@use_strict); @context.eval('js', code, file || '(mini_racer)'); end
|
|
362
|
+
RUBY
|
|
363
|
+
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
class Isolate
|
|
367
|
+
def init_with_snapshot(snapshot)
|
|
368
|
+
# TruffleRuby does not have a 1-1 concept with isolate.
|
|
369
|
+
# However, isolate can hold a snapshot, and code and ASTs are shared between contexts.
|
|
370
|
+
@snapshot = snapshot
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
class Platform
|
|
375
|
+
def self.set_flag_as_str!(flag)
|
|
376
|
+
raise TypeError, "wrong type argument #{flag.class} (should be a string)" unless flag.is_a?(String)
|
|
377
|
+
raise MiniRacer::PlatformAlreadyInitialized, "The platform is already initialized." if Context.instance_variable_get(:@context_initialized)
|
|
378
|
+
Context.instance_variable_set(:@use_strict, true) if "--use_strict" == flag
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
class Snapshot
|
|
383
|
+
def load(str)
|
|
384
|
+
raise TypeError, "wrong type argument #{str.class} (should be a string)" unless str.is_a?(String)
|
|
385
|
+
# Intentionally noop since TruffleRuby mocks the snapshot API
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def warmup_unsafe!(src)
|
|
389
|
+
raise TypeError, "wrong type argument #{src.class} (should be a string)" unless src.is_a?(String)
|
|
390
|
+
# Intentionally noop since TruffleRuby mocks the snapshot API
|
|
391
|
+
# by replaying snapshot source before the first eval/call
|
|
392
|
+
self
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
# GraalJS has no per-script bytecode cache reachable from
|
|
397
|
+
# Polyglot::InnerContext#eval, so cached_data: is silently ignored and
|
|
398
|
+
# Script#run replays the source through Context#eval. compile_module +
|
|
399
|
+
# dynamic_import_resolver raise NotImplementedError because GraalJS has
|
|
400
|
+
# its own module-loading mechanism that doesn't map onto this
|
|
401
|
+
# handle-based API. The MiniRacer::Module class itself is stubbed so
|
|
402
|
+
# cross-engine code can reference it for is_a? / rescue without
|
|
403
|
+
# tripping NameError.
|
|
404
|
+
class Context
|
|
405
|
+
def compile(source, filename: nil, cached_data: nil, produce_cache: false)
|
|
406
|
+
raise(ContextDisposedError, 'attempted to call compile on a disposed context!') if @disposed
|
|
407
|
+
raise TypeError, "wrong type argument #{source.class} (should be a string)" unless source.is_a?(String)
|
|
408
|
+
raise TypeError, "wrong type argument #{filename.class} (should be a string)" unless filename.nil? || filename.is_a?(String)
|
|
409
|
+
if cached_data
|
|
410
|
+
raise TypeError, "wrong type argument #{cached_data.class} (should be a string)" unless cached_data.is_a?(String)
|
|
411
|
+
raise EncodingError, "cached_data must be ASCII-8BIT (binary), got #{cached_data.encoding}" if cached_data.encoding != Encoding::ASCII_8BIT
|
|
412
|
+
end
|
|
413
|
+
# produce_cache is accepted for API parity but has no effect — the shim
|
|
414
|
+
# has no per-script bytecode cache to produce.
|
|
415
|
+
Script.send(:new, self, source, filename)
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
def compile_module(*_args, **_opts)
|
|
419
|
+
raise NotImplementedError,
|
|
420
|
+
'Context#compile_module is not supported on TruffleRuby'
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def load_module_graph(*_args, **_opts)
|
|
424
|
+
raise NotImplementedError,
|
|
425
|
+
'Context#load_module_graph is not supported on TruffleRuby'
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
# nil is the documented "disable" value; accept it as a no-op so that
|
|
429
|
+
# `ctx.dynamic_import_resolver ||= ...` style code doesn't crash on
|
|
430
|
+
# TruffleRuby. Any callable raises, mirroring `compile_module`.
|
|
431
|
+
def dynamic_import_resolver=(blk)
|
|
432
|
+
return blk if blk.nil?
|
|
433
|
+
raise NotImplementedError,
|
|
434
|
+
'Context#dynamic_import_resolver= is not supported on TruffleRuby'
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
def dynamic_import_resolver = nil
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
class Module
|
|
441
|
+
UNSUPPORTED = 'MiniRacer::Module is not supported on TruffleRuby'
|
|
442
|
+
|
|
443
|
+
def initialize(*) = raise(NotImplementedError, UNSUPPORTED)
|
|
444
|
+
def instantiate(*, &_blk) = raise(NotImplementedError, UNSUPPORTED)
|
|
445
|
+
def evaluate = raise(NotImplementedError, UNSUPPORTED)
|
|
446
|
+
def namespace = raise(NotImplementedError, UNSUPPORTED)
|
|
447
|
+
def status = raise(NotImplementedError, UNSUPPORTED)
|
|
448
|
+
def dispose = raise(NotImplementedError, UNSUPPORTED)
|
|
449
|
+
def disposed? = raise(NotImplementedError, UNSUPPORTED)
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
class Script
|
|
453
|
+
private_class_method :new
|
|
454
|
+
|
|
455
|
+
def initialize(ctx, source, filename)
|
|
456
|
+
@ctx = ctx
|
|
457
|
+
@source = source
|
|
458
|
+
@filename = filename
|
|
459
|
+
@disposed = false
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
def run
|
|
463
|
+
raise MiniRacer::RuntimeError, 'disposed script' if @disposed
|
|
464
|
+
@ctx.eval(@source, filename: @filename) # raises ContextDisposedError if @ctx is disposed
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
def cached_data; nil; end
|
|
468
|
+
def cache_rejected?; false; end
|
|
469
|
+
|
|
470
|
+
def dispose
|
|
471
|
+
@disposed = true
|
|
472
|
+
nil
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
def disposed?
|
|
476
|
+
@disposed
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MiniRacer
|
|
4
|
+
# mini_racer-csim fork: upstream version + a fork revision segment.
|
|
5
|
+
# 0.21.1.0 = first fork release on upstream 0.21.1; bump the 4th segment for
|
|
6
|
+
# fork-only changes, reset it when rebasing onto a new upstream version.
|
|
7
|
+
VERSION = "0.21.1.0"
|
|
8
|
+
LIBV8_NODE_VERSION = "~> 24.12.0.1"
|
|
9
|
+
end
|
data/lib/mini_racer.rb
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
require "mini_racer/version"
|
|
2
|
+
require "pathname"
|
|
3
|
+
|
|
4
|
+
module MiniRacer
|
|
5
|
+
class Binary
|
|
6
|
+
attr_reader :data
|
|
7
|
+
|
|
8
|
+
def initialize(data)
|
|
9
|
+
raise TypeError, "wrong argument type #{data.class} (expected String)" unless data.is_a?(String)
|
|
10
|
+
@data = data
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
if RUBY_ENGINE == "truffleruby"
|
|
16
|
+
require "mini_racer/truffleruby"
|
|
17
|
+
else
|
|
18
|
+
if ENV["LD_PRELOAD"].to_s.include?("malloc")
|
|
19
|
+
require "mini_racer_extension"
|
|
20
|
+
else
|
|
21
|
+
require "mini_racer_loader"
|
|
22
|
+
ext_filename = "mini_racer_extension.#{RbConfig::CONFIG["DLEXT"]}"
|
|
23
|
+
# This is the mini_racer-csim fork; fall back to the upstream name and then
|
|
24
|
+
# to the default require_paths so the extension is found however we're loaded.
|
|
25
|
+
spec = Gem.loaded_specs["mini_racer-csim"] || Gem.loaded_specs["mini_racer"]
|
|
26
|
+
ext_path =
|
|
27
|
+
(spec ? spec.require_paths : %w[lib ext]).map do |p|
|
|
28
|
+
(p = Pathname.new(p)).absolute? ? p : Pathname.new(__dir__).parent + p
|
|
29
|
+
end
|
|
30
|
+
ext_found = ext_path.map { |p| p + ext_filename }.find { |p| p.file? }
|
|
31
|
+
|
|
32
|
+
unless ext_found
|
|
33
|
+
raise LoadError,
|
|
34
|
+
"Could not find #{ext_filename} in #{ext_path.map(&:to_s)}"
|
|
35
|
+
end
|
|
36
|
+
MiniRacer::Loader.load(ext_found.to_s)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
require "thread"
|
|
41
|
+
require "json"
|
|
42
|
+
require "io/wait"
|
|
43
|
+
|
|
44
|
+
module MiniRacer
|
|
45
|
+
class Error < ::StandardError; end
|
|
46
|
+
|
|
47
|
+
class ContextDisposedError < Error; end
|
|
48
|
+
class PlatformAlreadyInitialized < Error; end
|
|
49
|
+
|
|
50
|
+
class EvalError < Error; end
|
|
51
|
+
class ParseError < EvalError; end
|
|
52
|
+
class ScriptTerminatedError < EvalError; end
|
|
53
|
+
class V8OutOfMemoryError < EvalError; end
|
|
54
|
+
|
|
55
|
+
class RuntimeError < EvalError
|
|
56
|
+
def initialize(message)
|
|
57
|
+
message, *@frames = message.split("\n")
|
|
58
|
+
@frames.map! { "JavaScript #{_1.strip}" }
|
|
59
|
+
super(message)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def backtrace
|
|
63
|
+
frames = super
|
|
64
|
+
@frames + frames unless frames.nil?
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
class ScriptError < EvalError
|
|
69
|
+
def initialize(message)
|
|
70
|
+
message, *@frames = message.split("\n")
|
|
71
|
+
@frames.map! { "JavaScript #{_1.strip}" }
|
|
72
|
+
super(message)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def backtrace
|
|
76
|
+
frames = super || []
|
|
77
|
+
@frames + frames
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
class SnapshotError < Error
|
|
82
|
+
def initialize(message)
|
|
83
|
+
message, *@frames = message.split("\n")
|
|
84
|
+
@frames.map! { "JavaScript #{_1.strip}" }
|
|
85
|
+
super(message)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def backtrace
|
|
89
|
+
frames = super
|
|
90
|
+
@frames + frames unless frames.nil?
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
class Context
|
|
95
|
+
def load(filename)
|
|
96
|
+
eval(File.read(filename))
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def write_heap_snapshot(file_or_io)
|
|
100
|
+
f = nil
|
|
101
|
+
implicit = false
|
|
102
|
+
|
|
103
|
+
if String === file_or_io
|
|
104
|
+
f = File.open(file_or_io, "w")
|
|
105
|
+
implicit = true
|
|
106
|
+
else
|
|
107
|
+
f = file_or_io
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
raise ArgumentError, "file_or_io" unless File === f
|
|
111
|
+
|
|
112
|
+
f.write(heap_snapshot())
|
|
113
|
+
ensure
|
|
114
|
+
f.close if implicit
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|