12
12
#include "ngx_js.h"
13
13
14
14
15
+ #define NGX_MAX_JOB_ITERATIONS 0x1000
16
+
17
+
15
18
typedef struct {
16
19
ngx_queue_t labels ;
17
20
} ngx_js_console_t ;
@@ -683,6 +686,42 @@ ngx_njs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external)
683
686
}
684
687
685
688
689
+ static njs_int_t
690
+ ngx_njs_execute_pending_jobs (njs_vm_t * vm , ngx_js_ctx_t * ctx )
691
+ {
692
+ njs_int_t ret , job_count ;
693
+ ngx_str_t exception ;
694
+
695
+ job_count = 0 ;
696
+
697
+ for ( ;; ) {
698
+ ret = njs_vm_execute_pending_job (vm );
699
+ if (ret <= NJS_OK ) {
700
+ if (ret == NJS_ERROR ) {
701
+ ngx_js_exception (vm , & exception );
702
+
703
+ ngx_log_error (NGX_LOG_ERR , ctx -> log , 0 ,
704
+ "js job exception: %V" , & exception );
705
+ return NGX_ERROR ;
706
+ }
707
+
708
+ break ;
709
+ }
710
+
711
+ job_count ++ ;
712
+
713
+ if (job_count >= NGX_MAX_JOB_ITERATIONS ) {
714
+ ngx_log_error (NGX_LOG_ERR , ctx -> log , 0 ,
715
+ "js job queue processing exceeded %ui iterations" ,
716
+ NGX_MAX_JOB_ITERATIONS );
717
+ return NGX_ERROR ;
718
+ }
719
+ }
720
+
721
+ return NGX_OK ;
722
+ }
723
+
724
+
686
725
static ngx_int_t
687
726
ngx_engine_njs_call (ngx_js_ctx_t * ctx , ngx_str_t * fname ,
688
727
njs_opaque_value_t * args , njs_uint_t nargs )
@@ -698,6 +737,11 @@ ngx_engine_njs_call(ngx_js_ctx_t *ctx, ngx_str_t *fname,
698
737
699
738
vm = ctx -> engine -> u .njs .vm ;
700
739
740
+ ret = ngx_njs_execute_pending_jobs (vm , ctx );
741
+ if (ret != NGX_OK ) {
742
+ return NGX_ERROR ;
743
+ }
744
+
701
745
func = njs_vm_function (vm , & name );
702
746
if (func == NULL ) {
703
747
ngx_log_error (NGX_LOG_ERR , ctx -> log , 0 ,
@@ -716,18 +760,27 @@ ngx_engine_njs_call(ngx_js_ctx_t *ctx, ngx_str_t *fname,
716
760
return NGX_ERROR ;
717
761
}
718
762
719
- for ( ;; ) {
720
- ret = njs_vm_execute_pending_job (vm );
721
- if (ret <= NJS_OK ) {
722
- if (ret == NJS_ERROR ) {
723
- ngx_js_exception (vm , & exception );
763
+ ret = ngx_njs_execute_pending_jobs (vm , ctx );
764
+ if (ret != NGX_OK ) {
765
+ return NGX_ERROR ;
766
+ }
724
767
725
- ngx_log_error (NGX_LOG_ERR , ctx -> log , 0 ,
726
- "js job exception: %V" , & exception );
727
- return NGX_ERROR ;
728
- }
768
+ njs_value_t * val = njs_value_arg (& ctx -> retval );
769
+ if (njs_value_is_promise (val )) {
770
+ njs_promise_type_t state = njs_promise_state (val );
729
771
730
- break ;
772
+ if (state == NJS_PROMISE_FULFILL ) {
773
+ njs_value_assign (val , njs_promise_result (val ));
774
+
775
+ } else if (state == NJS_PROMISE_REJECTED ) {
776
+ njs_vm_throw (vm , njs_promise_result (val ));
777
+
778
+ } else if (state == NJS_PROMISE_PENDING &&
779
+ njs_rbtree_is_empty (& ctx -> waiting_events ))
780
+ {
781
+ ngx_log_error (NGX_LOG_ERR , ctx -> log , 0 ,
782
+ "js promise pending, no jobs, no waiting_events" );
783
+ return NGX_ERROR ;
731
784
}
732
785
}
733
786
@@ -741,6 +794,7 @@ ngx_engine_njs_external(ngx_engine_t *engine)
741
794
return njs_vm_external_ptr (engine -> u .njs .vm );
742
795
}
743
796
797
+
744
798
static ngx_int_t
745
799
ngx_engine_njs_pending (ngx_engine_t * e )
746
800
{
@@ -754,8 +808,9 @@ ngx_engine_njs_string(ngx_engine_t *e, njs_opaque_value_t *value,
754
808
{
755
809
ngx_int_t rc ;
756
810
njs_str_t s ;
811
+ njs_value_t * val = njs_value_arg (value );
757
812
758
- rc = ngx_js_string (e -> u .njs .vm , njs_value_arg ( value ) , & s );
813
+ rc = ngx_js_string (e -> u .njs .vm , val , & s );
759
814
760
815
str -> data = s .start ;
761
816
str -> len = s .length ;
@@ -875,38 +930,59 @@ ngx_engine_qjs_compile(ngx_js_loc_conf_t *conf, ngx_log_t *log, u_char *start,
875
930
876
931
877
932
static JSValue
878
- js_std_await (JSContext * ctx , JSValue obj )
933
+ ngx_qjs_await (JSContext * ctx , JSValue obj )
879
934
{
880
- int state , err ;
881
- JSValue ret ;
882
- JSContext * ctx1 ;
935
+ int rc , job_count ;
936
+ JSValue ret ;
937
+ JSRuntime * rt ;
938
+ ngx_js_ctx_t * js_ctx ;
939
+
940
+ rt = JS_GetRuntime (ctx );
941
+ js_ctx = ngx_qjs_external_ctx (ctx , JS_GetContextOpaque (ctx ));
942
+
943
+ job_count = 0 ;
944
+
945
+ for ( ;; ) {
946
+ rc = JS_ExecutePendingJob (rt , NULL );
947
+ if (rc <= 0 ) {
948
+ if (rc == -1 ) {
949
+ JS_FreeValue (ctx , obj );
950
+ return JS_EXCEPTION ;
951
+ }
952
+ break ;
953
+ }
883
954
884
- for (;;) {
885
- state = JS_PromiseState (ctx , obj );
955
+ job_count ++ ;
956
+
957
+ if (job_count >= NGX_MAX_JOB_ITERATIONS ) {
958
+ JS_FreeValue (ctx , obj );
959
+ return JS_ThrowInternalError (ctx , "js job queue processing "
960
+ "exceeded %u iterations" ,
961
+ NGX_MAX_JOB_ITERATIONS );
962
+ }
963
+ }
964
+
965
+ if (JS_IsObject (obj )) {
966
+ JSPromiseStateEnum state = JS_PromiseState (ctx , obj );
886
967
if (state == JS_PROMISE_FULFILLED ) {
887
968
ret = JS_PromiseResult (ctx , obj );
888
969
JS_FreeValue (ctx , obj );
889
- break ;
890
-
970
+ return ret ;
891
971
} else if (state == JS_PROMISE_REJECTED ) {
892
- ret = JS_Throw ( ctx , JS_PromiseResult (ctx , obj ) );
972
+ JSValue rejection = JS_PromiseResult (ctx , obj );
893
973
JS_FreeValue (ctx , obj );
894
- break ;
895
-
974
+ return JS_Throw (ctx , rejection );
896
975
} else if (state == JS_PROMISE_PENDING ) {
897
- err = JS_ExecutePendingJob (JS_GetRuntime (ctx ), & ctx1 );
898
- if (err < 0 ) {
899
- /* js_std_dump_error(ctx1); */
976
+ if (js_ctx && njs_rbtree_is_empty (& js_ctx -> waiting_events )) {
977
+ JS_FreeValue (ctx , obj );
978
+ return JS_ThrowInternalError (ctx , "js promise pending, "
979
+ "no jobs, no waiting_events" );
900
980
}
901
-
902
- } else {
903
- /* not a promise */
904
- ret = obj ;
905
- break ;
981
+ return obj ;
906
982
}
907
983
}
908
984
909
- return ret ;
985
+ return obj ;
910
986
}
911
987
912
988
@@ -1000,12 +1076,13 @@ ngx_qjs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external)
1000
1076
goto destroy ;
1001
1077
}
1002
1078
1003
- rv = js_std_await (cx , rv );
1079
+ rv = ngx_qjs_await (cx , rv );
1004
1080
if (JS_IsException (rv )) {
1005
1081
ngx_qjs_exception (engine , & exception );
1006
1082
1007
1083
ngx_log_error (NGX_LOG_ERR , ctx -> log , 0 , "js eval exception: %V" ,
1008
1084
& exception );
1085
+
1009
1086
goto destroy ;
1010
1087
}
1011
1088
@@ -1023,6 +1100,43 @@ ngx_qjs_clone(ngx_js_ctx_t *ctx, ngx_js_loc_conf_t *cf, void *external)
1023
1100
}
1024
1101
1025
1102
1103
+ static ngx_int_t
1104
+ ngx_qjs_execute_pending_jobs (ngx_js_ctx_t * ctx , JSRuntime * rt )
1105
+ {
1106
+ int rc , job_count ;
1107
+ ngx_str_t exception ;
1108
+
1109
+ job_count = 0 ;
1110
+
1111
+ for ( ;; ) {
1112
+ rc = JS_ExecutePendingJob (rt , NULL );
1113
+ if (rc <= 0 ) {
1114
+ if (rc == -1 ) {
1115
+ ngx_qjs_exception (ctx -> engine , & exception );
1116
+
1117
+ ngx_log_error (NGX_LOG_ERR , ctx -> log , 0 ,
1118
+ "js job exception: %V" , & exception );
1119
+
1120
+ return NGX_ERROR ;
1121
+ }
1122
+
1123
+ break ;
1124
+ }
1125
+
1126
+ job_count ++ ;
1127
+
1128
+ if (job_count >= NGX_MAX_JOB_ITERATIONS ) {
1129
+ ngx_log_error (NGX_LOG_ERR , ctx -> log , 0 ,
1130
+ "js job queue processing exceeded %ui iterations" ,
1131
+ NGX_MAX_JOB_ITERATIONS );
1132
+ return NGX_ERROR ;
1133
+ }
1134
+ }
1135
+
1136
+ return NGX_OK ;
1137
+ }
1138
+
1139
+
1026
1140
static ngx_int_t
1027
1141
ngx_engine_qjs_call (ngx_js_ctx_t * ctx , ngx_str_t * fname ,
1028
1142
njs_opaque_value_t * args , njs_uint_t nargs )
@@ -1031,9 +1145,15 @@ ngx_engine_qjs_call(ngx_js_ctx_t *ctx, ngx_str_t *fname,
1031
1145
JSValue fn , val ;
1032
1146
ngx_str_t exception ;
1033
1147
JSRuntime * rt ;
1034
- JSContext * cx , * cx1 ;
1148
+ JSContext * cx ;
1035
1149
1036
1150
cx = ctx -> engine -> u .qjs .ctx ;
1151
+ rt = JS_GetRuntime (cx );
1152
+
1153
+ rc = ngx_qjs_execute_pending_jobs (ctx , rt );
1154
+ if (rc != NGX_OK ) {
1155
+ return NGX_ERROR ;
1156
+ }
1037
1157
1038
1158
fn = ngx_qjs_value (cx , fname );
1039
1159
if (!JS_IsFunction (cx , fn )) {
@@ -1058,21 +1178,31 @@ ngx_engine_qjs_call(ngx_js_ctx_t *ctx, ngx_str_t *fname,
1058
1178
JS_FreeValue (cx , ngx_qjs_arg (ctx -> retval ));
1059
1179
ngx_qjs_arg (ctx -> retval ) = val ;
1060
1180
1061
- rt = JS_GetRuntime (cx );
1181
+ rc = ngx_qjs_execute_pending_jobs (ctx , rt );
1182
+ if (rc != NGX_OK ) {
1183
+ return NGX_ERROR ;
1184
+ }
1062
1185
1063
- for ( ;; ) {
1064
- rc = JS_ExecutePendingJob (rt , & cx1 );
1065
- if (rc <= 0 ) {
1066
- if (rc == -1 ) {
1067
- ngx_qjs_exception (ctx -> engine , & exception );
1186
+ JSValue retval = ngx_qjs_arg (ctx -> retval );
1187
+ if (JS_IsObject (retval )) {
1188
+ JSPromiseStateEnum state = JS_PromiseState (cx , retval );
1068
1189
1069
- ngx_log_error (NGX_LOG_ERR , ctx -> log , 0 ,
1070
- "js job exception: %V" , & exception );
1190
+ if (state == JS_PROMISE_FULFILLED ) {
1191
+ JSValue result = JS_PromiseResult (cx , retval );
1192
+ JS_FreeValue (cx , ngx_qjs_arg (ctx -> retval ));
1193
+ ngx_qjs_arg (ctx -> retval ) = result ;
1071
1194
1072
- return NGX_ERROR ;
1073
- }
1195
+ } else if (state == JS_PROMISE_REJECTED ) {
1196
+ JSValue rejection = JS_PromiseResult (cx , retval );
1197
+ JS_FreeValue (cx , ngx_qjs_arg (ctx -> retval ));
1198
+ ngx_qjs_arg (ctx -> retval ) = JS_Throw (cx , rejection );
1074
1199
1075
- break ;
1200
+ } else if (state == JS_PROMISE_PENDING &&
1201
+ njs_rbtree_is_empty (& ctx -> waiting_events ))
1202
+ {
1203
+ ngx_log_error (NGX_LOG_ERR , ctx -> log , 0 ,
1204
+ "js promise pending, no jobs, no waiting_events" );
1205
+ return NGX_ERROR ;
1076
1206
}
1077
1207
}
1078
1208
@@ -1098,7 +1228,9 @@ static ngx_int_t
1098
1228
ngx_engine_qjs_string (ngx_engine_t * e , njs_opaque_value_t * value ,
1099
1229
ngx_str_t * str )
1100
1230
{
1101
- return ngx_qjs_dump_obj (e , ngx_qjs_arg (* value ), str );
1231
+ JSValue val = ngx_qjs_arg (* value );
1232
+
1233
+ return ngx_qjs_dump_obj (e , val , str );
1102
1234
}
1103
1235
1104
1236
@@ -1386,7 +1518,6 @@ ngx_qjs_call(JSContext *cx, JSValue fn, JSValue *argv, int argc)
1386
1518
JSValue ret ;
1387
1519
ngx_str_t exception ;
1388
1520
JSRuntime * rt ;
1389
- JSContext * cx1 ;
1390
1521
ngx_js_ctx_t * ctx ;
1391
1522
1392
1523
ctx = ngx_qjs_external_ctx (cx , JS_GetContextOpaque (cx ));
@@ -1406,7 +1537,7 @@ ngx_qjs_call(JSContext *cx, JSValue fn, JSValue *argv, int argc)
1406
1537
rt = JS_GetRuntime (cx );
1407
1538
1408
1539
for ( ;; ) {
1409
- rc = JS_ExecutePendingJob (rt , & cx1 );
1540
+ rc = JS_ExecutePendingJob (rt , NULL );
1410
1541
if (rc <= 0 ) {
1411
1542
if (rc == -1 ) {
1412
1543
ngx_qjs_exception (ctx -> engine , & exception );
0 commit comments