mini_racer 0.3.1 → 0.6.4
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/.dockerignore +12 -0
- data/.github/workflows/ci.yml +124 -0
- data/.gitignore +2 -0
- data/CHANGELOG +61 -1
- data/Dockerfile +21 -0
- data/README.md +36 -19
- data/Rakefile +16 -3
- data/ext/mini_racer_extension/extconf.rb +41 -13
- data/ext/mini_racer_extension/mini_racer_extension.cc +416 -219
- data/ext/mini_racer_loader/extconf.rb +13 -0
- data/ext/mini_racer_loader/mini_racer_loader.c +123 -0
- data/lib/mini_racer/truffleruby.rb +355 -0
- data/lib/mini_racer/version.rb +2 -1
- data/lib/mini_racer.rb +37 -16
- data/mini_racer.gemspec +3 -5
- metadata +18 -12
- data/.travis.yml +0 -17
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
#include <ruby.h>
|
|
3
3
|
#include <ruby/thread.h>
|
|
4
4
|
#include <ruby/io.h>
|
|
5
|
+
#include <ruby/version.h>
|
|
5
6
|
#include <v8.h>
|
|
6
7
|
#include <v8-profiler.h>
|
|
7
8
|
#include <libplatform/libplatform.h>
|
|
@@ -11,6 +12,15 @@
|
|
|
11
12
|
#include <mutex>
|
|
12
13
|
#include <atomic>
|
|
13
14
|
#include <math.h>
|
|
15
|
+
#include <errno.h>
|
|
16
|
+
|
|
17
|
+
/* workaround C Ruby <= 2.x problems w/ clang in C++ mode */
|
|
18
|
+
#if defined(ENGINE_IS_CRUBY) && \
|
|
19
|
+
RUBY_API_VERSION_MAJOR == 2 && RUBY_API_VERSION_MINOR <= 6
|
|
20
|
+
# define MR_METHOD_FUNC(fn) RUBY_METHOD_FUNC(fn)
|
|
21
|
+
#else
|
|
22
|
+
# define MR_METHOD_FUNC(fn) fn
|
|
23
|
+
#endif
|
|
14
24
|
|
|
15
25
|
using namespace v8;
|
|
16
26
|
|
|
@@ -115,6 +125,7 @@ typedef struct {
|
|
|
115
125
|
useconds_t timeout;
|
|
116
126
|
EvalResult* result;
|
|
117
127
|
size_t max_memory;
|
|
128
|
+
size_t marshal_stackdepth;
|
|
118
129
|
} EvalParams;
|
|
119
130
|
|
|
120
131
|
typedef struct {
|
|
@@ -126,13 +137,152 @@ typedef struct {
|
|
|
126
137
|
Local<Value> *argv;
|
|
127
138
|
EvalResult result;
|
|
128
139
|
size_t max_memory;
|
|
140
|
+
size_t marshal_stackdepth;
|
|
129
141
|
} FunctionCall;
|
|
130
142
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
143
|
+
class IsolateData {
|
|
144
|
+
public:
|
|
145
|
+
enum Flag {
|
|
146
|
+
// first flags are bitfield
|
|
147
|
+
// max count: sizeof(uintptr_t) * 8
|
|
148
|
+
IN_GVL, // whether we are inside of ruby gvl or not
|
|
149
|
+
DO_TERMINATE, // terminate as soon as possible
|
|
150
|
+
MEM_SOFTLIMIT_REACHED, // we've hit the memory soft limit
|
|
151
|
+
MEM_SOFTLIMIT_MAX, // maximum memory value
|
|
152
|
+
MARSHAL_STACKDEPTH_REACHED, // we've hit our max stack depth
|
|
153
|
+
MARSHAL_STACKDEPTH_VALUE, // current stackdepth
|
|
154
|
+
MARSHAL_STACKDEPTH_MAX, // maximum stack depth during marshal
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
static void Init(Isolate *isolate) {
|
|
158
|
+
// zero out all fields in the bitfield
|
|
159
|
+
isolate->SetData(0, 0);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
static uintptr_t Get(Isolate *isolate, Flag flag) {
|
|
163
|
+
Bitfield u = { reinterpret_cast<uint64_t>(isolate->GetData(0)) };
|
|
164
|
+
switch (flag) {
|
|
165
|
+
case IN_GVL: return u.IN_GVL;
|
|
166
|
+
case DO_TERMINATE: return u.DO_TERMINATE;
|
|
167
|
+
case MEM_SOFTLIMIT_REACHED: return u.MEM_SOFTLIMIT_REACHED;
|
|
168
|
+
case MEM_SOFTLIMIT_MAX: return static_cast<uintptr_t>(u.MEM_SOFTLIMIT_MAX) << 10;
|
|
169
|
+
case MARSHAL_STACKDEPTH_REACHED: return u.MARSHAL_STACKDEPTH_REACHED;
|
|
170
|
+
case MARSHAL_STACKDEPTH_VALUE: return u.MARSHAL_STACKDEPTH_VALUE;
|
|
171
|
+
case MARSHAL_STACKDEPTH_MAX: return u.MARSHAL_STACKDEPTH_MAX;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// avoid compiler warning
|
|
175
|
+
return u.IN_GVL;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
static void Set(Isolate *isolate, Flag flag, uintptr_t value) {
|
|
179
|
+
Bitfield u = { reinterpret_cast<uint64_t>(isolate->GetData(0)) };
|
|
180
|
+
switch (flag) {
|
|
181
|
+
case IN_GVL: u.IN_GVL = value; break;
|
|
182
|
+
case DO_TERMINATE: u.DO_TERMINATE = value; break;
|
|
183
|
+
case MEM_SOFTLIMIT_REACHED: u.MEM_SOFTLIMIT_REACHED = value; break;
|
|
184
|
+
// drop least significant 10 bits 'store memory amount in kb'
|
|
185
|
+
case MEM_SOFTLIMIT_MAX: u.MEM_SOFTLIMIT_MAX = value >> 10; break;
|
|
186
|
+
case MARSHAL_STACKDEPTH_REACHED: u.MARSHAL_STACKDEPTH_REACHED = value; break;
|
|
187
|
+
case MARSHAL_STACKDEPTH_VALUE: u.MARSHAL_STACKDEPTH_VALUE = value; break;
|
|
188
|
+
case MARSHAL_STACKDEPTH_MAX: u.MARSHAL_STACKDEPTH_MAX = value; break;
|
|
189
|
+
}
|
|
190
|
+
isolate->SetData(0, reinterpret_cast<void*>(u.dataPtr));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
private:
|
|
194
|
+
struct Bitfield {
|
|
195
|
+
// WARNING: this would explode on platforms below 64 bit ptrs
|
|
196
|
+
// compiler will fail here, making it clear for them.
|
|
197
|
+
// Additionally, using the other part of the union to reinterpret the
|
|
198
|
+
// memory is undefined behavior according to spec, but is / has been stable
|
|
199
|
+
// across major compilers for decades.
|
|
200
|
+
static_assert(sizeof(uintptr_t) >= sizeof(uint64_t), "mini_racer not supported on this platform. ptr size must be at least 64 bit.");
|
|
201
|
+
union {
|
|
202
|
+
uint64_t dataPtr: 64;
|
|
203
|
+
// order in this struct matters. For cpu performance keep larger subobjects
|
|
204
|
+
// aligned on their boundaries (8 16 32), try not to straddle
|
|
205
|
+
struct {
|
|
206
|
+
size_t MEM_SOFTLIMIT_MAX:22;
|
|
207
|
+
bool IN_GVL:1;
|
|
208
|
+
bool DO_TERMINATE:1;
|
|
209
|
+
bool MEM_SOFTLIMIT_REACHED:1;
|
|
210
|
+
bool MARSHAL_STACKDEPTH_REACHED:1;
|
|
211
|
+
uint8_t :0; // align to next 8bit bound
|
|
212
|
+
size_t MARSHAL_STACKDEPTH_VALUE:10;
|
|
213
|
+
uint8_t :0; // align to next 8bit bound
|
|
214
|
+
size_t MARSHAL_STACKDEPTH_MAX:10;
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
};
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
struct StackCounter {
|
|
221
|
+
static void Reset(Isolate* isolate) {
|
|
222
|
+
if (IsolateData::Get(isolate, IsolateData::MARSHAL_STACKDEPTH_MAX) > 0) {
|
|
223
|
+
IsolateData::Set(isolate, IsolateData::MARSHAL_STACKDEPTH_VALUE, 0);
|
|
224
|
+
IsolateData::Set(isolate, IsolateData::MARSHAL_STACKDEPTH_REACHED, false);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
static void SetMax(Isolate* isolate, size_t marshalMaxStackDepth) {
|
|
229
|
+
if (marshalMaxStackDepth > 0) {
|
|
230
|
+
IsolateData::Set(isolate, IsolateData::MARSHAL_STACKDEPTH_MAX, marshalMaxStackDepth);
|
|
231
|
+
IsolateData::Set(isolate, IsolateData::MARSHAL_STACKDEPTH_VALUE, 0);
|
|
232
|
+
IsolateData::Set(isolate, IsolateData::MARSHAL_STACKDEPTH_REACHED, false);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
StackCounter(Isolate* isolate) {
|
|
237
|
+
this->isActive = IsolateData::Get(isolate, IsolateData::MARSHAL_STACKDEPTH_MAX) > 0;
|
|
238
|
+
|
|
239
|
+
if (this->isActive) {
|
|
240
|
+
this->isolate = isolate;
|
|
241
|
+
this->IncDepth(1);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
bool IsTooDeep() {
|
|
246
|
+
if (!this->IsActive()) {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
size_t depth = IsolateData::Get(this->isolate, IsolateData::MARSHAL_STACKDEPTH_VALUE);
|
|
251
|
+
size_t maxDepth = IsolateData::Get(this->isolate, IsolateData::MARSHAL_STACKDEPTH_MAX);
|
|
252
|
+
if (depth > maxDepth) {
|
|
253
|
+
IsolateData::Set(this->isolate, IsolateData::MARSHAL_STACKDEPTH_REACHED, true);
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
bool IsActive() {
|
|
261
|
+
return this->isActive && !IsolateData::Get(this->isolate, IsolateData::DO_TERMINATE);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
~StackCounter() {
|
|
265
|
+
if (this->IsActive()) {
|
|
266
|
+
this->IncDepth(-1);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private:
|
|
271
|
+
Isolate* isolate;
|
|
272
|
+
bool isActive;
|
|
273
|
+
|
|
274
|
+
void IncDepth(int direction) {
|
|
275
|
+
int inc = direction > 0 ? 1 : -1;
|
|
276
|
+
|
|
277
|
+
size_t depth = IsolateData::Get(this->isolate, IsolateData::MARSHAL_STACKDEPTH_VALUE);
|
|
278
|
+
|
|
279
|
+
// don't decrement past 0
|
|
280
|
+
if (inc > 0 || depth > 0) {
|
|
281
|
+
depth += inc;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
IsolateData::Set(this->isolate, IsolateData::MARSHAL_STACKDEPTH_VALUE, depth);
|
|
285
|
+
}
|
|
136
286
|
};
|
|
137
287
|
|
|
138
288
|
static VALUE rb_cContext;
|
|
@@ -155,21 +305,44 @@ static std::unique_ptr<Platform> current_platform = NULL;
|
|
|
155
305
|
static std::mutex platform_lock;
|
|
156
306
|
|
|
157
307
|
static pthread_attr_t *thread_attr_p;
|
|
158
|
-
static
|
|
159
|
-
static bool
|
|
308
|
+
static std::atomic_int ruby_exiting(0);
|
|
309
|
+
static bool single_threaded = false;
|
|
310
|
+
|
|
311
|
+
static void mark_context(void *);
|
|
312
|
+
static void deallocate(void *);
|
|
313
|
+
static size_t context_memsize(const void *);
|
|
314
|
+
static const rb_data_type_t context_type = {
|
|
315
|
+
"mini_racer/context_info",
|
|
316
|
+
{ mark_context, deallocate, context_memsize }
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
static void deallocate_snapshot(void *);
|
|
320
|
+
static size_t snapshot_memsize(const void *);
|
|
321
|
+
static const rb_data_type_t snapshot_type = {
|
|
322
|
+
"mini_racer/snapshot_info",
|
|
323
|
+
{ NULL, deallocate_snapshot, snapshot_memsize }
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
static void mark_isolate(void *);
|
|
327
|
+
static void deallocate_isolate(void *);
|
|
328
|
+
static size_t isolate_memsize(const void *);
|
|
329
|
+
static const rb_data_type_t isolate_type = {
|
|
330
|
+
"mini_racer/isolate_info",
|
|
331
|
+
{ mark_isolate, deallocate_isolate, isolate_memsize }
|
|
332
|
+
};
|
|
160
333
|
|
|
161
334
|
static VALUE rb_platform_set_flag_as_str(VALUE _klass, VALUE flag_as_str) {
|
|
162
335
|
bool platform_already_initialized = false;
|
|
163
336
|
|
|
164
|
-
|
|
165
|
-
rb_raise(rb_eArgError, "wrong type argument %" PRIsVALUE" (should be a string)",
|
|
166
|
-
rb_obj_class(flag_as_str));
|
|
167
|
-
}
|
|
337
|
+
Check_Type(flag_as_str, T_STRING);
|
|
168
338
|
|
|
169
339
|
platform_lock.lock();
|
|
170
340
|
|
|
171
341
|
if (current_platform == NULL) {
|
|
172
|
-
|
|
342
|
+
if (!strcmp(RSTRING_PTR(flag_as_str), "--single_threaded")) {
|
|
343
|
+
single_threaded = true;
|
|
344
|
+
}
|
|
345
|
+
V8::SetFlagsFromString(RSTRING_PTR(flag_as_str), RSTRING_LENINT(flag_as_str));
|
|
173
346
|
} else {
|
|
174
347
|
platform_already_initialized = true;
|
|
175
348
|
}
|
|
@@ -192,7 +365,11 @@ static void init_v8() {
|
|
|
192
365
|
|
|
193
366
|
if (current_platform == NULL) {
|
|
194
367
|
V8::InitializeICU();
|
|
195
|
-
|
|
368
|
+
if (single_threaded) {
|
|
369
|
+
current_platform = platform::NewSingleThreadedDefaultPlatform();
|
|
370
|
+
} else {
|
|
371
|
+
current_platform = platform::NewDefaultPlatform();
|
|
372
|
+
}
|
|
196
373
|
V8::InitializePlatform(current_platform.get());
|
|
197
374
|
V8::Initialize();
|
|
198
375
|
}
|
|
@@ -201,16 +378,18 @@ static void init_v8() {
|
|
|
201
378
|
}
|
|
202
379
|
|
|
203
380
|
static void gc_callback(Isolate *isolate, GCType type, GCCallbackFlags flags) {
|
|
204
|
-
if((
|
|
381
|
+
if (IsolateData::Get(isolate, IsolateData::MEM_SOFTLIMIT_REACHED)) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
205
384
|
|
|
206
|
-
size_t softlimit =
|
|
385
|
+
size_t softlimit = IsolateData::Get(isolate, IsolateData::MEM_SOFTLIMIT_MAX);
|
|
207
386
|
|
|
208
387
|
HeapStatistics stats;
|
|
209
388
|
isolate->GetHeapStatistics(&stats);
|
|
210
389
|
size_t used = stats.used_heap_size();
|
|
211
390
|
|
|
212
391
|
if(used > softlimit) {
|
|
213
|
-
isolate
|
|
392
|
+
IsolateData::Set(isolate, IsolateData::MEM_SOFTLIMIT_REACHED, true);
|
|
214
393
|
isolate->TerminateExecution();
|
|
215
394
|
}
|
|
216
395
|
}
|
|
@@ -235,28 +414,32 @@ static void prepare_result(MaybeLocal<Value> v8res,
|
|
|
235
414
|
Local<Value> local_value = v8res.ToLocalChecked();
|
|
236
415
|
if ((local_value->IsObject() || local_value->IsArray()) &&
|
|
237
416
|
!local_value->IsDate() && !local_value->IsFunction()) {
|
|
238
|
-
|
|
239
|
-
context, String::NewFromUtf8Literal(isolate, "JSON"))
|
|
240
|
-
.ToLocalChecked().As<Object>();
|
|
417
|
+
MaybeLocal<v8::Value> ml = context->Global()->Get(
|
|
418
|
+
context, String::NewFromUtf8Literal(isolate, "JSON"));
|
|
241
419
|
|
|
242
|
-
|
|
243
|
-
context, v8::String::NewFromUtf8Literal(isolate, "stringify"))
|
|
244
|
-
.ToLocalChecked().As<Function>();
|
|
245
|
-
|
|
246
|
-
Local<Object> object = local_value->ToObject(context).ToLocalChecked();
|
|
247
|
-
const unsigned argc = 1;
|
|
248
|
-
Local<Value> argv[argc] = { object };
|
|
249
|
-
MaybeLocal<Value> json = stringify->Call(context, JSON, argc, argv);
|
|
250
|
-
|
|
251
|
-
if (json.IsEmpty()) {
|
|
420
|
+
if (ml.IsEmpty()) { // exception
|
|
252
421
|
evalRes.executed = false;
|
|
253
422
|
} else {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
423
|
+
Local<Object> JSON = ml.ToLocalChecked().As<Object>();
|
|
424
|
+
|
|
425
|
+
Local<Function> stringify = JSON->Get(
|
|
426
|
+
context, v8::String::NewFromUtf8Literal(isolate, "stringify"))
|
|
427
|
+
.ToLocalChecked().As<Function>();
|
|
428
|
+
|
|
429
|
+
Local<Object> object = local_value->ToObject(context).ToLocalChecked();
|
|
430
|
+
const unsigned argc = 1;
|
|
431
|
+
Local<Value> argv[argc] = { object };
|
|
432
|
+
MaybeLocal<Value> json = stringify->Call(context, JSON, argc, argv);
|
|
433
|
+
|
|
434
|
+
if (json.IsEmpty()) {
|
|
435
|
+
evalRes.executed = false;
|
|
436
|
+
} else {
|
|
437
|
+
evalRes.json = true;
|
|
438
|
+
Persistent<Value>* persistent = new Persistent<Value>();
|
|
439
|
+
persistent->Reset(isolate, json.ToLocalChecked());
|
|
440
|
+
evalRes.value = persistent;
|
|
441
|
+
}
|
|
258
442
|
}
|
|
259
|
-
|
|
260
443
|
} else {
|
|
261
444
|
Persistent<Value>* persistent = new Persistent<Value>();
|
|
262
445
|
persistent->Reset(isolate, local_value);
|
|
@@ -307,7 +490,7 @@ static void prepare_result(MaybeLocal<Value> v8res,
|
|
|
307
490
|
}
|
|
308
491
|
}
|
|
309
492
|
|
|
310
|
-
void*
|
|
493
|
+
static void*
|
|
311
494
|
nogvl_context_eval(void* arg) {
|
|
312
495
|
|
|
313
496
|
EvalParams* eval_params = (EvalParams*)arg;
|
|
@@ -322,14 +505,15 @@ nogvl_context_eval(void* arg) {
|
|
|
322
505
|
Context::Scope context_scope(context);
|
|
323
506
|
v8::ScriptOrigin *origin = NULL;
|
|
324
507
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
508
|
+
IsolateData::Init(isolate);
|
|
509
|
+
|
|
510
|
+
if (eval_params->max_memory > 0) {
|
|
511
|
+
IsolateData::Set(isolate, IsolateData::MEM_SOFTLIMIT_MAX, eval_params->max_memory);
|
|
512
|
+
if (!isolate_info->added_gc_cb) {
|
|
513
|
+
isolate->AddGCEpilogueCallback(gc_callback);
|
|
514
|
+
isolate_info->added_gc_cb = true;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
333
517
|
|
|
334
518
|
MaybeLocal<Script> parsed_script;
|
|
335
519
|
|
|
@@ -355,12 +539,8 @@ nogvl_context_eval(void* arg) {
|
|
|
355
539
|
result->message->Reset(isolate, trycatch.Exception());
|
|
356
540
|
} else {
|
|
357
541
|
// parsing successful
|
|
358
|
-
if (eval_params->
|
|
359
|
-
isolate
|
|
360
|
-
if (!isolate_info->added_gc_cb) {
|
|
361
|
-
isolate->AddGCEpilogueCallback(gc_callback);
|
|
362
|
-
isolate_info->added_gc_cb = true;
|
|
363
|
-
}
|
|
542
|
+
if (eval_params->marshal_stackdepth > 0) {
|
|
543
|
+
StackCounter::SetMax(isolate, eval_params->marshal_stackdepth);
|
|
364
544
|
}
|
|
365
545
|
|
|
366
546
|
maybe_value = parsed_script.ToLocalChecked()->Run(context);
|
|
@@ -368,7 +548,7 @@ nogvl_context_eval(void* arg) {
|
|
|
368
548
|
|
|
369
549
|
prepare_result(maybe_value, trycatch, isolate, context, *result);
|
|
370
550
|
|
|
371
|
-
isolate
|
|
551
|
+
IsolateData::Set(isolate, IsolateData::IN_GVL, true);
|
|
372
552
|
|
|
373
553
|
return NULL;
|
|
374
554
|
}
|
|
@@ -386,6 +566,18 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context,
|
|
|
386
566
|
Isolate::Scope isolate_scope(isolate);
|
|
387
567
|
HandleScope scope(isolate);
|
|
388
568
|
|
|
569
|
+
StackCounter stackCounter(isolate);
|
|
570
|
+
|
|
571
|
+
if (IsolateData::Get(isolate, IsolateData::MARSHAL_STACKDEPTH_REACHED)) {
|
|
572
|
+
return Qnil;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
if (stackCounter.IsTooDeep()) {
|
|
576
|
+
IsolateData::Set(isolate, IsolateData::DO_TERMINATE, true);
|
|
577
|
+
isolate->TerminateExecution();
|
|
578
|
+
return Qnil;
|
|
579
|
+
}
|
|
580
|
+
|
|
389
581
|
if (value->IsNull() || value->IsUndefined()){
|
|
390
582
|
return Qnil;
|
|
391
583
|
}
|
|
@@ -468,13 +660,9 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context,
|
|
|
468
660
|
v8::String::Utf8Value symbol_name(isolate,
|
|
469
661
|
Local<Symbol>::Cast(value)->Name());
|
|
470
662
|
|
|
471
|
-
VALUE str_symbol =
|
|
472
|
-
*symbol_name,
|
|
473
|
-
symbol_name.length(),
|
|
474
|
-
rb_enc_find("utf-8")
|
|
475
|
-
);
|
|
663
|
+
VALUE str_symbol = rb_utf8_str_new(*symbol_name, symbol_name.length());
|
|
476
664
|
|
|
477
|
-
return
|
|
665
|
+
return rb_str_intern(str_symbol);
|
|
478
666
|
}
|
|
479
667
|
|
|
480
668
|
MaybeLocal<String> rstr_maybe = value->ToString(context);
|
|
@@ -483,7 +671,7 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context,
|
|
|
483
671
|
return Qnil;
|
|
484
672
|
} else {
|
|
485
673
|
Local<String> rstr = rstr_maybe.ToLocalChecked();
|
|
486
|
-
return
|
|
674
|
+
return rb_utf8_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(isolate));
|
|
487
675
|
}
|
|
488
676
|
}
|
|
489
677
|
|
|
@@ -528,7 +716,7 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context,
|
|
|
528
716
|
case T_FLOAT:
|
|
529
717
|
return scope.Escape(Number::New(isolate, NUM2DBL(value)));
|
|
530
718
|
case T_STRING:
|
|
531
|
-
return scope.Escape(String::NewFromUtf8(isolate, RSTRING_PTR(value), NewStringType::kNormal, (
|
|
719
|
+
return scope.Escape(String::NewFromUtf8(isolate, RSTRING_PTR(value), NewStringType::kNormal, RSTRING_LENINT(value)).ToLocalChecked());
|
|
532
720
|
case T_NIL:
|
|
533
721
|
return scope.Escape(Null(isolate));
|
|
534
722
|
case T_TRUE:
|
|
@@ -539,7 +727,8 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context,
|
|
|
539
727
|
length = RARRAY_LEN(value);
|
|
540
728
|
array = Array::New(isolate, (int)length);
|
|
541
729
|
for(i=0; i<length; i++) {
|
|
542
|
-
array->Set(context, i, convert_ruby_to_v8(isolate, context, rb_ary_entry(value, i)));
|
|
730
|
+
Maybe<bool> success = array->Set(context, i, convert_ruby_to_v8(isolate, context, rb_ary_entry(value, i)));
|
|
731
|
+
(void)(success);
|
|
543
732
|
}
|
|
544
733
|
return scope.Escape(array);
|
|
545
734
|
case T_HASH:
|
|
@@ -548,13 +737,14 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context,
|
|
|
548
737
|
length = RARRAY_LEN(hash_as_array);
|
|
549
738
|
for(i=0; i<length; i++) {
|
|
550
739
|
pair = rb_ary_entry(hash_as_array, i);
|
|
551
|
-
object->Set(context, convert_ruby_to_v8(isolate, context, rb_ary_entry(pair, 0)),
|
|
740
|
+
Maybe<bool> success = object->Set(context, convert_ruby_to_v8(isolate, context, rb_ary_entry(pair, 0)),
|
|
552
741
|
convert_ruby_to_v8(isolate, context, rb_ary_entry(pair, 1)));
|
|
742
|
+
(void)(success);
|
|
553
743
|
}
|
|
554
744
|
return scope.Escape(object);
|
|
555
745
|
case T_SYMBOL:
|
|
556
746
|
value = rb_funcall(value, rb_intern("to_s"), 0);
|
|
557
|
-
return scope.Escape(String::NewFromUtf8(isolate, RSTRING_PTR(value), NewStringType::kNormal, (
|
|
747
|
+
return scope.Escape(String::NewFromUtf8(isolate, RSTRING_PTR(value), NewStringType::kNormal, RSTRING_LENINT(value)).ToLocalChecked());
|
|
558
748
|
case T_DATA:
|
|
559
749
|
klass = rb_funcall(value, rb_intern("class"), 0);
|
|
560
750
|
if (klass == rb_cTime || klass == rb_cDateTime)
|
|
@@ -629,6 +819,7 @@ create_snapshot_data_blob(const char *embedded_source = nullptr) {
|
|
|
629
819
|
SnapshotCreator::FunctionCodeHandling::kClear);
|
|
630
820
|
}
|
|
631
821
|
|
|
822
|
+
static
|
|
632
823
|
StartupData warm_up_snapshot_data_blob(StartupData cold_snapshot_blob,
|
|
633
824
|
const char *warmup_source) {
|
|
634
825
|
// Use following steps to create a warmed up snapshot blob from a cold one:
|
|
@@ -662,21 +853,18 @@ StartupData warm_up_snapshot_data_blob(StartupData cold_snapshot_blob,
|
|
|
662
853
|
return result;
|
|
663
854
|
}
|
|
664
855
|
|
|
665
|
-
static VALUE rb_snapshot_size(VALUE self
|
|
856
|
+
static VALUE rb_snapshot_size(VALUE self) {
|
|
666
857
|
SnapshotInfo* snapshot_info;
|
|
667
|
-
|
|
858
|
+
TypedData_Get_Struct(self, SnapshotInfo, &snapshot_type, snapshot_info);
|
|
668
859
|
|
|
669
860
|
return INT2NUM(snapshot_info->raw_size);
|
|
670
861
|
}
|
|
671
862
|
|
|
672
863
|
static VALUE rb_snapshot_load(VALUE self, VALUE str) {
|
|
673
864
|
SnapshotInfo* snapshot_info;
|
|
674
|
-
|
|
865
|
+
TypedData_Get_Struct(self, SnapshotInfo, &snapshot_type, snapshot_info);
|
|
675
866
|
|
|
676
|
-
|
|
677
|
-
rb_raise(rb_eArgError, "wrong type argument %" PRIsVALUE " (should be a string)",
|
|
678
|
-
rb_obj_class(str));
|
|
679
|
-
}
|
|
867
|
+
Check_Type(str, T_STRING);
|
|
680
868
|
|
|
681
869
|
init_v8();
|
|
682
870
|
|
|
@@ -692,21 +880,18 @@ static VALUE rb_snapshot_load(VALUE self, VALUE str) {
|
|
|
692
880
|
return Qnil;
|
|
693
881
|
}
|
|
694
882
|
|
|
695
|
-
static VALUE rb_snapshot_dump(VALUE self
|
|
883
|
+
static VALUE rb_snapshot_dump(VALUE self) {
|
|
696
884
|
SnapshotInfo* snapshot_info;
|
|
697
|
-
|
|
885
|
+
TypedData_Get_Struct(self, SnapshotInfo, &snapshot_type, snapshot_info);
|
|
698
886
|
|
|
699
887
|
return rb_str_new(snapshot_info->data, snapshot_info->raw_size);
|
|
700
888
|
}
|
|
701
889
|
|
|
702
890
|
static VALUE rb_snapshot_warmup_unsafe(VALUE self, VALUE str) {
|
|
703
891
|
SnapshotInfo* snapshot_info;
|
|
704
|
-
|
|
892
|
+
TypedData_Get_Struct(self, SnapshotInfo, &snapshot_type, snapshot_info);
|
|
705
893
|
|
|
706
|
-
|
|
707
|
-
rb_raise(rb_eArgError, "wrong type argument %" PRIsVALUE " (should be a string)",
|
|
708
|
-
rb_obj_class(str));
|
|
709
|
-
}
|
|
894
|
+
Check_Type(str, T_STRING);
|
|
710
895
|
|
|
711
896
|
init_v8();
|
|
712
897
|
|
|
@@ -748,13 +933,13 @@ void IsolateInfo::init(SnapshotInfo* snapshot_info) {
|
|
|
748
933
|
|
|
749
934
|
static VALUE rb_isolate_init_with_snapshot(VALUE self, VALUE snapshot) {
|
|
750
935
|
IsolateInfo* isolate_info;
|
|
751
|
-
|
|
936
|
+
TypedData_Get_Struct(self, IsolateInfo, &isolate_type, isolate_info);
|
|
752
937
|
|
|
753
938
|
init_v8();
|
|
754
939
|
|
|
755
940
|
SnapshotInfo* snapshot_info = nullptr;
|
|
756
941
|
if (!NIL_P(snapshot)) {
|
|
757
|
-
|
|
942
|
+
TypedData_Get_Struct(snapshot, SnapshotInfo, &snapshot_type, snapshot_info);
|
|
758
943
|
}
|
|
759
944
|
|
|
760
945
|
isolate_info->init(snapshot_info);
|
|
@@ -765,7 +950,7 @@ static VALUE rb_isolate_init_with_snapshot(VALUE self, VALUE snapshot) {
|
|
|
765
950
|
|
|
766
951
|
static VALUE rb_isolate_idle_notification(VALUE self, VALUE idle_time_in_ms) {
|
|
767
952
|
IsolateInfo* isolate_info;
|
|
768
|
-
|
|
953
|
+
TypedData_Get_Struct(self, IsolateInfo, &isolate_type, isolate_info);
|
|
769
954
|
|
|
770
955
|
if (current_platform == NULL) return Qfalse;
|
|
771
956
|
|
|
@@ -776,7 +961,7 @@ static VALUE rb_isolate_idle_notification(VALUE self, VALUE idle_time_in_ms) {
|
|
|
776
961
|
|
|
777
962
|
static VALUE rb_isolate_low_memory_notification(VALUE self) {
|
|
778
963
|
IsolateInfo* isolate_info;
|
|
779
|
-
|
|
964
|
+
TypedData_Get_Struct(self, IsolateInfo, &isolate_type, isolate_info);
|
|
780
965
|
|
|
781
966
|
if (current_platform == NULL) return Qfalse;
|
|
782
967
|
|
|
@@ -786,7 +971,7 @@ static VALUE rb_isolate_low_memory_notification(VALUE self) {
|
|
|
786
971
|
|
|
787
972
|
static VALUE rb_isolate_pump_message_loop(VALUE self) {
|
|
788
973
|
IsolateInfo* isolate_info;
|
|
789
|
-
|
|
974
|
+
TypedData_Get_Struct(self, IsolateInfo, &isolate_type, isolate_info);
|
|
790
975
|
|
|
791
976
|
if (current_platform == NULL) return Qfalse;
|
|
792
977
|
|
|
@@ -799,7 +984,7 @@ static VALUE rb_isolate_pump_message_loop(VALUE self) {
|
|
|
799
984
|
|
|
800
985
|
static VALUE rb_context_init_unsafe(VALUE self, VALUE isolate, VALUE snap) {
|
|
801
986
|
ContextInfo* context_info;
|
|
802
|
-
|
|
987
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
|
803
988
|
|
|
804
989
|
init_v8();
|
|
805
990
|
|
|
@@ -810,11 +995,11 @@ static VALUE rb_context_init_unsafe(VALUE self, VALUE isolate, VALUE snap) {
|
|
|
810
995
|
|
|
811
996
|
SnapshotInfo *snapshot_info = nullptr;
|
|
812
997
|
if (!NIL_P(snap) && rb_obj_is_kind_of(snap, rb_cSnapshot)) {
|
|
813
|
-
|
|
998
|
+
TypedData_Get_Struct(snap, SnapshotInfo, &snapshot_type, snapshot_info);
|
|
814
999
|
}
|
|
815
1000
|
isolate_info->init(snapshot_info);
|
|
816
1001
|
} else { // given isolate or snapshot
|
|
817
|
-
|
|
1002
|
+
TypedData_Get_Struct(isolate, IsolateInfo, &isolate_type, isolate_info);
|
|
818
1003
|
}
|
|
819
1004
|
|
|
820
1005
|
context_info->isolate_info = isolate_info;
|
|
@@ -844,7 +1029,7 @@ static VALUE rb_context_init_unsafe(VALUE self, VALUE isolate, VALUE snap) {
|
|
|
844
1029
|
static VALUE convert_result_to_ruby(VALUE self /* context */,
|
|
845
1030
|
EvalResult& result) {
|
|
846
1031
|
ContextInfo *context_info;
|
|
847
|
-
|
|
1032
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
|
848
1033
|
|
|
849
1034
|
Isolate *isolate = context_info->isolate_info->isolate;
|
|
850
1035
|
Persistent<Context> *p_ctx = context_info->context;
|
|
@@ -871,7 +1056,7 @@ static VALUE convert_result_to_ruby(VALUE self /* context */,
|
|
|
871
1056
|
// a v8 scope, if we do the scope is never cleaned up properly and we leak
|
|
872
1057
|
if (!result.parsed) {
|
|
873
1058
|
if(TYPE(message) == T_STRING) {
|
|
874
|
-
rb_raise(rb_eParseError, "%
|
|
1059
|
+
rb_raise(rb_eParseError, "%" PRIsVALUE, message);
|
|
875
1060
|
} else {
|
|
876
1061
|
rb_raise(rb_eParseError, "Unknown JavaScript Error during parse");
|
|
877
1062
|
}
|
|
@@ -880,9 +1065,13 @@ static VALUE convert_result_to_ruby(VALUE self /* context */,
|
|
|
880
1065
|
if (!result.executed) {
|
|
881
1066
|
VALUE ruby_exception = rb_iv_get(self, "@current_exception");
|
|
882
1067
|
if (ruby_exception == Qnil) {
|
|
883
|
-
bool mem_softlimit_reached = (
|
|
1068
|
+
bool mem_softlimit_reached = IsolateData::Get(isolate, IsolateData::MEM_SOFTLIMIT_REACHED);
|
|
1069
|
+
bool marshal_stack_maxdepth_reached = IsolateData::Get(isolate, IsolateData::MARSHAL_STACKDEPTH_REACHED);
|
|
884
1070
|
// If we were terminated or have the memory softlimit flag set
|
|
885
|
-
if (
|
|
1071
|
+
if (marshal_stack_maxdepth_reached) {
|
|
1072
|
+
ruby_exception = rb_eScriptRuntimeError;
|
|
1073
|
+
message = rb_utf8_str_new_literal("Marshal object depth too deep. Script terminated.");
|
|
1074
|
+
} else if (result.terminated || mem_softlimit_reached) {
|
|
886
1075
|
ruby_exception = mem_softlimit_reached ? rb_eV8OutOfMemoryError : rb_eScriptTerminatedError;
|
|
887
1076
|
} else {
|
|
888
1077
|
ruby_exception = rb_eScriptRuntimeError;
|
|
@@ -890,15 +1079,17 @@ static VALUE convert_result_to_ruby(VALUE self /* context */,
|
|
|
890
1079
|
|
|
891
1080
|
// exception report about what happened
|
|
892
1081
|
if (TYPE(backtrace) == T_STRING) {
|
|
893
|
-
rb_raise(ruby_exception, "%
|
|
1082
|
+
rb_raise(ruby_exception, "%" PRIsVALUE, backtrace);
|
|
894
1083
|
} else if(TYPE(message) == T_STRING) {
|
|
895
|
-
rb_raise(ruby_exception, "%
|
|
1084
|
+
rb_raise(ruby_exception, "%" PRIsVALUE, message);
|
|
896
1085
|
} else {
|
|
897
1086
|
rb_raise(ruby_exception, "Unknown JavaScript Error during execution");
|
|
898
1087
|
}
|
|
1088
|
+
} else if (rb_obj_is_kind_of(ruby_exception, rb_eException)) {
|
|
1089
|
+
rb_exc_raise(ruby_exception);
|
|
899
1090
|
} else {
|
|
900
1091
|
VALUE rb_str = rb_funcall(ruby_exception, rb_intern("to_s"), 0);
|
|
901
|
-
rb_raise(CLASS_OF(ruby_exception), "%
|
|
1092
|
+
rb_raise(CLASS_OF(ruby_exception), "%" PRIsVALUE, rb_str);
|
|
902
1093
|
}
|
|
903
1094
|
}
|
|
904
1095
|
|
|
@@ -914,9 +1105,10 @@ static VALUE convert_result_to_ruby(VALUE self /* context */,
|
|
|
914
1105
|
|
|
915
1106
|
if (result.json) {
|
|
916
1107
|
Local<String> rstr = tmp->ToString(p_ctx->Get(isolate)).ToLocalChecked();
|
|
917
|
-
VALUE json_string =
|
|
1108
|
+
VALUE json_string = rb_utf8_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(isolate));
|
|
918
1109
|
ret = rb_funcall(rb_mJSON, rb_intern("parse"), 1, json_string);
|
|
919
1110
|
} else {
|
|
1111
|
+
StackCounter::Reset(isolate);
|
|
920
1112
|
ret = convert_v8_to_ruby(isolate, *p_ctx, tmp);
|
|
921
1113
|
}
|
|
922
1114
|
|
|
@@ -939,16 +1131,13 @@ static VALUE rb_context_eval_unsafe(VALUE self, VALUE str, VALUE filename) {
|
|
|
939
1131
|
EvalResult eval_result;
|
|
940
1132
|
ContextInfo* context_info;
|
|
941
1133
|
|
|
942
|
-
|
|
1134
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
|
943
1135
|
Isolate* isolate = context_info->isolate_info->isolate;
|
|
944
1136
|
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
if(filename != Qnil && TYPE(filename) != T_STRING) {
|
|
950
|
-
rb_raise(rb_eArgError, "wrong type argument %" PRIsVALUE " (should be nil or a string)",
|
|
951
|
-
rb_obj_class(filename));
|
|
1137
|
+
Check_Type(str, T_STRING);
|
|
1138
|
+
|
|
1139
|
+
if (!NIL_P(filename)) {
|
|
1140
|
+
Check_Type(filename, T_STRING);
|
|
952
1141
|
}
|
|
953
1142
|
|
|
954
1143
|
{
|
|
@@ -957,13 +1146,13 @@ static VALUE rb_context_eval_unsafe(VALUE self, VALUE str, VALUE filename) {
|
|
|
957
1146
|
HandleScope handle_scope(isolate);
|
|
958
1147
|
|
|
959
1148
|
Local<String> eval = String::NewFromUtf8(isolate, RSTRING_PTR(str),
|
|
960
|
-
NewStringType::kNormal, (
|
|
1149
|
+
NewStringType::kNormal, RSTRING_LENINT(str)).ToLocalChecked();
|
|
961
1150
|
|
|
962
1151
|
Local<String> local_filename;
|
|
963
1152
|
|
|
964
1153
|
if (filename != Qnil) {
|
|
965
1154
|
local_filename = String::NewFromUtf8(isolate, RSTRING_PTR(filename),
|
|
966
|
-
NewStringType::kNormal, (
|
|
1155
|
+
NewStringType::kNormal, RSTRING_LENINT(filename)).ToLocalChecked();
|
|
967
1156
|
eval_params.filename = &local_filename;
|
|
968
1157
|
} else {
|
|
969
1158
|
eval_params.filename = NULL;
|
|
@@ -974,6 +1163,7 @@ static VALUE rb_context_eval_unsafe(VALUE self, VALUE str, VALUE filename) {
|
|
|
974
1163
|
eval_params.result = &eval_result;
|
|
975
1164
|
eval_params.timeout = 0;
|
|
976
1165
|
eval_params.max_memory = 0;
|
|
1166
|
+
eval_params.marshal_stackdepth = 0;
|
|
977
1167
|
VALUE timeout = rb_iv_get(self, "@timeout");
|
|
978
1168
|
if (timeout != Qnil) {
|
|
979
1169
|
eval_params.timeout = (useconds_t)NUM2LONG(timeout);
|
|
@@ -984,6 +1174,11 @@ static VALUE rb_context_eval_unsafe(VALUE self, VALUE str, VALUE filename) {
|
|
|
984
1174
|
eval_params.max_memory = (size_t)NUM2ULONG(mem_softlimit);
|
|
985
1175
|
}
|
|
986
1176
|
|
|
1177
|
+
VALUE stack_depth = rb_iv_get(self, "@marshal_stack_depth");
|
|
1178
|
+
if (stack_depth != Qnil) {
|
|
1179
|
+
eval_params.marshal_stackdepth = (size_t)NUM2ULONG(stack_depth);
|
|
1180
|
+
}
|
|
1181
|
+
|
|
987
1182
|
eval_result.message = NULL;
|
|
988
1183
|
eval_result.backtrace = NULL;
|
|
989
1184
|
|
|
@@ -1021,7 +1216,7 @@ VALUE rescue_callback(VALUE rdata, VALUE exception) {
|
|
|
1021
1216
|
return exception;
|
|
1022
1217
|
}
|
|
1023
1218
|
|
|
1024
|
-
void*
|
|
1219
|
+
static void*
|
|
1025
1220
|
gvl_ruby_callback(void* data) {
|
|
1026
1221
|
|
|
1027
1222
|
FunctionCallbackInfo<Value>* args = (FunctionCallbackInfo<Value>*)data;
|
|
@@ -1037,7 +1232,7 @@ gvl_ruby_callback(void* data) {
|
|
|
1037
1232
|
HandleScope scope(args->GetIsolate());
|
|
1038
1233
|
Local<External> external = Local<External>::Cast(args->Data());
|
|
1039
1234
|
|
|
1040
|
-
self =
|
|
1235
|
+
self = (VALUE)(external->Value());
|
|
1041
1236
|
callback = rb_iv_get(self, "@callback");
|
|
1042
1237
|
|
|
1043
1238
|
parent = rb_iv_get(self, "@parent");
|
|
@@ -1045,7 +1240,7 @@ gvl_ruby_callback(void* data) {
|
|
|
1045
1240
|
return NULL;
|
|
1046
1241
|
}
|
|
1047
1242
|
|
|
1048
|
-
|
|
1243
|
+
TypedData_Get_Struct(parent, ContextInfo, &context_type, context_info);
|
|
1049
1244
|
|
|
1050
1245
|
if (length > 0) {
|
|
1051
1246
|
ruby_args = rb_ary_tmp_new(length);
|
|
@@ -1053,6 +1248,7 @@ gvl_ruby_callback(void* data) {
|
|
|
1053
1248
|
|
|
1054
1249
|
for (int i = 0; i < length; i++) {
|
|
1055
1250
|
Local<Value> value = ((*args)[i]).As<Value>();
|
|
1251
|
+
StackCounter::Reset(args->GetIsolate());
|
|
1056
1252
|
VALUE tmp = convert_v8_to_ruby(args->GetIsolate(),
|
|
1057
1253
|
*context_info->context, value);
|
|
1058
1254
|
rb_ary_push(ruby_args, tmp);
|
|
@@ -1066,20 +1262,22 @@ gvl_ruby_callback(void* data) {
|
|
|
1066
1262
|
callback_data.ruby_args = ruby_args;
|
|
1067
1263
|
callback_data.failed = false;
|
|
1068
1264
|
|
|
1069
|
-
if ((
|
|
1265
|
+
if (IsolateData::Get(args->GetIsolate(), IsolateData::DO_TERMINATE)) {
|
|
1070
1266
|
args->GetIsolate()->ThrowException(
|
|
1071
1267
|
String::NewFromUtf8Literal(args->GetIsolate(),
|
|
1072
1268
|
"Terminated execution during transition from Ruby to JS"));
|
|
1073
1269
|
args->GetIsolate()->TerminateExecution();
|
|
1074
1270
|
if (length > 0) {
|
|
1075
1271
|
rb_ary_clear(ruby_args);
|
|
1076
|
-
rb_gc_force_recycle(ruby_args);
|
|
1077
1272
|
}
|
|
1078
1273
|
return NULL;
|
|
1079
1274
|
}
|
|
1080
1275
|
|
|
1081
|
-
|
|
1082
|
-
|
|
1276
|
+
VALUE callback_data_value = (VALUE)&callback_data;
|
|
1277
|
+
|
|
1278
|
+
// TODO: use rb_vrescue2 in Ruby 2.7 and above
|
|
1279
|
+
result = rb_rescue2(MR_METHOD_FUNC(protected_callback), callback_data_value,
|
|
1280
|
+
MR_METHOD_FUNC(rescue_callback), callback_data_value, rb_eException, (VALUE)0);
|
|
1083
1281
|
|
|
1084
1282
|
if(callback_data.failed) {
|
|
1085
1283
|
rb_iv_set(parent, "@current_exception", result);
|
|
@@ -1093,26 +1291,24 @@ gvl_ruby_callback(void* data) {
|
|
|
1093
1291
|
|
|
1094
1292
|
if (length > 0) {
|
|
1095
1293
|
rb_ary_clear(ruby_args);
|
|
1096
|
-
rb_gc_force_recycle(ruby_args);
|
|
1097
1294
|
}
|
|
1098
1295
|
|
|
1099
|
-
if ((
|
|
1100
|
-
|
|
1101
|
-
isolate->TerminateExecution();
|
|
1296
|
+
if (IsolateData::Get(args->GetIsolate(), IsolateData::DO_TERMINATE)) {
|
|
1297
|
+
args->GetIsolate()->TerminateExecution();
|
|
1102
1298
|
}
|
|
1103
1299
|
|
|
1104
1300
|
return NULL;
|
|
1105
1301
|
}
|
|
1106
1302
|
|
|
1107
1303
|
static void ruby_callback(const FunctionCallbackInfo<Value>& args) {
|
|
1108
|
-
bool has_gvl = (
|
|
1304
|
+
bool has_gvl = IsolateData::Get(args.GetIsolate(), IsolateData::IN_GVL);
|
|
1109
1305
|
|
|
1110
1306
|
if(has_gvl) {
|
|
1111
1307
|
gvl_ruby_callback((void*)&args);
|
|
1112
1308
|
} else {
|
|
1113
|
-
args.GetIsolate()
|
|
1309
|
+
IsolateData::Set(args.GetIsolate(), IsolateData::IN_GVL, true);
|
|
1114
1310
|
rb_thread_call_with_gvl(gvl_ruby_callback, (void*)(&args));
|
|
1115
|
-
args.GetIsolate()
|
|
1311
|
+
IsolateData::Set(args.GetIsolate(), IsolateData::IN_GVL, false);
|
|
1116
1312
|
}
|
|
1117
1313
|
}
|
|
1118
1314
|
|
|
@@ -1129,7 +1325,7 @@ static VALUE rb_external_function_notify_v8(VALUE self) {
|
|
|
1129
1325
|
bool parse_error = false;
|
|
1130
1326
|
bool attach_error = false;
|
|
1131
1327
|
|
|
1132
|
-
|
|
1328
|
+
TypedData_Get_Struct(parent, ContextInfo, &context_type, context_info);
|
|
1133
1329
|
Isolate* isolate = context_info->isolate_info->isolate;
|
|
1134
1330
|
|
|
1135
1331
|
{
|
|
@@ -1142,29 +1338,27 @@ static VALUE rb_external_function_notify_v8(VALUE self) {
|
|
|
1142
1338
|
|
|
1143
1339
|
Local<String> v8_str =
|
|
1144
1340
|
String::NewFromUtf8(isolate, RSTRING_PTR(name),
|
|
1145
|
-
NewStringType::kNormal, (
|
|
1341
|
+
NewStringType::kNormal, RSTRING_LENINT(name))
|
|
1146
1342
|
.ToLocalChecked();
|
|
1147
1343
|
|
|
1148
|
-
//
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
*self_copy = self;
|
|
1152
|
-
|
|
1153
|
-
Local<Value> external = External::New(isolate, self_copy);
|
|
1344
|
+
// Note that self (rb_cExternalFunction) is a pure Ruby T_OBJECT,
|
|
1345
|
+
// not a T_DATA type like most other classes in this file
|
|
1346
|
+
Local<Value> external = External::New(isolate, (void *)self);
|
|
1154
1347
|
|
|
1155
1348
|
if (parent_object == Qnil) {
|
|
1156
|
-
context->Global()->Set(
|
|
1349
|
+
Maybe<bool> success = context->Global()->Set(
|
|
1157
1350
|
context,
|
|
1158
1351
|
v8_str,
|
|
1159
1352
|
FunctionTemplate::New(isolate, ruby_callback, external)
|
|
1160
1353
|
->GetFunction(context)
|
|
1161
1354
|
.ToLocalChecked());
|
|
1355
|
+
(void)success;
|
|
1162
1356
|
|
|
1163
1357
|
} else {
|
|
1164
1358
|
Local<String> eval =
|
|
1165
1359
|
String::NewFromUtf8(isolate, RSTRING_PTR(parent_object_eval),
|
|
1166
1360
|
NewStringType::kNormal,
|
|
1167
|
-
(
|
|
1361
|
+
RSTRING_LENINT(parent_object_eval))
|
|
1168
1362
|
.ToLocalChecked();
|
|
1169
1363
|
|
|
1170
1364
|
MaybeLocal<Script> parsed_script = Script::Compile(context, eval);
|
|
@@ -1178,12 +1372,13 @@ static VALUE rb_external_function_notify_v8(VALUE self) {
|
|
|
1178
1372
|
if (!maybe_value.IsEmpty()) {
|
|
1179
1373
|
Local<Value> value = maybe_value.ToLocalChecked();
|
|
1180
1374
|
if (value->IsObject()) {
|
|
1181
|
-
value.As<Object>()->Set(
|
|
1375
|
+
Maybe<bool> success = value.As<Object>()->Set(
|
|
1182
1376
|
context,
|
|
1183
1377
|
v8_str,
|
|
1184
1378
|
FunctionTemplate::New(isolate, ruby_callback, external)
|
|
1185
1379
|
->GetFunction(context)
|
|
1186
1380
|
.ToLocalChecked());
|
|
1381
|
+
(void)success;
|
|
1187
1382
|
attach_error = false;
|
|
1188
1383
|
}
|
|
1189
1384
|
}
|
|
@@ -1205,7 +1400,7 @@ static VALUE rb_external_function_notify_v8(VALUE self) {
|
|
|
1205
1400
|
|
|
1206
1401
|
static VALUE rb_context_isolate_mutex(VALUE self) {
|
|
1207
1402
|
ContextInfo* context_info;
|
|
1208
|
-
|
|
1403
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
|
1209
1404
|
|
|
1210
1405
|
if (!context_info->isolate_info) {
|
|
1211
1406
|
rb_raise(rb_eScriptRuntimeError, "Context has no Isolate available anymore");
|
|
@@ -1221,11 +1416,16 @@ IsolateInfo::~IsolateInfo() {
|
|
|
1221
1416
|
"it can not be disposed and memory will not be "
|
|
1222
1417
|
"reclaimed till the Ruby process exits.\n");
|
|
1223
1418
|
} else {
|
|
1224
|
-
if (this->pid != getpid()) {
|
|
1419
|
+
if (this->pid != getpid() && !single_threaded) {
|
|
1225
1420
|
fprintf(stderr, "WARNING: V8 isolate was forked, "
|
|
1226
1421
|
"it can not be disposed and "
|
|
1227
1422
|
"memory will not be reclaimed "
|
|
1228
|
-
"till the Ruby process exits.\n"
|
|
1423
|
+
"till the Ruby process exits.\n"
|
|
1424
|
+
"It is VERY likely your process will hang.\n"
|
|
1425
|
+
"If you wish to use v8 in forked environment "
|
|
1426
|
+
"please ensure the platform is initialized with:\n"
|
|
1427
|
+
"MiniRacer::Platform.set_flags! :single_threaded\n"
|
|
1428
|
+
);
|
|
1229
1429
|
} else {
|
|
1230
1430
|
isolate->Dispose();
|
|
1231
1431
|
}
|
|
@@ -1256,42 +1456,33 @@ static void free_context_raw(void *arg) {
|
|
|
1256
1456
|
if (isolate_info) {
|
|
1257
1457
|
isolate_info->release();
|
|
1258
1458
|
}
|
|
1259
|
-
|
|
1260
|
-
xfree(context_info);
|
|
1261
1459
|
}
|
|
1262
1460
|
|
|
1263
1461
|
static void *free_context_thr(void* arg) {
|
|
1264
|
-
if (
|
|
1265
|
-
|
|
1462
|
+
if (ruby_exiting.load() == 0) {
|
|
1463
|
+
free_context_raw(arg);
|
|
1464
|
+
xfree(arg);
|
|
1266
1465
|
}
|
|
1267
|
-
if (ruby_exiting) {
|
|
1268
|
-
return NULL;
|
|
1269
|
-
}
|
|
1270
|
-
|
|
1271
|
-
free_context_raw(arg);
|
|
1272
|
-
|
|
1273
|
-
pthread_rwlock_unlock(&exit_lock);
|
|
1274
|
-
|
|
1275
1466
|
return NULL;
|
|
1276
1467
|
}
|
|
1277
1468
|
|
|
1278
1469
|
// destroys everything except freeing the ContextInfo struct (see deallocate())
|
|
1279
1470
|
static void free_context(ContextInfo* context_info) {
|
|
1280
|
-
|
|
1281
1471
|
IsolateInfo* isolate_info = context_info->isolate_info;
|
|
1282
1472
|
|
|
1283
|
-
ContextInfo* context_info_copy = ALLOC(ContextInfo);
|
|
1284
|
-
context_info_copy->isolate_info = context_info->isolate_info;
|
|
1285
|
-
context_info_copy->context = context_info->context;
|
|
1286
|
-
|
|
1287
1473
|
if (isolate_info && isolate_info->refs() > 1) {
|
|
1288
1474
|
pthread_t free_context_thread;
|
|
1475
|
+
ContextInfo* context_info_copy = ALLOC(ContextInfo);
|
|
1476
|
+
|
|
1477
|
+
context_info_copy->isolate_info = context_info->isolate_info;
|
|
1478
|
+
context_info_copy->context = context_info->context;
|
|
1289
1479
|
if (pthread_create(&free_context_thread, thread_attr_p,
|
|
1290
1480
|
free_context_thr, (void*)context_info_copy)) {
|
|
1291
1481
|
fprintf(stderr, "WARNING failed to release memory in MiniRacer, thread to release could not be created, process will leak memory\n");
|
|
1482
|
+
xfree(context_info_copy);
|
|
1292
1483
|
}
|
|
1293
1484
|
} else {
|
|
1294
|
-
free_context_raw(
|
|
1485
|
+
free_context_raw(context_info);
|
|
1295
1486
|
}
|
|
1296
1487
|
|
|
1297
1488
|
context_info->context = NULL;
|
|
@@ -1310,6 +1501,11 @@ static void mark_isolate(void* data) {
|
|
|
1310
1501
|
isolate_info->mark();
|
|
1311
1502
|
}
|
|
1312
1503
|
|
|
1504
|
+
static size_t isolate_memsize(const void *ptr) {
|
|
1505
|
+
const IsolateInfo *isolate_info = (const IsolateInfo *)ptr;
|
|
1506
|
+
return sizeof(*isolate_info);
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1313
1509
|
static void deallocate(void* data) {
|
|
1314
1510
|
ContextInfo* context_info = (ContextInfo*)data;
|
|
1315
1511
|
|
|
@@ -1318,6 +1514,11 @@ static void deallocate(void* data) {
|
|
|
1318
1514
|
xfree(data);
|
|
1319
1515
|
}
|
|
1320
1516
|
|
|
1517
|
+
static size_t context_memsize(const void *ptr)
|
|
1518
|
+
{
|
|
1519
|
+
return sizeof(ContextInfo);
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1321
1522
|
static void mark_context(void* data) {
|
|
1322
1523
|
ContextInfo* context_info = (ContextInfo*)data;
|
|
1323
1524
|
if (context_info->isolate_info) {
|
|
@@ -1325,48 +1526,39 @@ static void mark_context(void* data) {
|
|
|
1325
1526
|
}
|
|
1326
1527
|
}
|
|
1327
1528
|
|
|
1328
|
-
static void deallocate_external_function(void * data) {
|
|
1329
|
-
xfree(data);
|
|
1330
|
-
}
|
|
1331
|
-
|
|
1332
1529
|
static void deallocate_snapshot(void * data) {
|
|
1333
1530
|
SnapshotInfo* snapshot_info = (SnapshotInfo*)data;
|
|
1334
1531
|
delete[] snapshot_info->data;
|
|
1335
1532
|
xfree(snapshot_info);
|
|
1336
1533
|
}
|
|
1337
1534
|
|
|
1338
|
-
static
|
|
1339
|
-
|
|
1340
|
-
return
|
|
1535
|
+
static size_t snapshot_memsize(const void *data) {
|
|
1536
|
+
SnapshotInfo* snapshot_info = (SnapshotInfo*)data;
|
|
1537
|
+
return sizeof(*snapshot_info) + snapshot_info->raw_size;
|
|
1341
1538
|
}
|
|
1342
1539
|
|
|
1343
1540
|
static VALUE allocate(VALUE klass) {
|
|
1344
|
-
ContextInfo* context_info
|
|
1345
|
-
|
|
1346
|
-
context_info->context = NULL;
|
|
1347
|
-
|
|
1348
|
-
return Data_Wrap_Struct(klass, mark_context, deallocate, (void*)context_info);
|
|
1541
|
+
ContextInfo* context_info;
|
|
1542
|
+
return TypedData_Make_Struct(klass, ContextInfo, &context_type, context_info);
|
|
1349
1543
|
}
|
|
1350
1544
|
|
|
1351
1545
|
static VALUE allocate_snapshot(VALUE klass) {
|
|
1352
|
-
SnapshotInfo* snapshot_info
|
|
1353
|
-
snapshot_info->data = NULL;
|
|
1354
|
-
snapshot_info->raw_size = 0;
|
|
1546
|
+
SnapshotInfo* snapshot_info;
|
|
1355
1547
|
|
|
1356
|
-
return
|
|
1548
|
+
return TypedData_Make_Struct(klass, SnapshotInfo, &snapshot_type, snapshot_info);
|
|
1357
1549
|
}
|
|
1358
1550
|
|
|
1359
1551
|
static VALUE allocate_isolate(VALUE klass) {
|
|
1360
1552
|
IsolateInfo* isolate_info = new IsolateInfo();
|
|
1361
1553
|
|
|
1362
|
-
return
|
|
1554
|
+
return TypedData_Wrap_Struct(klass, &isolate_type, isolate_info);
|
|
1363
1555
|
}
|
|
1364
1556
|
|
|
1365
1557
|
static VALUE
|
|
1366
1558
|
rb_heap_stats(VALUE self) {
|
|
1367
1559
|
|
|
1368
1560
|
ContextInfo* context_info;
|
|
1369
|
-
|
|
1561
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
|
1370
1562
|
Isolate* isolate;
|
|
1371
1563
|
v8::HeapStatistics stats;
|
|
1372
1564
|
|
|
@@ -1398,7 +1590,9 @@ rb_heap_stats(VALUE self) {
|
|
|
1398
1590
|
// https://github.com/bnoordhuis/node-heapdump/blob/master/src/heapdump.cc
|
|
1399
1591
|
class FileOutputStream : public OutputStream {
|
|
1400
1592
|
public:
|
|
1401
|
-
|
|
1593
|
+
int err;
|
|
1594
|
+
|
|
1595
|
+
FileOutputStream(int fd) : fd(fd) { err = 0; }
|
|
1402
1596
|
|
|
1403
1597
|
virtual int GetChunkSize() {
|
|
1404
1598
|
return 65536;
|
|
@@ -1407,17 +1601,27 @@ class FileOutputStream : public OutputStream {
|
|
|
1407
1601
|
virtual void EndOfStream() {}
|
|
1408
1602
|
|
|
1409
1603
|
virtual WriteResult WriteAsciiChunk(char* data, int size) {
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1604
|
+
size_t len = static_cast<size_t>(size);
|
|
1605
|
+
|
|
1606
|
+
while (len) {
|
|
1607
|
+
ssize_t w = write(fd, data, len);
|
|
1608
|
+
|
|
1609
|
+
if (w > 0) {
|
|
1610
|
+
data += w;
|
|
1611
|
+
len -= w;
|
|
1612
|
+
} else if (w < 0) {
|
|
1613
|
+
err = errno;
|
|
1614
|
+
return kAbort;
|
|
1615
|
+
} else { /* w == 0, could be out-of-space */
|
|
1616
|
+
err = -1;
|
|
1617
|
+
return kAbort;
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
return kContinue;
|
|
1417
1621
|
}
|
|
1418
1622
|
|
|
1419
1623
|
private:
|
|
1420
|
-
|
|
1624
|
+
int fd;
|
|
1421
1625
|
};
|
|
1422
1626
|
|
|
1423
1627
|
|
|
@@ -1430,13 +1634,11 @@ rb_heap_snapshot(VALUE self, VALUE file) {
|
|
|
1430
1634
|
|
|
1431
1635
|
if (!fptr) return Qfalse;
|
|
1432
1636
|
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
if (fp == NULL) return Qfalse;
|
|
1436
|
-
|
|
1637
|
+
// prepare for unbuffered write(2) below:
|
|
1638
|
+
rb_funcall(file, rb_intern("flush"), 0);
|
|
1437
1639
|
|
|
1438
1640
|
ContextInfo* context_info;
|
|
1439
|
-
|
|
1641
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
|
1440
1642
|
Isolate* isolate;
|
|
1441
1643
|
isolate = context_info->isolate_info ? context_info->isolate_info->isolate : NULL;
|
|
1442
1644
|
|
|
@@ -1450,13 +1652,14 @@ rb_heap_snapshot(VALUE self, VALUE file) {
|
|
|
1450
1652
|
|
|
1451
1653
|
const HeapSnapshot* const snap = heap_profiler->TakeHeapSnapshot();
|
|
1452
1654
|
|
|
1453
|
-
FileOutputStream stream(
|
|
1655
|
+
FileOutputStream stream(fptr->fd);
|
|
1454
1656
|
snap->Serialize(&stream, HeapSnapshot::kJSON);
|
|
1455
1657
|
|
|
1456
|
-
fflush(fp);
|
|
1457
|
-
|
|
1458
1658
|
const_cast<HeapSnapshot*>(snap)->Delete();
|
|
1459
1659
|
|
|
1660
|
+
/* TODO: perhaps rb_sys_fail here */
|
|
1661
|
+
if (stream.err) return Qfalse;
|
|
1662
|
+
|
|
1460
1663
|
return Qtrue;
|
|
1461
1664
|
}
|
|
1462
1665
|
|
|
@@ -1464,12 +1667,12 @@ static VALUE
|
|
|
1464
1667
|
rb_context_stop(VALUE self) {
|
|
1465
1668
|
|
|
1466
1669
|
ContextInfo* context_info;
|
|
1467
|
-
|
|
1670
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
|
1468
1671
|
|
|
1469
1672
|
Isolate* isolate = context_info->isolate_info->isolate;
|
|
1470
1673
|
|
|
1471
1674
|
// flag for termination
|
|
1472
|
-
isolate
|
|
1675
|
+
IsolateData::Set(isolate, IsolateData::DO_TERMINATE, true);
|
|
1473
1676
|
|
|
1474
1677
|
isolate->TerminateExecution();
|
|
1475
1678
|
rb_funcall(self, rb_intern("stop_attached"), 0);
|
|
@@ -1481,7 +1684,7 @@ static VALUE
|
|
|
1481
1684
|
rb_context_dispose(VALUE self) {
|
|
1482
1685
|
|
|
1483
1686
|
ContextInfo* context_info;
|
|
1484
|
-
|
|
1687
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
|
1485
1688
|
|
|
1486
1689
|
free_context(context_info);
|
|
1487
1690
|
|
|
@@ -1498,18 +1701,20 @@ nogvl_context_call(void *args) {
|
|
|
1498
1701
|
IsolateInfo *isolate_info = call->context_info->isolate_info;
|
|
1499
1702
|
Isolate* isolate = isolate_info->isolate;
|
|
1500
1703
|
|
|
1501
|
-
|
|
1502
|
-
isolate
|
|
1503
|
-
// terminate ASAP
|
|
1504
|
-
isolate->SetData(DO_TERMINATE, (void*)false);
|
|
1704
|
+
IsolateData::Set(isolate, IsolateData::IN_GVL, false);
|
|
1705
|
+
IsolateData::Set(isolate, IsolateData::DO_TERMINATE, false);
|
|
1505
1706
|
|
|
1506
1707
|
if (call->max_memory > 0) {
|
|
1507
|
-
isolate
|
|
1508
|
-
isolate
|
|
1708
|
+
IsolateData::Set(isolate, IsolateData::MEM_SOFTLIMIT_MAX, call->max_memory);
|
|
1709
|
+
IsolateData::Set(isolate, IsolateData::MEM_SOFTLIMIT_REACHED, false);
|
|
1509
1710
|
if (!isolate_info->added_gc_cb) {
|
|
1510
|
-
|
|
1711
|
+
isolate->AddGCEpilogueCallback(gc_callback);
|
|
1511
1712
|
isolate_info->added_gc_cb = true;
|
|
1713
|
+
}
|
|
1512
1714
|
}
|
|
1715
|
+
|
|
1716
|
+
if (call->marshal_stackdepth > 0) {
|
|
1717
|
+
StackCounter::SetMax(isolate, call->marshal_stackdepth);
|
|
1513
1718
|
}
|
|
1514
1719
|
|
|
1515
1720
|
Isolate::Scope isolate_scope(isolate);
|
|
@@ -1527,7 +1732,7 @@ nogvl_context_call(void *args) {
|
|
|
1527
1732
|
MaybeLocal<v8::Value> res = fun->Call(context, context->Global(), call->argc, call->argv);
|
|
1528
1733
|
prepare_result(res, trycatch, isolate, context, eval_res);
|
|
1529
1734
|
|
|
1530
|
-
isolate
|
|
1735
|
+
IsolateData::Set(isolate, IsolateData::IN_GVL, true);
|
|
1531
1736
|
|
|
1532
1737
|
return NULL;
|
|
1533
1738
|
}
|
|
@@ -1542,7 +1747,7 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) {
|
|
|
1542
1747
|
FunctionCall call;
|
|
1543
1748
|
VALUE *call_argv = NULL;
|
|
1544
1749
|
|
|
1545
|
-
|
|
1750
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
|
1546
1751
|
Isolate* isolate = context_info->isolate_info->isolate;
|
|
1547
1752
|
|
|
1548
1753
|
if (argc < 1) {
|
|
@@ -1550,9 +1755,7 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) {
|
|
|
1550
1755
|
}
|
|
1551
1756
|
|
|
1552
1757
|
VALUE function_name = argv[0];
|
|
1553
|
-
|
|
1554
|
-
rb_raise(rb_eTypeError, "first argument should be a String");
|
|
1555
|
-
}
|
|
1758
|
+
Check_Type(function_name, T_STRING);
|
|
1556
1759
|
|
|
1557
1760
|
char *fname = RSTRING_PTR(function_name);
|
|
1558
1761
|
if (!fname) {
|
|
@@ -1575,6 +1778,13 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) {
|
|
|
1575
1778
|
unsigned long sl_int = NUM2ULONG(mem_softlimit);
|
|
1576
1779
|
call.max_memory = (size_t)sl_int;
|
|
1577
1780
|
}
|
|
1781
|
+
|
|
1782
|
+
call.marshal_stackdepth = 0;
|
|
1783
|
+
VALUE marshal_stackdepth = rb_iv_get(self, "@marshal_stack_depth");
|
|
1784
|
+
if (marshal_stackdepth != Qnil) {
|
|
1785
|
+
unsigned long sl_int = NUM2ULONG(marshal_stackdepth);
|
|
1786
|
+
call.marshal_stackdepth = (size_t)sl_int;
|
|
1787
|
+
}
|
|
1578
1788
|
|
|
1579
1789
|
bool missingFunction = false;
|
|
1580
1790
|
{
|
|
@@ -1596,23 +1806,15 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) {
|
|
|
1596
1806
|
if (val.IsEmpty() || !val.ToLocalChecked()->IsFunction()) {
|
|
1597
1807
|
missingFunction = true;
|
|
1598
1808
|
} else {
|
|
1599
|
-
|
|
1600
1809
|
Local<v8::Function> fun = Local<v8::Function>::Cast(val.ToLocalChecked());
|
|
1810
|
+
VALUE tmp;
|
|
1601
1811
|
call.fun = fun;
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
call.argv = (v8::Local<Value> *) malloc(sizeof(void *) * fun_argc);
|
|
1606
|
-
if (!call.argv) {
|
|
1607
|
-
return Qnil;
|
|
1608
|
-
}
|
|
1609
|
-
for(int i=0; i < fun_argc; i++) {
|
|
1610
|
-
call.argv[i] = convert_ruby_to_v8(isolate, context, call_argv[i]);
|
|
1611
|
-
}
|
|
1812
|
+
call.argv = (v8::Local<Value> *)RB_ALLOCV_N(void *, tmp, call.argc);
|
|
1813
|
+
for(int i=0; i < call.argc; i++) {
|
|
1814
|
+
call.argv[i] = convert_ruby_to_v8(isolate, context, call_argv[i]);
|
|
1612
1815
|
}
|
|
1613
1816
|
rb_thread_call_without_gvl(nogvl_context_call, &call, unblock_function, &call);
|
|
1614
|
-
|
|
1615
|
-
|
|
1817
|
+
RB_ALLOCV_END(tmp);
|
|
1616
1818
|
}
|
|
1617
1819
|
}
|
|
1618
1820
|
|
|
@@ -1625,7 +1827,7 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) {
|
|
|
1625
1827
|
|
|
1626
1828
|
static VALUE rb_context_create_isolate_value(VALUE self) {
|
|
1627
1829
|
ContextInfo* context_info;
|
|
1628
|
-
|
|
1830
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
|
1629
1831
|
IsolateInfo *isolate_info = context_info->isolate_info;
|
|
1630
1832
|
|
|
1631
1833
|
if (!isolate_info) {
|
|
@@ -1633,22 +1835,18 @@ static VALUE rb_context_create_isolate_value(VALUE self) {
|
|
|
1633
1835
|
}
|
|
1634
1836
|
|
|
1635
1837
|
isolate_info->hold();
|
|
1636
|
-
return
|
|
1838
|
+
return TypedData_Wrap_Struct(rb_cIsolate, &isolate_type, isolate_info);
|
|
1637
1839
|
}
|
|
1638
1840
|
|
|
1639
1841
|
static void set_ruby_exiting(VALUE value) {
|
|
1640
1842
|
(void)value;
|
|
1641
1843
|
|
|
1642
|
-
|
|
1643
|
-
ruby_exiting = true;
|
|
1644
|
-
if (res == 0) {
|
|
1645
|
-
pthread_rwlock_unlock(&exit_lock);
|
|
1646
|
-
}
|
|
1844
|
+
ruby_exiting.store(1);
|
|
1647
1845
|
}
|
|
1648
1846
|
|
|
1649
1847
|
extern "C" {
|
|
1650
1848
|
|
|
1651
|
-
void Init_mini_racer_extension ( void )
|
|
1849
|
+
__attribute__((visibility("default"))) void Init_mini_racer_extension ( void )
|
|
1652
1850
|
{
|
|
1653
1851
|
VALUE rb_mMiniRacer = rb_define_module("MiniRacer");
|
|
1654
1852
|
rb_cContext = rb_define_class_under(rb_mMiniRacer, "Context", rb_cObject);
|
|
@@ -1688,7 +1886,6 @@ extern "C" {
|
|
|
1688
1886
|
rb_define_alloc_func(rb_cIsolate, allocate_isolate);
|
|
1689
1887
|
|
|
1690
1888
|
rb_define_private_method(rb_cExternalFunction, "notify_v8", (VALUE(*)(...))&rb_external_function_notify_v8, 0);
|
|
1691
|
-
rb_define_alloc_func(rb_cExternalFunction, allocate_external_function);
|
|
1692
1889
|
|
|
1693
1890
|
rb_define_method(rb_cSnapshot, "size", (VALUE(*)(...))&rb_snapshot_size, 0);
|
|
1694
1891
|
rb_define_method(rb_cSnapshot, "dump", (VALUE(*)(...))&rb_snapshot_dump, 0);
|