mini_racer 0.5.0 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +72 -26
- data/CHANGELOG +40 -0
- data/README.md +18 -16
- data/Rakefile +16 -4
- data/ext/mini_racer_extension/extconf.rb +34 -13
- data/ext/mini_racer_extension/mini_racer_extension.cc +181 -177
- data/ext/mini_racer_loader/extconf.rb +6 -1
- data/lib/mini_racer/truffleruby.rb +353 -0
- data/lib/mini_racer/version.rb +1 -1
- data/lib/mini_racer.rb +19 -17
- metadata +10 -10
- data/.travis.yml +0 -23
@@ -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
|
|
@@ -295,17 +305,36 @@ static std::unique_ptr<Platform> current_platform = NULL;
|
|
295
305
|
static std::mutex platform_lock;
|
296
306
|
|
297
307
|
static pthread_attr_t *thread_attr_p;
|
298
|
-
static
|
299
|
-
static bool ruby_exiting = false; // guarded by exit_lock
|
308
|
+
static std::atomic_int ruby_exiting(0);
|
300
309
|
static bool single_threaded = false;
|
301
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
|
+
};
|
333
|
+
|
302
334
|
static VALUE rb_platform_set_flag_as_str(VALUE _klass, VALUE flag_as_str) {
|
303
335
|
bool platform_already_initialized = false;
|
304
336
|
|
305
|
-
|
306
|
-
rb_raise(rb_eArgError, "wrong type argument %" PRIsVALUE" (should be a string)",
|
307
|
-
rb_obj_class(flag_as_str));
|
308
|
-
}
|
337
|
+
Check_Type(flag_as_str, T_STRING);
|
309
338
|
|
310
339
|
platform_lock.lock();
|
311
340
|
|
@@ -313,7 +342,7 @@ static VALUE rb_platform_set_flag_as_str(VALUE _klass, VALUE flag_as_str) {
|
|
313
342
|
if (!strcmp(RSTRING_PTR(flag_as_str), "--single_threaded")) {
|
314
343
|
single_threaded = true;
|
315
344
|
}
|
316
|
-
V8::SetFlagsFromString(RSTRING_PTR(flag_as_str), (
|
345
|
+
V8::SetFlagsFromString(RSTRING_PTR(flag_as_str), RSTRING_LENINT(flag_as_str));
|
317
346
|
} else {
|
318
347
|
platform_already_initialized = true;
|
319
348
|
}
|
@@ -336,7 +365,11 @@ static void init_v8() {
|
|
336
365
|
|
337
366
|
if (current_platform == NULL) {
|
338
367
|
V8::InitializeICU();
|
339
|
-
|
368
|
+
if (single_threaded) {
|
369
|
+
current_platform = platform::NewSingleThreadedDefaultPlatform();
|
370
|
+
} else {
|
371
|
+
current_platform = platform::NewDefaultPlatform();
|
372
|
+
}
|
340
373
|
V8::InitializePlatform(current_platform.get());
|
341
374
|
V8::Initialize();
|
342
375
|
}
|
@@ -381,28 +414,32 @@ static void prepare_result(MaybeLocal<Value> v8res,
|
|
381
414
|
Local<Value> local_value = v8res.ToLocalChecked();
|
382
415
|
if ((local_value->IsObject() || local_value->IsArray()) &&
|
383
416
|
!local_value->IsDate() && !local_value->IsFunction()) {
|
384
|
-
|
385
|
-
context, String::NewFromUtf8Literal(isolate, "JSON"))
|
386
|
-
.ToLocalChecked().As<Object>();
|
387
|
-
|
388
|
-
Local<Function> stringify = JSON->Get(
|
389
|
-
context, v8::String::NewFromUtf8Literal(isolate, "stringify"))
|
390
|
-
.ToLocalChecked().As<Function>();
|
417
|
+
MaybeLocal<v8::Value> ml = context->Global()->Get(
|
418
|
+
context, String::NewFromUtf8Literal(isolate, "JSON"));
|
391
419
|
|
392
|
-
|
393
|
-
const unsigned argc = 1;
|
394
|
-
Local<Value> argv[argc] = { object };
|
395
|
-
MaybeLocal<Value> json = stringify->Call(context, JSON, argc, argv);
|
396
|
-
|
397
|
-
if (json.IsEmpty()) {
|
420
|
+
if (ml.IsEmpty()) { // exception
|
398
421
|
evalRes.executed = false;
|
399
422
|
} else {
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
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
|
+
}
|
404
442
|
}
|
405
|
-
|
406
443
|
} else {
|
407
444
|
Persistent<Value>* persistent = new Persistent<Value>();
|
408
445
|
persistent->Reset(isolate, local_value);
|
@@ -453,7 +490,7 @@ static void prepare_result(MaybeLocal<Value> v8res,
|
|
453
490
|
}
|
454
491
|
}
|
455
492
|
|
456
|
-
void*
|
493
|
+
static void*
|
457
494
|
nogvl_context_eval(void* arg) {
|
458
495
|
|
459
496
|
EvalParams* eval_params = (EvalParams*)arg;
|
@@ -623,11 +660,7 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context,
|
|
623
660
|
v8::String::Utf8Value symbol_name(isolate,
|
624
661
|
Local<Symbol>::Cast(value)->Name());
|
625
662
|
|
626
|
-
VALUE str_symbol =
|
627
|
-
*symbol_name,
|
628
|
-
symbol_name.length(),
|
629
|
-
rb_enc_find("utf-8")
|
630
|
-
);
|
663
|
+
VALUE str_symbol = rb_utf8_str_new(*symbol_name, symbol_name.length());
|
631
664
|
|
632
665
|
return rb_str_intern(str_symbol);
|
633
666
|
}
|
@@ -638,7 +671,7 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context,
|
|
638
671
|
return Qnil;
|
639
672
|
} else {
|
640
673
|
Local<String> rstr = rstr_maybe.ToLocalChecked();
|
641
|
-
return
|
674
|
+
return rb_utf8_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(isolate));
|
642
675
|
}
|
643
676
|
}
|
644
677
|
|
@@ -683,7 +716,7 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context,
|
|
683
716
|
case T_FLOAT:
|
684
717
|
return scope.Escape(Number::New(isolate, NUM2DBL(value)));
|
685
718
|
case T_STRING:
|
686
|
-
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());
|
687
720
|
case T_NIL:
|
688
721
|
return scope.Escape(Null(isolate));
|
689
722
|
case T_TRUE:
|
@@ -711,7 +744,7 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context,
|
|
711
744
|
return scope.Escape(object);
|
712
745
|
case T_SYMBOL:
|
713
746
|
value = rb_funcall(value, rb_intern("to_s"), 0);
|
714
|
-
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());
|
715
748
|
case T_DATA:
|
716
749
|
klass = rb_funcall(value, rb_intern("class"), 0);
|
717
750
|
if (klass == rb_cTime || klass == rb_cDateTime)
|
@@ -786,6 +819,7 @@ create_snapshot_data_blob(const char *embedded_source = nullptr) {
|
|
786
819
|
SnapshotCreator::FunctionCodeHandling::kClear);
|
787
820
|
}
|
788
821
|
|
822
|
+
static
|
789
823
|
StartupData warm_up_snapshot_data_blob(StartupData cold_snapshot_blob,
|
790
824
|
const char *warmup_source) {
|
791
825
|
// Use following steps to create a warmed up snapshot blob from a cold one:
|
@@ -819,21 +853,18 @@ StartupData warm_up_snapshot_data_blob(StartupData cold_snapshot_blob,
|
|
819
853
|
return result;
|
820
854
|
}
|
821
855
|
|
822
|
-
static VALUE rb_snapshot_size(VALUE self
|
856
|
+
static VALUE rb_snapshot_size(VALUE self) {
|
823
857
|
SnapshotInfo* snapshot_info;
|
824
|
-
|
858
|
+
TypedData_Get_Struct(self, SnapshotInfo, &snapshot_type, snapshot_info);
|
825
859
|
|
826
860
|
return INT2NUM(snapshot_info->raw_size);
|
827
861
|
}
|
828
862
|
|
829
863
|
static VALUE rb_snapshot_load(VALUE self, VALUE str) {
|
830
864
|
SnapshotInfo* snapshot_info;
|
831
|
-
|
865
|
+
TypedData_Get_Struct(self, SnapshotInfo, &snapshot_type, snapshot_info);
|
832
866
|
|
833
|
-
|
834
|
-
rb_raise(rb_eArgError, "wrong type argument %" PRIsVALUE " (should be a string)",
|
835
|
-
rb_obj_class(str));
|
836
|
-
}
|
867
|
+
Check_Type(str, T_STRING);
|
837
868
|
|
838
869
|
init_v8();
|
839
870
|
|
@@ -849,21 +880,18 @@ static VALUE rb_snapshot_load(VALUE self, VALUE str) {
|
|
849
880
|
return Qnil;
|
850
881
|
}
|
851
882
|
|
852
|
-
static VALUE rb_snapshot_dump(VALUE self
|
883
|
+
static VALUE rb_snapshot_dump(VALUE self) {
|
853
884
|
SnapshotInfo* snapshot_info;
|
854
|
-
|
885
|
+
TypedData_Get_Struct(self, SnapshotInfo, &snapshot_type, snapshot_info);
|
855
886
|
|
856
887
|
return rb_str_new(snapshot_info->data, snapshot_info->raw_size);
|
857
888
|
}
|
858
889
|
|
859
890
|
static VALUE rb_snapshot_warmup_unsafe(VALUE self, VALUE str) {
|
860
891
|
SnapshotInfo* snapshot_info;
|
861
|
-
|
892
|
+
TypedData_Get_Struct(self, SnapshotInfo, &snapshot_type, snapshot_info);
|
862
893
|
|
863
|
-
|
864
|
-
rb_raise(rb_eArgError, "wrong type argument %" PRIsVALUE " (should be a string)",
|
865
|
-
rb_obj_class(str));
|
866
|
-
}
|
894
|
+
Check_Type(str, T_STRING);
|
867
895
|
|
868
896
|
init_v8();
|
869
897
|
|
@@ -905,13 +933,13 @@ void IsolateInfo::init(SnapshotInfo* snapshot_info) {
|
|
905
933
|
|
906
934
|
static VALUE rb_isolate_init_with_snapshot(VALUE self, VALUE snapshot) {
|
907
935
|
IsolateInfo* isolate_info;
|
908
|
-
|
936
|
+
TypedData_Get_Struct(self, IsolateInfo, &isolate_type, isolate_info);
|
909
937
|
|
910
938
|
init_v8();
|
911
939
|
|
912
940
|
SnapshotInfo* snapshot_info = nullptr;
|
913
941
|
if (!NIL_P(snapshot)) {
|
914
|
-
|
942
|
+
TypedData_Get_Struct(snapshot, SnapshotInfo, &snapshot_type, snapshot_info);
|
915
943
|
}
|
916
944
|
|
917
945
|
isolate_info->init(snapshot_info);
|
@@ -922,7 +950,7 @@ static VALUE rb_isolate_init_with_snapshot(VALUE self, VALUE snapshot) {
|
|
922
950
|
|
923
951
|
static VALUE rb_isolate_idle_notification(VALUE self, VALUE idle_time_in_ms) {
|
924
952
|
IsolateInfo* isolate_info;
|
925
|
-
|
953
|
+
TypedData_Get_Struct(self, IsolateInfo, &isolate_type, isolate_info);
|
926
954
|
|
927
955
|
if (current_platform == NULL) return Qfalse;
|
928
956
|
|
@@ -933,7 +961,7 @@ static VALUE rb_isolate_idle_notification(VALUE self, VALUE idle_time_in_ms) {
|
|
933
961
|
|
934
962
|
static VALUE rb_isolate_low_memory_notification(VALUE self) {
|
935
963
|
IsolateInfo* isolate_info;
|
936
|
-
|
964
|
+
TypedData_Get_Struct(self, IsolateInfo, &isolate_type, isolate_info);
|
937
965
|
|
938
966
|
if (current_platform == NULL) return Qfalse;
|
939
967
|
|
@@ -943,7 +971,7 @@ static VALUE rb_isolate_low_memory_notification(VALUE self) {
|
|
943
971
|
|
944
972
|
static VALUE rb_isolate_pump_message_loop(VALUE self) {
|
945
973
|
IsolateInfo* isolate_info;
|
946
|
-
|
974
|
+
TypedData_Get_Struct(self, IsolateInfo, &isolate_type, isolate_info);
|
947
975
|
|
948
976
|
if (current_platform == NULL) return Qfalse;
|
949
977
|
|
@@ -956,7 +984,7 @@ static VALUE rb_isolate_pump_message_loop(VALUE self) {
|
|
956
984
|
|
957
985
|
static VALUE rb_context_init_unsafe(VALUE self, VALUE isolate, VALUE snap) {
|
958
986
|
ContextInfo* context_info;
|
959
|
-
|
987
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
960
988
|
|
961
989
|
init_v8();
|
962
990
|
|
@@ -967,11 +995,11 @@ static VALUE rb_context_init_unsafe(VALUE self, VALUE isolate, VALUE snap) {
|
|
967
995
|
|
968
996
|
SnapshotInfo *snapshot_info = nullptr;
|
969
997
|
if (!NIL_P(snap) && rb_obj_is_kind_of(snap, rb_cSnapshot)) {
|
970
|
-
|
998
|
+
TypedData_Get_Struct(snap, SnapshotInfo, &snapshot_type, snapshot_info);
|
971
999
|
}
|
972
1000
|
isolate_info->init(snapshot_info);
|
973
1001
|
} else { // given isolate or snapshot
|
974
|
-
|
1002
|
+
TypedData_Get_Struct(isolate, IsolateInfo, &isolate_type, isolate_info);
|
975
1003
|
}
|
976
1004
|
|
977
1005
|
context_info->isolate_info = isolate_info;
|
@@ -1001,7 +1029,7 @@ static VALUE rb_context_init_unsafe(VALUE self, VALUE isolate, VALUE snap) {
|
|
1001
1029
|
static VALUE convert_result_to_ruby(VALUE self /* context */,
|
1002
1030
|
EvalResult& result) {
|
1003
1031
|
ContextInfo *context_info;
|
1004
|
-
|
1032
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
1005
1033
|
|
1006
1034
|
Isolate *isolate = context_info->isolate_info->isolate;
|
1007
1035
|
Persistent<Context> *p_ctx = context_info->context;
|
@@ -1028,7 +1056,7 @@ static VALUE convert_result_to_ruby(VALUE self /* context */,
|
|
1028
1056
|
// a v8 scope, if we do the scope is never cleaned up properly and we leak
|
1029
1057
|
if (!result.parsed) {
|
1030
1058
|
if(TYPE(message) == T_STRING) {
|
1031
|
-
rb_raise(rb_eParseError, "%
|
1059
|
+
rb_raise(rb_eParseError, "%" PRIsVALUE, message);
|
1032
1060
|
} else {
|
1033
1061
|
rb_raise(rb_eParseError, "Unknown JavaScript Error during parse");
|
1034
1062
|
}
|
@@ -1042,8 +1070,7 @@ static VALUE convert_result_to_ruby(VALUE self /* context */,
|
|
1042
1070
|
// If we were terminated or have the memory softlimit flag set
|
1043
1071
|
if (marshal_stack_maxdepth_reached) {
|
1044
1072
|
ruby_exception = rb_eScriptRuntimeError;
|
1045
|
-
|
1046
|
-
message = rb_enc_str_new(msg.c_str(), msg.length(), rb_enc_find("utf-8"));
|
1073
|
+
message = rb_utf8_str_new_literal("Marshal object depth too deep. Script terminated.");
|
1047
1074
|
} else if (result.terminated || mem_softlimit_reached) {
|
1048
1075
|
ruby_exception = mem_softlimit_reached ? rb_eV8OutOfMemoryError : rb_eScriptTerminatedError;
|
1049
1076
|
} else {
|
@@ -1052,15 +1079,17 @@ static VALUE convert_result_to_ruby(VALUE self /* context */,
|
|
1052
1079
|
|
1053
1080
|
// exception report about what happened
|
1054
1081
|
if (TYPE(backtrace) == T_STRING) {
|
1055
|
-
rb_raise(ruby_exception, "%
|
1082
|
+
rb_raise(ruby_exception, "%" PRIsVALUE, backtrace);
|
1056
1083
|
} else if(TYPE(message) == T_STRING) {
|
1057
|
-
rb_raise(ruby_exception, "%
|
1084
|
+
rb_raise(ruby_exception, "%" PRIsVALUE, message);
|
1058
1085
|
} else {
|
1059
1086
|
rb_raise(ruby_exception, "Unknown JavaScript Error during execution");
|
1060
1087
|
}
|
1088
|
+
} else if (rb_obj_is_kind_of(ruby_exception, rb_eException)) {
|
1089
|
+
rb_exc_raise(ruby_exception);
|
1061
1090
|
} else {
|
1062
1091
|
VALUE rb_str = rb_funcall(ruby_exception, rb_intern("to_s"), 0);
|
1063
|
-
rb_raise(CLASS_OF(ruby_exception), "%
|
1092
|
+
rb_raise(CLASS_OF(ruby_exception), "%" PRIsVALUE, rb_str);
|
1064
1093
|
}
|
1065
1094
|
}
|
1066
1095
|
|
@@ -1076,7 +1105,7 @@ static VALUE convert_result_to_ruby(VALUE self /* context */,
|
|
1076
1105
|
|
1077
1106
|
if (result.json) {
|
1078
1107
|
Local<String> rstr = tmp->ToString(p_ctx->Get(isolate)).ToLocalChecked();
|
1079
|
-
VALUE json_string =
|
1108
|
+
VALUE json_string = rb_utf8_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(isolate));
|
1080
1109
|
ret = rb_funcall(rb_mJSON, rb_intern("parse"), 1, json_string);
|
1081
1110
|
} else {
|
1082
1111
|
StackCounter::Reset(isolate);
|
@@ -1102,16 +1131,13 @@ static VALUE rb_context_eval_unsafe(VALUE self, VALUE str, VALUE filename) {
|
|
1102
1131
|
EvalResult eval_result;
|
1103
1132
|
ContextInfo* context_info;
|
1104
1133
|
|
1105
|
-
|
1134
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
1106
1135
|
Isolate* isolate = context_info->isolate_info->isolate;
|
1107
1136
|
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
if(filename != Qnil && TYPE(filename) != T_STRING) {
|
1113
|
-
rb_raise(rb_eArgError, "wrong type argument %" PRIsVALUE " (should be nil or a string)",
|
1114
|
-
rb_obj_class(filename));
|
1137
|
+
Check_Type(str, T_STRING);
|
1138
|
+
|
1139
|
+
if (!NIL_P(filename)) {
|
1140
|
+
Check_Type(filename, T_STRING);
|
1115
1141
|
}
|
1116
1142
|
|
1117
1143
|
{
|
@@ -1120,13 +1146,13 @@ static VALUE rb_context_eval_unsafe(VALUE self, VALUE str, VALUE filename) {
|
|
1120
1146
|
HandleScope handle_scope(isolate);
|
1121
1147
|
|
1122
1148
|
Local<String> eval = String::NewFromUtf8(isolate, RSTRING_PTR(str),
|
1123
|
-
NewStringType::kNormal, (
|
1149
|
+
NewStringType::kNormal, RSTRING_LENINT(str)).ToLocalChecked();
|
1124
1150
|
|
1125
1151
|
Local<String> local_filename;
|
1126
1152
|
|
1127
1153
|
if (filename != Qnil) {
|
1128
1154
|
local_filename = String::NewFromUtf8(isolate, RSTRING_PTR(filename),
|
1129
|
-
NewStringType::kNormal, (
|
1155
|
+
NewStringType::kNormal, RSTRING_LENINT(filename)).ToLocalChecked();
|
1130
1156
|
eval_params.filename = &local_filename;
|
1131
1157
|
} else {
|
1132
1158
|
eval_params.filename = NULL;
|
@@ -1190,7 +1216,7 @@ VALUE rescue_callback(VALUE rdata, VALUE exception) {
|
|
1190
1216
|
return exception;
|
1191
1217
|
}
|
1192
1218
|
|
1193
|
-
void*
|
1219
|
+
static void*
|
1194
1220
|
gvl_ruby_callback(void* data) {
|
1195
1221
|
|
1196
1222
|
FunctionCallbackInfo<Value>* args = (FunctionCallbackInfo<Value>*)data;
|
@@ -1206,7 +1232,7 @@ gvl_ruby_callback(void* data) {
|
|
1206
1232
|
HandleScope scope(args->GetIsolate());
|
1207
1233
|
Local<External> external = Local<External>::Cast(args->Data());
|
1208
1234
|
|
1209
|
-
self =
|
1235
|
+
self = (VALUE)(external->Value());
|
1210
1236
|
callback = rb_iv_get(self, "@callback");
|
1211
1237
|
|
1212
1238
|
parent = rb_iv_get(self, "@parent");
|
@@ -1214,7 +1240,7 @@ gvl_ruby_callback(void* data) {
|
|
1214
1240
|
return NULL;
|
1215
1241
|
}
|
1216
1242
|
|
1217
|
-
|
1243
|
+
TypedData_Get_Struct(parent, ContextInfo, &context_type, context_info);
|
1218
1244
|
|
1219
1245
|
if (length > 0) {
|
1220
1246
|
ruby_args = rb_ary_tmp_new(length);
|
@@ -1243,7 +1269,6 @@ gvl_ruby_callback(void* data) {
|
|
1243
1269
|
args->GetIsolate()->TerminateExecution();
|
1244
1270
|
if (length > 0) {
|
1245
1271
|
rb_ary_clear(ruby_args);
|
1246
|
-
rb_gc_force_recycle(ruby_args);
|
1247
1272
|
}
|
1248
1273
|
return NULL;
|
1249
1274
|
}
|
@@ -1251,8 +1276,8 @@ gvl_ruby_callback(void* data) {
|
|
1251
1276
|
VALUE callback_data_value = (VALUE)&callback_data;
|
1252
1277
|
|
1253
1278
|
// TODO: use rb_vrescue2 in Ruby 2.7 and above
|
1254
|
-
result = rb_rescue2(
|
1255
|
-
|
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);
|
1256
1281
|
|
1257
1282
|
if(callback_data.failed) {
|
1258
1283
|
rb_iv_set(parent, "@current_exception", result);
|
@@ -1266,7 +1291,6 @@ gvl_ruby_callback(void* data) {
|
|
1266
1291
|
|
1267
1292
|
if (length > 0) {
|
1268
1293
|
rb_ary_clear(ruby_args);
|
1269
|
-
rb_gc_force_recycle(ruby_args);
|
1270
1294
|
}
|
1271
1295
|
|
1272
1296
|
if (IsolateData::Get(args->GetIsolate(), IsolateData::DO_TERMINATE)) {
|
@@ -1301,7 +1325,7 @@ static VALUE rb_external_function_notify_v8(VALUE self) {
|
|
1301
1325
|
bool parse_error = false;
|
1302
1326
|
bool attach_error = false;
|
1303
1327
|
|
1304
|
-
|
1328
|
+
TypedData_Get_Struct(parent, ContextInfo, &context_type, context_info);
|
1305
1329
|
Isolate* isolate = context_info->isolate_info->isolate;
|
1306
1330
|
|
1307
1331
|
{
|
@@ -1314,15 +1338,12 @@ static VALUE rb_external_function_notify_v8(VALUE self) {
|
|
1314
1338
|
|
1315
1339
|
Local<String> v8_str =
|
1316
1340
|
String::NewFromUtf8(isolate, RSTRING_PTR(name),
|
1317
|
-
NewStringType::kNormal, (
|
1341
|
+
NewStringType::kNormal, RSTRING_LENINT(name))
|
1318
1342
|
.ToLocalChecked();
|
1319
1343
|
|
1320
|
-
//
|
1321
|
-
|
1322
|
-
|
1323
|
-
*self_copy = self;
|
1324
|
-
|
1325
|
-
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);
|
1326
1347
|
|
1327
1348
|
if (parent_object == Qnil) {
|
1328
1349
|
Maybe<bool> success = context->Global()->Set(
|
@@ -1337,7 +1358,7 @@ static VALUE rb_external_function_notify_v8(VALUE self) {
|
|
1337
1358
|
Local<String> eval =
|
1338
1359
|
String::NewFromUtf8(isolate, RSTRING_PTR(parent_object_eval),
|
1339
1360
|
NewStringType::kNormal,
|
1340
|
-
(
|
1361
|
+
RSTRING_LENINT(parent_object_eval))
|
1341
1362
|
.ToLocalChecked();
|
1342
1363
|
|
1343
1364
|
MaybeLocal<Script> parsed_script = Script::Compile(context, eval);
|
@@ -1379,7 +1400,7 @@ static VALUE rb_external_function_notify_v8(VALUE self) {
|
|
1379
1400
|
|
1380
1401
|
static VALUE rb_context_isolate_mutex(VALUE self) {
|
1381
1402
|
ContextInfo* context_info;
|
1382
|
-
|
1403
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
1383
1404
|
|
1384
1405
|
if (!context_info->isolate_info) {
|
1385
1406
|
rb_raise(rb_eScriptRuntimeError, "Context has no Isolate available anymore");
|
@@ -1435,42 +1456,33 @@ static void free_context_raw(void *arg) {
|
|
1435
1456
|
if (isolate_info) {
|
1436
1457
|
isolate_info->release();
|
1437
1458
|
}
|
1438
|
-
|
1439
|
-
xfree(context_info);
|
1440
1459
|
}
|
1441
1460
|
|
1442
1461
|
static void *free_context_thr(void* arg) {
|
1443
|
-
if (
|
1444
|
-
|
1462
|
+
if (ruby_exiting.load() == 0) {
|
1463
|
+
free_context_raw(arg);
|
1464
|
+
xfree(arg);
|
1445
1465
|
}
|
1446
|
-
if (ruby_exiting) {
|
1447
|
-
return NULL;
|
1448
|
-
}
|
1449
|
-
|
1450
|
-
free_context_raw(arg);
|
1451
|
-
|
1452
|
-
pthread_rwlock_unlock(&exit_lock);
|
1453
|
-
|
1454
1466
|
return NULL;
|
1455
1467
|
}
|
1456
1468
|
|
1457
1469
|
// destroys everything except freeing the ContextInfo struct (see deallocate())
|
1458
1470
|
static void free_context(ContextInfo* context_info) {
|
1459
|
-
|
1460
1471
|
IsolateInfo* isolate_info = context_info->isolate_info;
|
1461
1472
|
|
1462
|
-
ContextInfo* context_info_copy = ALLOC(ContextInfo);
|
1463
|
-
context_info_copy->isolate_info = context_info->isolate_info;
|
1464
|
-
context_info_copy->context = context_info->context;
|
1465
|
-
|
1466
1473
|
if (isolate_info && isolate_info->refs() > 1) {
|
1467
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;
|
1468
1479
|
if (pthread_create(&free_context_thread, thread_attr_p,
|
1469
1480
|
free_context_thr, (void*)context_info_copy)) {
|
1470
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);
|
1471
1483
|
}
|
1472
1484
|
} else {
|
1473
|
-
free_context_raw(
|
1485
|
+
free_context_raw(context_info);
|
1474
1486
|
}
|
1475
1487
|
|
1476
1488
|
context_info->context = NULL;
|
@@ -1489,6 +1501,11 @@ static void mark_isolate(void* data) {
|
|
1489
1501
|
isolate_info->mark();
|
1490
1502
|
}
|
1491
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
|
+
|
1492
1509
|
static void deallocate(void* data) {
|
1493
1510
|
ContextInfo* context_info = (ContextInfo*)data;
|
1494
1511
|
|
@@ -1497,6 +1514,11 @@ static void deallocate(void* data) {
|
|
1497
1514
|
xfree(data);
|
1498
1515
|
}
|
1499
1516
|
|
1517
|
+
static size_t context_memsize(const void *ptr)
|
1518
|
+
{
|
1519
|
+
return sizeof(ContextInfo);
|
1520
|
+
}
|
1521
|
+
|
1500
1522
|
static void mark_context(void* data) {
|
1501
1523
|
ContextInfo* context_info = (ContextInfo*)data;
|
1502
1524
|
if (context_info->isolate_info) {
|
@@ -1504,48 +1526,39 @@ static void mark_context(void* data) {
|
|
1504
1526
|
}
|
1505
1527
|
}
|
1506
1528
|
|
1507
|
-
static void deallocate_external_function(void * data) {
|
1508
|
-
xfree(data);
|
1509
|
-
}
|
1510
|
-
|
1511
1529
|
static void deallocate_snapshot(void * data) {
|
1512
1530
|
SnapshotInfo* snapshot_info = (SnapshotInfo*)data;
|
1513
1531
|
delete[] snapshot_info->data;
|
1514
1532
|
xfree(snapshot_info);
|
1515
1533
|
}
|
1516
1534
|
|
1517
|
-
static
|
1518
|
-
|
1519
|
-
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;
|
1520
1538
|
}
|
1521
1539
|
|
1522
1540
|
static VALUE allocate(VALUE klass) {
|
1523
|
-
ContextInfo* context_info
|
1524
|
-
|
1525
|
-
context_info->context = NULL;
|
1526
|
-
|
1527
|
-
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);
|
1528
1543
|
}
|
1529
1544
|
|
1530
1545
|
static VALUE allocate_snapshot(VALUE klass) {
|
1531
|
-
SnapshotInfo* snapshot_info
|
1532
|
-
snapshot_info->data = NULL;
|
1533
|
-
snapshot_info->raw_size = 0;
|
1546
|
+
SnapshotInfo* snapshot_info;
|
1534
1547
|
|
1535
|
-
return
|
1548
|
+
return TypedData_Make_Struct(klass, SnapshotInfo, &snapshot_type, snapshot_info);
|
1536
1549
|
}
|
1537
1550
|
|
1538
1551
|
static VALUE allocate_isolate(VALUE klass) {
|
1539
1552
|
IsolateInfo* isolate_info = new IsolateInfo();
|
1540
1553
|
|
1541
|
-
return
|
1554
|
+
return TypedData_Wrap_Struct(klass, &isolate_type, isolate_info);
|
1542
1555
|
}
|
1543
1556
|
|
1544
1557
|
static VALUE
|
1545
1558
|
rb_heap_stats(VALUE self) {
|
1546
1559
|
|
1547
1560
|
ContextInfo* context_info;
|
1548
|
-
|
1561
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
1549
1562
|
Isolate* isolate;
|
1550
1563
|
v8::HeapStatistics stats;
|
1551
1564
|
|
@@ -1577,7 +1590,9 @@ rb_heap_stats(VALUE self) {
|
|
1577
1590
|
// https://github.com/bnoordhuis/node-heapdump/blob/master/src/heapdump.cc
|
1578
1591
|
class FileOutputStream : public OutputStream {
|
1579
1592
|
public:
|
1580
|
-
|
1593
|
+
int err;
|
1594
|
+
|
1595
|
+
FileOutputStream(int fd) : fd(fd) { err = 0; }
|
1581
1596
|
|
1582
1597
|
virtual int GetChunkSize() {
|
1583
1598
|
return 65536;
|
@@ -1586,17 +1601,27 @@ class FileOutputStream : public OutputStream {
|
|
1586
1601
|
virtual void EndOfStream() {}
|
1587
1602
|
|
1588
1603
|
virtual WriteResult WriteAsciiChunk(char* data, int size) {
|
1589
|
-
|
1590
|
-
|
1591
|
-
|
1592
|
-
|
1593
|
-
|
1594
|
-
|
1595
|
-
|
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;
|
1596
1621
|
}
|
1597
1622
|
|
1598
1623
|
private:
|
1599
|
-
|
1624
|
+
int fd;
|
1600
1625
|
};
|
1601
1626
|
|
1602
1627
|
|
@@ -1609,13 +1634,11 @@ rb_heap_snapshot(VALUE self, VALUE file) {
|
|
1609
1634
|
|
1610
1635
|
if (!fptr) return Qfalse;
|
1611
1636
|
|
1612
|
-
|
1613
|
-
|
1614
|
-
if (fp == NULL) return Qfalse;
|
1615
|
-
|
1637
|
+
// prepare for unbuffered write(2) below:
|
1638
|
+
rb_funcall(file, rb_intern("flush"), 0);
|
1616
1639
|
|
1617
1640
|
ContextInfo* context_info;
|
1618
|
-
|
1641
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
1619
1642
|
Isolate* isolate;
|
1620
1643
|
isolate = context_info->isolate_info ? context_info->isolate_info->isolate : NULL;
|
1621
1644
|
|
@@ -1629,13 +1652,14 @@ rb_heap_snapshot(VALUE self, VALUE file) {
|
|
1629
1652
|
|
1630
1653
|
const HeapSnapshot* const snap = heap_profiler->TakeHeapSnapshot();
|
1631
1654
|
|
1632
|
-
FileOutputStream stream(
|
1655
|
+
FileOutputStream stream(fptr->fd);
|
1633
1656
|
snap->Serialize(&stream, HeapSnapshot::kJSON);
|
1634
1657
|
|
1635
|
-
fflush(fp);
|
1636
|
-
|
1637
1658
|
const_cast<HeapSnapshot*>(snap)->Delete();
|
1638
1659
|
|
1660
|
+
/* TODO: perhaps rb_sys_fail here */
|
1661
|
+
if (stream.err) return Qfalse;
|
1662
|
+
|
1639
1663
|
return Qtrue;
|
1640
1664
|
}
|
1641
1665
|
|
@@ -1643,7 +1667,7 @@ static VALUE
|
|
1643
1667
|
rb_context_stop(VALUE self) {
|
1644
1668
|
|
1645
1669
|
ContextInfo* context_info;
|
1646
|
-
|
1670
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
1647
1671
|
|
1648
1672
|
Isolate* isolate = context_info->isolate_info->isolate;
|
1649
1673
|
|
@@ -1660,7 +1684,7 @@ static VALUE
|
|
1660
1684
|
rb_context_dispose(VALUE self) {
|
1661
1685
|
|
1662
1686
|
ContextInfo* context_info;
|
1663
|
-
|
1687
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
1664
1688
|
|
1665
1689
|
free_context(context_info);
|
1666
1690
|
|
@@ -1723,7 +1747,7 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) {
|
|
1723
1747
|
FunctionCall call;
|
1724
1748
|
VALUE *call_argv = NULL;
|
1725
1749
|
|
1726
|
-
|
1750
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
1727
1751
|
Isolate* isolate = context_info->isolate_info->isolate;
|
1728
1752
|
|
1729
1753
|
if (argc < 1) {
|
@@ -1731,9 +1755,7 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) {
|
|
1731
1755
|
}
|
1732
1756
|
|
1733
1757
|
VALUE function_name = argv[0];
|
1734
|
-
|
1735
|
-
rb_raise(rb_eTypeError, "first argument should be a String");
|
1736
|
-
}
|
1758
|
+
Check_Type(function_name, T_STRING);
|
1737
1759
|
|
1738
1760
|
char *fname = RSTRING_PTR(function_name);
|
1739
1761
|
if (!fname) {
|
@@ -1784,23 +1806,15 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) {
|
|
1784
1806
|
if (val.IsEmpty() || !val.ToLocalChecked()->IsFunction()) {
|
1785
1807
|
missingFunction = true;
|
1786
1808
|
} else {
|
1787
|
-
|
1788
1809
|
Local<v8::Function> fun = Local<v8::Function>::Cast(val.ToLocalChecked());
|
1810
|
+
VALUE tmp;
|
1789
1811
|
call.fun = fun;
|
1790
|
-
|
1791
|
-
|
1792
|
-
|
1793
|
-
call.argv = (v8::Local<Value> *) malloc(sizeof(void *) * fun_argc);
|
1794
|
-
if (!call.argv) {
|
1795
|
-
return Qnil;
|
1796
|
-
}
|
1797
|
-
for(int i=0; i < fun_argc; i++) {
|
1798
|
-
call.argv[i] = convert_ruby_to_v8(isolate, context, call_argv[i]);
|
1799
|
-
}
|
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]);
|
1800
1815
|
}
|
1801
1816
|
rb_thread_call_without_gvl(nogvl_context_call, &call, unblock_function, &call);
|
1802
|
-
|
1803
|
-
|
1817
|
+
RB_ALLOCV_END(tmp);
|
1804
1818
|
}
|
1805
1819
|
}
|
1806
1820
|
|
@@ -1813,7 +1827,7 @@ static VALUE rb_context_call_unsafe(int argc, VALUE *argv, VALUE self) {
|
|
1813
1827
|
|
1814
1828
|
static VALUE rb_context_create_isolate_value(VALUE self) {
|
1815
1829
|
ContextInfo* context_info;
|
1816
|
-
|
1830
|
+
TypedData_Get_Struct(self, ContextInfo, &context_type, context_info);
|
1817
1831
|
IsolateInfo *isolate_info = context_info->isolate_info;
|
1818
1832
|
|
1819
1833
|
if (!isolate_info) {
|
@@ -1821,18 +1835,13 @@ static VALUE rb_context_create_isolate_value(VALUE self) {
|
|
1821
1835
|
}
|
1822
1836
|
|
1823
1837
|
isolate_info->hold();
|
1824
|
-
return
|
1838
|
+
return TypedData_Wrap_Struct(rb_cIsolate, &isolate_type, isolate_info);
|
1825
1839
|
}
|
1826
1840
|
|
1827
1841
|
static void set_ruby_exiting(VALUE value) {
|
1828
1842
|
(void)value;
|
1829
1843
|
|
1830
|
-
|
1831
|
-
|
1832
|
-
ruby_exiting = true;
|
1833
|
-
if (res == 0) {
|
1834
|
-
pthread_rwlock_unlock(&exit_lock);
|
1835
|
-
}
|
1844
|
+
ruby_exiting.store(1);
|
1836
1845
|
}
|
1837
1846
|
|
1838
1847
|
extern "C" {
|
@@ -1877,7 +1886,6 @@ extern "C" {
|
|
1877
1886
|
rb_define_alloc_func(rb_cIsolate, allocate_isolate);
|
1878
1887
|
|
1879
1888
|
rb_define_private_method(rb_cExternalFunction, "notify_v8", (VALUE(*)(...))&rb_external_function_notify_v8, 0);
|
1880
|
-
rb_define_alloc_func(rb_cExternalFunction, allocate_external_function);
|
1881
1889
|
|
1882
1890
|
rb_define_method(rb_cSnapshot, "size", (VALUE(*)(...))&rb_snapshot_size, 0);
|
1883
1891
|
rb_define_method(rb_cSnapshot, "dump", (VALUE(*)(...))&rb_snapshot_dump, 0);
|
@@ -1899,9 +1907,5 @@ extern "C" {
|
|
1899
1907
|
thread_attr_p = &attr;
|
1900
1908
|
}
|
1901
1909
|
}
|
1902
|
-
auto on_fork_for_child = []() {
|
1903
|
-
exit_lock = PTHREAD_RWLOCK_INITIALIZER;
|
1904
|
-
};
|
1905
|
-
pthread_atfork(nullptr, nullptr, on_fork_for_child);
|
1906
1910
|
}
|
1907
1911
|
}
|