Advertisement
Guest User

Untitled

a guest
Jul 21st, 2019
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 82.50 KB | None | 0 0
  1. # HG changeset patch
  2. # User Dmitry Volyntsev <xeioex@nginx.com>
  3. # Date 1562352328 -10800
  4. # Fri Jul 05 21:45:28 2019 +0300
  5. # Node ID 23ac9dad4973023117aaa36331645ebb415531e0
  6. # Parent b946c107396835be316b192154feb9bb7efaa175
  7. Refactored working with non-primitive types.
  8.  
  9. Traps mechanism is remove.
  10.  
  11. diff --git a/njs/njs.c b/njs/njs.c
  12. --- a/njs/njs.c
  13. +++ b/njs/njs.c
  14. @@ -984,8 +984,6 @@ again:
  15.  
  16. /* value evaluation threw an exception. */
  17.  
  18. - vm->top_frame->trap_tries = 0;
  19. -
  20. src = &vm->retval;
  21. goto again;
  22. }
  23. @@ -1006,6 +1004,10 @@ njs_vm_retval_string(njs_vm_t *vm, nxt_s
  24. njs_vm_init(vm);
  25. }
  26.  
  27. + if (vm->current == NULL) {
  28. + vm->current = (u_char *) njs_stop;
  29. + }
  30. +
  31. return njs_vm_value_string(vm, dst, &vm->retval);
  32. }
  33.  
  34. @@ -1019,6 +1021,10 @@ njs_vm_retval_dump(njs_vm_t *vm, nxt_str
  35. njs_vm_init(vm);
  36. }
  37.  
  38. + if (vm->current == NULL) {
  39. + vm->current = (u_char *) njs_stop;
  40. + }
  41. +
  42. return njs_vm_value_dump(vm, dst, &vm->retval, 0, 1);
  43. }
  44.  
  45. diff --git a/njs/njs_array.c b/njs/njs_array.c
  46. --- a/njs/njs_array.c
  47. +++ b/njs/njs_array.c
  48. @@ -528,10 +528,7 @@ njs_array_prototype_slice(njs_vm_t *vm,
  49. ret = njs_value_property(vm, &args[0], &njs_string_length, &slice->length,
  50. 0);
  51.  
  52. - if (nxt_slow_path(ret == NXT_ERROR
  53. - || ret == NJS_TRAP
  54. - || ret == NJS_APPLIED))
  55. - {
  56. + if (nxt_slow_path(ret == NXT_ERROR || ret == NJS_APPLIED)) {
  57. return ret;
  58. }
  59.  
  60. @@ -544,13 +541,16 @@ njs_array_prototype_slice_continuation(n
  61. nxt_uint_t nargs, njs_index_t unused)
  62. {
  63. int64_t start, end, length;
  64. + njs_ret_t ret;
  65. njs_array_slice_t *slice;
  66.  
  67. slice = njs_vm_continuation(vm);
  68.  
  69. if (nxt_slow_path(!njs_is_primitive(&slice->length))) {
  70. - njs_vm_trap_value(vm, &slice->length);
  71. - return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
  72. + ret = njs_value_to_numeric(vm, &slice->length, &slice->length);
  73. + if (ret != NXT_OK) {
  74. + return ret;
  75. + }
  76. }
  77.  
  78. start = njs_primitive_value_to_integer(njs_arg(args, nargs, 1));
  79. @@ -958,7 +958,7 @@ njs_array_prototype_reverse(njs_vm_t *vm
  80.  
  81. static njs_ret_t
  82. njs_array_prototype_to_string(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
  83. - njs_index_t retval)
  84. + njs_index_t unused)
  85. {
  86. njs_object_prop_t *prop;
  87. nxt_lvlhsh_query_t lhq;
  88. @@ -970,12 +970,12 @@ njs_array_prototype_to_string(njs_vm_t *
  89. prop = njs_object_property(vm, njs_object(&args[0]), &lhq);
  90.  
  91. if (nxt_fast_path(prop != NULL && njs_is_function(&prop->value))) {
  92. - return njs_function_replace(vm, njs_function(&prop->value),
  93. - args, nargs, retval);
  94. + return njs_function_call(vm, njs_function(&prop->value), args,
  95. + nargs, (njs_index_t) &vm->retval);
  96. }
  97. }
  98.  
  99. - return njs_object_prototype_to_string(vm, args, nargs, retval);
  100. + return njs_object_prototype_to_string(vm, args, nargs, unused);
  101. }
  102.  
  103.  
  104. @@ -1063,6 +1063,7 @@ njs_array_prototype_join_continuation(nj
  105. u_char *p;
  106. size_t size, length, mask;
  107. uint32_t max;
  108. + njs_ret_t ret;
  109. nxt_uint_t i, n;
  110. njs_array_t *array;
  111. njs_value_t *value, *values;
  112. @@ -1089,9 +1090,10 @@ njs_array_prototype_join_continuation(nj
  113. value = &values[n++];
  114.  
  115. if (!njs_is_string(value)) {
  116. - njs_vm_trap_value(vm, value);
  117. -
  118. - return njs_trap(vm, NJS_TRAP_STRING_ARG);
  119. + ret = njs_value_to_string(vm, value, value);
  120. + if (ret != NXT_OK) {
  121. + return ret;
  122. + }
  123. }
  124. }
  125.  
  126. @@ -1438,10 +1440,7 @@ njs_array_prototype_fill(njs_vm_t *vm, n
  127. ret = njs_value_property(vm, this, &njs_string_length, &fill->length,
  128. 0);
  129.  
  130. - if (nxt_slow_path(ret == NXT_ERROR
  131. - || ret == NJS_TRAP
  132. - || ret == NJS_APPLIED))
  133. - {
  134. + if (nxt_slow_path(ret == NXT_ERROR || ret == NJS_APPLIED)) {
  135. return ret;
  136. }
  137. }
  138. @@ -1455,6 +1454,7 @@ njs_array_prototype_fill_continuation(nj
  139. nxt_uint_t nargs, njs_index_t unused)
  140. {
  141. nxt_int_t i, start, end, length;
  142. + njs_ret_t ret;
  143. njs_array_t *array;
  144. njs_object_t *object;
  145. njs_array_fill_t *fill;
  146. @@ -1484,8 +1484,10 @@ njs_array_prototype_fill_continuation(nj
  147. } else {
  148.  
  149. if (nxt_slow_path(!njs_is_primitive(&fill->length))) {
  150. - njs_vm_trap_value(vm, &fill->length);
  151. - return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
  152. + ret = njs_value_to_numeric(vm, &fill->length, &fill->length);
  153. + if (ret != NXT_OK) {
  154. + return ret;
  155. + }
  156. }
  157.  
  158. length = njs_primitive_value_to_length(&fill->length);
  159. @@ -2198,9 +2200,10 @@ njs_array_string_sort(njs_vm_t *vm, njs_
  160.  
  161. for (i = 1; i < nargs; i++) {
  162. if (!njs_is_string(&args[i])) {
  163. - njs_vm_trap_value(vm, &args[i]);
  164. -
  165. - return njs_trap(vm, NJS_TRAP_STRING_ARG);
  166. + ret = njs_value_to_string(vm, &args[i], &args[i]);
  167. + if (ret != NXT_OK) {
  168. + return ret;
  169. + }
  170. }
  171. }
  172.  
  173. diff --git a/njs/njs_date.c b/njs/njs_date.c
  174. --- a/njs/njs_date.c
  175. +++ b/njs/njs_date.c
  176. @@ -73,6 +73,7 @@ njs_date_constructor(njs_vm_t *vm, njs_v
  177. {
  178. double num, time;
  179. int64_t values[8];
  180. + njs_ret_t ret;
  181. nxt_uint_t i, n;
  182. njs_date_t *date;
  183. struct tm tm;
  184. @@ -85,11 +86,14 @@ njs_date_constructor(njs_vm_t *vm, njs_v
  185. } else if (nargs == 2) {
  186. if (njs_is_object(&args[1])) {
  187. if (!njs_is_date(&args[1])) {
  188. - njs_vm_trap_value(vm, &args[1]);
  189. -
  190. - return njs_trap(vm, NJS_TRAP_PRIMITIVE_ARG);
  191. + ret = njs_value_to_primitive(vm, &args[1], &args[1], 0);
  192. + if (ret != NXT_OK) {
  193. + return ret;
  194. + }
  195. }
  196. -
  197. + }
  198. +
  199. + if (njs_is_date(&args[1])) {
  200. time = njs_date(&args[1])->time;
  201.  
  202. } else if (njs_is_string(&args[1])) {
  203. @@ -108,9 +112,10 @@ njs_date_constructor(njs_vm_t *vm, njs_v
  204.  
  205. for (i = 1; i < n; i++) {
  206. if (!njs_is_numeric(&args[i])) {
  207. - njs_vm_trap_value(vm, &args[i]);
  208. -
  209. - return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
  210. + ret = njs_value_to_numeric(vm, &args[i], &args[i]);
  211. + if (ret != NXT_OK) {
  212. + return ret;
  213. + }
  214. }
  215.  
  216. num = njs_number(&args[i]);
  217. @@ -171,6 +176,7 @@ njs_date_utc(njs_vm_t *vm, njs_value_t *
  218. {
  219. double num, time;
  220. struct tm tm;
  221. + njs_ret_t ret;
  222. nxt_uint_t i, n;
  223. int32_t values[8];
  224.  
  225. @@ -183,9 +189,10 @@ njs_date_utc(njs_vm_t *vm, njs_value_t *
  226.  
  227. for (i = 1; i < n; i++) {
  228. if (!njs_is_numeric(&args[i])) {
  229. - njs_vm_trap_value(vm, &args[i]);
  230. -
  231. - return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
  232. + ret = njs_value_to_numeric(vm, &args[i], &args[i]);
  233. + if (ret != NXT_OK) {
  234. + return ret;
  235. + }
  236. }
  237.  
  238. num = njs_number(&args[i]);
  239. @@ -1902,8 +1909,8 @@ njs_date_prototype_to_json(njs_vm_t *vm,
  240. prop = njs_object_property(vm, njs_object(&args[0]), &lhq);
  241.  
  242. if (nxt_fast_path(prop != NULL && njs_is_function(&prop->value))) {
  243. - return njs_function_replace(vm, njs_function(&prop->value),
  244. - args, nargs, retval);
  245. + return njs_function_call(vm, njs_function(&prop->value), args,
  246. + nargs, (njs_index_t) &vm->retval);
  247. }
  248. }
  249.  
  250. diff --git a/njs/njs_function.c b/njs/njs_function.c
  251. --- a/njs/njs_function.c
  252. +++ b/njs/njs_function.c
  253. @@ -473,6 +473,48 @@ njs_function_frame_alloc(njs_vm_t *vm, s
  254.  
  255.  
  256. njs_ret_t
  257. +njs_function_call(njs_vm_t *vm, njs_function_t *function, njs_value_t *args,
  258. + nxt_uint_t nargs, njs_index_t retval)
  259. +{
  260. + u_char *return_address;
  261. + njs_ret_t ret;
  262. + njs_native_frame_t *frame;
  263. + njs_continuation_t *cont;
  264. +
  265. + ret = njs_function_frame(vm, function, &args[0], &args[1], nargs - 1, 0, 0);
  266. + if (nxt_slow_path(ret != NXT_OK)) {
  267. + return ret;
  268. + }
  269. +
  270. + frame = vm->top_frame;
  271. + frame->call = 1;
  272. +
  273. + return_address = vm->current;
  274. +
  275. + if (function->native) {
  276. +
  277. + if (function->continuation_size != 0) {
  278. + cont = njs_vm_continuation(vm);
  279. + cont->return_address = return_address;
  280. + }
  281. +
  282. + ret = njs_function_native_call(vm, function->u.native, frame->arguments,
  283. + function->args_types, frame->nargs,
  284. + (njs_index_t) retval, return_address);
  285. +
  286. + } else {
  287. + ret = njs_function_lambda_call(vm, retval, return_address);
  288. +
  289. + if (nxt_fast_path(ret == NJS_APPLIED)) {
  290. + ret = njs_vmcode_run(vm);
  291. + }
  292. + }
  293. +
  294. + return ret;
  295. +}
  296. +
  297. +
  298. +njs_ret_t
  299. njs_function_lambda_call(njs_vm_t *vm, njs_index_t retval,
  300. u_char *return_address)
  301. {
  302. @@ -636,8 +678,8 @@ static njs_ret_t
  303. njs_normalize_args(njs_vm_t *vm, njs_value_t *args, uint8_t *args_types,
  304. nxt_uint_t nargs)
  305. {
  306. + njs_ret_t ret;
  307. nxt_uint_t n;
  308. - njs_trap_t trap;
  309.  
  310. n = nxt_min(nargs, NJS_ARGS_TYPES_MAX);
  311.  
  312. @@ -655,43 +697,47 @@ njs_normalize_args(njs_vm_t *vm, njs_val
  313.  
  314. case NJS_STRING_ARG:
  315.  
  316. - if (njs_is_string(args)) {
  317. - break;
  318. + if (!njs_is_string(args)) {
  319. + ret = njs_value_to_string(vm, args, args);
  320. + if (ret != NXT_OK) {
  321. + return ret;
  322. + }
  323. }
  324.  
  325. - trap = NJS_TRAP_STRING_ARG;
  326. - goto trap;
  327. + break;
  328.  
  329. case NJS_NUMBER_ARG:
  330.  
  331. - if (njs_is_numeric(args)) {
  332. - break;
  333. + if (!njs_is_numeric(args)) {
  334. + ret = njs_value_to_numeric(vm, args, args);
  335. + if (ret != NXT_OK) {
  336. + return ret;
  337. + }
  338. }
  339.  
  340. - trap = NJS_TRAP_NUMBER_ARG;
  341. - goto trap;
  342. + break;
  343.  
  344. case NJS_INTEGER_ARG:
  345.  
  346. - if (njs_is_numeric(args)) {
  347. + if (!njs_is_numeric(args)) {
  348. + ret = njs_value_to_numeric(vm, args, args);
  349. + if (ret != NXT_OK) {
  350. + return ret;
  351. + }
  352. + }
  353.  
  354. - /* Numbers are truncated to fit in 32-bit integers. */
  355. + /* Numbers are truncated to fit in 32-bit integers. */
  356.  
  357. - if (isnan(njs_number(args))) {
  358. - njs_number(args) = 0;
  359. -
  360. - } else if (njs_number(args) > 2147483647.0) {
  361. + if (!isnan(njs_number(args))) {
  362. + if (njs_number(args) > 2147483647.0) {
  363. njs_number(args) = 2147483647.0;
  364.  
  365. } else if (njs_number(args) < -2147483648.0) {
  366. njs_number(args) = -2147483648.0;
  367. }
  368. -
  369. - break;
  370. }
  371.  
  372. - trap = NJS_TRAP_NUMBER_ARG;
  373. - goto trap;
  374. + break;
  375.  
  376. case NJS_FUNCTION_ARG:
  377.  
  378. @@ -701,8 +747,10 @@ njs_normalize_args(njs_vm_t *vm, njs_val
  379. break;
  380.  
  381. default:
  382. - trap = NJS_TRAP_STRING_ARG;
  383. - goto trap;
  384. + ret = njs_value_to_string(vm, args, args);
  385. + if (ret != NXT_OK) {
  386. + return ret;
  387. + }
  388. }
  389.  
  390. break;
  391. @@ -716,8 +764,10 @@ njs_normalize_args(njs_vm_t *vm, njs_val
  392. break;
  393.  
  394. default:
  395. - trap = NJS_TRAP_STRING_ARG;
  396. - goto trap;
  397. + ret = njs_value_to_string(vm, args, args);
  398. + if (ret != NXT_OK) {
  399. + return ret;
  400. + }
  401. }
  402.  
  403. break;
  404. @@ -751,12 +801,6 @@ njs_normalize_args(njs_vm_t *vm, njs_val
  405.  
  406. return NJS_OK;
  407.  
  408. -trap:
  409. -
  410. - njs_vm_trap_value(vm, args);
  411. -
  412. - return njs_trap(vm, trap);
  413. -
  414. type_error:
  415.  
  416. njs_type_error(vm, "cannot convert %s to %s", njs_type_string(args->type),
  417. diff --git a/njs/njs_function.h b/njs/njs_function.h
  418. --- a/njs/njs_function.h
  419. +++ b/njs/njs_function.h
  420. @@ -74,11 +74,6 @@ typedef struct {
  421. #define NJS_CONTINUATION_SIZE njs_continuation_size(njs_continuation_t)
  422.  
  423.  
  424. -#define njs_vm_trap_value(vm, val) \
  425. - (vm)->top_frame->trap_scratch.data.u.value = val
  426. -
  427. -
  428. -
  429. typedef struct njs_exception_s njs_exception_t;
  430.  
  431. struct njs_exception_s {
  432. @@ -92,10 +87,6 @@ struct njs_exception_s {
  433.  
  434.  
  435. struct njs_native_frame_s {
  436. - njs_value_t trap_scratch;
  437. - njs_value_t trap_values[2];
  438. - u_char *trap_restart;
  439. -
  440. u_char *free;
  441.  
  442. njs_function_t *function;
  443. @@ -118,14 +109,7 @@ struct njs_native_frame_s {
  444. /* Skip the Function.call() and Function.apply() methods frames. */
  445. uint8_t skip; /* 1 bit */
  446.  
  447. - /* A number of trap tries, it can be no more than three. */
  448. - uint8_t trap_tries; /* 2 bits */
  449. -
  450. - /*
  451. - * The first operand in trap is reference to original value,
  452. - * it is used to increment or decrement this value.
  453. - */
  454. - uint8_t trap_reference; /* 1 bit */
  455. + uint8_t call; /* 1 bit */
  456. };
  457.  
  458.  
  459. @@ -168,6 +152,8 @@ njs_ret_t njs_function_lambda_frame(njs_
  460. njs_ret_t njs_function_activate(njs_vm_t *vm, njs_function_t *function,
  461. const njs_value_t *this, const njs_value_t *args, nxt_uint_t nargs,
  462. njs_index_t retval, size_t advance);
  463. +njs_ret_t njs_function_call(njs_vm_t *vm, njs_function_t *function,
  464. + njs_value_t *args, nxt_uint_t nargs, njs_index_t retval);
  465. njs_ret_t njs_function_lambda_call(njs_vm_t *vm, njs_index_t retval,
  466. u_char *return_address);
  467. njs_ret_t njs_function_native_call(njs_vm_t *vm, njs_function_native_t native,
  468. @@ -215,36 +201,6 @@ njs_function_apply(njs_vm_t *vm, njs_fun
  469. }
  470.  
  471.  
  472. -/*
  473. - * Replaces the current function with a new one.
  474. - * Can only be used for continuation functions
  475. - * (data.u.function.continuation_size > 0).
  476. - */
  477. -nxt_inline njs_ret_t
  478. -njs_function_replace(njs_vm_t *vm, njs_function_t *function,
  479. - const njs_value_t *args, nxt_uint_t nargs, njs_index_t retval)
  480. -{
  481. - nxt_int_t ret;
  482. -
  483. - ret = njs_function_apply(vm, function, args, nargs, retval);
  484. - if (nxt_slow_path(ret == NXT_ERROR)) {
  485. - return ret;
  486. - }
  487. -
  488. - /*
  489. - * 1) njs_function_apply() allocs a new function frame,
  490. - * in order to preserve the retval of a new function and ignore
  491. - * retval of the current function during stack unwinding
  492. - * skip flag is needed.
  493. - * 2) it is also needed for correct callee arguments update in
  494. - * njs_function_native_call() see "Object((new Date(0)).toJSON())".
  495. - */
  496. - vm->top_frame->previous->skip = 1;
  497. -
  498. - return NJS_APPLIED;
  499. -}
  500. -
  501. -
  502. nxt_inline njs_native_frame_t *
  503. njs_function_previous_frame(njs_native_frame_t *frame)
  504. {
  505. diff --git a/njs/njs_math.c b/njs/njs_math.c
  506. --- a/njs/njs_math.c
  507. +++ b/njs/njs_math.c
  508. @@ -359,13 +359,15 @@ njs_object_math_hypot(njs_vm_t *vm, njs_
  509. njs_index_t unused)
  510. {
  511. double num;
  512. + njs_ret_t ret;
  513. nxt_uint_t i;
  514.  
  515. for (i = 1; i < nargs; i++) {
  516. if (!njs_is_numeric(&args[i])) {
  517. - njs_vm_trap_value(vm, &args[i]);
  518. -
  519. - return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
  520. + ret = njs_value_to_numeric(vm, &args[i], &args[i]);
  521. + if (ret != NXT_OK) {
  522. + return ret;
  523. + }
  524. }
  525. }
  526.  
  527. @@ -498,6 +500,7 @@ njs_object_math_max(njs_vm_t *vm, njs_va
  528. njs_index_t unused)
  529. {
  530. double num;
  531. + njs_ret_t ret;
  532. nxt_uint_t i;
  533.  
  534. if (nargs > 1) {
  535. @@ -507,9 +510,10 @@ njs_object_math_max(njs_vm_t *vm, njs_va
  536. goto done;
  537.  
  538. } else if (!njs_is_numeric(&args[i])) {
  539. - njs_vm_trap_value(vm, &args[i]);
  540. -
  541. - return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
  542. + ret = njs_value_to_numeric(vm, &args[i], &args[i]);
  543. + if (ret != NXT_OK) {
  544. + return ret;
  545. + }
  546. }
  547. }
  548.  
  549. @@ -536,14 +540,16 @@ njs_object_math_min(njs_vm_t *vm, njs_va
  550. njs_index_t unused)
  551. {
  552. double num;
  553. + njs_ret_t ret;
  554. nxt_uint_t i;
  555.  
  556. if (nargs > 1) {
  557. for (i = 1; i < nargs; i++) {
  558. if (!njs_is_numeric(&args[i])) {
  559. - njs_vm_trap_value(vm, &args[i]);
  560. -
  561. - return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
  562. + ret = njs_value_to_numeric(vm, &args[i], &args[i]);
  563. + if (ret != NXT_OK) {
  564. + return ret;
  565. + }
  566. }
  567. }
  568.  
  569. diff --git a/njs/njs_object.c b/njs/njs_object.c
  570. --- a/njs/njs_object.c
  571. +++ b/njs/njs_object.c
  572. @@ -2144,7 +2144,6 @@ njs_object_prototype_has_own_property(nj
  573. vm->retval = njs_value_false;
  574. return NXT_OK;
  575.  
  576. - case NJS_TRAP:
  577. case NXT_ERROR:
  578. default:
  579. return ret;
  580. @@ -2185,7 +2184,6 @@ njs_object_prototype_prop_is_enumerable(
  581. retval = &njs_value_false;
  582. break;
  583.  
  584. - case NJS_TRAP:
  585. case NXT_ERROR:
  586. default:
  587. return ret;
  588. diff --git a/njs/njs_object_property.c b/njs/njs_object_property.c
  589. --- a/njs/njs_object_property.c
  590. +++ b/njs/njs_object_property.c
  591. @@ -38,7 +38,6 @@ static njs_object_prop_t *njs_descriptor
  592. * NXT_DECLINED property was not found in object,
  593. * if pq->lhq.value != NULL it contains retval of type
  594. * njs_object_prop_t * where prop->type is NJS_WHITEOUT
  595. - * NJS_TRAP the property trap must be called,
  596. * NXT_ERROR exception has been thrown.
  597. *
  598. * TODO:
  599. @@ -53,10 +52,16 @@ njs_property_query(njs_vm_t *vm, njs_pro
  600. uint32_t (*hash)(const void *, size_t);
  601. njs_ret_t ret;
  602. njs_object_t *obj;
  603. + njs_value_t prop;
  604. njs_function_t *function;
  605.  
  606. if (nxt_slow_path(!njs_is_primitive(property))) {
  607. - return njs_trap(vm, NJS_TRAP_PROPERTY);
  608. + ret = njs_value_to_string(vm, &prop, (njs_value_t *) property);
  609. + if (ret != NXT_OK) {
  610. + return ret;
  611. + }
  612. +
  613. + property = &prop;
  614. }
  615.  
  616. hash = nxt_djb_hash;
  617. @@ -473,7 +478,6 @@ njs_external_property_delete(njs_vm_t *v
  618. * retval will contain the property's value
  619. *
  620. * NXT_DECLINED property was not found in object
  621. - * NJS_TRAP the property trap must be called
  622. * NJS_APPLIED the property getter was applied
  623. * NXT_ERROR exception has been thrown.
  624. * retval will contain undefined
  625. @@ -553,7 +557,6 @@ njs_value_property(njs_vm_t *vm, const n
  626.  
  627. return NXT_DECLINED;
  628.  
  629. - case NJS_TRAP:
  630. case NXT_ERROR:
  631. default:
  632.  
  633. @@ -566,7 +569,6 @@ njs_value_property(njs_vm_t *vm, const n
  634.  
  635. /*
  636. * NXT_OK property has been set successfully
  637. - * NJS_TRAP the property trap must be called
  638. * NJS_APPLIED the property setter was applied
  639. * NXT_ERROR exception has been thrown.
  640. */
  641. @@ -669,7 +671,6 @@ njs_value_property_set(njs_vm_t *vm, njs
  642.  
  643. break;
  644.  
  645. - case NJS_TRAP:
  646. case NXT_ERROR:
  647. default:
  648.  
  649. @@ -1152,7 +1153,6 @@ njs_object_prop_descriptor(njs_vm_t *vm,
  650. *dest = njs_value_undefined;
  651. return NXT_OK;
  652.  
  653. - case NJS_TRAP:
  654. case NXT_ERROR:
  655. default:
  656. return ret;
  657. diff --git a/njs/njs_regexp.c b/njs/njs_regexp.c
  658. --- a/njs/njs_regexp.c
  659. +++ b/njs/njs_regexp.c
  660. @@ -112,17 +112,19 @@ njs_regexp_constructor(njs_vm_t *vm, njs
  661. pattern = njs_arg(args, nargs, 1);
  662.  
  663. if (!njs_is_regexp(pattern) && !njs_is_primitive(pattern)) {
  664. - njs_vm_trap_value(vm, &args[1]);
  665. -
  666. - return njs_trap(vm, NJS_TRAP_STRING_ARG);
  667. + ret = njs_value_to_string(vm, &args[1], &args[1]);
  668. + if (ret != NXT_OK) {
  669. + return ret;
  670. + }
  671. }
  672.  
  673. flags = njs_arg(args, nargs, 2);
  674.  
  675. if (!njs_is_primitive(flags)) {
  676. - njs_vm_trap_value(vm, &args[2]);
  677. -
  678. - return njs_trap(vm, NJS_TRAP_STRING_ARG);
  679. + ret = njs_value_to_string(vm, &args[2], &args[2]);
  680. + if (ret != NXT_OK) {
  681. + return ret;
  682. + }
  683. }
  684.  
  685. re_flags = 0;
  686. diff --git a/njs/njs_string.c b/njs/njs_string.c
  687. --- a/njs/njs_string.c
  688. +++ b/njs/njs_string.c
  689. @@ -853,6 +853,7 @@ njs_string_prototype_concat(njs_vm_t *vm
  690. {
  691. u_char *p, *start;
  692. uint64_t size, length, mask;
  693. + njs_ret_t ret;
  694. nxt_uint_t i;
  695. njs_string_prop_t string;
  696.  
  697. @@ -863,9 +864,10 @@ njs_string_prototype_concat(njs_vm_t *vm
  698.  
  699. for (i = 0; i < nargs; i++) {
  700. if (!njs_is_string(&args[i])) {
  701. - njs_vm_trap_value(vm, &args[i]);
  702. -
  703. - return njs_trap(vm, NJS_TRAP_STRING_ARG);
  704. + ret = njs_value_to_string(vm, &args[i], &args[i]);
  705. + if (ret != NXT_OK) {
  706. + return ret;
  707. + }
  708. }
  709. }
  710.  
  711. @@ -1222,16 +1224,12 @@ njs_string_prototype_char_at(njs_vm_t *v
  712.  
  713. slice.string_length = njs_string_prop(&string, &args[0]);
  714.  
  715. - start = 0;
  716. + start = njs_primitive_value_to_integer(njs_arg(args, nargs, 1));
  717. length = 1;
  718.  
  719. - if (nargs > 1) {
  720. - start = njs_number(&args[1]);
  721. -
  722. - if (start < 0 || start >= (ssize_t) slice.string_length) {
  723. - start = 0;
  724. - length = 0;
  725. - }
  726. + if (start < 0 || start >= (ssize_t) slice.string_length) {
  727. + start = 0;
  728. + length = 0;
  729. }
  730.  
  731. slice.start = start;
  732. @@ -1448,6 +1446,7 @@ njs_string_bytes_from_array(njs_vm_t *vm
  733. {
  734. u_char *p;
  735. uint32_t i, length;
  736. + njs_ret_t ret;
  737. njs_array_t *array;
  738. njs_value_t *octet;
  739.  
  740. @@ -1456,9 +1455,10 @@ njs_string_bytes_from_array(njs_vm_t *vm
  741.  
  742. for (i = 0; i < length; i++) {
  743. if (!njs_is_numeric(&array->start[i])) {
  744. - njs_vm_trap_value(vm, &array->start[i]);
  745. -
  746. - return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
  747. + ret = njs_value_to_numeric(vm, &array->start[i], &array->start[i]);
  748. + if (ret != NXT_OK) {
  749. + return ret;
  750. + }
  751. }
  752. }
  753.  
  754. @@ -1684,13 +1684,15 @@ njs_string_from_char_code(njs_vm_t *vm,
  755. double num;
  756. size_t size;
  757. int32_t code;
  758. + njs_ret_t ret;
  759. nxt_uint_t i;
  760.  
  761. for (i = 1; i < nargs; i++) {
  762. if (!njs_is_numeric(&args[i])) {
  763. - njs_vm_trap_value(vm, &args[i]);
  764. -
  765. - return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
  766. + ret = njs_value_to_numeric(vm, &args[i], &args[i]);
  767. + if (ret != NXT_OK) {
  768. + return ret;
  769. + }
  770. }
  771. }
  772.  
  773. @@ -2397,20 +2399,16 @@ njs_string_prototype_repeat(njs_vm_t *vm
  774. uint32_t size, length;
  775. njs_string_prop_t string;
  776.  
  777. - n = 0;
  778. + n = njs_primitive_value_to_integer(njs_arg(args, nargs, 1));
  779.  
  780. (void) njs_string_prop(&string, &args[0]);
  781.  
  782. - if (nargs > 1) {
  783. - max = (string.size > 1) ? NJS_STRING_MAX_LENGTH / string.size
  784. - : NJS_STRING_MAX_LENGTH;
  785. -
  786. - n = njs_number(&args[1]);
  787. -
  788. - if (nxt_slow_path(n < 0 || n >= max)) {
  789. - njs_range_error(vm, NULL);
  790. - return NXT_ERROR;
  791. - }
  792. + max = (string.size > 1) ? NJS_STRING_MAX_LENGTH / string.size
  793. + : NJS_STRING_MAX_LENGTH;
  794. +
  795. + if (nxt_slow_path(n < 0 || n >= max)) {
  796. + njs_range_error(vm, NULL);
  797. + return NXT_ERROR;
  798. }
  799.  
  800. if (string.size == 0) {
  801. @@ -3390,8 +3388,10 @@ njs_string_replace_search_continuation(n
  802. r = njs_vm_continuation(vm);
  803.  
  804. if (!njs_is_primitive(&r->retval)) {
  805. - njs_vm_trap_value(vm, &r->retval);
  806. - return njs_trap(vm, NJS_TRAP_STRING_ARG);
  807. + ret = njs_value_to_string(vm, &r->retval, &r->retval);
  808. + if (ret != NXT_OK) {
  809. + return ret;
  810. + }
  811. }
  812.  
  813. ret = njs_primitive_value_to_string(vm, &string, &r->retval);
  814. diff --git a/njs/njs_value.c b/njs/njs_value.c
  815. --- a/njs/njs_value.c
  816. +++ b/njs/njs_value.c
  817. @@ -169,11 +169,12 @@ njs_values_strict_equal(const njs_value_
  818. */
  819.  
  820. njs_ret_t
  821. -njs_value_to_primitive(njs_vm_t *vm, njs_value_t *value, nxt_uint_t hint)
  822. +njs_value_to_primitive(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value,
  823. + nxt_uint_t hint)
  824. {
  825. njs_ret_t ret;
  826. - njs_value_t *retval;
  827. - njs_function_t *function;
  828. + nxt_uint_t trap_tries;
  829. + njs_value_t retval;
  830. njs_object_prop_t *prop;
  831. nxt_lvlhsh_query_t lhq;
  832.  
  833. @@ -187,76 +188,100 @@ njs_value_to_primitive(njs_vm_t *vm, njs
  834. nxt_string("toString"),
  835. };
  836.  
  837. - if (!njs_is_primitive(value)) {
  838. - retval = &vm->top_frame->trap_scratch;
  839.  
  840. - if (!njs_is_primitive(retval)) {
  841. + if (njs_is_primitive(value)) {
  842. + /* GC */
  843. + *dst = *value;
  844. + return NXT_OK;
  845. + }
  846.  
  847. - for ( ;; ) {
  848. - ret = NXT_ERROR;
  849. + trap_tries = 0;
  850.  
  851. - if (njs_is_object(value) && vm->top_frame->trap_tries < 2) {
  852. - hint ^= vm->top_frame->trap_tries++;
  853. + for ( ;; ) {
  854. + ret = NXT_ERROR;
  855.  
  856. - lhq.key_hash = hashes[hint];
  857. - lhq.key = names[hint];
  858. + if (njs_is_object(value) && trap_tries < 2) {
  859. + hint ^= trap_tries++;
  860.  
  861. - prop = njs_object_property(vm, njs_object(value), &lhq);
  862. + lhq.key_hash = hashes[hint];
  863. + lhq.key = names[hint];
  864.  
  865. - if (nxt_fast_path(prop != NULL)) {
  866. + prop = njs_object_property(vm, njs_object(value), &lhq);
  867.  
  868. - if (!njs_is_function(&prop->value)) {
  869. - /* Try the second method. */
  870. - continue;
  871. - }
  872. + if (prop == NULL || !njs_is_function(&prop->value)) {
  873. + /* Try the second method. */
  874. + continue;
  875. + }
  876.  
  877. - function = njs_function(&prop->value);
  878. + ret = njs_function_call(vm, njs_function(&prop->value), value, 1,
  879. + (njs_index_t) &retval);
  880.  
  881. - ret = njs_function_apply(vm, function, value, 1,
  882. - (njs_index_t) retval);
  883. - /*
  884. - * njs_function_apply() can return
  885. - * NXT_OK, NJS_APPLIED, NXT_ERROR, NXT_AGAIN.
  886. - */
  887. - if (nxt_fast_path(ret == NXT_OK)) {
  888. + if (nxt_fast_path(ret == NXT_OK)) {
  889. + if (njs_is_primitive(&retval)) {
  890. + break;
  891. + }
  892.  
  893. - if (njs_is_primitive(&vm->retval)) {
  894. - retval = &vm->retval;
  895. - break;
  896. - }
  897. + /* Try the second method. */
  898. + continue;
  899. + }
  900.  
  901. - /* Try the second method. */
  902. - continue;
  903. - }
  904. + /* NXT_ERROR */
  905.  
  906. - if (ret == NJS_APPLIED) {
  907. - /*
  908. - * A user-defined method or continuation have
  909. - * been prepared to run. The method will return
  910. - * to the current instruction and will restart it.
  911. - */
  912. - ret = 0;
  913. - }
  914. - }
  915. - }
  916. + return ret;
  917. + }
  918.  
  919. - if (ret == NXT_ERROR) {
  920. - njs_type_error(vm,
  921. - "Cannot convert object to primitive value");
  922. - }
  923. + njs_type_error(vm, "Cannot convert object to primitive value");
  924.  
  925. - return ret;
  926. - }
  927. + return ret;
  928. + }
  929. +
  930. + *dst = retval;
  931. +
  932. + return NXT_OK;
  933. +}
  934. +
  935. +
  936. +njs_ret_t
  937. +njs_value_to_numeric(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value)
  938. +{
  939. + double num;
  940. + njs_ret_t ret;
  941. +
  942. + ret = njs_value_to_primitive(vm, dst, value, 0);
  943. + if (nxt_slow_path(ret != NXT_OK)) {
  944. + return ret;
  945. + }
  946. +
  947. + if (!njs_is_numeric(dst)) {
  948. + num = NAN;
  949. +
  950. + if (njs_is_string(dst)) {
  951. + num = njs_string_to_number(dst, 0);
  952. }
  953.  
  954. - *value = *retval;
  955. -
  956. - njs_set_invalid(retval);
  957. + njs_set_number(dst, num);
  958. }
  959.  
  960. - vm->top_frame->trap_tries = 0;
  961. + return NXT_OK;
  962. +}
  963.  
  964. - return 1;
  965. +
  966. +njs_ret_t
  967. +njs_value_to_string(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value)
  968. +{
  969. + njs_ret_t ret;
  970. + njs_value_t primitive;
  971. +
  972. + if (nxt_slow_path(!njs_is_primitive(value))) {
  973. + ret = njs_value_to_primitive(vm, &primitive, value, 1);
  974. + if (nxt_slow_path(ret != NXT_OK)) {
  975. + return ret;
  976. + }
  977. +
  978. + value = &primitive;
  979. + }
  980. +
  981. + return njs_primitive_value_to_string(vm, dst, value);
  982. }
  983.  
  984.  
  985. diff --git a/njs/njs_value.h b/njs/njs_value.h
  986. --- a/njs/njs_value.h
  987. +++ b/njs/njs_value.h
  988. @@ -561,7 +561,7 @@ typedef enum {
  989.  
  990.  
  991. #define njs_set_boolean(value, yn) \
  992. - *(value) = yn ? njs_value_true : njs_value_false
  993. + *(value) = (yn) ? njs_value_true : njs_value_false
  994.  
  995.  
  996. #define njs_set_true(value) \
  997. @@ -687,8 +687,12 @@ void njs_value_retain(njs_value_t *value
  998. void njs_value_release(njs_vm_t *vm, njs_value_t *value);
  999. nxt_bool_t njs_values_strict_equal(const njs_value_t *val1,
  1000. const njs_value_t *val2);
  1001. -njs_ret_t njs_value_to_primitive(njs_vm_t *vm, njs_value_t *value,
  1002. - nxt_uint_t hint);
  1003. +njs_ret_t njs_value_to_primitive(njs_vm_t *vm, njs_value_t *dst,
  1004. + njs_value_t *value, nxt_uint_t hint);
  1005. +njs_ret_t njs_value_to_numeric(njs_vm_t *vm, njs_value_t *dst,
  1006. + njs_value_t *value);
  1007. +njs_ret_t njs_value_to_string(njs_vm_t *vm, njs_value_t *dst,
  1008. + njs_value_t *value);
  1009. njs_array_t *njs_value_enumerate(njs_vm_t *vm, const njs_value_t *value,
  1010. njs_object_enum_t kind, nxt_bool_t all);
  1011. njs_array_t *njs_value_own_enumerate(njs_vm_t *vm, const njs_value_t *value,
  1012. diff --git a/njs/njs_vm.c b/njs/njs_vm.c
  1013. --- a/njs/njs_vm.c
  1014. +++ b/njs/njs_vm.c
  1015. @@ -23,10 +23,10 @@ struct njs_property_next_s {
  1016.  
  1017. static njs_ret_t njs_string_concat(njs_vm_t *vm, njs_value_t *val1,
  1018. njs_value_t *val2);
  1019. -static njs_ret_t njs_values_equal(njs_vm_t *vm, const njs_value_t *val1,
  1020. - const njs_value_t *val2);
  1021. -static njs_ret_t njs_values_compare(njs_vm_t *vm, const njs_value_t *val1,
  1022. - const njs_value_t *val2);
  1023. +static njs_ret_t njs_values_equal(njs_vm_t *vm, njs_value_t *val1,
  1024. + njs_value_t *val2);
  1025. +static njs_ret_t njs_values_compare(njs_vm_t *vm, njs_value_t *val1,
  1026. + njs_value_t *val2);
  1027. static njs_ret_t njs_function_frame_create(njs_vm_t *vm, njs_value_t *value,
  1028. const njs_value_t *this, uintptr_t nargs, nxt_bool_t ctor);
  1029. static njs_object_t *njs_function_new_object(njs_vm_t *vm, njs_value_t *value);
  1030. @@ -35,29 +35,6 @@ static void njs_vm_scopes_restore(njs_vm
  1031. static njs_ret_t njs_vmcode_continuation(njs_vm_t *vm, njs_value_t *invld1,
  1032. njs_value_t *invld2);
  1033.  
  1034. -static void njs_vm_trap(njs_vm_t *vm, njs_trap_t trap, njs_value_t *value1,
  1035. - njs_value_t *value2);
  1036. -static void njs_vm_trap_argument(njs_vm_t *vm, njs_trap_t trap);
  1037. -static njs_ret_t njs_vmcode_number_primitive(njs_vm_t *vm, njs_value_t *invld,
  1038. - njs_value_t *narg);
  1039. -static njs_ret_t njs_vmcode_string_primitive(njs_vm_t *vm, njs_value_t *invld,
  1040. - njs_value_t *narg);
  1041. -static njs_ret_t njs_vmcode_addition_primitive(njs_vm_t *vm, njs_value_t *invld,
  1042. - njs_value_t *narg);
  1043. -static njs_ret_t njs_vmcode_comparison_primitive(njs_vm_t *vm,
  1044. - njs_value_t *invld, njs_value_t *narg);
  1045. -static njs_ret_t njs_vmcode_number_argument(njs_vm_t *vm, njs_value_t *invld1,
  1046. - njs_value_t *inlvd2);
  1047. -static njs_ret_t njs_vmcode_string_argument(njs_vm_t *vm, njs_value_t *invld1,
  1048. - njs_value_t *inlvd2);
  1049. -static njs_ret_t njs_vmcode_primitive_argument(njs_vm_t *vm,
  1050. - njs_value_t *invld1, njs_value_t *inlvd2);
  1051. -static njs_ret_t njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1,
  1052. - njs_value_t *invld2);
  1053. -static njs_ret_t njs_object_value_to_string(njs_vm_t *vm, njs_value_t *value);
  1054. -static njs_ret_t njs_vmcode_value_to_string(njs_vm_t *vm, njs_value_t *invld1,
  1055. - njs_value_t *invld2);
  1056. -
  1057. static njs_ret_t njs_vm_add_backtrace_entry(njs_vm_t *vm, njs_frame_t *frame);
  1058.  
  1059. void njs_debug(njs_index_t index, njs_value_t *value);
  1060. @@ -79,9 +56,8 @@ const nxt_str_t njs_entry_anonymous =
  1061. nxt_int_t
  1062. njs_vmcode_interpreter(njs_vm_t *vm)
  1063. {
  1064. - u_char *catch;
  1065. + u_char *catch, call;
  1066. njs_ret_t ret;
  1067. - njs_trap_t trap;
  1068. njs_value_t *retval, *value1, *value2;
  1069. njs_frame_t *frame;
  1070. njs_native_frame_t *previous;
  1071. @@ -147,40 +123,6 @@ start:
  1072. }
  1073. }
  1074.  
  1075. - if (ret == NJS_TRAP) {
  1076. - trap = vm->trap;
  1077. -
  1078. - switch (trap) {
  1079. -
  1080. - case NJS_TRAP_NUMBER:
  1081. - value2 = value1;
  1082. -
  1083. - /* Fall through. */
  1084. -
  1085. - case NJS_TRAP_NUMBERS:
  1086. - case NJS_TRAP_ADDITION:
  1087. - case NJS_TRAP_COMPARISON:
  1088. - case NJS_TRAP_INCDEC:
  1089. - case NJS_TRAP_PROPERTY:
  1090. -
  1091. - njs_vm_trap(vm, trap, value1, value2);
  1092. -
  1093. - goto start;
  1094. -
  1095. - case NJS_TRAP_NUMBER_ARG:
  1096. - case NJS_TRAP_STRING_ARG:
  1097. - case NJS_TRAP_PRIMITIVE_ARG:
  1098. -
  1099. - njs_vm_trap_argument(vm, trap);
  1100. -
  1101. - goto start;
  1102. -
  1103. - default:
  1104. - ret = NXT_ERROR;
  1105. - break;
  1106. - }
  1107. - }
  1108. -
  1109. if (ret == NXT_ERROR) {
  1110.  
  1111. for ( ;; ) {
  1112. @@ -210,14 +152,44 @@ start:
  1113.  
  1114. njs_vm_scopes_restore(vm, frame, previous);
  1115.  
  1116. + call = frame->native.call;
  1117. +
  1118. if (frame->native.size != 0) {
  1119. vm->stack_size -= frame->native.size;
  1120. nxt_mp_free(vm->mem_pool, frame);
  1121. }
  1122. +
  1123. + if (call) {
  1124. + return NXT_ERROR;
  1125. + }
  1126. +
  1127. }
  1128. }
  1129.  
  1130. - /* NXT_AGAIN, NJS_STOP. */
  1131. + /* NXT_ERROR, NJS_STOP. */
  1132. +
  1133. + return ret;
  1134. +}
  1135. +
  1136. +
  1137. +nxt_int_t
  1138. +njs_vmcode_run(njs_vm_t *vm)
  1139. +{
  1140. + njs_ret_t ret;
  1141. +
  1142. + if (nxt_slow_path(vm->count > 128)) {
  1143. + njs_internal_error(vm, "recursion limit reached");
  1144. + return NXT_ERROR;
  1145. + }
  1146. +
  1147. + vm->count++;
  1148. +
  1149. + ret = njs_vmcode_interpreter(vm);
  1150. + if (ret == NJS_STOP) {
  1151. + ret = NJS_OK;
  1152. + }
  1153. +
  1154. + vm->count--;
  1155.  
  1156. return ret;
  1157. }
  1158. @@ -620,7 +592,6 @@ njs_vmcode_property_in(njs_vm_t *vm, njs
  1159.  
  1160. break;
  1161.  
  1162. - case NJS_TRAP:
  1163. case NXT_ERROR:
  1164. default:
  1165.  
  1166. @@ -715,7 +686,6 @@ njs_vmcode_property_delete(njs_vm_t *vm,
  1167. case NXT_DECLINED:
  1168. break;
  1169.  
  1170. - case NJS_TRAP:
  1171. case NXT_ERROR:
  1172. default:
  1173.  
  1174. @@ -892,40 +862,60 @@ njs_vmcode_instance_of(njs_vm_t *vm, njs
  1175. njs_ret_t
  1176. njs_vmcode_increment(njs_vm_t *vm, njs_value_t *reference, njs_value_t *value)
  1177. {
  1178. - double num;
  1179. -
  1180. - if (nxt_fast_path(njs_is_numeric(value))) {
  1181. - num = njs_number(value) + 1.0;
  1182. -
  1183. - njs_release(vm, reference);
  1184. -
  1185. - njs_set_number(reference, num);
  1186. - vm->retval = *reference;
  1187. -
  1188. - return sizeof(njs_vmcode_3addr_t);
  1189. + double num;
  1190. + njs_ret_t ret;
  1191. + njs_value_t numeric;
  1192. +
  1193. + if (nxt_slow_path(!njs_is_numeric(value))) {
  1194. + ret = njs_value_to_numeric(vm, &numeric, value);
  1195. + if (nxt_slow_path(ret != NXT_OK)) {
  1196. + return ret;
  1197. + }
  1198. +
  1199. + num = njs_number(&numeric);
  1200. +
  1201. + } else {
  1202. + num = njs_number(value);
  1203. }
  1204.  
  1205. - return njs_trap(vm, NJS_TRAP_INCDEC);
  1206. + num += 1.0;
  1207. +
  1208. + njs_release(vm, reference);
  1209. +
  1210. + njs_set_number(reference, num);
  1211. + vm->retval = *reference;
  1212. +
  1213. + return sizeof(njs_vmcode_3addr_t);
  1214. }
  1215.  
  1216.  
  1217. njs_ret_t
  1218. njs_vmcode_decrement(njs_vm_t *vm, njs_value_t *reference, njs_value_t *value)
  1219. {
  1220. - double num;
  1221. -
  1222. - if (nxt_fast_path(njs_is_numeric(value))) {
  1223. - num = njs_number(value) - 1.0;
  1224. -
  1225. - njs_release(vm, reference);
  1226. -
  1227. - njs_set_number(reference, num);
  1228. - vm->retval = *reference;
  1229. -
  1230. - return sizeof(njs_vmcode_3addr_t);
  1231. + double num;
  1232. + njs_ret_t ret;
  1233. + njs_value_t numeric;
  1234. +
  1235. + if (nxt_slow_path(!njs_is_numeric(value))) {
  1236. + ret = njs_value_to_numeric(vm, &numeric, value);
  1237. + if (nxt_slow_path(ret != NXT_OK)) {
  1238. + return ret;
  1239. + }
  1240. +
  1241. + num = njs_number(&numeric);
  1242. +
  1243. + } else {
  1244. + num = njs_number(value);
  1245. }
  1246.  
  1247. - return njs_trap(vm, NJS_TRAP_INCDEC);
  1248. + num -= 1.0;
  1249. +
  1250. + njs_release(vm, reference);
  1251. +
  1252. + njs_set_number(reference, num);
  1253. + vm->retval = *reference;
  1254. +
  1255. + return sizeof(njs_vmcode_3addr_t);
  1256. }
  1257.  
  1258.  
  1259. @@ -934,19 +924,27 @@ njs_vmcode_post_increment(njs_vm_t *vm,
  1260. njs_value_t *value)
  1261. {
  1262. double num;
  1263. -
  1264. - if (nxt_fast_path(njs_is_numeric(value))) {
  1265. + njs_ret_t ret;
  1266. + njs_value_t numeric;
  1267. +
  1268. + if (nxt_slow_path(!njs_is_numeric(value))) {
  1269. + ret = njs_value_to_numeric(vm, &numeric, value);
  1270. + if (nxt_slow_path(ret != NXT_OK)) {
  1271. + return ret;
  1272. + }
  1273. +
  1274. + num = njs_number(&numeric);
  1275. +
  1276. + } else {
  1277. num = njs_number(value);
  1278. -
  1279. - njs_release(vm, reference);
  1280. -
  1281. - njs_set_number(reference, num + 1.0);
  1282. - njs_set_number(&vm->retval, num);
  1283. -
  1284. - return sizeof(njs_vmcode_3addr_t);
  1285. }
  1286.  
  1287. - return njs_trap(vm, NJS_TRAP_INCDEC);
  1288. + njs_release(vm, reference);
  1289. +
  1290. + njs_set_number(reference, num + 1.0);
  1291. + njs_set_number(&vm->retval, num);
  1292. +
  1293. + return sizeof(njs_vmcode_3addr_t);
  1294. }
  1295.  
  1296.  
  1297. @@ -954,20 +952,28 @@ njs_ret_t
  1298. njs_vmcode_post_decrement(njs_vm_t *vm, njs_value_t *reference,
  1299. njs_value_t *value)
  1300. {
  1301. - double num;
  1302. -
  1303. - if (nxt_fast_path(njs_is_numeric(value))) {
  1304. + double num;
  1305. + njs_ret_t ret;
  1306. + njs_value_t numeric;
  1307. +
  1308. + if (nxt_slow_path(!njs_is_numeric(value))) {
  1309. + ret = njs_value_to_numeric(vm, &numeric, value);
  1310. + if (nxt_slow_path(ret != NXT_OK)) {
  1311. + return ret;
  1312. + }
  1313. +
  1314. + num = njs_number(&numeric);
  1315. +
  1316. + } else {
  1317. num = njs_number(value);
  1318. -
  1319. - njs_release(vm, reference);
  1320. -
  1321. - njs_set_number(reference, num - 1.0);
  1322. - njs_set_number(&vm->retval, num);
  1323. -
  1324. - return sizeof(njs_vmcode_3addr_t);
  1325. }
  1326.  
  1327. - return njs_trap(vm, NJS_TRAP_INCDEC);
  1328. + njs_release(vm, reference);
  1329. +
  1330. + njs_set_number(reference, num - 1.0);
  1331. + njs_set_number(&vm->retval, num);
  1332. +
  1333. + return sizeof(njs_vmcode_3addr_t);
  1334. }
  1335.  
  1336.  
  1337. @@ -1042,69 +1048,105 @@ njs_vmcode_delete(njs_vm_t *vm, njs_valu
  1338. njs_ret_t
  1339. njs_vmcode_unary_plus(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld)
  1340. {
  1341. - if (nxt_fast_path(njs_is_numeric(value))) {
  1342. - njs_set_number(&vm->retval, njs_number(value));
  1343. - return sizeof(njs_vmcode_2addr_t);
  1344. + njs_ret_t ret;
  1345. + njs_value_t numeric;
  1346. +
  1347. + if (nxt_slow_path(!njs_is_numeric(value))) {
  1348. + ret = njs_value_to_numeric(vm, &numeric, value);
  1349. + if (ret != NXT_OK) {
  1350. + return ret;
  1351. + }
  1352. +
  1353. + value = &numeric;
  1354. }
  1355.  
  1356. - return njs_trap(vm, NJS_TRAP_NUMBER);
  1357. + njs_set_number(&vm->retval, njs_number(value));
  1358. +
  1359. + return sizeof(njs_vmcode_2addr_t);
  1360. }
  1361.  
  1362.  
  1363. njs_ret_t
  1364. njs_vmcode_unary_negation(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld)
  1365. {
  1366. - if (nxt_fast_path(njs_is_numeric(value))) {
  1367. - njs_set_number(&vm->retval, - njs_number(value));
  1368. - return sizeof(njs_vmcode_2addr_t);
  1369. + njs_ret_t ret;
  1370. + njs_value_t numeric;
  1371. +
  1372. + if (nxt_slow_path(!njs_is_numeric(value))) {
  1373. + ret = njs_value_to_numeric(vm, &numeric, value);
  1374. + if (ret != NXT_OK) {
  1375. + return ret;
  1376. + }
  1377. +
  1378. + value = &numeric;
  1379. }
  1380.  
  1381. - return njs_trap(vm, NJS_TRAP_NUMBER);
  1382. + njs_set_number(&vm->retval, -njs_number(value));
  1383. +
  1384. + return sizeof(njs_vmcode_2addr_t);
  1385. }
  1386.  
  1387.  
  1388. njs_ret_t
  1389. njs_vmcode_addition(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  1390. {
  1391. - double num;
  1392. njs_ret_t ret;
  1393. - njs_value_t *s1, *s2, *src, dst;
  1394. +
  1395. + njs_value_t primitive1, primitive2, dst, *s1, *s2, *src;
  1396. +
  1397. + if (nxt_slow_path(!njs_is_primitive(val1))) {
  1398. +
  1399. + /*
  1400. + * ECMAScript 5.1:
  1401. + * Date should return String, other types sould return Number.
  1402. + */
  1403. +
  1404. + ret = njs_value_to_primitive(vm, &primitive1, val1, njs_is_date(val1));
  1405. + if (ret != NXT_OK) {
  1406. + return ret;
  1407. + }
  1408. +
  1409. + val1 = &primitive1;
  1410. + }
  1411. +
  1412. + if (nxt_slow_path(!njs_is_primitive(val2))) {
  1413. +
  1414. + /*
  1415. + * ECMAScript 5.1:
  1416. + * Date should return String, other types sould return Number.
  1417. + */
  1418. +
  1419. + ret = njs_value_to_primitive(vm, &primitive2, val2, njs_is_date(val2));
  1420. + if (ret != NXT_OK) {
  1421. + return ret;
  1422. + }
  1423. +
  1424. + val2 = &primitive2;
  1425. + }
  1426.  
  1427. if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
  1428. -
  1429. - num = njs_number(val1) + njs_number(val2);
  1430. - njs_set_number(&vm->retval, num);
  1431. -
  1432. + njs_set_number(&vm->retval, njs_number(val1) + njs_number(val2));
  1433. return sizeof(njs_vmcode_3addr_t);
  1434. }
  1435.  
  1436. - if (nxt_fast_path(njs_is_string(val1) && njs_is_string(val2))) {
  1437. - return njs_string_concat(vm, val1, val2);
  1438. + if (njs_is_string(val1)) {
  1439. + s1 = val1;
  1440. + s2 = &dst;
  1441. + src = val2;
  1442. +
  1443. + } else {
  1444. + s1 = &dst;
  1445. + s2 = val2;
  1446. + src = val1;
  1447. }
  1448.  
  1449. - if (nxt_fast_path(njs_is_primitive(val1) && njs_is_primitive(val2))) {
  1450. -
  1451. - if (njs_is_string(val1)) {
  1452. - s1 = val1;
  1453. - s2 = &dst;
  1454. - src = val2;
  1455. -
  1456. - } else {
  1457. - s1 = &dst;
  1458. - s2 = val2;
  1459. - src = val1;
  1460. - }
  1461. -
  1462. - ret = njs_primitive_value_to_string(vm, &dst, src);
  1463. -
  1464. - if (nxt_fast_path(ret == NXT_OK)) {
  1465. - return njs_string_concat(vm, s1, s2);
  1466. - }
  1467. -
  1468. - return ret;
  1469. + ret = njs_primitive_value_to_string(vm, &dst, src);
  1470. +
  1471. + if (nxt_fast_path(ret == NXT_OK)) {
  1472. + return njs_string_concat(vm, s1, s2);
  1473. }
  1474.  
  1475. - return njs_trap(vm, NJS_TRAP_ADDITION);
  1476. + return ret;
  1477. }
  1478.  
  1479.  
  1480. @@ -1149,140 +1191,238 @@ njs_string_concat(njs_vm_t *vm, njs_valu
  1481. njs_ret_t
  1482. njs_vmcode_substraction(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  1483. {
  1484. - double num;
  1485. -
  1486. - if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
  1487. -
  1488. - num = njs_number(val1) - njs_number(val2);
  1489. - njs_set_number(&vm->retval, num);
  1490. -
  1491. - return sizeof(njs_vmcode_3addr_t);
  1492. + njs_ret_t ret;
  1493. + njs_value_t numeric1, numeric2;
  1494. +
  1495. + if (nxt_slow_path(!njs_is_numeric(val1))) {
  1496. + ret = njs_value_to_numeric(vm, &numeric1, val1);
  1497. + if (ret != NXT_OK) {
  1498. + return ret;
  1499. + }
  1500. +
  1501. + val1 = &numeric1;
  1502. }
  1503.  
  1504. - return njs_trap(vm, NJS_TRAP_NUMBERS);
  1505. + if (nxt_slow_path(!njs_is_numeric(val2))) {
  1506. + ret = njs_value_to_numeric(vm, &numeric2, val2);
  1507. + if (ret != NXT_OK) {
  1508. + return ret;
  1509. + }
  1510. +
  1511. + val2 = &numeric2;
  1512. + }
  1513. +
  1514. + njs_set_number(&vm->retval, njs_number(val1) - njs_number(val2));
  1515. +
  1516. + return sizeof(njs_vmcode_3addr_t);
  1517. }
  1518.  
  1519.  
  1520. njs_ret_t
  1521. njs_vmcode_multiplication(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  1522. {
  1523. - double num;
  1524. -
  1525. - if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
  1526. -
  1527. - num = njs_number(val1) * njs_number(val2);
  1528. - njs_set_number(&vm->retval, num);
  1529. -
  1530. - return sizeof(njs_vmcode_3addr_t);
  1531. + njs_ret_t ret;
  1532. + njs_value_t numeric1, numeric2;
  1533. +
  1534. + if (nxt_slow_path(!njs_is_numeric(val1))) {
  1535. + ret = njs_value_to_numeric(vm, &numeric1, val1);
  1536. + if (ret != NXT_OK) {
  1537. + return ret;
  1538. + }
  1539. +
  1540. + val1 = &numeric1;
  1541. }
  1542.  
  1543. - return njs_trap(vm, NJS_TRAP_NUMBERS);
  1544. + if (nxt_slow_path(!njs_is_numeric(val2))) {
  1545. + ret = njs_value_to_numeric(vm, &numeric2, val2);
  1546. + if (ret != NXT_OK) {
  1547. + return ret;
  1548. + }
  1549. +
  1550. + val2 = &numeric2;
  1551. + }
  1552. +
  1553. + njs_set_number(&vm->retval, njs_number(val1) * njs_number(val2));
  1554. +
  1555. + return sizeof(njs_vmcode_3addr_t);
  1556. }
  1557.  
  1558.  
  1559. njs_ret_t
  1560. njs_vmcode_exponentiation(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  1561. {
  1562. - double num, base, exponent;
  1563. - nxt_bool_t valid;
  1564. -
  1565. - if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
  1566. - base = njs_number(val1);
  1567. - exponent = njs_number(val2);
  1568. -
  1569. - /*
  1570. - * According to ES7:
  1571. - * 1. If exponent is NaN, the result should be NaN;
  1572. - * 2. The result of +/-1 ** +/-Infinity should be NaN.
  1573. - */
  1574. - valid = nxt_expect(1, fabs(base) != 1
  1575. - || (!isnan(exponent) && !isinf(exponent)));
  1576. -
  1577. - if (valid) {
  1578. - num = pow(base, exponent);
  1579. -
  1580. - } else {
  1581. - num = NAN;
  1582. + double num, base, exponent;
  1583. + njs_ret_t ret;
  1584. + nxt_bool_t valid;
  1585. + njs_value_t numeric1, numeric2;
  1586. +
  1587. + if (nxt_slow_path(!njs_is_numeric(val1))) {
  1588. + ret = njs_value_to_numeric(vm, &numeric1, val1);
  1589. + if (ret != NXT_OK) {
  1590. + return ret;
  1591. }
  1592.  
  1593. - njs_set_number(&vm->retval, num);
  1594. -
  1595. - return sizeof(njs_vmcode_3addr_t);
  1596. + val1 = &numeric1;
  1597. }
  1598.  
  1599. - return njs_trap(vm, NJS_TRAP_NUMBERS);
  1600. + if (nxt_slow_path(!njs_is_numeric(val2))) {
  1601. + ret = njs_value_to_numeric(vm, &numeric2, val2);
  1602. + if (ret != NXT_OK) {
  1603. + return ret;
  1604. + }
  1605. +
  1606. + val2 = &numeric2;
  1607. + }
  1608. +
  1609. + base = njs_number(val1);
  1610. + exponent = njs_number(val2);
  1611. +
  1612. + /*
  1613. + * According to ES7:
  1614. + * 1. If exponent is NaN, the result should be NaN;
  1615. + * 2. The result of +/-1 ** +/-Infinity should be NaN.
  1616. + */
  1617. + valid = nxt_expect(1, fabs(base) != 1
  1618. + || (!isnan(exponent) && !isinf(exponent)));
  1619. +
  1620. + if (valid) {
  1621. + num = pow(base, exponent);
  1622. +
  1623. + } else {
  1624. + num = NAN;
  1625. + }
  1626. +
  1627. + njs_set_number(&vm->retval, num);
  1628. +
  1629. + return sizeof(njs_vmcode_3addr_t);
  1630. }
  1631.  
  1632.  
  1633. njs_ret_t
  1634. njs_vmcode_division(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  1635. {
  1636. - double num;
  1637. -
  1638. - if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
  1639. -
  1640. - num = njs_number(val1) / njs_number(val2);
  1641. - njs_set_number(&vm->retval, num);
  1642. -
  1643. - return sizeof(njs_vmcode_3addr_t);
  1644. + njs_ret_t ret;
  1645. + njs_value_t numeric1, numeric2;
  1646. +
  1647. + if (nxt_slow_path(!njs_is_numeric(val1))) {
  1648. + ret = njs_value_to_numeric(vm, &numeric1, val1);
  1649. + if (ret != NXT_OK) {
  1650. + return ret;
  1651. + }
  1652. +
  1653. + val1 = &numeric1;
  1654. }
  1655.  
  1656. - return njs_trap(vm, NJS_TRAP_NUMBERS);
  1657. + if (nxt_slow_path(!njs_is_numeric(val2))) {
  1658. + ret = njs_value_to_numeric(vm, &numeric2, val2);
  1659. + if (ret != NXT_OK) {
  1660. + return ret;
  1661. + }
  1662. +
  1663. + val2 = &numeric2;
  1664. + }
  1665. +
  1666. + njs_set_number(&vm->retval, njs_number(val1) / njs_number(val2));
  1667. +
  1668. + return sizeof(njs_vmcode_3addr_t);
  1669. }
  1670.  
  1671.  
  1672. njs_ret_t
  1673. njs_vmcode_remainder(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  1674. {
  1675. - double num;
  1676. -
  1677. - if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
  1678. -
  1679. - num = fmod(njs_number(val1), njs_number(val2));
  1680. - njs_set_number(&vm->retval, num);
  1681. -
  1682. - return sizeof(njs_vmcode_3addr_t);
  1683. + njs_ret_t ret;
  1684. + njs_value_t numeric1, numeric2;
  1685. +
  1686. + if (nxt_slow_path(!njs_is_numeric(val1))) {
  1687. + ret = njs_value_to_numeric(vm, &numeric1, val1);
  1688. + if (ret != NXT_OK) {
  1689. + return ret;
  1690. + }
  1691. +
  1692. + val1 = &numeric1;
  1693. }
  1694.  
  1695. - return njs_trap(vm, NJS_TRAP_NUMBERS);
  1696. + if (nxt_slow_path(!njs_is_numeric(val2))) {
  1697. + ret = njs_value_to_numeric(vm, &numeric2, val2);
  1698. + if (ret != NXT_OK) {
  1699. + return ret;
  1700. + }
  1701. +
  1702. + val2 = &numeric2;
  1703. + }
  1704. +
  1705. + njs_set_number(&vm->retval, fmod(njs_number(val1), njs_number(val2)));
  1706. +
  1707. + return sizeof(njs_vmcode_3addr_t);
  1708. }
  1709.  
  1710.  
  1711. njs_ret_t
  1712. njs_vmcode_left_shift(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  1713. {
  1714. - int32_t num1;
  1715. - uint32_t num2;
  1716. -
  1717. - if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
  1718. -
  1719. - num1 = njs_number_to_int32(njs_number(val1));
  1720. - num2 = njs_number_to_uint32(njs_number(val2));
  1721. - njs_set_number(&vm->retval, num1 << (num2 & 0x1f));
  1722. -
  1723. - return sizeof(njs_vmcode_3addr_t);
  1724. + int32_t num1;
  1725. + uint32_t num2;
  1726. + njs_ret_t ret;
  1727. + njs_value_t numeric1, numeric2;
  1728. +
  1729. + if (nxt_slow_path(!njs_is_numeric(val1))) {
  1730. + ret = njs_value_to_numeric(vm, &numeric1, val1);
  1731. + if (ret != NXT_OK) {
  1732. + return ret;
  1733. + }
  1734. +
  1735. + val1 = &numeric1;
  1736. }
  1737.  
  1738. - return njs_trap(vm, NJS_TRAP_NUMBERS);
  1739. + if (nxt_slow_path(!njs_is_numeric(val2))) {
  1740. + ret = njs_value_to_numeric(vm, &numeric2, val2);
  1741. + if (ret != NXT_OK) {
  1742. + return ret;
  1743. + }
  1744. +
  1745. + val2 = &numeric2;
  1746. + }
  1747. +
  1748. + num1 = njs_number_to_int32(njs_number(val1));
  1749. + num2 = njs_number_to_uint32(njs_number(val2));
  1750. + njs_set_number(&vm->retval, num1 << (num2 & 0x1f));
  1751. +
  1752. + return sizeof(njs_vmcode_3addr_t);
  1753. }
  1754.  
  1755.  
  1756. njs_ret_t
  1757. njs_vmcode_right_shift(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  1758. {
  1759. - int32_t num1;
  1760. - uint32_t num2;
  1761. -
  1762. - if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
  1763. -
  1764. - num1 = njs_number_to_int32(njs_number(val1));
  1765. - num2 = njs_number_to_uint32(njs_number(val2));
  1766. - njs_set_number(&vm->retval, num1 >> (num2 & 0x1f));
  1767. -
  1768. - return sizeof(njs_vmcode_3addr_t);
  1769. + int32_t num1;
  1770. + uint32_t num2;
  1771. + njs_ret_t ret;
  1772. + njs_value_t numeric1, numeric2;
  1773. +
  1774. + if (nxt_slow_path(!njs_is_numeric(val1))) {
  1775. + ret = njs_value_to_numeric(vm, &numeric1, val1);
  1776. + if (ret != NXT_OK) {
  1777. + return ret;
  1778. + }
  1779. +
  1780. + val1 = &numeric1;
  1781. }
  1782.  
  1783. - return njs_trap(vm, NJS_TRAP_NUMBERS);
  1784. + if (nxt_slow_path(!njs_is_numeric(val2))) {
  1785. + ret = njs_value_to_numeric(vm, &numeric2, val2);
  1786. + if (ret != NXT_OK) {
  1787. + return ret;
  1788. + }
  1789. +
  1790. + val2 = &numeric2;
  1791. + }
  1792. +
  1793. + num1 = njs_number_to_int32(njs_number(val1));
  1794. + num2 = njs_number_to_uint32(njs_number(val2));
  1795. + njs_set_number(&vm->retval, num1 >> (num2 & 0x1f));
  1796. +
  1797. + return sizeof(njs_vmcode_3addr_t);
  1798. }
  1799.  
  1800.  
  1801. @@ -1290,34 +1430,40 @@ njs_ret_t
  1802. njs_vmcode_unsigned_right_shift(njs_vm_t *vm, njs_value_t *val1,
  1803. njs_value_t *val2)
  1804. {
  1805. - uint32_t num1, num2;
  1806. -
  1807. - if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
  1808. -
  1809. - num1 = njs_number_to_uint32(njs_number(val1));
  1810. - num2 = njs_number_to_uint32(njs_number(val2));
  1811. - njs_set_number(&vm->retval, num1 >> (num2 & 0x1f));
  1812. -
  1813. - return sizeof(njs_vmcode_3addr_t);
  1814. + uint32_t num1, num2;
  1815. + njs_ret_t ret;
  1816. + njs_value_t numeric1, numeric2;
  1817. +
  1818. + if (nxt_slow_path(!njs_is_numeric(val1))) {
  1819. + ret = njs_value_to_numeric(vm, &numeric1, val1);
  1820. + if (ret != NXT_OK) {
  1821. + return ret;
  1822. + }
  1823. +
  1824. + val1 = &numeric1;
  1825. }
  1826.  
  1827. - return njs_trap(vm, NJS_TRAP_NUMBERS);
  1828. + if (nxt_slow_path(!njs_is_numeric(val2))) {
  1829. + ret = njs_value_to_numeric(vm, &numeric2, val2);
  1830. + if (ret != NXT_OK) {
  1831. + return ret;
  1832. + }
  1833. +
  1834. + val2 = &numeric2;
  1835. + }
  1836. +
  1837. + num1 = njs_number_to_uint32(njs_number(val1));
  1838. + num2 = njs_number_to_uint32(njs_number(val2));
  1839. + njs_set_number(&vm->retval, num1 >> (num2 & 0x1f));
  1840. +
  1841. + return sizeof(njs_vmcode_3addr_t);
  1842. }
  1843.  
  1844.  
  1845. njs_ret_t
  1846. njs_vmcode_logical_not(njs_vm_t *vm, njs_value_t *value, njs_value_t *inlvd)
  1847. {
  1848. - const njs_value_t *retval;
  1849. -
  1850. - if (njs_is_true(value)) {
  1851. - retval = &njs_value_false;
  1852. -
  1853. - } else {
  1854. - retval = &njs_value_true;
  1855. - }
  1856. -
  1857. - vm->retval = *retval;
  1858. + njs_set_boolean(&vm->retval, !njs_is_true(value));
  1859.  
  1860. return sizeof(njs_vmcode_2addr_t);
  1861. }
  1862. @@ -1358,85 +1504,133 @@ njs_vmcode_test_if_false(njs_vm_t *vm, n
  1863. njs_ret_t
  1864. njs_vmcode_bitwise_not(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld)
  1865. {
  1866. - int32_t num;
  1867. -
  1868. - if (nxt_fast_path(njs_is_numeric(value))) {
  1869. - num = njs_number_to_integer(njs_number(value));
  1870. - njs_set_number(&vm->retval, ~num);
  1871. -
  1872. - return sizeof(njs_vmcode_2addr_t);
  1873. + njs_ret_t ret;
  1874. + njs_value_t numeric;
  1875. +
  1876. + if (nxt_slow_path(!njs_is_numeric(value))) {
  1877. + ret = njs_value_to_numeric(vm, &numeric, value);
  1878. + if (ret != NXT_OK) {
  1879. + return ret;
  1880. + }
  1881. +
  1882. + value = &numeric;
  1883. }
  1884.  
  1885. - return njs_trap(vm, NJS_TRAP_NUMBER);
  1886. + njs_set_number(&vm->retval, ~njs_number_to_integer(njs_number(value)));
  1887. +
  1888. + return sizeof(njs_vmcode_2addr_t);
  1889. }
  1890.  
  1891.  
  1892. njs_ret_t
  1893. njs_vmcode_bitwise_and(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  1894. {
  1895. - int32_t num1, num2;
  1896. -
  1897. - if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
  1898. -
  1899. - num1 = njs_number_to_integer(njs_number(val1));
  1900. - num2 = njs_number_to_integer(njs_number(val2));
  1901. - njs_set_number(&vm->retval, num1 & num2);
  1902. -
  1903. - return sizeof(njs_vmcode_3addr_t);
  1904. + int32_t num1, num2;
  1905. + njs_ret_t ret;
  1906. + njs_value_t numeric1, numeric2;
  1907. +
  1908. + if (nxt_slow_path(!njs_is_numeric(val1))) {
  1909. + ret = njs_value_to_numeric(vm, &numeric1, val1);
  1910. + if (ret != NXT_OK) {
  1911. + return ret;
  1912. + }
  1913. +
  1914. + val1 = &numeric1;
  1915. }
  1916.  
  1917. - return njs_trap(vm, NJS_TRAP_NUMBERS);
  1918. + if (nxt_slow_path(!njs_is_numeric(val2))) {
  1919. + ret = njs_value_to_numeric(vm, &numeric2, val2);
  1920. + if (ret != NXT_OK) {
  1921. + return ret;
  1922. + }
  1923. +
  1924. + val2 = &numeric2;
  1925. + }
  1926. +
  1927. + num1 = njs_number_to_integer(njs_number(val1));
  1928. + num2 = njs_number_to_integer(njs_number(val2));
  1929. + njs_set_number(&vm->retval, num1 & num2);
  1930. +
  1931. + return sizeof(njs_vmcode_3addr_t);
  1932. }
  1933.  
  1934.  
  1935. njs_ret_t
  1936. njs_vmcode_bitwise_xor(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  1937. {
  1938. - int32_t num1, num2;
  1939. -
  1940. - if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
  1941. -
  1942. - num1 = njs_number_to_integer(njs_number(val1));
  1943. - num2 = njs_number_to_integer(njs_number(val2));
  1944. - njs_set_number(&vm->retval, num1 ^ num2);
  1945. -
  1946. - return sizeof(njs_vmcode_3addr_t);
  1947. + int32_t num1, num2;
  1948. + njs_ret_t ret;
  1949. + njs_value_t numeric1, numeric2;
  1950. +
  1951. + if (nxt_slow_path(!njs_is_numeric(val1))) {
  1952. + ret = njs_value_to_numeric(vm, &numeric1, val1);
  1953. + if (ret != NXT_OK) {
  1954. + return ret;
  1955. + }
  1956. +
  1957. + val1 = &numeric1;
  1958. }
  1959.  
  1960. - return njs_trap(vm, NJS_TRAP_NUMBERS);
  1961. + if (nxt_slow_path(!njs_is_numeric(val2))) {
  1962. + ret = njs_value_to_numeric(vm, &numeric2, val2);
  1963. + if (ret != NXT_OK) {
  1964. + return ret;
  1965. + }
  1966. +
  1967. + val2 = &numeric2;
  1968. + }
  1969. +
  1970. + num1 = njs_number_to_integer(njs_number(val1));
  1971. + num2 = njs_number_to_integer(njs_number(val2));
  1972. + njs_set_number(&vm->retval, num1 ^ num2);
  1973. +
  1974. + return sizeof(njs_vmcode_3addr_t);
  1975. }
  1976.  
  1977.  
  1978. njs_ret_t
  1979. njs_vmcode_bitwise_or(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  1980. {
  1981. - int32_t num1, num2;
  1982. -
  1983. - if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
  1984. -
  1985. - num1 = njs_number_to_uint32(njs_number(val1));
  1986. - num2 = njs_number_to_uint32(njs_number(val2));
  1987. - njs_set_number(&vm->retval, num1 | num2);
  1988. -
  1989. - return sizeof(njs_vmcode_3addr_t);
  1990. + int32_t num1, num2;
  1991. + njs_ret_t ret;
  1992. + njs_value_t numeric1, numeric2;
  1993. +
  1994. + if (nxt_slow_path(!njs_is_numeric(val1))) {
  1995. + ret = njs_value_to_numeric(vm, &numeric1, val1);
  1996. + if (ret != NXT_OK) {
  1997. + return ret;
  1998. + }
  1999. +
  2000. + val1 = &numeric1;
  2001. }
  2002.  
  2003. - return njs_trap(vm, NJS_TRAP_NUMBERS);
  2004. + if (nxt_slow_path(!njs_is_numeric(val2))) {
  2005. + ret = njs_value_to_numeric(vm, &numeric2, val2);
  2006. + if (ret != NXT_OK) {
  2007. + return ret;
  2008. + }
  2009. +
  2010. + val2 = &numeric2;
  2011. + }
  2012. +
  2013. + num1 = njs_number_to_integer(njs_number(val1));
  2014. + num2 = njs_number_to_integer(njs_number(val2));
  2015. + njs_set_number(&vm->retval, num1 | num2);
  2016. +
  2017. + return sizeof(njs_vmcode_3addr_t);
  2018. }
  2019.  
  2020.  
  2021. njs_ret_t
  2022. njs_vmcode_equal(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  2023. {
  2024. - njs_ret_t ret;
  2025. - const njs_value_t *retval;
  2026. + njs_ret_t ret;
  2027.  
  2028. ret = njs_values_equal(vm, val1, val2);
  2029.  
  2030. if (nxt_fast_path(ret >= 0)) {
  2031.  
  2032. - retval = (ret != 0) ? &njs_value_true : &njs_value_false;
  2033. - vm->retval = *retval;
  2034. + njs_set_boolean(&vm->retval, ret != 0);
  2035.  
  2036. return sizeof(njs_vmcode_3addr_t);
  2037. }
  2038. @@ -1466,10 +1660,14 @@ njs_vmcode_not_equal(njs_vm_t *vm, njs_v
  2039.  
  2040.  
  2041. static njs_ret_t
  2042. -njs_values_equal(njs_vm_t *vm, const njs_value_t *val1, const njs_value_t *val2)
  2043. +njs_values_equal(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  2044. {
  2045. - nxt_bool_t nv1, nv2;
  2046. - const njs_value_t *hv, *lv;
  2047. + njs_ret_t ret;
  2048. + nxt_bool_t nv1, nv2;
  2049. + njs_value_t primitive;
  2050. + njs_value_t *hv, *lv;
  2051. +
  2052. +again:
  2053.  
  2054. nv1 = njs_is_null_or_undefined(val1);
  2055. nv2 = njs_is_null_or_undefined(val2);
  2056. @@ -1515,22 +1713,29 @@ njs_values_equal(njs_vm_t *vm, const njs
  2057. }
  2058.  
  2059. /* "hv" is an object and "lv" is either a string or a numeric. */
  2060. - return njs_trap(vm, NJS_TRAP_COMPARISON);
  2061. +
  2062. + ret = njs_value_to_primitive(vm, &primitive, hv, 0);
  2063. + if (ret != NXT_OK) {
  2064. + return ret;
  2065. + }
  2066. +
  2067. + val1 = &primitive;
  2068. + val2 = lv;
  2069. +
  2070. + goto again;
  2071. }
  2072.  
  2073.  
  2074. njs_ret_t
  2075. njs_vmcode_less(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  2076. {
  2077. - njs_ret_t ret;
  2078. - const njs_value_t *retval;
  2079. + njs_ret_t ret;
  2080.  
  2081. ret = njs_values_compare(vm, val1, val2);
  2082.  
  2083. if (nxt_fast_path(ret >= -1)) {
  2084.  
  2085. - retval = (ret > 0) ? &njs_value_true : &njs_value_false;
  2086. - vm->retval = *retval;
  2087. + njs_set_boolean(&vm->retval, ret > 0);
  2088.  
  2089. return sizeof(njs_vmcode_3addr_t);
  2090. }
  2091. @@ -1556,15 +1761,13 @@ njs_vmcode_less_or_equal(njs_vm_t *vm, n
  2092. njs_ret_t
  2093. njs_vmcode_greater_or_equal(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  2094. {
  2095. - njs_ret_t ret;
  2096. - const njs_value_t *retval;
  2097. + njs_ret_t ret;
  2098.  
  2099. ret = njs_values_compare(vm, val1, val2);
  2100.  
  2101. if (nxt_fast_path(ret >= -1)) {
  2102.  
  2103. - retval = (ret == 0) ? &njs_value_true : &njs_value_false;
  2104. - vm->retval = *retval;
  2105. + njs_set_boolean(&vm->retval, ret == 0);
  2106.  
  2107. return sizeof(njs_vmcode_3addr_t);
  2108. }
  2109. @@ -1578,62 +1781,66 @@ njs_vmcode_greater_or_equal(njs_vm_t *vm
  2110. * njs_values_compare() returns
  2111. * 1 if val1 is less than val2,
  2112. * 0 if val1 is greater than or equal to val2,
  2113. - * -1 if the values are not comparable,
  2114. - * or negative trap number if convertion to primitive is required.
  2115. + * -1 if the values are not comparable.
  2116. */
  2117.  
  2118. static njs_ret_t
  2119. -njs_values_compare(njs_vm_t *vm, const njs_value_t *val1,
  2120. - const njs_value_t *val2)
  2121. +njs_values_compare(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  2122. {
  2123. - double num1, num2;
  2124. -
  2125. - if (nxt_fast_path(njs_is_primitive(val1) && njs_is_primitive(val2))) {
  2126. -
  2127. - if (nxt_fast_path(njs_is_numeric(val1))) {
  2128. - num1 = njs_number(val1);
  2129. -
  2130. - if (nxt_fast_path(njs_is_numeric(val2))) {
  2131. - num2 = njs_number(val2);
  2132. -
  2133. - } else {
  2134. - num2 = njs_string_to_number(val2, 0);
  2135. - }
  2136. -
  2137. - } else if (njs_is_numeric(val2)) {
  2138. - num1 = njs_string_to_number(val1, 0);
  2139. + double num1, num2;
  2140. + njs_ret_t ret;
  2141. + njs_value_t primitive1, primitive2;
  2142. +
  2143. + if (nxt_slow_path(!njs_is_primitive(val1))) {
  2144. + ret = njs_value_to_primitive(vm, &primitive1, val1, 0);
  2145. + if (ret != NXT_OK) {
  2146. + return ret;
  2147. + }
  2148. +
  2149. + val1 = &primitive1;
  2150. + }
  2151. +
  2152. + if (nxt_slow_path(!njs_is_primitive(val2))) {
  2153. + ret = njs_value_to_primitive(vm, &primitive2, val2, 0);
  2154. + if (ret != NXT_OK) {
  2155. + return ret;
  2156. + }
  2157. +
  2158. + val2 = &primitive2;
  2159. + }
  2160. +
  2161. + if (nxt_fast_path(njs_is_numeric(val1))) {
  2162. + num1 = njs_number(val1);
  2163. +
  2164. + if (nxt_fast_path(njs_is_numeric(val2))) {
  2165. num2 = njs_number(val2);
  2166.  
  2167. } else {
  2168. - return (njs_string_cmp(val1, val2) < 0) ? 1 : 0;
  2169. + num2 = njs_string_to_number(val2, 0);
  2170. }
  2171.  
  2172. - /* NaN and void values are not comparable with anything. */
  2173. - if (isnan(num1) || isnan(num2)) {
  2174. - return -1;
  2175. - }
  2176. -
  2177. - /* Infinities are handled correctly by comparision. */
  2178. - return (num1 < num2);
  2179. + } else if (njs_is_numeric(val2)) {
  2180. + num1 = njs_string_to_number(val1, 0);
  2181. + num2 = njs_number(val2);
  2182. +
  2183. + } else {
  2184. + return (njs_string_cmp(val1, val2) < 0) ? 1 : 0;
  2185. }
  2186.  
  2187. - return njs_trap(vm, NJS_TRAP_COMPARISON);
  2188. + /* NaN and void values are not comparable with anything. */
  2189. + if (isnan(num1) || isnan(num2)) {
  2190. + return -1;
  2191. + }
  2192. +
  2193. + /* Infinities are handled correctly by comparision. */
  2194. + return (num1 < num2);
  2195. }
  2196.  
  2197.  
  2198. njs_ret_t
  2199. njs_vmcode_strict_equal(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  2200. {
  2201. - const njs_value_t *retval;
  2202. -
  2203. - if (njs_values_strict_equal(val1, val2)) {
  2204. - retval = &njs_value_true;
  2205. -
  2206. - } else {
  2207. - retval = &njs_value_false;
  2208. - }
  2209. -
  2210. - vm->retval = *retval;
  2211. + njs_set_boolean(&vm->retval, njs_values_strict_equal(val1, val2));
  2212.  
  2213. return sizeof(njs_vmcode_3addr_t);
  2214. }
  2215. @@ -1642,16 +1849,7 @@ njs_vmcode_strict_equal(njs_vm_t *vm, nj
  2216. njs_ret_t
  2217. njs_vmcode_strict_not_equal(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
  2218. {
  2219. - const njs_value_t *retval;
  2220. -
  2221. - if (njs_values_strict_equal(val1, val2)) {
  2222. - retval = &njs_value_false;
  2223. -
  2224. - } else {
  2225. - retval = &njs_value_true;
  2226. - }
  2227. -
  2228. - vm->retval = *retval;
  2229. + njs_set_boolean(&vm->retval, !njs_values_strict_equal(val1, val2));
  2230.  
  2231. return sizeof(njs_vmcode_3addr_t);
  2232. }
  2233. @@ -1863,7 +2061,6 @@ njs_vmcode_method_frame(njs_vm_t *vm, nj
  2234. case NXT_DECLINED:
  2235. break;
  2236.  
  2237. - case NJS_TRAP:
  2238. case NXT_ERROR:
  2239. default:
  2240.  
  2241. @@ -1871,6 +2068,11 @@ njs_vmcode_method_frame(njs_vm_t *vm, nj
  2242. }
  2243.  
  2244. if (value == NULL || !njs_is_function(value)) {
  2245. + ret = njs_value_to_string(vm, name, name);
  2246. + if (nxt_slow_path(ret != NXT_OK)) {
  2247. + return NXT_ERROR;
  2248. + }
  2249. +
  2250. njs_string_get(name, &string);
  2251. njs_type_error(vm, "(intermediate value)[\"%V\"] is not a function",
  2252. &string);
  2253. @@ -1935,6 +2137,7 @@ njs_vmcode_function_call(njs_vm_t *vm, n
  2254. njs_ret_t
  2255. njs_vmcode_return(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval)
  2256. {
  2257. + uint8_t call;
  2258. njs_value_t *value;
  2259. njs_frame_t *frame;
  2260. njs_native_frame_t *previous;
  2261. @@ -1967,9 +2170,11 @@ njs_vmcode_return(njs_vm_t *vm, njs_valu
  2262.  
  2263. vm->current = frame->return_address;
  2264.  
  2265. + call = frame->native.call;
  2266. +
  2267. njs_function_frame_free(vm, &frame->native);
  2268.  
  2269. - return 0;
  2270. + return call ? NJS_STOP : 0;
  2271. }
  2272.  
  2273.  
  2274. @@ -2037,6 +2242,14 @@ const njs_vmcode_generic_t njs_continua
  2275. };
  2276.  
  2277.  
  2278. +const njs_vmcode_generic_t njs_stop[] = {
  2279. + { .code = { .operation = njs_vmcode_stop,
  2280. + .operands = NJS_VMCODE_1OPERAND,
  2281. + .retval = NJS_VMCODE_NO_RETVAL },
  2282. + .operand1 = NJS_INDEX_GLOBAL_RETVAL },
  2283. +};
  2284. +
  2285. +
  2286. static njs_ret_t
  2287. njs_vmcode_continuation(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
  2288. {
  2289. @@ -2289,384 +2502,6 @@ njs_vmcode_reference_error(njs_vm_t *vm,
  2290. }
  2291.  
  2292.  
  2293. -static const njs_vmcode_1addr_t njs_trap_number[] = {
  2294. - { .code = { .operation = njs_vmcode_number_primitive,
  2295. - .operands = NJS_VMCODE_1OPERAND,
  2296. - .retval = NJS_VMCODE_NO_RETVAL },
  2297. - .index = 0 },
  2298. - { .code = { .operation = njs_vmcode_restart,
  2299. - .operands = NJS_VMCODE_NO_OPERAND,
  2300. - .retval = NJS_VMCODE_NO_RETVAL } },
  2301. -};
  2302. -
  2303. -
  2304. -static const njs_vmcode_1addr_t njs_trap_numbers[] = {
  2305. - { .code = { .operation = njs_vmcode_number_primitive,
  2306. - .operands = NJS_VMCODE_1OPERAND,
  2307. - .retval = NJS_VMCODE_NO_RETVAL },
  2308. - .index = 0 },
  2309. - { .code = { .operation = njs_vmcode_number_primitive,
  2310. - .operands = NJS_VMCODE_1OPERAND,
  2311. - .retval = NJS_VMCODE_NO_RETVAL },
  2312. - .index = 1 },
  2313. - { .code = { .operation = njs_vmcode_restart,
  2314. - .operands = NJS_VMCODE_NO_OPERAND,
  2315. - .retval = NJS_VMCODE_NO_RETVAL } },
  2316. -};
  2317. -
  2318. -
  2319. -static const njs_vmcode_1addr_t njs_trap_addition[] = {
  2320. - { .code = { .operation = njs_vmcode_addition_primitive,
  2321. - .operands = NJS_VMCODE_1OPERAND,
  2322. - .retval = NJS_VMCODE_NO_RETVAL },
  2323. - .index = 0 },
  2324. - { .code = { .operation = njs_vmcode_addition_primitive,
  2325. - .operands = NJS_VMCODE_1OPERAND,
  2326. - .retval = NJS_VMCODE_NO_RETVAL },
  2327. - .index = 1 },
  2328. - { .code = { .operation = njs_vmcode_restart,
  2329. - .operands = NJS_VMCODE_NO_OPERAND,
  2330. - .retval = NJS_VMCODE_NO_RETVAL } },
  2331. -};
  2332. -
  2333. -
  2334. -static const njs_vmcode_1addr_t njs_trap_comparison[] = {
  2335. - { .code = { .operation = njs_vmcode_comparison_primitive,
  2336. - .operands = NJS_VMCODE_1OPERAND,
  2337. - .retval = NJS_VMCODE_NO_RETVAL },
  2338. - .index = 0 },
  2339. - { .code = { .operation = njs_vmcode_comparison_primitive,
  2340. - .operands = NJS_VMCODE_1OPERAND,
  2341. - .retval = NJS_VMCODE_NO_RETVAL },
  2342. - .index = 1 },
  2343. - { .code = { .operation = njs_vmcode_restart,
  2344. - .operands = NJS_VMCODE_NO_OPERAND,
  2345. - .retval = NJS_VMCODE_NO_RETVAL } },
  2346. -};
  2347. -
  2348. -
  2349. -static const njs_vmcode_1addr_t njs_trap_property[] = {
  2350. - { .code = { .operation = njs_vmcode_string_primitive,
  2351. - .operands = NJS_VMCODE_1OPERAND,
  2352. - .retval = NJS_VMCODE_NO_RETVAL },
  2353. - .index = 1 },
  2354. - { .code = { .operation = njs_vmcode_restart,
  2355. - .operands = NJS_VMCODE_NO_OPERAND,
  2356. - .retval = NJS_VMCODE_NO_RETVAL } },
  2357. -};
  2358. -
  2359. -
  2360. -static const njs_vmcode_1addr_t njs_trap_number_argument = {
  2361. - .code = { .operation = njs_vmcode_number_argument,
  2362. - .operands = NJS_VMCODE_NO_OPERAND,
  2363. - .retval = NJS_VMCODE_NO_RETVAL }
  2364. -};
  2365. -
  2366. -
  2367. -static const njs_vmcode_1addr_t njs_trap_string_argument = {
  2368. - .code = { .operation = njs_vmcode_string_argument,
  2369. - .operands = NJS_VMCODE_NO_OPERAND,
  2370. - .retval = NJS_VMCODE_NO_RETVAL }
  2371. -};
  2372. -
  2373. -
  2374. -static const njs_vmcode_1addr_t njs_trap_primitive_argument = {
  2375. - .code = { .operation = njs_vmcode_primitive_argument,
  2376. - .operands = NJS_VMCODE_NO_OPERAND,
  2377. - .retval = NJS_VMCODE_NO_RETVAL }
  2378. -};
  2379. -
  2380. -
  2381. -static const njs_vm_trap_t njs_vm_traps[] = {
  2382. - /* NJS_TRAP_NUMBER */ { .code = &njs_trap_number[0] },
  2383. - /* NJS_TRAP_NUMBERS */ { .code = &njs_trap_numbers[0] },
  2384. - /* NJS_TRAP_ADDITION */ { .code = &njs_trap_addition[0] },
  2385. - /* NJS_TRAP_COMPARISON */ { .code = &njs_trap_comparison[0] },
  2386. - /* NJS_TRAP_INCDEC */ { .code = &njs_trap_numbers[1],
  2387. - .reference = 1 },
  2388. - /* NJS_TRAP_PROPERTY */ { .code = &njs_trap_property[0] },
  2389. - /* NJS_TRAP_NUMBER_ARG */ { .code = &njs_trap_number_argument },
  2390. - /* NJS_TRAP_STRING_ARG */ { .code = &njs_trap_string_argument },
  2391. - /* NJS_TRAP_PRIMITIVE_ARG */ { .code = &njs_trap_primitive_argument },
  2392. -};
  2393. -
  2394. -
  2395. -static void
  2396. -njs_vm_trap(njs_vm_t *vm, njs_trap_t trap, njs_value_t *value1,
  2397. - njs_value_t *value2)
  2398. -{
  2399. - njs_native_frame_t *frame;
  2400. -
  2401. - frame = vm->top_frame;
  2402. -
  2403. - /*
  2404. - * The trap_scratch value is for results of "valueOf" and "toString"
  2405. - * methods. The trap_values[] are original operand values which will
  2406. - * be replaced with primitive values returned by "valueOf" or "toString"
  2407. - * methods. The scratch value is stored separately to preserve the
  2408. - * original operand values for the second method call if the first
  2409. - * method call will return non-primitive value.
  2410. - */
  2411. - njs_set_invalid(&frame->trap_scratch);
  2412. - frame->trap_values[1] = *value2;
  2413. - frame->trap_reference = njs_vm_traps[trap].reference;
  2414. -
  2415. - if (njs_vm_traps[trap].reference) {
  2416. - frame->trap_values[0].data.u.value = value1;
  2417. -
  2418. - } else {
  2419. - frame->trap_values[0] = *value1;
  2420. - }
  2421. -
  2422. - frame->trap_restart = vm->current;
  2423. - vm->current = (u_char *) njs_vm_traps[trap].code;
  2424. -}
  2425. -
  2426. -
  2427. -static void
  2428. -njs_vm_trap_argument(njs_vm_t *vm, njs_trap_t trap)
  2429. -{
  2430. - njs_value_t *value;
  2431. - njs_native_frame_t *frame;
  2432. -
  2433. - frame = vm->top_frame;
  2434. - value = frame->trap_scratch.data.u.value;
  2435. - njs_set_invalid(&frame->trap_scratch);
  2436. -
  2437. - frame->trap_values[1].data.u.value = value;
  2438. - frame->trap_values[0] = *value;
  2439. -
  2440. - frame->trap_restart = vm->current;
  2441. - vm->current = (u_char *) njs_vm_traps[trap].code;
  2442. -}
  2443. -
  2444. -
  2445. -static njs_ret_t
  2446. -njs_vmcode_number_primitive(njs_vm_t *vm, njs_value_t *invld, njs_value_t *narg)
  2447. -{
  2448. - double num;
  2449. - njs_ret_t ret;
  2450. - njs_value_t *value;
  2451. -
  2452. - value = &vm->top_frame->trap_values[(uintptr_t) narg];
  2453. -
  2454. - ret = njs_value_to_primitive(vm, value, 0);
  2455. -
  2456. - if (nxt_fast_path(ret > 0)) {
  2457. -
  2458. - if (!njs_is_numeric(value)) {
  2459. - num = NAN;
  2460. -
  2461. - if (njs_is_string(value)) {
  2462. - num = njs_string_to_number(value, 0);
  2463. - }
  2464. -
  2465. - njs_set_number(value, num);
  2466. - }
  2467. -
  2468. - ret = sizeof(njs_vmcode_1addr_t);
  2469. - }
  2470. -
  2471. - return ret;
  2472. -}
  2473. -
  2474. -
  2475. -static njs_ret_t
  2476. -njs_vmcode_string_primitive(njs_vm_t *vm, njs_value_t *invld, njs_value_t *narg)
  2477. -{
  2478. - njs_ret_t ret;
  2479. - njs_value_t *value;
  2480. -
  2481. - value = &vm->top_frame->trap_values[(uintptr_t) narg];
  2482. -
  2483. - ret = njs_value_to_primitive(vm, value, 1);
  2484. -
  2485. - if (nxt_fast_path(ret > 0)) {
  2486. - ret = njs_primitive_value_to_string(vm, value, value);
  2487. -
  2488. - if (nxt_fast_path(ret == NXT_OK)) {
  2489. - return sizeof(njs_vmcode_1addr_t);
  2490. - }
  2491. - }
  2492. -
  2493. - return ret;
  2494. -}
  2495. -
  2496. -
  2497. -static njs_ret_t
  2498. -njs_vmcode_addition_primitive(njs_vm_t *vm, njs_value_t *invld,
  2499. - njs_value_t *narg)
  2500. -{
  2501. - njs_ret_t ret;
  2502. - nxt_uint_t hint;
  2503. - njs_value_t *value;
  2504. -
  2505. - value = &vm->top_frame->trap_values[(uintptr_t) narg];
  2506. -
  2507. - /*
  2508. - * ECMAScript 5.1:
  2509. - * Date should return String, other types sould return Number.
  2510. - */
  2511. - hint = njs_is_date(value);
  2512. -
  2513. - ret = njs_value_to_primitive(vm, value, hint);
  2514. -
  2515. - if (nxt_fast_path(ret > 0)) {
  2516. - return sizeof(njs_vmcode_1addr_t);
  2517. - }
  2518. -
  2519. - return ret;
  2520. -}
  2521. -
  2522. -
  2523. -static njs_ret_t
  2524. -njs_vmcode_comparison_primitive(njs_vm_t *vm, njs_value_t *invld,
  2525. - njs_value_t *narg)
  2526. -{
  2527. - njs_ret_t ret;
  2528. - njs_value_t *value;
  2529. -
  2530. - value = &vm->top_frame->trap_values[(uintptr_t) narg];
  2531. -
  2532. - ret = njs_value_to_primitive(vm, value, 0);
  2533. -
  2534. - if (nxt_fast_path(ret > 0)) {
  2535. - return sizeof(njs_vmcode_1addr_t);
  2536. - }
  2537. -
  2538. - return ret;
  2539. -}
  2540. -
  2541. -
  2542. -static njs_ret_t
  2543. -njs_vmcode_number_argument(njs_vm_t *vm, njs_value_t *invld1,
  2544. - njs_value_t *inlvd2)
  2545. -{
  2546. - double num;
  2547. - njs_ret_t ret;
  2548. - njs_value_t *value;
  2549. -
  2550. - value = &vm->top_frame->trap_values[0];
  2551. -
  2552. - ret = njs_value_to_primitive(vm, value, 0);
  2553. -
  2554. - if (nxt_fast_path(ret > 0)) {
  2555. -
  2556. - if (!njs_is_numeric(value)) {
  2557. - num = NAN;
  2558. -
  2559. - if (njs_is_string(value)) {
  2560. - num = njs_string_to_number(value, 0);
  2561. - }
  2562. -
  2563. - njs_set_number(value, num);
  2564. - }
  2565. -
  2566. - *vm->top_frame->trap_values[1].data.u.value = *value;
  2567. -
  2568. - vm->current = vm->top_frame->trap_restart;
  2569. - vm->top_frame->trap_restart = NULL;
  2570. -
  2571. - return 0;
  2572. - }
  2573. -
  2574. - return ret;
  2575. -}
  2576. -
  2577. -
  2578. -static njs_ret_t
  2579. -njs_vmcode_string_argument(njs_vm_t *vm, njs_value_t *invld1,
  2580. - njs_value_t *inlvd2)
  2581. -{
  2582. - njs_ret_t ret;
  2583. - njs_value_t *value;
  2584. -
  2585. - value = &vm->top_frame->trap_values[0];
  2586. -
  2587. - ret = njs_value_to_primitive(vm, value, 1);
  2588. -
  2589. - if (nxt_fast_path(ret > 0)) {
  2590. - ret = njs_primitive_value_to_string(vm, value, value);
  2591. -
  2592. - if (nxt_fast_path(ret == NXT_OK)) {
  2593. - *vm->top_frame->trap_values[1].data.u.value = *value;
  2594. -
  2595. - vm->current = vm->top_frame->trap_restart;
  2596. - vm->top_frame->trap_restart = NULL;
  2597. - }
  2598. - }
  2599. -
  2600. - return ret;
  2601. -}
  2602. -
  2603. -
  2604. -static njs_ret_t
  2605. -njs_vmcode_primitive_argument(njs_vm_t *vm, njs_value_t *invld1,
  2606. - njs_value_t *inlvd2)
  2607. -{
  2608. - njs_ret_t ret;
  2609. - njs_value_t *value;
  2610. -
  2611. - value = &vm->top_frame->trap_values[0];
  2612. -
  2613. - ret = njs_value_to_primitive(vm, value, 0);
  2614. -
  2615. - if (nxt_fast_path(ret > 0)) {
  2616. - *vm->top_frame->trap_values[1].data.u.value = *value;
  2617. -
  2618. - vm->current = vm->top_frame->trap_restart;
  2619. - vm->top_frame->trap_restart = NULL;
  2620. -
  2621. - return 0;
  2622. - }
  2623. -
  2624. - return ret;
  2625. -}
  2626. -
  2627. -
  2628. -static njs_ret_t
  2629. -njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
  2630. -{
  2631. - u_char *restart;
  2632. - njs_ret_t ret;
  2633. - njs_value_t *retval, *value1;
  2634. - njs_native_frame_t *frame;
  2635. - njs_vmcode_generic_t *vmcode;
  2636. -
  2637. - frame = vm->top_frame;
  2638. - restart = frame->trap_restart;
  2639. - frame->trap_restart = NULL;
  2640. - vm->current = restart;
  2641. - vmcode = (njs_vmcode_generic_t *) restart;
  2642. -
  2643. - value1 = &frame->trap_values[0];
  2644. -
  2645. - if (frame->trap_reference) {
  2646. - value1 = value1->data.u.value;
  2647. - }
  2648. -
  2649. - ret = vmcode->code.operation(vm, value1, &frame->trap_values[1]);
  2650. -
  2651. - if (nxt_slow_path(ret == NJS_ERROR)) {
  2652. - return ret;
  2653. - }
  2654. -
  2655. - if (nxt_slow_path(ret == NJS_TRAP)) {
  2656. - /* Trap handlers are not reentrant. */
  2657. - njs_internal_error(vm, "trap inside restart instruction");
  2658. - return NXT_ERROR;
  2659. - }
  2660. -
  2661. - if (vmcode->code.retval) {
  2662. - retval = njs_vmcode_operand(vm, vmcode->operand1);
  2663. - njs_release(vm, retval);
  2664. - *retval = vm->retval;
  2665. - }
  2666. -
  2667. - return ret;
  2668. -}
  2669. -
  2670. -
  2671. njs_ret_t
  2672. njs_vm_value_to_string(njs_vm_t *vm, nxt_str_t *dst, const njs_value_t *src)
  2673. {
  2674. @@ -2689,14 +2524,7 @@ njs_vm_value_to_string(njs_vm_t *vm, nxt
  2675.  
  2676. value = *src;
  2677.  
  2678. - if (nxt_slow_path(!njs_is_primitive(&value))) {
  2679. - ret = njs_object_value_to_string(vm, &value);
  2680. - if (nxt_slow_path(ret != NXT_OK)) {
  2681. - return ret;
  2682. - }
  2683. - }
  2684. -
  2685. - ret = njs_primitive_value_to_string(vm, &value, &value);
  2686. + ret = njs_value_to_string(vm, &value, &value);
  2687.  
  2688. if (nxt_fast_path(ret == NXT_OK)) {
  2689. size = value.short_string.size;
  2690. @@ -2723,73 +2551,6 @@ njs_vm_value_to_string(njs_vm_t *vm, nxt
  2691. }
  2692.  
  2693.  
  2694. -static njs_ret_t
  2695. -njs_object_value_to_string(njs_vm_t *vm, njs_value_t *value)
  2696. -{
  2697. - u_char *current;
  2698. - njs_ret_t ret;
  2699. - njs_native_frame_t *previous;
  2700. -
  2701. - static const njs_vmcode_1addr_t value_to_string[] = {
  2702. - { .code = { .operation = njs_vmcode_value_to_string,
  2703. - .operands = NJS_VMCODE_NO_OPERAND,
  2704. - .retval = NJS_VMCODE_NO_RETVAL } },
  2705. - };
  2706. -
  2707. - /*
  2708. - * Execute the single njs_vmcode_value_to_string() instruction.
  2709. - * The trap_scratch value is for results of "toString" or "valueOf"
  2710. - * methods. The trap_values[0] is an original object value which will
  2711. - * be replaced with primitive value returned by "toString" or "valueOf"
  2712. - * methods. The scratch value is stored separately to preserve the
  2713. - * original object value for the second "valueOf" method call if the
  2714. - * first "toString" method call will return non-primitive value.
  2715. - */
  2716. -
  2717. - current = vm->current;
  2718. - vm->current = (u_char *) value_to_string;
  2719. -
  2720. - njs_set_invalid(&vm->top_frame->trap_scratch);
  2721. - vm->top_frame->trap_values[0] = *value;
  2722. -
  2723. - /*
  2724. - * Prevent njs_vmcode_interpreter() to unwind the current frame if
  2725. - * an exception happens. It preserves the current frame state if
  2726. - * njs_vm_value_string() is called from within njs_vm_run().
  2727. - */
  2728. - previous = vm->top_frame->previous;
  2729. - vm->top_frame->previous = NULL;
  2730. -
  2731. - ret = njs_vmcode_interpreter(vm);
  2732. -
  2733. - if (ret == NJS_STOP) {
  2734. - ret = NXT_OK;
  2735. - *value = vm->top_frame->trap_values[0];
  2736. - }
  2737. -
  2738. - vm->current = current;
  2739. - vm->top_frame->previous = previous;
  2740. -
  2741. - return ret;
  2742. -}
  2743. -
  2744. -
  2745. -static njs_ret_t
  2746. -njs_vmcode_value_to_string(njs_vm_t *vm, njs_value_t *invld1,
  2747. - njs_value_t *invld2)
  2748. -{
  2749. - njs_ret_t ret;
  2750. -
  2751. - ret = njs_value_to_primitive(vm, &vm->top_frame->trap_values[0], 1);
  2752. -
  2753. - if (nxt_fast_path(ret > 0)) {
  2754. - return NJS_STOP;
  2755. - }
  2756. -
  2757. - return ret;
  2758. -}
  2759. -
  2760. -
  2761. nxt_int_t
  2762. njs_vm_value_string_copy(njs_vm_t *vm, nxt_str_t *retval,
  2763. const njs_value_t *value, uintptr_t *next)
  2764. diff --git a/njs/njs_vm.h b/njs/njs_vm.h
  2765. --- a/njs/njs_vm.h
  2766. +++ b/njs/njs_vm.h
  2767. @@ -19,33 +19,14 @@
  2768. * -3: not used;
  2769. * -4 (NJS_STOP/NXT_DONE): njs_vmcode_stop() has stopped execution,
  2770. * execution has completed successfully;
  2771. - * -5 (NJS_TRAP) trap to convert objects to primitive values;
  2772. - * -6 .. -11: not used.
  2773. + * -5 .. -11: not used.
  2774. */
  2775.  
  2776. #define NJS_STOP NXT_DONE
  2777. -#define NJS_TRAP (-5)
  2778.  
  2779. /* The last return value which preempts execution. */
  2780. #define NJS_PREEMPT (-11)
  2781.  
  2782. -/* Traps events. */
  2783. -typedef enum {
  2784. - NJS_TRAP_NUMBER = 0,
  2785. - NJS_TRAP_NUMBERS,
  2786. - NJS_TRAP_ADDITION,
  2787. - NJS_TRAP_COMPARISON,
  2788. - NJS_TRAP_INCDEC,
  2789. - NJS_TRAP_PROPERTY,
  2790. - NJS_TRAP_NUMBER_ARG,
  2791. - NJS_TRAP_STRING_ARG,
  2792. - NJS_TRAP_PRIMITIVE_ARG,
  2793. -} njs_trap_t;
  2794. -
  2795. -
  2796. -#define njs_trap(vm, code) \
  2797. - vm->trap = code, NJS_TRAP;
  2798. -
  2799.  
  2800. /*
  2801. * A user-defined function is prepared to run. This code is never
  2802. @@ -532,12 +513,6 @@ enum njs_function_e {
  2803.  
  2804.  
  2805. typedef struct {
  2806. - const njs_vmcode_1addr_t *code;
  2807. - nxt_bool_t reference;
  2808. -} njs_vm_trap_t;
  2809. -
  2810. -
  2811. -typedef struct {
  2812. uint32_t line;
  2813. nxt_str_t file;
  2814. nxt_str_t name;
  2815. @@ -549,6 +524,8 @@ struct njs_vm_s {
  2816. /* njs_vm_t must be aligned to njs_value_t due to scratch value. */
  2817. njs_value_t retval;
  2818.  
  2819. + nxt_uint_t count;
  2820. +
  2821. nxt_array_t *paths;
  2822.  
  2823. u_char *current;
  2824. @@ -613,8 +590,6 @@ struct njs_vm_s {
  2825. nxt_array_t *debug;
  2826. nxt_array_t *backtrace;
  2827.  
  2828. - njs_trap_t trap:8;
  2829. -
  2830. /*
  2831. * njs_property_query() uses it to store reference to a temporary
  2832. * PROPERTY_HANDLERs for NJS_EXTERNAL values in NJS_PROPERTY_QUERY_SET
  2833. @@ -659,6 +634,7 @@ struct njs_vm_shared_s {
  2834.  
  2835.  
  2836. nxt_int_t njs_vmcode_interpreter(njs_vm_t *vm);
  2837. +nxt_int_t njs_vmcode_run(njs_vm_t *vm);
  2838.  
  2839. njs_ret_t njs_vmcode_object(njs_vm_t *vm, njs_value_t *inlvd1,
  2840. njs_value_t *inlvd2);
  2841. @@ -821,6 +797,7 @@ extern const nxt_mem_proto_t njs_arr
  2842. extern const nxt_lvlhsh_proto_t njs_object_hash_proto;
  2843.  
  2844. extern const njs_vmcode_generic_t njs_continuation_nexus[];
  2845. +extern const njs_vmcode_generic_t njs_stop[];
  2846.  
  2847.  
  2848. #endif /* _NJS_VM_H_INCLUDED_ */
  2849. diff --git a/njs/test/njs_interactive_test.c b/njs/test/njs_interactive_test.c
  2850. --- a/njs/test/njs_interactive_test.c
  2851. +++ b/njs/test/njs_interactive_test.c
  2852. @@ -230,8 +230,7 @@ static njs_interactive_test_t njs_test[
  2853.  
  2854. { nxt_string("var o = { toString: function() { return [1] } }" ENTER
  2855. "o" ENTER),
  2856. - nxt_string("TypeError: Cannot convert object to primitive value\n"
  2857. - " at main (native)\n") },
  2858. + nxt_string("TypeError: Cannot convert object to primitive value") },
  2859.  
  2860. /* line numbers */
  2861.  
  2862. diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c
  2863. --- a/njs/test/njs_unit_test.c
  2864. +++ b/njs/test/njs_unit_test.c
  2865. @@ -450,6 +450,49 @@ static njs_unit_test_t njs_test[] =
  2866. "var b = { toString: function() { return a+'b' } }; '0'+b"),
  2867. nxt_string("0ab") },
  2868.  
  2869. + { nxt_string("({valueOf:()=>'4'}) / ({valueOf:()=>2})"),
  2870. + nxt_string("2") },
  2871. +
  2872. + { nxt_string("({valueOf:()=>{throw 'x'}}) / ({valueOf:()=>{throw 'y'}});"
  2873. + "var e; try { x/y } catch(ex) {e = ex}; ex"),
  2874. + nxt_string("x") },
  2875. +
  2876. + { nxt_string("({valueOf:()=>2}) / ({valueOf:()=>{throw 'y'}});"
  2877. + "var e; try { x/y } catch(ex) {e = ex}; ex"),
  2878. + nxt_string("y") },
  2879. +
  2880. + { nxt_string("({valueOf:()=>'4'}) % ({valueOf:()=>3})"),
  2881. + nxt_string("1") },
  2882. +
  2883. + { nxt_string("({valueOf:()=>9}) >>> ({valueOf:()=>2})"),
  2884. + nxt_string("2") },
  2885. +
  2886. + { nxt_string("({valueOf:()=>0x1f}) & ({valueOf:()=>0xf})"),
  2887. + nxt_string("15") },
  2888. +
  2889. + { nxt_string("({valueOf:()=>0x1f}) ^ ({valueOf:()=>0xf})"),
  2890. + nxt_string("16") },
  2891. +
  2892. + { nxt_string("({valueOf:()=>0xf}) == ({valueOf:()=>0xf})"),
  2893. + nxt_string("false") },
  2894. +
  2895. + { nxt_string("({valueOf:()=>0xf}) == 0xf"),
  2896. + nxt_string("true") },
  2897. +
  2898. + { nxt_string("0xf == ({valueOf:()=>0xf})"),
  2899. + nxt_string("true") },
  2900. +
  2901. + { nxt_string("({valueOf:()=>'0xf'}) == 0xf"),
  2902. + nxt_string("true") },
  2903. +
  2904. + { nxt_string("0xf == ({valueOf:()=>'0xf'})"),
  2905. + nxt_string("true") },
  2906. +
  2907. + { nxt_string("({valueOf:()=>0xf}) == '0xf'"),
  2908. + nxt_string("true") },
  2909. +
  2910. + { nxt_string("'0xf' == ({valueOf:()=>0xf})"),
  2911. + nxt_string("true") },
  2912. /**/
  2913.  
  2914. { nxt_string("1 + undefined"),
  2915. @@ -1648,6 +1691,9 @@ static njs_unit_test_t njs_test[] =
  2916. { nxt_string("new 0[isNaN]"),
  2917. nxt_string("TypeError: (intermediate value)[\"[object Function]\"] is not a function") },
  2918.  
  2919. + { nxt_string("new 0[undefined]"),
  2920. + nxt_string("TypeError: (intermediate value)[\"undefined\"] is not a function") },
  2921. +
  2922. /**/
  2923.  
  2924. { nxt_string("var a; a = 1 ? 2 : 3"),
  2925. @@ -4766,6 +4812,9 @@ static njs_unit_test_t njs_test[] =
  2926. { nxt_string("String.prototype.substring(1, 5)"),
  2927. nxt_string("") },
  2928.  
  2929. + { nxt_string("String.prototype.substr.call({toString:()=>{throw new Error('Oops')}})"),
  2930. + nxt_string("Error: Oops") },
  2931. +
  2932. { nxt_string("String.prototype.slice(1, 5)"),
  2933. nxt_string("") },
  2934.  
  2935. @@ -6418,6 +6467,9 @@ static njs_unit_test_t njs_test[] =
  2936. { nxt_string("(function(){ function f() {return f}; return f()})()"),
  2937. nxt_string("[object Function]") },
  2938.  
  2939. + { nxt_string("function f() {}; f.toString = ()=> 'F'; ({'F':1})[f]"),
  2940. + nxt_string("1") },
  2941. +
  2942. { nxt_string("var a = ''; "
  2943. "function f(list) {"
  2944. " function add(v) {a+=v};"
  2945. @@ -10324,6 +10376,9 @@ static njs_unit_test_t njs_test[] =
  2946. { nxt_string("Date.UTC(2011, 5, 24, 6, 0)"),
  2947. nxt_string("1308895200000") },
  2948.  
  2949. + { nxt_string("Date.UTC({valueOf:()=>2011}, 5, 24, 6, 0)"),
  2950. + nxt_string("1308895200000") },
  2951. +
  2952. { nxt_string("Date.parse()"),
  2953. nxt_string("NaN") },
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement