mini_racer_rs 1.0.0 → 1.0.2
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/CHANGELOG.md +14 -0
- data/COMPATIBILITY.md +7 -1
- data/Cargo.lock +4 -4
- data/Cargo.toml +1 -1
- data/README.md +3 -5
- data/crates/mini_racer_engine/src/context.rs +11 -6
- data/crates/mini_racer_engine/src/control.rs +24 -3
- data/crates/mini_racer_engine/src/lib.rs +2 -1
- data/crates/mini_racer_engine/src/process/code_cache.rs +26 -15
- data/crates/mini_racer_engine/src/process/fork.rs +12 -2
- data/crates/mini_racer_engine/src/process/sources.rs +539 -0
- data/crates/mini_racer_engine/src/process.rs +1 -0
- data/crates/mini_racer_engine/src/request.rs +552 -0
- data/crates/mini_racer_engine/src/runner.rs +84 -28
- data/crates/mini_racer_engine/src/serialize.rs +65 -4
- data/crates/mini_racer_engine/src/sys.rs +91 -1
- data/crates/mini_racer_wire/src/lib.rs +1 -1
- data/crates/mini_racer_wire/src/write.rs +33 -1
- data/ext/mini_racer_rs/src/context.rs +7 -5
- data/ext/mini_racer_rs/src/decode.rs +11 -4
- data/ext/mini_racer_rs/src/encode.rs +221 -69
- data/lib/mini_racer_rs/version.rb +1 -1
- metadata +3 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
use std::collections::HashMap;
|
|
2
|
+
use std::hash::{BuildHasherDefault, Hasher};
|
|
2
3
|
|
|
3
4
|
use magnus::encoding::{EncodingCapable, RbEncoding};
|
|
4
5
|
use magnus::r_hash::ForEach;
|
|
@@ -8,6 +9,7 @@ use magnus::{
|
|
|
8
9
|
Error, Fixnum, Float, Module, Object, RArray, RClass, RHash, RModule, RObject, RString, Ruby,
|
|
9
10
|
Time, Value,
|
|
10
11
|
};
|
|
12
|
+
use mini_racer_engine::CallRequest;
|
|
11
13
|
use mini_racer_wire::Writer;
|
|
12
14
|
|
|
13
15
|
use crate::gc_root::{OnceRoot, Pins, StaticRoot};
|
|
@@ -61,17 +63,44 @@ enum Item {
|
|
|
61
63
|
EndObject(u32),
|
|
62
64
|
}
|
|
63
65
|
|
|
66
|
+
// A pinned object's address is distinct for the whole encode; multiplying it
|
|
67
|
+
// spreads its aligned low bits over the bits the map buckets and tags by.
|
|
68
|
+
#[derive(Default)]
|
|
69
|
+
struct Address(u64);
|
|
70
|
+
|
|
71
|
+
impl Hasher for Address {
|
|
72
|
+
fn finish(&self) -> u64 {
|
|
73
|
+
self.0
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fn write(&mut self, bytes: &[u8]) {
|
|
77
|
+
for &byte in bytes {
|
|
78
|
+
self.0 = self.0.rotate_left(8) ^ u64::from(byte);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
fn write_u64(&mut self, address: u64) {
|
|
83
|
+
self.0 = (address >> 3).wrapping_mul(0x9E37_79B9_7F4A_7C15);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
64
87
|
// Iterative so a deeply nested argument cannot overflow the Ruby thread's
|
|
65
88
|
// stack; how deep V8 then reads is V8's own limit.
|
|
66
89
|
struct Encoder<'r, 'o> {
|
|
67
90
|
ruby: &'r Ruby,
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
|
|
91
|
+
// Made for the first value that holds others or can run Ruby code, before
|
|
92
|
+
// anything is pinned or keyed by address. The object, not a reference into
|
|
93
|
+
// its data: each use of the object keeps it where the GC finds it, while a
|
|
94
|
+
// bare data pointer lets an optimized build drop it and the GC free it
|
|
95
|
+
// mid-encode.
|
|
96
|
+
pins: Option<Obj<Pins>>,
|
|
72
97
|
writer: Writer<'o>,
|
|
73
98
|
work: Vec<Item>,
|
|
74
|
-
seen: HashMap<u64, u32
|
|
99
|
+
seen: HashMap<u64, u32, BuildHasherDefault<Address>>,
|
|
100
|
+
// The hashes written and their pairs in all, which tell the runner
|
|
101
|
+
// whether to build a call's arguments itself.
|
|
102
|
+
objects: usize,
|
|
103
|
+
properties: usize,
|
|
75
104
|
}
|
|
76
105
|
|
|
77
106
|
/// Writes `value` as `mini_racer`'s `serialize` does, with the object ids V8
|
|
@@ -83,33 +112,102 @@ pub fn encode(
|
|
|
83
112
|
unsupported: impl FnOnce(Vec<u8>) -> Error,
|
|
84
113
|
) -> Result<Vec<u8>, Error> {
|
|
85
114
|
let mut out = Vec::new();
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
writer: Writer::new(&mut out),
|
|
90
|
-
work: Vec::new(),
|
|
91
|
-
seen: HashMap::new(),
|
|
92
|
-
};
|
|
93
|
-
let root = encoder.pins.push(value);
|
|
94
|
-
encoder.work.push(Item::Value(root));
|
|
95
|
-
encoder.run().map_err(|error| match error {
|
|
96
|
-
EncodeError::Unsupported(message) => unsupported(message),
|
|
97
|
-
EncodeError::Raised(error) => error,
|
|
98
|
-
})?;
|
|
115
|
+
Encoder::new(ruby, &mut out)
|
|
116
|
+
.top(value)
|
|
117
|
+
.map_err(|error| error.raise(unsupported))?;
|
|
99
118
|
Ok(out)
|
|
100
119
|
}
|
|
101
120
|
|
|
121
|
+
/// Writes `[name, *args]`, the array `mini_racer` sends for a call, without
|
|
122
|
+
/// making it: no code can reach that array, so reading `args` as each turn
|
|
123
|
+
/// comes is reading it.
|
|
124
|
+
pub fn call(
|
|
125
|
+
ruby: &Ruby,
|
|
126
|
+
name: RString,
|
|
127
|
+
args: &[Value],
|
|
128
|
+
unsupported: impl FnOnce(Vec<u8>) -> Error,
|
|
129
|
+
) -> Result<CallRequest, Error> {
|
|
130
|
+
let mut bytes = Vec::new();
|
|
131
|
+
let mut encoder = Encoder::new(ruby, &mut bytes);
|
|
132
|
+
let count = length(args.len().saturating_add(1));
|
|
133
|
+
encoder.writer.begin_array(count);
|
|
134
|
+
encoder.string(name);
|
|
135
|
+
args.iter()
|
|
136
|
+
.try_for_each(|&arg| encoder.top(arg))
|
|
137
|
+
.map_err(|error| error.raise(unsupported))?;
|
|
138
|
+
encoder.writer.end_array(count);
|
|
139
|
+
let (objects, properties) = (encoder.objects, encoder.properties);
|
|
140
|
+
Ok(CallRequest {
|
|
141
|
+
bytes,
|
|
142
|
+
objects,
|
|
143
|
+
properties,
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
impl EncodeError {
|
|
148
|
+
fn raise(self, unsupported: impl FnOnce(Vec<u8>) -> Error) -> Error {
|
|
149
|
+
match self {
|
|
150
|
+
Self::Unsupported(message) => unsupported(message),
|
|
151
|
+
Self::Raised(error) => error,
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
102
156
|
fn length(len: usize) -> u32 {
|
|
103
157
|
u32::try_from(len).unwrap_or(u32::MAX)
|
|
104
158
|
}
|
|
105
159
|
|
|
160
|
+
// The values whose encoding runs no Ruby code and holds no other value.
|
|
161
|
+
const fn immediate(kind: RubyType) -> bool {
|
|
162
|
+
matches!(
|
|
163
|
+
kind,
|
|
164
|
+
RubyType::Fixnum
|
|
165
|
+
| RubyType::Float
|
|
166
|
+
| RubyType::Nil
|
|
167
|
+
| RubyType::True
|
|
168
|
+
| RubyType::False
|
|
169
|
+
| RubyType::String
|
|
170
|
+
| RubyType::Symbol
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
impl<'r, 'o> Encoder<'r, 'o> {
|
|
175
|
+
fn new(ruby: &'r Ruby, out: &'o mut Vec<u8>) -> Self {
|
|
176
|
+
Self {
|
|
177
|
+
ruby,
|
|
178
|
+
pins: None,
|
|
179
|
+
writer: Writer::new(out),
|
|
180
|
+
work: Vec::new(),
|
|
181
|
+
seen: HashMap::default(),
|
|
182
|
+
objects: 0,
|
|
183
|
+
properties: 0,
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
106
188
|
impl Encoder<'_, '_> {
|
|
189
|
+
fn pin(&mut self, value: Value) -> usize {
|
|
190
|
+
let ruby = self.ruby;
|
|
191
|
+
self.pins.get_or_insert_with(|| Pins::new(ruby)).push(value)
|
|
192
|
+
}
|
|
193
|
+
|
|
107
194
|
fn pinned(&self, index: usize) -> Value {
|
|
108
195
|
self.pins
|
|
109
|
-
.
|
|
196
|
+
.as_ref()
|
|
197
|
+
.and_then(|pins| pins.get(self.ruby, index))
|
|
110
198
|
.unwrap_or_else(|| self.ruby.qnil().as_value())
|
|
111
199
|
}
|
|
112
200
|
|
|
201
|
+
// Writes an immediate at once; anything else waits, pinned, for `run`.
|
|
202
|
+
fn top(&mut self, value: Value) -> Result<(), EncodeError> {
|
|
203
|
+
if self.immediate(value, rb_raw::ruby_type(self.ruby, value)) {
|
|
204
|
+
return Ok(());
|
|
205
|
+
}
|
|
206
|
+
let root = self.pin(value);
|
|
207
|
+
self.work.push(Item::Value(root));
|
|
208
|
+
self.run()
|
|
209
|
+
}
|
|
210
|
+
|
|
113
211
|
fn run(&mut self) -> Result<(), EncodeError> {
|
|
114
212
|
while let Some(item) = self.work.pop() {
|
|
115
213
|
match item {
|
|
@@ -128,92 +226,135 @@ impl Encoder<'_, '_> {
|
|
|
128
226
|
Ok(())
|
|
129
227
|
}
|
|
130
228
|
|
|
131
|
-
fn
|
|
229
|
+
fn immediate(&mut self, value: Value, kind: RubyType) -> bool {
|
|
132
230
|
let ruby = self.ruby;
|
|
133
|
-
match
|
|
231
|
+
match kind {
|
|
232
|
+
RubyType::Fixnum => self
|
|
233
|
+
.writer
|
|
234
|
+
.integer(Fixnum::from_value(value).map_or(0, Fixnum::to_i64)),
|
|
235
|
+
RubyType::Float => self
|
|
236
|
+
.writer
|
|
237
|
+
.number(Float::from_value(value).map_or(f64::NAN, Float::to_f64)),
|
|
238
|
+
RubyType::Nil => self.writer.null(),
|
|
239
|
+
RubyType::True => self.writer.bool(true),
|
|
240
|
+
RubyType::False => self.writer.bool(false),
|
|
241
|
+
RubyType::String => {
|
|
242
|
+
self.string(RString::from_value(value).unwrap_or_else(|| ruby.str_new("")));
|
|
243
|
+
}
|
|
244
|
+
RubyType::Symbol => self.string(rb_raw::sym2str(ruby, value)),
|
|
245
|
+
_ => return false,
|
|
246
|
+
}
|
|
247
|
+
true
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
fn value(&mut self, value: Value) -> Result<(), EncodeError> {
|
|
251
|
+
let kind = rb_raw::ruby_type(self.ruby, value);
|
|
252
|
+
if self.immediate(value, kind) {
|
|
253
|
+
return Ok(());
|
|
254
|
+
}
|
|
255
|
+
match kind {
|
|
134
256
|
RubyType::Array => {
|
|
135
257
|
self.array(value);
|
|
136
258
|
Ok(())
|
|
137
259
|
}
|
|
138
260
|
RubyType::Hash => self.hash(value),
|
|
139
261
|
RubyType::Data => self.data(value),
|
|
140
|
-
RubyType::Nil => {
|
|
141
|
-
self.writer.null();
|
|
142
|
-
Ok(())
|
|
143
|
-
}
|
|
144
|
-
RubyType::True => {
|
|
145
|
-
self.writer.bool(true);
|
|
146
|
-
Ok(())
|
|
147
|
-
}
|
|
148
|
-
RubyType::False => {
|
|
149
|
-
self.writer.bool(false);
|
|
150
|
-
Ok(())
|
|
151
|
-
}
|
|
152
262
|
RubyType::Bignum => self.bigint(value),
|
|
153
|
-
RubyType::Fixnum => {
|
|
154
|
-
self.writer
|
|
155
|
-
.integer(Fixnum::from_value(value).map_or(0, Fixnum::to_i64));
|
|
156
|
-
Ok(())
|
|
157
|
-
}
|
|
158
|
-
RubyType::Float => {
|
|
159
|
-
self.writer
|
|
160
|
-
.number(Float::from_value(value).map_or(f64::NAN, Float::to_f64));
|
|
161
|
-
Ok(())
|
|
162
|
-
}
|
|
163
|
-
RubyType::Symbol => {
|
|
164
|
-
self.string(rb_raw::sym2str(ruby, value));
|
|
165
|
-
Ok(())
|
|
166
|
-
}
|
|
167
|
-
RubyType::String => {
|
|
168
|
-
self.string(RString::from_value(value).unwrap_or_else(|| ruby.str_new("")));
|
|
169
|
-
Ok(())
|
|
170
|
-
}
|
|
171
263
|
RubyType::Object => self.object(value),
|
|
172
264
|
RubyType::Other(kind) => Err(EncodeError::unsupported(&format!(
|
|
173
265
|
"unsupported type {kind:x}"
|
|
174
266
|
))),
|
|
267
|
+
RubyType::Fixnum
|
|
268
|
+
| RubyType::Float
|
|
269
|
+
| RubyType::Nil
|
|
270
|
+
| RubyType::True
|
|
271
|
+
| RubyType::False
|
|
272
|
+
| RubyType::String
|
|
273
|
+
| RubyType::Symbol => Ok(()),
|
|
175
274
|
}
|
|
176
275
|
}
|
|
177
276
|
|
|
277
|
+
// The leading immediates are written at once: reading one runs no code
|
|
278
|
+
// that could change the array before its turn. The rest wait their turns.
|
|
178
279
|
fn array(&mut self, value: Value) {
|
|
179
280
|
if let Some(&id) = self.seen.get(&rb_raw::identity(value)) {
|
|
180
281
|
self.writer.object_ref(id);
|
|
181
282
|
return;
|
|
182
283
|
}
|
|
183
|
-
let
|
|
284
|
+
let array = RArray::from_value(value);
|
|
285
|
+
let len = array.map_or(0, RArray::len);
|
|
184
286
|
let count = length(len);
|
|
185
287
|
let id = self.writer.begin_array(count);
|
|
186
|
-
let
|
|
288
|
+
let pinned = self.pin(value);
|
|
187
289
|
self.seen.insert(rb_raw::identity(value), id);
|
|
290
|
+
let end = isize::try_from(len).unwrap_or(isize::MAX);
|
|
291
|
+
let mut next = 0;
|
|
292
|
+
while let Some(array) = array
|
|
293
|
+
&& next < end
|
|
294
|
+
{
|
|
295
|
+
let element = array
|
|
296
|
+
.entry::<Value>(next)
|
|
297
|
+
.unwrap_or_else(|_| self.ruby.qnil().as_value());
|
|
298
|
+
if !self.immediate(element, rb_raw::ruby_type(self.ruby, element)) {
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
next += 1;
|
|
302
|
+
}
|
|
303
|
+
if next >= end {
|
|
304
|
+
self.writer.end_array(count);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
188
307
|
self.work.push(Item::EndArray(count));
|
|
189
|
-
for index in (
|
|
190
|
-
self.work.push(Item::Element {
|
|
308
|
+
for index in (next..end).rev() {
|
|
309
|
+
self.work.push(Item::Element {
|
|
310
|
+
array: pinned,
|
|
311
|
+
index,
|
|
312
|
+
});
|
|
191
313
|
}
|
|
192
314
|
}
|
|
193
315
|
|
|
316
|
+
// mini_racer collects every pair before it writes one. Until a value that
|
|
317
|
+
// is not an immediate, each pair is written as it is collected, which no
|
|
318
|
+
// Ruby code can tell apart; from there on, the pairs wait their turns.
|
|
194
319
|
fn hash(&mut self, value: Value) -> Result<(), EncodeError> {
|
|
195
320
|
if let Some(&id) = self.seen.get(&rb_raw::identity(value)) {
|
|
196
321
|
self.writer.object_ref(id);
|
|
197
322
|
return Ok(());
|
|
198
323
|
}
|
|
199
|
-
self.
|
|
324
|
+
self.pin(value);
|
|
200
325
|
let hash = RHash::from_value(value).unwrap_or_else(|| self.ruby.hash_new());
|
|
326
|
+
self.objects = self.objects.saturating_add(1);
|
|
327
|
+
self.properties = self.properties.saturating_add(hash.len());
|
|
328
|
+
let id = self.writer.begin_object();
|
|
329
|
+
self.seen.insert(rb_raw::identity(value), id);
|
|
201
330
|
let mut pairs = Vec::new();
|
|
202
331
|
let mut keys_fit = true;
|
|
332
|
+
let mut written = 0u32;
|
|
203
333
|
hash.foreach(|key: Value, item: Value| {
|
|
334
|
+
let key_kind = rb_raw::ruby_type(self.ruby, key);
|
|
204
335
|
keys_fit &= matches!(
|
|
205
|
-
|
|
336
|
+
key_kind,
|
|
206
337
|
RubyType::Fixnum | RubyType::String | RubyType::Symbol
|
|
207
338
|
);
|
|
208
|
-
|
|
339
|
+
let item_kind = rb_raw::ruby_type(self.ruby, item);
|
|
340
|
+
if keys_fit && pairs.is_empty() && immediate(item_kind) {
|
|
341
|
+
self.immediate(key, key_kind);
|
|
342
|
+
self.immediate(item, item_kind);
|
|
343
|
+
written = written.saturating_add(1);
|
|
344
|
+
} else {
|
|
345
|
+
pairs.push((self.pin(key), self.pin(item)));
|
|
346
|
+
}
|
|
209
347
|
Ok(ForEach::Continue)
|
|
210
348
|
})?;
|
|
211
|
-
let id = self.writer.begin_object();
|
|
212
|
-
self.seen.insert(rb_raw::identity(value), id);
|
|
213
349
|
if !keys_fit {
|
|
214
350
|
return Err(EncodeError::unsupported("TODO serialize as Map"));
|
|
215
351
|
}
|
|
216
|
-
|
|
352
|
+
let count = written.saturating_add(length(pairs.len()));
|
|
353
|
+
if pairs.is_empty() {
|
|
354
|
+
self.writer.end_object(count);
|
|
355
|
+
return Ok(());
|
|
356
|
+
}
|
|
357
|
+
self.work.push(Item::EndObject(count));
|
|
217
358
|
for (key, item) in pairs.into_iter().rev() {
|
|
218
359
|
self.work.push(Item::Value(item));
|
|
219
360
|
self.work.push(Item::Value(key));
|
|
@@ -232,7 +373,7 @@ impl Encoder<'_, '_> {
|
|
|
232
373
|
}
|
|
233
374
|
|
|
234
375
|
fn remember(&mut self, value: Value, id: u32) {
|
|
235
|
-
self.
|
|
376
|
+
self.pin(value);
|
|
236
377
|
self.seen.insert(rb_raw::identity(value), id);
|
|
237
378
|
}
|
|
238
379
|
|
|
@@ -246,7 +387,7 @@ impl Encoder<'_, '_> {
|
|
|
246
387
|
rb_raw::identity(value.class().as_value()) == rb_raw::identity(date_time)
|
|
247
388
|
}) {
|
|
248
389
|
time = value.funcall("to_time", ())?;
|
|
249
|
-
self.
|
|
390
|
+
self.pin(time);
|
|
250
391
|
}
|
|
251
392
|
if rb_raw::identity(time.class().as_value())
|
|
252
393
|
== rb_raw::identity(ruby.class_time().as_value())
|
|
@@ -266,7 +407,7 @@ impl Encoder<'_, '_> {
|
|
|
266
407
|
}
|
|
267
408
|
if value.respond_to("to_time", false)? {
|
|
268
409
|
let time: Value = value.funcall("to_time", ())?;
|
|
269
|
-
self.
|
|
410
|
+
self.pin(time);
|
|
270
411
|
if time.is_kind_of(ruby.class_time()) {
|
|
271
412
|
let id = self.date(time)?;
|
|
272
413
|
self.remember(value, id);
|
|
@@ -322,12 +463,23 @@ impl Encoder<'_, '_> {
|
|
|
322
463
|
.map_err(|error| EncodeError::unsupported(&error.to_string()))
|
|
323
464
|
}
|
|
324
465
|
|
|
466
|
+
// mini_racer tells encodings apart by name. The ones it sends as UTF-8
|
|
467
|
+
// that strings most often have are told by index, without the lookup.
|
|
325
468
|
fn string(&mut self, text: RString) {
|
|
326
|
-
let
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
469
|
+
let ruby = self.ruby;
|
|
470
|
+
let index = text.enc_get();
|
|
471
|
+
let utf8 = index == ruby.utf8_encindex()
|
|
472
|
+
|| index == ruby.usascii_encindex()
|
|
473
|
+
|| index == ruby.ascii8bit_encindex();
|
|
474
|
+
rb_raw::with_string_bytes(ruby, text, |bytes| {
|
|
475
|
+
if utf8 {
|
|
476
|
+
return self.writer.utf8(bytes);
|
|
477
|
+
}
|
|
478
|
+
match RbEncoding::from(index).name() {
|
|
479
|
+
"ISO-8859-1" => self.writer.latin1(bytes),
|
|
480
|
+
"UTF-16LE" => self.writer.utf16le(bytes),
|
|
481
|
+
_ => self.writer.utf8(bytes),
|
|
482
|
+
}
|
|
331
483
|
});
|
|
332
484
|
}
|
|
333
485
|
}
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mini_racer_rs
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andy Aragon
|
|
@@ -54,9 +54,11 @@ files:
|
|
|
54
54
|
- crates/mini_racer_engine/src/process/code_cache.rs
|
|
55
55
|
- crates/mini_racer_engine/src/process/fork.rs
|
|
56
56
|
- crates/mini_racer_engine/src/process/platform.rs
|
|
57
|
+
- crates/mini_racer_engine/src/process/sources.rs
|
|
57
58
|
- crates/mini_racer_engine/src/process/tasks.rs
|
|
58
59
|
- crates/mini_racer_engine/src/process/watchdog.rs
|
|
59
60
|
- crates/mini_racer_engine/src/process/workers.rs
|
|
61
|
+
- crates/mini_racer_engine/src/request.rs
|
|
60
62
|
- crates/mini_racer_engine/src/runner.rs
|
|
61
63
|
- crates/mini_racer_engine/src/serialize.rs
|
|
62
64
|
- crates/mini_racer_engine/src/snapshot.rs
|