PageRenderTime 64ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/erts/emulator/beam/erl_bif_guard.c

https://github.com/Bwooce/otp
C | 669 lines | 539 code | 68 blank | 62 comment | 113 complexity | be60709ddc38fd8cfaaa78548c13cee1 MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-2-Clause
  1. /*
  2. * %CopyrightBegin%
  3. *
  4. * Copyright Ericsson AB 2006-2010. All Rights Reserved.
  5. *
  6. * The contents of this file are subject to the Erlang Public License,
  7. * Version 1.1, (the "License"); you may not use this file except in
  8. * compliance with the License. You should have received a copy of the
  9. * Erlang Public License along with this software. If not, it can be
  10. * retrieved online at http://www.erlang.org/.
  11. *
  12. * Software distributed under the License is distributed on an "AS IS"
  13. * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  14. * the License for the specific language governing rights and limitations
  15. * under the License.
  16. *
  17. * %CopyrightEnd%
  18. */
  19. /*
  20. * Numeric guard BIFs.
  21. */
  22. #ifdef HAVE_CONFIG_H
  23. # include "config.h"
  24. #endif
  25. #include "sys.h"
  26. #include "erl_vm.h"
  27. #include "global.h"
  28. #include "erl_process.h"
  29. #include "error.h"
  30. #include "bif.h"
  31. #include "big.h"
  32. #include "erl_binary.h"
  33. static Eterm gc_double_to_integer(Process* p, double x, Eterm* reg, Uint live);
  34. static Eterm double_to_integer(Process* p, double x);
  35. /*
  36. * Guard BIFs called using apply/3 and guard BIFs that never build
  37. * anything on the heap.
  38. */
  39. BIF_RETTYPE abs_1(BIF_ALIST_1)
  40. {
  41. Eterm res;
  42. Sint i0, i;
  43. Eterm* hp;
  44. /* integer arguments */
  45. if (is_small(BIF_ARG_1)) {
  46. i0 = signed_val(BIF_ARG_1);
  47. i = labs(i0);
  48. if (i0 == MIN_SMALL) {
  49. hp = HAlloc(BIF_P, BIG_UINT_HEAP_SIZE);
  50. BIF_RET(uint_to_big(i, hp));
  51. } else {
  52. BIF_RET(make_small(i));
  53. }
  54. } else if (is_big(BIF_ARG_1)) {
  55. if (!big_sign(BIF_ARG_1)) {
  56. BIF_RET(BIF_ARG_1);
  57. } else {
  58. int sz = big_arity(BIF_ARG_1) + 1;
  59. Uint* x;
  60. hp = HAlloc(BIF_P, sz); /* See note at beginning of file */
  61. sz--;
  62. res = make_big(hp);
  63. x = big_val(BIF_ARG_1);
  64. *hp++ = make_pos_bignum_header(sz);
  65. x++; /* skip thing */
  66. while(sz--)
  67. *hp++ = *x++;
  68. BIF_RET(res);
  69. }
  70. } else if (is_float(BIF_ARG_1)) {
  71. FloatDef f;
  72. GET_DOUBLE(BIF_ARG_1, f);
  73. if (f.fd < 0.0) {
  74. hp = HAlloc(BIF_P, FLOAT_SIZE_OBJECT);
  75. f.fd = fabs(f.fd);
  76. res = make_float(hp);
  77. PUT_DOUBLE(f, hp);
  78. BIF_RET(res);
  79. }
  80. else
  81. BIF_RET(BIF_ARG_1);
  82. }
  83. BIF_ERROR(BIF_P, BADARG);
  84. }
  85. BIF_RETTYPE float_1(BIF_ALIST_1)
  86. {
  87. Eterm res;
  88. Eterm* hp;
  89. FloatDef f;
  90. /* check args */
  91. if (is_not_integer(BIF_ARG_1)) {
  92. if (is_float(BIF_ARG_1)) {
  93. BIF_RET(BIF_ARG_1);
  94. } else {
  95. badarg:
  96. BIF_ERROR(BIF_P, BADARG);
  97. }
  98. }
  99. if (is_small(BIF_ARG_1)) {
  100. Sint i = signed_val(BIF_ARG_1);
  101. f.fd = i; /* use "C"'s auto casting */
  102. } else if (big_to_double(BIF_ARG_1, &f.fd) < 0) {
  103. goto badarg;
  104. }
  105. hp = HAlloc(BIF_P, FLOAT_SIZE_OBJECT);
  106. res = make_float(hp);
  107. PUT_DOUBLE(f, hp);
  108. BIF_RET(res);
  109. }
  110. BIF_RETTYPE trunc_1(BIF_ALIST_1)
  111. {
  112. Eterm res;
  113. FloatDef f;
  114. /* check arg */
  115. if (is_not_float(BIF_ARG_1)) {
  116. if (is_integer(BIF_ARG_1))
  117. BIF_RET(BIF_ARG_1);
  118. BIF_ERROR(BIF_P, BADARG);
  119. }
  120. /* get the float */
  121. GET_DOUBLE(BIF_ARG_1, f);
  122. /* truncate it and return the resultant integer */
  123. res = double_to_integer(BIF_P, (f.fd >= 0.0) ? floor(f.fd) : ceil(f.fd));
  124. BIF_RET(res);
  125. }
  126. BIF_RETTYPE round_1(BIF_ALIST_1)
  127. {
  128. Eterm res;
  129. FloatDef f;
  130. /* check arg */
  131. if (is_not_float(BIF_ARG_1)) {
  132. if (is_integer(BIF_ARG_1))
  133. BIF_RET(BIF_ARG_1);
  134. BIF_ERROR(BIF_P, BADARG);
  135. }
  136. /* get the float */
  137. GET_DOUBLE(BIF_ARG_1, f);
  138. /* round it and return the resultant integer */
  139. res = double_to_integer(BIF_P, (f.fd > 0.0) ? f.fd + 0.5 : f.fd - 0.5);
  140. BIF_RET(res);
  141. }
  142. BIF_RETTYPE length_1(BIF_ALIST_1)
  143. {
  144. Eterm list;
  145. Uint i;
  146. if (is_nil(BIF_ARG_1))
  147. BIF_RET(SMALL_ZERO);
  148. if (is_not_list(BIF_ARG_1)) {
  149. BIF_ERROR(BIF_P, BADARG);
  150. }
  151. list = BIF_ARG_1;
  152. i = 0;
  153. while (is_list(list)) {
  154. i++;
  155. list = CDR(list_val(list));
  156. }
  157. if (is_not_nil(list)) {
  158. BIF_ERROR(BIF_P, BADARG);
  159. }
  160. BIF_RET(make_small(i));
  161. }
  162. /* returns the size of a tuple or a binary */
  163. BIF_RETTYPE size_1(BIF_ALIST_1)
  164. {
  165. if (is_tuple(BIF_ARG_1)) {
  166. Eterm* tupleptr = tuple_val(BIF_ARG_1);
  167. BIF_RET(make_small(arityval(*tupleptr)));
  168. } else if (is_binary(BIF_ARG_1)) {
  169. Uint sz = binary_size(BIF_ARG_1);
  170. if (IS_USMALL(0, sz)) {
  171. return make_small(sz);
  172. } else {
  173. Eterm* hp = HAlloc(BIF_P, BIG_UINT_HEAP_SIZE);
  174. BIF_RET(uint_to_big(sz, hp));
  175. }
  176. }
  177. BIF_ERROR(BIF_P, BADARG);
  178. }
  179. /**********************************************************************/
  180. /* returns the bitsize of a bitstring */
  181. BIF_RETTYPE bit_size_1(BIF_ALIST_1)
  182. {
  183. Uint low_bits;
  184. Uint bytesize;
  185. Uint high_bits;
  186. if (is_binary(BIF_ARG_1)) {
  187. bytesize = binary_size(BIF_ARG_1);
  188. high_bits = bytesize >> ((sizeof(Uint) * 8)-3);
  189. low_bits = (bytesize << 3) + binary_bitsize(BIF_ARG_1);
  190. if (high_bits == 0) {
  191. if (IS_USMALL(0,low_bits)) {
  192. BIF_RET(make_small(low_bits));
  193. } else {
  194. Eterm* hp = HAlloc(BIF_P, BIG_UINT_HEAP_SIZE);
  195. BIF_RET(uint_to_big(low_bits, hp));
  196. }
  197. } else {
  198. Uint sz = BIG_UINT_HEAP_SIZE+1;
  199. Eterm* hp = HAlloc(BIF_P, sz);
  200. hp[0] = make_pos_bignum_header(sz-1);
  201. BIG_DIGIT(hp,0) = low_bits;
  202. BIG_DIGIT(hp,1) = high_bits;
  203. BIF_RET(make_big(hp));
  204. }
  205. } else {
  206. BIF_ERROR(BIF_P, BADARG);
  207. }
  208. }
  209. /**********************************************************************/
  210. /* returns the number of bytes need to store a bitstring */
  211. BIF_RETTYPE byte_size_1(BIF_ALIST_1)
  212. {
  213. if (is_binary(BIF_ARG_1)) {
  214. Uint bytesize = binary_size(BIF_ARG_1);
  215. if (binary_bitsize(BIF_ARG_1) > 0) {
  216. bytesize++;
  217. }
  218. if (IS_USMALL(0, bytesize)) {
  219. BIF_RET(make_small(bytesize));
  220. } else {
  221. Eterm* hp = HAlloc(BIF_P, BIG_UINT_HEAP_SIZE);
  222. BIF_RET(uint_to_big(bytesize, hp));
  223. }
  224. } else {
  225. BIF_ERROR(BIF_P, BADARG);
  226. }
  227. }
  228. /*
  229. * Generate the integer part from a double.
  230. */
  231. static Eterm
  232. double_to_integer(Process* p, double x)
  233. {
  234. int is_negative;
  235. int ds;
  236. ErtsDigit* xp;
  237. int i;
  238. Eterm res;
  239. size_t sz;
  240. Eterm* hp;
  241. double dbase;
  242. if ((x < (double) (MAX_SMALL+1)) && (x > (double) (MIN_SMALL-1))) {
  243. Sint xi = x;
  244. return make_small(xi);
  245. }
  246. if (x >= 0) {
  247. is_negative = 0;
  248. } else {
  249. is_negative = 1;
  250. x = -x;
  251. }
  252. /* Unscale & (calculate exponent) */
  253. ds = 0;
  254. dbase = ((double)(D_MASK)+1);
  255. while(x >= 1.0) {
  256. x /= dbase; /* "shift" right */
  257. ds++;
  258. }
  259. sz = BIG_NEED_SIZE(ds); /* number of words including arity */
  260. hp = HAlloc(p, sz);
  261. res = make_big(hp);
  262. xp = (ErtsDigit*) (hp + 1);
  263. for (i = ds-1; i >= 0; i--) {
  264. ErtsDigit d;
  265. x *= dbase; /* "shift" left */
  266. d = x; /* trunc */
  267. xp[i] = d; /* store digit */
  268. x -= d; /* remove integer part */
  269. }
  270. while ((ds & (BIG_DIGITS_PER_WORD-1)) != 0) {
  271. xp[ds++] = 0;
  272. }
  273. if (is_negative) {
  274. *hp = make_neg_bignum_header(sz-1);
  275. } else {
  276. *hp = make_pos_bignum_header(sz-1);
  277. }
  278. return res;
  279. }
  280. /********************************************************************************
  281. * binary_part guards. The actual implementation is in erl_bif_binary.c
  282. ********************************************************************************/
  283. BIF_RETTYPE binary_part_3(BIF_ALIST_3)
  284. {
  285. return erts_binary_part(BIF_P,BIF_ARG_1,BIF_ARG_2, BIF_ARG_3);
  286. }
  287. BIF_RETTYPE binary_part_2(BIF_ALIST_2)
  288. {
  289. Eterm *tp;
  290. if (is_not_tuple(BIF_ARG_2)) {
  291. goto badarg;
  292. }
  293. tp = tuple_val(BIF_ARG_2);
  294. if (arityval(*tp) != 2) {
  295. goto badarg;
  296. }
  297. return erts_binary_part(BIF_P,BIF_ARG_1,tp[1], tp[2]);
  298. badarg:
  299. BIF_ERROR(BIF_P,BADARG);
  300. }
  301. /*
  302. * The following code is used when a guard that may build on the
  303. * heap is called directly. They must not use HAlloc(), but must
  304. * do a garbage collection if there is insufficient heap space.
  305. *
  306. * Important note: All error checking MUST be done before doing
  307. * a garbage collection. The compiler assumes that all registers
  308. * are still valid if a guard BIF generates an exception.
  309. */
  310. #define ERTS_NEED_GC(p, need) ((HEAP_LIMIT((p)) - HEAP_TOP((p))) <= (need))
  311. Eterm erts_gc_length_1(Process* p, Eterm* reg, Uint live)
  312. {
  313. Eterm list = reg[live];
  314. int i;
  315. if (is_nil(list))
  316. return SMALL_ZERO;
  317. i = 0;
  318. while (is_list(list)) {
  319. i++;
  320. list = CDR(list_val(list));
  321. }
  322. if (is_not_nil(list)) {
  323. BIF_ERROR(p, BADARG);
  324. }
  325. return make_small(i);
  326. }
  327. Eterm erts_gc_size_1(Process* p, Eterm* reg, Uint live)
  328. {
  329. Eterm arg = reg[live];
  330. if (is_tuple(arg)) {
  331. Eterm* tupleptr = tuple_val(arg);
  332. return make_small(arityval(*tupleptr));
  333. } else if (is_binary(arg)) {
  334. Uint sz = binary_size(arg);
  335. if (IS_USMALL(0, sz)) {
  336. return make_small(sz);
  337. } else {
  338. Eterm* hp;
  339. if (ERTS_NEED_GC(p, BIG_UINT_HEAP_SIZE)) {
  340. erts_garbage_collect(p, BIG_UINT_HEAP_SIZE, reg, live);
  341. }
  342. hp = p->htop;
  343. p->htop += BIG_UINT_HEAP_SIZE;
  344. return uint_to_big(sz, hp);
  345. }
  346. }
  347. BIF_ERROR(p, BADARG);
  348. }
  349. Eterm erts_gc_bit_size_1(Process* p, Eterm* reg, Uint live)
  350. {
  351. Eterm arg = reg[live];
  352. if (is_binary(arg)) {
  353. Uint low_bits;
  354. Uint bytesize;
  355. Uint high_bits;
  356. bytesize = binary_size(arg);
  357. high_bits = bytesize >> ((sizeof(Uint) * 8)-3);
  358. low_bits = (bytesize << 3) + binary_bitsize(arg);
  359. if (high_bits == 0) {
  360. if (IS_USMALL(0,low_bits)) {
  361. return make_small(low_bits);
  362. } else {
  363. Eterm* hp;
  364. if (ERTS_NEED_GC(p, BIG_UINT_HEAP_SIZE)) {
  365. erts_garbage_collect(p, BIG_UINT_HEAP_SIZE, reg, live);
  366. }
  367. hp = p->htop;
  368. p->htop += BIG_UINT_HEAP_SIZE;
  369. return uint_to_big(low_bits, hp);
  370. }
  371. } else {
  372. Uint sz = BIG_UINT_HEAP_SIZE+1;
  373. Eterm* hp;
  374. if (ERTS_NEED_GC(p, sz)) {
  375. erts_garbage_collect(p, sz, reg, live);
  376. }
  377. hp = p->htop;
  378. p->htop += sz;
  379. hp[0] = make_pos_bignum_header(sz-1);
  380. BIG_DIGIT(hp,0) = low_bits;
  381. BIG_DIGIT(hp,1) = high_bits;
  382. return make_big(hp);
  383. }
  384. } else {
  385. BIF_ERROR(p, BADARG);
  386. }
  387. }
  388. Eterm erts_gc_byte_size_1(Process* p, Eterm* reg, Uint live)
  389. {
  390. Eterm arg = reg[live];
  391. if (is_binary(arg)) {
  392. Uint bytesize = binary_size(arg);
  393. if (binary_bitsize(arg) > 0) {
  394. bytesize++;
  395. }
  396. if (IS_USMALL(0, bytesize)) {
  397. return make_small(bytesize);
  398. } else {
  399. Eterm* hp;
  400. if (ERTS_NEED_GC(p, BIG_UINT_HEAP_SIZE)) {
  401. erts_garbage_collect(p, BIG_UINT_HEAP_SIZE, reg, live);
  402. }
  403. hp = p->htop;
  404. p->htop += BIG_UINT_HEAP_SIZE;
  405. return uint_to_big(bytesize, hp);
  406. }
  407. } else {
  408. BIF_ERROR(p, BADARG);
  409. }
  410. }
  411. Eterm erts_gc_abs_1(Process* p, Eterm* reg, Uint live)
  412. {
  413. Eterm arg;
  414. Eterm res;
  415. Sint i0, i;
  416. Eterm* hp;
  417. arg = reg[live];
  418. /* integer arguments */
  419. if (is_small(arg)) {
  420. i0 = signed_val(arg);
  421. i = labs(i0);
  422. if (i0 == MIN_SMALL) {
  423. if (ERTS_NEED_GC(p, BIG_UINT_HEAP_SIZE)) {
  424. erts_garbage_collect(p, BIG_UINT_HEAP_SIZE, reg, live+1);
  425. arg = reg[live];
  426. }
  427. hp = p->htop;
  428. p->htop += BIG_UINT_HEAP_SIZE;
  429. return uint_to_big(i, hp);
  430. } else {
  431. return make_small(i);
  432. }
  433. } else if (is_big(arg)) {
  434. if (!big_sign(arg)) {
  435. return arg;
  436. } else {
  437. int sz = big_arity(arg) + 1;
  438. Uint* x;
  439. if (ERTS_NEED_GC(p, sz)) {
  440. erts_garbage_collect(p, sz, reg, live+1);
  441. arg = reg[live];
  442. }
  443. hp = p->htop;
  444. p->htop += sz;
  445. sz--;
  446. res = make_big(hp);
  447. x = big_val(arg);
  448. *hp++ = make_pos_bignum_header(sz);
  449. x++; /* skip thing */
  450. while(sz--)
  451. *hp++ = *x++;
  452. return res;
  453. }
  454. } else if (is_float(arg)) {
  455. FloatDef f;
  456. GET_DOUBLE(arg, f);
  457. if (f.fd < 0.0) {
  458. if (ERTS_NEED_GC(p, FLOAT_SIZE_OBJECT)) {
  459. erts_garbage_collect(p, FLOAT_SIZE_OBJECT, reg, live+1);
  460. arg = reg[live];
  461. }
  462. hp = p->htop;
  463. p->htop += FLOAT_SIZE_OBJECT;
  464. f.fd = fabs(f.fd);
  465. res = make_float(hp);
  466. PUT_DOUBLE(f, hp);
  467. return res;
  468. }
  469. else
  470. return arg;
  471. }
  472. BIF_ERROR(p, BADARG);
  473. }
  474. Eterm erts_gc_float_1(Process* p, Eterm* reg, Uint live)
  475. {
  476. Eterm arg;
  477. Eterm res;
  478. Eterm* hp;
  479. FloatDef f;
  480. /* check args */
  481. arg = reg[live];
  482. if (is_not_integer(arg)) {
  483. if (is_float(arg)) {
  484. return arg;
  485. } else {
  486. badarg:
  487. BIF_ERROR(p, BADARG);
  488. }
  489. }
  490. if (is_small(arg)) {
  491. Sint i = signed_val(arg);
  492. f.fd = i; /* use "C"'s auto casting */
  493. } else if (big_to_double(arg, &f.fd) < 0) {
  494. goto badarg;
  495. }
  496. if (ERTS_NEED_GC(p, FLOAT_SIZE_OBJECT)) {
  497. erts_garbage_collect(p, FLOAT_SIZE_OBJECT, reg, live+1);
  498. arg = reg[live];
  499. }
  500. hp = p->htop;
  501. p->htop += FLOAT_SIZE_OBJECT;
  502. res = make_float(hp);
  503. PUT_DOUBLE(f, hp);
  504. return res;
  505. }
  506. Eterm erts_gc_round_1(Process* p, Eterm* reg, Uint live)
  507. {
  508. Eterm arg;
  509. FloatDef f;
  510. arg = reg[live];
  511. if (is_not_float(arg)) {
  512. if (is_integer(arg)) {
  513. return arg;
  514. }
  515. BIF_ERROR(p, BADARG);
  516. }
  517. GET_DOUBLE(arg, f);
  518. return gc_double_to_integer(p, (f.fd > 0.0) ? f.fd + 0.5 : f.fd - 0.5,
  519. reg, live);
  520. }
  521. Eterm erts_gc_trunc_1(Process* p, Eterm* reg, Uint live)
  522. {
  523. Eterm arg;
  524. FloatDef f;
  525. arg = reg[live];
  526. if (is_not_float(arg)) {
  527. if (is_integer(arg)) {
  528. return arg;
  529. }
  530. BIF_ERROR(p, BADARG);
  531. }
  532. /* get the float */
  533. GET_DOUBLE(arg, f);
  534. /* truncate it and return the resultant integer */
  535. return gc_double_to_integer(p, (f.fd >= 0.0) ? floor(f.fd) : ceil(f.fd),
  536. reg, live);
  537. }
  538. static Eterm
  539. gc_double_to_integer(Process* p, double x, Eterm* reg, Uint live)
  540. {
  541. int is_negative;
  542. int ds;
  543. ErtsDigit* xp;
  544. int i;
  545. Eterm res;
  546. size_t sz;
  547. Eterm* hp;
  548. double dbase;
  549. if ((x < (double) (MAX_SMALL+1)) && (x > (double) (MIN_SMALL-1))) {
  550. Sint xi = x;
  551. return make_small(xi);
  552. }
  553. if (x >= 0) {
  554. is_negative = 0;
  555. } else {
  556. is_negative = 1;
  557. x = -x;
  558. }
  559. /* Unscale & (calculate exponent) */
  560. ds = 0;
  561. dbase = ((double)(D_MASK)+1);
  562. while(x >= 1.0) {
  563. x /= dbase; /* "shift" right */
  564. ds++;
  565. }
  566. sz = BIG_NEED_SIZE(ds); /* number of words including arity */
  567. if (ERTS_NEED_GC(p, sz)) {
  568. erts_garbage_collect(p, sz, reg, live);
  569. }
  570. hp = p->htop;
  571. p->htop += sz;
  572. res = make_big(hp);
  573. xp = (ErtsDigit*) (hp + 1);
  574. for (i = ds-1; i >= 0; i--) {
  575. ErtsDigit d;
  576. x *= dbase; /* "shift" left */
  577. d = x; /* trunc */
  578. xp[i] = d; /* store digit */
  579. x -= d; /* remove integer part */
  580. }
  581. while ((ds & (BIG_DIGITS_PER_WORD-1)) != 0) {
  582. xp[ds++] = 0;
  583. }
  584. if (is_negative) {
  585. *hp = make_neg_bignum_header(sz-1);
  586. } else {
  587. *hp = make_pos_bignum_header(sz-1);
  588. }
  589. return res;
  590. }
  591. /********************************************************************************
  592. * binary_part guards. The actual implementation is in erl_bif_binary.c
  593. ********************************************************************************/
  594. Eterm erts_gc_binary_part_3(Process* p, Eterm* reg, Uint live)
  595. {
  596. return erts_gc_binary_part(p,reg,live,0);
  597. }
  598. Eterm erts_gc_binary_part_2(Process* p, Eterm* reg, Uint live)
  599. {
  600. return erts_gc_binary_part(p,reg,live,1);
  601. }