1 /* 2 ** C type conversions. 3 ** Copyright (C) 2005-2025 Mike Pall. See Copyright Notice below. 4 ** 5 ** This file contains derived work from LuaJIT's FFI conversion machinery (lj_cconv.c). 6 ** 7 ** Modifications: 8 ** - Adapted VM interactions to use ucode's API (uc_vm_t, uc_value_t, etc.) 9 ** - Replaced LuaJIT's parallel call infrastructure with libffi 10 ** - Adapted value marshaling between ucode and C types 11 ** - Removed JIT-specific code and dependencies 12 ** 13 ** See NOTICE and ATTRIBUTION.md for complete attribution details. 14 */ 15 16 17 #include "uc_ctype.h" 18 #include "uc_cdata.h" 19 #include "uc_cconv.h" 20 21 #include <ffi.h> 22 23 /* -- Conversion errors --------------------------------------------------- */ 24 25 /* Bad conversion. */ 26 static bool 27 cconv_err_conv(CTState *cts, CType *d, CType *s, CTInfo flags) 28 { 29 uc_value_t *dst_repr = uc_ctype_repr(cts->vm, ctype_typeid(cts, d), NULL); 30 uc_value_t *src_repr = NULL; 31 const char *dst = ucv_string_get(dst_repr); 32 const char *src; 33 34 if ((flags & CCF_FROMTV)) 35 { 36 src = ctype_isnum(s->info) 37 ? "number" 38 : ctype_isarray(s->info) 39 ? "string" 40 : "null"; 41 } 42 else 43 { 44 src_repr = uc_ctype_repr(cts->vm, ctype_typeid(cts, s), NULL); 45 src = ucv_string_get(src_repr); 46 } 47 48 if (CCF_GETARG(flags)) { 49 uc_vm_raise_exception(cts->vm, EXCEPTION_TYPE, 50 "cannot convert argument #%d from '%s' to '%s'", 51 CCF_GETARG(flags), src, dst); 52 } 53 // lj_err_argv(cts->L, CCF_GETARG(flags), LJ_ERR_FFI_BADCONV, src, dst); 54 else { 55 uc_vm_raise_exception(cts->vm, EXCEPTION_TYPE, 56 "cannot convert from '%s' to '%s'", 57 src, dst); 58 } 59 60 // lj_err_callerv(cts->L, LJ_ERR_FFI_BADCONV, src, dst); 61 ucv_put(dst_repr); 62 ucv_put(src_repr); 63 64 return false; 65 } 66 67 /* Bad conversion from TValue. */ 68 static bool 69 cconv_err_convtv(CTState *cts, CType *d, uc_value_t *uv, CTInfo flags) 70 { 71 uc_value_t *dst_repr = uc_ctype_repr(cts->vm, ctype_typeid(cts, d), NULL); 72 const char *dst = ucv_string_get(dst_repr); 73 const char *src = ucv_typename(uv); 74 75 if (CCF_GETARG(flags)) { 76 uc_vm_raise_exception(cts->vm, EXCEPTION_TYPE, 77 "cannot convert argument #%d from '%s' to '%s'", 78 CCF_GETARG(flags), src, dst); 79 } 80 // lj_err_argv(cts->L, CCF_GETARG(flags), LJ_ERR_FFI_BADCONV, src, dst); 81 else { 82 uc_vm_raise_exception(cts->vm, EXCEPTION_TYPE, 83 "cannot convert from '%s' to '%s'", 84 src, dst); 85 } 86 87 // lj_err_callerv(cts->L, LJ_ERR_FFI_BADCONV, src, dst); 88 ucv_put(dst_repr); 89 90 return false; 91 } 92 93 /* Initializer overflow. */ 94 static bool 95 cconv_err_initov(CTState *cts, CType *d) 96 { 97 uc_value_t *repr = uc_ctype_repr(cts->vm, ctype_typeid(cts, d), NULL); 98 99 uc_vm_raise_exception(cts->vm, EXCEPTION_REFERENCE, 100 "too many initializers for '%s'", 101 ucv_string_get(repr)); 102 103 ucv_put(repr); 104 105 return false; 106 } 107 108 /* -- C type compatibility checks ----------------------------------------- */ 109 110 /* Get raw type and qualifiers for a child type. Resolves enums, too. */ 111 static CType *cconv_childqual(CTState *cts, CType *ct, CTInfo *qual) 112 { 113 ct = ctype_child(cts, ct); 114 for (;;) 115 { 116 if (ctype_isattrib(ct->info)) 117 { 118 if (ctype_attrib(ct->info) == CTA_QUAL) 119 *qual |= ct->size; 120 } 121 else if (!ctype_isenum(ct->info)) 122 { 123 break; 124 } 125 ct = ctype_child(cts, ct); 126 } 127 *qual |= (ct->info & CTF_QUAL); 128 return ct; 129 } 130 131 /* Check for compatible types when converting to a pointer. 132 ** Note: these checks are more relaxed than what C99 mandates. 133 */ 134 int uc_cconv_compatptr(CTState *cts, CType *d, CType *s, CTInfo flags) 135 { 136 if (!((flags & CCF_CAST) || d == s)) 137 { 138 CTInfo dqual = 0, squal = 0; 139 d = cconv_childqual(cts, d, &dqual); 140 if (!ctype_isstruct(s->info)) 141 s = cconv_childqual(cts, s, &squal); 142 if ((flags & CCF_SAME)) 143 { 144 if (dqual != squal) 145 return 0; /* Different qualifiers. */ 146 } 147 else if (!(flags & CCF_IGNQUAL)) 148 { 149 if ((dqual & squal) != squal) 150 return 0; /* Discarded qualifiers. */ 151 if (ctype_isvoid(d->info) || ctype_isvoid(s->info)) 152 return 1; /* Converting to/from void * is always ok. */ 153 } 154 if (ctype_type(d->info) != ctype_type(s->info) || 155 d->size != s->size) 156 return 0; /* Different type or different size. */ 157 if (ctype_isnum(d->info)) 158 { 159 if (((d->info ^ s->info) & (CTF_BOOL | CTF_FP))) 160 return 0; /* Different numeric types. */ 161 } 162 else if (ctype_ispointer(d->info)) 163 { 164 /* Check child types for compatibility. */ 165 return uc_cconv_compatptr(cts, d, s, flags | CCF_SAME); 166 } 167 else if (ctype_isstruct(d->info)) 168 { 169 if (d != s) 170 return 0; /* Must be exact same type for struct/union. */ 171 } 172 else if (ctype_isfunc(d->info)) 173 { 174 /* NYI: structural equality of functions. */ 175 } 176 } 177 return 1; /* Types are compatible. */ 178 } 179 180 /* -- C type to C type conversion ----------------------------------------- */ 181 182 /* Convert C type to C type. Caveat: expects to get the raw CType! 183 ** 184 ** Note: This is only used by the interpreter and not optimized at all. 185 ** The JIT compiler will do a much better job specializing for each case. 186 */ 187 bool uc_cconv_ct_ct(CTState *cts, CType *d, CType *s, 188 uint8_t *dp, uint8_t *sp, CTInfo flags) 189 { 190 CTSize dsize = d->size, ssize = s->size; 191 CTInfo dinfo = d->info, sinfo = s->info; 192 void *tmpptr; 193 194 uc_assertCTS(!ctype_isenum(dinfo) && !ctype_isenum(sinfo), 195 "unresolved enum"); 196 uc_assertCTS(!ctype_isattrib(dinfo) && !ctype_isattrib(sinfo), 197 "unstripped attribute"); 198 199 if (ctype_type(dinfo) > CT_MAYCONVERT || ctype_type(sinfo) > CT_MAYCONVERT) 200 goto err_conv; 201 202 /* Some basic sanity checks. */ 203 uc_assertCTS(!ctype_isnum(dinfo) || dsize > 0, "bad size for number type"); 204 uc_assertCTS(!ctype_isnum(sinfo) || ssize > 0, "bad size for number type"); 205 uc_assertCTS(!ctype_isbool(dinfo) || dsize == 1 || dsize == 4, 206 "bad size for bool type"); 207 uc_assertCTS(!ctype_isbool(sinfo) || ssize == 1 || ssize == 4, 208 "bad size for bool type"); 209 uc_assertCTS(!ctype_isinteger(dinfo) || (1u << uc_fls(dsize)) == dsize, 210 "bad size for integer type"); 211 uc_assertCTS(!ctype_isinteger(sinfo) || (1u << uc_fls(ssize)) == ssize, 212 "bad size for integer type"); 213 214 switch (cconv_idx2(dinfo, sinfo)) 215 { 216 /* Destination is a bool. */ 217 case CCX(B, B): 218 /* Source operand is already normalized. */ 219 if (dsize == 1) 220 *dp = *sp; 221 else 222 *(int *)dp = *sp; 223 break; 224 case CCX(B, I): 225 { 226 size_t i; 227 uint8_t b = 0; 228 for (i = 0; i < ssize; i++) 229 b |= sp[i]; 230 b = (b != 0); 231 if (dsize == 1) 232 *dp = b; 233 else 234 *(int *)dp = b; 235 break; 236 } 237 case CCX(B, F): 238 { 239 uint8_t b; 240 if (ssize == sizeof(double)) 241 b = (*(double *)sp != 0); 242 else if (ssize == sizeof(float)) 243 b = (*(float *)sp != 0); 244 else 245 goto err_conv; /* NYI: long double. */ 246 if (dsize == 1) 247 *dp = b; 248 else 249 *(int *)dp = b; 250 break; 251 } 252 253 /* Destination is an integer. */ 254 case CCX(I, B): 255 case CCX(I, I): 256 conv_I_I: 257 if (dsize > ssize) 258 { /* Zero-extend or sign-extend LSB. */ 259 #if __BYTE_ORDER == __LITTLE_ENDIAN 260 uint8_t fill = (!(sinfo & CTF_UNSIGNED) && (sp[ssize - 1] & 0x80)) ? 0xff : 0; 261 memcpy(dp, sp, ssize); 262 memset(dp + ssize, fill, dsize - ssize); 263 #else 264 uint8_t fill = (!(sinfo & CTF_UNSIGNED) && (sp[0] & 0x80)) ? 0xff : 0; 265 memset(dp, fill, dsize - ssize); 266 memcpy(dp + (dsize - ssize), sp, ssize); 267 #endif 268 } 269 else 270 { /* Copy LSB. */ 271 #if __BYTE_ORDER == __LITTLE_ENDIAN 272 memcpy(dp, sp, dsize); 273 #else 274 memcpy(dp, sp + (ssize - dsize), dsize); 275 #endif 276 } 277 break; 278 case CCX(I, F): 279 { 280 double n; /* Always convert via double. */ 281 conv_I_F: 282 /* Convert source to double. */ 283 if (ssize == sizeof(double)) 284 n = *(double *)sp; 285 else if (ssize == sizeof(float)) 286 n = (double)*(float *)sp; 287 else 288 goto err_conv; /* NYI: long double. */ 289 /* Then convert double to integer. */ 290 /* The conversion must exactly match the semantics of JIT-compiled code! */ 291 if (dsize < 4 || (dsize == 4 && !(dinfo & CTF_UNSIGNED))) 292 { 293 int32_t i = (int32_t)n; 294 if (dsize == 4) 295 *(int32_t *)dp = i; 296 else if (dsize == 2) 297 *(int16_t *)dp = (int16_t)i; 298 else 299 *(int8_t *)dp = (int8_t)i; 300 } 301 else if (dsize == 4) 302 { 303 *(uint32_t *)dp = (uint32_t)n; 304 } 305 else if (dsize == 8) 306 { 307 if (!(dinfo & CTF_UNSIGNED)) 308 *(int64_t *)dp = (int64_t)n; 309 else 310 *(uint64_t *)dp = uc_num2u64(n); 311 } 312 else 313 { 314 goto err_conv; /* NYI: conversion to >64 bit integers. */ 315 } 316 break; 317 } 318 case CCX(I, C): 319 s = ctype_child(cts, s); 320 ssize = s->size; 321 goto conv_I_F; /* Just convert re. */ 322 case CCX(I, P): 323 if (!(flags & CCF_CAST)) 324 goto err_conv; 325 sinfo = CTINFO(CT_NUM, CTF_UNSIGNED); 326 goto conv_I_I; 327 case CCX(I, A): 328 if (!(flags & CCF_CAST)) 329 goto err_conv; 330 sinfo = CTINFO(CT_NUM, CTF_UNSIGNED); 331 ssize = CTSIZE_PTR; 332 tmpptr = sp; 333 sp = (uint8_t *)&tmpptr; 334 goto conv_I_I; 335 336 /* Destination is a floating-point number. */ 337 case CCX(F, B): 338 case CCX(F, I): 339 { 340 double n; /* Always convert via double. */ 341 conv_F_I: 342 /* First convert source to double. */ 343 /* The conversion must exactly match the semantics of JIT-compiled code! */ 344 if (ssize < 4 || (ssize == 4 && !(sinfo & CTF_UNSIGNED))) 345 { 346 int32_t i; 347 if (ssize == 4) 348 { 349 i = *(int32_t *)sp; 350 } 351 else if (!(sinfo & CTF_UNSIGNED)) 352 { 353 if (ssize == 2) 354 i = *(int16_t *)sp; 355 else 356 i = *(int8_t *)sp; 357 } 358 else 359 { 360 if (ssize == 2) 361 i = *(uint16_t *)sp; 362 else 363 i = *(uint8_t *)sp; 364 } 365 n = (double)i; 366 } 367 else if (ssize == 4) 368 { 369 n = (double)*(uint32_t *)sp; 370 } 371 else if (ssize == 8) 372 { 373 if (!(sinfo & CTF_UNSIGNED)) 374 n = (double)*(int64_t *)sp; 375 else 376 n = (double)*(uint64_t *)sp; 377 } 378 else 379 { 380 goto err_conv; /* NYI: conversion from >64 bit integers. */ 381 } 382 /* Convert double to destination. */ 383 if (dsize == sizeof(double)) 384 *(double *)dp = n; 385 else if (dsize == sizeof(float)) 386 *(float *)dp = (float)n; 387 else 388 goto err_conv; /* NYI: long double. */ 389 break; 390 } 391 case CCX(F, F): 392 { 393 double n; /* Always convert via double. */ 394 conv_F_F: 395 if (ssize == dsize) 396 goto copyval; 397 /* Convert source to double. */ 398 if (ssize == sizeof(double)) 399 n = *(double *)sp; 400 else if (ssize == sizeof(float)) 401 n = (double)*(float *)sp; 402 else 403 goto err_conv; /* NYI: long double. */ 404 /* Convert double to destination. */ 405 if (dsize == sizeof(double)) 406 *(double *)dp = n; 407 else if (dsize == sizeof(float)) 408 *(float *)dp = (float)n; 409 else 410 goto err_conv; /* NYI: long double. */ 411 break; 412 } 413 case CCX(F, C): 414 s = ctype_child(cts, s); 415 ssize = s->size; 416 goto conv_F_F; /* Ignore im, and convert from re. */ 417 418 /* Destination is a complex number. */ 419 case CCX(C, I): 420 d = ctype_child(cts, d); 421 dsize = d->size; 422 memset(dp + dsize, 0, dsize); /* Clear im. */ 423 goto conv_F_I; /* Convert to re. */ 424 case CCX(C, F): 425 d = ctype_child(cts, d); 426 dsize = d->size; 427 memset(dp + dsize, 0, dsize); /* Clear im. */ 428 goto conv_F_F; /* Convert to re. */ 429 430 case CCX(C, C): 431 if (dsize != ssize) 432 { /* Different types: convert re/im separately. */ 433 CType *dc = ctype_child(cts, d); 434 CType *sc = ctype_child(cts, s); 435 return uc_cconv_ct_ct(cts, dc, sc, dp, sp, flags) && 436 uc_cconv_ct_ct(cts, dc, sc, dp + dc->size, sp + sc->size, flags); 437 } 438 goto copyval; /* Otherwise this is easy. */ 439 440 /* Destination is a vector. */ 441 case CCX(V, I): 442 case CCX(V, F): 443 case CCX(V, C): 444 { 445 CType *dc = ctype_child(cts, d); 446 CTSize esize; 447 /* First convert the scalar to the first element. */ 448 if (!uc_cconv_ct_ct(cts, dc, s, dp, sp, flags)) 449 return false; 450 /* Then replicate it to the other elements (splat). */ 451 for (sp = dp, esize = dc->size; dsize > esize; dsize -= esize) 452 { 453 dp += esize; 454 memcpy(dp, sp, esize); 455 } 456 break; 457 } 458 459 case CCX(V, V): 460 /* Copy same-sized vectors, even for different lengths/element-types. */ 461 if (dsize != ssize) 462 goto err_conv; 463 goto copyval; 464 465 /* Destination is a pointer. */ 466 case CCX(P, I): 467 if (!(flags & CCF_CAST)) 468 goto err_conv; 469 goto conv_I_I; 470 471 case CCX(P, F): 472 if (!(flags & CCF_CAST) || !(flags & CCF_FROMTV)) 473 goto err_conv; 474 /* The signed conversion is cheaper. x64 really has 47 bit pointers. */ 475 dinfo = CTINFO(CT_NUM, (UC_64 && dsize == 8) ? 0 : CTF_UNSIGNED); 476 goto conv_I_F; 477 478 case CCX(P, P): 479 if (!uc_cconv_compatptr(cts, d, s, flags)) 480 goto err_conv; 481 cdata_setptr(dp, dsize, cdata_getptr(sp, ssize)); 482 break; 483 484 case CCX(P, A): 485 case CCX(P, S): 486 if (!uc_cconv_compatptr(cts, d, s, flags)) { 487 goto err_conv; 488 } 489 cdata_setptr(dp, dsize, sp); 490 break; 491 492 /* Destination is an array. */ 493 case CCX(A, A): 494 if ((flags & CCF_CAST) || (d->info & CTF_VLA) || dsize != ssize || 495 d->size == CTSIZE_INVALID || !uc_cconv_compatptr(cts, d, s, flags)) 496 goto err_conv; 497 goto copyval; 498 499 /* Destination is a struct/union. */ 500 case CCX(S, S): 501 if ((flags & CCF_CAST) || (d->info & CTF_VLA) || d != s) 502 goto err_conv; /* Must be exact same type. */ 503 copyval: /* Copy value. */ 504 uc_assertCTS(dsize == ssize, "value copy with different sizes"); 505 memcpy(dp, sp, dsize); 506 break; 507 508 default: 509 err_conv: 510 return cconv_err_conv(cts, d, s, flags); 511 } 512 513 return true; 514 } 515 516 /* -- C type to TValue conversion ----------------------------------------- */ 517 518 /* Convert C type to TValue. Caveat: expects to get the raw CType! */ 519 int uc_cconv_tv_ct(CTState *cts, CType *s, CTypeID sid, 520 uc_value_t **uv, uint8_t *sp) 521 { 522 CTInfo sinfo = s->info; 523 if (ctype_isnum(sinfo)) 524 { 525 ucv_put(*uv); 526 527 if (!ctype_isbool(sinfo)) 528 { 529 if (ctype_isinteger(sinfo)) { 530 if (sinfo & CTF_UNSIGNED) { 531 uint64_t u; 532 uc_cconv_ct_ct(cts, ctype_get(cts, CTID_UINT64), s, 533 (uint8_t *)&u, sp, 0); 534 *uv = ucv_uint64_new(u); 535 } 536 else { 537 int64_t n; 538 uc_cconv_ct_ct(cts, ctype_get(cts, CTID_INT64), s, 539 (uint8_t *)&n, sp, 0); 540 *uv = ucv_int64_new(n); 541 } 542 } 543 else { 544 double d; 545 uc_cconv_ct_ct(cts, ctype_get(cts, CTID_DOUBLE), s, 546 (uint8_t *)&d, sp, 0); 547 *uv = ucv_double_new(d); 548 } 549 } 550 else 551 { 552 uint32_t b = s->size == 1 ? (*sp != 0) : (*(int *)sp != 0); 553 *uv = ucv_boolean_new(b); 554 //setboolV(o, b); 555 //setboolV(&cts->g->tmptv2, b); /* Remember for trace recorder. */ 556 } 557 return 0; 558 } 559 else if (ctype_isrefarray(sinfo) || ctype_isstruct(sinfo)) 560 { 561 /* Create reference. */ 562 ucv_put(*uv); 563 *uv = uc_cdata_newref(cts->vm, sp, sid); 564 565 //setcdataV(cts->L, o, lj_cdata_newref(cts, sp, sid)); 566 return 1; /* Need GC step. */ 567 } 568 else 569 { 570 CTSize sz = s->size; 571 uc_assertCTS(sz != CTSIZE_INVALID, "value copy with invalid size"); 572 573 /* Attributes are stripped, qualifiers are kept (but mostly ignored). */ 574 uc_value_t *res = uc_cdata_new(cts->vm, ctype_typeid(cts, s), sz); 575 memcpy(uc_cdata_dataptr(res), sp, sz); 576 577 ucv_put(*uv); 578 *uv = res; 579 580 return 1; /* Need GC step. */ 581 } 582 } 583 584 /* Convert bitfield to TValue. */ 585 int uc_cconv_tv_bf(CTState *cts, CType *s, uc_value_t **uv, uint8_t *sp) 586 { 587 CTInfo info = s->info; 588 CTSize pos, bsz; 589 uint32_t val; 590 uc_assertCTS(ctype_isbitfield(info), "bitfield expected"); 591 /* NYI: packed bitfields may cause misaligned reads. */ 592 switch (ctype_bitcsz(info)) 593 { 594 case 4: 595 val = *(uint32_t *)sp; 596 break; 597 case 2: 598 val = *(uint16_t *)sp; 599 break; 600 case 1: 601 val = *(uint8_t *)sp; 602 break; 603 default: 604 uc_assertCTS(0, "bad bitfield container size %d", ctype_bitcsz(info)); 605 val = 0; 606 break; 607 } 608 /* Check if a packed bitfield crosses a container boundary. */ 609 pos = ctype_bitpos(info); 610 bsz = ctype_bitbsz(info); 611 uc_assertCTS(pos < 8 * ctype_bitcsz(info), "bad bitfield position"); 612 uc_assertCTS(bsz > 0 && bsz <= 8 * ctype_bitcsz(info), "bad bitfield size"); 613 if (pos + bsz > 8 * ctype_bitcsz(info)) { 614 uc_vm_raise_exception(cts->vm, EXCEPTION_TYPE, 615 "packed bit fields are not implemented yet"); 616 return 0; 617 } 618 if (!(info & CTF_BOOL)) 619 { 620 CTSize shift = 32 - bsz; 621 if (!(info & CTF_UNSIGNED)) 622 { 623 ucv_put(*uv); 624 *uv = ucv_int64_new((int32_t)(val << (shift - pos)) >> shift); 625 //setintV(o, (int32_t)(val << (shift - pos)) >> shift); 626 } 627 else 628 { 629 val = (val << (shift - pos)) >> shift; 630 ucv_put(*uv); 631 *uv = ucv_uint64_new(val); 632 //if (!LJ_DUALNUM || (int32_t)val < 0) 633 // setnumV(o, (lua_Number)(uint32_t)val); 634 //else 635 // setintV(o, (int32_t)val); 636 } 637 } 638 else 639 { 640 uint32_t b = (val >> pos) & 1; 641 uc_assertCTS(bsz == 1, "bad bool bitfield size"); 642 ucv_put(*uv); 643 *uv = ucv_boolean_new(b); 644 //setboolV(o, b); 645 //setboolV(&cts->g->tmptv2, b); /* Remember for trace recorder. */ 646 } 647 return 0; /* No GC step needed. */ 648 } 649 650 /* -- TValue to C type conversion ----------------------------------------- */ 651 652 /* Convert ucode array to C array. */ 653 static bool cconv_array_tab(CTState *cts, CType *d, 654 uint8_t *dp, uc_value_t *arr, CTInfo flags, 655 uc_value_t **refs) 656 { 657 size_t arrlen = ucv_array_length(arr); 658 size_t i; 659 CType *dc = ctype_rawchild(cts, d); /* Array element type. */ 660 CTSize size = d->size, esize = dc->size, ofs = 0; 661 for (i = 0; i < arrlen; i++) 662 { 663 if (ofs >= size) 664 cconv_err_initov(cts, d); 665 uc_cconv_ct_tv(cts, dc, dp + ofs, ucv_array_get(arr, i), flags, refs); 666 ofs += esize; 667 } 668 if (size != CTSIZE_INVALID) 669 { /* Only fill up arrays with known size. */ 670 if (ofs == esize) 671 { /* Replicate a single element. */ 672 for (; ofs < size; ofs += esize) 673 memcpy(dp + ofs, dp, esize); 674 } 675 else 676 { /* Otherwise fill the remainder with zero. */ 677 memset(dp + ofs, 0, size - ofs); 678 } 679 } 680 681 return true; 682 } 683 684 /* Convert ucode array to sub-struct/union. */ 685 static bool cconv_substruct_tab(CTState *cts, CType *d, uint8_t *dp, 686 uc_value_t *tab, int32_t *ip, CTInfo flags, 687 uc_value_t **refs) 688 { 689 CTypeID id = d->sib; 690 691 while (id) 692 { 693 CType *df = ctype_get(cts, id); 694 id = df->sib; 695 696 if (ctype_isfield(df->info) || ctype_isbitfield(df->info)) 697 { 698 uc_value_t *uv; 699 700 if (!df->uv_name) 701 continue; /* Ignore unnamed fields. */ 702 703 if (ucv_type(tab) == UC_ARRAY) 704 { 705 int32_t i = *ip; 706 707 uv = ucv_array_get(tab, i); 708 709 if (!uv) 710 break; /* Stop at first nil. */ 711 712 *ip = i + 1; 713 } 714 else if (ucv_type(tab) == UC_OBJECT) 715 { 716 uv = ucv_object_get(tab, ucv_string_get(df->uv_name), NULL); 717 718 if (!uv) 719 continue; 720 } 721 else { 722 uc_vm_raise_exception(cts->vm, EXCEPTION_TYPE, 723 "array or object initializer value expected, got %s", 724 ucv_typename(tab)); 725 726 return false; 727 } 728 729 if (ctype_isfield(df->info)) 730 uc_cconv_ct_tv(cts, ctype_rawchild(cts, df), dp + df->size, 731 uv, flags, refs); 732 else 733 uc_cconv_bf_tv(cts, df, dp + df->size, uv, refs); 734 735 if ((d->info & CTF_UNION)) 736 break; 737 } 738 else if (ctype_isxattrib(df->info, CTA_SUBTYPE)) 739 { 740 if (!cconv_substruct_tab(cts, ctype_rawchild(cts, df), 741 dp + df->size, tab, ip, flags, refs)) 742 return false; 743 } /* Ignore all other entries in the chain. */ 744 } 745 746 return true; 747 } 748 749 /* Convert table to struct/union. */ 750 static bool cconv_struct_tab(CTState *cts, CType *d, 751 uint8_t *dp, uc_value_t *tab, CTInfo flags, 752 uc_value_t **refs) 753 { 754 int32_t i = 0; 755 756 memset(dp, 0, d->size); /* Much simpler to clear the struct first. */ 757 758 return cconv_substruct_tab(cts, d, dp, tab, &i, flags, refs); 759 } 760 761 /* Convert TValue to C type. Caveat: expects to get the raw CType! */ 762 bool uc_cconv_ct_tv(CTState *cts, CType *d, 763 uint8_t *dp, uc_value_t *uv, CTInfo flags, 764 uc_value_t **refs) 765 { 766 uintptr_t pv = (uintptr_t)uv; 767 CTypeID sid = CTID_P_VOID; 768 CType *s; 769 void *tmpptr; 770 uint8_t tmpbool, *sp = (uint8_t *)&tmpptr; 771 GCcdata *cd; 772 uc_type_t utt = pv & 3; 773 uc_type_t ut = (!utt && uv) ? uv->type : utt; 774 775 /* optimized case: fast tagged integer read */ 776 if (UC_LIKELY(utt == UC_INTEGER)) { 777 /* unsigned */ 778 if (((pv >> 2) & 1) == 0) { 779 tmpptr = (void *)(pv >> 3); 780 sid = (sizeof(tmpptr) == sizeof(uint64_t)) ? CTID_UINT64 : CTID_UINT32; 781 } 782 else { 783 tmpptr = (void *)(uintptr_t)-(pv >> 3); 784 sid = (sizeof(tmpptr) == sizeof(int64_t)) ? CTID_INT64 : CTID_INT32; 785 } 786 787 flags |= CCF_FROMTV; 788 } 789 /* optimized case: fast bool read */ 790 else if (UC_LIKELY(utt == UC_BOOLEAN)) 791 { 792 tmpbool = (pv >> 2) & 1; 793 sp = &tmpbool; 794 sid = CTID_BOOL; 795 } 796 else if (UC_LIKELY(ut == UC_INTEGER)) 797 { 798 uc_integer_t *ui = (uc_integer_t *)uv; 799 800 /* unsigned */ 801 if (ui->header.ext_flag) { 802 sp = (uint8_t *)&ui->i.u64; 803 sid = CTID_UINT64; 804 } 805 else { 806 sp = (uint8_t *)&ui->i.s64; 807 sid = CTID_INT64; 808 } 809 810 flags |= CCF_FROMTV; 811 } 812 else if (UC_LIKELY(ut == UC_DOUBLE)) 813 { 814 uc_double_t *ud = (uc_double_t *)uv; 815 816 sp = (uint8_t *)&ud->dbl; 817 sid = CTID_DOUBLE; 818 flags |= CCF_FROMTV; 819 } 820 else if (ut == UC_RESOURCE && (cd = ucv_resource_data(uv, "ffi.ctype")) != NULL) 821 { 822 sp = cdataptr(cd); 823 sid = cd->ctypeid; 824 s = ctype_get(cts, sid); 825 if (ctype_isref(s->info)) 826 { /* Resolve reference for value. */ 827 uc_assertCTS(s->size == CTSIZE_PTR, "ref is not pointer-sized"); 828 sp = *(void **)sp; 829 sid = ctype_cid(s->info); 830 } 831 s = ctype_raw(cts, sid); 832 if (ctype_isfunc(s->info)) 833 { 834 CTypeID did = ctype_typeid(cts, d); 835 sid = uc_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR | sid), CTSIZE_PTR); 836 d = ctype_get(cts, did); /* cts->tab may have been reallocated. */ 837 } 838 else 839 { 840 if (ctype_isenum(s->info)) 841 s = ctype_child(cts, s); 842 goto doconv; 843 } 844 } 845 else if (ut == UC_STRING) 846 { 847 if (ctype_isenum(d->info)) 848 { /* Match string against enum constant. */ 849 CTSize ofs; 850 CType *cct = uc_ctype_getfield(cts, d, uv, &ofs); 851 if (!cct || !ctype_isconstval(cct->info)) 852 goto err_conv; 853 uc_assertCTS(d->size == 4, "only 32 bit enum supported"); /* NYI */ 854 sp = (uint8_t *)&cct->size; 855 sid = ctype_cid(cct->info); 856 } 857 else if (ctype_isrefarray(d->info)) 858 { /* Copy string to array. */ 859 CType *dc = ctype_rawchild(cts, d); 860 CTSize sz = ucv_string_length(uv) + 1; 861 if (!ctype_isinteger(dc->info) || dc->size != 1) 862 goto err_conv; 863 if (d->size != 0 && d->size < sz) 864 sz = d->size; 865 return memcpy(dp, ucv_string_get(uv), sz); 866 } 867 else 868 { /* Otherwise pass it as a const char[]. */ 869 uc_value_t *us = uc_cconv_addref(refs, uv); 870 sp = (uint8_t *)ucv_string_get(us); 871 sid = CTID_A_CCHAR; 872 flags |= CCF_FROMTV; 873 } 874 } 875 else if (ut == UC_ARRAY) 876 { 877 if (ctype_isarray(d->info)) 878 { 879 return cconv_array_tab(cts, d, dp, uv, flags, refs); 880 } 881 else if (ctype_isstruct(d->info)) 882 { 883 return cconv_struct_tab(cts, d, dp, uv, flags, refs); 884 } 885 else 886 { 887 goto err_conv; 888 } 889 } 890 else if (ut == UC_OBJECT) 891 { 892 if (ctype_isstruct(d->info)) 893 { 894 return cconv_struct_tab(cts, d, dp, uv, flags, refs); 895 } 896 else 897 { 898 goto err_conv; 899 } 900 } 901 else if (ut == UC_NULL) 902 { 903 tmpptr = (void *)0; 904 flags |= CCF_FROMTV; 905 } 906 else if (ut == UC_RESOURCE) 907 { 908 tmpptr = ucv_resource_data(uv, NULL); 909 } 910 else 911 { 912 err_conv: 913 return cconv_err_convtv(cts, d, uv, flags); 914 } 915 s = ctype_get(cts, sid); 916 doconv: 917 if (ctype_isenum(d->info)) 918 d = ctype_child(cts, d); 919 return uc_cconv_ct_ct(cts, d, s, dp, sp, flags); 920 } 921 922 /* Convert TValue to bitfield. */ 923 bool uc_cconv_bf_tv(CTState *cts, CType *d, uint8_t *dp, uc_value_t *uv, 924 uc_value_t **refs) 925 { 926 CTInfo info = d->info; 927 CTSize pos, bsz; 928 uint32_t val = 0, mask; 929 uc_assertCTS(ctype_isbitfield(info), "bitfield expected"); 930 if ((info & CTF_BOOL)) 931 { 932 uint8_t tmpbool = 0; 933 uc_assertCTS(ctype_bitbsz(info) == 1, "bad bool bitfield size"); 934 if (!uc_cconv_ct_tv(cts, ctype_get(cts, CTID_BOOL), &tmpbool, uv, 0, refs)) 935 return false; 936 val = tmpbool; 937 } 938 else 939 { 940 CTypeID did = (info & CTF_UNSIGNED) ? CTID_UINT32 : CTID_INT32; 941 if (!uc_cconv_ct_tv(cts, ctype_get(cts, did), (uint8_t *)&val, uv, 0, refs)) 942 return false; 943 } 944 pos = ctype_bitpos(info); 945 bsz = ctype_bitbsz(info); 946 uc_assertCTS(pos < 8 * ctype_bitcsz(info), "bad bitfield position"); 947 uc_assertCTS(bsz > 0 && bsz <= 8 * ctype_bitcsz(info), "bad bitfield size"); 948 /* Check if a packed bitfield crosses a container boundary. */ 949 if (pos + bsz > 8 * ctype_bitcsz(info)) { 950 //lj_err_caller(cts->L, LJ_ERR_FFI_NYIPACKBIT); 951 uc_vm_raise_exception(cts->vm, EXCEPTION_TYPE, 952 "packed bit fields are not implemented yet"); 953 954 return false; 955 } 956 mask = ((1u << bsz) - 1u) << pos; 957 val = (val << pos) & mask; 958 /* NYI: packed bitfields may cause misaligned reads/writes. */ 959 switch (ctype_bitcsz(info)) 960 { 961 case 4: 962 *(uint32_t *)dp = (*(uint32_t *)dp & ~mask) | (uint32_t)val; 963 break; 964 case 2: 965 *(uint16_t *)dp = (*(uint16_t *)dp & ~mask) | (uint16_t)val; 966 break; 967 case 1: 968 *(uint8_t *)dp = (*(uint8_t *)dp & ~mask) | (uint8_t)val; 969 break; 970 default: 971 uc_assertCTS(0, "bad bitfield container size %d", ctype_bitcsz(info)); 972 break; 973 } 974 975 return true; 976 } 977 978 /* -- Initialize C type with TValues -------------------------------------- */ 979 980 /* Initialize an array with TValues. */ 981 static bool cconv_array_init(CTState *cts, CType *d, CTSize sz, uint8_t *dp, 982 uc_value_t **uv, size_t len, uc_value_t **refs) 983 { 984 CType *dc = ctype_rawchild(cts, d); /* Array element type. */ 985 CTSize ofs, esize = dc->size; 986 size_t i; 987 if (len * esize > sz) 988 return cconv_err_initov(cts, d); 989 for (i = 0, ofs = 0; i < len; i++, ofs += esize) 990 if (!uc_cconv_ct_tv(cts, dc, dp + ofs, uv[i], 0, refs)) 991 return false; 992 if (ofs == esize) 993 { /* Replicate a single element. */ 994 for (; ofs < sz; ofs += esize) 995 memcpy(dp + ofs, dp, esize); 996 } 997 else 998 { /* Otherwise fill the remainder with zero. */ 999 memset(dp + ofs, 0, sz - ofs); 1000 } 1001 1002 return true; 1003 } 1004 1005 /* Initialize a sub-struct/union with TValues. */ 1006 static bool cconv_substruct_init(CTState *cts, CType *d, uint8_t *dp, 1007 uc_value_t **uv, size_t len, size_t *ip, 1008 uc_value_t **refs) 1009 { 1010 CTypeID id = d->sib; 1011 while (id) 1012 { 1013 CType *df = ctype_get(cts, id); 1014 id = df->sib; 1015 if (ctype_isfield(df->info) || ctype_isbitfield(df->info)) 1016 { 1017 size_t i = *ip; 1018 if (!df->uv_name) 1019 continue; /* Ignore unnamed fields. */ 1020 if (i >= len) 1021 break; 1022 *ip = i + 1; 1023 1024 if (ctype_isfield(df->info)) { 1025 if (!uc_cconv_ct_tv(cts, ctype_rawchild(cts, df), 1026 dp + df->size, uv[i], 0, refs)) 1027 return false; 1028 } 1029 else { 1030 if (!uc_cconv_bf_tv(cts, df, dp + df->size, uv[i], refs)) 1031 return false; 1032 } 1033 1034 if ((d->info & CTF_UNION)) 1035 break; 1036 } 1037 else if (ctype_isxattrib(df->info, CTA_SUBTYPE)) 1038 { 1039 if (!cconv_substruct_init(cts, ctype_rawchild(cts, df), 1040 dp + df->size, uv, len, ip, refs)) 1041 return false; 1042 1043 if ((d->info & CTF_UNION)) 1044 break; 1045 } /* Ignore all other entries in the chain. */ 1046 } 1047 1048 return true; 1049 } 1050 1051 /* Initialize a struct/union with TValues. */ 1052 static bool cconv_struct_init(CTState *cts, CType *d, CTSize sz, uint8_t *dp, 1053 uc_value_t **uv, size_t len, uc_value_t **refs) 1054 { 1055 size_t i = 0; 1056 1057 memset(dp, 0, sz); /* Much simpler to clear the struct first. */ 1058 1059 if (!cconv_substruct_init(cts, d, dp, uv, len, &i, refs)) 1060 return false; 1061 1062 if (i < len) 1063 return cconv_err_initov(cts, d); 1064 1065 return true; 1066 } 1067 1068 /* Initialize a struct/union with a ucode object. */ 1069 static bool cconv_struct_object_init(CTState *cts, CType *d, CTSize sz, uint8_t *dp, 1070 uc_value_t *obj, uc_value_t **refs) 1071 { 1072 CTypeID id = d->sib; 1073 1074 memset(dp, 0, sz); 1075 1076 while (id) 1077 { 1078 CType *df = ctype_get(cts, id); 1079 id = df->sib; 1080 1081 if (ctype_isfield(df->info) || ctype_isbitfield(df->info)) 1082 { 1083 if (!df->uv_name) 1084 continue; 1085 1086 uc_value_t *uv = ucv_object_get(obj, ucv_string_get(df->uv_name), NULL); 1087 1088 if (uv) 1089 { 1090 if (ctype_isfield(df->info)) { 1091 if (!uc_cconv_ct_tv(cts, ctype_rawchild(cts, df), 1092 dp + df->size, uv, 0, refs)) 1093 return false; 1094 } 1095 else { 1096 if (!uc_cconv_bf_tv(cts, df, dp + df->size, uv, refs)) 1097 return false; 1098 } 1099 } 1100 1101 if ((d->info & CTF_UNION)) 1102 break; 1103 } 1104 else if (ctype_isxattrib(df->info, CTA_SUBTYPE)) 1105 { 1106 CType *child = ctype_rawchild(cts, df); 1107 if (!cconv_struct_object_init(cts, child, child->size, 1108 dp + df->size, obj, refs)) 1109 return false; 1110 1111 if ((d->info & CTF_UNION)) 1112 break; 1113 } 1114 } 1115 1116 return true; 1117 } 1118 1119 /* Check whether to use a multi-value initializer. 1120 ** This is true if an aggregate is to be initialized with a value. 1121 ** Valarrays are treated as values here so ct_tv handles (V|C, I|F). 1122 */ 1123 int uc_cconv_multi_init(CTState *cts, CType *d, uc_value_t *uv) 1124 { 1125 uc_type_t ut = ucv_type(uv); 1126 GCcdata *cd = (ut == UC_RESOURCE) ? ucv_resource_data(uv, "ffi.ctype") : NULL; 1127 1128 if (!(ctype_isrefarray(d->info) || ctype_isstruct(d->info))) 1129 return 0; /* Destination is not an aggregate. */ 1130 if (ut == UC_ARRAY || ut == UC_OBJECT || (ut == UC_STRING && !ctype_isstruct(d->info))) 1131 return 0; /* Initializer is not a value. */ 1132 if (cd && uc_ctype_rawref(cts, cd->ctypeid) == d) 1133 return 0; /* Source and destination are identical aggregates. */ 1134 return 1; /* Otherwise the initializer is a value. */ 1135 } 1136 1137 /* Initialize C type with TValues. Caveat: expects to get the raw CType! */ 1138 bool uc_cconv_ct_init(CTState *cts, CType *d, CTSize sz, 1139 uint8_t *dp, uc_value_t **uv, size_t len, uc_value_t **refs) 1140 { 1141 if (len == 0) 1142 return memset(dp, 0, sz); 1143 else if (len == 1 && !uc_cconv_multi_init(cts, d, *uv)) 1144 return uc_cconv_ct_tv(cts, d, dp, *uv, 0, refs); 1145 else if (ctype_isarray(d->info)) /* Also handles valarray init with len>1. */ 1146 return cconv_array_init(cts, d, sz, dp, uv, len, refs); 1147 else if (ctype_isstruct(d->info)) { 1148 if (len == 1 && ucv_type(*uv) == UC_OBJECT) 1149 return cconv_struct_object_init(cts, d, sz, dp, *uv, refs); 1150 return cconv_struct_init(cts, d, sz, dp, uv, len, refs); 1151 } 1152 else 1153 return cconv_err_initov(cts, d); 1154 } 1155
This page was automatically generated by LXR 0.3.1. • OpenWrt