diff --git a/texk/web2c/Makefile.in b/texk/web2c/Makefile.in index 05fd556f6c..695e0c1185 100644 --- a/texk/web2c/Makefile.in +++ b/texk/web2c/Makefile.in @@ -5311,6 +5311,8 @@ nodist_libluaffi_a_SOURCES = $(libluaffi_sources) #nodist_liblua53ffi_a_SOURCES = $(libluaffi_sources) libluaffi_sources = \ luatexdir/luaffi/call_arm.h \ + luatexdir/luaffi/call_arm64.h \ + luatexdir/luaffi/call_arm_hf.h \ luatexdir/luaffi/call.c \ luatexdir/luaffi/call_x64.h \ luatexdir/luaffi/call_x64win.h \ diff --git a/texk/web2c/luatexdir/ChangeLog b/texk/web2c/luatexdir/ChangeLog index 663000337b..f4f2f1d877 100644 --- a/texk/web2c/luatexdir/ChangeLog +++ b/texk/web2c/luatexdir/ChangeLog @@ -1,9 +1,13 @@ +2025-01-01 Luigi Scarso + * New luaffi, support for aarch64. + * LuaTeX 1.20.0 + + 2024-12-30 Luigi Scarso * Increment tally in tprint also when doterm is true (thanks to user202729@protonmail.com). * LuaTeX 1.19.4 - 2024-12-30 Luigi Scarso * Avoid useless 0 beginbfrange endbfrange in pdf * LuaTeX 1.19.3 diff --git a/texk/web2c/luatexdir/am/luaffi.am b/texk/web2c/luatexdir/am/luaffi.am index 260b7da833..63c7a657c9 100644 --- a/texk/web2c/luatexdir/am/luaffi.am +++ b/texk/web2c/luatexdir/am/luaffi.am @@ -36,6 +36,8 @@ nodist_libluaffi_a_SOURCES = $(libluaffi_sources) libluaffi_sources = \ luatexdir/luaffi/call_arm.h \ + luatexdir/luaffi/call_arm64.h \ + luatexdir/luaffi/call_arm_hf.h \ luatexdir/luaffi/call.c \ luatexdir/luaffi/call_x64.h \ luatexdir/luaffi/call_x64win.h \ diff --git a/texk/web2c/luatexdir/luaffi/CONTRIBUTING.md b/texk/web2c/luatexdir/luaffi/CONTRIBUTING.md deleted file mode 100644 index 3591e05a0b..0000000000 --- a/texk/web2c/luatexdir/luaffi/CONTRIBUTING.md +++ /dev/null @@ -1,30 +0,0 @@ -# Contributing to luaffifb -We want to make contributing to this project as easy and transparent as -possible. - -## Our Development Process -... (in particular how this is synced with internal changes to the project) - -## Pull Requests -We actively welcome your pull requests. -1. Fork the repo and create your branch from `master`. -2. If you've added code that should be tested, add tests -3. If you haven't already, complete the Contributor License Agreement ("CLA"). - -## Contributor License Agreement ("CLA") -In order to accept your pull request, we need you to submit a CLA. You only need -to do this once to work on any of Facebook's open source projects. - -Complete your CLA here: - -## Issues -We use GitHub issues to track public bugs. Please ensure your description is -clear and has sufficient instructions to be able to reproduce the issue. - -## Coding Style -* Use four spaces for indentation rather than tabs -* 80 character line length - -## License -By contributing to luaffifb, you agree that your contributions will be licensed -under its BSD license. diff --git a/texk/web2c/luatexdir/luaffi/LICENSE b/texk/web2c/luatexdir/luaffi/LICENSE index d38b164449..c2a6fbd8df 100644 --- a/texk/web2c/luatexdir/luaffi/LICENSE +++ b/texk/web2c/luatexdir/luaffi/LICENSE @@ -1,8 +1,39 @@ +This product contains portions of third party software provided under this license: + +ravi-ffi, based on luaffifb (https://github.com/facebookarchive/luaffifb) by Facebook, + based on luaffi (https://github.com/jmckaskill/luaffi) by James R. McKaskill + +Portions Copyright (c) 2018 Dibyendu Majumdar + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + + + +------------------------------------------------------------------------ + +This product contains portions of third party software provided under this license: + BSD License -For luaffifb software +For luaffifb software (enhancements done by Facebook) -Copyright (c) 2015, Facebook, Inc. All rights reserved. +Portions Copyright (c) 2015, Facebook, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -35,7 +66,7 @@ This product contains portions of third party software provided under this licen luaffi software -Copyright (c) 2011 James R. McKaskill +Portions Copyright (c) 2011 James R. McKaskill Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -55,4 +86,3 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Facebook provides this code under the BSD License above. diff --git a/texk/web2c/luatexdir/luaffi/Makefile.orig b/texk/web2c/luatexdir/luaffi/Makefile.orig deleted file mode 100644 index 79bbd4cede..0000000000 --- a/texk/web2c/luatexdir/luaffi/Makefile.orig +++ /dev/null @@ -1,32 +0,0 @@ -# -# Use luarocks to install LuaFFI: -# > git clone https://github.com/facebook/luaffifb -# > cd luaffifb && luarocks make -# -# To rebuild the call_* headers: -# > rm call_*.h && make headers -# - -.PHONY: build clean headers -LUA=lua - -build: - luarocks make - -clean: - rm -f *.o *.so *.dylib - -headers: - $(MAKE) call_x86.h call_x64.h call_x64win.h call_arm.h - -call_x86.h: call_x86.dasc dynasm/*.lua - $(LUA) dynasm/dynasm.lua -LN -o $@ $< - -call_x64.h: call_x86.dasc dynasm/*.lua - $(LUA) dynasm/dynasm.lua -D X64 -LN -o $@ $< - -call_x64win.h: call_x86.dasc dynasm/*.lua - $(LUA) dynasm/dynasm.lua -D X64 -D X64WIN -LN -o $@ $< - -call_arm.h: call_arm.dasc dynasm/*.lua - $(LUA) dynasm/dynasm.lua -LNE -o $@ $< diff --git a/texk/web2c/luatexdir/luaffi/PATENTS b/texk/web2c/luatexdir/luaffi/PATENTS index f6388c50d5..bb0e9c1fcb 100644 --- a/texk/web2c/luatexdir/luaffi/PATENTS +++ b/texk/web2c/luatexdir/luaffi/PATENTS @@ -1,3 +1,5 @@ +Following is from third party software luaffifb (https://github.com/facebookarchive/luaffifb) + Additional Grant of Patent Rights Version 2 "Software" means the luaffifb software distributed by Facebook, Inc. diff --git a/texk/web2c/luatexdir/luaffi/README b/texk/web2c/luatexdir/luaffi/README index 745ed379b9..72b2abfbfe 100644 --- a/texk/web2c/luatexdir/luaffi/README +++ b/texk/web2c/luatexdir/luaffi/README @@ -7,10 +7,10 @@ because there is a ffi stub that does nothing: local info = [[ The ffi module is available for: - archictures : ARCH_X86 and ARCH_X64, + archictures : ARCH_X86, ARCH_X64 and ARM_64, operating systems : OS_CE, OS_WIN, OS_LINUX, OS_BSD and OS_POSIX -The ARM processor is currently not supported. There are subtle +The ARM 32bit processor is currently not supported. There are subtle differences between this module and the one in luajitTeX and we hope to be in sync around TeXLive 2025. Different OS can have different interfaces, @@ -72,7 +72,7 @@ the OS enabled are OS_CE, OS_WIN, OS_LINUX, OS BD and OS_POSIX. Currently ARM is not supported. The module is not aligned with luajit-2.1.0.beta2 -(the plan is to be in sync for TeXLive 2018) and +(the plan is to be in sync for TeXLive 2025) and test.lua can fail. Be careful that different OS have different interfaces (i.e. OS_WIN has not complex.h, for example) so extra care must be take to ensure code portability. diff --git a/texk/web2c/luatexdir/luaffi/README.md b/texk/web2c/luatexdir/luaffi/README.md index b9a168c100..fd1f21ab9c 100644 --- a/texk/web2c/luatexdir/luaffi/README.md +++ b/texk/web2c/luatexdir/luaffi/README.md @@ -1,36 +1,54 @@ -[![Build Status](https://travis-ci.org/facebook/luaffifb.svg?branch=master)](https://travis-ci.org/facebook/luaffifb) - About ----- -This is a library for calling C function and manipulating C types from lua. It -is designed to be interface compatible with the FFI library in LuaJIT (see -http://luajit.org/ext_ffi.html). It can parse C function declarations and -struct definitions that have been directly copied out of C header files and +This is a library for calling C function and manipulating C types from [Ravi](https://github.com/dibyendumajumdar/ravi). It +is designed to be interface compatible with the FFI library in [LuaJIT's ffi](http://luajit.org/ext_ffi.html). +It can parse C function declarations and struct definitions that have been directly copied out of C header files and into lua source as a string. -This is a fork of https://github.com/jmckaskill/luaffi +This project is a fork of https://github.com/facebook/luaffifb which is a fork of https://github.com/jmckaskill/luaffi. Source ------ -https://github.com/facebook/luaffifb +https://github.com/dibyendumajumdar/ravi-ffi Platforms --------- -Currently supported: -- Linux x86/x64 -- OS X x86/x64 +Currently being developed for: +- Linux x64 - builds and tests pass +- OS X x64 - builds and tests pass +- Windows 10 x64 - builds and tests pass -Runs with Lua 5.1, 5.2, and 5.3 +Ravi and Lua 5.3 are supported. Build ----- -In a terminal: +This project requires: + +* CMake installation +* Ravi 5.3 installation + +Windows 10 +---------- +* Note that only Visual Studio 2017 is supported. +* Note that only x86-64 is supported + +In the instructions below, we assume that Ravi was installed under `c:/Software/ravi`. ```bash -git clone https://github.com/facebook/luaffifb -cd luaffifb -luarocks make +git clone https://github.com/dibyendumajumdar/ravi-ffi +cd ravi-ffi +mkdir build +cd build +cmake -DCMAKE_INSTALL_PREFIX=/Software/Ravi -G "Visual Studio 15 2017 Win64" .. +``` + +Above creates Visual Studio projects which can be used to build and install. Note that the install prefix ensures that the DLL files will be installed under /Software/ravi/bin so that they can be found by the library. + +To build for Lua, change above to: +``` +cmake -DCMAKE_INSTALL_PREFIX=/Software/lua53 -DUSE_LUA53=ON -G "Visual Studio 15 2017 Win64" .. ``` +This assumes Lua 5.3 installation under `/Software/lua53'. Documentation ------------- diff --git a/texk/web2c/luatexdir/luaffi/call.c b/texk/web2c/luatexdir/luaffi/call.c index 71bb3aea88..09f38ed389 100644 --- a/texk/web2c/luatexdir/luaffi/call.c +++ b/texk/web2c/luatexdir/luaffi/call.c @@ -6,12 +6,13 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ + #include "ffi.h" static cfunction compile(Dst_DECL, lua_State* L, cfunction func, int ref); static void* reserve_code(struct jit* jit, lua_State* L, size_t sz); -static void commit_code(struct jit* jit, void* p, size_t sz); +static void commit_code(struct jit *jit, size_t sz); static void push_int(lua_State* L, int val) { lua_pushinteger(L, val); } @@ -22,13 +23,6 @@ static void push_uint(lua_State* L, unsigned int val) static void push_float(lua_State* L, float val) { lua_pushnumber(L, val); } -#ifndef _WIN32 -static int GetLastError(void) -{ return errno; } -static void SetLastError(int err) -{ errno = err; } -#endif - #ifdef NDEBUG #define shred(a,b,c) #else @@ -42,9 +36,18 @@ static void SetLastError(int err) #elif defined __amd64__ #include "dynasm/dasm_x86.h" #include "call_x64.h" -#elif defined __arm__ || defined __arm || defined __ARM__ || defined __ARM || defined ARM || defined _ARM_ || defined ARMV4I || defined _M_ARM +#elif defined(ARCH_ARM) #include "dynasm/dasm_arm.h" +//See http://code.google.com/p/v8/issues/detail?id=2140 for more information +#if defined(__ARM_PCS_VFP) || (GCC_VERSION==40500||defined(__clang__))&&!defined(__ARM_PCS) && !defined(__SOFTFP__) && !defined(__SOFTFP) && \ + defined(__VFP_FP__) +#include "call_arm_hf.h" +#else #include "call_arm.h" +#endif +#elif defined ARCH_ARM64 +#include "dynasm/dasm_arm64.h" +#include "call_arm64.h" #else #include "dynasm/dasm_x86.h" #include "call_x86.h" @@ -53,10 +56,12 @@ static void SetLastError(int err) struct jit_head { size_t size; int ref; +#ifndef NO_FUNCTION_EXTERN uint8_t jump[JUMP_SIZE]; +#endif }; -#define LINKTABLE_MAX_SIZE (sizeof(extnames) / sizeof(extnames[0]) * (JUMP_SIZE)) +#define LINKTABLE_MAX_SIZE ((sizeof(extnames) / sizeof(extnames[0])-1) * (JUMP_SIZE)) static cfunction compile(struct jit* jit, lua_State* L, cfunction func, int ref) { @@ -75,17 +80,20 @@ static cfunction compile(struct jit* jit, lua_State* L, cfunction func, int ref) code = (struct jit_head*) reserve_code(jit, L, codesz); code->ref = ref; code->size = codesz; +#ifndef NO_FUNCTION_EXTERN compile_extern_jump(jit, L, func, code->jump); +#endif if ((err = dasm_encode(jit, code+1)) != 0) { char buf[32]; sprintf(buf, "%x", err); - commit_code(jit, code, 0); + commit_code(jit, 0); luaL_error(L, "dasm_encode error %s", buf); } - commit_code(jit, code, codesz); - return (cfunction) (code+1); + commit_code(jit, codesz); + cfunction ret = (cfunction) (code + 1); + return ret; } typedef uint8_t jump_t[JUMP_SIZE]; @@ -97,10 +105,12 @@ int get_extern(struct jit* jit, uint8_t* addr, int idx, int type) struct jit_head* h = (struct jit_head*) ((uint8_t*) page + page->off); uint8_t* jmp; ptrdiff_t off; - +#ifndef NO_FUNCTION_EXTERN if (idx == jit->function_extern) { jmp = h->jump; - } else { + } else +#endif + { jmp = jumps[idx]; } @@ -112,12 +122,20 @@ int get_extern(struct jit* jit, uint8_t* addr, int idx, int type) * jump instruction */ off = *(uint8_t**) jmp - addr; - if (MIN_BRANCH <= off && off <= MAX_BRANCH) { + if (MIN_BRANCH <= off && off <= MAX_BRANCH + // thumb address must be called by extern jump rather than direct jump +#ifdef ARCH_ARM + &&((*(uintptr_t*) jmp)&1)==0 +#endif + ) { return (int32_t) off; } else { return (int32_t)(jmp + sizeof(uint8_t*) - addr); } } +static void rawgeti(lua_State* L,int idx,ptrdiff_t key){ + lua_rawgeti(L,idx,key); +} static void* reserve_code(struct jit* jit, lua_State* L, size_t sz) { @@ -140,16 +158,24 @@ static void* reserve_code(struct jit* jit, lua_State* L, size_t sz) pdata = (uint8_t*) page; page->size = size; page->off = sizeof(struct page); + if(jit->default_functions!=NULL){ + memcpy((uint8_t*)(page+1),jit->default_functions,LINKTABLE_MAX_SIZE); + page->off+=LINKTABLE_MAX_SIZE; + page->freed=page->off; + goto End; + } lua_newtable(L); -#define ADDFUNC(DLL, NAME) \ +#define ADD_FUNC_WITH_NAME(DLL, NAME,FUNC) \ lua_pushliteral(L, #NAME); \ - func = DLL ? (cfunction) GetProcAddressA(DLL, #NAME) : NULL; \ - func = func ? func : (cfunction) &NAME; \ + func = DLL ? (cfunction) GetProcAddressA(DLL, #FUNC) : NULL; \ + func = func ? func : (cfunction) &FUNC; \ lua_pushcfunction(L, (lua_CFunction) func); \ lua_rawset(L, -3) +#define ADDFUNC(DLL, NAME) ADD_FUNC_WITH_NAME(DLL,NAME,NAME) + ADDFUNC(NULL, check_double); ADDFUNC(NULL, check_float); ADDFUNC(NULL, check_uint64); @@ -158,6 +184,7 @@ static void* reserve_code(struct jit* jit, lua_State* L, size_t sz) ADDFUNC(NULL, check_uint32); ADDFUNC(NULL, check_uintptr); ADDFUNC(NULL, check_enum); + ADDFUNC(NULL, check_struct); ADDFUNC(NULL, check_typed_pointer); ADDFUNC(NULL, check_typed_cfunction); ADDFUNC(NULL, check_complex_double); @@ -167,31 +194,45 @@ static void* reserve_code(struct jit* jit, lua_State* L, size_t sz) ADDFUNC(NULL, unpack_varargs_reg); ADDFUNC(NULL, unpack_varargs_float); ADDFUNC(NULL, unpack_varargs_int); + ADDFUNC(NULL, memcpy);//for x86,x64 only +#if ARM_HF + ADDFUNC(NULL, unpack_varargs_bound); +#endif ADDFUNC(NULL, push_cdata); ADDFUNC(NULL, push_int); ADDFUNC(NULL, push_uint); ADDFUNC(NULL, lua_pushinteger); ADDFUNC(NULL, push_float); - ADDFUNC(jit->kernel32_dll, SetLastError); - ADDFUNC(jit->kernel32_dll, GetLastError); ADDFUNC(jit->lua_dll, luaL_error); ADDFUNC(jit->lua_dll, lua_pushnumber); ADDFUNC(jit->lua_dll, lua_pushboolean); ADDFUNC(jit->lua_dll, lua_gettop); - ADDFUNC(jit->lua_dll, lua_rawgeti); +#if LUA_VERSION_NUM<503 || defined(__LP64__) || defined(__amd64__) ||defined (_WIN64) + ADD_FUNC_WITH_NAME(jit->lua_dll,rawgeti, lua_rawgeti); +#else + ADDFUNC(NULL,rawgeti); + +#endif +#if LUA_VERSION_NUM<502 + ADD_FUNC_WITH_NAME(jit->lua_dll, lua_setuservalue,lua_setfenv); +#else + ADDFUNC(jit->lua_dll, lua_setuservalue); +#endif ADDFUNC(jit->lua_dll, lua_pushnil); - ADDFUNC(jit->lua_dll, lua_callk); + ADDFUNC(jit->lua_dll, lua_call); ADDFUNC(jit->lua_dll, lua_settop); ADDFUNC(jit->lua_dll, lua_remove); + ADDFUNC(jit->lua_dll, lua_pushvalue); #undef ADDFUNC for (i = 0; extnames[i] != NULL; i++) { - +#ifndef NO_FUNCTION_EXTERN if (strcmp(extnames[i], "FUNCTION") == 0) { shred(pdata + page->off, 0, JUMP_SIZE); jit->function_extern = i; - - } else { + } else +#endif + { lua_getfield(L, -1, extnames[i]); func = (cfunction) lua_tocfunction(L, -1); @@ -202,10 +243,14 @@ static void* reserve_code(struct jit* jit, lua_State* L, size_t sz) compile_extern_jump(jit, L, func, pdata + page->off); lua_pop(L, 1); } - page->off += JUMP_SIZE; } - +#ifndef NO_FUNCTION_EXTERN + if(jit->function_extern==0){ + luaL_error(L, "internal error: should define extern FUNCTION"); + } +#endif + jit->default_functions=(uint8_t*)(page+1); page->freed = page->off; lua_pop(L, 1); @@ -213,22 +258,15 @@ static void* reserve_code(struct jit* jit, lua_State* L, size_t sz) page = jit->pages[jit->pagenum-1]; EnableWrite(page, page->size); } - + End: return (uint8_t*) page + page->off; } -static void commit_code(struct jit* jit, void* code, size_t sz) +static void commit_code(struct jit *jit, size_t sz) { struct page* page = jit->pages[jit->pagenum-1]; page->off += sz; EnableExecute(page, page->size); - { -#if 0 - FILE* out = fopen("\\Hard Disk\\out.bin", "wb"); - fwrite(page, page->off, 1, out); - fclose(out); -#endif - } } /* push_func_ref pushes a copy of the upval table embedded in the compiled @@ -262,7 +300,9 @@ void free_code(struct jit* jit, lua_State* L, cfunction func) EnableExecute(p, p->size); return; } - + if((uint8_t*)(p+1)==jit->default_functions){ + jit->default_functions=NULL; + } FreePage(p, p->size); memmove(&jit->pages[i], &jit->pages[i+1], (jit->pagenum - (i+1)) * sizeof(jit->pages[0])); jit->pagenum--; diff --git a/texk/web2c/luatexdir/luaffi/call_arm.dasc b/texk/web2c/luatexdir/luaffi/call_arm.dasc index f85753255f..a5f371bf97 100644 --- a/texk/web2c/luatexdir/luaffi/call_arm.dasc +++ b/texk/web2c/luatexdir/luaffi/call_arm.dasc @@ -6,15 +6,39 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ + +//The generate code is for arm not for thumb |.arch arm + |.actionlist build_actionlist |.globalnames globnames |.externnames extnames #define JUMP_SIZE 8 + #define MIN_BRANCH ((INT32_MIN) >> 8) #define MAX_BRANCH ((INT32_MAX) >> 8) -#define BRANCH_OFF 4 +//arm pc offset 8 so comparing with next instruction is 4, +//unlike x86 which pass in the current instruction address+1 rather than the next instruction +#define BRANCH_OFF 4 + + +#define ROUND_UP(x, align) (((int) (x) + (align - 1)) & ~(align - 1)) +#ifdef TARGET_OS_IPHONE +#define CK_ALGIN 0 +#else +#define CK_ALGIN 1 +#endif +#define ALIGNED(x, align) (!CK_ALGIN||((int)(x) & (align - 1)) == 0) +#if defined(__ARM_PCS_VFP) || (GCC_VERSION==40500||defined(__clang__))&&!defined(__ARM_PCS) && !defined(__SOFTFP__) && !defined(__SOFTFP) && \ + defined(__VFP_FP__) +#define ARM_HF 1 +#else +#define ARM_HF 0 +#endif +#if ARM_HF&&!CK_ALGIN +#error "Unsupported unaligned stack for hard floating point" +#endif static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, uint8_t* code) { @@ -25,21 +49,21 @@ static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, u * Note we have to manually set this up since there are commands buffered * in the jit state. */ + *(cfunction*) code = func; - /* ldr pc, [pc - 12] */ - *(uint32_t*) &code[4] = 0xE51FF00CU; + //ldr pc, [pc - 12] + *(uint32_t*) &code[4] = 0xE51FF00CU; + } -|.define TOP, r4 -|.define L_ARG, r5 +|.define L_ARG, r4 +|.define TOP, r5 +|.define INFO, r5 |.define DATA, r6 -|.define DATA2, r7 |.macro load32, reg, val -| ldr reg, [pc] -| b >5 -|.long val -|5: +| movw reg, #(unsigned short)(val) +| movt reg, #(((unsigned int)(val))>>16) |.endmacro |.macro lcall, func @@ -52,11 +76,379 @@ void compile_globals(struct jit* jit, lua_State* L) (void) jit; } +typedef struct stack_info{ + int extra; + int int_off; + int stack_off; + int float_size; +#if ARM_HF + int float_off; +#endif +} stack_info; +//vfp use back-filling rule for registers until a float value on stack +typedef struct reg_info{ + uint16_t exs; + union{ + uint8_t ints; + uint8_t regs; + }; +#if ARM_HF + uint8_t float_sealed; + short floats;//each bit is a float: s0-s15 or v0-v7 or q0-q3 + uint8_t left_single; + uint8_t highest_bit; +#endif +} reg_info; + +#define MAX_REGS 4 +#define MAX_FLOAT_REGS 16 +#ifndef bool +#define bool uint8_t +#endif + +#define has_bit(x,b) (((x)&(1<<(b)))!=0) +#define set_bit(x,b) (x=((x)|(1<<(b)))) +#define FIX_ALIGN(x,al) \ + if(!ALIGNED((x),al)){\ + x=ROUND_UP(x,al);\ + } +static ALWAYS_INLINE bool is_float_sealed(reg_info* regs){ +#if ARM_HF +return regs->float_sealed; +#else +return regs->regs>=MAX_REGS; +#endif +} +//return size need to put on stack +static ALWAYS_INLINE int add_int_reg(reg_info* regs){ + if(regs->regsregs++; + return 0; + } + return 1; + +} +//return size need to put on stack +static ALWAYS_INLINE int add_int64_reg(reg_info* regs){ + if(regs->regsregs=ROUND_UP(regs->regs,2)+2; + return 0; + }else if(regs->regs==MAX_REGS-1){ + regs->regs=MAX_REGS; + } + + return 2; +} +static ALWAYS_INLINE bool is_float_type(int t){ + return t==FLOAT_TYPE||t==DOUBLE_TYPE; +} +static int hfa_size(lua_State* L,int idx, const struct ctype* ct,int* isfloat){ + struct ctype* mt; + int type,ele_count,i,ct_usr; + lua_getuservalue(L,idx); + ct_usr=lua_absindex(L,-1); + lua_rawgeti(L,ct_usr,1); + mt=(struct ctype*)lua_touserdata(L,-1); + if(mt==NULL||(mt->pointers&&!mt->is_array)||mt->is_reference||!is_float_type(mt->type)){ + lua_pop(L,2); + if(ct->type==COMPLEX_DOUBLE_TYPE){ + if(isfloat) *isfloat=0; + return 4; + }else if(ct->type==COMPLEX_FLOAT_TYPE){ + if(isfloat) *isfloat=1; + return 2; + } + return 0; + } + type=mt->type; + ele_count=(int)(ct->base_size/mt->base_size); + if(ele_count>4||ct->base_size%mt->base_size){ + lua_pop(L,2); + return 0; + } + lua_pop(L,1); + for (i = 2; i <=4 ; ++i) { + lua_rawgeti(L,ct_usr,i); + if(lua_isnil(L,-1)){//case have array member; + lua_pop(L,1); + break; + } + mt=(struct ctype*)lua_touserdata(L,-1); + if(mt->type!=type||(mt->pointers&&!mt->is_array)||mt->is_reference||!is_float_type(mt->type)){ + lua_pop(L,2); + return 0; + } + lua_pop(L,1); + } + if(isfloat){ + *isfloat=mt->type==FLOAT_TYPE; + } + lua_pop(L,1); + return ele_count*(mt->type==FLOAT_TYPE?1:2); +} +#if ARM_HF +static void save_float_reg(struct jit* Dst,int reg,int size,stack_info* st){ + int sz; + if(reg==-1) return; + for(;size>0;size-=8){ + sz=size>8?8:size; + |.if ARM_HF + switch(sz){ + case 4: + switch(reg){ + case 0: + | vstr s0,[sp,#st->float_size] + break; + case 1: + | vstr s1,[sp,#st->float_size] + break; + case 2: + | vstr s2,[sp,#st->float_size] + break; + case 3: + | vstr s3,[sp,#st->float_size] + break; + case 4: + | vstr s4,[sp,#st->float_size] + break; + case 5: + | vstr s5,[sp,#st->float_size] + break; + case 6: + | vstr s6,[sp,#st->float_size] + break; + case 7: + | vstr s7,[sp,#st->float_size] + break; + case 8: + | vstr s8,[sp,#st->float_size] + break; + case 9: + | vstr s9,[sp,#st->float_size] + break; + case 10: + | vstr s10,[sp,#st->float_size] + break; + case 11: + | vstr s11,[sp,#st->float_size] + break; + case 12: + | vstr s12,[sp,#st->float_size] + break; + case 13: + | vstr s13,[sp,#st->float_size] + break; + case 14: + | vstr s14,[sp,#st->float_size] + break; + case 15: + | vstr s15,[sp,#st->float_size] + break; + } + break; + case 8: + switch(reg>>1){ + case 0: + | vstr d0,[sp,#st->float_size] + break; + case 1: + | vstr d1,[sp,#st->float_size] + break; + case 2: + | vstr d2,[sp,#st->float_size] + break; + case 3: + | vstr d3,[sp,#st->float_size] + break; + case 4: + | vstr d4,[sp,#st->float_size] + break; + case 5: + | vstr d5,[sp,#st->float_size] + break; + case 6: + | vstr d6,[sp,#st->float_size] + break; + case 7: + | vstr d7,[sp,#st->float_size] + break; + } + reg+=2; + break; + } + |.endif + st->float_size+=sz; + } +} + +//128 bit vector type is not supported by this +static int add_float_reg(reg_info* regs,int sz,int isfloat){ + + if(is_float_sealed(regs)) return -1; + int i,ret=-1; + if(sz==1){ + if(regs->left_single){ + int n=regs->highest_bit; + for(i=0;ifloats,i)){ + regs->left_single--; + set_bit(regs->floats,i); + ret=i; + } + } + }else{ + ret=regs->highest_bit; + set_bit(regs->floats,regs->highest_bit); + ++regs->highest_bit; + } + }else{ + if(regs->highest_bit>MAX_FLOAT_REGS-sz){ + regs->highest_bit=MAX_FLOAT_REGS; + }else{ + if(!isfloat&&!ALIGNED(regs->highest_bit, 2)){ + regs->highest_bit++; + regs->left_single++; + } + ret=regs->highest_bit; + for(i=0;ifloats,regs->highest_bit++); + } + } + } + if(regs->highest_bit==MAX_FLOAT_REGS){ + regs->float_sealed=true; + } + return ret; +} +#endif +static void load_reg(struct jit* Dst,int off,int size){ + if(size==16){ + | add r12, sp,#off + | ldmia r12, {r1, r2, r3, r12} + }else if(size==12){ + | add r12, sp,#off + | ldmia r12, {r1, r2, r3, r12} + }else if(size==8){ + | add r12, sp,#off + | ldmia r12, {r1, r2} + }else{ + | ldr r1, [sp,#off] + } +} +// arm store/load range for immediate value is only -256-255 +static void load_stack(struct jit* Dst,stack_info* st,int size,int align){ + int off=st->stack_off; + FIX_ALIGN(st->stack_off,align); + if((off=st->stack_off-off)){ + | add DATA, DATA, #off + } + if(size==16){ + | ldmia DATA!, {r1, r2, r3, r12} + }else if(size==8){ + | ldmia DATA!, {r1, r2} + }else{ + | ldr r1, [DATA],#4 + } + st->stack_off+=size; +} + +static void load_int(struct jit* Dst,stack_info* st,int size,int align){ + FIX_ALIGN(st->int_off,align); + if(st->int_off<0x40*ARM_HF+MAX_REGS*4&&(!st->stack_off||MAX_REGS*4+size<=0x40*ARM_HF+MAX_REGS*4)){ + load_reg(Dst,st->int_off+st->extra,size); + st->int_off+=size; + }else{ + st->int_off=0x40*ARM_HF+MAX_REGS*4; + load_stack(Dst,st,size,align); + } + +} + +static void load_float(struct jit* Dst,stack_info* st,int size,int vfp,int align){ + #if ARM_HF + if(st->float_offfloat_size){ + |.if ARM_HF + if(vfp){ + if(size==4){//float + | vldr s0, [sp,#st->float_off+st->extra]; + }else if(size==8){//double + | vldr d0, [sp,#st->float_off+st->extra]; + } + }else load_reg(Dst,st->float_off+st->extra,size); + st->float_off+=size; + }else if(vfp){ + if(size==4){//float + | vldr s0, [DATA]; + | add DATA, DATA, #4 + }else if(size==8){//double + int off=st->stack_off; + FIX_ALIGN(st->stack_off,align); + if((off=st->stack_off-off)){ + | add DATA, DATA, #off + } + | vldr d0, [DATA]; + | add DATA, DATA, #8 + } + |.endif + }else{ + load_stack(Dst,st,size,align); + } + #else + load_int(Dst,st,size,align); + #endif +} +#if ARM_HF +static void push_regs(lua_State* L,struct jit* Dst,int ct_usr,int nargs,stack_info* st){ + const struct ctype* mt; + reg_info regs;int i; + memset(®s,0,sizeof(reg_info)); + for (i = 1; i <= nargs&&!is_float_sealed(®s); ++i){ + lua_rawgeti(L, ct_usr, i); + mt = (const struct ctype*) lua_touserdata(L, -1); + if (!mt->pointers &&! mt->is_reference) { + switch(mt->type){ + case COMPLEX_DOUBLE_TYPE: + save_float_reg(Dst,add_float_reg(®s,4,0),16,st); + break; + case DOUBLE_TYPE: + save_float_reg(Dst,add_float_reg(®s,2,0),8,st); + break; + case COMPLEX_FLOAT_TYPE: + save_float_reg(Dst,add_float_reg(®s,2,1),8,st); + break; + case FLOAT_TYPE: + save_float_reg(Dst,add_float_reg(®s,1,1),4,st); + break; + case STRUCT_TYPE: + { + int isfloat,hfasize=hfa_size(L,-1,mt,&isfloat); + if(hfasize){ + save_float_reg(Dst,add_float_reg(®s,hfasize,isfloat),4*hfasize,st); + break; + } + } + case UNION_TYPE: + break; + case INT64_TYPE: + //add_int64_reg(®s); + break; + default: + //add_int_reg(®s);//no need to check type support here + break; + } + } + lua_pop(L,1); + } + st->float_off+=st->int_off; + st->int_off+=0x40; +} +#endif cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctype* ct) { struct jit* Dst = get_jit(L);; int i, nargs, num_upvals, ref; const struct ctype* mt; + stack_info st; int top = lua_gettop(L); @@ -74,27 +466,45 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp if (ct->has_var_arg) { luaL_error(L, "can't create callbacks with varargs"); } - + memset(&st,0,sizeof(stack_info)); + st.extra=0x10; /* prolog and get the upval table */ | mov r12, sp - | push {r0, r1, r2, r3} // do this first so that r0-r3 is right before stack bound arguments - | push {TOP, L_ARG, DATA, DATA2, r12, lr} - | sub DATA, r12, #16 // points to r0 on stack - | ldr L_ARG, [pc, #8] - | ldr r2, [pc, #8] - | ldr r1, [pc, #8] - | b >1 - |.long L, ref, LUA_REGISTRYINDEX - |1: - | lcall extern lua_rawgeti - + | push {r0,r1,r2,r3} +#if ARM_HF + |.if ARM_HF + | sub sp, sp , #0x40 + |.endif + push_regs(L,Dst,ct_usr,nargs,&st); +#endif + + | push {L_ARG, DATA, r12, lr} + | mov DATA, r12 + | load32 L_ARG, L + | load32 r2, ref + | load32 r1, LUA_REGISTRYINDEX + | lcall extern rawgeti + /* get the lua function */ lua_pushvalue(L, fidx); lua_rawseti(L, -2, ++num_upvals); + + | mov r2, #num_upvals | mvn r1, #0 // -1 - | lcall extern lua_rawgeti + | lcall extern rawgeti + // Complex type is return in the address stored in r0 for softfp + lua_rawgeti(L, ct_usr, 0); + mt = (const struct ctype*) lua_touserdata(L, -1); + if(!mt->pointers && !mt->is_reference &&(mt->type==STRUCT_TYPE || mt->type==UNION_TYPE|| + ||(!ARM_HF&&(mt->type==COMPLEX_DOUBLE_TYPE||mt->type==COMPLEX_FLOAT_TYPE)))&&mt->base_size>4&&!(ARM_HF&&hfa_size(L,-1,mt,NULL))){ + st.int_off+=4; + } + lua_pop(L,1); + + //whether 64 bit type requires 8 bytes alignment in stack is defined by compiler.android compiler reqiures only 4 byte alignment; + //actually the stack it self may reqiures 8 bytes alignment for (i = 1; i <= nargs; i++) { lua_rawgeti(L, ct_usr, i); mt = (const struct ctype*) lua_touserdata(L, -1); @@ -103,95 +513,228 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* usr value */ lua_rawseti(L, -2, ++num_upvals); /* mt */ - + | mov r2, #num_upvals-1 // usr value | mvn r1, #i // -i-1, stack is upval table, func, i-1 args - | lcall extern lua_rawgeti + | lcall extern rawgeti | load32 r2, mt - | mvn r1, #0 // -1 + | mvn r1, #0 //-1 | lcall extern push_cdata - | ldr r2, [DATA], #4 - | str r2, [r0] + load_int(Dst,&st,4,4); + | str r1, [r0] | mvn r1, #1 // -2 | lcall extern lua_remove // remove the usr value - } else { switch (mt->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ + #if ARM_HF + int isfloat,hfasize=0; + if(mt->type!=UNION_TYPE){ + hfasize=hfa_size(L,-1,mt,&isfloat); + } + #endif + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + | mov r2, #num_upvals-1 // usr value + | mvn r1, #i // -i-1, stack is upval table, func, i-1 args + | lcall extern rawgeti + | load32 r2, mt + | mvn r1, #0 //-1 + | lcall extern push_cdata + #if ARM_HF + |.if ARM_HF + if(hfasize){ + if(hfasize<=4)load_float(Dst,&st,4*hfasize,0,4*(2-isfloat)); + switch(hfasize){ + case 8: + load_float(Dst,&st,16,0,8); + | stmia r0!, {r1, r2, r3, r12} + load_float(Dst,&st,16,0,8); + | stmia r0, {r1, r2, r3, r12} + break; + case 6: + load_float(Dst,&st,16,0,8); + | stmia r0!, {r1, r2, r3, r12} + load_float(Dst,&st,8,0,8); + | stmia r0, {r1, r2} + break; + case 4: + | stmia r0, {r1, r2, r3, r12} + break; + case 3: + | stmia r0, {r1, r2, r3} + break; + case 2: + | stmia r0, {r1, r2} + break; + case 1: + | str r1, [r0] + break; + } + }else + |.endif + #endif + if(!mt->is_empty){ + int size=mt->base_size; + if(size<=4){ + load_int(Dst,&st,4,4); + | str r1, [r0] + }else{ + size=ROUND_UP(size,4); + if(mt->align_mask>4){//8 byte max alignment + if(st.int_off<0x40*ARM_HF+MAX_REGS*4){FIX_ALIGN(st.int_off,8);} + else {FIX_ALIGN(st.stack_off,8);} + } + + if(st.int_off<0x40*ARM_HF+MAX_REGS*4&&(!st.stack_off||st.int_off+size<=0x40*ARM_HF+MAX_REGS*4)){//to ensure consective memory for the struct + | add r1, sp, #st.int_off+st.extra + st.int_off+=size; + }else{ + st.int_off=0x40*ARM_HF+MAX_REGS*4; + | mov r1, DATA + st.stack_off+=size; + } + | load32 r2, mt->base_size + | load32 r12, memcpy + | blx r12 + } + } + | mvn r1, #1 // -2 + | lcall extern lua_remove // remove the nil usr + break; + } + + case COMPLEX_DOUBLE_TYPE: + + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + | mov r2, #num_upvals-1 // usr value + | mvn r1, #i // -i-1, stack is upval table, func, i-1 args + | lcall extern rawgeti + | load32 r2, mt + | mvn r1, #0 //-1 + | lcall extern push_cdata + load_float(Dst,&st,16,0,8); + | stmia r0, {r1, r2, r3, r12} + | mvn r1, #1 // -2 + | lcall extern lua_remove // remove the nil usr + break; + case COMPLEX_FLOAT_TYPE: + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + | mov r2, #num_upvals-1 // usr value + | mvn r1, #i // -i-1, stack is upval table, func, i-1 args + | lcall extern rawgeti + | load32 r2, mt + | mvn r1, #0 //-1 + | lcall extern push_cdata + load_float(Dst,&st,8,0,4); + | stmia r0, {r1, r2} + | mvn r1, #1 // -2 + | lcall extern lua_remove // remove the nil usr + break; case INT64_TYPE: + + #if LUA_VERSION_NUM>=503 + lua_pop(L, 1); + + #if CK_ALGIN + FIX_ALIGN(st.int_off,8); + if(st.int_off<16){ + | add r12, sp,#st.int_off+st.extra + | ldmia r12, {r2, r3} + st.int_off+=8; + }else{ + if(!ALIGNED(st.stack_off,8)){ + st.stack_off+=4; + | add DATA,DATA,#4 + } + | ldmia DATA!, {r2, r3} + st.stack_off+=8; + } + #else + load_int(Dst,st,8,8); + #endif + | lcall extern lua_pushinteger + #else lua_rawseti(L, -2, ++num_upvals); /* mt */ - | lcall extern lua_pushnil + | load32 r2, mt - | mvn r1, #0 // -1 + | mov r1, #0 | lcall extern push_cdata - | ldr r2, [DATA], #4 - | ldr r3, [DATA], #4 - | str r2, [r0] - | str r3, [r0, #4] + load_int(Dst,&st,8,8); + | stmia r0, {r1, r2} | mvn r1, #1 // -2 | lcall extern lua_remove // remove the nil usr + #endif break; case INTPTR_TYPE: lua_rawseti(L, -2, ++num_upvals); /* mt */ - | lcall extern lua_pushnil + | load32 r2, mt - | mvn r1, #0 // -1 + | mov r1, #0 | lcall extern push_cdata - | ldr r2, [DATA], #4 - | str r2, [r0] + load_int(Dst,&st,4,4); + | str r1, [r0] | mvn r1, #1 // -2 | lcall extern lua_remove // remove the nil usr + break; case BOOL_TYPE: lua_pop(L, 1); - | ldr r1, [DATA], #4 + + load_int(Dst,&st,4,4); | lcall extern lua_pushboolean break; - case INT8_TYPE: - lua_pop(L, 1); - | ldr r1, [DATA], #4 - | mov r1, r1, lsl #24 - if (mt->is_unsigned) { - | mov r1, r1, lsr #24 - } else { - | mov r1, r1, asr #24 - } - | lcall extern push_int - break; - - case INT16_TYPE: - lua_pop(L, 1); - | ldr r1, [DATA], #4 - | mov r1, r1, lsl #16 - if (mt->is_unsigned) { - | mov r1, r1, lsr #16 - } else { - | mov r1, r1, asr #16 - } - | lcall extern push_int - break; - + case INT8_TYPE: // no need to narrow cause narrowed by caller + case INT16_TYPE: // no need to narrow cause narrowed by caller case ENUM_TYPE: case INT32_TYPE: lua_pop(L, 1); - | ldr r1, [DATA], #4 + + load_int(Dst,&st,4,4); | lcall extern push_int break; case FLOAT_TYPE: lua_pop(L, 1); - | ldr r1, [DATA], #4 + + load_float(Dst,&st,4,ARM_HF,4); | lcall extern push_float break; case DOUBLE_TYPE: lua_pop(L, 1); - | ldmia DATA!, {r1, r2} + + #if ARM_HF + load_float(Dst,&st,8,ARM_HF,8); + #elif CK_ALGIN + FIX_ALIGN(st.int_off,8); + if(st.int_off<16){ + | add r12, sp,#st.int_off+st.extra + | ldmia r12, {r2, r3} + st.int_off+=8; + }else{ + if(!ALIGNED(st.stack_off,8)){ + st.stack_off+=4; + | add DATA,DATA,#4 + } + | ldmia DATA!, {r2, r3} + st.stack_off+=8; + } + #else + load_float(Dst,&st,8,ARM_HF,8); + #endif | lcall extern lua_pushnumber break; - + default: luaL_error(L, "NYI: callback arg type"); } @@ -201,63 +744,126 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_rawgeti(L, ct_usr, 0); mt = (const struct ctype*) lua_touserdata(L, -1); - | mov r3, #0 | mov r2, #((mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0) | mov r1, #nargs - | lcall extern lua_callk + | lcall extern lua_call + + |.macro retcdata, func + | mov r2, #num_upvals-1 // usr value + | mvn r1, #1 // -2 stack is (upval table, ret val) + | lcall extern rawgeti + | load32 r3, mt + | mvn r2, #0 // -1 - ct_usr + | mvn r1, #1 // -2 - val + | lcall extern func + |.endmacro if (mt->pointers || mt->is_reference) { lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* usr value */ lua_rawseti(L, -2, ++num_upvals); /* mt */ - | mov r2, #num_upvals-1 // usr value - | mvn r1, #1 // -2 stack is (upval table, ret val) - | lcall extern lua_rawgeti - | load32 r3, mt - | mov r2, #0 // -1 - ct_usr - | mvn r1, #1 // -2 - val - | lcall extern to_typed_pointer - | mov DATA, r0 - | mvn r1, #3 // -4 - remove 3 (upval table, ret val, usr value) - | lcall extern lua_settop - | mov r0, DATA + | retcdata check_typed_pointer + goto single_no_pop; } else { switch (mt->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ + int isfloat,hfasize=0; + if(mt->type!=UNION_TYPE){ + hfasize=hfa_size(L,-1,mt,&isfloat); + } + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + | retcdata check_struct + | mov DATA ,r0 + | mvn r1, #2 // -3 + | lcall extern lua_settop + #if ARM_HF + |.if ARM_HF + if(hfasize>0){ + switch(hfasize){ + case 8: + | vldmia DATA, {d0-d3} + break; + case 6: + | vldmia DATA, {d0-d2} + break; + case 4: + | vldmia DATA, {d0-d1} + break; + case 3: + | vldmia DATA, {s0-s3} + break; + case 2: + | vldr d0, [DATA] + break; + case 1: + | vldr s0, [DATA] + break; + } + }else + |.endif + #endif + if(!mt->is_empty){ + if(mt->base_size<=4){ + | ldr r0, [DATA] + }else{ + | ldr r0, [sp,#st.extra+0x40*ARM_HF] + | mov r1, DATA + | load32 r2, mt->base_size + | load32 r12, memcpy + | blx r12 + } + } + break; + } case ENUM_TYPE: lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* usr value */ lua_rawseti(L, -2, ++num_upvals); /* mt */ - | mov r2, #num_upvals-1 // usr value - | mvn r1, #1 // -2 stack is (upval table, ret val) - | lcall extern lua_rawgeti - | load32 r3, mt - | mvn r2, #0 // -1 - ct_usr - | mvn r1, #1 // -2 - val - | lcall extern to_enum - | mov DATA, r0 - | mvn r1, #3 // -4 - remove 3 (upval table, ret val, usr value) - | lcall extern lua_settop - | mov r0, DATA - break; + | retcdata check_enum + + goto single_no_pop; case VOID_TYPE: - | mvn r1, #1 // -2 + | mvn r1, #1 // -2 | lcall extern lua_settop lua_pop(L, 1); break; case BOOL_TYPE: - case INT8_TYPE: - case INT16_TYPE: + case INT8_TYPE:// narrow it + case INT16_TYPE:// narrow it case INT32_TYPE: - | mvn r1, #0 // -1 + | mvn r1, #0 // -1 if (mt->is_unsigned) { | lcall extern check_uint32 } else { | lcall extern check_int32 } + switch(mt->type){ + case BOOL_TYPE: + | cmp r0, #0 + | movne r0,#1 + break; + case INT8_TYPE: + if (mt->is_unsigned) { + | uxtb r0, r0 + } else { + | sxtb r0 ,r0 + } + break; + case INT16_TYPE: + if (mt->is_unsigned) { + | uxth r0, r0 + } else { + | sxth r0 ,r0 + } + break; + } goto single; case INT64_TYPE: @@ -271,44 +877,107 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp case INTPTR_TYPE: | mvn r1, #0 // -1 - | lcall extern check_intptr + | lcall extern check_uintptr goto single; case FLOAT_TYPE: | mvn r1, #0 // -1 | lcall extern check_float + #if ARM_HF + |.if ARM_HF + | vmov DATA, s0 + | mvn r1, #2 // -3 + | lcall extern lua_settop + | vmov s0, DATA + |.endif + lua_pop(L, 1); + #else goto single; - + #endif + break; case DOUBLE_TYPE: | mvn r1, #0 // -1 | lcall extern check_double - goto dual; - + #if ARM_HF + |.if ARM_HF + | mov r0, L_ARG + | vmov L_ARG, DATA, d0 + | mvn r1, #2 // -3 + | bl extern lua_settop + | vmov d0, L_ARG, DATA + |.endif + lua_pop(L, 1); + #else + goto dual; + #endif + break; + case COMPLEX_DOUBLE_TYPE: + lua_pop(L, 1); + |.if ARM_HF + | mvn r1, #0 // -1 + | lcall extern check_complex_double + | vpush {d0-d1} + | mvn r1, #2 // -3 + | lcall extern lua_settop + | vpop {d0-d1} + |.else + | mvn r2, #0 // -1 + | mov r1,L_ARG + | ldr r0,[sp, #st.extra]//saved r0,the return address + | bl extern check_complex_double + | mvn r1, #2 // -3 + | lcall extern lua_settop + |.endif + break; + case COMPLEX_FLOAT_TYPE: + lua_pop(L, 1); + |.if ARM_HF + | mvn r1, #0 // -1 + | lcall extern check_complex_float + | vpush {s0-s1} + | mvn r1, #2 // -3 + | lcall extern lua_settop + | vpop {s0-s1} + |.else + | mvn r2, #0 // -1 + | mov r1,L_ARG + | ldr r0,[sp, #st.extra]//saved r0,the return address + | bl extern check_complex_float + | mvn r1, #2 // -3 + | lcall extern lua_settop + |.endif + break; + single: + lua_pop(L, 1); + single_no_pop: | mov DATA, r0 | mvn r1, #2 // -3 | lcall extern lua_settop | mov r0, DATA - lua_pop(L, 1); + break; - - dual: - | mov DATA, r0 - | mov DATA2, r1 + dual: + | mov DATA,r0 + | mov r0, L_ARG + | mov L_ARG,r1 | mvn r1, #2 // -3 - | lcall extern lua_settop + | bl extern lua_settop | mov r0, DATA - | mov r1, DATA2 + | mov r1, L_ARG + lua_pop(L, 1); - break; + break; + + default: luaL_error(L, "NYI: callback return type"); } } - - | ldmia sp, {TOP, L_ARG, DATA, DATA2, sp, pc} - + + | ldmia sp, {pc, sp, DATA, L_ARG } + lua_pop(L, 1); /* upval table - already in registry */ assert(lua_gettop(L) == top); @@ -330,12 +999,209 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp } } +static ALWAYS_INLINE void save_int64_stack_align(struct jit* Dst,reg_info* regs,int align){ + if(align&&!ALIGNED(regs->exs,2)){ + regs->exs++; + | add DATA, DATA, #4 + } + | stmia DATA!, {r0,r1} + regs->exs+=2; +} + +static ALWAYS_INLINE void save_int64_align(struct jit* Dst,reg_info* regs,int align){ + if((align&&!ALIGNED(regs->ints,2))||(regs->ints==MAX_REGS-1&®s->exs/*to ensure consective memory*/)){ + regs->ints++; + } + if(regs->intsints<<2)+0x40*ARM_HF) + | stmia r12, {r0,r1} + regs->ints+=2; + }else{ + save_int64_stack_align(Dst,regs,align); + } + +} + +static ALWAYS_INLINE void save_int64(struct jit* Dst,reg_info* regs){ + save_int64_align(Dst,regs,1); +} + +static ALWAYS_INLINE void save_int_stack_align(struct jit* Dst,reg_info* regs){ + | str, r0,[DATA], #4 + regs->exs++; +} + +static ALWAYS_INLINE void save_int(struct jit* Dst,reg_info* regs){ + if(regs->intsints++<<2)+0x40*ARM_HF)] + }else{ + save_int_stack_align(Dst,regs); + } +} + +static void save_float(struct jit* Dst,reg_info* regs,int size,int isfloat){ +#if ARM_HF +|.if ARM_HF + if(!regs->float_sealed){ + int reg=add_float_reg(regs,size,isfloat); + if(reg<0) goto SAVE_STACK; + switch(size){ + case 8: + | vstr d3,[sp,#(reg<<2)+24] + case 6: + | vstr d2,[sp,#(reg<<2)+16] + case 4: + | vstr d1,[sp,#(reg<<2)+8] + goto sf_2; + case 3: + | vstr s3,[sp,#(reg<<2)+8] + case 2: + sf_2: + | vstr d0,[sp,#(reg<<2)] + break; + case 1: + | vstr s0,[sp,#(reg<<2)] + break; + } + return; + } +|.endif + SAVE_STACK: + + if(!isfloat&&!ALIGNED(regs->exs,2)){ + regs->exs++; + | add DATA, DATA, #4 + } + switch(size){ + case 1: + | vstmia DATA!, {s0-s0} + break; + case 2: + | vstmia DATA!, {d0-d0} + break; + case 3: + | vstmia DATA!, {s0-s3} + break; + case 4: + | vstmia DATA!, {d0-d1} + break; + case 6: + | vstmia DATA!, {d0-d2} + break; + case 8: + | vstmia DATA!, {d0-d3} + break; + + } + regs->exs+=size; + +#else + if(size==1){ + save_int(Dst,regs); + }else if(size==2){ + save_int64_align(Dst,regs,!isfloat); + } +#endif +} + +static int calculate_stack(lua_State* L,int ct_usr,int nargs){ + const struct ctype* mt; + reg_info regs;int i,stack=0; + memset(®s,0,sizeof(reg_info)); + for (i = 1; i <= nargs;++i){ + lua_rawgeti(L, ct_usr, i); + mt = (const struct ctype*) lua_touserdata(L, -1); + if (mt->pointers || mt->is_reference) { + stack+=add_int_reg(®s); + }else{ + switch(mt->type){ + case COMPLEX_DOUBLE_TYPE: + #if ARM_HF + stack+=add_float_reg(®s,4,0)<0?4:0; + #else + stack+=add_int64_reg(®s); + stack+=add_int64_reg(®s); + #endif + FIX_ALIGN(stack,2); + break; + case DOUBLE_TYPE: + #if ARM_HF + stack+=add_float_reg(®s,2,0)<0?2:0; + #else + stack+=add_int64_reg(®s); + #endif + FIX_ALIGN(stack,2); + break; + case COMPLEX_FLOAT_TYPE:// Though complex alignment is 4, but vfp requires a sequence of regsiters + #if ARM_HF + stack+=add_float_reg(®s,2,1)<0?2:0; + #else + stack+=add_int_reg(®s); + stack+=add_int_reg(®s); + #endif + break; + case FLOAT_TYPE: + #if ARM_HF + stack+=add_float_reg(®s,1,1)<0?1:0; + #else + stack+=add_int_reg(®s); + #endif + break; + case INT64_TYPE: + stack+=add_int64_reg(®s); + FIX_ALIGN(stack,2); + break; + case STRUCT_TYPE:{ + #if ARM_HF + int isfloat; + int hfasize=hfa_size(L,-1,mt,&isfloat); + if(hfasize>0){ + stack+=add_float_reg(®s,2,0)<0?hfasize:0; + if(!isfloat){ + FIX_ALIGN(stack,2); + } + break; + } + #endif + } + case UNION_TYPE:{ + int intsize=(mt->base_size+3)>>2; + if(mt->align_mask>4){//8-byte max alignment + if(regs.intshas_var_arg) { - | bge >1 - | load32 r1, "too few arguments" - | lcall extern luaL_error - |1: - } else { - | beq >1 - | load32 r1, "incorrect number of arguments" - | lcall extern luaL_error - |1: - } - - /* reserve enough stack space for all of the arguments (8 bytes per - * argument for double and maintains alignment). Add an extra 16 bytes so - * that the pop {r0, r1, r2, r3} doesn't clean out our stack frame */ - | sub sp, sp, TOP, lsl #3 - | sub sp, sp, #16 - | mov DATA, sp - + + /* Reserve enough stack space for all of the arguments. For hard floating point, + * leave extra 64 bytes + */ + stack_size=calculate_stack(L,ct_usr,nargs); + lua_rawgeti(L, ct_usr, 0); + mt = (const struct ctype*) lua_touserdata(L, -1); + + // Complex types in softfp and structs/unions larger than 4-bytes are return in the address stored in r0 + ret_by_addr=!mt->pointers && !mt->is_reference &&(mt->type==STRUCT_TYPE || mt->type==UNION_TYPE|| + (!ARM_HF&&(mt->type==COMPLEX_DOUBLE_TYPE||mt->type==COMPLEX_FLOAT_TYPE)))&&mt->base_size>4&&!(ARM_HF&&hfa_size(L,-1,mt,NULL)); + lua_pop(L,1); + if(ret_by_addr){ + if(stack_size==0) + stack_size=0x40*ARM_HF+0x10; + stack_size+=8; + } + if(stack_size>0){ + if(stack_size>=1<<12){ + | load32 r12, stack_size + | sub sp, sp, r12 + }else{ + | sub sp, sp,#stack_size + } + if (ct->has_var_arg){ + | bl extern lua_gettop + | cmp r0,#nargs + | bge >1 + | load32 r1, "too few arguments" + | lcall extern luaL_error + |1: + | mov TOP, r0 + | sub sp, sp, TOP, lsl #3 + } + | add DATA, sp, #0x40*ARM_HF+0x10 + } + + memset(®s,0,sizeof(reg_info)); + + if (ret_by_addr) { + regs.ints++; + | load32 r2, mt + | mov r1, #0 + | lcall extern push_cdata + | str r0,[sp,#0x40*ARM_HF] // address for large data return + } + + for (i = 1; i <= nargs; i++) { lua_rawgeti(L, ct_usr, i); mt = (const struct ctype*) lua_touserdata(L, -1); - - if (mt->pointers || mt->is_reference || mt->type == FUNCTION_PTR_TYPE || mt->type == ENUM_TYPE) { + + if (mt->pointers || mt->is_reference || mt->type == FUNCTION_PTR_TYPE || mt->type == ENUM_TYPE|| mt->type==STRUCT_TYPE || mt->type==UNION_TYPE) { lua_getuservalue(L, -1); num_upvals += 2; - | ldr r3, [pc, #4] - | ldr r2, [pc, #4] - | b >1 - |.long mt, lua_upvalueindex(num_upvals) - |1: + | load32 r3, mt + | load32 r2, lua_upvalueindex(num_upvals) | mov r1, #i - | mov r0, L_ARG - + if (mt->pointers || mt->is_reference) { - | bl extern to_typed_pointer + | lcall extern check_typed_pointer } else if (mt->type == FUNCTION_PTR_TYPE) { - | bl extern to_typed_function + | lcall extern check_typed_cfunction } else if (mt->type == ENUM_TYPE) { - | bl extern to_enum - } - - | str r0, [DATA], #4 - + | lcall extern check_enum + }else if(mt->type==STRUCT_TYPE || mt->type==UNION_TYPE){ + if(mt->is_empty) continue; + | lcall extern check_struct + #if ARM_HF + |.if ARM_HF + { + int hfasize,isfloat; + hfasize=hfa_size(L,-2,mt,&isfloat); + if(hfasize){ + switch(hfasize){ + case 8: + | vldmia r0, {d0-d4} + break; + case 6: + | vldmia r0, {d0-d4} + break; + case 4: + | vldmia r0, {d0-d2} + break; + case 3: + | vldmia r0, {s0-s3} + break; + case 2: + | vldr d0, [r0] + break; + case 1: + | vldr s0, [r0] + break; + + } + save_float(Dst,®s,hfasize,isfloat); + continue; + } + } + |.endif + #endif + + if(mt->align_mask>4){//8 byte max alignment + if(regs.ints<4){ + FIX_ALIGN(regs.ints,2) + }else if(!ALIGNED(regs.exs,2)){ + int diff=regs.exs; + regs.exs+=4; + | add DATA, DATA,#4 + } + } + int size=ROUND_UP(mt->base_size,4)>>2; + | mov r1, r0 + | load32 r2, mt->base_size + | load32, r12, memcpy + if(regs.intstype) { + case BOOL_TYPE: + | lcall extern check_int32 + | cmp r0, #0 + | movne r0,#1 + save_int(Dst,®s); + break; case INT8_TYPE: | lcall extern check_int32 if (mt->is_unsigned) { - | and r0, r0, #0xFF + | uxtb r0,r0 } else { - | mov r0, r0, lsl #24 - | mov r0, r0, asr #24 + | sxtb r0,r0 } - | str r0, [DATA], #4 + save_int(Dst,®s); break; case INT16_TYPE: | lcall extern check_int32 if (mt->is_unsigned) { - | mov r0, r0, lsl #16 - | mov r0, r0, lsr #16 + | uxth r0,r0 } else { - | mov r0, r0, lsl #16 - | mov r0, r0, asr #16 + | sxth r0,r0 } - | str r0, [DATA], #4 + save_int(Dst,®s); break; case INT32_TYPE: @@ -436,8 +1396,12 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty } else { | lcall extern check_int32 } - | str r0, [DATA], #4 + save_int(Dst,®s); break; + case INTPTR_TYPE: + | lcall extern check_uintptr + save_int(Dst,®s); + break; case INT64_TYPE: if (mt->is_unsigned) { @@ -445,26 +1409,71 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty } else { | lcall extern check_int64 } - | str r0, [DATA], #4 - | str r1, [DATA], #4 + save_int64(Dst,®s); break; case DOUBLE_TYPE: - | lcall extern check_double - | str r0, [DATA], #4 - | str r1, [DATA], #4 - break; - - case INTPTR_TYPE: - | lcall extern check_intptr - | str r0, [DATA], #4 + | lcall extern check_double + save_float(Dst,®s,2,0); break; case FLOAT_TYPE: - | lcall extern check_float - | str r0, [DATA], #4 + | lcall extern check_float + save_float(Dst,®s,1,1); + break; + + case COMPLEX_DOUBLE_TYPE: + |.if ARM_HF + #if ARM_HF + | lcall extern check_complex_double + save_float(Dst,®s,4,0); + #else + |.else + FIX_ALIGN(regs.ints,2); + | mov r2,r1 + | mov r1,L_ARG + if(regs.intsMAX_REGS){ + | add DATA, DATA,#(regs.ints-4)<<2 + regs.exs+=regs.ints-MAX_REGS; + regs.ints=MAX_REGS; + } + |.endif + #endif break; - default: luaL_error(L, "NYI: call arg type"); } @@ -472,139 +1481,309 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty } if (ct->has_var_arg) { - | mov r3, DATA + int offset=nargs+1; + | mov r1, #offset + #if ARM_HF + |.if ARM_HF + if(regs.ints==4||regs.float_sealed){ + if(regs.ints<4&®s.float_sealed){//some arg must be loaded to core registers. + | add r2, sp,#((regs.ints<<2)+0x40) + | add r3, sp,#(0x10+0x40) + | lcall extern unpack_varargs_bound + | add r1, r0, #offset + } + | mov r3, DATA + } + #else + |.else + if(regs.ints==4){ + | mov r3, DATA + } + |.endif + #endif + else{//no hard floating point in variadic procedure + | add r3, sp,#((regs.ints<<2)+ARM_HF*0x40) + } + | mov r2, TOP - | mov r1, #nargs+1 | lcall extern unpack_varargs_stack - } - - | load32 r0, &Dst->last_errno - | ldr r0, [r0] - | bl extern SetLastError - - | pop {r0, r1, r2, r3} // this pop is balanced with the sub sp, #16 - | bl extern FUNCTION - - |.macro get_errno - | bl extern GetLastError - | load32 r1, &Dst->last_errno - | str r0, [r1] - |.endmacro - - |.macro return - | ldmdb r11, {TOP, L_ARG, DATA, r11, sp, pc} - |.endmacro + regs.ints=4; + } + + |.if ARM_HF + #if ARM_HF + switch(ROUND_UP(regs.highest_bit,4)>>1){ + case 8 : + | vldmia sp, {d0-d7} + break; + case 7 : + | vldmia sp, {d0-d6} + break; + case 6 : + | vldmia sp, {d0-d5} + break; + case 5: + | vldmia sp, {d0-d4} + break; + case 4 : + | vldmia sp, {d0-d3} + break; + case 3 : + | vldmia sp, {d0-d2} + break; + case 2 : + | vldmia sp, {d0-d1} + break; + case 1 : + | vldr d0, [sp] + break; + } + if(stack_size>0){ + | add sp,sp,#0x40 + } + #endif + |.endif + + //pop registers from stack,align 8 for some compiler + assert(regs.ints<=4); + switch(regs.ints){ + case 4: + case 3: + | pop {r0,r1,r2,r3} + break; + case 2: + case 1: + | pop {r0,r1} + #if ARM_HF + if(regs.float_sealed){ + |.if ARM_HF + | add sp, sp, #0x8 + |.endif + } + #endif + break; + default: + #if ARM_HF + if(regs.float_sealed){ + |.if ARM_HF + | add sp, sp, #0x10 + |.endif + } + #endif + break; + } + + | load32 r12,func + | blx r12 lua_rawgeti(L, ct_usr, 0); mt = (const struct ctype*) lua_touserdata(L, -1); - if (mt->pointers || mt->is_reference) { + if (mt->pointers || mt->is_reference || mt->type==FUNCTION_PTR_TYPE) { lua_getuservalue(L, -1); num_upvals += 2; | mov DATA, r0 - | get_errno - | ldr r2, [pc, #4] - | ldr r1, [pc, #4] - | b >1 - |.long mt, lua_upvalueindex(num_upvals) - |1: + | load32 r2, mt + | load32 r1, lua_upvalueindex(num_upvals) | lcall extern push_cdata | str DATA, [r0] | mov r0, #1 - | return } else { switch (mt->type) { case INT64_TYPE: - num_upvals++; + #if LUA_VERSION_NUM>=503 + lua_pop(L, 1); + #if CK_ALGIN + | mov r3, r1 + | mov r2, r0 + #else + | mov r2, r1 + | mov r1, r0 + #endif + | lcall extern lua_pushinteger + | mov r0, #1 + break; + #else + num_upvals++; | mov DATA, r0 - | mov DATA2, r1 - | get_errno - | lcall extern lua_pushnil + | mov INFO, r1 | load32 r2, mt - | mvn r1, #0 // -1 + | mov r1, #0 | lcall extern push_cdata | str DATA, [r0] - | str DATA2, [r0, #4] + | str INFO, [r0,#0x4] | mov r0, #1 - | return break; - + #endif + case INTPTR_TYPE: num_upvals++; | mov DATA, r0 - | get_errno - | lcall extern lua_pushnil | load32 r2, mt - | mvn r1, #0 // -1 + | mov r1, #0 | lcall extern push_cdata | str DATA, [r0] | mov r0, #1 - | return break; case VOID_TYPE: lua_pop(L, 1); - | get_errno | mov r0, #0 - | return break; case BOOL_TYPE: lua_pop(L, 1); - | mov DATA, r0 - | get_errno - | mov r1, DATA + | mov r1, r0 | lcall extern lua_pushboolean | mov r0, #1 - | return break; case INT8_TYPE: case INT16_TYPE: case INT32_TYPE: - case ENUM_TYPE: + case ENUM_TYPE:// value must be narrowed before callee return lua_pop(L, 1); - | mov DATA, r0 - | get_errno - | mov r1, DATA + + | mov r1, r0 if (mt->is_unsigned) { | lcall extern push_uint } else { | lcall extern push_int } + | mov r0, #1 - | return break; case FLOAT_TYPE: lua_pop(L, 1); - | mov DATA, r0 - | get_errno - | mov r1, DATA + |.if not ARM_HF + | mov r1, r0 + |.endif | lcall extern push_float | mov r0, #1 - | return break; case DOUBLE_TYPE: lua_pop(L, 1); - | mov DATA, r0 - | mov DATA2, r1 - | get_errno - | mov r2, DATA2 - | mov r1, DATA + #if CK_ALGIN + |.if not ARM_HF + | mov r3, r1 + | mov r2, r0 + #else + | mov r2, r1 + | mov r1, r0 + |.endif + #endif | lcall extern lua_pushnumber | mov r0, #1 - | return break; - + case COMPLEX_DOUBLE_TYPE: + case COMPLEX_FLOAT_TYPE: + case STRUCT_TYPE: + case UNION_TYPE:{ + lua_getuservalue(L,-1); + num_upvals += 2; + #if ARM_HF + |.if ARM_HF + { + int isfloat,hfasize=hfa_size(L,-2,mt,&isfloat); + if(hfasize>0){ + switch(hfasize){ + case 8: + | vpush {d0-d3} + break; + case 6: + | vpush {d0-d2} + break; + case 4: + case 3: + | vpush {d0-d1} + break; + case 2: + case 1: + | vpush {d0-d0} + break; + + } + | mov DATA, r0 + | load32 r2, mt + | load32 r1,lua_upvalueindex(num_upvals) + | lcall extern push_cdata + switch(hfasize){ + case 8: + | vpop {d0-d3} + | vstmia r0, {d0-d3} + break; + case 6: + | vpop {d0-d2} + | vstmia r0, {d0-d2} + break; + case 4: + | vpop {d0-d1} + | vstmia r0, {d0-d1} + break; + case 3: + | vpop {d0-d1} + | vstmia r0, {s0-s3} + break; + case 2: + | vpop {d0-d0} + | vstr d0,[r0] + break; + case 1: + | vpop {d0-d0} + | vstr s0,[r0] + break; + + } + | mov r0, #1 + break; + } + } + + |.endif + #endif + if(mt->base_size>4){ + // value are stored in return storage in r0 for softfp, set usr value here + if(!lua_isnil(L,-1)){ + | load32 r1, lua_upvalueindex(num_upvals) + | lcall extern lua_pushvalue // lua_pushvalue(L,lua_upvalueindex(num_upvals)) + | mvn r1, #1 //-2 + | lcall extern lua_setuservalue // lua_setuservalue(L,-2) + } + }else if(mt->is_empty){ + | mov r0, #0 + break; + }else{ + | mov DATA, r0 + | load32 r2, mt + | load32 r1,lua_upvalueindex(num_upvals) + | lcall extern push_cdata + | str DATA, [r0] + } + | mov r0, #1 + break; + } default: luaL_error(L, "NYI: call return type"); } } +#ifdef __thumb__ + | sub sp, r7, #12 + | pop {L_ARG, TOP, DATA, r7, pc} +#else + | sub sp, r11, #12 + | pop {L_ARG, TOP, DATA, r11, pc} +#endif assert(lua_gettop(L) == top + num_upvals); - lua_pushcclosure(L, (lua_CFunction) compile(Dst, L, func, LUA_NOREF), num_upvals); + { + cfunction f = compile(Dst, L, NULL, LUA_NOREF); + /* add a callback as an upval so that the jitted code gets cleaned up when + * the function gets gc'd */ + push_callback(L, f, func); + lua_pushcclosure(L, (lua_CFunction) f, num_upvals+1); + } } diff --git a/texk/web2c/luatexdir/luaffi/call_arm.h b/texk/web2c/luatexdir/luaffi/call_arm.h index efe7f9567e..3d1ce33e62 100644 --- a/texk/web2c/luatexdir/luaffi/call_arm.h +++ b/texk/web2c/luatexdir/luaffi/call_arm.h @@ -1,14 +1,10 @@ /* ** This file has been pre-processed with DynASM. ** http://luajit.org/dynasm.html -** DynASM version 1.3.0, DynASM arm version 1.3.0 +** DynASM version 1.4.0, DynASM arm version 1.4.0 ** DO NOT EDIT! The original file is in "call_arm.dasc". */ -#if DASM_VERSION != 10300 -#error "Version mismatch between DynASM and included encoding engine" -#endif - /* vim: ts=4 sw=4 sts=4 et tw=78 * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved. * Portions copyright (c) 2011 James R. McKaskill. @@ -17,28 +13,62 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ -static const unsigned int build_actionlist[546] = { + +//The generate code is for arm not for thumb +#if DASM_VERSION != 10400 +#error "Version mismatch between DynASM and included encoding engine" +#endif + +static const unsigned int build_actionlist[743] = { +0xe28dc000, +0x000b0000, +0xe89c100e, +0x00000000, +0xe28dc000, +0x000b0000, +0xe89c100e, +0x00000000, +0xe28dc000, +0x000b0000, +0xe89c0006, +0x00000000, +0xe51d1000, +0x000e8180, +0x00000000, +0xe2866000, +0x000b0000, +0x00000000, +0xe8b6100e, +0x00000000, +0xe8b60006, +0x00000000, +0xe4961004, +0x00000000, 0xe1a0c00d, 0xe92d000f, -0xe92d50f0, -0xe24c6010, -0xe59f5008, -0xe59f2008, -0xe59f1008, -0xea000000, -0x00050001, -0x00090000, -0x00090000, -0x00090000, -0x0006000b, -0xe1a00005, +0x00000000, +0xe92d5050, +0xe1a0600c, +0xe3004000, +0x000c0200, +0xe3404000, +0x000c0200, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3001000, +0x000c0200, +0xe3401000, +0x000c0200, +0xe1a00004, 0xeb000000, 0x00030000, 0x00000000, 0xe3a02000, 0x000b0000, 0xe3e01000, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030000, 0x00000000, @@ -46,523 +76,692 @@ static const unsigned int build_actionlist[546] = { 0x000b0000, 0xe3e01000, 0x000b0000, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030000, -0xe59f2000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, 0xe3e01000, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030001, -0xe4962004, -0xe5802000, +0x00000000, +0xe5801000, 0xe3e01001, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030002, 0x00000000, -0xe1a00005, +0xe3a02000, +0x000b0000, +0xe3e01000, +0x000b0000, +0xe1a00004, 0xeb000000, -0x00030003, -0xe59f2000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, +0x00030000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, 0xe3e01000, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030001, -0xe4962004, -0xe4963004, -0xe5802000, -0xe5803004, +0x00000000, +0xe5801000, +0x00000000, +0xe28d1000, +0x000b0000, +0x00000000, +0xe1a01006, +0x00000000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe300c000, +0x000c0200, +0xe340c000, +0x000c0200, +0xe12fff3c, +0x00000000, 0xe3e01001, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030002, 0x00000000, -0xe1a00005, +0xe3a02000, +0x000b0000, +0xe3e01000, +0x000b0000, +0xe1a00004, 0xeb000000, -0x00030003, -0xe59f2000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, +0x00030000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, 0xe3e01000, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030001, -0xe4962004, -0xe5802000, +0x00000000, +0xe880100e, 0xe3e01001, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030002, 0x00000000, -0xe4961004, -0xe1a00005, +0xe3a02000, +0x000b0000, +0xe3e01000, +0x000b0000, +0xe1a00004, 0xeb000000, -0x00030004, +0x00030000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3e01000, +0xe1a00004, +0xeb000000, +0x00030001, 0x00000000, -0xe4961004, -0xe1a01c01, +0xe8800006, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x00030002, 0x00000000, -0xe1a01c21, +0xe28dc000, +0x000b0000, +0xe89c000c, +0x00000000, +0xe2866004, 0x00000000, -0xe1a01c41, +0xe8b6000c, 0x00000000, -0xe1a00005, +0xe1a00004, 0xeb000000, -0x00030005, +0x00030003, 0x00000000, -0xe4961004, -0xe1a01801, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3a01000, +0xe1a00004, +0xeb000000, +0x00030001, 0x00000000, -0xe1a01821, +0xe8800006, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x00030002, 0x00000000, -0xe1a01841, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3a01000, +0xe1a00004, +0xeb000000, +0x00030001, 0x00000000, -0xe1a00005, +0xe5801000, +0xe3e01001, +0xe1a00004, 0xeb000000, -0x00030005, +0x00030002, 0x00000000, -0xe4961004, -0xe1a00005, +0xe1a00004, +0xeb000000, +0x00030004, +0x00000000, +0xe1a00004, 0xeb000000, 0x00030005, 0x00000000, -0xe4961004, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030006, 0x00000000, -0xe8b60006, -0xe1a00005, +0xe28dc000, +0x000b0000, +0xe89c000c, +0x00000000, +0xe2866004, +0x00000000, +0xe8b6000c, +0x00000000, +0xe1a00004, 0xeb000000, 0x00030007, 0x00000000, -0xe3a03000, 0xe3a02000, 0x000b0000, 0xe3a01000, 0x000b0000, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030008, 0x00000000, 0xe3a02000, 0x000b0000, 0xe3e01001, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030000, -0xe59f3000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, -0xe3a02000, +0xe3003000, +0x000c0200, +0xe3403000, +0x000c0200, +0xe3e02000, 0xe3e01001, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030009, -0xe1a06000, -0xe3e01003, -0xe1a00005, -0xeb000000, -0x0003000a, -0xe1a00006, 0x00000000, 0xe3a02000, 0x000b0000, 0xe3e01001, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030000, -0xe59f3000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, +0xe3003000, +0x000c0200, +0xe3403000, +0x000c0200, 0xe3e02000, 0xe3e01001, -0xe1a00005, +0xe1a00004, 0xeb000000, -0x0003000b, +0x0003000a, 0xe1a06000, -0xe3e01003, -0xe1a00005, +0xe3e01002, +0xe1a00004, 0xeb000000, -0x0003000a, -0xe1a00006, +0x0003000b, 0x00000000, -0xe3e01001, -0xe1a00005, -0xeb000000, -0x0003000a, +0xe5960000, 0x00000000, -0xe3e01000, +0xe51d0000, +0x000e8180, +0xe1a01006, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe300c000, +0x000c0200, +0xe340c000, +0x000c0200, +0xe12fff3c, 0x00000000, -0xe1a00005, +0xe3a02000, +0x000b0000, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x00030000, +0xe3003000, +0x000c0200, +0xe3403000, +0x000c0200, +0xe3e02000, +0xe3e01001, +0xe1a00004, 0xeb000000, 0x0003000c, 0x00000000, -0xe1a00005, +0xe3e01001, +0xe1a00004, 0xeb000000, -0x0003000d, +0x0003000b, 0x00000000, 0xe3e01000, 0x00000000, -0xe1a00005, +0xe1a00004, +0xeb000000, +0x0003000d, +0x00000000, +0xe1a00004, 0xeb000000, 0x0003000e, 0x00000000, -0xe1a00005, +0xe3500000, +0x13a00001, +0x00000000, +0xe6ef0070, +0x00000000, +0xe6af0070, +0x00000000, +0xe6ff0070, +0x00000000, +0xe6bf0070, +0x00000000, +0xe3e01000, +0x00000000, +0xe1a00004, 0xeb000000, 0x0003000f, 0x00000000, -0xe3e01000, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030010, 0x00000000, 0xe3e01000, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030011, 0x00000000, 0xe3e01000, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030012, 0x00000000, +0xe3e01000, +0xe1a00004, +0xeb000000, +0x00030013, +0x00000000, +0xe3e02000, +0xe1a01004, +0xe51d0000, +0x000e8180, +0xeb000000, +0x00030014, +0xe3e01002, +0xe1a00004, +0xeb000000, +0x0003000b, +0x00000000, +0xe3e02000, +0xe1a01004, +0xe51d0000, +0x000e8180, +0xeb000000, +0x00030015, +0xe3e01002, +0xe1a00004, +0xeb000000, +0x0003000b, +0x00000000, 0xe1a06000, 0xe3e01002, -0xe1a00005, +0xe1a00004, 0xeb000000, -0x0003000a, +0x0003000b, 0xe1a00006, 0x00000000, 0xe1a06000, -0xe1a07001, +0xe1a00004, +0xe1a04001, 0xe3e01002, -0xe1a00005, 0xeb000000, -0x0003000a, +0x0003000b, 0xe1a00006, -0xe1a01007, +0xe1a01004, 0x00000000, -0xe89da0f0, +0xe89da050, +0x00000000, +0xe2866004, +0x00000000, +0xe8a60003, +0x00000000, +0xe28dc000, +0x000b0000, +0xe88c0003, +0x00000000, +0xe4860004, +0x00000000, +0xe50d0000, +0x000e8180, +0x00000000, +0xe2866004, +0x00000000, +0xeca60a01, +0x00000000, +0xeca60b02, +0x00000000, +0xeca60a04, +0x00000000, +0xeca60b04, +0x00000000, +0xeca60b06, +0x00000000, +0xeca60b08, +0x00000000, +0xe92d40f0, +0xe28d700c, +0x00000000, +0xe92d4870, +0xe28db00c, +0x00000000, +0xe24dd004, 0x00000000, -0xe1a0c00d, -0xe92d0001, -0xe92d58f0, -0xe24cb004, -0xe1a05000, -0xe1a00005, -0xeb000000, -0x00030013, 0xe1a04000, -0xe3540000, +0x00000000, +0xe300c000, +0x000c0200, +0xe340c000, +0x000c0200, +0xe04dd00c, +0x00000000, +0xe24dd000, 0x000b0000, 0x00000000, -0xaa000000, -0x00050001, -0xe59f1000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, -0xe1a00005, 0xeb000000, -0x00030014, -0x0006000b, -0x00000000, -0x0a000000, +0x00030016, +0xe3500000, +0x000b0000, +0xaa000000, 0x00050001, -0xe59f1000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, -0xe1a00005, +0xe3001000, +0x000c0200, +0xe3401000, +0x000c0200, +0xe1a00004, 0xeb000000, -0x00030014, +0x00030017, 0x0006000b, +0xe1a05000, +0xe04dd185, 0x00000000, -0xe04dd184, -0xe24dd010, -0xe1a0600d, +0xe28d6000, +0x000b0000, 0x00000000, -0xe59f3004, -0xe59f2004, -0xea000000, -0x00050001, -0x00090000, -0x00090000, -0x0006000b, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3a01000, +0xe1a00004, +0xeb000000, +0x00030001, +0xe50d0000, +0x000e8180, +0x00000000, +0xe3003000, +0x000c0200, +0xe3403000, +0x000c0200, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, 0xe3a01000, 0x000b0000, -0xe1a00005, 0x00000000, +0xe1a00004, 0xeb000000, 0x00030009, 0x00000000, +0xe1a00004, 0xeb000000, -0x00030015, +0x00030018, 0x00000000, +0xe1a00004, 0xeb000000, -0x0003000b, +0x0003000c, 0x00000000, -0xe4860004, +0xe1a00004, +0xeb000000, +0x0003000a, 0x00000000, -0xe3a01000, +0xe2866004, +0x00000000, +0xe1a01000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe300c000, +0x000c0200, +0xe340c000, +0x000c0200, +0x00000000, +0xe28d0000, 0x000b0000, 0x00000000, -0xe1a00005, -0xeb000000, -0x0003000d, +0xe1a00006, 0x00000000, -0xe20000ff, +0xe12fff3c, 0x00000000, -0xe1a00c00, -0xe1a00c40, +0xe2866000, +0x000b0000, 0x00000000, -0xe4860004, +0xe3a01000, +0x000b0000, 0x00000000, -0xe1a00005, +0xe1a00004, 0xeb000000, -0x0003000d, +0x0003000e, +0xe3500000, +0x13a00001, 0x00000000, -0xe1a00800, -0xe1a00820, +0xe1a00004, +0xeb000000, +0x0003000e, 0x00000000, -0xe1a00800, -0xe1a00840, +0xe6ef0070, 0x00000000, -0xe4860004, +0xe6af0070, 0x00000000, -0xe1a00005, +0xe1a00004, 0xeb000000, -0x0003000c, +0x0003000e, +0x00000000, +0xe6ff0070, 0x00000000, -0xe1a00005, +0xe6bf0070, +0x00000000, +0xe1a00004, 0xeb000000, 0x0003000d, 0x00000000, -0xe4860004, -0x00000000, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x0003000e, 0x00000000, -0xe1a00005, +0xe1a00004, +0xeb000000, +0x00030011, +0x00000000, +0xe1a00004, 0xeb000000, 0x0003000f, 0x00000000, -0xe4860004, -0xe4861004, +0xe1a00004, +0xeb000000, +0x00030010, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030013, 0x00000000, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030012, -0xe4860004, -0xe4861004, 0x00000000, -0xe1a00005, +0xe1a02001, +0xe1a01004, +0x00000000, +0xe28d0000, +0x000b0000, +0x00000000, +0xe2866004, +0x00000000, +0xe1a00006, +0x00000000, 0xeb000000, -0x00030010, -0xe4860004, +0x00030014, +0x00000000, +0xe1a02001, +0xe1a01004, +0x00000000, +0xe28d0000, +0x000b0000, +0x00000000, +0xe1a00006, 0x00000000, -0xe1a00005, 0xeb000000, -0x00030011, -0xe4860004, +0x00030015, +0x00000000, +0xe2866000, +0x000b0000, 0x00000000, -0xe1a03006, -0xe1a02004, 0xe3a01000, 0x000b0000, -0xe1a00005, -0xeb000000, -0x00030016, 0x00000000, -0xe59f0000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, -0xe5900000, +0xe1a03006, +0x00000000, +0xe28d3000, +0x000b0000, +0x00000000, +0xe1a02005, +0xe1a00004, 0xeb000000, -0x00030017, +0x00030019, 0x00000000, 0xe8bd000f, -0xeb000000, -0x00030018, +0x00000000, +0xe8bd0003, +0x00000000, +0xe300c000, +0x000c0200, +0xe340c000, +0x000c0200, +0xe12fff3c, 0x00000000, 0xe1a06000, -0xeb000000, -0x00030019, -0xe59f1000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, -0xe5810000, -0xe59f2004, -0xe59f1004, -0xea000000, -0x00050001, -0x00090000, -0x00090000, -0x0006000b, -0xe1a00005, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3001000, +0x000c0200, +0xe3401000, +0x000c0200, +0xe1a00004, 0xeb000000, 0x00030001, 0xe5806000, 0xe3a00001, -0xe91ba870, 0x00000000, -0xe1a06000, -0xe1a07001, -0xeb000000, -0x00030019, -0xe59f1000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, -0xe5810000, -0xe1a00005, +0xe1a03001, +0xe1a02000, +0x00000000, +0xe1a02001, +0xe1a01000, +0x00000000, +0xe1a00004, 0xeb000000, 0x00030003, -0xe59f2000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, -0xe3e01000, -0xe1a00005, +0xe3a00001, +0x00000000, +0xe1a06000, +0xe1a05001, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3a01000, +0xe1a00004, 0xeb000000, 0x00030001, 0xe5806000, -0xe5807004, +0xe5805004, 0xe3a00001, -0xe91ba870, 0x00000000, 0xe1a06000, -0xeb000000, -0x00030019, -0xe59f1000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, -0xe5810000, -0xe1a00005, -0xeb000000, -0x00030003, -0xe59f2000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, -0xe3e01000, -0xe1a00005, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3a01000, +0xe1a00004, 0xeb000000, 0x00030001, 0xe5806000, 0xe3a00001, -0xe91ba870, 0x00000000, -0xeb000000, -0x00030019, -0xe59f1000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, -0xe5810000, 0xe3a00000, -0xe91ba870, 0x00000000, -0xe1a06000, -0xeb000000, -0x00030019, -0xe59f1000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, -0xe5810000, -0xe1a01006, -0xe1a00005, +0xe1a01000, +0xe1a00004, 0xeb000000, 0x00030004, 0xe3a00001, -0xe91ba870, 0x00000000, -0xe1a06000, -0xeb000000, -0x00030019, -0xe59f1000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, -0xe5810000, -0xe1a01006, +0xe1a01000, 0x00000000, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x0003001a, 0x00000000, -0xe1a00005, +0xe1a00004, 0xeb000000, 0x00030005, 0x00000000, 0xe3a00001, -0xe91ba870, 0x00000000, -0xe1a06000, -0xeb000000, -0x00030019, -0xe59f1000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, -0xe5810000, -0xe1a01006, -0xe1a00005, +0xe1a01000, +0xe1a00004, 0xeb000000, 0x00030006, 0xe3a00001, -0xe91ba870, 0x00000000, -0xe1a06000, -0xe1a07001, -0xeb000000, -0x00030019, -0xe59f1000, -0xea000000, -0x00050005, -0x00090000, -0x0006000f, -0xe5810000, -0xe1a02007, -0xe1a01006, -0xe1a00005, +0xe1a03001, +0xe1a02000, +0x00000000, +0xe1a02001, +0xe1a01000, +0x00000000, +0xe1a00004, 0xeb000000, 0x00030007, 0xe3a00001, -0xe91ba870, +0x00000000, +0xe3001000, +0x000c0200, +0xe3401000, +0x000c0200, +0xe1a00004, +0xeb000000, +0x0003001b, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x0003001c, +0x00000000, +0xe3a00000, +0x00000000, +0xe1a06000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3001000, +0x000c0200, +0xe3401000, +0x000c0200, +0xe1a00004, +0xeb000000, +0x00030001, +0xe5806000, +0x00000000, +0xe3a00001, +0x00000000, +0xe247d00c, +0xe8bd80f0, +0x00000000, +0xe24bd00c, +0xe8bd8870, 0x00000000 }; @@ -570,40 +769,63 @@ static const char *const globnames[] = { (const char *)0 }; static const char *const extnames[] = { - "lua_rawgeti", + "rawgeti", "push_cdata", "lua_remove", - "lua_pushnil", + "lua_pushinteger", "lua_pushboolean", "push_int", "push_float", "lua_pushnumber", - "lua_callk", - "to_typed_pointer", + "lua_call", + "check_typed_pointer", + "check_struct", "lua_settop", - "to_enum", + "check_enum", "check_uint32", "check_int32", "check_uint64", "check_int64", - "check_intptr", + "check_uintptr", "check_float", "check_double", + "check_complex_double", + "check_complex_float", "lua_gettop", "luaL_error", - "to_typed_function", + "check_typed_cfunction", "unpack_varargs_stack", - "SetLastError", - "FUNCTION", - "GetLastError", "push_uint", + "lua_pushvalue", + "lua_setuservalue", (const char *)0 }; #define JUMP_SIZE 8 + #define MIN_BRANCH ((INT32_MIN) >> 8) #define MAX_BRANCH ((INT32_MAX) >> 8) -#define BRANCH_OFF 4 +//arm pc offset 8 so comparing with next instruction is 4, +//unlike x86 which pass in the current instruction address+1 rather than the next instruction +#define BRANCH_OFF 4 + + +#define ROUND_UP(x, align) (((int) (x) + (align - 1)) & ~(align - 1)) +#ifdef TARGET_OS_IPHONE +#define CK_ALGIN 0 +#else +#define CK_ALGIN 1 +#endif +#define ALIGNED(x, align) (!CK_ALGIN||((int)(x) & (align - 1)) == 0) +#if defined(__ARM_PCS_VFP) || (GCC_VERSION==40500||defined(__clang__))&&!defined(__ARM_PCS) && !defined(__SOFTFP__) && !defined(__SOFTFP) && \ + defined(__VFP_FP__) +#define ARM_HF 1 +#else +#define ARM_HF 0 +#endif +#if ARM_HF&&!CK_ALGIN +#error "Unsupported unaligned stack for hard floating point" +#endif static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, uint8_t* code) { @@ -614,9 +836,11 @@ static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, u * Note we have to manually set this up since there are commands buffered * in the jit state. */ + *(cfunction*) code = func; - /* ldr pc, [pc - 12] */ - *(uint32_t*) &code[4] = 0xE51FF00CU; + //ldr pc, [pc - 12] + *(uint32_t*) &code[4] = 0xE51FF00CU; + } @@ -627,11 +851,341 @@ void compile_globals(struct jit* jit, lua_State* L) (void) jit; } +typedef struct stack_info{ + int extra; + int int_off; + int stack_off; + int float_size; +#if ARM_HF + int float_off; +#endif +} stack_info; +//vfp use back-filling rule for registers until a float value on stack +typedef struct reg_info{ + uint16_t exs; + union{ + uint8_t ints; + uint8_t regs; + }; +#if ARM_HF + uint8_t float_sealed; + short floats;//each bit is a float: s0-s15 or v0-v7 or q0-q3 + uint8_t left_single; + uint8_t highest_bit; +#endif +} reg_info; + +#define MAX_REGS 4 +#define MAX_FLOAT_REGS 16 +#ifndef bool +#define bool uint8_t +#endif + +#define has_bit(x,b) (((x)&(1<<(b)))!=0) +#define set_bit(x,b) (x=((x)|(1<<(b)))) +#define FIX_ALIGN(x,al) \ + if(!ALIGNED((x),al)){\ + x=ROUND_UP(x,al);\ + } +static ALWAYS_INLINE bool is_float_sealed(reg_info* regs){ +#if ARM_HF +return regs->float_sealed; +#else +return regs->regs>=MAX_REGS; +#endif +} +//return size need to put on stack +static ALWAYS_INLINE int add_int_reg(reg_info* regs){ + if(regs->regsregs++; + return 0; + } + return 1; + +} +//return size need to put on stack +static ALWAYS_INLINE int add_int64_reg(reg_info* regs){ + if(regs->regsregs=ROUND_UP(regs->regs,2)+2; + return 0; + }else if(regs->regs==MAX_REGS-1){ + regs->regs=MAX_REGS; + } + + return 2; +} +static ALWAYS_INLINE bool is_float_type(int t){ + return t==FLOAT_TYPE||t==DOUBLE_TYPE; +} +static int hfa_size(lua_State* L,int idx, const struct ctype* ct,int* isfloat){ + struct ctype* mt; + int type,ele_count,i,ct_usr; + lua_getuservalue(L,idx); + ct_usr=lua_absindex(L,-1); + lua_rawgeti(L,ct_usr,1); + mt=(struct ctype*)lua_touserdata(L,-1); + if(mt==NULL||(mt->pointers&&!mt->is_array)||mt->is_reference||!is_float_type(mt->type)){ + lua_pop(L,2); + if(ct->type==COMPLEX_DOUBLE_TYPE){ + if(isfloat) *isfloat=0; + return 4; + }else if(ct->type==COMPLEX_FLOAT_TYPE){ + if(isfloat) *isfloat=1; + return 2; + } + return 0; + } + type=mt->type; + ele_count=(int)(ct->base_size/mt->base_size); + if(ele_count>4||ct->base_size%mt->base_size){ + lua_pop(L,2); + return 0; + } + lua_pop(L,1); + for (i = 2; i <=4 ; ++i) { + lua_rawgeti(L,ct_usr,i); + if(lua_isnil(L,-1)){//case have array member; + lua_pop(L,1); + break; + } + mt=(struct ctype*)lua_touserdata(L,-1); + if(mt->type!=type||(mt->pointers&&!mt->is_array)||mt->is_reference||!is_float_type(mt->type)){ + lua_pop(L,2); + return 0; + } + lua_pop(L,1); + } + if(isfloat){ + *isfloat=mt->type==FLOAT_TYPE; + } + lua_pop(L,1); + return ele_count*(mt->type==FLOAT_TYPE?1:2); +} +#if ARM_HF +static void save_float_reg(struct jit* Dst,int reg,int size,stack_info* st){ + int sz; + if(reg==-1) return; + for(;size>0;size-=8){ + sz=size>8?8:size; + switch(sz){ + case 4: + switch(reg){ + case 0: + break; + case 1: + break; + case 2: + break; + case 3: + break; + case 4: + break; + case 5: + break; + case 6: + break; + case 7: + break; + case 8: + break; + case 9: + break; + case 10: + break; + case 11: + break; + case 12: + break; + case 13: + break; + case 14: + break; + case 15: + break; + } + break; + case 8: + switch(reg>>1){ + case 0: + break; + case 1: + break; + case 2: + break; + case 3: + break; + case 4: + break; + case 5: + break; + case 6: + break; + case 7: + break; + } + reg+=2; + break; + } + st->float_size+=sz; + } +} + +//128 bit vector type is not supported by this +static int add_float_reg(reg_info* regs,int sz,int isfloat){ + + if(is_float_sealed(regs)) return -1; + int i,ret=-1; + if(sz==1){ + if(regs->left_single){ + int n=regs->highest_bit; + for(i=0;ifloats,i)){ + regs->left_single--; + set_bit(regs->floats,i); + ret=i; + } + } + }else{ + ret=regs->highest_bit; + set_bit(regs->floats,regs->highest_bit); + ++regs->highest_bit; + } + }else{ + if(regs->highest_bit>MAX_FLOAT_REGS-sz){ + regs->highest_bit=MAX_FLOAT_REGS; + }else{ + if(!isfloat&&!ALIGNED(regs->highest_bit, 2)){ + regs->highest_bit++; + regs->left_single++; + } + ret=regs->highest_bit; + for(i=0;ifloats,regs->highest_bit++); + } + } + } + if(regs->highest_bit==MAX_FLOAT_REGS){ + regs->float_sealed=true; + } + return ret; +} +#endif +static void load_reg(struct jit* Dst,int off,int size){ + if(size==16){ + dasm_put(Dst, 0, off); + }else if(size==12){ + dasm_put(Dst, 4, off); + }else if(size==8){ + dasm_put(Dst, 8, off); + }else{ + dasm_put(Dst, 12, off); + } +} +// arm store/load range for immediate value is only -256-255 +static void load_stack(struct jit* Dst,stack_info* st,int size,int align){ + int off=st->stack_off; + FIX_ALIGN(st->stack_off,align); + if((off=st->stack_off-off)){ + dasm_put(Dst, 15, off); + } + if(size==16){ + dasm_put(Dst, 18); + }else if(size==8){ + dasm_put(Dst, 20); + }else{ + dasm_put(Dst, 22); + } + st->stack_off+=size; +} + +static void load_int(struct jit* Dst,stack_info* st,int size,int align){ + FIX_ALIGN(st->int_off,align); + if(st->int_off<0x40*ARM_HF+MAX_REGS*4&&(!st->stack_off||MAX_REGS*4+size<=0x40*ARM_HF+MAX_REGS*4)){ + load_reg(Dst,st->int_off+st->extra,size); + st->int_off+=size; + }else{ + st->int_off=0x40*ARM_HF+MAX_REGS*4; + load_stack(Dst,st,size,align); + } + +} + +static void load_float(struct jit* Dst,stack_info* st,int size,int vfp,int align){ + #if ARM_HF + if(st->float_offfloat_size){ + if(vfp){ + if(size==4){//float + }else if(size==8){//double + } + }else load_reg(Dst,st->float_off+st->extra,size); + st->float_off+=size; + }else if(vfp){ + if(size==4){//float + }else if(size==8){//double + int off=st->stack_off; + FIX_ALIGN(st->stack_off,align); + if((off=st->stack_off-off)){ + } + } + }else{ + load_stack(Dst,st,size,align); + } + #else + load_int(Dst,st,size,align); + #endif +} +#if ARM_HF +static void push_regs(lua_State* L,struct jit* Dst,int ct_usr,int nargs,stack_info* st){ + const struct ctype* mt; + reg_info regs;int i; + memset(®s,0,sizeof(reg_info)); + for (i = 1; i <= nargs&&!is_float_sealed(®s); ++i){ + lua_rawgeti(L, ct_usr, i); + mt = (const struct ctype*) lua_touserdata(L, -1); + if (!mt->pointers &&! mt->is_reference) { + switch(mt->type){ + case COMPLEX_DOUBLE_TYPE: + save_float_reg(Dst,add_float_reg(®s,4,0),16,st); + break; + case DOUBLE_TYPE: + save_float_reg(Dst,add_float_reg(®s,2,0),8,st); + break; + case COMPLEX_FLOAT_TYPE: + save_float_reg(Dst,add_float_reg(®s,2,1),8,st); + break; + case FLOAT_TYPE: + save_float_reg(Dst,add_float_reg(®s,1,1),4,st); + break; + case STRUCT_TYPE: + { + int isfloat,hfasize=hfa_size(L,-1,mt,&isfloat); + if(hfasize){ + save_float_reg(Dst,add_float_reg(®s,hfasize,isfloat),4*hfasize,st); + break; + } + } + case UNION_TYPE: + break; + case INT64_TYPE: + //add_int64_reg(®s); + break; + default: + //add_int_reg(®s);//no need to check type support here + break; + } + } + lua_pop(L,1); + } + st->float_off+=st->int_off; + st->int_off+=0x40; +} +#endif cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctype* ct) { struct jit* Dst = get_jit(L);; int i, nargs, num_upvals, ref; const struct ctype* mt; + stack_info st; int top = lua_gettop(L); @@ -649,15 +1203,34 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp if (ct->has_var_arg) { luaL_error(L, "can't create callbacks with varargs"); } - + memset(&st,0,sizeof(stack_info)); + st.extra=0x10; /* prolog and get the upval table */ - dasm_put(Dst, 0, (uintptr_t)(L), (uintptr_t)(ref), (uintptr_t)(LUA_REGISTRYINDEX)); - + dasm_put(Dst, 24); +#if ARM_HF + push_regs(L,Dst,ct_usr,nargs,&st); +#endif + + dasm_put(Dst, 27, (unsigned short)(L), (((unsigned int)(L))>>16), (unsigned short)(ref), (((unsigned int)(ref))>>16), (unsigned short)(LUA_REGISTRYINDEX), (((unsigned int)(LUA_REGISTRYINDEX))>>16)); + /* get the lua function */ lua_pushvalue(L, fidx); lua_rawseti(L, -2, ++num_upvals); - dasm_put(Dst, 17, num_upvals); + + + dasm_put(Dst, 45, num_upvals); + // Complex type is return in the address stored in r0 for softfp + lua_rawgeti(L, ct_usr, 0); + mt = (const struct ctype*) lua_touserdata(L, -1); + if(!mt->pointers && !mt->is_reference &&(mt->type==STRUCT_TYPE || mt->type==UNION_TYPE|| + (!ARM_HF&&(mt->type==COMPLEX_DOUBLE_TYPE||mt->type==COMPLEX_FLOAT_TYPE)))&&mt->base_size>4&&!(ARM_HF&&hfa_size(L,-1,mt,NULL))){ + st.int_off+=4; + } + lua_pop(L,1); + + //whether 64 bit type requires 8 bytes alignment in stack is defined by compiler.android compiler reqiures only 4 byte alignment; + //actually the stack it self may reqiures 8 bytes alignment for (i = 1; i <= nargs; i++) { lua_rawgeti(L, ct_usr, i); mt = (const struct ctype*) lua_touserdata(L, -1); @@ -666,64 +1239,179 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* usr value */ lua_rawseti(L, -2, ++num_upvals); /* mt */ - - dasm_put(Dst, 24, num_upvals-1, i, (uintptr_t)(mt)); - + + dasm_put(Dst, 52, num_upvals-1, i, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + load_int(Dst,&st,4,4); + dasm_put(Dst, 68); } else { switch (mt->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ + #if ARM_HF + int isfloat,hfasize=0; + if(mt->type!=UNION_TYPE){ + hfasize=hfa_size(L,-1,mt,&isfloat); + } + #endif + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + dasm_put(Dst, 74, num_upvals-1, i, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + #if ARM_HF + if(hfasize){ + if(hfasize<=4)load_float(Dst,&st,4*hfasize,0,4*(2-isfloat)); + switch(hfasize){ + case 8: + load_float(Dst,&st,16,0,8); + load_float(Dst,&st,16,0,8); + break; + case 6: + load_float(Dst,&st,16,0,8); + load_float(Dst,&st,8,0,8); + break; + case 4: + break; + case 3: + break; + case 2: + break; + case 1: + break; + } + }else + #endif + if(!mt->is_empty){ + int size=mt->base_size; + if(size<=4){ + load_int(Dst,&st,4,4); + dasm_put(Dst, 90); + }else{ + size=ROUND_UP(size,4); + if(mt->align_mask>4){//8 byte max alignment + if(st.int_off<0x40*ARM_HF+MAX_REGS*4){FIX_ALIGN(st.int_off,8);} + else {FIX_ALIGN(st.stack_off,8);} + } + + if(st.int_off<0x40*ARM_HF+MAX_REGS*4&&(!st.stack_off||st.int_off+size<=0x40*ARM_HF+MAX_REGS*4)){//to ensure consective memory for the struct + dasm_put(Dst, 92, st.int_off+st.extra); + st.int_off+=size; + }else{ + st.int_off=0x40*ARM_HF+MAX_REGS*4; + dasm_put(Dst, 95); + st.stack_off+=size; + } + dasm_put(Dst, 97, (unsigned short)(mt->base_size), (((unsigned int)(mt->base_size))>>16), (unsigned short)(memcpy), (((unsigned int)(memcpy))>>16)); + } + } + dasm_put(Dst, 107); + break; + } + + case COMPLEX_DOUBLE_TYPE: + + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + dasm_put(Dst, 112, num_upvals-1, i, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + load_float(Dst,&st,16,0,8); + dasm_put(Dst, 128); + break; + case COMPLEX_FLOAT_TYPE: + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + dasm_put(Dst, 134, num_upvals-1, i, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + load_float(Dst,&st,8,0,4); + dasm_put(Dst, 150); + break; case INT64_TYPE: + + #if LUA_VERSION_NUM>=503 + lua_pop(L, 1); + + #if CK_ALGIN + FIX_ALIGN(st.int_off,8); + if(st.int_off<16){ + dasm_put(Dst, 156, st.int_off+st.extra); + st.int_off+=8; + }else{ + if(!ALIGNED(st.stack_off,8)){ + st.stack_off+=4; + dasm_put(Dst, 160); + } + dasm_put(Dst, 162); + st.stack_off+=8; + } + #else + load_int(Dst,st,8,8); + #endif + dasm_put(Dst, 164); + #else lua_rawseti(L, -2, ++num_upvals); /* mt */ - dasm_put(Dst, 47, (uintptr_t)(mt)); + + dasm_put(Dst, 168, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + load_int(Dst,&st,8,8); + dasm_put(Dst, 177); + #endif break; case INTPTR_TYPE: lua_rawseti(L, -2, ++num_upvals); /* mt */ - dasm_put(Dst, 68, (uintptr_t)(mt)); + + dasm_put(Dst, 183, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + load_int(Dst,&st,4,4); + dasm_put(Dst, 192); + break; case BOOL_TYPE: lua_pop(L, 1); - dasm_put(Dst, 87); - break; - - case INT8_TYPE: - lua_pop(L, 1); - dasm_put(Dst, 92); - if (mt->is_unsigned) { - dasm_put(Dst, 95); - } else { - dasm_put(Dst, 97); - } - dasm_put(Dst, 99); - break; - - case INT16_TYPE: - lua_pop(L, 1); - dasm_put(Dst, 103); - if (mt->is_unsigned) { - dasm_put(Dst, 106); - } else { - dasm_put(Dst, 108); - } - dasm_put(Dst, 110); + + load_int(Dst,&st,4,4); + dasm_put(Dst, 198); break; + case INT8_TYPE: // no need to narrow cause narrowed by caller + case INT16_TYPE: // no need to narrow cause narrowed by caller case ENUM_TYPE: case INT32_TYPE: lua_pop(L, 1); - dasm_put(Dst, 114); + + load_int(Dst,&st,4,4); + dasm_put(Dst, 202); break; case FLOAT_TYPE: lua_pop(L, 1); - dasm_put(Dst, 119); + + load_float(Dst,&st,4,ARM_HF,4); + dasm_put(Dst, 206); break; case DOUBLE_TYPE: lua_pop(L, 1); - dasm_put(Dst, 124); + + #if ARM_HF + load_float(Dst,&st,8,ARM_HF,8); + #elif CK_ALGIN + FIX_ALIGN(st.int_off,8); + if(st.int_off<16){ + dasm_put(Dst, 210, st.int_off+st.extra); + st.int_off+=8; + }else{ + if(!ALIGNED(st.stack_off,8)){ + st.stack_off+=4; + dasm_put(Dst, 214); + } + dasm_put(Dst, 216); + st.stack_off+=8; + } + #else + load_float(Dst,&st,8,ARM_HF,8); + #endif + dasm_put(Dst, 218); break; - + default: luaL_error(L, "NYI: callback arg type"); } @@ -733,79 +1421,159 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_rawgeti(L, ct_usr, 0); mt = (const struct ctype*) lua_touserdata(L, -1); - dasm_put(Dst, 129, ((mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0), nargs); + dasm_put(Dst, 222, ((mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0), nargs); + if (mt->pointers || mt->is_reference) { lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* usr value */ lua_rawseti(L, -2, ++num_upvals); /* mt */ - dasm_put(Dst, 138, num_upvals-1, (uintptr_t)(mt)); + dasm_put(Dst, 230, num_upvals-1, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + goto single_no_pop; } else { switch (mt->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ + int isfloat,hfasize=0; + if(mt->type!=UNION_TYPE){ + hfasize=hfa_size(L,-1,mt,&isfloat); + } + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + dasm_put(Dst, 246, num_upvals-1, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + #if ARM_HF + if(hfasize>0){ + switch(hfasize){ + case 8: + break; + case 6: + break; + case 4: + break; + case 3: + break; + case 2: + break; + case 1: + break; + } + }else + #endif + if(!mt->is_empty){ + if(mt->base_size<=4){ + dasm_put(Dst, 267); + }else{ + dasm_put(Dst, 269, st.extra+0x40*ARM_HF, (unsigned short)(mt->base_size), (((unsigned int)(mt->base_size))>>16), (unsigned short)(memcpy), (((unsigned int)(memcpy))>>16)); + } + } + break; + } case ENUM_TYPE: lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* usr value */ lua_rawseti(L, -2, ++num_upvals); /* mt */ - dasm_put(Dst, 161, num_upvals-1, (uintptr_t)(mt)); - break; + dasm_put(Dst, 282, num_upvals-1, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + + goto single_no_pop; case VOID_TYPE: - dasm_put(Dst, 184); + dasm_put(Dst, 298); lua_pop(L, 1); break; case BOOL_TYPE: - case INT8_TYPE: - case INT16_TYPE: + case INT8_TYPE:// narrow it + case INT16_TYPE:// narrow it case INT32_TYPE: - dasm_put(Dst, 189); + dasm_put(Dst, 303); if (mt->is_unsigned) { - dasm_put(Dst, 191); + dasm_put(Dst, 305); } else { - dasm_put(Dst, 195); + dasm_put(Dst, 309); } + switch(mt->type){ + case BOOL_TYPE: + dasm_put(Dst, 313); + break; + case INT8_TYPE: + if (mt->is_unsigned) { + dasm_put(Dst, 316); + } else { + dasm_put(Dst, 318); + } + break; + case INT16_TYPE: + if (mt->is_unsigned) { + dasm_put(Dst, 320); + } else { + dasm_put(Dst, 322); + } + break; + } goto single; case INT64_TYPE: - dasm_put(Dst, 199); + dasm_put(Dst, 324); if (mt->is_unsigned) { - dasm_put(Dst, 201); + dasm_put(Dst, 326); } else { - dasm_put(Dst, 205); + dasm_put(Dst, 330); } goto dual; case INTPTR_TYPE: - dasm_put(Dst, 209); + dasm_put(Dst, 334); goto single; case FLOAT_TYPE: - dasm_put(Dst, 214); + dasm_put(Dst, 339); + #if ARM_HF + lua_pop(L, 1); + #else goto single; - + #endif + break; case DOUBLE_TYPE: - dasm_put(Dst, 219); - goto dual; - + dasm_put(Dst, 344); + #if ARM_HF + lua_pop(L, 1); + #else + goto dual; + #endif + break; + case COMPLEX_DOUBLE_TYPE: + lua_pop(L, 1); + dasm_put(Dst, 349, st.extra); + break; + case COMPLEX_FLOAT_TYPE: + lua_pop(L, 1); + dasm_put(Dst, 360, st.extra); + break; + single: - dasm_put(Dst, 224); lua_pop(L, 1); + single_no_pop: + dasm_put(Dst, 371); + break; - - dual: - dasm_put(Dst, 231); + dual: + dasm_put(Dst, 378); + lua_pop(L, 1); - break; + break; + + default: luaL_error(L, "NYI: callback return type"); } } - - dasm_put(Dst, 240); - + + dasm_put(Dst, 387); + lua_pop(L, 1); /* upval table - already in registry */ assert(lua_gettop(L) == top); @@ -827,12 +1595,200 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp } } +static ALWAYS_INLINE void save_int64_stack_align(struct jit* Dst,reg_info* regs,int align){ + if(align&&!ALIGNED(regs->exs,2)){ + regs->exs++; + dasm_put(Dst, 389); + } + dasm_put(Dst, 391); + regs->exs+=2; +} + +static ALWAYS_INLINE void save_int64_align(struct jit* Dst,reg_info* regs,int align){ + if((align&&!ALIGNED(regs->ints,2))||(regs->ints==MAX_REGS-1&®s->exs/*to ensure consective memory*/)){ + regs->ints++; + } + if(regs->intsints<<2)+0x40*ARM_HF)); + regs->ints+=2; + }else{ + save_int64_stack_align(Dst,regs,align); + } + +} + +static ALWAYS_INLINE void save_int64(struct jit* Dst,reg_info* regs){ + save_int64_align(Dst,regs,1); +} + +static ALWAYS_INLINE void save_int_stack_align(struct jit* Dst,reg_info* regs){ + dasm_put(Dst, 397); + regs->exs++; +} + +static ALWAYS_INLINE void save_int(struct jit* Dst,reg_info* regs){ + if(regs->intsints++<<2)+0x40*ARM_HF)); + }else{ + save_int_stack_align(Dst,regs); + } +} + +static void save_float(struct jit* Dst,reg_info* regs,int size,int isfloat){ +#if ARM_HF + if(!regs->float_sealed){ + int reg=add_float_reg(regs,size,isfloat); + if(reg<0) goto SAVE_STACK; + switch(size){ + case 8: + case 6: + case 4: + goto sf_2; + case 3: + case 2: + sf_2: + break; + case 1: + break; + } + return; + } + SAVE_STACK: + + if(!isfloat&&!ALIGNED(regs->exs,2)){ + regs->exs++; + dasm_put(Dst, 402); + } + switch(size){ + case 1: + dasm_put(Dst, 404); + break; + case 2: + dasm_put(Dst, 406); + break; + case 3: + dasm_put(Dst, 408); + break; + case 4: + dasm_put(Dst, 410); + break; + case 6: + dasm_put(Dst, 412); + break; + case 8: + dasm_put(Dst, 414); + break; + + } + regs->exs+=size; + +#else + if(size==1){ + save_int(Dst,regs); + }else if(size==2){ + save_int64_align(Dst,regs,!isfloat); + } +#endif +} + +static int calculate_stack(lua_State* L,int ct_usr,int nargs){ + const struct ctype* mt; + reg_info regs;int i,stack=0; + memset(®s,0,sizeof(reg_info)); + for (i = 1; i <= nargs;++i){ + lua_rawgeti(L, ct_usr, i); + mt = (const struct ctype*) lua_touserdata(L, -1); + if (mt->pointers || mt->is_reference) { + stack+=add_int_reg(®s); + }else{ + switch(mt->type){ + case COMPLEX_DOUBLE_TYPE: + #if ARM_HF + stack+=add_float_reg(®s,4,0)<0?4:0; + #else + stack+=add_int64_reg(®s); + stack+=add_int64_reg(®s); + #endif + FIX_ALIGN(stack,2); + break; + case DOUBLE_TYPE: + #if ARM_HF + stack+=add_float_reg(®s,2,0)<0?2:0; + #else + stack+=add_int64_reg(®s); + #endif + FIX_ALIGN(stack,2); + break; + case COMPLEX_FLOAT_TYPE:// Though complex alignment is 4, but vfp requires a sequence of regsiters + #if ARM_HF + stack+=add_float_reg(®s,2,1)<0?2:0; + #else + stack+=add_int_reg(®s); + stack+=add_int_reg(®s); + #endif + break; + case FLOAT_TYPE: + #if ARM_HF + stack+=add_float_reg(®s,1,1)<0?1:0; + #else + stack+=add_int_reg(®s); + #endif + break; + case INT64_TYPE: + stack+=add_int64_reg(®s); + FIX_ALIGN(stack,2); + break; + case STRUCT_TYPE:{ + #if ARM_HF + int isfloat; + int hfasize=hfa_size(L,-1,mt,&isfloat); + if(hfasize>0){ + stack+=add_float_reg(®s,2,0)<0?hfasize:0; + if(!isfloat){ + FIX_ALIGN(stack,2); + } + break; + } + #endif + } + case UNION_TYPE:{ + int intsize=(mt->base_size+3)>>2; + if(mt->align_mask>4){//8-byte max alignment + if(regs.intshas_var_arg) { - dasm_put(Dst, 254, (uintptr_t)("too few arguments")); - } else { - dasm_put(Dst, 266, (uintptr_t)("incorrect number of arguments")); - } - - /* reserve enough stack space for all of the arguments (8 bytes per - * argument for double and maintains alignment). Add an extra 16 bytes so - * that the pop {r0, r1, r2, r3} doesn't clean out our stack frame */ - dasm_put(Dst, 278); - +#if defined __thumb__ //keep frame pointer + dasm_put(Dst, 416); +#else + dasm_put(Dst, 419); +#endif +#if CK_ALGIN + dasm_put(Dst, 422); +#endif + dasm_put(Dst, 424); + + /* Reserve enough stack space for all of the arguments. For hard floating point, + * leave extra 64 bytes + */ + stack_size=calculate_stack(L,ct_usr,nargs); + lua_rawgeti(L, ct_usr, 0); + mt = (const struct ctype*) lua_touserdata(L, -1); + + // Complex types in softfp and structs/unions larger than 4-bytes are return in the address stored in r0 + ret_by_addr=!mt->pointers && !mt->is_reference &&(mt->type==STRUCT_TYPE || mt->type==UNION_TYPE|| + (!ARM_HF&&(mt->type==COMPLEX_DOUBLE_TYPE||mt->type==COMPLEX_FLOAT_TYPE)))&&mt->base_size>4&&!(ARM_HF&&hfa_size(L,-1,mt,NULL)); + lua_pop(L,1); + if(ret_by_addr){ + if(stack_size==0) + stack_size=0x40*ARM_HF+0x10; + stack_size+=8; + } + if(stack_size>0){ + if(stack_size>=1<<12){ + dasm_put(Dst, 426, (unsigned short)(stack_size), (((unsigned int)(stack_size))>>16)); + }else{ + dasm_put(Dst, 432, stack_size); + } + if (ct->has_var_arg){ + dasm_put(Dst, 435, nargs, (unsigned short)("too few arguments"), (((unsigned int)("too few arguments"))>>16)); + } + dasm_put(Dst, 452, 0x40*ARM_HF+0x10); + } + + memset(®s,0,sizeof(reg_info)); + + if (ret_by_addr) { + regs.ints++; + dasm_put(Dst, 455, (unsigned short)(mt), (((unsigned int)(mt))>>16), 0x40*ARM_HF); + } + + for (i = 1; i <= nargs; i++) { lua_rawgeti(L, ct_usr, i); mt = (const struct ctype*) lua_touserdata(L, -1); - - if (mt->pointers || mt->is_reference || mt->type == FUNCTION_PTR_TYPE || mt->type == ENUM_TYPE) { + + if (mt->pointers || mt->is_reference || mt->type == FUNCTION_PTR_TYPE || mt->type == ENUM_TYPE|| mt->type==STRUCT_TYPE || mt->type==UNION_TYPE) { lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 282, (uintptr_t)(mt), (uintptr_t)(lua_upvalueindex(num_upvals)), i); - + dasm_put(Dst, 466, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)(lua_upvalueindex(num_upvals)), (((unsigned int)(lua_upvalueindex(num_upvals)))>>16), i); + if (mt->pointers || mt->is_reference) { - dasm_put(Dst, 293); + dasm_put(Dst, 477); } else if (mt->type == FUNCTION_PTR_TYPE) { - dasm_put(Dst, 296); + dasm_put(Dst, 481); } else if (mt->type == ENUM_TYPE) { - dasm_put(Dst, 299); - } - - dasm_put(Dst, 302); - + dasm_put(Dst, 485); + }else if(mt->type==STRUCT_TYPE || mt->type==UNION_TYPE){ + if(mt->is_empty) continue; + dasm_put(Dst, 489); + #if ARM_HF + { + int hfasize,isfloat; + hfasize=hfa_size(L,-2,mt,&isfloat); + if(hfasize){ + switch(hfasize){ + case 8: + break; + case 6: + break; + case 4: + break; + case 3: + break; + case 2: + break; + case 1: + break; + + } + save_float(Dst,®s,hfasize,isfloat); + continue; + } + } + #endif + + if(mt->align_mask>4){//8 byte max alignment + if(regs.ints<4){ + FIX_ALIGN(regs.ints,2) + }else if(!ALIGNED(regs.exs,2)){ + int diff=regs.exs; + regs.exs+=4; + dasm_put(Dst, 493); + } + } + int size=ROUND_UP(mt->base_size,4)>>2; + dasm_put(Dst, 495, (unsigned short)(mt->base_size), (((unsigned int)(mt->base_size))>>16), (unsigned short)(memcpy), (((unsigned int)(memcpy))>>16)); + if(regs.intstype) { + case BOOL_TYPE: + dasm_put(Dst, 518); + save_int(Dst,®s); + break; case INT8_TYPE: - dasm_put(Dst, 307); + dasm_put(Dst, 524); if (mt->is_unsigned) { - dasm_put(Dst, 311); + dasm_put(Dst, 528); } else { - dasm_put(Dst, 313); + dasm_put(Dst, 530); } - dasm_put(Dst, 316); + save_int(Dst,®s); break; case INT16_TYPE: - dasm_put(Dst, 318); + dasm_put(Dst, 532); if (mt->is_unsigned) { - dasm_put(Dst, 322); + dasm_put(Dst, 536); } else { - dasm_put(Dst, 325); + dasm_put(Dst, 538); } - dasm_put(Dst, 328); + save_int(Dst,®s); break; case INT32_TYPE: if (mt->is_unsigned) { - dasm_put(Dst, 330); + dasm_put(Dst, 540); } else { - dasm_put(Dst, 334); + dasm_put(Dst, 544); } - dasm_put(Dst, 338); + save_int(Dst,®s); break; + case INTPTR_TYPE: + dasm_put(Dst, 548); + save_int(Dst,®s); + break; case INT64_TYPE: if (mt->is_unsigned) { - dasm_put(Dst, 340); + dasm_put(Dst, 552); } else { - dasm_put(Dst, 344); + dasm_put(Dst, 556); } - dasm_put(Dst, 348); + save_int64(Dst,®s); break; case DOUBLE_TYPE: - dasm_put(Dst, 351); - break; - - case INTPTR_TYPE: - dasm_put(Dst, 357); + dasm_put(Dst, 560); + save_float(Dst,®s,2,0); break; case FLOAT_TYPE: - dasm_put(Dst, 362); + dasm_put(Dst, 564); + save_float(Dst,®s,1,1); + break; + + case COMPLEX_DOUBLE_TYPE: + #if ARM_HF + save_float(Dst,®s,4,0); + #else + FIX_ALIGN(regs.ints,2); + dasm_put(Dst, 568); + if(regs.intsMAX_REGS){ + dasm_put(Dst, 592, (regs.ints-4)<<2); + regs.exs+=regs.ints-MAX_REGS; + regs.ints=MAX_REGS; + } + #endif break; - default: luaL_error(L, "NYI: call arg type"); } @@ -939,75 +2031,219 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty } if (ct->has_var_arg) { - dasm_put(Dst, 367, nargs+1); - } - - dasm_put(Dst, 375, (uintptr_t)(&Dst->last_errno)); - - dasm_put(Dst, 384); - - + int offset=nargs+1; + dasm_put(Dst, 595, offset); + #if ARM_HF + if(regs.ints==4||regs.float_sealed){ + if(regs.ints<4&®s.float_sealed){//some arg must be loaded to core registers. + } + } + #else + if(regs.ints==4){ + dasm_put(Dst, 598); + } + #endif + else{//no hard floating point in variadic procedure + dasm_put(Dst, 600, ((regs.ints<<2)+ARM_HF*0x40)); + } + + dasm_put(Dst, 603); + regs.ints=4; + } + + #if ARM_HF + switch(ROUND_UP(regs.highest_bit,4)>>1){ + case 8 : + break; + case 7 : + break; + case 6 : + break; + case 5: + break; + case 4 : + break; + case 3 : + break; + case 2 : + break; + case 1 : + break; + } + if(stack_size>0){ + } + #endif + + //pop registers from stack,align 8 for some compiler + assert(regs.ints<=4); + switch(regs.ints){ + case 4: + case 3: + dasm_put(Dst, 608); + break; + case 2: + case 1: + dasm_put(Dst, 610); + #if ARM_HF + if(regs.float_sealed){ + } + #endif + break; + default: + #if ARM_HF + if(regs.float_sealed){ + } + #endif + break; + } + + dasm_put(Dst, 612, (unsigned short)(func), (((unsigned int)(func))>>16)); lua_rawgeti(L, ct_usr, 0); mt = (const struct ctype*) lua_touserdata(L, -1); - if (mt->pointers || mt->is_reference) { + if (mt->pointers || mt->is_reference || mt->type==FUNCTION_PTR_TYPE) { lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 388, (uintptr_t)(&Dst->last_errno), (uintptr_t)(mt), (uintptr_t)(lua_upvalueindex(num_upvals))); + dasm_put(Dst, 618, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)(lua_upvalueindex(num_upvals)), (((unsigned int)(lua_upvalueindex(num_upvals)))>>16)); } else { switch (mt->type) { case INT64_TYPE: - num_upvals++; - dasm_put(Dst, 411, (uintptr_t)(&Dst->last_errno), (uintptr_t)(mt)); + #if LUA_VERSION_NUM>=503 + lua_pop(L, 1); + #if CK_ALGIN + dasm_put(Dst, 633); + #else + dasm_put(Dst, 636); + #endif + dasm_put(Dst, 639); break; - + #else + num_upvals++; + dasm_put(Dst, 644, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + break; + #endif + case INTPTR_TYPE: num_upvals++; - dasm_put(Dst, 438, (uintptr_t)(&Dst->last_errno), (uintptr_t)(mt)); + dasm_put(Dst, 658, (unsigned short)(mt), (((unsigned int)(mt))>>16)); break; case VOID_TYPE: lua_pop(L, 1); - dasm_put(Dst, 463, (uintptr_t)(&Dst->last_errno)); + dasm_put(Dst, 670); break; case BOOL_TYPE: lua_pop(L, 1); - dasm_put(Dst, 474, (uintptr_t)(&Dst->last_errno)); + dasm_put(Dst, 672); break; case INT8_TYPE: case INT16_TYPE: case INT32_TYPE: - case ENUM_TYPE: + case ENUM_TYPE:// value must be narrowed before callee return lua_pop(L, 1); - dasm_put(Dst, 490, (uintptr_t)(&Dst->last_errno)); + + dasm_put(Dst, 678); if (mt->is_unsigned) { - dasm_put(Dst, 501); + dasm_put(Dst, 680); } else { - dasm_put(Dst, 505); + dasm_put(Dst, 684); } - dasm_put(Dst, 509); + + dasm_put(Dst, 688); break; case FLOAT_TYPE: lua_pop(L, 1); - dasm_put(Dst, 512, (uintptr_t)(&Dst->last_errno)); + dasm_put(Dst, 690); break; case DOUBLE_TYPE: lua_pop(L, 1); - dasm_put(Dst, 528, (uintptr_t)(&Dst->last_errno)); + #if CK_ALGIN + dasm_put(Dst, 696); + #else + dasm_put(Dst, 699); + #endif + dasm_put(Dst, 702); break; - + case COMPLEX_DOUBLE_TYPE: + case COMPLEX_FLOAT_TYPE: + case STRUCT_TYPE: + case UNION_TYPE:{ + lua_getuservalue(L,-1); + num_upvals += 2; + #if ARM_HF + { + int isfloat,hfasize=hfa_size(L,-2,mt,&isfloat); + if(hfasize>0){ + switch(hfasize){ + case 8: + break; + case 6: + break; + case 4: + case 3: + break; + case 2: + case 1: + break; + + } + switch(hfasize){ + case 8: + break; + case 6: + break; + case 4: + break; + case 3: + break; + case 2: + break; + case 1: + break; + + } + break; + } + } + + #endif + if(mt->base_size>4){ + // value are stored in return storage in r0 for softfp, set usr value here + if(!lua_isnil(L,-1)){ + dasm_put(Dst, 707, (unsigned short)(lua_upvalueindex(num_upvals)), (((unsigned int)(lua_upvalueindex(num_upvals)))>>16)); + } + }else if(mt->is_empty){ + dasm_put(Dst, 719); + break; + }else{ + dasm_put(Dst, 721, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)(lua_upvalueindex(num_upvals)), (((unsigned int)(lua_upvalueindex(num_upvals)))>>16)); + } + dasm_put(Dst, 735); + break; + } default: luaL_error(L, "NYI: call return type"); } } +#ifdef __thumb__ + dasm_put(Dst, 737); +#else + dasm_put(Dst, 740); +#endif assert(lua_gettop(L) == top + num_upvals); - lua_pushcclosure(L, (lua_CFunction) compile(Dst, L, func, LUA_NOREF), num_upvals); + { + cfunction f = compile(Dst, L, NULL, LUA_NOREF); + /* add a callback as an upval so that the jitted code gets cleaned up when + * the function gets gc'd */ + push_callback(L, f, func); + lua_pushcclosure(L, (lua_CFunction) f, num_upvals+1); + } } diff --git a/texk/web2c/luatexdir/luaffi/call_arm64.dasc b/texk/web2c/luatexdir/luaffi/call_arm64.dasc new file mode 100644 index 0000000000..e6198451b5 --- /dev/null +++ b/texk/web2c/luatexdir/luaffi/call_arm64.dasc @@ -0,0 +1,1496 @@ +/* vim: ts=4 sw=4 sts=4 et tw=78 + * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved. + * Portions copyright (c) 2011 James R. McKaskill. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +|.arch arm64 + +|.actionlist build_actionlist +|.globalnames globnames +|.externnames extnames + +#define JUMP_SIZE 16 + +//in aarch64 the pc is indicated the current +#define MIN_BRANCH ((INT32_MIN) >> 6) +#define MAX_BRANCH ((INT32_MAX) >> 6) +//arm64 pc has no offset so comparing with next instruction is -4 +#define BRANCH_OFF -4 +#define ROUND_UP(x, align) (((int) (x) + (align - 1)) & ~(align - 1)) + +static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, uint8_t* code) +{ + /* The jump code is the function pointer followed by a stub to call the + * function pointer. The stub exists so we can jump to functions with an + * offset greater than 128MB. + * + * Note we have to manually set this up since there are commands buffered + * in the jit state. + */ + + //l: ptr + *(cfunction*) code = func; + // ldr x9,#-8 + *(uint32_t*) &code[8] = 0x58FFFFC9; + //br x9 + *(uint32_t*) &code[12] = 0xD61F0120; + +} + +|.define TOP, x19 +|.define DATA,x20 +|.define L_ARG,x21 +|.macro load64, reg, val +//| ldr reg, >5 +//| b >6 +//|5: +//|.long64 val +//|6: +| mov reg, #(unsigned short)(val) +| movk reg, #(((unsigned int)(val))>>16), lsl #16 +| movk reg, #(unsigned short)((unsigned long)(val)>>32), lsl #32 +| movk reg, #(unsigned short)((unsigned long)(val)>>48), lsl #48 +|.endmacro + +|.macro load32, reg, val +| mov reg, #(unsigned short)(val) +| movk reg, #(((unsigned int)(val))>>16), lsl #16 +|.endmacro + +|.macro lcall, func +| mov x0, L_ARG +| bl func +|.endmacro + +void compile_globals(struct jit* jit, lua_State* L) +{ + (void) jit; +} +typedef struct reg_info{ + uint8_t ints; + uint8_t floats; + uint16_t ex; +} reg_info; + +static ALWAYS_INLINE bool is_float_type(int t){ + return t==FLOAT_TYPE||t==DOUBLE_TYPE; +} + +static int hfa_size(lua_State* L,int idx, const struct ctype* ct,int* isfloat){ + struct ctype* mt; + int type,ele_count,i,ct_usr; + lua_getuservalue(L,idx); + ct_usr=lua_absindex(L,-1); + lua_rawgeti(L,ct_usr,1); + mt=(struct ctype*)lua_touserdata(L,-1); + if(mt==NULL||(mt->pointers&&!mt->is_array)||mt->is_reference||!is_float_type(mt->type)){ + lua_pop(L,2); + return 0; + } + type=mt->type; + ele_count=(int)(ct->base_size/mt->base_size); + if(ele_count>4||ct->base_size%mt->base_size){ + lua_pop(L,2); + return 0; + } + lua_pop(L,1); + for (i = 2;i<=4; ++i) { + lua_rawgeti(L,ct_usr,i); + if(lua_isnil(L,-1)){//case have array member; + lua_pop(L,1); + break; + } + mt=(struct ctype*)lua_touserdata(L,-1); + if(mt->type!=type||(mt->pointers&&!mt->is_array)||mt->is_reference||!is_float_type(mt->type)){ + lua_pop(L,2); + return 0; + } + lua_pop(L,1); + } + if(isfloat){ + *isfloat=mt->type==FLOAT_TYPE; + } + lua_pop(L,1); + return ele_count; +} + +static reg_info caculate_regs(lua_State* L,int ct_usr,int nargs){ + int i;reg_info regs; + const struct ctype* mt; + for (i = 1,regs.ints=0,regs.floats=0; i <= nargs&&(regs.floats<8||regs.ints<8); ++i){ + lua_rawgeti(L, ct_usr, i); + mt = (const struct ctype*) lua_touserdata(L, -1); + if (mt->pointers || mt->is_reference) { + if(regs.ints<8)regs.ints++; + }else{ + switch(mt->type){ + case COMPLEX_DOUBLE_TYPE: + case COMPLEX_FLOAT_TYPE: + if(regs.floats<7) + regs.floats+=2; + else if(regs.floats==7) + regs.floats=8; + break; + case FLOAT_TYPE: + case DOUBLE_TYPE: + if(regs.floats<8) ++regs.floats; + break; + case STRUCT_TYPE:{ + int hfasize=hfa_size(L,-1,mt,NULL); + if(hfasize>0){ + regs.floats+=hfasize; + if(regs.floats>8) + regs.floats=8; + break; + } + } + case UNION_TYPE:{ + int size=mt->base_size; + if(size>16){//passed by address + if(regs.ints<8)++regs.ints; + break; + } + if(mt->is_empty){ + break; //ignored empty struct + } + size=(size+7)>>3; + if(regs.ints+size<=8) regs.ints+=size; + break; + } + default: + if(regs.ints<8)++regs.ints;//no need to check type support here + } + } + lua_pop(L,1); + } + + return regs; +} + +// arm store/load range for immediate value is only -256-255 +static ALWAYS_INLINE void load_int(struct jit* Dst,reg_info* regs){ + if(regs->ints<8) + | ldr x1, [sp, #0x60+(regs->ints++<<3)] //64 bit ptr + else + | ldr x1, [DATA], #(regs->ex++,8) +} + +static void load_float(struct jit* Dst,reg_info* regs,int isfloat,int exSize){ + if(regs->floats+exSize<8){ + switch(exSize){ + case 3: + | ldp d2,d3, [sp, #0x30+(regs->floats<<3)] + goto l_dual; + case 2: + | ldr d2, [sp, #0x30+(regs->floats<<3)] + case 1: + l_dual: + | ldp d0,d1, [sp, #0x20+(regs->floats<<3)] + break; + case 0: + | ldr d0, [sp, #0x20+(regs->floats<<3)] + break; + } + regs->floats+=exSize+1; + + }else{ + regs->floats=8; + regs->ex+=exSize+1; + switch(exSize){ + case 3: + if(isfloat){ + | ldp s0,s1, [DATA], #8 + | ldp s2,s3, [DATA], #8 + }else{ + | ldp d0, d1, [DATA], #16 + | ldp d2, d3, [DATA], #16 + } + break; + case 2: + if(isfloat){ //12 bytes rounded to 16 + | ldp s0,s1, [DATA], #8 + | ldr s2, [DATA], #8 + break; + }else { + | ldp d0, d1, [DATA], #16 + | ldr d2, [DATA], #8 + } + break; + case 1: + if(isfloat){ + | ldp s0,s1, [DATA], #8 + }else{ + | ldp d0, d1, [DATA], #16 + } + break; + case 0: + if(isfloat){ + | ldr s0, [DATA], #8 + }else { + | ldr d0, [DATA], #8 + } + break; + } + + } +} + +cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctype* ct) +{ + struct jit* Dst = get_jit(L);; + int i, nargs, num_upvals, ref,ret_by_addr; + const struct ctype* mt; + + int top = lua_gettop(L); + + ct_usr = lua_absindex(L, ct_usr); + fidx = lua_absindex(L, fidx); + nargs = (int) lua_rawlen(L, ct_usr); + + dasm_setup(Dst, build_actionlist); + + lua_newtable(L); + lua_pushvalue(L, -1); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + num_upvals = 0; + + if (ct->has_var_arg) { + luaL_error(L, "can't create callbacks with varargs"); + } + + lua_rawgeti(L, ct_usr, 0); + mt = (const struct ctype*) lua_touserdata(L, -1); + ret_by_addr=!mt->pointers && !mt->is_reference &&(mt->type==STRUCT_TYPE||mt->type==UNION_TYPE) + && mt->base_size>16&& !(mt->type==STRUCT_TYPE&&hfa_size(L,-1,mt,NULL)!=0); + if(ret_by_addr){ + | str x8, [sp, #-16]! //preserve ret address; + } + lua_pop(L,1); + reg_info regs=caculate_regs(L,ct_usr,nargs); + + if(regs.ints||regs.floats){ + | sub sp,sp,#0xa0 + }else{ + | sub sp,sp,#0x20 + } + //8 integer reigsters and 8 floating registers + switch(regs.ints){ + case 8: + case 7: + | stp x6,x7, [sp,#0x90] + case 6: + case 5: + | stp x4,x5, [sp,#0x80] + case 4: + case 3: + | stp x2,x3, [sp,#0x70] + case 2: + case 1: + | stp x0,x1, [sp,#0x60] + } + + switch(regs.floats){ + case 8: + case 7: + | stp d6,d7, [sp,#0x50] + case 6: + case 5: + | stp d4,d5, [sp,#0x40] + case 4: + case 3: + | stp d2,d3, [sp,#0x30] + case 2: + case 1: + | stp d0,d1, [sp,#0x20] + } + | stp DATA, L_ARG,[sp,#0x10] + | stp x29, x30,[sp] + + if(regs.ints==8||regs.floats==8){ // may be overflowed if it's full + | add DATA, sp, #0xa0+ret_by_addr*0x10 + } + + /* get the lua function */ + lua_pushvalue(L, fidx); + lua_rawseti(L, -2, ++num_upvals); + + | load64 L_ARG, L + | load32 w2, ref + | load32 w1, LUA_REGISTRYINDEX + | lcall extern rawgeti //get the table + + | mov w2, #num_upvals + | movn x1, #0 // -1 + | lcall extern rawgeti //get the function + + + for (i = 1,regs.ints=0,regs.floats=0; i <= nargs; ++i) { + lua_rawgeti(L, ct_usr, i); + mt = (const struct ctype*) lua_touserdata(L, -1); + + if (mt->pointers || mt->is_reference) { + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + | mov w2, #num_upvals-1 // usr value + | movn x1, #i // -i-1, stack is upval table, func, i-1 args + | lcall extern rawgeti + | load64 x2, mt + | movn w1, #0 // -1 + | lcall extern push_cdata + load_int(Dst,®s); + | str x1, [x0] + | movn w1, #1 //-2 + | lcall extern lua_remove // remove the usr value + + } else { + switch (mt->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ + int isfloat,hfasize=0; + if(mt->type!=UNION_TYPE){ + hfasize=hfa_size(L,-1,mt,&isfloat); + } + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + | mov w2, #num_upvals-1 // usr value + | movn x1, #i // -i-1, stack is upval table, func, i-1 args + | lcall extern rawgeti + | load64 x2, mt + | movn w1, #0 // -1 + | lcall extern push_cdata + + if(hfasize){ + load_float(Dst,®s,isfloat,hfasize-1); + switch(hfasize){ + case 4: + if(isfloat){ + | stp s2, s3, [x0,#8] + }else{ + | stp d2, d3, [x0,#16] + } + goto hfa2; + case 3: + if(isfloat){ + | str s2, [x0,#8] + }else{ + | str d2, [x0,#16] + } + case 2: + hfa2: + if(isfloat){ + | stp s0, s1, [x0] + }else{ + | stp d0, d1, [x0] + } + break; + case 1: + if(isfloat){ + | str s0, [x0] + }else{ + | str d0, [x0] + } + break; + + } + }else if(!mt->is_empty){ + size_t size=mt->base_size; + if(size>16){ + load_int(Dst,®s); + | load64 x2, mt->base_size + | load64 x9, memcpy + | blr x9 + }else{ + size=(size+7)>>3; + if(mt->align_mask>8){ + if(regs.ints&1) regs.ints++; + else if(regs.ex&1) regs.ex++; + } + if(regs.ints+size<=8){ + if(size>1){ + | ldp x1,x2, [sp,#0x60+(regs.ints<<3)] + | stp x1, x2, [x0] + }else{ + | ldr x1, [sp,#0x60+(regs.ints<<3)] + | str x1, [x0] + } + regs.ints+=size; + }else{ + regs.ints=8; + if(size>1){ + | ldp x1,x2, [DATA], #16 + | stp x1, x2, [x0] + }else{ + | ldr x1, [DATA], #8 + | str x1, [x0] + } + + } + } + + + } + + | movn w1, #1 // -2 + | lcall extern lua_remove // remove the nil usr + break; + } + case COMPLEX_DOUBLE_TYPE: + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + | mov w2, #num_upvals-1 // usr value + | movn x1, #i // -i-1, stack is upval table, func, i-1 args + | lcall extern rawgeti + | load64 x2, mt + | movn w1, #0 // -1 + | lcall extern push_cdata + load_float(Dst,®s,0,1); + |stp d0,d1,[x0] + | movn w1, #1 // -2 + | lcall extern lua_remove // remove the nil usr + + break; + case COMPLEX_FLOAT_TYPE: + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + | mov w2, #num_upvals-1 // usr value + | movn x1, #i // -i-1, stack is upval table, func, i-1 args + | lcall extern rawgeti + | load64 x2, mt + | movn w1, #0 // -1 + | lcall extern push_cdata + load_float(Dst,®s,1,1); + | stp s0,s1, [x0] + | movn w1, #1 // -2 + | lcall extern lua_remove // remove the nil usr + + break; + case INT64_TYPE: + #if LUA_VERSION_NUM>=503 + lua_pop(L, 1); + load_int(Dst,®s); + | lcall extern lua_pushinteger + + #else + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + | load64 x2, mt + | mov w1, wzr + | lcall extern push_cdata + load_int(Dst,®s); + | str x1, [x0] + | movn w1, #1 // -2 + | lcall extern lua_remove // remove the nil usr + + #endif + break; + + case INTPTR_TYPE: + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + | load64 x2, mt + | mov w1, wzr + | lcall extern push_cdata + load_int(Dst,®s); + | str x1, [x0] + | movn w1, #1 // -2 + | lcall extern lua_remove // remove the nil usr + + break; + + case BOOL_TYPE: + lua_pop(L, 1); + + load_int(Dst,®s); + | lcall extern lua_pushboolean + + break; + + case INT8_TYPE:// need to narrow for caller doesn't do it + lua_pop(L, 1); + if(regs.ints<8){ + if (mt->is_unsigned) { + | ldrb w1, [sp,#0x60+(regs.ints++<<3)] + } else { + | ldrsb w1, [sp,#0x60+(regs.ints++<<3)] + } + }else { + if (mt->is_unsigned) { + | ldrb w1, [DATA], #8 + } else { + | ldrsb w1, [DATA], #8 + } + } + | lcall extern push_int + break; + + case INT16_TYPE:// need to narrow for caller doesn't do it + lua_pop(L, 1); + if(regs.ints<8){ + if (mt->is_unsigned) { + | ldrh w1, [sp,#0x60+(regs.ints++<<3)] + } else { + | ldrsh w1, [sp,#0x60+(regs.ints++<<3)] + } + }else { + if (mt->is_unsigned) { + | ldrh w1, [DATA], #8 + } else { + | ldrsh w1, [DATA], #8 + } + } + | lcall extern push_int + break; + + case ENUM_TYPE: + case INT32_TYPE: + lua_pop(L, 1); + load_int(Dst,®s); + + | lcall extern push_int + break; + + case FLOAT_TYPE: + lua_pop(L, 1); + load_float(Dst,®s,1,0); + | lcall extern push_float + break; + + case DOUBLE_TYPE: + lua_pop(L, 1); + load_float(Dst,®s,0,0); + | lcall extern lua_pushnumber + break; + default: + luaL_error(L, "NYI: callback arg type"); + } + } + } + + lua_rawgeti(L, ct_usr, 0); + mt = (const struct ctype*) lua_touserdata(L, -1); + + | mov w2, #((mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0) + | mov w1, #nargs + | lcall extern lua_call + + |.macro retcdata, func + | mov w2, #num_upvals-1 // usr value + | movn x1, #1 // -2 stack is (upval table, ret val) + | lcall extern rawgeti + | load64 x3, mt + | movn x2, #0 // -1 - ct_usr + | movn x1, #1 // -2 - val + | lcall extern func + |.endmacro + + + if (mt->pointers || mt->is_reference) { + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + | retcdata check_typed_pointer + goto single_no_pop; + } else { + switch (mt->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ + int hfasize=0,isfloat; + if(mt->type!=UNION_TYPE){ + hfasize=hfa_size(L,-1,mt,&isfloat); + } + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + | retcdata check_struct + | mov DATA ,x0 + | movn w1, #2 // -3 + | lcall extern lua_settop + if(hfasize){ + switch(hfasize){ + case 4: + if(isfloat){ + | ldp s2,s3, [DATA,#8] + }else{ + | ldp d2,d3, [DATA,#16] + } + goto ld_hfa; + case 3: + if(isfloat){ + | ldr s2, [DATA,#8] + }else{ + | ldr d2, [DATA,#16] + } + case 2: + ld_hfa: + if(isfloat){ + | ldp s0,s1, [DATA] + }else{ + | ldp d0,d1, [DATA] + } + break; + case 1: + if(isfloat){ + | ldr s0, [DATA] + }else{ + | ldr d0, [DATA] + } + break; + } + }else{ + if(mt->base_size>16){ + | ldr x0, [sp, #0x20+((regs.ints||regs.floats)?0x80:0)] + | mov x1, DATA + | load64 x2, mt->base_size + | load64 x9, memcpy + | blr x9 + }else{ + if(mt->base_size>8){ + | ldp x0, x1, [DATA] + }else{ + | ldr x0, [DATA] + } + } + } + break; + } + case ENUM_TYPE: + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + | retcdata check_enum + + goto single_no_pop; + + case VOID_TYPE: + | movn w1,#1 //-2 + | lcall extern lua_settop + lua_pop(L, 1); + break; + + case BOOL_TYPE: + case INT8_TYPE: + case INT16_TYPE: + case INT32_TYPE: //caller's responsiblity to narrow + | movn w1,#0 + if (mt->is_unsigned) { + | lcall extern check_uint32 + } else { + | lcall extern check_int32 + } + + goto single; + + case INT64_TYPE: + | movn w1,#0 //-1 + if (mt->is_unsigned) { + | lcall extern check_uint64 + } else { + | lcall extern check_int64 + } + + goto single; + + case INTPTR_TYPE: + | movn w1,#0 //-1 + | lcall extern check_uintptr + goto single; + + case FLOAT_TYPE: + | movn w1,#0 //-1 + | lcall extern check_float + + | fmov DATA,d0 + | movn w1, #2 // -3 + | lcall extern lua_settop + | fmov d0,DATA + lua_pop(L, 1); + break; + case DOUBLE_TYPE: + | movn w1,#0 //-1 + | lcall extern check_double + + | fmov DATA,d0 + | movn w1, #2 // -3 + | lcall extern lua_settop + | fmov d0,DATA + + lua_pop(L, 1); + break; + + case COMPLEX_DOUBLE_TYPE: + + | movn w1, #0 // -1 + | lcall extern check_complex_double + + goto complex_ret; + case COMPLEX_FLOAT_TYPE: + | movn w1, #0 // -1 + | lcall extern check_complex_float + + complex_ret: + | mov x0,L_ARG + | movn w1, #2 // -3 + | fmov DATA,d0 + | fmov L_ARG,d1 + | bl extern lua_settop + | fmov d0,DATA + | fmov d1,L_ARG + + lua_pop(L, 1); + break; + single: + lua_pop(L, 1); + single_no_pop: + | mov DATA, x0 + | movn w1, #2 // -3 + | lcall extern lua_settop + | mov x0, DATA + break; + + + default: + luaL_error(L, "NYI: callback return type"); + } + } + + | ldp x29,x30,[sp] + | ldp DATA, L_ARG,[sp,#0x10] + | add sp,sp, # (0x20 +ret_by_addr*0x10+ ((regs.floats!=0)||(regs.ints!=0)) * 0x80) + | ret + + lua_pop(L, 1); /* upval table - already in registry */ + assert(lua_gettop(L) == top); + + { + void* p; + struct ctype ft; + cfunction func; + + func = compile(Dst, L, NULL, ref); + + ft = *ct; + ft.is_jitted = 1; + p = push_cdata(L, ct_usr, &ft); + *(cfunction*) p = func; + + assert(lua_gettop(L) == top + 1); + + return func; + } +} + +//arm64 argument can only be in stack or registers. An argument can't be splited between stack and register. +static void store_float(struct jit* Dst,reg_info* regs,int isfloat,int ex){ + if(regs->floats+ex<8){ + + switch(ex){ + case 3: + | stp d2,d3, [sp, #0x10+(regs->floats<<3)] + goto sd_dual; + case 2: + | str d2, [sp, #0x10+(regs->floats<<3)] + case 1: + sd_dual: + | stp d0,d1, [sp, #(regs->floats<<3)] + break; + case 0: + | str d0, [sp, #(regs->floats<<3)] + break; + } + regs->floats+=1+ex; + }else { + regs->floats=8; + switch(ex){ + case 3: + if(isfloat){ + | stp s0,s1, [DATA], #8 + | stp s2,s3, [DATA], #8 + }else{ + | stp d0, d1, [DATA], #16 + | stp d2, d3, [DATA], #16 + } + break; + case 2: + if(isfloat){ + | stp s0,s1, [DATA], #8 + | str s2, [DATA], #8 + }else{ + | stp d0, d1,[DATA], #16 + | str d2, [DATA], #8 + } + break; + case 1: + if(isfloat){ + | stp s0,s1, [DATA], #8 + }else{ + | stp d0, d1,[DATA], #16 + } + break; + case 0: + if(isfloat){ + | str s0, [DATA], #8 + }else { + | str d0, [DATA], #8 + } + break; + } + //complex float is packed as one double on stack + regs->ex+=ex+1; + } +} + +static void store_int(struct jit* Dst,reg_info* regs,int intSize){ + switch(intSize){ + case 1: + if(regs->ints<8) + | str w0, [sp,#0x40+(regs->ints++<<3)] + else + | str w0, [DATA], #(regs->ex++,8) + break; + case 2: + if(regs->ints<8) + | str x0, [sp,#0x40+(regs->ints++<<3)] + else + | str x0, [DATA], #(regs->ex++,8) + break; + case 3: + case 4: + if(regs->ints<7){ + | stp x0,x1, [sp,#0x40+(regs->ints<<3)] + regs->ints+=2; + } + else{ + if(regs->ints==7) + regs->ints=8; + | stp x0,x1, [DATA], #16 + regs->ex+=2; + } + + break; + } +} + +static int caculate_stack(lua_State* L,int ct_usr,int nargs){ + int i;reg_info regs={0,0,0}; + const struct ctype* mt;int stack=0,extra=0; + for (i = 1; i <= nargs; ++i){ + lua_rawgeti(L, ct_usr, i); + mt = (const struct ctype*) lua_touserdata(L, -1); + if (mt->pointers || mt->is_reference) { + if(regs.ints<8)regs.ints++; + else stack++; + }else{ + switch(mt->type){ + case COMPLEX_DOUBLE_TYPE: + case COMPLEX_FLOAT_TYPE: + if(regs.floats<7) + regs.floats+=2; + else if(regs.floats==7) + regs.floats=8; + else stack+=mt->base_size>>3; + break; + case FLOAT_TYPE: + case DOUBLE_TYPE: + if(regs.floats<8) ++regs.floats; + else stack++; + break; + case STRUCT_TYPE:{ + int isfloat; + int hfasize=hfa_size(L,-1,mt,&isfloat); + if(hfasize>0){ + if(regs.floats+hfasize<=8) + regs.floats +=hfasize; + else { + regs.floats=8; + stack+=(hfasize*(2-isfloat)+1)>>1; + } + break; + } + } + case UNION_TYPE:{ + int size=mt->base_size; + size=(size+7)>>3; + if(size>2){//passed by address + if(regs.ints<8)++regs.ints; + else stack++; + extra+=size;//extra copy stack; + break; + } + if(mt->is_empty){ + break; //ignored empty struct + } + if(mt->align_mask>8){ + if(regs.ints&1) regs.ints++; + else if(stack&1) stack++; + } + if(regs.ints+size<=8) regs.ints+=size; + else{ + regs.ints=8; + stack+=size; + } + + break; + } + default: + if(regs.ints<8)++regs.ints;//no need to check type support here + else stack++; + } + } + lua_pop(L,1); + } + + return (regs.ints||regs.floats)?((stack+extra+17/*16 for regs, 1 for align*/)>>1)<<4:0;//2 eightbytes align +} + + +void compile_function(lua_State* L, cfunction func, int ct_usr, const struct ctype* ct) +{ + struct jit* Dst = get_jit(L);; + int i, nargs, num_upvals,ret_by_addr; + const struct ctype* mt; + int stack_size,struct_offset; + void* p; + + int top = lua_gettop(L); + + ct_usr = lua_absindex(L, ct_usr); + nargs = (int) lua_rawlen(L, ct_usr); + + p = push_cdata(L, ct_usr, ct); + *(cfunction*) p = func; + num_upvals = 1; + + dasm_setup(Dst, build_actionlist); + + reg_info regs={0,0}; + + | sub sp,sp,#0x30 + | str L_ARG, [sp,#20] + | stp TOP,DATA,[sp,#0x10] + | stp x29,x30,[sp] + | mov x29,sp + | mov L_ARG,x0 + + /* reserve enough stack space for all of the arguments. */ + stack_size=caculate_stack(L,ct_usr,nargs); + struct_offset=0; + if(stack_size>0){ + if(stack_size>=1<<12){ + | load32 x9, stack_size //trick x9 + | sub sp, sp, x9 + } + else{ + | sub sp, sp, #stack_size + } + if (ct->has_var_arg) { + | bl extern lua_gettop + | cmp w0, #nargs + | bge >1 + | load64 x1, "too few arguments" + | lcall extern luaL_error + |1: + | mov TOP, x0 + | add x0, x0, #1 + | bfm x0,xzr, #0, #0 //round up 2 for stack alignment. + | sub sp, sp, x0, lsl #3 + } + | add DATA,sp,#0x80 + } + + for (i = 1,regs.ints=0,regs.floats=0; i <= nargs; i++) { + lua_rawgeti(L, ct_usr, i); + mt = (const struct ctype*) lua_touserdata(L, -1); + + if (mt->pointers || mt->is_reference || mt->type == FUNCTION_PTR_TYPE || mt->type == ENUM_TYPE||mt->type==STRUCT_TYPE||mt->type==UNION_TYPE) { + lua_getuservalue(L, -1); + num_upvals += 2; + + + | load64 x3,mt + | load32 w2,lua_upvalueindex(num_upvals) + | mov x1,#i + + if (mt->pointers || mt->is_reference) { + | lcall extern check_typed_pointer + } else{ + switch (mt->type) { + case FUNCTION_PTR_TYPE: { + | lcall extern check_typed_cfunction + break; + } + case ENUM_TYPE:{ + | lcall extern check_enum + break; + } + case STRUCT_TYPE: + case UNION_TYPE:{ + if(mt->is_empty) continue; + + int isfloat; + int hfasize=hfa_size(L,-2,mt,&isfloat); + | lcall extern check_struct + if(hfasize>0){ + switch(hfasize){ + case 4: + if(isfloat){ + | ldp s2,s3, [x0,#8] + }else{ + | ldp d2,d3, [x0,#16] + } + goto ld_hfa; + case 3: + if(isfloat){ + | ldr s2, [x0,#8] + }else{ + | ldr d2, [x0,#16] + } + case 2: + ld_hfa: + if(isfloat){ + | ldp s0,s1, [x0] + }else{ + | ldp d0,d1, [x0] + } + break; + case 1: + if(isfloat){ + | ldr s0, [x0] + }else{ + | ldr d0, [x0] + } + break; + + } + store_float(Dst,®s,isfloat,hfasize-1); + continue; + } + if(mt->base_size>16){ + | mov x1 ,x0 + struct_offset+=(mt->base_size+7)&(~7); + if(struct_offset>=1<<12){ + | load32 x0, struct_offset //trick x0 + | sub x0, x29, x0 + } + else{ + | sub x0, x29, #struct_offset + } + store_int(Dst,®s,2); + | mov x2, #mt->base_size + | load64 x9, memcpy + | blr x9 + }else{ + if(mt->align_mask>8){//==15 + if(regs.ints&1) regs.ints++; + else if(regs.ex&1) regs.ex++; + } + int intSize=(mt->base_size+3)>>2; + switch(intSize){ + case 1: + | ldr w0, [x0] + break; + case 2: + | ldr x0, [x0] + break; + case 3: + case 4: + | ldp x0, x1, [x0] + break; + } + store_int(Dst,®s,intSize); + } + continue; + } + } + } + goto longstore; + + } else { + lua_pop(L, 1); + | mov w1, #i + + switch (mt->type) { + case BOOL_TYPE: + | lcall extern check_uint32 + | cmp w0, wzr + | cset w0, ne + goto intstore; + + case INT8_TYPE: + case INT16_TYPE: //arm64 requires callee to narrow the type + case INT32_TYPE: + + | lcall extern check_int32 + + goto intstore; + + case INT64_TYPE: + + | lcall extern check_int64 + + goto longstore; + + case INTPTR_TYPE: + | lcall extern check_uintptr + + goto longstore; + + case DOUBLE_TYPE: + | lcall extern check_double + store_float(Dst,®s,0,0); + break; + + case FLOAT_TYPE: + | lcall extern check_float + store_float(Dst,®s,1,0); + break; + case COMPLEX_DOUBLE_TYPE: + | lcall extern check_complex_double + store_float(Dst,®s,0,1); + break; + + case COMPLEX_FLOAT_TYPE: + | lcall extern check_complex_float + store_float(Dst,®s,1,1); + break; + + intstore: + store_int(Dst,®s,1); + break; + longstore: + store_int(Dst,®s,2); + break; + + default: + luaL_error(L, "NYI: call arg type"); + } + } + } + + if (ct->has_var_arg) { + if(regs.floats<8){ + | add x4, sp ,#regs.floats<<3 + | mov w3, #(8-regs.floats) + | mov x2, TOP + | mov w1, #nargs+1 + | lcall extern unpack_varargs_float + } + if(regs.ints<8){ + | add x4, sp ,#0x40+(regs.ints<<3) + | mov w3, #(8-regs.ints) + | mov x2, TOP + | mov w1, #nargs+1 + | lcall extern unpack_varargs_int + } + |//case when DATA is not allocated, all arg is skipped + | cmp TOP,#(nargs>8?nargs:8) + | ble >1 + | mov x5, DATA + | mov w3, #(8-regs.floats) + | mov w3, #(8-regs.ints) + | mov x2, TOP + | mov w1, #nargs+1 + | lcall extern unpack_varargs_stack_skip + | 1: + regs.floats=regs.ints=8; + } + + lua_rawgeti(L, ct_usr, 0); + mt = (const struct ctype*) lua_touserdata(L, -1); + ret_by_addr=!mt->pointers && !mt->is_reference &&(mt->type==STRUCT_TYPE||mt->type==UNION_TYPE) + && mt->base_size>16&& !(mt->type==STRUCT_TYPE&&hfa_size(L,-1,mt,NULL)!=0); + if(ret_by_addr){ + | load64 x2, mt + | mov x1, #0 + | lcall extern push_cdata + | mov x8, x0 + } + + //pop all args in registers + switch(regs.ints){ + case 8: + case 7: + | ldp x6,x7,[sp,#0x70] + case 6: + case 5: + | ldp x4,x5,[sp,#0x60] + case 4: + case 3: + | ldp x2,x3,[sp,#0x50] + case 2: + case 1: + | ldp x0,x1,[sp,#0x40] + } + + switch(regs.floats){ + case 8: + case 7: + | ldp d6,d7,[sp,#0x30] + case 6: + case 5: + | ldp d4,d5,[sp,#0x20] + case 4: + case 3: + | ldp d2,d3,[sp,#0x10] + case 2: + case 1: + | ldp d0,d1,[sp] + } + if(regs.ints==8|| regs.floats==8){// fix stack case registers is full + | add sp,sp,#0x80 + } + + | load64 x9,func + | blr x9 + + |.macro return + | mov sp, x29 + | ldp x29, x30, [sp] + | ldp TOP, DATA, [sp,#0x10] + | ldr L_ARG, [sp,#0x20] + | add sp, sp, #0x30 + | ret + |.endmacro + + if (mt->pointers || mt->is_reference || mt->type==FUNCTION_PTR_TYPE) { + lua_getuservalue(L, -1); + num_upvals += 2; + | mov DATA, x0 + | load64 x2, mt + | load32 w1, lua_upvalueindex(num_upvals) + | lcall extern push_cdata + | str DATA, [x0] + | mov w0, #1 + | return + + } else { + switch (mt->type) { + case INT64_TYPE: + #if LUA_VERSION_NUM>=503 + lua_pop(L, 1); + | mov x1, x0 + | lcall extern lua_pushinteger + | mov w0, #1 + | return + break; + #endif + + case INTPTR_TYPE: + num_upvals++; + | mov DATA, x0 + | load64 x2, mt + | mov w1, wzr + | lcall extern push_cdata + | str DATA, [x0] + | mov w0, #1 + | return + break; + case VOID_TYPE: + lua_pop(L, 1); + | mov w0, wzr + | return + break; + + case BOOL_TYPE: + lua_pop(L, 1); + | mov w1, w0 + | lcall extern lua_pushboolean + | mov w0, #1 + | return + break; + + case INT8_TYPE:// we need to narrow the value before return + lua_pop(L, 1); + | mov w1, w0 + if (mt->is_unsigned) { + | uxtb w1, w1 + | lcall extern push_uint + } else { + | sxtb w1, w1 + | lcall extern push_int + } + | mov w0, #1 + | return + break; + case INT16_TYPE:// we need to narrow the value before return + lua_pop(L, 1); + | mov w1, w0 + if (mt->is_unsigned) { + | uxth w1, w1 + | lcall extern push_uint + } else { + | sxth w1, w1 + | lcall extern push_int + } + | mov w0, #1 + | return + break; + case INT32_TYPE: + case ENUM_TYPE: + lua_pop(L, 1); + | mov w1, w0 + if (mt->is_unsigned) { + | lcall extern push_uint + } else { + | lcall extern push_int + } + | mov w0, #1 + | return + break; + + case FLOAT_TYPE: + lua_pop(L, 1); + | lcall extern push_float + | mov w0, #1 + | return + break; + + case DOUBLE_TYPE: + lua_pop(L, 1); + | lcall extern lua_pushnumber + | mov w0, #1 + | return + break; + case COMPLEX_FLOAT_TYPE: + lua_getuservalue(L, -1); + num_upvals+=2; + | fmov w0, s0 + | fmov w1, s1 + | orr x0, x0, x1, lsl #32 + | mov DATA, x0 + | load64 x2, mt + | load32 w1, lua_upvalueindex(num_upvals) + | lcall extern push_cdata + | str DATA, [x0] + | mov w0, #1 + | return + break; + + case COMPLEX_DOUBLE_TYPE: + lua_getuservalue(L, -1); + num_upvals+=2; + | fmov TOP, d0 + | fmov DATA, d1 + | load64 x2, mt + | load32 w1, lua_upvalueindex(num_upvals) + | lcall extern push_cdata + | stp TOP,DATA, [x0] + | mov w0, #1 + | return + break; + case STRUCT_TYPE: + case UNION_TYPE: + lua_getuservalue(L, -1); + num_upvals+=2; + if(ret_by_addr){ + if(!lua_isnil(L,-1)){ + | load32 w1, lua_upvalueindex(num_upvals) + | lcall extern lua_pushvalue // lua_pushvalue(L,lua_upvalueindex(num_upvals)) + | movn w1, #1 //-2 + | lcall extern lua_setuservalue // lua_setuservalue(L,-2) + } + | mov w0, #1 + | return + }else if(mt->is_empty){ + | mov w0, #0 + | return + }else{ + int isfloat; + int hfasize=hfa_size(L,-2,mt,&isfloat); + if(hfasize){ + switch(hfasize){ + case 4: + | stp d2, d3, [sp, #-16]! + goto hfs_dual; + case 3: + | str d2, [sp, #-16]! + case 2: + hfs_dual: + | fmov TOP, d1 + case 1: + | fmov DATA, d0 + break; + } + }else{ + if(mt->base_size>8){ + | mov TOP, x1 + } + | mov DATA, x0 + + } + | load64 x2, mt + | load32 w1, lua_upvalueindex(num_upvals) + | lcall extern push_cdata + if(hfasize){ + switch(hfasize){ + case 4: + | ldp d0, d1, [sp], #16 + if(isfloat){ + | stp s0,s1, [x0,#8] + }else{ + | stp d0,d1, [x0,#16] + } + goto hfl_dual; + case 3: + | ldr d0, [sp], #16 + if(isfloat){ + | str s0, [x0,#8] + }else{ + | str d0, [x0,#16] + } + case 2: + hfl_dual: + if(isfloat){ + | fmov d0, TOP + | str s0, [x0,#4] + }else{ + | str TOP, [x0,#8] + } + case 1: + if(isfloat){ + | fmov d0, DATA + | str s0, [x0] + }else{ + | str DATA, [x0] + } + break; + } + }else{ + if(mt->base_size>8){ + | str TOP, [x0, #8] + } + | str DATA, [x0] + + } + | mov w0, #1 + | return + } + break; + + default: + luaL_error(L, "NYI: call return type"); + } + } + + assert(lua_gettop(L) == top + num_upvals); + { + cfunction f = compile(Dst, L, NULL, LUA_NOREF); + /* add a callback as an upval so that the jitted code gets cleaned up when + * the function gets gc'd */ + push_callback(L, f, func); + lua_pushcclosure(L, (lua_CFunction) f, num_upvals+1); + } +} + diff --git a/texk/web2c/luatexdir/luaffi/call_arm64.h b/texk/web2c/luatexdir/luaffi/call_arm64.h new file mode 100644 index 0000000000..aee72759ea --- /dev/null +++ b/texk/web2c/luatexdir/luaffi/call_arm64.h @@ -0,0 +1,2438 @@ +/* +** This file has been pre-processed with DynASM. +** http://luajit.org/dynasm.html +** DynASM version 1.4.0, DynASM arm version 1.4.0 +** DO NOT EDIT! The original file is in "call_arm64.dasc". +*/ + +/* vim: ts=4 sw=4 sts=4 et tw=78 + * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved. + * Portions copyright (c) 2011 James R. McKaskill. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#if DASM_VERSION != 10400 +#error "Version mismatch between DynASM and included encoding engine" +#endif + +static const unsigned int build_actionlist[1117] = { +0xf84003e1, +0x000f0000, +0x00000000, +0xf8400681, +0x000a812c, +0x00000000, +0x6d400fe2, +0x000a8cef, +0x00000000, +0xfc4003e2, +0x000f0000, +0x00000000, +0x6d4007e0, +0x000a8cef, +0x00000000, +0xfc4003e0, +0x000f0000, +0x00000000, +0x2cc10680, +0x2cc10e82, +0x00000000, +0x6cc10680, +0x6cc10e82, +0x00000000, +0x2cc10680, +0xbc408682, +0x00000000, +0x6cc10680, +0xfc408682, +0x00000000, +0x2cc10680, +0x00000000, +0x6cc10680, +0x00000000, +0xbc408680, +0x00000000, +0xfc408680, +0x00000000, +0xf81f0fe8, +0x00000000, +0xd10283ff, +0x00000000, +0xd10083ff, +0x00000000, +0xa9091fe6, +0x00000000, +0xa90817e4, +0x00000000, +0xa9070fe2, +0x00000000, +0xa90607e0, +0x00000000, +0x6d051fe6, +0x00000000, +0x6d0417e4, +0x00000000, +0x6d030fe2, +0x00000000, +0x6d0207e0, +0x00000000, +0xa90157f4, +0xa9007bfd, +0x00000000, +0x910003f4, +0x000c0000, +0x00000000, +0x52800015, +0x000a0205, +0xf2a00015, +0x000a0205, +0xf2c00015, +0x000a0205, +0xf2e00015, +0x000a0205, +0x52800002, +0x000a0205, +0x72a00002, +0x000a0205, +0x52800001, +0x000a0205, +0x72a00001, +0x000a0205, +0xaa1503e0, +0x94000000, +0x00030000, +0x00000000, +0x52800002, +0x000a0205, +0x92800001, +0xaa1503e0, +0x94000000, +0x00030000, +0x00000000, +0x52800002, +0x000a0205, +0x92800001, +0x000a0205, +0xaa1503e0, +0x94000000, +0x00030000, +0x52800002, +0x000a0205, +0xf2a00002, +0x000a0205, +0xf2c00002, +0x000a0205, +0xf2e00002, +0x000a0205, +0x12800001, +0xaa1503e0, +0x94000000, +0x00030001, +0x00000000, +0xf9000001, +0x12800021, +0xaa1503e0, +0x94000000, +0x00030002, +0x00000000, +0x52800002, +0x000a0205, +0x92800001, +0x000a0205, +0xaa1503e0, +0x94000000, +0x00030000, +0x52800002, +0x000a0205, +0xf2a00002, +0x000a0205, +0xf2c00002, +0x000a0205, +0xf2e00002, +0x000a0205, +0x12800001, +0xaa1503e0, +0x94000000, +0x00030001, +0x00000000, +0x2d010c02, +0x00000000, +0x6d010c02, +0x00000000, +0xbd000802, +0x00000000, +0xfd000802, +0x00000000, +0x2d000400, +0x00000000, +0x6d000400, +0x00000000, +0xbd000000, +0x00000000, +0xfd000000, +0x00000000, +0x52800002, +0x000a0205, +0xf2a00002, +0x000a0205, +0xf2c00002, +0x000a0205, +0xf2e00002, +0x000a0205, +0x52800009, +0x000a0205, +0xf2a00009, +0x000a0205, +0xf2c00009, +0x000a0205, +0xf2e00009, +0x000a0205, +0xd63f0120, +0x00000000, +0xa9400be1, +0x000a8cef, +0xa9000801, +0x00000000, +0xf84003e1, +0x000f0000, +0xf9000001, +0x00000000, +0xa8c10a81, +0xa9000801, +0x00000000, +0xf8408681, +0xf9000001, +0x00000000, +0x12800021, +0xaa1503e0, +0x94000000, +0x00030002, +0x00000000, +0x52800002, +0x000a0205, +0x92800001, +0x000a0205, +0xaa1503e0, +0x94000000, +0x00030000, +0x52800002, +0x000a0205, +0xf2a00002, +0x000a0205, +0xf2c00002, +0x000a0205, +0xf2e00002, +0x000a0205, +0x12800001, +0xaa1503e0, +0x94000000, +0x00030001, +0x00000000, +0x6d000400, +0x12800021, +0xaa1503e0, +0x94000000, +0x00030002, +0x00000000, +0x52800002, +0x000a0205, +0x92800001, +0x000a0205, +0xaa1503e0, +0x94000000, +0x00030000, +0x52800002, +0x000a0205, +0xf2a00002, +0x000a0205, +0xf2c00002, +0x000a0205, +0xf2e00002, +0x000a0205, +0x12800001, +0xaa1503e0, +0x94000000, +0x00030001, +0x00000000, +0x2d000400, +0x12800021, +0xaa1503e0, +0x94000000, +0x00030002, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030003, +0x00000000, +0x52800002, +0x000a0205, +0xf2a00002, +0x000a0205, +0xf2c00002, +0x000a0205, +0xf2e00002, +0x000a0205, +0x2a1f03e1, +0xaa1503e0, +0x94000000, +0x00030001, +0x00000000, +0xf9000001, +0x12800021, +0xaa1503e0, +0x94000000, +0x00030002, +0x00000000, +0x52800002, +0x000a0205, +0xf2a00002, +0x000a0205, +0xf2c00002, +0x000a0205, +0xf2e00002, +0x000a0205, +0x2a1f03e1, +0xaa1503e0, +0x94000000, +0x00030001, +0x00000000, +0xf9000001, +0x12800021, +0xaa1503e0, +0x94000000, +0x00030002, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030004, +0x00000000, +0x384003e1, +0x000f0000, +0x00000000, +0x38c003e1, +0x000f0000, +0x00000000, +0x38408681, +0x00000000, +0x38c08681, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030005, +0x00000000, +0x784003e1, +0x000f0000, +0x00000000, +0x78c003e1, +0x000f0000, +0x00000000, +0x78408681, +0x00000000, +0x78c08681, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030005, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030005, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030006, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030007, +0x00000000, +0x52800002, +0x000a0205, +0x52800001, +0x000a0205, +0xaa1503e0, +0x94000000, +0x00030008, +0x00000000, +0x52800002, +0x000a0205, +0x92800021, +0xaa1503e0, +0x94000000, +0x00030000, +0x52800003, +0x000a0205, +0xf2a00003, +0x000a0205, +0xf2c00003, +0x000a0205, +0xf2e00003, +0x000a0205, +0x92800002, +0x92800021, +0xaa1503e0, +0x94000000, +0x00030009, +0x00000000, +0x52800002, +0x000a0205, +0x92800021, +0xaa1503e0, +0x94000000, +0x00030000, +0x52800003, +0x000a0205, +0xf2a00003, +0x000a0205, +0xf2c00003, +0x000a0205, +0xf2e00003, +0x000a0205, +0x92800002, +0x92800021, +0xaa1503e0, +0x94000000, +0x0003000a, +0xaa0003f4, +0x12800041, +0xaa1503e0, +0x94000000, +0x0003000b, +0x00000000, +0x2d410e82, +0x00000000, +0x6d410e82, +0x00000000, +0xbd400a82, +0x00000000, +0xfd400a82, +0x00000000, +0x2d400680, +0x00000000, +0x6d400680, +0x00000000, +0xbd400280, +0x00000000, +0xfd400280, +0x00000000, +0xf84003e0, +0x000f0000, +0xaa1403e1, +0x52800002, +0x000a0205, +0xf2a00002, +0x000a0205, +0xf2c00002, +0x000a0205, +0xf2e00002, +0x000a0205, +0x52800009, +0x000a0205, +0xf2a00009, +0x000a0205, +0xf2c00009, +0x000a0205, +0xf2e00009, +0x000a0205, +0xd63f0120, +0x00000000, +0xa9400680, +0x00000000, +0xf9400280, +0x00000000, +0x52800002, +0x000a0205, +0x92800021, +0xaa1503e0, +0x94000000, +0x00030000, +0x52800003, +0x000a0205, +0xf2a00003, +0x000a0205, +0xf2c00003, +0x000a0205, +0xf2e00003, +0x000a0205, +0x92800002, +0x92800021, +0xaa1503e0, +0x94000000, +0x0003000c, +0x00000000, +0x12800021, +0xaa1503e0, +0x94000000, +0x0003000b, +0x00000000, +0x12800001, +0x00000000, +0xaa1503e0, +0x94000000, +0x0003000d, +0x00000000, +0xaa1503e0, +0x94000000, +0x0003000e, +0x00000000, +0x12800001, +0x00000000, +0xaa1503e0, +0x94000000, +0x0003000f, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030010, +0x00000000, +0x12800001, +0xaa1503e0, +0x94000000, +0x00030011, +0x00000000, +0x12800001, +0xaa1503e0, +0x94000000, +0x00030012, +0x00000000, +0x9e660014, +0x12800041, +0xaa1503e0, +0x94000000, +0x0003000b, +0x9e670280, +0x00000000, +0x12800001, +0xaa1503e0, +0x94000000, +0x00030013, +0x00000000, +0x9e660014, +0x12800041, +0xaa1503e0, +0x94000000, +0x0003000b, +0x9e670280, +0x00000000, +0x12800001, +0xaa1503e0, +0x94000000, +0x00030014, +0x00000000, +0x12800001, +0xaa1503e0, +0x94000000, +0x00030015, +0x00000000, +0xaa1503e0, +0x12800041, +0x9e660014, +0x9e660035, +0x94000000, +0x0003000b, +0x9e670280, +0x9e6702a1, +0x00000000, +0xaa0003f4, +0x12800041, +0xaa1503e0, +0x94000000, +0x0003000b, +0xaa1403e0, +0x00000000, +0xa9407bfd, +0xa94157f4, +0x910003ff, +0x000c0000, +0xd65f03c0, +0x00000000, +0x6d000fe2, +0x000a8cef, +0x00000000, +0xfc0003e2, +0x000f0000, +0x00000000, +0x6d0007e0, +0x000a8cef, +0x00000000, +0xfc0003e0, +0x000f0000, +0x00000000, +0x2c810680, +0x2c810e82, +0x00000000, +0x6c810680, +0x6c810e82, +0x00000000, +0x2c810680, +0xbc008682, +0x00000000, +0x6c810680, +0xfc008682, +0x00000000, +0x2c810680, +0x00000000, +0x6c810680, +0x00000000, +0xbc008680, +0x00000000, +0xfc008680, +0x00000000, +0xb80003e0, +0x000f0000, +0x00000000, +0xb8000680, +0x000a812c, +0x00000000, +0xf80003e0, +0x000f0000, +0x00000000, +0xf8000680, +0x000a812c, +0x00000000, +0xa90007e0, +0x000a8cef, +0x00000000, +0xa8810680, +0x00000000, +0xd100c3ff, +0xf80143f5, +0xa90153f3, +0xa9007bfd, +0x910003fd, +0xaa0003f5, +0x00000000, +0x52800009, +0x000a0205, +0xf2a00009, +0x000a0205, +0xcb2963ff, +0x00000000, +0xd10003ff, +0x000c0000, +0x00000000, +0x94000000, +0x00030016, +0x7100001f, +0x000c0000, +0x5400000a, +0x00050801, +0x52800001, +0x000a0205, +0xf2a00001, +0x000a0205, +0xf2c00001, +0x000a0205, +0xf2e00001, +0x000a0205, +0xaa1503e0, +0x94000000, +0x00030017, +0x0006000b, +0xaa0003f3, +0x91000400, +0xb34003e0, +0xcb206fff, +0x00000000, +0x910203f4, +0x00000000, +0x52800003, +0x000a0205, +0xf2a00003, +0x000a0205, +0xf2c00003, +0x000a0205, +0xf2e00003, +0x000a0205, +0x52800002, +0x000a0205, +0x72a00002, +0x000a0205, +0x52800001, +0x000a0205, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030009, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030018, +0x00000000, +0xaa1503e0, +0x94000000, +0x0003000c, +0x00000000, +0xaa1503e0, +0x94000000, +0x0003000a, +0x00000000, +0x2d410c02, +0x00000000, +0x6d410c02, +0x00000000, +0xbd400802, +0x00000000, +0xfd400802, +0x00000000, +0x2d400400, +0x00000000, +0x6d400400, +0x00000000, +0xbd400000, +0x00000000, +0xfd400000, +0x00000000, +0xaa0003e1, +0x00000000, +0x52800000, +0x000a0205, +0xf2a00000, +0x000a0205, +0xcb0003a0, +0x00000000, +0xd10003a0, +0x000c0000, +0x00000000, +0x52800002, +0x000a0205, +0x52800009, +0x000a0205, +0xf2a00009, +0x000a0205, +0xf2c00009, +0x000a0205, +0xf2e00009, +0x000a0205, +0xd63f0120, +0x00000000, +0xb9400000, +0x00000000, +0xf9400000, +0x00000000, +0xa9400400, +0x00000000, +0x52800001, +0x000a0205, +0x00000000, +0xaa1503e0, +0x94000000, +0x0003000d, +0x6b1f001f, +0x1a9f07e0, +0x00000000, +0xaa1503e0, +0x94000000, +0x0003000e, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030010, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030011, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030013, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030012, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030014, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030015, +0x00000000, +0x910003e4, +0x000c0000, +0x52800003, +0x000a0205, +0xaa1303e2, +0x52800001, +0x000a0205, +0xaa1503e0, +0x94000000, +0x00030019, +0x00000000, +0x910003e4, +0x000c0000, +0x52800003, +0x000a0205, +0xaa1303e2, +0x52800001, +0x000a0205, +0xaa1503e0, +0x94000000, +0x0003001a, +0x00000000, +0xf100027f, +0x000c0000, +0x5400000d, +0x00050801, +0xaa1403e5, +0x52800003, +0x000a0205, +0x52800003, +0x000a0205, +0xaa1303e2, +0x52800001, +0x000a0205, +0xaa1503e0, +0x94000000, +0x0003001b, +0x0006000b, +0x00000000, +0x52800002, +0x000a0205, +0xf2a00002, +0x000a0205, +0xf2c00002, +0x000a0205, +0xf2e00002, +0x000a0205, +0x52800001, +0xaa1503e0, +0x94000000, +0x00030001, +0xaa0003e8, +0x00000000, +0xa9471fe6, +0x00000000, +0xa94617e4, +0x00000000, +0xa9450fe2, +0x00000000, +0xa94407e0, +0x00000000, +0x6d431fe6, +0x00000000, +0x6d4217e4, +0x00000000, +0x6d410fe2, +0x00000000, +0x6d4007e0, +0x00000000, +0x910203ff, +0x00000000, +0x52800009, +0x000a0205, +0xf2a00009, +0x000a0205, +0xf2c00009, +0x000a0205, +0xf2e00009, +0x000a0205, +0xd63f0120, +0x00000000, +0xaa0003f4, +0x52800002, +0x000a0205, +0xf2a00002, +0x000a0205, +0xf2c00002, +0x000a0205, +0xf2e00002, +0x000a0205, +0x52800001, +0x000a0205, +0x72a00001, +0x000a0205, +0xaa1503e0, +0x94000000, +0x00030001, +0xf9000014, +0x52800020, +0x910003bf, +0xa9407bfd, +0xa94153f3, +0xf94013f5, +0x9100c3ff, +0xd65f03c0, +0x00000000, +0xaa0003e1, +0xaa1503e0, +0x94000000, +0x00030003, +0x52800020, +0x910003bf, +0xa9407bfd, +0xa94153f3, +0xf94013f5, +0x9100c3ff, +0xd65f03c0, +0x00000000, +0xaa0003f4, +0x52800002, +0x000a0205, +0xf2a00002, +0x000a0205, +0xf2c00002, +0x000a0205, +0xf2e00002, +0x000a0205, +0x2a1f03e1, +0xaa1503e0, +0x94000000, +0x00030001, +0xf9000014, +0x52800020, +0x910003bf, +0xa9407bfd, +0xa94153f3, +0xf94013f5, +0x9100c3ff, +0xd65f03c0, +0x00000000, +0x2a1f03e0, +0x910003bf, +0xa9407bfd, +0xa94153f3, +0xf94013f5, +0x9100c3ff, +0xd65f03c0, +0x00000000, +0x2a0003e1, +0xaa1503e0, +0x94000000, +0x00030004, +0x52800020, +0x910003bf, +0xa9407bfd, +0xa94153f3, +0xf94013f5, +0x9100c3ff, +0xd65f03c0, +0x00000000, +0x2a0003e1, +0x00000000, +0x53001c21, +0xaa1503e0, +0x94000000, +0x0003001c, +0x00000000, +0x13001c21, +0xaa1503e0, +0x94000000, +0x00030005, +0x00000000, +0x52800020, +0x910003bf, +0xa9407bfd, +0xa94153f3, +0xf94013f5, +0x9100c3ff, +0xd65f03c0, +0x00000000, +0x2a0003e1, +0x00000000, +0x53003c21, +0xaa1503e0, +0x94000000, +0x0003001c, +0x00000000, +0x13003c21, +0xaa1503e0, +0x94000000, +0x00030005, +0x00000000, +0x52800020, +0x910003bf, +0xa9407bfd, +0xa94153f3, +0xf94013f5, +0x9100c3ff, +0xd65f03c0, +0x00000000, +0x2a0003e1, +0x00000000, +0xaa1503e0, +0x94000000, +0x0003001c, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030005, +0x00000000, +0x52800020, +0x910003bf, +0xa9407bfd, +0xa94153f3, +0xf94013f5, +0x9100c3ff, +0xd65f03c0, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030006, +0x52800020, +0x910003bf, +0xa9407bfd, +0xa94153f3, +0xf94013f5, +0x9100c3ff, +0xd65f03c0, +0x00000000, +0xaa1503e0, +0x94000000, +0x00030007, +0x52800020, +0x910003bf, +0xa9407bfd, +0xa94153f3, +0xf94013f5, +0x9100c3ff, +0xd65f03c0, +0x00000000, +0x1e260000, +0x1e260021, +0xaa018000, +0xaa0003f4, +0x52800002, +0x000a0205, +0xf2a00002, +0x000a0205, +0xf2c00002, +0x000a0205, +0xf2e00002, +0x000a0205, +0x52800001, +0x000a0205, +0x72a00001, +0x000a0205, +0xaa1503e0, +0x94000000, +0x00030001, +0xf9000014, +0x52800020, +0x910003bf, +0xa9407bfd, +0xa94153f3, +0xf94013f5, +0x9100c3ff, +0xd65f03c0, +0x00000000, +0x9e660013, +0x9e660034, +0x52800002, +0x000a0205, +0xf2a00002, +0x000a0205, +0xf2c00002, +0x000a0205, +0xf2e00002, +0x000a0205, +0x52800001, +0x000a0205, +0x72a00001, +0x000a0205, +0xaa1503e0, +0x94000000, +0x00030001, +0xa9005013, +0x52800020, +0x910003bf, +0xa9407bfd, +0xa94153f3, +0xf94013f5, +0x9100c3ff, +0xd65f03c0, +0x00000000, +0x52800001, +0x000a0205, +0x72a00001, +0x000a0205, +0xaa1503e0, +0x94000000, +0x0003001d, +0x12800021, +0xaa1503e0, +0x94000000, +0x0003001e, +0x00000000, +0x52800020, +0x910003bf, +0xa9407bfd, +0xa94153f3, +0xf94013f5, +0x9100c3ff, +0xd65f03c0, +0x00000000, +0x52800000, +0x910003bf, +0xa9407bfd, +0xa94153f3, +0xf94013f5, +0x9100c3ff, +0xd65f03c0, +0x00000000, +0x6dbf0fe2, +0x00000000, +0xfc1f0fe2, +0x00000000, +0x9e660033, +0x00000000, +0x9e660014, +0x00000000, +0xaa0103f3, +0x00000000, +0xaa0003f4, +0x00000000, +0x52800002, +0x000a0205, +0xf2a00002, +0x000a0205, +0xf2c00002, +0x000a0205, +0xf2e00002, +0x000a0205, +0x52800001, +0x000a0205, +0x72a00001, +0x000a0205, +0xaa1503e0, +0x94000000, +0x00030001, +0x00000000, +0x6cc107e0, +0x00000000, +0x2d010400, +0x00000000, +0x6d010400, +0x00000000, +0xfc4107e0, +0x00000000, +0xbd000800, +0x00000000, +0xfd000800, +0x00000000, +0x9e670260, +0xbd000400, +0x00000000, +0xf9000413, +0x00000000, +0x9e670280, +0xbd000000, +0x00000000, +0xf9000014, +0x00000000, +0xf9000413, +0x00000000, +0xf9000014, +0x00000000, +0x52800020, +0x910003bf, +0xa9407bfd, +0xa94153f3, +0xf94013f5, +0x9100c3ff, +0xd65f03c0, +0x00000000 +}; + +static const char *const globnames[] = { + (const char *)0 +}; +static const char *const extnames[] = { + "rawgeti", + "push_cdata", + "lua_remove", + "lua_pushinteger", + "lua_pushboolean", + "push_int", + "push_float", + "lua_pushnumber", + "lua_call", + "check_typed_pointer", + "check_struct", + "lua_settop", + "check_enum", + "check_uint32", + "check_int32", + "check_uint64", + "check_int64", + "check_uintptr", + "check_float", + "check_double", + "check_complex_double", + "check_complex_float", + "lua_gettop", + "luaL_error", + "check_typed_cfunction", + "unpack_varargs_float", + "unpack_varargs_int", + "unpack_varargs_stack_skip", + "push_uint", + "lua_pushvalue", + "lua_setuservalue", + (const char *)0 +}; + +#define JUMP_SIZE 16 + +//in aarch64 the pc is indicated the current +#define MIN_BRANCH ((INT32_MIN) >> 6) +#define MAX_BRANCH ((INT32_MAX) >> 6) +//arm64 pc has no offset so comparing with next instruction is -4 +#define BRANCH_OFF -4 +#define ROUND_UP(x, align) (((int) (x) + (align - 1)) & ~(align - 1)) + +static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, uint8_t* code) +{ + /* The jump code is the function pointer followed by a stub to call the + * function pointer. The stub exists so we can jump to functions with an + * offset greater than 128MB. + * + * Note we have to manually set this up since there are commands buffered + * in the jit state. + */ + + //l: ptr + *(cfunction*) code = func; + // ldr x9,#-8 + *(uint32_t*) &code[8] = 0x58FFFFC9; + //br x9 + *(uint32_t*) &code[12] = 0xD61F0120; + +} + +//| ldr reg, >5 +//| b >6 +//|5: +//|.long64 val +//|6: + + + +void compile_globals(struct jit* jit, lua_State* L) +{ + (void) jit; +} +typedef struct reg_info{ + uint8_t ints; + uint8_t floats; + uint16_t ex; +} reg_info; + +static ALWAYS_INLINE bool is_float_type(int t){ + return t==FLOAT_TYPE||t==DOUBLE_TYPE; +} + +static int hfa_size(lua_State* L,int idx, const struct ctype* ct,int* isfloat){ + struct ctype* mt; + int type,ele_count,i,ct_usr; + lua_getuservalue(L,idx); + ct_usr=lua_absindex(L,-1); + lua_rawgeti(L,ct_usr,1); + mt=(struct ctype*)lua_touserdata(L,-1); + if(mt==NULL||(mt->pointers&&!mt->is_array)||mt->is_reference||!is_float_type(mt->type)){ + lua_pop(L,2); + return 0; + } + type=mt->type; + ele_count=(int)(ct->base_size/mt->base_size); + if(ele_count>4||ct->base_size%mt->base_size){ + lua_pop(L,2); + return 0; + } + lua_pop(L,1); + for (i = 2;i<=4; ++i) { + lua_rawgeti(L,ct_usr,i); + if(lua_isnil(L,-1)){//case have array member; + lua_pop(L,1); + break; + } + mt=(struct ctype*)lua_touserdata(L,-1); + if(mt->type!=type||(mt->pointers&&!mt->is_array)||mt->is_reference||!is_float_type(mt->type)){ + lua_pop(L,2); + return 0; + } + lua_pop(L,1); + } + if(isfloat){ + *isfloat=mt->type==FLOAT_TYPE; + } + lua_pop(L,1); + return ele_count; +} + +static reg_info caculate_regs(lua_State* L,int ct_usr,int nargs){ + int i;reg_info regs; + const struct ctype* mt; + for (i = 1,regs.ints=0,regs.floats=0; i <= nargs&&(regs.floats<8||regs.ints<8); ++i){ + lua_rawgeti(L, ct_usr, i); + mt = (const struct ctype*) lua_touserdata(L, -1); + if (mt->pointers || mt->is_reference) { + if(regs.ints<8)regs.ints++; + }else{ + switch(mt->type){ + case COMPLEX_DOUBLE_TYPE: + case COMPLEX_FLOAT_TYPE: + if(regs.floats<7) + regs.floats+=2; + else if(regs.floats==7) + regs.floats=8; + break; + case FLOAT_TYPE: + case DOUBLE_TYPE: + if(regs.floats<8) ++regs.floats; + break; + case STRUCT_TYPE:{ + int hfasize=hfa_size(L,-1,mt,NULL); + if(hfasize>0){ + regs.floats+=hfasize; + if(regs.floats>8) + regs.floats=8; + break; + } + } + case UNION_TYPE:{ + int size=mt->base_size; + if(size>16){//passed by address + if(regs.ints<8)++regs.ints; + break; + } + if(mt->is_empty){ + break; //ignored empty struct + } + size=(size+7)>>3; + if(regs.ints+size<=8) regs.ints+=size; + break; + } + default: + if(regs.ints<8)++regs.ints;//no need to check type support here + } + } + lua_pop(L,1); + } + + return regs; +} + +// arm store/load range for immediate value is only -256-255 +static ALWAYS_INLINE void load_int(struct jit* Dst,reg_info* regs){ + if(regs->ints<8) + dasm_put(Dst, 0, 0x60+(regs->ints++<<3)); + else + dasm_put(Dst, 3, (regs->ex++,8)); +} + +static void load_float(struct jit* Dst,reg_info* regs,int isfloat,int exSize){ + if(regs->floats+exSize<8){ + switch(exSize){ + case 3: + dasm_put(Dst, 6, 0x30+(regs->floats<<3)); + goto l_dual; + case 2: + dasm_put(Dst, 9, 0x30+(regs->floats<<3)); + case 1: + l_dual: + dasm_put(Dst, 12, 0x20+(regs->floats<<3)); + break; + case 0: + dasm_put(Dst, 15, 0x20+(regs->floats<<3)); + break; + } + regs->floats+=exSize+1; + + }else{ + regs->floats=8; + regs->ex+=exSize+1; + switch(exSize){ + case 3: + if(isfloat){ + dasm_put(Dst, 18); + }else{ + dasm_put(Dst, 21); + } + break; + case 2: + if(isfloat){ //12 bytes rounded to 16 + dasm_put(Dst, 24); + break; + }else { + dasm_put(Dst, 27); + } + break; + case 1: + if(isfloat){ + dasm_put(Dst, 30); + }else{ + dasm_put(Dst, 32); + } + break; + case 0: + if(isfloat){ + dasm_put(Dst, 34); + }else { + dasm_put(Dst, 36); + } + break; + } + + } +} + +cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctype* ct) +{ + struct jit* Dst = get_jit(L);; + int i, nargs, num_upvals, ref,ret_by_addr; + const struct ctype* mt; + + int top = lua_gettop(L); + + ct_usr = lua_absindex(L, ct_usr); + fidx = lua_absindex(L, fidx); + nargs = (int) lua_rawlen(L, ct_usr); + + dasm_setup(Dst, build_actionlist); + + lua_newtable(L); + lua_pushvalue(L, -1); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + num_upvals = 0; + + if (ct->has_var_arg) { + luaL_error(L, "can't create callbacks with varargs"); + } + + lua_rawgeti(L, ct_usr, 0); + mt = (const struct ctype*) lua_touserdata(L, -1); + ret_by_addr=!mt->pointers && !mt->is_reference &&(mt->type==STRUCT_TYPE||mt->type==UNION_TYPE) + && mt->base_size>16&& !(mt->type==STRUCT_TYPE&&hfa_size(L,-1,mt,NULL)!=0); + if(ret_by_addr){ + dasm_put(Dst, 38); + } + lua_pop(L,1); + reg_info regs=caculate_regs(L,ct_usr,nargs); + + if(regs.ints||regs.floats){ + dasm_put(Dst, 40); + }else{ + dasm_put(Dst, 42); + } + //8 integer reigsters and 8 floating registers + switch(regs.ints){ + case 8: + case 7: + dasm_put(Dst, 44); + case 6: + case 5: + dasm_put(Dst, 46); + case 4: + case 3: + dasm_put(Dst, 48); + case 2: + case 1: + dasm_put(Dst, 50); + } + + switch(regs.floats){ + case 8: + case 7: + dasm_put(Dst, 52); + case 6: + case 5: + dasm_put(Dst, 54); + case 4: + case 3: + dasm_put(Dst, 56); + case 2: + case 1: + dasm_put(Dst, 58); + } + dasm_put(Dst, 60); + + if(regs.ints==8||regs.floats==8){ // may be overflowed if it's full + dasm_put(Dst, 63, 0xa0+ret_by_addr*0x10); + } + + /* get the lua function */ + lua_pushvalue(L, fidx); + lua_rawseti(L, -2, ++num_upvals); + + dasm_put(Dst, 66, (unsigned short)(L), (((unsigned int)(L))>>16), (unsigned short)((unsigned long)(L)>>32), (unsigned short)((unsigned long)(L)>>48), (unsigned short)(ref), (((unsigned int)(ref))>>16), (unsigned short)(LUA_REGISTRYINDEX), (((unsigned int)(LUA_REGISTRYINDEX))>>16)); + + dasm_put(Dst, 86, num_upvals); + + + for (i = 1,regs.ints=0,regs.floats=0; i <= nargs; ++i) { + lua_rawgeti(L, ct_usr, i); + mt = (const struct ctype*) lua_touserdata(L, -1); + + if (mt->pointers || mt->is_reference) { + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + dasm_put(Dst, 93, num_upvals-1, i, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)((unsigned long)(mt)>>32), (unsigned short)((unsigned long)(mt)>>48)); + load_int(Dst,®s); + dasm_put(Dst, 113); + + } else { + switch (mt->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ + int isfloat,hfasize=0; + if(mt->type!=UNION_TYPE){ + hfasize=hfa_size(L,-1,mt,&isfloat); + } + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + dasm_put(Dst, 119, num_upvals-1, i, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)((unsigned long)(mt)>>32), (unsigned short)((unsigned long)(mt)>>48)); + + if(hfasize){ + load_float(Dst,®s,isfloat,hfasize-1); + switch(hfasize){ + case 4: + if(isfloat){ + dasm_put(Dst, 139); + }else{ + dasm_put(Dst, 141); + } + goto hfa2; + case 3: + if(isfloat){ + dasm_put(Dst, 143); + }else{ + dasm_put(Dst, 145); + } + case 2: + hfa2: + if(isfloat){ + dasm_put(Dst, 147); + }else{ + dasm_put(Dst, 149); + } + break; + case 1: + if(isfloat){ + dasm_put(Dst, 151); + }else{ + dasm_put(Dst, 153); + } + break; + + } + }else if(!mt->is_empty){ + size_t size=mt->base_size; + if(size>16){ + load_int(Dst,®s); + dasm_put(Dst, 155, (unsigned short)(mt->base_size), (((unsigned int)(mt->base_size))>>16), (unsigned short)((unsigned long)(mt->base_size)>>32), (unsigned short)((unsigned long)(mt->base_size)>>48), (unsigned short)(memcpy), (((unsigned int)(memcpy))>>16), (unsigned short)((unsigned long)(memcpy)>>32), (unsigned short)((unsigned long)(memcpy)>>48)); + }else{ + size=(size+7)>>3; + if(mt->align_mask>8){ + if(regs.ints&1) regs.ints++; + else if(regs.ex&1) regs.ex++; + } + if(regs.ints+size<=8){ + if(size>1){ + dasm_put(Dst, 173, 0x60+(regs.ints<<3)); + }else{ + dasm_put(Dst, 177, 0x60+(regs.ints<<3)); + } + regs.ints+=size; + }else{ + regs.ints=8; + if(size>1){ + dasm_put(Dst, 181); + }else{ + dasm_put(Dst, 184); + } + + } + } + + + } + + dasm_put(Dst, 187); + break; + } + case COMPLEX_DOUBLE_TYPE: + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + dasm_put(Dst, 192, num_upvals-1, i, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)((unsigned long)(mt)>>32), (unsigned short)((unsigned long)(mt)>>48)); + load_float(Dst,®s,0,1); + dasm_put(Dst, 212); + + break; + case COMPLEX_FLOAT_TYPE: + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + dasm_put(Dst, 218, num_upvals-1, i, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)((unsigned long)(mt)>>32), (unsigned short)((unsigned long)(mt)>>48)); + load_float(Dst,®s,1,1); + dasm_put(Dst, 238); + + break; + case INT64_TYPE: + #if LUA_VERSION_NUM>=503 + lua_pop(L, 1); + load_int(Dst,®s); + dasm_put(Dst, 244); + + #else + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + dasm_put(Dst, 248, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)((unsigned long)(mt)>>32), (unsigned short)((unsigned long)(mt)>>48)); + load_int(Dst,®s); + dasm_put(Dst, 261); + + #endif + break; + + case INTPTR_TYPE: + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + dasm_put(Dst, 267, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)((unsigned long)(mt)>>32), (unsigned short)((unsigned long)(mt)>>48)); + load_int(Dst,®s); + dasm_put(Dst, 280); + + break; + + case BOOL_TYPE: + lua_pop(L, 1); + + load_int(Dst,®s); + dasm_put(Dst, 286); + + break; + + case INT8_TYPE:// need to narrow for caller doesn't do it + lua_pop(L, 1); + if(regs.ints<8){ + if (mt->is_unsigned) { + dasm_put(Dst, 290, 0x60+(regs.ints++<<3)); + } else { + dasm_put(Dst, 293, 0x60+(regs.ints++<<3)); + } + }else { + if (mt->is_unsigned) { + dasm_put(Dst, 296); + } else { + dasm_put(Dst, 298); + } + } + dasm_put(Dst, 300); + break; + + case INT16_TYPE:// need to narrow for caller doesn't do it + lua_pop(L, 1); + if(regs.ints<8){ + if (mt->is_unsigned) { + dasm_put(Dst, 304, 0x60+(regs.ints++<<3)); + } else { + dasm_put(Dst, 307, 0x60+(regs.ints++<<3)); + } + }else { + if (mt->is_unsigned) { + dasm_put(Dst, 310); + } else { + dasm_put(Dst, 312); + } + } + dasm_put(Dst, 314); + break; + + case ENUM_TYPE: + case INT32_TYPE: + lua_pop(L, 1); + load_int(Dst,®s); + + dasm_put(Dst, 318); + break; + + case FLOAT_TYPE: + lua_pop(L, 1); + load_float(Dst,®s,1,0); + dasm_put(Dst, 322); + break; + + case DOUBLE_TYPE: + lua_pop(L, 1); + load_float(Dst,®s,0,0); + dasm_put(Dst, 326); + break; + default: + luaL_error(L, "NYI: callback arg type"); + } + } + } + + lua_rawgeti(L, ct_usr, 0); + mt = (const struct ctype*) lua_touserdata(L, -1); + + dasm_put(Dst, 330, ((mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0), nargs); + + + + if (mt->pointers || mt->is_reference) { + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + dasm_put(Dst, 338, num_upvals-1, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)((unsigned long)(mt)>>32), (unsigned short)((unsigned long)(mt)>>48)); + goto single_no_pop; + } else { + switch (mt->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ + int hfasize=0,isfloat; + if(mt->type!=UNION_TYPE){ + hfasize=hfa_size(L,-1,mt,&isfloat); + } + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + dasm_put(Dst, 358, num_upvals-1, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)((unsigned long)(mt)>>32), (unsigned short)((unsigned long)(mt)>>48)); + if(hfasize){ + switch(hfasize){ + case 4: + if(isfloat){ + dasm_put(Dst, 383); + }else{ + dasm_put(Dst, 385); + } + goto ld_hfa; + case 3: + if(isfloat){ + dasm_put(Dst, 387); + }else{ + dasm_put(Dst, 389); + } + case 2: + ld_hfa: + if(isfloat){ + dasm_put(Dst, 391); + }else{ + dasm_put(Dst, 393); + } + break; + case 1: + if(isfloat){ + dasm_put(Dst, 395); + }else{ + dasm_put(Dst, 397); + } + break; + } + }else{ + if(mt->base_size>16){ + dasm_put(Dst, 399, 0x20+((regs.ints||regs.floats)?0x80:0), (unsigned short)(mt->base_size), (((unsigned int)(mt->base_size))>>16), (unsigned short)((unsigned long)(mt->base_size)>>32), (unsigned short)((unsigned long)(mt->base_size)>>48), (unsigned short)(memcpy), (((unsigned int)(memcpy))>>16), (unsigned short)((unsigned long)(memcpy)>>32), (unsigned short)((unsigned long)(memcpy)>>48)); + }else{ + if(mt->base_size>8){ + dasm_put(Dst, 420); + }else{ + dasm_put(Dst, 422); + } + } + } + break; + } + case ENUM_TYPE: + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + dasm_put(Dst, 424, num_upvals-1, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)((unsigned long)(mt)>>32), (unsigned short)((unsigned long)(mt)>>48)); + + goto single_no_pop; + + case VOID_TYPE: + dasm_put(Dst, 444); + lua_pop(L, 1); + break; + + case BOOL_TYPE: + case INT8_TYPE: + case INT16_TYPE: + case INT32_TYPE: //caller's responsiblity to narrow + dasm_put(Dst, 449); + if (mt->is_unsigned) { + dasm_put(Dst, 451); + } else { + dasm_put(Dst, 455); + } + + goto single; + + case INT64_TYPE: + dasm_put(Dst, 459); + if (mt->is_unsigned) { + dasm_put(Dst, 461); + } else { + dasm_put(Dst, 465); + } + + goto single; + + case INTPTR_TYPE: + dasm_put(Dst, 469); + goto single; + + case FLOAT_TYPE: + dasm_put(Dst, 474); + + dasm_put(Dst, 479); + lua_pop(L, 1); + break; + case DOUBLE_TYPE: + dasm_put(Dst, 486); + + dasm_put(Dst, 491); + + lua_pop(L, 1); + break; + + case COMPLEX_DOUBLE_TYPE: + + dasm_put(Dst, 498); + + goto complex_ret; + case COMPLEX_FLOAT_TYPE: + dasm_put(Dst, 503); + + complex_ret: + dasm_put(Dst, 508); + + lua_pop(L, 1); + break; + single: + lua_pop(L, 1); + single_no_pop: + dasm_put(Dst, 517); + break; + + + default: + luaL_error(L, "NYI: callback return type"); + } + } + + dasm_put(Dst, 524, (0x20 +ret_by_addr*0x10+ ((regs.floats!=0)||(regs.ints!=0)) * 0x80)); + + lua_pop(L, 1); /* upval table - already in registry */ + assert(lua_gettop(L) == top); + + { + void* p; + struct ctype ft; + cfunction func; + + func = compile(Dst, L, NULL, ref); + + ft = *ct; + ft.is_jitted = 1; + p = push_cdata(L, ct_usr, &ft); + *(cfunction*) p = func; + + assert(lua_gettop(L) == top + 1); + + return func; + } +} + +//arm64 argument can only be in stack or registers. An argument can't be splited between stack and register. +static void store_float(struct jit* Dst,reg_info* regs,int isfloat,int ex){ + if(regs->floats+ex<8){ + + switch(ex){ + case 3: + dasm_put(Dst, 530, 0x10+(regs->floats<<3)); + goto sd_dual; + case 2: + dasm_put(Dst, 533, 0x10+(regs->floats<<3)); + case 1: + sd_dual: + dasm_put(Dst, 536, (regs->floats<<3)); + break; + case 0: + dasm_put(Dst, 539, (regs->floats<<3)); + break; + } + regs->floats+=1+ex; + }else { + regs->floats=8; + switch(ex){ + case 3: + if(isfloat){ + dasm_put(Dst, 542); + }else{ + dasm_put(Dst, 545); + } + break; + case 2: + if(isfloat){ + dasm_put(Dst, 548); + }else{ + dasm_put(Dst, 551); + } + break; + case 1: + if(isfloat){ + dasm_put(Dst, 554); + }else{ + dasm_put(Dst, 556); + } + break; + case 0: + if(isfloat){ + dasm_put(Dst, 558); + }else { + dasm_put(Dst, 560); + } + break; + } + //complex float is packed as one double on stack + regs->ex+=ex+1; + } +} + +static void store_int(struct jit* Dst,reg_info* regs,int intSize){ + switch(intSize){ + case 1: + if(regs->ints<8) + dasm_put(Dst, 562, 0x40+(regs->ints++<<3)); + else + dasm_put(Dst, 565, (regs->ex++,8)); + break; + case 2: + if(regs->ints<8) + dasm_put(Dst, 568, 0x40+(regs->ints++<<3)); + else + dasm_put(Dst, 571, (regs->ex++,8)); + break; + case 3: + case 4: + if(regs->ints<7){ + dasm_put(Dst, 574, 0x40+(regs->ints<<3)); + regs->ints+=2; + } + else{ + if(regs->ints==7) + regs->ints=8; + dasm_put(Dst, 577); + regs->ex+=2; + } + + break; + } +} + +static int caculate_stack(lua_State* L,int ct_usr,int nargs){ + int i;reg_info regs={0,0,0}; + const struct ctype* mt;int stack=0,extra=0; + for (i = 1; i <= nargs; ++i){ + lua_rawgeti(L, ct_usr, i); + mt = (const struct ctype*) lua_touserdata(L, -1); + if (mt->pointers || mt->is_reference) { + if(regs.ints<8)regs.ints++; + else stack++; + }else{ + switch(mt->type){ + case COMPLEX_DOUBLE_TYPE: + case COMPLEX_FLOAT_TYPE: + if(regs.floats<7) + regs.floats+=2; + else if(regs.floats==7) + regs.floats=8; + else stack+=mt->base_size>>3; + break; + case FLOAT_TYPE: + case DOUBLE_TYPE: + if(regs.floats<8) ++regs.floats; + else stack++; + break; + case STRUCT_TYPE:{ + int isfloat; + int hfasize=hfa_size(L,-1,mt,&isfloat); + if(hfasize>0){ + if(regs.floats+hfasize<=8) + regs.floats +=hfasize; + else { + regs.floats=8; + stack+=(hfasize*(2-isfloat)+1)>>1; + } + break; + } + } + case UNION_TYPE:{ + int size=mt->base_size; + size=(size+7)>>3; + if(size>2){//passed by address + if(regs.ints<8)++regs.ints; + else stack++; + extra+=size;//extra copy stack; + break; + } + if(mt->is_empty){ + break; //ignored empty struct + } + if(mt->align_mask>8){ + if(regs.ints&1) regs.ints++; + else if(stack&1) stack++; + } + if(regs.ints+size<=8) regs.ints+=size; + else{ + regs.ints=8; + stack+=size; + } + + break; + } + default: + if(regs.ints<8)++regs.ints;//no need to check type support here + else stack++; + } + } + lua_pop(L,1); + } + + return (regs.ints||regs.floats)?((stack+extra+17/*16 for regs, 1 for align*/)>>1)<<4:0;//2 eightbytes align +} + + +void compile_function(lua_State* L, cfunction func, int ct_usr, const struct ctype* ct) +{ + struct jit* Dst = get_jit(L);; + int i, nargs, num_upvals,ret_by_addr; + const struct ctype* mt; + int stack_size,struct_offset; + void* p; + + int top = lua_gettop(L); + + ct_usr = lua_absindex(L, ct_usr); + nargs = (int) lua_rawlen(L, ct_usr); + + p = push_cdata(L, ct_usr, ct); + *(cfunction*) p = func; + num_upvals = 1; + + dasm_setup(Dst, build_actionlist); + + reg_info regs={0,0}; + + dasm_put(Dst, 579); + + /* reserve enough stack space for all of the arguments. */ + stack_size=caculate_stack(L,ct_usr,nargs); + struct_offset=0; + if(stack_size>0){ + if(stack_size>=1<<12){ + dasm_put(Dst, 586, (unsigned short)(stack_size), (((unsigned int)(stack_size))>>16)); + } + else{ + dasm_put(Dst, 592, stack_size); + } + if (ct->has_var_arg) { + dasm_put(Dst, 595, nargs, (unsigned short)("too few arguments"), (((unsigned int)("too few arguments"))>>16), (unsigned short)((unsigned long)("too few arguments")>>32), (unsigned short)((unsigned long)("too few arguments")>>48)); + } + dasm_put(Dst, 618); + } + + for (i = 1,regs.ints=0,regs.floats=0; i <= nargs; i++) { + lua_rawgeti(L, ct_usr, i); + mt = (const struct ctype*) lua_touserdata(L, -1); + + if (mt->pointers || mt->is_reference || mt->type == FUNCTION_PTR_TYPE || mt->type == ENUM_TYPE||mt->type==STRUCT_TYPE||mt->type==UNION_TYPE) { + lua_getuservalue(L, -1); + num_upvals += 2; + + + dasm_put(Dst, 620, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)((unsigned long)(mt)>>32), (unsigned short)((unsigned long)(mt)>>48), (unsigned short)(lua_upvalueindex(num_upvals)), (((unsigned int)(lua_upvalueindex(num_upvals)))>>16), i); + + if (mt->pointers || mt->is_reference) { + dasm_put(Dst, 635); + } else{ + switch (mt->type) { + case FUNCTION_PTR_TYPE: { + dasm_put(Dst, 639); + break; + } + case ENUM_TYPE:{ + dasm_put(Dst, 643); + break; + } + case STRUCT_TYPE: + case UNION_TYPE:{ + if(mt->is_empty) continue; + + int isfloat; + int hfasize=hfa_size(L,-2,mt,&isfloat); + dasm_put(Dst, 647); + if(hfasize>0){ + switch(hfasize){ + case 4: + if(isfloat){ + dasm_put(Dst, 651); + }else{ + dasm_put(Dst, 653); + } + goto ld_hfa; + case 3: + if(isfloat){ + dasm_put(Dst, 655); + }else{ + dasm_put(Dst, 657); + } + case 2: + ld_hfa: + if(isfloat){ + dasm_put(Dst, 659); + }else{ + dasm_put(Dst, 661); + } + break; + case 1: + if(isfloat){ + dasm_put(Dst, 663); + }else{ + dasm_put(Dst, 665); + } + break; + + } + store_float(Dst,®s,isfloat,hfasize-1); + continue; + } + if(mt->base_size>16){ + dasm_put(Dst, 667); + struct_offset+=(mt->base_size+7)&(~7); + if(struct_offset>=1<<12){ + dasm_put(Dst, 669, (unsigned short)(struct_offset), (((unsigned int)(struct_offset))>>16)); + } + else{ + dasm_put(Dst, 675, struct_offset); + } + store_int(Dst,®s,2); + dasm_put(Dst, 678, mt->base_size, (unsigned short)(memcpy), (((unsigned int)(memcpy))>>16), (unsigned short)((unsigned long)(memcpy)>>32), (unsigned short)((unsigned long)(memcpy)>>48)); + }else{ + if(mt->align_mask>8){//==15 + if(regs.ints&1) regs.ints++; + else if(regs.ex&1) regs.ex++; + } + int intSize=(mt->base_size+3)>>2; + switch(intSize){ + case 1: + dasm_put(Dst, 690); + break; + case 2: + dasm_put(Dst, 692); + break; + case 3: + case 4: + dasm_put(Dst, 694); + break; + } + store_int(Dst,®s,intSize); + } + continue; + } + } + } + goto longstore; + + } else { + lua_pop(L, 1); + dasm_put(Dst, 696, i); + + switch (mt->type) { + case BOOL_TYPE: + dasm_put(Dst, 699); + goto intstore; + + case INT8_TYPE: + case INT16_TYPE: //arm64 requires callee to narrow the type + case INT32_TYPE: + + dasm_put(Dst, 705); + + goto intstore; + + case INT64_TYPE: + + dasm_put(Dst, 709); + + goto longstore; + + case INTPTR_TYPE: + dasm_put(Dst, 713); + + goto longstore; + + case DOUBLE_TYPE: + dasm_put(Dst, 717); + store_float(Dst,®s,0,0); + break; + + case FLOAT_TYPE: + dasm_put(Dst, 721); + store_float(Dst,®s,1,0); + break; + case COMPLEX_DOUBLE_TYPE: + dasm_put(Dst, 725); + store_float(Dst,®s,0,1); + break; + + case COMPLEX_FLOAT_TYPE: + dasm_put(Dst, 729); + store_float(Dst,®s,1,1); + break; + + intstore: + store_int(Dst,®s,1); + break; + longstore: + store_int(Dst,®s,2); + break; + + default: + luaL_error(L, "NYI: call arg type"); + } + } + } + + if (ct->has_var_arg) { + if(regs.floats<8){ + dasm_put(Dst, 733, regs.floats<<3, (8-regs.floats), nargs+1); + } + if(regs.ints<8){ + dasm_put(Dst, 744, 0x40+(regs.ints<<3), (8-regs.ints), nargs+1); + } + dasm_put(Dst, 755, (nargs>8?nargs:8), (8-regs.floats), (8-regs.ints), nargs+1); + regs.floats=regs.ints=8; + } + + lua_rawgeti(L, ct_usr, 0); + mt = (const struct ctype*) lua_touserdata(L, -1); + ret_by_addr=!mt->pointers && !mt->is_reference &&(mt->type==STRUCT_TYPE||mt->type==UNION_TYPE) + && mt->base_size>16&& !(mt->type==STRUCT_TYPE&&hfa_size(L,-1,mt,NULL)!=0); + if(ret_by_addr){ + dasm_put(Dst, 772, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)((unsigned long)(mt)>>32), (unsigned short)((unsigned long)(mt)>>48)); + } + + //pop all args in registers + switch(regs.ints){ + case 8: + case 7: + dasm_put(Dst, 786); + case 6: + case 5: + dasm_put(Dst, 788); + case 4: + case 3: + dasm_put(Dst, 790); + case 2: + case 1: + dasm_put(Dst, 792); + } + + switch(regs.floats){ + case 8: + case 7: + dasm_put(Dst, 794); + case 6: + case 5: + dasm_put(Dst, 796); + case 4: + case 3: + dasm_put(Dst, 798); + case 2: + case 1: + dasm_put(Dst, 800); + } + if(regs.ints==8|| regs.floats==8){// fix stack case registers is full + dasm_put(Dst, 802); + } + + dasm_put(Dst, 804, (unsigned short)(func), (((unsigned int)(func))>>16), (unsigned short)((unsigned long)(func)>>32), (unsigned short)((unsigned long)(func)>>48)); + + + if (mt->pointers || mt->is_reference || mt->type==FUNCTION_PTR_TYPE) { + lua_getuservalue(L, -1); + num_upvals += 2; + dasm_put(Dst, 814, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)((unsigned long)(mt)>>32), (unsigned short)((unsigned long)(mt)>>48), (unsigned short)(lua_upvalueindex(num_upvals)), (((unsigned int)(lua_upvalueindex(num_upvals)))>>16)); + + } else { + switch (mt->type) { + case INT64_TYPE: + #if LUA_VERSION_NUM>=503 + lua_pop(L, 1); + dasm_put(Dst, 839); + break; + #endif + + case INTPTR_TYPE: + num_upvals++; + dasm_put(Dst, 851, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)((unsigned long)(mt)>>32), (unsigned short)((unsigned long)(mt)>>48)); + break; + case VOID_TYPE: + lua_pop(L, 1); + dasm_put(Dst, 873); + break; + + case BOOL_TYPE: + lua_pop(L, 1); + dasm_put(Dst, 881); + break; + + case INT8_TYPE:// we need to narrow the value before return + lua_pop(L, 1); + dasm_put(Dst, 893); + if (mt->is_unsigned) { + dasm_put(Dst, 895); + } else { + dasm_put(Dst, 900); + } + dasm_put(Dst, 905); + break; + case INT16_TYPE:// we need to narrow the value before return + lua_pop(L, 1); + dasm_put(Dst, 913); + if (mt->is_unsigned) { + dasm_put(Dst, 915); + } else { + dasm_put(Dst, 920); + } + dasm_put(Dst, 925); + break; + case INT32_TYPE: + case ENUM_TYPE: + lua_pop(L, 1); + dasm_put(Dst, 933); + if (mt->is_unsigned) { + dasm_put(Dst, 935); + } else { + dasm_put(Dst, 939); + } + dasm_put(Dst, 943); + break; + + case FLOAT_TYPE: + lua_pop(L, 1); + dasm_put(Dst, 951); + break; + + case DOUBLE_TYPE: + lua_pop(L, 1); + dasm_put(Dst, 962); + break; + case COMPLEX_FLOAT_TYPE: + lua_getuservalue(L, -1); + num_upvals+=2; + dasm_put(Dst, 973, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)((unsigned long)(mt)>>32), (unsigned short)((unsigned long)(mt)>>48), (unsigned short)(lua_upvalueindex(num_upvals)), (((unsigned int)(lua_upvalueindex(num_upvals)))>>16)); + break; + + case COMPLEX_DOUBLE_TYPE: + lua_getuservalue(L, -1); + num_upvals+=2; + dasm_put(Dst, 1001, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)((unsigned long)(mt)>>32), (unsigned short)((unsigned long)(mt)>>48), (unsigned short)(lua_upvalueindex(num_upvals)), (((unsigned int)(lua_upvalueindex(num_upvals)))>>16)); + break; + case STRUCT_TYPE: + case UNION_TYPE: + lua_getuservalue(L, -1); + num_upvals+=2; + if(ret_by_addr){ + if(!lua_isnil(L,-1)){ + dasm_put(Dst, 1027, (unsigned short)(lua_upvalueindex(num_upvals)), (((unsigned int)(lua_upvalueindex(num_upvals)))>>16)); + } + dasm_put(Dst, 1039); + }else if(mt->is_empty){ + dasm_put(Dst, 1047); + }else{ + int isfloat; + int hfasize=hfa_size(L,-2,mt,&isfloat); + if(hfasize){ + switch(hfasize){ + case 4: + dasm_put(Dst, 1055); + goto hfs_dual; + case 3: + dasm_put(Dst, 1057); + case 2: + hfs_dual: + dasm_put(Dst, 1059); + case 1: + dasm_put(Dst, 1061); + break; + } + }else{ + if(mt->base_size>8){ + dasm_put(Dst, 1063); + } + dasm_put(Dst, 1065); + + } + dasm_put(Dst, 1067, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)((unsigned long)(mt)>>32), (unsigned short)((unsigned long)(mt)>>48), (unsigned short)(lua_upvalueindex(num_upvals)), (((unsigned int)(lua_upvalueindex(num_upvals)))>>16)); + if(hfasize){ + switch(hfasize){ + case 4: + dasm_put(Dst, 1083); + if(isfloat){ + dasm_put(Dst, 1085); + }else{ + dasm_put(Dst, 1087); + } + goto hfl_dual; + case 3: + dasm_put(Dst, 1089); + if(isfloat){ + dasm_put(Dst, 1091); + }else{ + dasm_put(Dst, 1093); + } + case 2: + hfl_dual: + if(isfloat){ + dasm_put(Dst, 1095); + }else{ + dasm_put(Dst, 1098); + } + case 1: + if(isfloat){ + dasm_put(Dst, 1100); + }else{ + dasm_put(Dst, 1103); + } + break; + } + }else{ + if(mt->base_size>8){ + dasm_put(Dst, 1105); + } + dasm_put(Dst, 1107); + + } + dasm_put(Dst, 1109); + } + break; + + default: + luaL_error(L, "NYI: call return type"); + } + } + + assert(lua_gettop(L) == top + num_upvals); + { + cfunction f = compile(Dst, L, NULL, LUA_NOREF); + /* add a callback as an upval so that the jitted code gets cleaned up when + * the function gets gc'd */ + push_callback(L, f, func); + lua_pushcclosure(L, (lua_CFunction) f, num_upvals+1); + } +} + diff --git a/texk/web2c/luatexdir/luaffi/call_arm_hf.h b/texk/web2c/luatexdir/luaffi/call_arm_hf.h new file mode 100644 index 0000000000..b9fec4d532 --- /dev/null +++ b/texk/web2c/luatexdir/luaffi/call_arm_hf.h @@ -0,0 +1,2530 @@ +/* +** This file has been pre-processed with DynASM. +** http://luajit.org/dynasm.html +** DynASM version 1.4.0, DynASM arm version 1.4.0 +** DO NOT EDIT! The original file is in "call_arm.dasc". +*/ + +/* vim: ts=4 sw=4 sts=4 et tw=78 + * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved. + * Portions copyright (c) 2011 James R. McKaskill. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +//The generate code is for arm not for thumb +#if DASM_VERSION != 10400 +#error "Version mismatch between DynASM and included encoding engine" +#endif + +static const unsigned int build_actionlist[951] = { +0xed0d0a00, +0x000f8100, +0x00000000, +0xed4d0a00, +0x000f8100, +0x00000000, +0xed0d1a00, +0x000f8100, +0x00000000, +0xed4d1a00, +0x000f8100, +0x00000000, +0xed0d2a00, +0x000f8100, +0x00000000, +0xed4d2a00, +0x000f8100, +0x00000000, +0xed0d3a00, +0x000f8100, +0x00000000, +0xed4d3a00, +0x000f8100, +0x00000000, +0xed0d4a00, +0x000f8100, +0x00000000, +0xed4d4a00, +0x000f8100, +0x00000000, +0xed0d5a00, +0x000f8100, +0x00000000, +0xed4d5a00, +0x000f8100, +0x00000000, +0xed0d6a00, +0x000f8100, +0x00000000, +0xed4d6a00, +0x000f8100, +0x00000000, +0xed0d7a00, +0x000f8100, +0x00000000, +0xed4d7a00, +0x000f8100, +0x00000000, +0xed0d0b00, +0x000f8100, +0x00000000, +0xed0d1b00, +0x000f8100, +0x00000000, +0xed0d2b00, +0x000f8100, +0x00000000, +0xed0d3b00, +0x000f8100, +0x00000000, +0xed0d4b00, +0x000f8100, +0x00000000, +0xed0d5b00, +0x000f8100, +0x00000000, +0xed0d6b00, +0x000f8100, +0x00000000, +0xed0d7b00, +0x000f8100, +0x00000000, +0xe28dc000, +0x000b0000, +0xe89c100e, +0x00000000, +0xe28dc000, +0x000b0000, +0xe89c100e, +0x00000000, +0xe28dc000, +0x000b0000, +0xe89c0006, +0x00000000, +0xe51d1000, +0x000e8180, +0x00000000, +0xe2866000, +0x000b0000, +0x00000000, +0xe8b6100e, +0x00000000, +0xe8b60006, +0x00000000, +0xe4961004, +0x00000000, +0xed1d0a00, +0x000f8100, +0x00000000, +0xed1d0b00, +0x000f8100, +0x00000000, +0xed160a00, +0xe2866004, +0x00000000, +0xe2866000, +0x000b0000, +0x00000000, +0xed160b00, +0xe2866008, +0x00000000, +0xe1a0c00d, +0xe92d000f, +0x00000000, +0xe24dd040, +0x00000000, +0xe92d5050, +0xe1a0600c, +0xe3004000, +0x000c0200, +0xe3404000, +0x000c0200, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3001000, +0x000c0200, +0xe3401000, +0x000c0200, +0xe1a00004, +0xeb000000, +0x00030000, +0x00000000, +0xe3a02000, +0x000b0000, +0xe3e01000, +0xe1a00004, +0xeb000000, +0x00030000, +0x00000000, +0xe3a02000, +0x000b0000, +0xe3e01000, +0x000b0000, +0xe1a00004, +0xeb000000, +0x00030000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3e01000, +0xe1a00004, +0xeb000000, +0x00030001, +0x00000000, +0xe5801000, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x00030002, +0x00000000, +0xe3a02000, +0x000b0000, +0xe3e01000, +0x000b0000, +0xe1a00004, +0xeb000000, +0x00030000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3e01000, +0xe1a00004, +0xeb000000, +0x00030001, +0x00000000, +0xe8a0100e, +0x00000000, +0xe880100e, +0x00000000, +0xe8a0100e, +0x00000000, +0xe8800006, +0x00000000, +0xe880100e, +0x00000000, +0xe880000e, +0x00000000, +0xe8800006, +0x00000000, +0xe5801000, +0x00000000, +0xe5801000, +0x00000000, +0xe28d1000, +0x000b0000, +0x00000000, +0xe1a01006, +0x00000000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe300c000, +0x000c0200, +0xe340c000, +0x000c0200, +0xe12fff3c, +0x00000000, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x00030002, +0x00000000, +0xe3a02000, +0x000b0000, +0xe3e01000, +0x000b0000, +0xe1a00004, +0xeb000000, +0x00030000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3e01000, +0xe1a00004, +0xeb000000, +0x00030001, +0x00000000, +0xe880100e, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x00030002, +0x00000000, +0xe3a02000, +0x000b0000, +0xe3e01000, +0x000b0000, +0xe1a00004, +0xeb000000, +0x00030000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3e01000, +0xe1a00004, +0xeb000000, +0x00030001, +0x00000000, +0xe8800006, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x00030002, +0x00000000, +0xe28dc000, +0x000b0000, +0xe89c000c, +0x00000000, +0xe2866004, +0x00000000, +0xe8b6000c, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030003, +0x00000000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3a01000, +0xe1a00004, +0xeb000000, +0x00030001, +0x00000000, +0xe8800006, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x00030002, +0x00000000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3a01000, +0xe1a00004, +0xeb000000, +0x00030001, +0x00000000, +0xe5801000, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x00030002, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030004, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030005, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030006, +0x00000000, +0xe28dc000, +0x000b0000, +0xe89c000c, +0x00000000, +0xe2866004, +0x00000000, +0xe8b6000c, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030007, +0x00000000, +0xe3a02000, +0x000b0000, +0xe3a01000, +0x000b0000, +0xe1a00004, +0xeb000000, +0x00030008, +0x00000000, +0xe3a02000, +0x000b0000, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x00030000, +0xe3003000, +0x000c0200, +0xe3403000, +0x000c0200, +0xe3e02000, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x00030009, +0x00000000, +0xe3a02000, +0x000b0000, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x00030000, +0xe3003000, +0x000c0200, +0xe3403000, +0x000c0200, +0xe3e02000, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x0003000a, +0xe1a06000, +0xe3e01002, +0xe1a00004, +0xeb000000, +0x0003000b, +0x00000000, +0xec960b08, +0x00000000, +0xec960b06, +0x00000000, +0xec960b04, +0x00000000, +0xec960a04, +0x00000000, +0xed160b00, +0x00000000, +0xed160a00, +0x00000000, +0xe5960000, +0x00000000, +0xe51d0000, +0x000e8180, +0xe1a01006, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe300c000, +0x000c0200, +0xe340c000, +0x000c0200, +0xe12fff3c, +0x00000000, +0xe3a02000, +0x000b0000, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x00030000, +0xe3003000, +0x000c0200, +0xe3403000, +0x000c0200, +0xe3e02000, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x0003000c, +0x00000000, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x0003000b, +0x00000000, +0xe3e01000, +0x00000000, +0xe1a00004, +0xeb000000, +0x0003000d, +0x00000000, +0xe1a00004, +0xeb000000, +0x0003000e, +0x00000000, +0xe3500000, +0x13a00001, +0x00000000, +0xe6ef0070, +0x00000000, +0xe6af0070, +0x00000000, +0xe6ff0070, +0x00000000, +0xe6bf0070, +0x00000000, +0xe3e01000, +0x00000000, +0xe1a00004, +0xeb000000, +0x0003000f, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030010, +0x00000000, +0xe3e01000, +0xe1a00004, +0xeb000000, +0x00030011, +0x00000000, +0xe3e01000, +0xe1a00004, +0xeb000000, +0x00030012, +0x00000000, +0xee106a10, +0xe3e01002, +0xe1a00004, +0xeb000000, +0x0003000b, +0xee006a10, +0x00000000, +0xe3e01000, +0xe1a00004, +0xeb000000, +0x00030013, +0x00000000, +0xe1a00004, +0xec564b10, +0xe3e01002, +0xeb000000, +0x0003000b, +0xec464b10, +0x00000000, +0xe3e01000, +0xe1a00004, +0xeb000000, +0x00030014, +0xed2d0b04, +0xe3e01002, +0xe1a00004, +0xeb000000, +0x0003000b, +0xecbd0b04, +0x00000000, +0xe3e01000, +0xe1a00004, +0xeb000000, +0x00030015, +0xed2d0a02, +0xe3e01002, +0xe1a00004, +0xeb000000, +0x0003000b, +0xecbd0a02, +0x00000000, +0xe1a06000, +0xe3e01002, +0xe1a00004, +0xeb000000, +0x0003000b, +0xe1a00006, +0x00000000, +0xe1a06000, +0xe1a00004, +0xe1a04001, +0xe3e01002, +0xeb000000, +0x0003000b, +0xe1a00006, +0xe1a01004, +0x00000000, +0xe89da050, +0x00000000, +0xe2866004, +0x00000000, +0xe8a60003, +0x00000000, +0xe28dc000, +0x000b0000, +0xe88c0003, +0x00000000, +0xe4860004, +0x00000000, +0xe50d0000, +0x000e8180, +0x00000000, +0xed0d3b00, +0x000f8100, +0x00000000, +0xed0d2b00, +0x000f8100, +0x00000000, +0xed0d1b00, +0x000f8100, +0x00000000, +0xed4d1a00, +0x000f8100, +0x00000000, +0xed0d0b00, +0x000f8100, +0x00000000, +0xed0d0a00, +0x000f8100, +0x00000000, +0xe2866004, +0x00000000, +0xeca60a01, +0x00000000, +0xeca60b02, +0x00000000, +0xeca60a04, +0x00000000, +0xeca60b04, +0x00000000, +0xeca60b06, +0x00000000, +0xeca60b08, +0x00000000, +0xe92d40f0, +0xe28d700c, +0x00000000, +0xe92d4870, +0xe28db00c, +0x00000000, +0xe24dd004, +0x00000000, +0xe1a04000, +0x00000000, +0xe300c000, +0x000c0200, +0xe340c000, +0x000c0200, +0xe04dd00c, +0x00000000, +0xe24dd000, +0x000b0000, +0x00000000, +0xeb000000, +0x00030016, +0xe3500000, +0x000b0000, +0xaa000000, +0x00050001, +0xe3001000, +0x000c0200, +0xe3401000, +0x000c0200, +0xe1a00004, +0xeb000000, +0x00030017, +0x0006000b, +0xe1a05000, +0xe04dd185, +0x00000000, +0xe28d6000, +0x000b0000, +0x00000000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3a01000, +0xe1a00004, +0xeb000000, +0x00030001, +0xe50d0000, +0x000e8180, +0x00000000, +0xe3003000, +0x000c0200, +0xe3403000, +0x000c0200, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3a01000, +0x000b0000, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030009, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030018, +0x00000000, +0xe1a00004, +0xeb000000, +0x0003000c, +0x00000000, +0xe1a00004, +0xeb000000, +0x0003000a, +0x00000000, +0xec900b0a, +0x00000000, +0xec900b0a, +0x00000000, +0xec900b06, +0x00000000, +0xec900a04, +0x00000000, +0xed100b00, +0x00000000, +0xed100a00, +0x00000000, +0xe2866004, +0x00000000, +0xe1a01000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe300c000, +0x000c0200, +0xe340c000, +0x000c0200, +0x00000000, +0xe28d0000, +0x000b0000, +0x00000000, +0xe1a00006, +0x00000000, +0xe12fff3c, +0x00000000, +0xe2866000, +0x000b0000, +0x00000000, +0xe3a01000, +0x000b0000, +0x00000000, +0xe1a00004, +0xeb000000, +0x0003000e, +0xe3500000, +0x13a00001, +0x00000000, +0xe1a00004, +0xeb000000, +0x0003000e, +0x00000000, +0xe6ef0070, +0x00000000, +0xe6af0070, +0x00000000, +0xe1a00004, +0xeb000000, +0x0003000e, +0x00000000, +0xe6ff0070, +0x00000000, +0xe6bf0070, +0x00000000, +0xe1a00004, +0xeb000000, +0x0003000d, +0x00000000, +0xe1a00004, +0xeb000000, +0x0003000e, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030011, +0x00000000, +0xe1a00004, +0xeb000000, +0x0003000f, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030010, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030013, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030012, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030014, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030015, +0x00000000, +0xe3a01000, +0x000b0000, +0x00000000, +0xe28d2000, +0x000b0000, +0xe28d3000, +0x000b0000, +0xe1a00004, +0xeb000000, +0x00030019, +0xe2801000, +0x000b0000, +0x00000000, +0xe1a03006, +0x00000000, +0xe28d3000, +0x000b0000, +0x00000000, +0xe1a02005, +0xe1a00004, +0xeb000000, +0x0003001a, +0x00000000, +0xec9d0b10, +0x00000000, +0xec9d0b0e, +0x00000000, +0xec9d0b0c, +0x00000000, +0xec9d0b0a, +0x00000000, +0xec9d0b08, +0x00000000, +0xec9d0b06, +0x00000000, +0xec9d0b04, +0x00000000, +0xed1d0b00, +0x00000000, +0xe28dd040, +0x00000000, +0xe8bd000f, +0x00000000, +0xe8bd0003, +0x00000000, +0xe28dd008, +0x00000000, +0xe28dd010, +0x00000000, +0xe300c000, +0x000c0200, +0xe340c000, +0x000c0200, +0xe12fff3c, +0x00000000, +0xe1a06000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3001000, +0x000c0200, +0xe3401000, +0x000c0200, +0xe1a00004, +0xeb000000, +0x00030001, +0xe5806000, +0xe3a00001, +0x00000000, +0xe1a03001, +0xe1a02000, +0x00000000, +0xe1a02001, +0xe1a01000, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030003, +0xe3a00001, +0x00000000, +0xe1a06000, +0xe1a05001, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3a01000, +0xe1a00004, +0xeb000000, +0x00030001, +0xe5806000, +0xe5805004, +0xe3a00001, +0x00000000, +0xe1a06000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3a01000, +0xe1a00004, +0xeb000000, +0x00030001, +0xe5806000, +0xe3a00001, +0x00000000, +0xe3a00000, +0x00000000, +0xe1a01000, +0xe1a00004, +0xeb000000, +0x00030004, +0xe3a00001, +0x00000000, +0xe1a01000, +0x00000000, +0xe1a00004, +0xeb000000, +0x0003001b, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030005, +0x00000000, +0xe3a00001, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030006, +0xe3a00001, +0x00000000, +0xe1a00004, +0xeb000000, +0x00030007, +0xe3a00001, +0x00000000, +0xed2d0b08, +0x00000000, +0xed2d0b06, +0x00000000, +0xed2d0b04, +0x00000000, +0xed2d0b02, +0x00000000, +0xe1a06000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3001000, +0x000c0200, +0xe3401000, +0x000c0200, +0xe1a00004, +0xeb000000, +0x00030001, +0x00000000, +0xecbd0b08, +0xec800b08, +0x00000000, +0xecbd0b06, +0xec800b06, +0x00000000, +0xecbd0b04, +0xec800b04, +0x00000000, +0xecbd0b04, +0xec800a04, +0x00000000, +0xecbd0b02, +0xed000b00, +0x00000000, +0xecbd0b02, +0xed000a00, +0x00000000, +0xe3a00001, +0x00000000, +0xe3001000, +0x000c0200, +0xe3401000, +0x000c0200, +0xe1a00004, +0xeb000000, +0x0003001c, +0xe3e01001, +0xe1a00004, +0xeb000000, +0x0003001d, +0x00000000, +0xe3a00000, +0x00000000, +0xe1a06000, +0xe3002000, +0x000c0200, +0xe3402000, +0x000c0200, +0xe3001000, +0x000c0200, +0xe3401000, +0x000c0200, +0xe1a00004, +0xeb000000, +0x00030001, +0xe5806000, +0x00000000, +0xe3a00001, +0x00000000, +0xe247d00c, +0xe8bd80f0, +0x00000000, +0xe24bd00c, +0xe8bd8870, +0x00000000 +}; + +static const char *const globnames[] = { + (const char *)0 +}; +static const char *const extnames[] = { + "rawgeti", + "push_cdata", + "lua_remove", + "lua_pushinteger", + "lua_pushboolean", + "push_int", + "push_float", + "lua_pushnumber", + "lua_call", + "check_typed_pointer", + "check_struct", + "lua_settop", + "check_enum", + "check_uint32", + "check_int32", + "check_uint64", + "check_int64", + "check_uintptr", + "check_float", + "check_double", + "check_complex_double", + "check_complex_float", + "lua_gettop", + "luaL_error", + "check_typed_cfunction", + "unpack_varargs_bound", + "unpack_varargs_stack", + "push_uint", + "lua_pushvalue", + "lua_setuservalue", + (const char *)0 +}; + +#define JUMP_SIZE 8 + +#define MIN_BRANCH ((INT32_MIN) >> 8) +#define MAX_BRANCH ((INT32_MAX) >> 8) +//arm pc offset 8 so comparing with next instruction is 4, +//unlike x86 which pass in the current instruction address+1 rather than the next instruction +#define BRANCH_OFF 4 + + +#define ROUND_UP(x, align) (((int) (x) + (align - 1)) & ~(align - 1)) +#ifdef TARGET_OS_IPHONE +#define CK_ALGIN 0 +#else +#define CK_ALGIN 1 +#endif +#define ALIGNED(x, align) (!CK_ALGIN||((int)(x) & (align - 1)) == 0) +#if defined(__ARM_PCS_VFP) || (GCC_VERSION==40500||defined(__clang__))&&!defined(__ARM_PCS) && !defined(__SOFTFP__) && !defined(__SOFTFP) && \ + defined(__VFP_FP__) +#define ARM_HF 1 +#else +#define ARM_HF 0 +#endif +#if ARM_HF&&!CK_ALGIN +#error "Unsupported unaligned stack for hard floating point" +#endif + +static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, uint8_t* code) +{ + /* The jump code is the function pointer followed by a stub to call the + * function pointer. The stub exists so we can jump to functions with an + * offset greater than 32MB. + * + * Note we have to manually set this up since there are commands buffered + * in the jit state. + */ + + *(cfunction*) code = func; + //ldr pc, [pc - 12] + *(uint32_t*) &code[4] = 0xE51FF00CU; + +} + + + + +void compile_globals(struct jit* jit, lua_State* L) +{ + (void) jit; +} + +typedef struct stack_info{ + int extra; + int int_off; + int stack_off; + int float_size; +#if ARM_HF + int float_off; +#endif +} stack_info; +//vfp use back-filling rule for registers until a float value on stack +typedef struct reg_info{ + uint16_t exs; + union{ + uint8_t ints; + uint8_t regs; + }; +#if ARM_HF + uint8_t float_sealed; + short floats;//each bit is a float: s0-s15 or v0-v7 or q0-q3 + uint8_t left_single; + uint8_t highest_bit; +#endif +} reg_info; + +#define MAX_REGS 4 +#define MAX_FLOAT_REGS 16 +#ifndef bool +#define bool uint8_t +#endif + +#define has_bit(x,b) (((x)&(1<<(b)))!=0) +#define set_bit(x,b) (x=((x)|(1<<(b)))) +#define FIX_ALIGN(x,al) \ + if(!ALIGNED((x),al)){\ + x=ROUND_UP(x,al);\ + } +static ALWAYS_INLINE bool is_float_sealed(reg_info* regs){ +#if ARM_HF +return regs->float_sealed; +#else +return regs->regs>=MAX_REGS; +#endif +} +//return size need to put on stack +static ALWAYS_INLINE int add_int_reg(reg_info* regs){ + if(regs->regsregs++; + return 0; + } + return 1; + +} +//return size need to put on stack +static ALWAYS_INLINE int add_int64_reg(reg_info* regs){ + if(regs->regsregs=ROUND_UP(regs->regs,2)+2; + return 0; + }else if(regs->regs==MAX_REGS-1){ + regs->regs=MAX_REGS; + } + + return 2; +} +static ALWAYS_INLINE bool is_float_type(int t){ + return t==FLOAT_TYPE||t==DOUBLE_TYPE; +} +static int hfa_size(lua_State* L,int idx, const struct ctype* ct,int* isfloat){ + struct ctype* mt; + int type,ele_count,i,ct_usr; + lua_getuservalue(L,idx); + ct_usr=lua_absindex(L,-1); + lua_rawgeti(L,ct_usr,1); + mt=(struct ctype*)lua_touserdata(L,-1); + if(mt==NULL||(mt->pointers&&!mt->is_array)||mt->is_reference||!is_float_type(mt->type)){ + lua_pop(L,2); + if(ct->type==COMPLEX_DOUBLE_TYPE){ + if(isfloat) *isfloat=0; + return 4; + }else if(ct->type==COMPLEX_FLOAT_TYPE){ + if(isfloat) *isfloat=1; + return 2; + } + return 0; + } + type=mt->type; + ele_count=(int)(ct->base_size/mt->base_size); + if(ele_count>4||ct->base_size%mt->base_size){ + lua_pop(L,2); + return 0; + } + lua_pop(L,1); + for (i = 2; i <=4 ; ++i) { + lua_rawgeti(L,ct_usr,i); + if(lua_isnil(L,-1)){//case have array member; + lua_pop(L,1); + break; + } + mt=(struct ctype*)lua_touserdata(L,-1); + if(mt->type!=type||(mt->pointers&&!mt->is_array)||mt->is_reference||!is_float_type(mt->type)){ + lua_pop(L,2); + return 0; + } + lua_pop(L,1); + } + if(isfloat){ + *isfloat=mt->type==FLOAT_TYPE; + } + lua_pop(L,1); + return ele_count*(mt->type==FLOAT_TYPE?1:2); +} +#if ARM_HF +static void save_float_reg(struct jit* Dst,int reg,int size,stack_info* st){ + int sz; + if(reg==-1) return; + for(;size>0;size-=8){ + sz=size>8?8:size; + switch(sz){ + case 4: + switch(reg){ + case 0: + dasm_put(Dst, 0, st->float_size); + break; + case 1: + dasm_put(Dst, 3, st->float_size); + break; + case 2: + dasm_put(Dst, 6, st->float_size); + break; + case 3: + dasm_put(Dst, 9, st->float_size); + break; + case 4: + dasm_put(Dst, 12, st->float_size); + break; + case 5: + dasm_put(Dst, 15, st->float_size); + break; + case 6: + dasm_put(Dst, 18, st->float_size); + break; + case 7: + dasm_put(Dst, 21, st->float_size); + break; + case 8: + dasm_put(Dst, 24, st->float_size); + break; + case 9: + dasm_put(Dst, 27, st->float_size); + break; + case 10: + dasm_put(Dst, 30, st->float_size); + break; + case 11: + dasm_put(Dst, 33, st->float_size); + break; + case 12: + dasm_put(Dst, 36, st->float_size); + break; + case 13: + dasm_put(Dst, 39, st->float_size); + break; + case 14: + dasm_put(Dst, 42, st->float_size); + break; + case 15: + dasm_put(Dst, 45, st->float_size); + break; + } + break; + case 8: + switch(reg>>1){ + case 0: + dasm_put(Dst, 48, st->float_size); + break; + case 1: + dasm_put(Dst, 51, st->float_size); + break; + case 2: + dasm_put(Dst, 54, st->float_size); + break; + case 3: + dasm_put(Dst, 57, st->float_size); + break; + case 4: + dasm_put(Dst, 60, st->float_size); + break; + case 5: + dasm_put(Dst, 63, st->float_size); + break; + case 6: + dasm_put(Dst, 66, st->float_size); + break; + case 7: + dasm_put(Dst, 69, st->float_size); + break; + } + reg+=2; + break; + } + st->float_size+=sz; + } +} + +//128 bit vector type is not supported by this +static int add_float_reg(reg_info* regs,int sz,int isfloat){ + + if(is_float_sealed(regs)) return -1; + int i,ret=-1; + if(sz==1){ + if(regs->left_single){ + int n=regs->highest_bit; + for(i=0;ifloats,i)){ + regs->left_single--; + set_bit(regs->floats,i); + ret=i; + } + } + }else{ + ret=regs->highest_bit; + set_bit(regs->floats,regs->highest_bit); + ++regs->highest_bit; + } + }else{ + if(regs->highest_bit>MAX_FLOAT_REGS-sz){ + regs->highest_bit=MAX_FLOAT_REGS; + }else{ + if(!isfloat&&!ALIGNED(regs->highest_bit, 2)){ + regs->highest_bit++; + regs->left_single++; + } + ret=regs->highest_bit; + for(i=0;ifloats,regs->highest_bit++); + } + } + } + if(regs->highest_bit==MAX_FLOAT_REGS){ + regs->float_sealed=true; + } + return ret; +} +#endif +static void load_reg(struct jit* Dst,int off,int size){ + if(size==16){ + dasm_put(Dst, 72, off); + }else if(size==12){ + dasm_put(Dst, 76, off); + }else if(size==8){ + dasm_put(Dst, 80, off); + }else{ + dasm_put(Dst, 84, off); + } +} +// arm store/load range for immediate value is only -256-255 +static void load_stack(struct jit* Dst,stack_info* st,int size,int align){ + int off=st->stack_off; + FIX_ALIGN(st->stack_off,align); + if((off=st->stack_off-off)){ + dasm_put(Dst, 87, off); + } + if(size==16){ + dasm_put(Dst, 90); + }else if(size==8){ + dasm_put(Dst, 92); + }else{ + dasm_put(Dst, 94); + } + st->stack_off+=size; +} + +static void load_int(struct jit* Dst,stack_info* st,int size,int align){ + FIX_ALIGN(st->int_off,align); + if(st->int_off<0x40*ARM_HF+MAX_REGS*4&&(!st->stack_off||MAX_REGS*4+size<=0x40*ARM_HF+MAX_REGS*4)){ + load_reg(Dst,st->int_off+st->extra,size); + st->int_off+=size; + }else{ + st->int_off=0x40*ARM_HF+MAX_REGS*4; + load_stack(Dst,st,size,align); + } + +} + +static void load_float(struct jit* Dst,stack_info* st,int size,int vfp,int align){ + #if ARM_HF + if(st->float_offfloat_size){ + if(vfp){ + if(size==4){//float + dasm_put(Dst, 96, st->float_off+st->extra); + }else if(size==8){//double + dasm_put(Dst, 99, st->float_off+st->extra); + } + }else load_reg(Dst,st->float_off+st->extra,size); + st->float_off+=size; + }else if(vfp){ + if(size==4){//float + dasm_put(Dst, 102); + }else if(size==8){//double + int off=st->stack_off; + FIX_ALIGN(st->stack_off,align); + if((off=st->stack_off-off)){ + dasm_put(Dst, 105, off); + } + dasm_put(Dst, 108); + } + }else{ + load_stack(Dst,st,size,align); + } + #else + load_int(Dst,st,size,align); + #endif +} +#if ARM_HF +static void push_regs(lua_State* L,struct jit* Dst,int ct_usr,int nargs,stack_info* st){ + const struct ctype* mt; + reg_info regs;int i; + memset(®s,0,sizeof(reg_info)); + for (i = 1; i <= nargs&&!is_float_sealed(®s); ++i){ + lua_rawgeti(L, ct_usr, i); + mt = (const struct ctype*) lua_touserdata(L, -1); + if (!mt->pointers &&! mt->is_reference) { + switch(mt->type){ + case COMPLEX_DOUBLE_TYPE: + save_float_reg(Dst,add_float_reg(®s,4,0),16,st); + break; + case DOUBLE_TYPE: + save_float_reg(Dst,add_float_reg(®s,2,0),8,st); + break; + case COMPLEX_FLOAT_TYPE: + save_float_reg(Dst,add_float_reg(®s,2,1),8,st); + break; + case FLOAT_TYPE: + save_float_reg(Dst,add_float_reg(®s,1,1),4,st); + break; + case STRUCT_TYPE: + { + int isfloat,hfasize=hfa_size(L,-1,mt,&isfloat); + if(hfasize){ + save_float_reg(Dst,add_float_reg(®s,hfasize,isfloat),4*hfasize,st); + break; + } + } + case UNION_TYPE: + break; + case INT64_TYPE: + //add_int64_reg(®s); + break; + default: + //add_int_reg(®s);//no need to check type support here + break; + } + } + lua_pop(L,1); + } + st->float_off+=st->int_off; + st->int_off+=0x40; +} +#endif +cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctype* ct) +{ + struct jit* Dst = get_jit(L);; + int i, nargs, num_upvals, ref; + const struct ctype* mt; + stack_info st; + + int top = lua_gettop(L); + + ct_usr = lua_absindex(L, ct_usr); + fidx = lua_absindex(L, fidx); + nargs = (int) lua_rawlen(L, ct_usr); + + dasm_setup(Dst, build_actionlist); + + lua_newtable(L); + lua_pushvalue(L, -1); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + num_upvals = 0; + + if (ct->has_var_arg) { + luaL_error(L, "can't create callbacks with varargs"); + } + memset(&st,0,sizeof(stack_info)); + st.extra=0x10; + /* prolog and get the upval table */ + dasm_put(Dst, 111); +#if ARM_HF + dasm_put(Dst, 114); + push_regs(L,Dst,ct_usr,nargs,&st); +#endif + + dasm_put(Dst, 116, (unsigned short)(L), (((unsigned int)(L))>>16), (unsigned short)(ref), (((unsigned int)(ref))>>16), (unsigned short)(LUA_REGISTRYINDEX), (((unsigned int)(LUA_REGISTRYINDEX))>>16)); + + /* get the lua function */ + lua_pushvalue(L, fidx); + lua_rawseti(L, -2, ++num_upvals); + + + dasm_put(Dst, 134, num_upvals); + + // Complex type is return in the address stored in r0 for softfp + lua_rawgeti(L, ct_usr, 0); + mt = (const struct ctype*) lua_touserdata(L, -1); + if(!mt->pointers && !mt->is_reference &&(mt->type==STRUCT_TYPE || mt->type==UNION_TYPE|| + (!1&&(mt->type==COMPLEX_DOUBLE_TYPE||mt->type==COMPLEX_FLOAT_TYPE)))&&mt->base_size>4&&!(1&&hfa_size(L,-1,mt,NULL))){ + st.int_off+=4; + } + lua_pop(L,1); + + //whether 64 bit type requires 8 bytes alignment in stack is defined by compiler.android compiler reqiures only 4 byte alignment; + //actually the stack it self may reqiures 8 bytes alignment + for (i = 1; i <= nargs; i++) { + lua_rawgeti(L, ct_usr, i); + mt = (const struct ctype*) lua_touserdata(L, -1); + + if (mt->pointers || mt->is_reference) { + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + dasm_put(Dst, 141, num_upvals-1, i, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + load_int(Dst,&st,4,4); + dasm_put(Dst, 157); + } else { + switch (mt->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ + #if ARM_HF + int isfloat,hfasize=0; + if(mt->type!=UNION_TYPE){ + hfasize=hfa_size(L,-1,mt,&isfloat); + } + #endif + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + dasm_put(Dst, 163, num_upvals-1, i, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + #if ARM_HF + if(hfasize){ + if(hfasize<=4)load_float(Dst,&st,4*hfasize,0,4*(2-isfloat)); + switch(hfasize){ + case 8: + load_float(Dst,&st,16,0,8); + dasm_put(Dst, 179); + load_float(Dst,&st,16,0,8); + dasm_put(Dst, 181); + break; + case 6: + load_float(Dst,&st,16,0,8); + dasm_put(Dst, 183); + load_float(Dst,&st,8,0,8); + dasm_put(Dst, 185); + break; + case 4: + dasm_put(Dst, 187); + break; + case 3: + dasm_put(Dst, 189); + break; + case 2: + dasm_put(Dst, 191); + break; + case 1: + dasm_put(Dst, 193); + break; + } + }else + #endif + if(!mt->is_empty){ + int size=mt->base_size; + if(size<=4){ + load_int(Dst,&st,4,4); + dasm_put(Dst, 195); + }else{ + size=ROUND_UP(size,4); + if(mt->align_mask>4){//8 byte max alignment + if(st.int_off<0x40*ARM_HF+MAX_REGS*4){FIX_ALIGN(st.int_off,8);} + else {FIX_ALIGN(st.stack_off,8);} + } + + if(st.int_off<0x40*ARM_HF+MAX_REGS*4&&(!st.stack_off||st.int_off+size<=0x40*ARM_HF+MAX_REGS*4)){//to ensure consective memory for the struct + dasm_put(Dst, 197, st.int_off+st.extra); + st.int_off+=size; + }else{ + st.int_off=0x40*ARM_HF+MAX_REGS*4; + dasm_put(Dst, 200); + st.stack_off+=size; + } + dasm_put(Dst, 202, (unsigned short)(mt->base_size), (((unsigned int)(mt->base_size))>>16), (unsigned short)(memcpy), (((unsigned int)(memcpy))>>16)); + } + } + dasm_put(Dst, 212); + break; + } + + case COMPLEX_DOUBLE_TYPE: + + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + dasm_put(Dst, 217, num_upvals-1, i, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + load_float(Dst,&st,16,0,8); + dasm_put(Dst, 233); + break; + case COMPLEX_FLOAT_TYPE: + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + dasm_put(Dst, 239, num_upvals-1, i, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + load_float(Dst,&st,8,0,4); + dasm_put(Dst, 255); + break; + case INT64_TYPE: + + #if LUA_VERSION_NUM>=503 + lua_pop(L, 1); + + #if CK_ALGIN + FIX_ALIGN(st.int_off,8); + if(st.int_off<16){ + dasm_put(Dst, 261, st.int_off+st.extra); + st.int_off+=8; + }else{ + if(!ALIGNED(st.stack_off,8)){ + st.stack_off+=4; + dasm_put(Dst, 265); + } + dasm_put(Dst, 267); + st.stack_off+=8; + } + #else + load_int(Dst,st,8,8); + #endif + dasm_put(Dst, 269); + #else + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + dasm_put(Dst, 273, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + load_int(Dst,&st,8,8); + dasm_put(Dst, 282); + #endif + break; + + case INTPTR_TYPE: + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + dasm_put(Dst, 288, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + load_int(Dst,&st,4,4); + dasm_put(Dst, 297); + + break; + + case BOOL_TYPE: + lua_pop(L, 1); + + load_int(Dst,&st,4,4); + dasm_put(Dst, 303); + break; + + case INT8_TYPE: // no need to narrow cause narrowed by caller + case INT16_TYPE: // no need to narrow cause narrowed by caller + case ENUM_TYPE: + case INT32_TYPE: + lua_pop(L, 1); + + load_int(Dst,&st,4,4); + dasm_put(Dst, 307); + break; + + case FLOAT_TYPE: + lua_pop(L, 1); + + load_float(Dst,&st,4,ARM_HF,4); + dasm_put(Dst, 311); + break; + + case DOUBLE_TYPE: + lua_pop(L, 1); + + #if ARM_HF + load_float(Dst,&st,8,ARM_HF,8); + #elif CK_ALGIN + FIX_ALIGN(st.int_off,8); + if(st.int_off<16){ + dasm_put(Dst, 315, st.int_off+st.extra); + st.int_off+=8; + }else{ + if(!ALIGNED(st.stack_off,8)){ + st.stack_off+=4; + dasm_put(Dst, 319); + } + dasm_put(Dst, 321); + st.stack_off+=8; + } + #else + load_float(Dst,&st,8,ARM_HF,8); + #endif + dasm_put(Dst, 323); + break; + + default: + luaL_error(L, "NYI: callback arg type"); + } + } + } + + lua_rawgeti(L, ct_usr, 0); + mt = (const struct ctype*) lua_touserdata(L, -1); + + dasm_put(Dst, 327, ((mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0), nargs); + + + if (mt->pointers || mt->is_reference) { + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + dasm_put(Dst, 335, num_upvals-1, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + goto single_no_pop; + } else { + switch (mt->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ + int isfloat,hfasize=0; + if(mt->type!=UNION_TYPE){ + hfasize=hfa_size(L,-1,mt,&isfloat); + } + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + dasm_put(Dst, 351, num_upvals-1, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + #if ARM_HF + if(hfasize>0){ + switch(hfasize){ + case 8: + dasm_put(Dst, 372); + break; + case 6: + dasm_put(Dst, 374); + break; + case 4: + dasm_put(Dst, 376); + break; + case 3: + dasm_put(Dst, 378); + break; + case 2: + dasm_put(Dst, 380); + break; + case 1: + dasm_put(Dst, 382); + break; + } + }else + #endif + if(!mt->is_empty){ + if(mt->base_size<=4){ + dasm_put(Dst, 384); + }else{ + dasm_put(Dst, 386, st.extra+0x40*1, (unsigned short)(mt->base_size), (((unsigned int)(mt->base_size))>>16), (unsigned short)(memcpy), (((unsigned int)(memcpy))>>16)); + } + } + break; + } + case ENUM_TYPE: + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + + dasm_put(Dst, 399, num_upvals-1, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + + goto single_no_pop; + + case VOID_TYPE: + dasm_put(Dst, 415); + lua_pop(L, 1); + break; + + case BOOL_TYPE: + case INT8_TYPE:// narrow it + case INT16_TYPE:// narrow it + case INT32_TYPE: + dasm_put(Dst, 420); + if (mt->is_unsigned) { + dasm_put(Dst, 422); + } else { + dasm_put(Dst, 426); + } + switch(mt->type){ + case BOOL_TYPE: + dasm_put(Dst, 430); + break; + case INT8_TYPE: + if (mt->is_unsigned) { + dasm_put(Dst, 433); + } else { + dasm_put(Dst, 435); + } + break; + case INT16_TYPE: + if (mt->is_unsigned) { + dasm_put(Dst, 437); + } else { + dasm_put(Dst, 439); + } + break; + } + goto single; + + case INT64_TYPE: + dasm_put(Dst, 441); + if (mt->is_unsigned) { + dasm_put(Dst, 443); + } else { + dasm_put(Dst, 447); + } + goto dual; + + case INTPTR_TYPE: + dasm_put(Dst, 451); + goto single; + + case FLOAT_TYPE: + dasm_put(Dst, 456); + #if ARM_HF + dasm_put(Dst, 461); + lua_pop(L, 1); + #else + goto single; + #endif + break; + case DOUBLE_TYPE: + dasm_put(Dst, 468); + #if ARM_HF + dasm_put(Dst, 473); + lua_pop(L, 1); + #else + goto dual; + #endif + break; + case COMPLEX_DOUBLE_TYPE: + lua_pop(L, 1); + dasm_put(Dst, 480); + break; + case COMPLEX_FLOAT_TYPE: + lua_pop(L, 1); + dasm_put(Dst, 491); + break; + + single: + lua_pop(L, 1); + single_no_pop: + dasm_put(Dst, 502); + + break; + dual: + dasm_put(Dst, 509); + + lua_pop(L, 1); + break; + + + + default: + luaL_error(L, "NYI: callback return type"); + } + } + + dasm_put(Dst, 518); + + lua_pop(L, 1); /* upval table - already in registry */ + assert(lua_gettop(L) == top); + + { + void* p; + struct ctype ft; + cfunction func; + + func = compile(Dst, L, NULL, ref); + + ft = *ct; + ft.is_jitted = 1; + p = push_cdata(L, ct_usr, &ft); + *(cfunction*) p = func; + + assert(lua_gettop(L) == top + 1); + + return func; + } +} + +static ALWAYS_INLINE void save_int64_stack_align(struct jit* Dst,reg_info* regs,int align){ + if(align&&!ALIGNED(regs->exs,2)){ + regs->exs++; + dasm_put(Dst, 520); + } + dasm_put(Dst, 522); + regs->exs+=2; +} + +static ALWAYS_INLINE void save_int64_align(struct jit* Dst,reg_info* regs,int align){ + if((align&&!ALIGNED(regs->ints,2))||(regs->ints==MAX_REGS-1&®s->exs/*to ensure consective memory*/)){ + regs->ints++; + } + if(regs->intsints<<2)+0x40*1)); + regs->ints+=2; + }else{ + save_int64_stack_align(Dst,regs,align); + } + +} + +static ALWAYS_INLINE void save_int64(struct jit* Dst,reg_info* regs){ + save_int64_align(Dst,regs,1); +} + +static ALWAYS_INLINE void save_int_stack_align(struct jit* Dst,reg_info* regs){ + dasm_put(Dst, 528); + regs->exs++; +} + +static ALWAYS_INLINE void save_int(struct jit* Dst,reg_info* regs){ + if(regs->intsints++<<2)+0x40*1)); + }else{ + save_int_stack_align(Dst,regs); + } +} + +static void save_float(struct jit* Dst,reg_info* regs,int size,int isfloat){ +#if ARM_HF + if(!regs->float_sealed){ + int reg=add_float_reg(regs,size,isfloat); + if(reg<0) goto SAVE_STACK; + switch(size){ + case 8: + dasm_put(Dst, 533, (reg<<2)+24); + case 6: + dasm_put(Dst, 536, (reg<<2)+16); + case 4: + dasm_put(Dst, 539, (reg<<2)+8); + goto sf_2; + case 3: + dasm_put(Dst, 542, (reg<<2)+8); + case 2: + sf_2: + dasm_put(Dst, 545, (reg<<2)); + break; + case 1: + dasm_put(Dst, 548, (reg<<2)); + break; + } + return; + } + SAVE_STACK: + + if(!isfloat&&!ALIGNED(regs->exs,2)){ + regs->exs++; + dasm_put(Dst, 551); + } + switch(size){ + case 1: + dasm_put(Dst, 553); + break; + case 2: + dasm_put(Dst, 555); + break; + case 3: + dasm_put(Dst, 557); + break; + case 4: + dasm_put(Dst, 559); + break; + case 6: + dasm_put(Dst, 561); + break; + case 8: + dasm_put(Dst, 563); + break; + + } + regs->exs+=size; + +#else + if(size==1){ + save_int(Dst,regs); + }else if(size==2){ + save_int64_align(Dst,regs,!isfloat); + } +#endif +} + +static int calculate_stack(lua_State* L,int ct_usr,int nargs){ + const struct ctype* mt; + reg_info regs;int i,stack=0; + memset(®s,0,sizeof(reg_info)); + for (i = 1; i <= nargs;++i){ + lua_rawgeti(L, ct_usr, i); + mt = (const struct ctype*) lua_touserdata(L, -1); + if (mt->pointers || mt->is_reference) { + stack+=add_int_reg(®s); + }else{ + switch(mt->type){ + case COMPLEX_DOUBLE_TYPE: + #if ARM_HF + stack+=add_float_reg(®s,4,0)<0?4:0; + #else + stack+=add_int64_reg(®s); + stack+=add_int64_reg(®s); + #endif + FIX_ALIGN(stack,2); + break; + case DOUBLE_TYPE: + #if ARM_HF + stack+=add_float_reg(®s,2,0)<0?2:0; + #else + stack+=add_int64_reg(®s); + #endif + FIX_ALIGN(stack,2); + break; + case COMPLEX_FLOAT_TYPE:// Though complex alignment is 4, but vfp requires a sequence of regsiters + #if ARM_HF + stack+=add_float_reg(®s,2,1)<0?2:0; + #else + stack+=add_int_reg(®s); + stack+=add_int_reg(®s); + #endif + break; + case FLOAT_TYPE: + #if ARM_HF + stack+=add_float_reg(®s,1,1)<0?1:0; + #else + stack+=add_int_reg(®s); + #endif + break; + case INT64_TYPE: + stack+=add_int64_reg(®s); + FIX_ALIGN(stack,2); + break; + case STRUCT_TYPE:{ + #if ARM_HF + int isfloat; + int hfasize=hfa_size(L,-1,mt,&isfloat); + if(hfasize>0){ + stack+=add_float_reg(®s,2,0)<0?hfasize:0; + if(!isfloat){ + FIX_ALIGN(stack,2); + } + break; + } + #endif + } + case UNION_TYPE:{ + int intsize=(mt->base_size+3)>>2; + if(mt->align_mask>4){//8-byte max alignment + if(regs.intspointers && !mt->is_reference &&(mt->type==STRUCT_TYPE || mt->type==UNION_TYPE|| + (!ARM_HF&&(mt->type==COMPLEX_DOUBLE_TYPE||mt->type==COMPLEX_FLOAT_TYPE)))&&mt->base_size>4&&!(ARM_HF&&hfa_size(L,-1,mt,NULL)); + lua_pop(L,1); + if(ret_by_addr){ + if(stack_size==0) + stack_size=0x40*ARM_HF+0x10; + stack_size+=8; + } + if(stack_size>0){ + if(stack_size>=1<<12){ + dasm_put(Dst, 575, (unsigned short)(stack_size), (((unsigned int)(stack_size))>>16)); + }else{ + dasm_put(Dst, 581, stack_size); + } + if (ct->has_var_arg){ + dasm_put(Dst, 584, nargs, (unsigned short)("too few arguments"), (((unsigned int)("too few arguments"))>>16)); + } + dasm_put(Dst, 601, 0x40*1+0x10); + } + + memset(®s,0,sizeof(reg_info)); + + if (ret_by_addr) { + regs.ints++; + dasm_put(Dst, 604, (unsigned short)(mt), (((unsigned int)(mt))>>16), 0x40*1); + } + + + for (i = 1; i <= nargs; i++) { + lua_rawgeti(L, ct_usr, i); + mt = (const struct ctype*) lua_touserdata(L, -1); + + if (mt->pointers || mt->is_reference || mt->type == FUNCTION_PTR_TYPE || mt->type == ENUM_TYPE|| mt->type==STRUCT_TYPE || mt->type==UNION_TYPE) { + lua_getuservalue(L, -1); + num_upvals += 2; + + dasm_put(Dst, 615, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)(lua_upvalueindex(num_upvals)), (((unsigned int)(lua_upvalueindex(num_upvals)))>>16), i); + + if (mt->pointers || mt->is_reference) { + dasm_put(Dst, 626); + } else if (mt->type == FUNCTION_PTR_TYPE) { + dasm_put(Dst, 630); + } else if (mt->type == ENUM_TYPE) { + dasm_put(Dst, 634); + }else if(mt->type==STRUCT_TYPE || mt->type==UNION_TYPE){ + if(mt->is_empty) continue; + dasm_put(Dst, 638); + #if ARM_HF + { + int hfasize,isfloat; + hfasize=hfa_size(L,-2,mt,&isfloat); + if(hfasize){ + switch(hfasize){ + case 8: + dasm_put(Dst, 642); + break; + case 6: + dasm_put(Dst, 644); + break; + case 4: + dasm_put(Dst, 646); + break; + case 3: + dasm_put(Dst, 648); + break; + case 2: + dasm_put(Dst, 650); + break; + case 1: + dasm_put(Dst, 652); + break; + + } + save_float(Dst,®s,hfasize,isfloat); + continue; + } + } + #endif + + if(mt->align_mask>4){//8 byte max alignment + if(regs.ints<4){ + FIX_ALIGN(regs.ints,2) + }else if(!ALIGNED(regs.exs,2)){ + int diff=regs.exs; + regs.exs+=4; + dasm_put(Dst, 654); + } + } + int size=ROUND_UP(mt->base_size,4)>>2; + dasm_put(Dst, 656, (unsigned short)(mt->base_size), (((unsigned int)(mt->base_size))>>16), (unsigned short)(memcpy), (((unsigned int)(memcpy))>>16)); + if(regs.intstype) { + case BOOL_TYPE: + dasm_put(Dst, 679); + save_int(Dst,®s); + break; + case INT8_TYPE: + dasm_put(Dst, 685); + if (mt->is_unsigned) { + dasm_put(Dst, 689); + } else { + dasm_put(Dst, 691); + } + save_int(Dst,®s); + break; + + case INT16_TYPE: + dasm_put(Dst, 693); + if (mt->is_unsigned) { + dasm_put(Dst, 697); + } else { + dasm_put(Dst, 699); + } + save_int(Dst,®s); + break; + + case INT32_TYPE: + if (mt->is_unsigned) { + dasm_put(Dst, 701); + } else { + dasm_put(Dst, 705); + } + save_int(Dst,®s); + break; + case INTPTR_TYPE: + dasm_put(Dst, 709); + save_int(Dst,®s); + break; + + case INT64_TYPE: + if (mt->is_unsigned) { + dasm_put(Dst, 713); + } else { + dasm_put(Dst, 717); + } + save_int64(Dst,®s); + break; + + case DOUBLE_TYPE: + dasm_put(Dst, 721); + save_float(Dst,®s,2,0); + break; + + case FLOAT_TYPE: + dasm_put(Dst, 725); + save_float(Dst,®s,1,1); + break; + + case COMPLEX_DOUBLE_TYPE: + #if ARM_HF + dasm_put(Dst, 729); + save_float(Dst,®s,4,0); + #else + FIX_ALIGN(regs.ints,2); + if(regs.intsMAX_REGS){ + regs.exs+=regs.ints-MAX_REGS; + regs.ints=MAX_REGS; + } + #endif + break; + default: + luaL_error(L, "NYI: call arg type"); + } + } + } + + if (ct->has_var_arg) { + int offset=nargs+1; + dasm_put(Dst, 737, offset); + #if ARM_HF + if(regs.ints==4||regs.float_sealed){ + if(regs.ints<4&®s.float_sealed){//some arg must be loaded to core registers. + dasm_put(Dst, 740, ((regs.ints<<2)+0x40), (0x10+0x40), offset); + } + dasm_put(Dst, 750); + } + #else + if(regs.ints==4){ + } + #endif + else{//no hard floating point in variadic procedure + dasm_put(Dst, 752, ((regs.ints<<2)+1*0x40)); + } + + dasm_put(Dst, 755); + regs.ints=4; + } + + #if ARM_HF + switch(ROUND_UP(regs.highest_bit,4)>>1){ + case 8 : + dasm_put(Dst, 760); + break; + case 7 : + dasm_put(Dst, 762); + break; + case 6 : + dasm_put(Dst, 764); + break; + case 5: + dasm_put(Dst, 766); + break; + case 4 : + dasm_put(Dst, 768); + break; + case 3 : + dasm_put(Dst, 770); + break; + case 2 : + dasm_put(Dst, 772); + break; + case 1 : + dasm_put(Dst, 774); + break; + } + if(stack_size>0){ + dasm_put(Dst, 776); + } + #endif + + //pop registers from stack,align 8 for some compiler + assert(regs.ints<=4); + switch(regs.ints){ + case 4: + case 3: + dasm_put(Dst, 778); + break; + case 2: + case 1: + dasm_put(Dst, 780); + #if ARM_HF + if(regs.float_sealed){ + dasm_put(Dst, 782); + } + #endif + break; + default: + #if ARM_HF + if(regs.float_sealed){ + dasm_put(Dst, 784); + } + #endif + break; + } + + dasm_put(Dst, 786, (unsigned short)(func), (((unsigned int)(func))>>16)); + + lua_rawgeti(L, ct_usr, 0); + mt = (const struct ctype*) lua_touserdata(L, -1); + + if (mt->pointers || mt->is_reference || mt->type==FUNCTION_PTR_TYPE) { + lua_getuservalue(L, -1); + num_upvals += 2; + dasm_put(Dst, 792, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)(lua_upvalueindex(num_upvals)), (((unsigned int)(lua_upvalueindex(num_upvals)))>>16)); + + } else { + switch (mt->type) { + case INT64_TYPE: + #if LUA_VERSION_NUM>=503 + lua_pop(L, 1); + #if CK_ALGIN + dasm_put(Dst, 807); + #else + dasm_put(Dst, 810); + #endif + dasm_put(Dst, 813); + break; + #else + num_upvals++; + dasm_put(Dst, 818, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + break; + #endif + + case INTPTR_TYPE: + num_upvals++; + dasm_put(Dst, 832, (unsigned short)(mt), (((unsigned int)(mt))>>16)); + break; + + case VOID_TYPE: + lua_pop(L, 1); + dasm_put(Dst, 844); + break; + + case BOOL_TYPE: + lua_pop(L, 1); + dasm_put(Dst, 846); + break; + + case INT8_TYPE: + case INT16_TYPE: + case INT32_TYPE: + case ENUM_TYPE:// value must be narrowed before callee return + lua_pop(L, 1); + + dasm_put(Dst, 852); + if (mt->is_unsigned) { + dasm_put(Dst, 854); + } else { + dasm_put(Dst, 858); + } + + dasm_put(Dst, 862); + break; + + case FLOAT_TYPE: + lua_pop(L, 1); + dasm_put(Dst, 864); + break; + + case DOUBLE_TYPE: + lua_pop(L, 1); + #if CK_ALGIN + #else + #endif + dasm_put(Dst, 869); + break; + case COMPLEX_DOUBLE_TYPE: + case COMPLEX_FLOAT_TYPE: + case STRUCT_TYPE: + case UNION_TYPE:{ + lua_getuservalue(L,-1); + num_upvals += 2; + #if ARM_HF + { + int isfloat,hfasize=hfa_size(L,-2,mt,&isfloat); + if(hfasize>0){ + switch(hfasize){ + case 8: + dasm_put(Dst, 874); + break; + case 6: + dasm_put(Dst, 876); + break; + case 4: + case 3: + dasm_put(Dst, 878); + break; + case 2: + case 1: + dasm_put(Dst, 880); + break; + + } + dasm_put(Dst, 882, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)(lua_upvalueindex(num_upvals)), (((unsigned int)(lua_upvalueindex(num_upvals)))>>16)); + switch(hfasize){ + case 8: + dasm_put(Dst, 895); + break; + case 6: + dasm_put(Dst, 898); + break; + case 4: + dasm_put(Dst, 901); + break; + case 3: + dasm_put(Dst, 904); + break; + case 2: + dasm_put(Dst, 907); + break; + case 1: + dasm_put(Dst, 910); + break; + + } + dasm_put(Dst, 913); + break; + } + } + + #endif + if(mt->base_size>4){ + // value are stored in return storage in r0 for softfp, set usr value here + if(!lua_isnil(L,-1)){ + dasm_put(Dst, 915, (unsigned short)(lua_upvalueindex(num_upvals)), (((unsigned int)(lua_upvalueindex(num_upvals)))>>16)); + } + }else if(mt->is_empty){ + dasm_put(Dst, 927); + break; + }else{ + dasm_put(Dst, 929, (unsigned short)(mt), (((unsigned int)(mt))>>16), (unsigned short)(lua_upvalueindex(num_upvals)), (((unsigned int)(lua_upvalueindex(num_upvals)))>>16)); + } + dasm_put(Dst, 943); + break; + } + default: + luaL_error(L, "NYI: call return type"); + } + } + +#ifdef __thumb__ + dasm_put(Dst, 945); +#else + dasm_put(Dst, 948); +#endif + assert(lua_gettop(L) == top + num_upvals); + { + cfunction f = compile(Dst, L, NULL, LUA_NOREF); + /* add a callback as an upval so that the jitted code gets cleaned up when + * the function gets gc'd */ + push_callback(L, f, func); + lua_pushcclosure(L, (lua_CFunction) f, num_upvals+1); + } +} + diff --git a/texk/web2c/luatexdir/luaffi/call_x64.h b/texk/web2c/luatexdir/luaffi/call_x64.h index 5cf89a0fc0..b582c6f10a 100644 --- a/texk/web2c/luatexdir/luaffi/call_x64.h +++ b/texk/web2c/luatexdir/luaffi/call_x64.h @@ -1,14 +1,10 @@ /* ** This file has been pre-processed with DynASM. ** http://luajit.org/dynasm.html -** DynASM version 1.3.0, DynASM x64 version 1.3.0 -** DO NOT EDIT! The original file is in "call_x86.dasc". +** DynASM version 1.4.0, DynASM x64 version 1.4.0 +** DO NOT EDIT! The original file is in "/home/luigisvn/lua/ravi-ffi-master-for-luaffi/call_x86.dasc". */ -#if DASM_VERSION != 10300 -#error "Version mismatch between DynASM and included encoding engine" -#endif - /* vim: ts=4 sw=4 sts=4 et tw=78 * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved. * Portions copyright (c) 2011 James R. McKaskill. @@ -17,126 +13,133 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +#if DASM_VERSION != 10400 +#error "Version mismatch between DynASM and included encoding engine" +#endif -static const unsigned char build_actionlist[2157] = { - 72,139,141,233,255,72,137,132,253,36,233,255,221,133,233,255,217,133,233, - 255,252,243,15,126,133,233,255,252,243,15,90,133,233,255,221,156,253,36,233, - 255,217,156,253,36,233,255,102,15,214,132,253,36,233,255,252,242,15,90,192, - 102,15,214,132,253,36,233,255,252,242,15,90,192,102,15,126,132,253,36,233, - 255,85,72,137,229,65,84,72,129,252,236,239,102,15,214,69,252,240,102,15,214, - 77,232,102,15,214,85,224,102,15,214,93,216,102,15,214,101,208,102,15,214, - 109,200,102,15,214,117,192,102,15,214,125,184,72,137,125,176,72,137,117,168, - 72,137,85,160,72,137,77,152,76,137,69,144,76,137,77,136,255,73,188,237,237, - 255,72,199,194,237,72,199,198,237,76,137,231,232,251,1,0,255,72,199,194,237, - 72,199,198,252,255,252,255,252,255,252,255,76,137,231,232,251,1,0,255,72, - 199,194,237,72,199,198,237,76,137,231,232,251,1,0,72,186,237,237,72,199,198, - 252,255,252,255,252,255,252,255,76,137,231,232,251,1,1,255,72,137,8,72,199, - 198,252,254,252,255,252,255,252,255,76,137,231,232,251,1,2,255,72,186,237, - 237,72,199,198,0,0,0,0,76,137,231,232,251,1,1,255,72,137,8,255,102,15,214, - 0,255,217,24,255,217,88,4,255,102,15,214,64,8,255,76,137,231,232,251,1,3, - 255,15,182,201,72,137,206,76,137,231,232,251,1,4,255,15,182,201,255,15,190, - 201,255,72,137,206,76,137,231,232,251,1,5,255,15,183,201,255,15,191,201,255, - 72,137,206,76,137,231,232,251,1,6,255,72,185,237,237,72,199,194,237,72,199, - 198,237,76,137,231,232,251,1,7,255,72,199,194,237,72,199,198,252,254,252, - 255,252,255,252,255,76,137,231,232,251,1,0,72,185,237,237,72,199,194,252, - 255,252,255,252,255,252,255,72,199,198,252,254,252,255,252,255,252,255,76, - 137,231,232,251,1,8,72,137,68,36,32,72,199,198,252,252,252,255,252,255,252, - 255,76,137,231,232,251,1,9,72,139,68,36,32,255,72,199,194,237,72,199,198, - 252,254,252,255,252,255,252,255,76,137,231,232,251,1,0,72,185,237,237,72, - 199,194,252,255,252,255,252,255,252,255,72,199,198,252,254,252,255,252,255, - 252,255,76,137,231,232,251,1,10,137,68,36,32,72,199,198,252,252,252,255,252, - 255,252,255,76,137,231,232,251,1,9,139,68,36,32,255,72,199,198,252,254,252, - 255,252,255,252,255,76,137,231,232,251,1,9,255,72,199,198,252,255,252,255, - 252,255,252,255,76,137,231,232,251,1,11,255,72,199,198,252,255,252,255,252, - 255,252,255,76,137,231,232,251,1,12,255,137,68,36,32,72,199,198,252,253,252, - 255,252,255,252,255,76,137,231,232,251,1,9,139,68,36,32,255,72,199,198,252, - 255,252,255,252,255,252,255,76,137,231,232,251,1,13,255,72,199,198,252,255, - 252,255,252,255,252,255,76,137,231,232,251,1,14,255,72,137,68,36,32,72,199, - 198,252,253,252,255,252,255,252,255,76,137,231,232,251,1,9,72,139,68,36,32, - 255,72,199,198,252,255,252,255,252,255,252,255,76,137,231,232,251,1,15,72, - 137,68,36,32,72,199,198,252,253,252,255,252,255,252,255,76,137,231,232,251, - 1,9,72,139,68,36,32,255,72,199,198,252,255,252,255,252,255,252,255,76,137, - 231,232,251,1,16,102,15,214,68,36,32,72,199,198,252,253,252,255,252,255,252, - 255,76,137,231,232,251,1,9,255,252,242,15,90,68,36,32,255,252,243,15,126, - 68,36,32,255,72,199,198,252,255,252,255,252,255,252,255,76,137,231,232,251, - 1,17,102,15,214,68,36,32,72,199,198,252,253,252,255,252,255,252,255,76,137, - 231,232,251,1,9,252,243,15,126,68,36,32,255,72,199,198,252,255,252,255,252, - 255,252,255,76,137,231,232,251,1,18,102,15,214,68,36,32,102,15,214,76,36, - 40,72,199,198,252,253,252,255,252,255,252,255,76,137,231,232,251,1,9,252, - 243,15,126,68,36,32,252,243,15,126,76,36,40,255,72,139,141,233,72,199,194, - 252,255,252,255,252,255,252,255,76,137,230,72,137,207,232,251,1,18,72,131, - 252,236,4,72,199,198,252,253,252,255,252,255,252,255,76,137,231,232,251,1, - 9,255,76,139,101,252,248,72,137,252,236,93,194,236,255,85,72,137,229,65,84, - 65,85,73,137,252,252,76,137,231,232,251,1,19,73,137,197,72,129,252,248,239, - 255,15,141,244,248,102,184,0,0,72,190,237,237,76,137,231,232,251,1,20,248, - 2,15,142,244,247,102,184,0,0,72,190,237,237,76,137,231,232,251,1,20,255,15, - 141,244,247,102,184,0,0,72,190,237,237,76,137,231,232,251,1,20,255,248,1, - 255,72,193,224,4,72,41,196,72,129,252,236,239,255,72,186,237,237,72,199,198, - 0,0,0,0,76,137,231,232,251,1,1,72,131,252,236,16,255,72,185,237,237,72,199, - 194,237,72,199,198,237,76,137,231,232,251,1,8,255,72,185,237,237,72,199,194, - 237,72,199,198,237,76,137,231,232,251,1,21,255,72,185,237,237,72,199,194, - 237,72,199,198,237,76,137,231,232,251,1,10,255,72,199,198,237,76,137,231, - 232,251,1,12,255,15,182,192,255,15,190,192,255,15,183,192,255,15,191,192, - 255,72,199,198,237,76,137,231,232,251,1,12,131,252,248,0,15,149,208,15,182, - 192,255,72,199,198,237,76,137,231,232,251,1,11,255,72,199,198,237,76,137, - 231,232,251,1,15,255,72,199,198,237,76,137,231,232,251,1,13,255,72,199,198, - 237,76,137,231,232,251,1,14,255,72,199,198,237,76,137,231,232,251,1,16,255, - 72,199,198,237,76,137,231,232,251,1,18,255,252,243,15,126,193,255,72,141, - 132,253,36,233,72,131,252,236,4,72,199,194,237,76,137,230,72,137,199,232, - 251,1,18,255,72,199,198,237,76,137,231,232,251,1,17,255,72,199,198,237,76, - 137,231,232,251,1,17,137,4,36,217,4,36,255,137,20,36,217,4,36,255,72,137, - 224,72,129,192,239,73,137,192,72,199,193,237,76,137,252,234,72,199,198,237, - 76,137,231,232,251,1,22,255,72,137,224,72,129,192,239,73,137,192,72,199,193, - 237,76,137,252,234,72,199,198,237,76,137,231,232,251,1,23,255,72,137,224, - 72,129,192,239,73,137,193,73,199,192,237,72,199,193,237,76,137,252,234,72, - 199,198,237,76,137,231,232,251,1,24,255,72,185,237,237,139,1,72,137,199,232, - 251,1,25,255,72,131,196,32,255,252,243,15,126,188,253,36,233,255,252,243, - 15,126,180,253,36,233,255,252,243,15,126,172,253,36,233,255,252,243,15,126, - 164,253,36,233,255,252,243,15,126,156,253,36,233,255,252,243,15,126,148,253, - 36,233,255,252,243,15,126,140,253,36,233,255,252,243,15,126,132,253,36,233, - 255,76,139,140,253,36,233,255,76,139,132,253,36,233,255,72,139,140,253,36, - 233,255,72,139,148,253,36,233,255,72,139,180,253,36,233,255,72,139,60,36, - 255,72,129,196,239,255,176,8,255,232,251,1,26,72,131,252,236,48,255,72,137, - 68,36,32,232,251,1,27,72,185,237,237,137,1,72,186,237,237,72,199,198,237, - 76,137,231,232,251,1,1,72,139,76,36,32,72,137,8,184,1,0,0,0,76,139,109,252, - 240,76,139,101,252,248,72,137,252,236,93,195,255,72,137,68,36,32,232,251, - 1,27,72,185,237,237,137,1,72,139,68,36,32,72,137,198,76,137,231,232,251,1, - 28,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252,236,93,195, - 255,72,137,68,36,32,232,251,1,27,72,185,237,237,137,1,72,186,237,237,72,199, - 198,0,0,0,0,76,137,231,232,251,1,1,72,139,76,36,32,72,137,8,184,1,0,0,0,76, - 139,109,252,240,76,139,101,252,248,72,137,252,236,93,195,255,102,15,214,68, - 36,32,232,251,1,27,72,185,237,237,137,1,72,186,237,237,72,199,198,237,76, - 137,231,232,251,1,1,72,139,76,36,32,72,137,8,184,1,0,0,0,76,139,109,252,240, - 76,139,101,252,248,72,137,252,236,93,195,255,102,15,214,76,36,40,102,15,214, - 68,36,32,232,251,1,27,72,185,237,237,137,1,72,186,237,237,72,199,198,237, - 76,137,231,232,251,1,1,72,139,76,36,40,72,137,72,8,72,139,76,36,32,72,137, - 8,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252,236,93,195, - 255,232,251,1,27,72,185,237,237,137,1,184,0,0,0,0,76,139,109,252,240,76,139, - 101,252,248,72,137,252,236,93,195,255,15,182,192,137,68,36,32,232,251,1,27, - 72,185,237,237,137,1,139,68,36,32,72,137,198,76,137,231,232,251,1,4,184,1, - 0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252,236,93,195,255,137, - 68,36,32,232,251,1,27,72,185,237,237,137,1,139,68,36,32,72,137,198,76,137, - 231,232,251,1,5,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137, - 252,236,93,195,255,137,68,36,32,232,251,1,27,72,185,237,237,137,1,139,68, - 36,32,72,137,198,76,137,231,232,251,1,6,184,1,0,0,0,76,139,109,252,240,76, - 139,101,252,248,72,137,252,236,93,195,255,252,243,15,90,192,102,15,214,68, - 36,32,232,251,1,27,72,185,237,237,137,1,252,243,15,126,68,36,32,76,137,231, - 232,251,1,3,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252, - 236,93,195,255 +static const unsigned char build_actionlist[2161] = { + 72,199,198,237,76,137,231,232,251,1,0,72,199,198,252,254,252,255,252,255, + 252,255,76,137,231,232,251,1,1,255,72,139,141,233,255,72,137,132,253,36,233, + 255,221,133,233,255,217,133,233,255,252,243,15,126,133,233,255,252,243,15, + 90,133,233,255,221,156,253,36,233,255,217,156,253,36,233,255,102,15,214,132, + 253,36,233,255,252,242,15,90,192,102,15,214,132,253,36,233,255,252,242,15, + 90,192,102,15,126,132,253,36,233,255,85,72,137,229,65,84,72,129,252,236,239, + 102,15,214,69,252,240,102,15,214,77,232,102,15,214,85,224,102,15,214,93,216, + 102,15,214,101,208,102,15,214,109,200,102,15,214,117,192,102,15,214,125,184, + 72,137,125,176,72,137,117,168,72,137,85,160,72,137,77,152,76,137,69,144,76, + 137,77,136,255,73,188,237,237,255,72,199,194,237,72,199,198,237,76,137,231, + 232,251,1,2,255,72,199,194,237,72,199,198,252,255,252,255,252,255,252,255, + 76,137,231,232,251,1,2,255,72,199,194,237,72,199,198,237,76,137,231,232,251, + 1,2,72,186,237,237,72,199,198,252,255,252,255,252,255,252,255,76,137,231, + 232,251,1,3,255,72,137,8,72,199,198,252,254,252,255,252,255,252,255,76,137, + 231,232,251,1,4,255,102,15,214,0,255,102,15,214,64,8,255,72,141,141,233,72, + 199,194,237,72,137,206,72,137,199,232,251,1,5,255,72,137,8,255,72,137,72, + 8,255,72,137,206,76,137,231,232,251,1,6,255,72,186,237,237,72,199,198,0,0, + 0,0,76,137,231,232,251,1,3,255,76,137,231,232,251,1,7,255,15,182,201,72,137, + 206,76,137,231,232,251,1,8,255,15,182,201,255,15,190,201,255,72,137,206,76, + 137,231,232,251,1,9,255,15,183,201,255,15,191,201,255,72,137,206,76,137,231, + 232,251,1,10,255,72,199,194,237,72,199,198,237,76,137,231,232,251,1,11,255, + 72,199,194,237,72,199,198,252,254,252,255,252,255,252,255,76,137,231,232, + 251,1,2,72,185,237,237,72,199,194,252,255,252,255,252,255,252,255,72,199, + 198,252,254,252,255,252,255,252,255,76,137,231,232,251,1,12,72,137,68,36, + 32,72,199,198,252,252,252,255,252,255,252,255,76,137,231,232,251,1,13,72, + 139,68,36,32,255,72,199,194,237,72,199,198,252,254,252,255,252,255,252,255, + 76,137,231,232,251,1,2,72,185,237,237,72,199,194,252,255,252,255,252,255, + 252,255,72,199,198,252,254,252,255,252,255,252,255,76,137,231,232,251,1,14, + 137,68,36,32,72,199,198,252,252,252,255,252,255,252,255,76,137,231,232,251, + 1,13,139,68,36,32,255,72,199,198,252,254,252,255,252,255,252,255,76,137,231, + 232,251,1,13,255,72,199,198,252,255,252,255,252,255,252,255,76,137,231,232, + 251,1,15,255,72,199,198,252,255,252,255,252,255,252,255,76,137,231,232,251, + 1,16,255,137,68,36,32,72,199,198,252,253,252,255,252,255,252,255,76,137,231, + 232,251,1,13,139,68,36,32,255,72,199,198,252,255,252,255,252,255,252,255, + 76,137,231,232,251,1,17,255,72,199,198,252,255,252,255,252,255,252,255,76, + 137,231,232,251,1,18,255,72,137,68,36,32,72,199,198,252,253,252,255,252,255, + 252,255,76,137,231,232,251,1,13,72,139,68,36,32,255,72,199,198,252,255,252, + 255,252,255,252,255,76,137,231,232,251,1,19,72,137,68,36,32,72,199,198,252, + 253,252,255,252,255,252,255,76,137,231,232,251,1,13,72,139,68,36,32,255,72, + 199,198,252,255,252,255,252,255,252,255,76,137,231,232,251,1,20,102,15,214, + 68,36,32,72,199,198,252,253,252,255,252,255,252,255,76,137,231,232,251,1, + 13,255,252,242,15,90,68,36,32,255,252,243,15,126,68,36,32,255,72,199,194, + 237,72,199,198,252,254,252,255,252,255,252,255,76,137,231,232,251,1,2,72, + 185,237,237,72,199,194,252,255,252,255,252,255,252,255,72,199,198,252,254, + 252,255,252,255,252,255,76,137,231,232,251,1,21,72,137,68,36,32,72,199,198, + 252,253,252,255,252,255,252,255,76,137,231,232,251,1,13,72,139,68,36,32,255, + 72,139,0,255,252,243,15,126,0,255,252,243,15,126,0,252,243,15,126,72,8,255, + 72,137,194,72,139,0,72,139,82,8,255,137,194,139,0,139,82,4,255,72,141,141, + 233,72,199,194,237,72,137,198,72,137,207,232,251,1,5,72,141,133,233,255,72, + 199,198,252,255,252,255,252,255,252,255,76,137,231,232,251,1,22,102,15,214, + 68,36,32,72,199,198,252,253,252,255,252,255,252,255,76,137,231,232,251,1, + 13,252,243,15,126,68,36,32,255,72,199,198,252,255,252,255,252,255,252,255, + 76,137,231,232,251,1,23,102,15,214,68,36,32,102,15,214,76,36,40,72,199,198, + 252,253,252,255,252,255,252,255,76,137,231,232,251,1,13,252,243,15,126,68, + 36,32,252,243,15,126,76,36,40,255,76,139,101,252,248,72,137,252,236,93,194, + 236,255,85,72,137,229,65,84,65,85,73,137,252,252,255,72,131,252,236,32,76, + 137,231,232,251,1,24,73,137,197,72,129,252,248,239,15,141,244,247,102,184, + 0,0,72,190,237,237,76,137,231,232,251,1,25,248,1,72,193,224,4,72,41,196,255, + 72,129,252,236,239,255,72,186,237,237,72,199,198,0,0,0,0,76,137,231,232,251, + 1,3,72,131,252,236,16,255,72,185,237,237,72,199,194,237,72,199,198,237,76, + 137,231,232,251,1,12,255,72,185,237,237,72,199,194,237,72,199,198,237,76, + 137,231,232,251,1,26,255,72,185,237,237,72,199,194,237,72,199,198,237,76, + 137,231,232,251,1,14,255,72,199,198,237,76,137,231,232,251,1,16,255,15,182, + 192,255,15,190,192,255,15,183,192,255,15,191,192,255,72,199,198,237,76,137, + 231,232,251,1,16,131,252,248,0,15,149,208,15,182,192,255,72,199,198,237,76, + 137,231,232,251,1,15,255,72,199,198,237,76,137,231,232,251,1,19,255,72,199, + 198,237,76,137,231,232,251,1,17,255,72,199,198,237,76,137,231,232,251,1,18, + 255,72,199,198,237,76,137,231,232,251,1,20,255,72,185,237,237,72,199,194, + 237,72,199,198,237,76,137,231,232,251,1,21,255,252,243,15,126,64,8,255,72, + 137,193,72,139,1,255,72,139,65,8,255,72,141,188,253,36,233,72,199,194,237, + 72,137,198,72,137,252,255,232,251,1,5,255,72,199,198,237,76,137,231,232,251, + 1,23,255,252,243,15,126,193,255,72,199,198,237,76,137,231,232,251,1,22,255, + 72,137,224,72,129,192,239,73,137,192,72,199,193,237,76,137,252,234,72,199, + 198,237,76,137,231,232,251,1,27,255,72,137,224,72,129,192,239,73,137,192, + 72,199,193,237,76,137,252,234,72,199,198,237,76,137,231,232,251,1,28,255, + 72,137,224,72,129,192,239,73,137,193,73,199,192,237,72,199,193,237,76,137, + 252,234,72,199,198,237,76,137,231,232,251,1,29,255,72,131,196,32,255,252, + 243,15,126,188,253,36,233,255,252,243,15,126,180,253,36,233,255,252,243,15, + 126,172,253,36,233,255,252,243,15,126,164,253,36,233,255,252,243,15,126,156, + 253,36,233,255,252,243,15,126,148,253,36,233,255,252,243,15,126,140,253,36, + 233,255,252,243,15,126,132,253,36,233,255,76,139,140,253,36,233,255,76,139, + 132,253,36,233,255,72,139,140,253,36,233,255,72,139,148,253,36,233,255,72, + 139,180,253,36,233,255,72,139,60,36,255,72,129,196,239,255,176,8,255,232, + 251,1,30,72,131,252,236,48,255,72,137,68,36,32,72,186,237,237,72,199,198, + 237,76,137,231,232,251,1,3,72,139,76,36,32,72,137,8,184,1,0,0,0,76,139,109, + 252,240,76,139,101,252,248,72,137,252,236,93,195,255,102,15,214,68,36,32, + 255,102,15,214,76,36,40,255,72,137,68,36,32,255,72,137,84,36,40,255,72,186, + 237,237,72,199,198,237,76,137,231,232,251,1,3,72,139,76,36,32,72,137,8,255, + 72,139,76,36,40,72,137,72,8,255,72,137,198,76,137,231,232,251,1,6,184,1,0, + 0,0,76,139,109,252,240,76,139,101,252,248,72,137,252,236,93,195,255,72,137, + 68,36,32,72,186,237,237,72,199,198,0,0,0,0,76,137,231,232,251,1,3,72,139, + 76,36,32,72,137,8,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137, + 252,236,93,195,255,102,15,214,68,36,32,72,186,237,237,72,199,198,237,76,137, + 231,232,251,1,3,72,139,76,36,32,72,137,8,184,1,0,0,0,76,139,109,252,240,76, + 139,101,252,248,72,137,252,236,93,195,255,102,15,214,76,36,40,102,15,214, + 68,36,32,72,186,237,237,72,199,198,237,76,137,231,232,251,1,3,72,139,76,36, + 40,72,137,72,8,72,139,76,36,32,72,137,8,255,184,0,0,0,0,76,139,109,252,240, + 76,139,101,252,248,72,137,252,236,93,195,255,15,182,192,72,137,198,76,137, + 231,232,251,1,8,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137, + 252,236,93,195,255,72,137,198,76,137,231,232,251,1,9,184,1,0,0,0,76,139,109, + 252,240,76,139,101,252,248,72,137,252,236,93,195,255,72,137,198,76,137,231, + 232,251,1,10,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252, + 236,93,195,255,252,243,15,90,192,76,137,231,232,251,1,7,184,1,0,0,0,76,139, + 109,252,240,76,139,101,252,248,72,137,252,236,93,195,255 }; static const char *const globnames[] = { (const char *)0 }; static const char *const extnames[] = { - "lua_rawgeti", + "lua_pushvalue", + "lua_setuservalue", + "rawgeti", "push_cdata", "lua_remove", + "memcpy", + "lua_pushinteger", "lua_pushnumber", "lua_pushboolean", "push_int", "push_uint", - "lua_callk", + "lua_call", "check_typed_pointer", "lua_settop", "check_enum", @@ -146,6 +149,7 @@ static const char *const extnames[] = { "check_int64", "check_uintptr", "check_double", + "check_struct", "check_complex_float", "check_complex_double", "lua_gettop", @@ -154,10 +158,7 @@ static const char *const extnames[] = { "unpack_varargs_float", "unpack_varargs_int", "unpack_varargs_stack_skip", - "SetLastError", "FUNCTION", - "GetLastError", - "lua_pushinteger", (const char *)0 }; @@ -176,7 +177,6 @@ static const char *const extnames[] = { - #if defined _WIN64 || defined __amd64__ #define JUMP_SIZE 14 #else @@ -216,7 +216,7 @@ static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, u void compile_globals(struct jit* jit, lua_State* L) { struct jit* Dst = jit; - int* perr = &jit->last_errno; + //int* perr = &jit->last_errno; dasm_setup(Dst, build_actionlist); /* Note: since the return code uses EBP to reset the stack pointer, we @@ -228,9 +228,99 @@ void compile_globals(struct jit* jit, lua_State* L) * stack */ + + compile(Dst, L, NULL, LUA_NOREF); } + +#ifdef _WIN64 +#define MAX_REGISTERS(ct) 4 /* rcx, rdx, r8, r9 */ + +#elif defined __amd64__ +#define MAX_INT_REGISTERS(ct) 6 /* rdi, rsi, rdx, rcx, r8, r9 */ +#define MAX_FLOAT_REGISTERS(ct) 8 /* xmm0-7 */ + +#else +#define MAX_INT_REGISTERS(ct) ((ct)->calling_convention == FAST_CALL ? 2 /* ecx, edx */ : 0) +#define MAX_FLOAT_REGISTERS(ct) 0 +#endif + +#if defined(_WIN64)||defined(__amd64__) +#define X64 1 +#else +#define X64 0 +#endif + +struct reg_alloc { +#ifdef _WIN64 + int regs; + int is_float[4]; + int is_int[4]; +#else + int floats; + int ints; +#endif + int off; +}; + +#ifdef _WIN64 +#define REGISTER_STACK_SPACE(ct) (4*8) +#elif defined __amd64__ +#define REGISTER_STACK_SPACE(ct) (14*8) +#else +#define REGISTER_STACK_SPACE(ct) ALIGN_UP(((ct)->calling_convention == FAST_CALL ? 2*4 : 0), 15) +#endif +#if defined __amd64__ +// float struct is passed by xmm0-xmm7 +static int float_reg_size(lua_State* L,int idx, const struct ctype* ct){ + struct ctype* mt; + int i,ct_usr; + if(ct->base_size>16){ + return 0; + } + lua_getuservalue(L,idx); + ct_usr=lua_absindex(L,-1); + for (i = 1;; ++i) { + lua_rawgeti(L,ct_usr,i); + if(lua_isnil(L,-1)){ + lua_pop(L,1); + break; + } + mt=(struct ctype*)lua_touserdata(L,-1); + if((mt->pointers&&!mt->is_array)||mt->is_reference|| + !(mt->type==FLOAT_TYPE||mt->type==DOUBLE_TYPE||((mt->type==STRUCT_TYPE||mt->type==UNION_TYPE)&&float_reg_size(L,-1,mt)))){ + lua_pop(L,2); + return 0; + } + lua_pop(L,1); + } + + lua_pop(L,1); + return (ct->base_size+7)>>3; +} +#endif + +static int return_by_address(const struct ctype* mbr_ct){ + + if(mbr_ct->is_reference|| mbr_ct->pointers) return 0; +#ifdef _WIN64 + return mbr_ct->base_size!=8&&mbr_ct->base_size!=2&&mbr_ct->base_size!=1&&mbr_ct->base_size!=4&& mbr_ct->base_size != 0;; +#elif defined __amd64__ + return mbr_ct->base_size>16; +#else + if(mbr_ct->base_size>8) return 1; + if(mbr_ct->type==STRUCT_TYPE||mbr_ct->type==UNION_TYPE){ + #if defined _WIN32 + return 0; + #else + return 1; + #endif + } + return 0; +#endif +} + int x86_return_size(lua_State* L, int usr, const struct ctype* ct) { int ret = 0; @@ -269,6 +359,10 @@ int x86_return_size(lua_State* L, int usr, const struct ctype* ct) case ENUM_TYPE: ret += 4; break; + case STRUCT_TYPE: + case UNION_TYPE: + ret +=ALIGN_UP(mt->base_size,3); + break; default: return luaL_error(L, "NYI - argument type"); } @@ -281,7 +375,7 @@ int x86_return_size(lua_State* L, int usr, const struct ctype* ct) #if !defined _WIN64 && !defined __amd64__ lua_rawgeti(L, usr, 0); mt = (const struct ctype*) lua_touserdata(L, -1); - if (!mt->pointers && !mt->is_reference && mt->type == COMPLEX_DOUBLE_TYPE) { + if (return_by_address(mt)) { ret += sizeof(void*); } lua_pop(L, 1); @@ -290,37 +384,11 @@ int x86_return_size(lua_State* L, int usr, const struct ctype* ct) return ret; } -#ifdef _WIN64 -#define MAX_REGISTERS(ct) 4 /* rcx, rdx, r8, r9 */ - -#elif defined __amd64__ -#define MAX_INT_REGISTERS(ct) 6 /* rdi, rsi, rdx, rcx, r8, r9 */ -#define MAX_FLOAT_REGISTERS(ct) 8 /* xmm0-7 */ - -#else -#define MAX_INT_REGISTERS(ct) ((ct)->calling_convention == FAST_CALL ? 2 /* ecx, edx */ : 0) -#define MAX_FLOAT_REGISTERS(ct) 0 -#endif - -struct reg_alloc { -#ifdef _WIN64 - int regs; - int is_float[4]; - int is_int[4]; -#else - int floats; - int ints; -#endif - int off; -}; - -#ifdef _WIN64 -#define REGISTER_STACK_SPACE(ct) (4*8) -#elif defined __amd64__ -#define REGISTER_STACK_SPACE(ct) (14*8) -#else -#define REGISTER_STACK_SPACE(ct) ALIGN_UP(((ct)->calling_convention == FAST_CALL ? 2*4 : 0), 15) -#endif +static void fix_usr_value(Dst_DECL,lua_State* L, int num_upvals){ + if(!lua_isnil(L,-1)){ + dasm_put(Dst, 0, lua_upvalueindex(num_upvals)); + } +} /* Fastcall: * Uses ecx, edx as first two int registers @@ -336,26 +404,33 @@ static void get_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int /* grab the register from the shadow space */ #ifdef _WIN64 if (reg->regs < MAX_REGISTERS(ct)) { - dasm_put(Dst, 0, 16 + 8*reg->regs); + dasm_put(Dst, 30, 16 + 8*reg->regs); reg->regs++; } #elif __amd64__ if (reg->ints < MAX_INT_REGISTERS(ct)) { - dasm_put(Dst, 0, - 80 - 8*reg->ints); + dasm_put(Dst, 30, - 80 - 8*reg->ints); reg->ints++; } #else if (!is_int64 && reg->ints < MAX_INT_REGISTERS(ct)) { - dasm_put(Dst, 1, - 8 - 4*reg->ints); + dasm_put(Dst, 31, - 8 - 4*reg->ints); reg->ints++; } #endif - else if (is_int64) { - dasm_put(Dst, 0, reg->off); - reg->off += 8; - } else { - dasm_put(Dst, 1, reg->off); - reg->off += 4; + else { +#if X64 + if (reg->off &7) { + reg->off = ALIGN_UP(reg->off,7); + } +#endif + if (is_int64) { + dasm_put(Dst, 30, reg->off); + reg->off += 8; + } else { + dasm_put(Dst, 31, reg->off); + reg->off += 4; + } } } @@ -363,31 +438,31 @@ static void add_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int { #ifdef _WIN64 if (reg->regs < MAX_REGISTERS(ct)) { - dasm_put(Dst, 5, 32 + 8*(reg->regs)); + dasm_put(Dst, 35, 32 + 8*(reg->regs)); reg->is_int[reg->regs++] = 1; } #elif __amd64__ if (reg->ints < MAX_INT_REGISTERS(ct)) { - dasm_put(Dst, 5, 32 + 8*reg->ints); + dasm_put(Dst, 35, 32 + 8*reg->ints); reg->ints++; } #else if (!is_int64 && reg->ints < MAX_INT_REGISTERS(ct)) { - dasm_put(Dst, 5, 32 + 4*reg->ints); + dasm_put(Dst, 35, 32 + 4*reg->ints); reg->ints++; } #endif else { -#if defined _WIN64 || defined __amd64__ - if (reg->off % 8 != 0) { - reg->off += 8 - (reg->off % 8); +#if X64 + if (reg->off &7) { + reg->off = ALIGN_UP(reg->off,7); } #endif if (is_int64) { - dasm_put(Dst, 5, reg->off); + dasm_put(Dst, 35, reg->off); reg->off += 8; } else { - dasm_put(Dst, 6, reg->off); + dasm_put(Dst, 36, reg->off); reg->off += 4; } } @@ -395,13 +470,13 @@ static void add_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int static void get_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_double) { -#if !defined _WIN64 && !defined __amd64__ +#if !X64 assert(MAX_FLOAT_REGISTERS(ct) == 0); if (is_double) { - dasm_put(Dst, 12, reg->off); + dasm_put(Dst, 42, reg->off); reg->off += 8; } else { - dasm_put(Dst, 16, reg->off); + dasm_put(Dst, 46, reg->off); reg->off += 4; } #else @@ -413,20 +488,25 @@ static void get_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, i reg->regs++; } #else - if (reg->floats < MAX_FLOAT_REGISTERS(ct)) { + if (reg->floats< MAX_FLOAT_REGISTERS(ct)) { off = -16 - 8*reg->floats; reg->floats++; } #endif else { - off = reg->off; +#if X64 + if (reg->off % 8 != 0) { + reg->off += 8 - (reg->off % 8); + } +#endif + off = reg->off; reg->off += is_double ? 8 : 4; } if (is_double) { - dasm_put(Dst, 20, off); + dasm_put(Dst, 50, off); } else { - dasm_put(Dst, 27, off); + dasm_put(Dst, 57, off); } #endif } @@ -436,10 +516,10 @@ static void add_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, i #if !defined _WIN64 && !defined __amd64__ assert(MAX_FLOAT_REGISTERS(ct) == 0); if (is_double) { - dasm_put(Dst, 34, reg->off); + dasm_put(Dst, 64, reg->off); reg->off += 8; } else { - dasm_put(Dst, 40, reg->off); + dasm_put(Dst, 70, reg->off); reg->off += 4; } #else @@ -447,29 +527,35 @@ static void add_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, i #ifdef _WIN64 if (reg->regs < MAX_REGISTERS(ct)) { if (is_double) { - dasm_put(Dst, 46, 32 + 8*(reg->regs)); + dasm_put(Dst, 76, 32 + 8*(reg->regs)); } else { - dasm_put(Dst, 54, 32 + 8*(reg->regs)); + dasm_put(Dst, 84, 32 + 8*(reg->regs)); } reg->is_float[reg->regs++] = 1; } #else if (reg->floats < MAX_FLOAT_REGISTERS(ct)) { if (is_double) { - dasm_put(Dst, 46, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats)); + dasm_put(Dst, 76, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats)); } else { - dasm_put(Dst, 54, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats)); + dasm_put(Dst, 84, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats)); } reg->floats++; } #endif - - else if (is_double) { - dasm_put(Dst, 46, reg->off); - reg->off += 8; - } else { - dasm_put(Dst, 67, reg->off); - reg->off += 4; + else { +#if defined _WIN64 || defined __amd64__ + if (reg->off % 8 != 0) { + reg->off += 8 - (reg->off % 8); + } +#endif + if (is_double) { + dasm_put(Dst, 76, reg->off); + reg->off += 8; + } else { + dasm_put(Dst, 97, reg->off); + reg->off += 4; + } } #endif } @@ -524,33 +610,39 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp // setup a stack frame to hold args for the call into lua_call - dasm_put(Dst, 80, 8 + 16 + 32 + REGISTER_STACK_SPACE(ct)); + dasm_put(Dst, 110, 8 + 16 + 32 + REGISTER_STACK_SPACE(ct)); if (ct->calling_convention == FAST_CALL) { } // hardcode the lua_State* value into the assembly - dasm_put(Dst, 157, (unsigned int)((uintptr_t)(L)), (unsigned int)(((uintptr_t)(L))>>32)); + dasm_put(Dst, 187, (unsigned int)((uintptr_t)(L)), (unsigned int)(((uintptr_t)(L))>>32)); /* get the upval table */ - dasm_put(Dst, 162, ref, LUA_REGISTRYINDEX); + dasm_put(Dst, 192, ref, LUA_REGISTRYINDEX); /* get the lua function */ lua_pushvalue(L, fidx); lua_rawseti(L, -2, ++num_upvals); assert(num_upvals == CALLBACK_FUNC_USR_IDX); - dasm_put(Dst, 178, num_upvals); + dasm_put(Dst, 208, num_upvals); + -#if !defined _WIN64 && !defined __amd64__ lua_rawgeti(L, ct_usr, 0); mt = (const struct ctype*) lua_touserdata(L, -1); - if (!mt->pointers && !mt->is_reference && mt->type == COMPLEX_DOUBLE_TYPE) { + if (return_by_address(mt)) { +#if defined _WIN64 + reg.regs++; + hidden_arg_off= 16; +#elif defined __amd64__ + reg.ints++; + hidden_arg_off= -80; +#else hidden_arg_off = reg.off; reg.off += sizeof(void*); +#endif } lua_pop(L, 1); -#else - (void) hidden_arg_off; -#endif + for (i = 1; i <= nargs; i++) { lua_rawgeti(L, ct_usr, i); @@ -563,90 +655,154 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp /* on the lua stack in the callback: * upval tbl, lua func, i-1 args */ - dasm_put(Dst, 201, num_upvals-1, -i-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); + dasm_put(Dst, 231, num_upvals-1, -i-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); get_pointer(Dst, ct, ®); - dasm_put(Dst, 239); + dasm_put(Dst, 269); } else { switch (mt->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ +#if defined __amd64__ + int floats=float_reg_size(L,-1,mt); + +#endif + int size=mt->base_size; + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + /* on the lua stack in the callback: + * upval tbl, lua func, i-1 args + */ + dasm_put(Dst, 231, num_upvals-1, -i-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); +#if defined _WIN64 + { + if(size!=8&&size!=2&&size!=1&&size!=4){ + get_pointer(Dst, ct, ®); + }else{ + get_int(Dst, ct, ®, 1); + } + } + +#elif defined __amd64__ + if(floats>0){ + if(floats>1&®.floats==MAX_FLOAT_REGISTERS(ct)-1){ + reg.floats++;// ensure argument not splited + } + get_float(Dst, ct, ®, 1); + dasm_put(Dst, 291); + if(floats>1){ + get_float(Dst, ct, ®, 1); + dasm_put(Dst, 296); + } + }else if(size>16){ + dasm_put(Dst, 302, reg.off, size); + reg.off+=ALIGN_UP(size,3); + }else { + if(size>8&®.ints==MAX_INT_REGISTERS(ct)-1){ + reg.ints++;// ensure argument not splited + } + get_int(Dst, ct, ®, 1); + dasm_put(Dst, 321); + if(size>8){ + get_int(Dst, ct, ®, 1); + dasm_put(Dst, 325); + } + } +#else + reg.off+=ALIGN_UP(size,3); +#endif + dasm_put(Dst, 272); + break; + } case INT64_TYPE: + #if LUA_VERSION_NUM >=503 + lua_pop(L, 1); + get_int(Dst, ct, ®, 1); + dasm_put(Dst, 330); + #else lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* mt */ lua_pop(L, 1); - dasm_put(Dst, 261, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); + dasm_put(Dst, 341, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); get_int(Dst, ct, ®, 1); - dasm_put(Dst, 280); + dasm_put(Dst, 321); + #endif break; case INTPTR_TYPE: lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* mt */ lua_pop(L, 1); - dasm_put(Dst, 261, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); + dasm_put(Dst, 341, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); get_pointer(Dst, ct, ®); - dasm_put(Dst, 280); + dasm_put(Dst, 321); break; case COMPLEX_FLOAT_TYPE: lua_pop(L, 1); -#if defined _WIN64 || defined __amd64__ + dasm_put(Dst, 341, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); +#if defined _WIN64 + /* complex floats are two floats packed into a int64_t */ + get_int(Dst, ct, ®, 1); +#elif defined __amd64__ /* complex floats are two floats packed into a double */ - dasm_put(Dst, 261, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); get_float(Dst, ct, ®, 1); - dasm_put(Dst, 284); + dasm_put(Dst, 291); #else /* complex floats are real followed by imag on the stack */ - dasm_put(Dst, 261, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); get_float(Dst, ct, ®, 0); - dasm_put(Dst, 289); get_float(Dst, ct, ®, 0); - dasm_put(Dst, 292); #endif break; case COMPLEX_DOUBLE_TYPE: lua_pop(L, 1); - dasm_put(Dst, 261, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); + dasm_put(Dst, 341, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); +#if defined _WIN64 + get_int(Dst, ct, ®, 1); +#else /* real */ get_float(Dst, ct, ®, 1); - dasm_put(Dst, 284); + dasm_put(Dst, 291); /* imag */ get_float(Dst, ct, ®, 1); - dasm_put(Dst, 296); + dasm_put(Dst, 296); +#endif break; case FLOAT_TYPE: case DOUBLE_TYPE: lua_pop(L, 1); get_float(Dst, ct, ®, mt->type == DOUBLE_TYPE); - dasm_put(Dst, 302); + dasm_put(Dst, 360); break; case BOOL_TYPE: lua_pop(L, 1); get_int(Dst, ct, ®, 0); - dasm_put(Dst, 310); + dasm_put(Dst, 368); break; case INT8_TYPE: lua_pop(L, 1); get_int(Dst, ct, ®, 0); if (mt->is_unsigned) { - dasm_put(Dst, 324); + dasm_put(Dst, 382); } else { - dasm_put(Dst, 328); + dasm_put(Dst, 386); } - dasm_put(Dst, 332); + dasm_put(Dst, 390); break; case INT16_TYPE: lua_pop(L, 1); get_int(Dst, ct, ®, 0); if (mt->is_unsigned) { - dasm_put(Dst, 343); + dasm_put(Dst, 401); } else { - dasm_put(Dst, 347); + dasm_put(Dst, 405); } - dasm_put(Dst, 332); + dasm_put(Dst, 390); break; case ENUM_TYPE: @@ -654,9 +810,9 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_pop(L, 1); get_int(Dst, ct, ®, 0); if (mt->is_unsigned) { - dasm_put(Dst, 351); + dasm_put(Dst, 409); } else { - dasm_put(Dst, 332); + dasm_put(Dst, 390); } break; @@ -669,7 +825,7 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_rawgeti(L, ct_usr, 0); mt = (const struct ctype*) lua_touserdata(L, -1); - dasm_put(Dst, 362, (unsigned int)((uintptr_t)(0)), (unsigned int)(((uintptr_t)(0))>>32), (mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0, nargs); + dasm_put(Dst, 420, (mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0, nargs); // Unpack the return argument if not "void", also clean-up the lua stack // to remove the return argument and bind table. Use lua_settop rather @@ -678,7 +834,7 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* usr value */ lua_rawseti(L, -2, ++num_upvals); /* mt */ - dasm_put(Dst, 382, num_upvals-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); + dasm_put(Dst, 436, num_upvals-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); } else { switch (mt->type) { @@ -686,12 +842,12 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* usr value */ lua_rawseti(L, -2, ++num_upvals); /* mt */ - dasm_put(Dst, 466, num_upvals-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); + dasm_put(Dst, 520, num_upvals-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); break; case VOID_TYPE: lua_pop(L, 1); - dasm_put(Dst, 548); + dasm_put(Dst, 602); break; case BOOL_TYPE: @@ -700,64 +856,104 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp case INT32_TYPE: lua_pop(L, 1); if (mt->is_unsigned) { - dasm_put(Dst, 567); + dasm_put(Dst, 621); } else { - dasm_put(Dst, 586); + dasm_put(Dst, 640); } - dasm_put(Dst, 605); + dasm_put(Dst, 659); break; case INT64_TYPE: lua_pop(L, 1); if (mt->is_unsigned) { - dasm_put(Dst, 632); + dasm_put(Dst, 686); } else { - dasm_put(Dst, 651); + dasm_put(Dst, 705); } - dasm_put(Dst, 670); + dasm_put(Dst, 724); break; case INTPTR_TYPE: lua_pop(L, 1); - dasm_put(Dst, 699); + dasm_put(Dst, 753); break; case FLOAT_TYPE: case DOUBLE_TYPE: lua_pop(L, 1); - dasm_put(Dst, 746); + dasm_put(Dst, 800); if (mt->type == FLOAT_TYPE) { - dasm_put(Dst, 789); + dasm_put(Dst, 843); } else { - dasm_put(Dst, 797); + dasm_put(Dst, 851); } break; - + case STRUCT_TYPE: + case UNION_TYPE:{ +#if defined __amd64__ + int floats=float_reg_size(L,-1,mt); +#endif + int size=mt->base_size; + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + dasm_put(Dst, 859, num_upvals-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); +#if defined _WIN64 + if(!return_by_address(mt)){ + dasm_put(Dst, 943); + }else +#elif defined __amd64__ + if(floats){ + if(size<=8){ + dasm_put(Dst, 947); + }else{ + dasm_put(Dst, 953); + } + }else if(size<=16){ + if(size<=8){ + dasm_put(Dst, 943); + }else{ + dasm_put(Dst, 965); + } + }else +#else + #ifdef _WIN32 + if(size<=8){ + if(size<=4){ + dasm_put(Dst, 944); + }else{ + dasm_put(Dst, 976); + } + }else + #endif + +#endif + { + dasm_put(Dst, 984, hidden_arg_off, size, hidden_arg_off); + } + break; + } case COMPLEX_FLOAT_TYPE: lua_pop(L, 1); -#if !defined HAVE_COMPLEX - luaL_error(L, "ffi lib compiled without complex number support"); -#endif + /* on 64 bit complex floats are two floats packed into a double, * on 32 bit returned complex floats use eax and edx */ - dasm_put(Dst, 805); + dasm_put(Dst, 1007); break; case COMPLEX_DOUBLE_TYPE: lua_pop(L, 1); -#if !defined HAVE_COMPLEX - luaL_error(L, "ffi lib compiled without complex number support"); -#endif + /* on 64 bit, returned complex doubles use xmm0, xmm1, on 32 bit * there is a hidden first parameter that points to 16 bytes where * the returned arg is stored which is popped by the called * function */ -#if defined _WIN64 || defined __amd64__ - dasm_put(Dst, 855); +#if defined _WIN64 +#elif defined __amd64__ + dasm_put(Dst, 1057); #else - dasm_put(Dst, 918, hidden_arg_off); #endif break; @@ -766,7 +962,7 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp } } - dasm_put(Dst, 967, x86_return_size(L, ct_usr, ct)); + dasm_put(Dst, 1120, x86_return_size(L, ct_usr, ct)); lua_pop(L, 1); /* upval table - already in registry */ assert(lua_gettop(L) == top); @@ -779,17 +975,47 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp return *pf; } +// leave enough stack for structs +static int caculate_extra_stack(lua_State* L,int ct_usr,size_t nargs){ + const struct ctype* mbr_ct; + int extra=0;int i; + for (i = 1; i <= nargs; i++) { + lua_rawgeti(L, ct_usr, (int) i); + mbr_ct = (const struct ctype*) lua_touserdata(L, -1); + if (!mbr_ct->pointers && !mbr_ct->is_reference) { + switch(mbr_ct->type){ + case STRUCT_TYPE: + case UNION_TYPE: + if(mbr_ct->base_size>16){ + extra+=ALIGN_UP(mbr_ct->base_size,15); + } + #if defined _WIN64 + else if(mbr_ct->base_size>8){ + extra+=16; + } + #endif + break; + #if defined _WIN64 + case COMPLEX_DOUBLE_TYPE: + extra+=16; + break; + #endif + } + } + lua_pop(L,1); + } + return extra; +} void compile_function(lua_State* L, cfunction func, int ct_usr, const struct ctype* ct) { size_t i, nargs; - int num_upvals; + int num_upvals,struct_offset; const struct ctype* mbr_ct; struct jit* Dst = get_jit(L); struct reg_alloc reg; void* p; int top = lua_gettop(L); - int* perr = &Dst->last_errno; ct_usr = lua_absindex(L, ct_usr); @@ -808,33 +1034,37 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty luaL_error(L, "vararg is only allowed with the c calling convention"); } - dasm_put(Dst, 980, nargs); - if (!ct->has_var_arg) { - dasm_put(Dst, 1008, (unsigned int)((uintptr_t)(&"too few arguments")), (unsigned int)(((uintptr_t)(&"too few arguments"))>>32), (unsigned int)((uintptr_t)(&"too many arguments")), (unsigned int)(((uintptr_t)(&"too many arguments"))>>32)); - } else { - dasm_put(Dst, 1049, (unsigned int)((uintptr_t)(&"too few arguments")), (unsigned int)(((uintptr_t)(&"too few arguments"))>>32)); - } - - dasm_put(Dst, 1069); - + dasm_put(Dst, 1133); + struct_offset=16; /* no need to zero extend eax returned by lua_gettop to rax as x86-64 * preguarentees that the upper 32 bits will be zero */ - dasm_put(Dst, 1072, 32 + REGISTER_STACK_SPACE(ct)); + if (ct->has_var_arg) { + dasm_put(Dst, 1146, nargs, (unsigned int)((uintptr_t)(&"too few arguments")), (unsigned int)(((uintptr_t)(&"too few arguments"))>>32)); + }else{ + dasm_put(Dst, 1195, nargs*16); + } + + dasm_put(Dst, 1195, 32 + REGISTER_STACK_SPACE(ct)); + + i=caculate_extra_stack(L,ct_usr,nargs); + if(i>0){ + dasm_put(Dst, 1195, i); + } -#if !defined _WIN64 && !defined __amd64__ /* Returned complex doubles require a hidden first parameter where the * data is stored, which is popped by the calling code. */ - lua_rawgeti(L, ct_usr, 0); + lua_rawgeti(L, ct_usr, 0); mbr_ct = (const struct ctype*) lua_touserdata(L, -1); - if (!mbr_ct->pointers && !mbr_ct->is_reference && mbr_ct->type == COMPLEX_DOUBLE_TYPE) { + if (return_by_address(mbr_ct)) { /* we can allocate more space for arguments as long as no add_* * function has been called yet, mbr_ct will be added as an upvalue in * the return processing later */ - dasm_put(Dst, 1085, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32)); + dasm_put(Dst, 1201, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32)); add_pointer(Dst, ct, ®); } - lua_pop(L, 1); -#endif + lua_pop(L,1); + + for (i = 1; i <= nargs; i++) { lua_rawgeti(L, ct_usr, (int) i); @@ -843,117 +1073,186 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty if (mbr_ct->pointers || mbr_ct->is_reference) { lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1109, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i); + dasm_put(Dst, 1225, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i); add_pointer(Dst, ct, ®); } else { switch (mbr_ct->type) { case FUNCTION_PTR_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1129, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i); + dasm_put(Dst, 1245, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i); add_pointer(Dst, ct, ®); break; case ENUM_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1149, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i); + dasm_put(Dst, 1265, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i); add_int(Dst, ct, ®, 0); break; case INT8_TYPE: - dasm_put(Dst, 1169, i); + dasm_put(Dst, 1285, i); if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1181); + dasm_put(Dst, 1297); } else { - dasm_put(Dst, 1185); + dasm_put(Dst, 1301); } add_int(Dst, ct, ®, 0); lua_pop(L, 1); break; case INT16_TYPE: - dasm_put(Dst, 1169, i); + dasm_put(Dst, 1285, i); if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1189); + dasm_put(Dst, 1305); } else { - dasm_put(Dst, 1193); + dasm_put(Dst, 1309); } add_int(Dst, ct, ®, 0); lua_pop(L, 1); break; case BOOL_TYPE: - dasm_put(Dst, 1197, i); + dasm_put(Dst, 1313, i); add_int(Dst, ct, ®, 0); lua_pop(L, 1); break; case INT32_TYPE: if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1219, i); + dasm_put(Dst, 1335, i); } else { - dasm_put(Dst, 1169, i); + dasm_put(Dst, 1285, i); } add_int(Dst, ct, ®, 0); lua_pop(L, 1); break; case INTPTR_TYPE: - dasm_put(Dst, 1231, i); + dasm_put(Dst, 1347, i); add_pointer(Dst, ct, ®); lua_pop(L, 1); break; case INT64_TYPE: if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1243, i); + dasm_put(Dst, 1359, i); } else { - dasm_put(Dst, 1255, i); + dasm_put(Dst, 1371, i); } add_int(Dst, ct, ®, 1); lua_pop(L, 1); break; case DOUBLE_TYPE: - dasm_put(Dst, 1267, i); + dasm_put(Dst, 1383, i); add_float(Dst, ct, ®, 1); lua_pop(L, 1); break; - - case COMPLEX_DOUBLE_TYPE: - /* on 64 bit, returned complex doubles use xmm0, xmm1, on 32 bit + case STRUCT_TYPE: + case UNION_TYPE: + /*Struct/Union in win 64 is pass by integer register if less than 64bit and aligned 8 + *or it's passed by momory pointer. On amd64, it's passed by registers less than 16 bytes(32 bytes for floating aggregates) + *else it's copy to stack. On x86, it's copied to the stack. Argument can't be splited between stack and registers. + */ + lua_getuservalue(L, -1); + num_upvals += 2; + dasm_put(Dst, 1395, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i); +#if defined _WIN64 + { + int size=mbr_ct->base_size; + if(size!=8&&size!=2&&size!=1&&size!=4){ + struct_offset+=ALIGN_UP(size,15);//16 byte alignment required + add_int(Dst, ct, ®, 1); + }else{ + add_int(Dst, ct, ®, 1); + } + } +#elif defined __amd64__ + { + int size=mbr_ct->base_size; + int floats=float_reg_size(L,-2,mbr_ct); + if(floats){ + if(size>8&®.floats==MAX_FLOAT_REGISTERS(ct)-1){ + reg.floats++;// the whole arguments should be in stack or registers + } + // 1st float + dasm_put(Dst, 947); + add_float(Dst, ct, ®, 1); + if(size>8){// 2nd float + dasm_put(Dst, 1415); + add_float(Dst, ct, ®, 1); + } + }else if(size<=16){ + if(size>8&®.ints==MAX_INT_REGISTERS(ct)-1){ + reg.ints++;// the whole arguments should be in stack or registers + } + if(size>8){ + dasm_put(Dst, 1422); + add_int(Dst, ct, ®, 1); + dasm_put(Dst, 1429); + add_int(Dst, ct, ®, 1); + }else{ + dasm_put(Dst, 943); + add_int(Dst, ct, ®, 1); + } + }else{ //passed in stack + if(reg.off&7){ + reg.off=ALIGN_UP(reg.off,7); + } + size=ALIGN_UP(size,7); + dasm_put(Dst, 1434, reg.off, size); + reg.off+=size; + } + } +#else + { + int size=ALIGN_UP(mbr_ct->base_size,3); + reg.off+=size; + } +#endif + break; + case COMPLEX_DOUBLE_TYPE:// passed by memory copy pointer in win64 + /* on amd64, returned complex doubles use xmm0, xmm1, on 32 bit or win64 * there is a hidden first parameter that points to 16 bytes where * the returned arg is stored (this is popped by the called - * function) */ -#if defined _WIN64 || defined __amd64__ - dasm_put(Dst, 1279, i); + * function on 32 bit) */ +#if defined _WIN64 + struct_offset+=16; + add_int(Dst, ct, ®, 1);//save the address +#elif defined __amd64__ + if(reg.floats==MAX_FLOAT_REGISTERS(ct)-1){ + reg.floats++;// the whole arguments should be in stack or registers + } + dasm_put(Dst, 1456, i); add_float(Dst, ct, ®, 1); - dasm_put(Dst, 1291); + dasm_put(Dst, 1468); add_float(Dst, ct, ®, 1); #else - dasm_put(Dst, 1297, reg.off, i); reg.off += 16; #endif lua_pop(L, 1); break; case FLOAT_TYPE: - dasm_put(Dst, 1267, i); + dasm_put(Dst, 1383, i); add_float(Dst, ct, ®, 0); lua_pop(L, 1); break; case COMPLEX_FLOAT_TYPE: -#if defined _WIN64 || defined __amd64__ - dasm_put(Dst, 1323, i); +#if defined _WIN64 + /* complex floats are return in rax */ + add_int(Dst, ct, ®, 1); +#elif defined __amd64__ + dasm_put(Dst, 1474, i); /* complex floats are two floats packed into a double */ add_float(Dst, ct, ®, 1); + #else /* returned complex floats use eax and edx */ - dasm_put(Dst, 1335, i); add_float(Dst, ct, ®, 0); - dasm_put(Dst, 1353); add_float(Dst, ct, ®, 0); #endif lua_pop(L, 1); @@ -978,14 +1277,14 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty reg.regs = MAX_REGISTERS(ct); #elif defined __amd64__ if (reg.floats < MAX_FLOAT_REGISTERS(ct)) { - dasm_put(Dst, 1360, 32 + 8*(MAX_INT_REGISTERS(ct) + reg.floats), MAX_FLOAT_REGISTERS(ct) - reg.floats, nargs+1); + dasm_put(Dst, 1486, 32 + 8*(MAX_INT_REGISTERS(ct) + reg.floats), MAX_FLOAT_REGISTERS(ct) - reg.floats, nargs+1); } if (reg.ints < MAX_INT_REGISTERS(ct)) { - dasm_put(Dst, 1390, 32 + 8*(reg.ints), MAX_INT_REGISTERS(ct) - reg.ints, nargs+1); + dasm_put(Dst, 1516, 32 + 8*(reg.ints), MAX_INT_REGISTERS(ct) - reg.ints, nargs+1); } - dasm_put(Dst, 1420, reg.off, MAX_FLOAT_REGISTERS(ct) - reg.floats, MAX_INT_REGISTERS(ct) - reg.ints, nargs+1); + dasm_put(Dst, 1546, reg.off, MAX_FLOAT_REGISTERS(ct) - reg.floats, MAX_INT_REGISTERS(ct) - reg.ints, nargs+1); reg.floats = MAX_FLOAT_REGISTERS(ct); reg.ints = MAX_INT_REGISTERS(ct); @@ -993,10 +1292,7 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty #endif } - dasm_put(Dst, 1454, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); - - /* remove the stack space to call local functions */ - dasm_put(Dst, 1468); + dasm_put(Dst, 1580); #ifdef _WIN64 switch (reg.regs) { @@ -1030,43 +1326,43 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty #elif defined __amd64__ switch (reg.floats) { case 8: - dasm_put(Dst, 1473, 8*(MAX_INT_REGISTERS(ct)+7)); + dasm_put(Dst, 1585, 8*(MAX_INT_REGISTERS(ct)+7)); case 7: - dasm_put(Dst, 1482, 8*(MAX_INT_REGISTERS(ct)+6)); + dasm_put(Dst, 1594, 8*(MAX_INT_REGISTERS(ct)+6)); case 6: - dasm_put(Dst, 1491, 8*(MAX_INT_REGISTERS(ct)+5)); + dasm_put(Dst, 1603, 8*(MAX_INT_REGISTERS(ct)+5)); case 5: - dasm_put(Dst, 1500, 8*(MAX_INT_REGISTERS(ct)+4)); + dasm_put(Dst, 1612, 8*(MAX_INT_REGISTERS(ct)+4)); case 4: - dasm_put(Dst, 1509, 8*(MAX_INT_REGISTERS(ct)+3)); + dasm_put(Dst, 1621, 8*(MAX_INT_REGISTERS(ct)+3)); case 3: - dasm_put(Dst, 1518, 8*(MAX_INT_REGISTERS(ct)+2)); + dasm_put(Dst, 1630, 8*(MAX_INT_REGISTERS(ct)+2)); case 2: - dasm_put(Dst, 1527, 8*(MAX_INT_REGISTERS(ct)+1)); + dasm_put(Dst, 1639, 8*(MAX_INT_REGISTERS(ct)+1)); case 1: - dasm_put(Dst, 1536, 8*(MAX_INT_REGISTERS(ct))); + dasm_put(Dst, 1648, 8*(MAX_INT_REGISTERS(ct))); case 0: break; } switch (reg.ints) { case 6: - dasm_put(Dst, 1545, 8*5); + dasm_put(Dst, 1657, 8*5); case 5: - dasm_put(Dst, 1552, 8*4); + dasm_put(Dst, 1664, 8*4); case 4: - dasm_put(Dst, 1559, 8*3); + dasm_put(Dst, 1671, 8*3); case 3: - dasm_put(Dst, 1566, 8*2); + dasm_put(Dst, 1678, 8*2); case 2: - dasm_put(Dst, 1573, 8*1); + dasm_put(Dst, 1685, 8*1); case 1: - dasm_put(Dst, 1580); + dasm_put(Dst, 1692); case 0: break; } - dasm_put(Dst, 1585, REGISTER_STACK_SPACE(ct)); + dasm_put(Dst, 1697, REGISTER_STACK_SPACE(ct)); #else if (ct->calling_convention == FAST_CALL) { switch (reg.ints) { @@ -1084,11 +1380,11 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty /* al stores an upper limit on the number of float register, note that * its allowed to be more than the actual number of float registers used as * long as its 0-8 */ - dasm_put(Dst, 1590); + dasm_put(Dst, 1702); } #endif - dasm_put(Dst, 1593); + dasm_put(Dst, 1705); /* note on windows X86 the stack may be only aligned to 4 (stdcall will * have popped a multiple of 4 bytes), but we don't need 16 byte alignment on @@ -1101,90 +1397,149 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty if (mbr_ct->pointers || mbr_ct->is_reference || mbr_ct->type == INTPTR_TYPE) { lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1603, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); + dasm_put(Dst, 1715, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); } else { switch (mbr_ct->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ + lua_getuservalue(L, -1); + num_upvals += 2; + +#if defined _WIN64 + if(return_by_address(mbr_ct)){ + fix_usr_value(Dst,L,num_upvals); + }else{ + } + +#elif defined __amd64__ + if(mbr_ct->base_size>16){ + fix_usr_value(Dst,L, num_upvals); + }else{ + int floats=float_reg_size(L,-2,mbr_ct),size=mbr_ct->base_size; + if(floats){ + dasm_put(Dst, 1765); + if(floats>1){ + dasm_put(Dst, 1772); + } + }else{ + dasm_put(Dst, 1779); + if(size>8){ + dasm_put(Dst, 1785); + } + } + dasm_put(Dst, 1791, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); + if(size>8){ + dasm_put(Dst, 1815); + } + + } +#else + { + #if defined _WIN32 + int size=ALIGN_UP(mbr_ct->base_size,3); + if(size==8){ + } + + if(size<=8){// small struct is return by value in win32 + if(size==8){ + } + }else + #endif + { + fix_usr_value(Dst,L, num_upvals); + } + + } +#endif + dasm_put(Dst, 1743); + break; + } case FUNCTION_PTR_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1603, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); + dasm_put(Dst, 1715, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); break; case INT64_TYPE: -#if LUA_VERSION_NUM == 503 +#if LUA_VERSION_NUM >= 503 lua_pop(L, 1); - if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1663, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); - } else { - dasm_put(Dst, 1663, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); - } + + dasm_put(Dst, 1825); + #else num_upvals++; - dasm_put(Dst, 1715, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32)); + dasm_put(Dst, 1857, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32)); #endif break; case COMPLEX_FLOAT_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1778, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); + dasm_put(Dst, 1910, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); break; case COMPLEX_DOUBLE_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1839, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); +#if defined _WIN64 + fix_usr_value(Dst,L,num_upvals); +#elif defined __amd64__ + dasm_put(Dst, 1961, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); +#else + fix_usr_value(Dst,L,num_upvals); +#endif + dasm_put(Dst, 1743); break; case VOID_TYPE: lua_pop(L, 1); - dasm_put(Dst, 1915, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); + dasm_put(Dst, 2006); break; case BOOL_TYPE: lua_pop(L, 1); - dasm_put(Dst, 1947, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); + dasm_put(Dst, 2028); break; case INT8_TYPE: lua_pop(L, 1); if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1181); + dasm_put(Dst, 1297); } else { - dasm_put(Dst, 1185); + dasm_put(Dst, 1301); } - dasm_put(Dst, 2000, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); + dasm_put(Dst, 2063); break; case INT16_TYPE: lua_pop(L, 1); if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1189); + dasm_put(Dst, 1305); } else { - dasm_put(Dst, 1193); + dasm_put(Dst, 1309); } - dasm_put(Dst, 2000, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); + dasm_put(Dst, 2063); break; case INT32_TYPE: case ENUM_TYPE: lua_pop(L, 1); if (mbr_ct->is_unsigned) { - dasm_put(Dst, 2050, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); + dasm_put(Dst, 2095); } else { - dasm_put(Dst, 2000, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); + dasm_put(Dst, 2063); } break; case FLOAT_TYPE: lua_pop(L, 1); - dasm_put(Dst, 2100, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); + dasm_put(Dst, 2127); break; case DOUBLE_TYPE: lua_pop(L, 1); - dasm_put(Dst, 2105, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); + dasm_put(Dst, 2132); break; default: diff --git a/texk/web2c/luatexdir/luaffi/call_x64win.h b/texk/web2c/luatexdir/luaffi/call_x64win.h index 337266ff35..52fda0d58d 100644 --- a/texk/web2c/luatexdir/luaffi/call_x64win.h +++ b/texk/web2c/luatexdir/luaffi/call_x64win.h @@ -1,14 +1,10 @@ /* ** This file has been pre-processed with DynASM. ** http://luajit.org/dynasm.html -** DynASM version 1.3.0, DynASM x64 version 1.3.0 -** DO NOT EDIT! The original file is in "call_x86.dasc". +** DynASM version 1.4.0, DynASM x64 version 1.4.0 +** DO NOT EDIT! The original file is in "/home/luigisvn/lua/ravi-ffi-master-for-luaffi/call_x86.dasc". */ -#if DASM_VERSION != 10300 -#error "Version mismatch between DynASM and included encoding engine" -#endif - /* vim: ts=4 sw=4 sts=4 et tw=78 * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved. * Portions copyright (c) 2011 James R. McKaskill. @@ -17,123 +13,122 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +#if DASM_VERSION != 10400 +#error "Version mismatch between DynASM and included encoding engine" +#endif -static const unsigned char build_actionlist[2100] = { - 72,139,141,233,255,72,137,132,253,36,233,255,221,133,233,255,217,133,233, - 255,252,243,15,126,133,233,255,252,243,15,90,133,233,255,221,156,253,36,233, - 255,217,156,253,36,233,255,102,15,214,132,253,36,233,255,252,242,15,90,192, - 102,15,214,132,253,36,233,255,252,242,15,90,192,102,15,126,132,253,36,233, - 255,85,72,137,229,65,84,72,129,252,236,239,72,137,77,16,72,137,85,24,76,137, - 69,32,76,137,77,40,102,15,214,69,252,240,102,15,214,77,232,102,15,214,85, - 224,102,15,214,93,216,255,73,188,237,237,255,73,199,192,237,72,199,194,237, - 76,137,225,232,251,1,0,255,73,199,192,237,72,199,194,252,255,252,255,252, - 255,252,255,76,137,225,232,251,1,0,255,73,199,192,237,72,199,194,237,76,137, - 225,232,251,1,0,73,184,237,237,72,199,194,252,255,252,255,252,255,252,255, - 76,137,225,232,251,1,1,255,72,137,8,72,199,194,252,254,252,255,252,255,252, - 255,76,137,225,232,251,1,2,255,73,184,237,237,72,199,194,0,0,0,0,76,137,225, - 232,251,1,1,255,72,137,8,255,102,15,214,0,255,217,24,255,217,88,4,255,102, - 15,214,64,8,255,252,243,15,126,200,76,137,225,232,251,1,3,255,15,182,201, - 72,137,202,76,137,225,232,251,1,4,255,15,182,201,255,15,190,201,255,72,137, - 202,76,137,225,232,251,1,5,255,15,183,201,255,15,191,201,255,72,137,202,76, - 137,225,232,251,1,6,255,73,185,237,237,73,199,192,237,72,199,194,237,76,137, - 225,232,251,1,7,255,73,199,192,237,72,199,194,252,254,252,255,252,255,252, - 255,76,137,225,232,251,1,0,73,185,237,237,73,199,192,252,255,252,255,252, - 255,252,255,72,199,194,252,254,252,255,252,255,252,255,76,137,225,232,251, - 1,8,72,137,68,36,32,72,199,194,252,252,252,255,252,255,252,255,76,137,225, - 232,251,1,9,72,139,68,36,32,255,73,199,192,237,72,199,194,252,254,252,255, - 252,255,252,255,76,137,225,232,251,1,0,73,185,237,237,73,199,192,252,255, - 252,255,252,255,252,255,72,199,194,252,254,252,255,252,255,252,255,76,137, - 225,232,251,1,10,137,68,36,32,72,199,194,252,252,252,255,252,255,252,255, - 76,137,225,232,251,1,9,139,68,36,32,255,72,199,194,252,254,252,255,252,255, - 252,255,76,137,225,232,251,1,9,255,72,199,194,252,255,252,255,252,255,252, - 255,76,137,225,232,251,1,11,255,72,199,194,252,255,252,255,252,255,252,255, - 76,137,225,232,251,1,12,255,137,68,36,32,72,199,194,252,253,252,255,252,255, - 252,255,76,137,225,232,251,1,9,139,68,36,32,255,72,199,194,252,255,252,255, - 252,255,252,255,76,137,225,232,251,1,13,255,72,199,194,252,255,252,255,252, - 255,252,255,76,137,225,232,251,1,14,255,72,137,68,36,32,72,199,194,252,253, - 252,255,252,255,252,255,76,137,225,232,251,1,9,72,139,68,36,32,255,72,199, - 194,252,255,252,255,252,255,252,255,76,137,225,232,251,1,15,72,137,68,36, - 32,72,199,194,252,253,252,255,252,255,252,255,76,137,225,232,251,1,9,72,139, - 68,36,32,255,72,199,194,252,255,252,255,252,255,252,255,76,137,225,232,251, - 1,16,102,15,214,68,36,32,72,199,194,252,253,252,255,252,255,252,255,76,137, - 225,232,251,1,9,255,252,242,15,90,68,36,32,255,252,243,15,126,68,36,32,255, - 72,199,194,252,255,252,255,252,255,252,255,76,137,225,232,251,1,17,102,15, - 214,68,36,32,72,199,194,252,253,252,255,252,255,252,255,76,137,225,232,251, - 1,9,252,243,15,126,68,36,32,255,72,199,194,252,255,252,255,252,255,252,255, - 76,137,225,232,251,1,18,102,15,214,68,36,32,102,15,214,76,36,40,72,199,194, - 252,253,252,255,252,255,252,255,76,137,225,232,251,1,9,252,243,15,126,68, - 36,32,252,243,15,126,76,36,40,255,72,139,141,233,73,199,192,252,255,252,255, - 252,255,252,255,76,137,226,72,137,201,232,251,1,18,72,131,252,236,4,72,199, - 194,252,253,252,255,252,255,252,255,76,137,225,232,251,1,9,255,76,139,101, - 252,248,72,137,252,236,93,194,236,255,85,72,137,229,65,84,65,85,73,137,204, - 72,131,252,236,32,76,137,225,232,251,1,19,73,137,197,72,129,252,248,239,255, - 15,141,244,248,102,184,0,0,72,186,237,237,76,137,225,232,251,1,20,248,2,15, - 142,244,247,102,184,0,0,72,186,237,237,76,137,225,232,251,1,20,255,15,141, - 244,247,102,184,0,0,72,186,237,237,76,137,225,232,251,1,20,255,248,1,255, - 72,193,224,4,72,41,196,72,129,252,236,239,255,73,184,237,237,72,199,194,0, - 0,0,0,76,137,225,232,251,1,1,72,131,252,236,16,255,73,185,237,237,73,199, - 192,237,72,199,194,237,76,137,225,232,251,1,8,255,73,185,237,237,73,199,192, - 237,72,199,194,237,76,137,225,232,251,1,21,255,73,185,237,237,73,199,192, - 237,72,199,194,237,76,137,225,232,251,1,10,255,72,199,194,237,76,137,225, - 232,251,1,12,255,15,182,192,255,15,190,192,255,15,183,192,255,15,191,192, - 255,72,199,194,237,76,137,225,232,251,1,12,131,252,248,0,15,149,208,15,182, - 192,255,72,199,194,237,76,137,225,232,251,1,11,255,72,199,194,237,76,137, - 225,232,251,1,15,255,72,199,194,237,76,137,225,232,251,1,13,255,72,199,194, - 237,76,137,225,232,251,1,14,255,72,199,194,237,76,137,225,232,251,1,16,255, - 72,199,194,237,76,137,225,232,251,1,18,255,252,243,15,126,193,255,72,141, - 132,253,36,233,72,131,252,236,4,73,199,192,237,76,137,226,72,137,193,232, - 251,1,18,255,72,199,194,237,76,137,225,232,251,1,17,255,72,199,194,237,76, - 137,225,232,251,1,17,137,4,36,217,4,36,255,137,20,36,217,4,36,255,73,129, - 252,253,239,15,142,244,247,72,137,224,72,129,192,239,73,137,193,77,137,232, - 72,199,194,237,76,137,225,232,251,1,22,72,137,224,72,129,192,239,73,137,193, - 73,199,192,237,72,199,194,237,76,137,225,232,251,1,23,252,233,244,248,248, - 1,72,137,224,72,129,192,239,73,137,193,77,137,232,72,199,194,237,76,137,225, - 232,251,1,23,248,2,255,72,137,224,72,129,192,239,73,137,193,77,137,232,72, - 199,194,237,76,137,225,232,251,1,22,255,72,185,237,237,139,1,72,137,193,232, - 251,1,24,255,72,131,196,32,255,252,243,15,126,156,253,36,233,255,76,139,140, - 253,36,233,255,252,243,15,126,148,253,36,233,255,76,139,132,253,36,233,255, - 252,243,15,126,140,253,36,233,255,72,139,148,253,36,233,255,252,243,15,126, - 4,36,255,72,139,12,36,255,232,251,1,25,72,131,252,236,48,255,72,137,68,36, - 32,232,251,1,26,72,185,237,237,137,1,73,184,237,237,72,199,194,237,76,137, - 225,232,251,1,1,72,139,76,36,32,72,137,8,184,1,0,0,0,76,139,109,252,240,76, - 139,101,252,248,72,137,252,236,93,195,255,72,137,68,36,32,232,251,1,26,72, - 185,237,237,137,1,72,139,68,36,32,72,137,194,76,137,225,232,251,1,27,184, - 1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252,236,93,195,255,72, - 137,68,36,32,232,251,1,26,72,185,237,237,137,1,73,184,237,237,72,199,194, - 0,0,0,0,76,137,225,232,251,1,1,72,139,76,36,32,72,137,8,184,1,0,0,0,76,139, - 109,252,240,76,139,101,252,248,72,137,252,236,93,195,255,102,15,214,68,36, - 32,232,251,1,26,72,185,237,237,137,1,73,184,237,237,72,199,194,237,76,137, - 225,232,251,1,1,72,139,76,36,32,72,137,8,184,1,0,0,0,76,139,109,252,240,76, - 139,101,252,248,72,137,252,236,93,195,255,102,15,214,76,36,40,102,15,214, - 68,36,32,232,251,1,26,72,185,237,237,137,1,73,184,237,237,72,199,194,237, - 76,137,225,232,251,1,1,72,139,76,36,40,72,137,72,8,72,139,76,36,32,72,137, - 8,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252,236,93,195, - 255,232,251,1,26,72,185,237,237,137,1,184,0,0,0,0,76,139,109,252,240,76,139, - 101,252,248,72,137,252,236,93,195,255,15,182,192,137,68,36,32,232,251,1,26, - 72,185,237,237,137,1,139,68,36,32,72,137,194,76,137,225,232,251,1,4,184,1, - 0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252,236,93,195,255,137, - 68,36,32,232,251,1,26,72,185,237,237,137,1,139,68,36,32,72,137,194,76,137, - 225,232,251,1,5,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137, - 252,236,93,195,255,137,68,36,32,232,251,1,26,72,185,237,237,137,1,139,68, - 36,32,72,137,194,76,137,225,232,251,1,6,184,1,0,0,0,76,139,109,252,240,76, - 139,101,252,248,72,137,252,236,93,195,255,252,243,15,90,192,102,15,214,68, - 36,32,232,251,1,26,72,185,237,237,137,1,252,243,15,126,76,36,32,76,137,225, - 232,251,1,3,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137,252, - 236,93,195,255 +static const unsigned char build_actionlist[1922] = { + 72,199,194,237,76,137,225,232,251,1,0,72,199,194,252,254,252,255,252,255, + 252,255,76,137,225,232,251,1,1,255,72,139,141,233,255,72,137,132,253,36,233, + 255,221,133,233,255,217,133,233,255,252,243,15,126,133,233,255,252,243,15, + 90,133,233,255,221,156,253,36,233,255,217,156,253,36,233,255,102,15,214,132, + 253,36,233,255,252,242,15,90,192,102,15,214,132,253,36,233,255,252,242,15, + 90,192,102,15,126,132,253,36,233,255,85,72,137,229,65,84,72,129,252,236,239, + 72,137,77,16,72,137,85,24,76,137,69,32,76,137,77,40,102,15,214,69,252,240, + 102,15,214,77,232,102,15,214,85,224,102,15,214,93,216,255,73,188,237,237, + 255,73,199,192,237,72,199,194,237,76,137,225,232,251,1,2,255,73,199,192,237, + 72,199,194,252,255,252,255,252,255,252,255,76,137,225,232,251,1,2,255,73, + 199,192,237,72,199,194,237,76,137,225,232,251,1,2,73,184,237,237,72,199,194, + 252,255,252,255,252,255,252,255,76,137,225,232,251,1,3,255,72,137,8,72,199, + 194,252,254,252,255,252,255,252,255,76,137,225,232,251,1,4,255,73,137,193, + 255,73,199,192,237,72,137,202,76,137,201,232,251,1,5,255,72,137,8,255,72, + 137,202,76,137,225,232,251,1,6,255,73,184,237,237,72,199,194,0,0,0,0,76,137, + 225,232,251,1,3,255,72,139,17,72,137,16,72,139,81,8,72,137,80,8,255,252,243, + 15,126,200,76,137,225,232,251,1,7,255,15,182,201,72,137,202,76,137,225,232, + 251,1,8,255,15,182,201,255,15,190,201,255,72,137,202,76,137,225,232,251,1, + 9,255,15,183,201,255,15,191,201,255,72,137,202,76,137,225,232,251,1,10,255, + 73,199,192,237,72,199,194,237,76,137,225,232,251,1,11,255,73,199,192,237, + 72,199,194,252,254,252,255,252,255,252,255,76,137,225,232,251,1,2,73,185, + 237,237,73,199,192,252,255,252,255,252,255,252,255,72,199,194,252,254,252, + 255,252,255,252,255,76,137,225,232,251,1,12,72,137,68,36,32,72,199,194,252, + 252,252,255,252,255,252,255,76,137,225,232,251,1,13,72,139,68,36,32,255,73, + 199,192,237,72,199,194,252,254,252,255,252,255,252,255,76,137,225,232,251, + 1,2,73,185,237,237,73,199,192,252,255,252,255,252,255,252,255,72,199,194, + 252,254,252,255,252,255,252,255,76,137,225,232,251,1,14,137,68,36,32,72,199, + 194,252,252,252,255,252,255,252,255,76,137,225,232,251,1,13,139,68,36,32, + 255,72,199,194,252,254,252,255,252,255,252,255,76,137,225,232,251,1,13,255, + 72,199,194,252,255,252,255,252,255,252,255,76,137,225,232,251,1,15,255,72, + 199,194,252,255,252,255,252,255,252,255,76,137,225,232,251,1,16,255,137,68, + 36,32,72,199,194,252,253,252,255,252,255,252,255,76,137,225,232,251,1,13, + 139,68,36,32,255,72,199,194,252,255,252,255,252,255,252,255,76,137,225,232, + 251,1,17,255,72,199,194,252,255,252,255,252,255,252,255,76,137,225,232,251, + 1,18,255,72,137,68,36,32,72,199,194,252,253,252,255,252,255,252,255,76,137, + 225,232,251,1,13,72,139,68,36,32,255,72,199,194,252,255,252,255,252,255,252, + 255,76,137,225,232,251,1,19,72,137,68,36,32,72,199,194,252,253,252,255,252, + 255,252,255,76,137,225,232,251,1,13,72,139,68,36,32,255,72,199,194,252,255, + 252,255,252,255,252,255,76,137,225,232,251,1,20,102,15,214,68,36,32,72,199, + 194,252,253,252,255,252,255,252,255,76,137,225,232,251,1,13,255,252,242,15, + 90,68,36,32,255,252,243,15,126,68,36,32,255,73,199,192,237,72,199,194,252, + 254,252,255,252,255,252,255,76,137,225,232,251,1,2,73,185,237,237,73,199, + 192,252,255,252,255,252,255,252,255,72,199,194,252,254,252,255,252,255,252, + 255,76,137,225,232,251,1,21,72,137,68,36,32,72,199,194,252,253,252,255,252, + 255,252,255,76,137,225,232,251,1,13,72,139,68,36,32,255,72,139,0,255,252, + 243,15,126,0,255,252,243,15,126,0,252,243,15,126,72,8,255,72,137,194,72,139, + 0,72,139,82,8,255,137,194,139,0,139,82,4,255,72,141,141,233,73,199,192,237, + 72,137,194,72,137,201,232,251,1,5,72,141,133,233,255,72,199,194,252,255,252, + 255,252,255,252,255,76,137,225,232,251,1,22,72,137,68,36,32,72,199,194,252, + 253,252,255,252,255,252,255,76,137,225,232,251,1,13,72,139,68,36,32,255,72, + 139,141,233,76,137,226,73,199,192,252,255,252,255,252,255,252,255,232,251, + 1,23,72,139,133,233,255,76,139,101,252,248,72,137,252,236,93,194,236,255, + 85,72,137,229,65,84,65,85,73,137,204,255,72,131,252,236,32,76,137,225,232, + 251,1,24,73,137,197,72,129,252,248,239,15,141,244,247,102,184,0,0,72,186, + 237,237,76,137,225,232,251,1,25,248,1,72,193,224,4,72,41,196,255,72,129,252, + 236,239,255,73,184,237,237,72,199,194,0,0,0,0,76,137,225,232,251,1,3,72,131, + 252,236,16,255,73,185,237,237,73,199,192,237,72,199,194,237,76,137,225,232, + 251,1,12,255,73,185,237,237,73,199,192,237,72,199,194,237,76,137,225,232, + 251,1,26,255,73,185,237,237,73,199,192,237,72,199,194,237,76,137,225,232, + 251,1,14,255,72,199,194,237,76,137,225,232,251,1,16,255,15,182,192,255,15, + 190,192,255,15,183,192,255,15,191,192,255,72,199,194,237,76,137,225,232,251, + 1,16,131,252,248,0,15,149,208,15,182,192,255,72,199,194,237,76,137,225,232, + 251,1,15,255,72,199,194,237,76,137,225,232,251,1,19,255,72,199,194,237,76, + 137,225,232,251,1,17,255,72,199,194,237,76,137,225,232,251,1,18,255,72,199, + 194,237,76,137,225,232,251,1,20,255,73,185,237,237,73,199,192,237,72,199, + 194,237,76,137,225,232,251,1,21,255,72,137,194,72,141,133,233,255,72,137, + 193,73,199,192,237,232,251,1,5,255,72,141,133,233,73,199,192,237,76,137,226, + 72,137,193,232,251,1,23,255,72,199,194,237,76,137,225,232,251,1,22,255,73, + 129,252,253,239,15,142,244,247,72,137,224,72,129,192,239,73,137,193,77,137, + 232,72,199,194,237,76,137,225,232,251,1,27,72,137,224,72,129,192,239,73,137, + 193,73,199,192,237,72,199,194,237,76,137,225,232,251,1,28,252,233,244,248, + 248,1,72,137,224,72,129,192,239,73,137,193,77,137,232,72,199,194,237,76,137, + 225,232,251,1,28,248,2,255,72,137,224,72,129,192,239,73,137,193,77,137,232, + 72,199,194,237,76,137,225,232,251,1,27,255,72,131,196,32,255,252,243,15,126, + 156,253,36,233,255,76,139,140,253,36,233,255,252,243,15,126,148,253,36,233, + 255,76,139,132,253,36,233,255,252,243,15,126,140,253,36,233,255,72,139,148, + 253,36,233,255,252,243,15,126,4,36,255,72,139,12,36,255,232,251,1,29,72,131, + 252,236,48,255,72,137,68,36,32,73,184,237,237,72,199,194,237,76,137,225,232, + 251,1,3,72,139,76,36,32,72,137,8,184,1,0,0,0,76,139,109,252,240,76,139,101, + 252,248,72,137,252,236,93,195,255,72,137,68,36,32,73,184,237,237,72,199,194, + 237,76,137,225,232,251,1,3,72,139,76,36,32,72,137,8,72,139,76,36,40,255,72, + 137,194,76,137,225,232,251,1,6,184,1,0,0,0,76,139,109,252,240,76,139,101, + 252,248,72,137,252,236,93,195,255,72,137,68,36,32,73,184,237,237,72,199,194, + 0,0,0,0,76,137,225,232,251,1,3,72,139,76,36,32,72,137,8,184,1,0,0,0,76,139, + 109,252,240,76,139,101,252,248,72,137,252,236,93,195,255,184,0,0,0,0,76,139, + 109,252,240,76,139,101,252,248,72,137,252,236,93,195,255,15,182,192,72,137, + 194,76,137,225,232,251,1,8,184,1,0,0,0,76,139,109,252,240,76,139,101,252, + 248,72,137,252,236,93,195,255,72,137,194,76,137,225,232,251,1,9,184,1,0,0, + 0,76,139,109,252,240,76,139,101,252,248,72,137,252,236,93,195,255,72,137, + 194,76,137,225,232,251,1,10,184,1,0,0,0,76,139,109,252,240,76,139,101,252, + 248,72,137,252,236,93,195,255,252,243,15,90,192,252,243,15,126,200,76,137, + 225,232,251,1,7,184,1,0,0,0,76,139,109,252,240,76,139,101,252,248,72,137, + 252,236,93,195,255 }; static const char *const globnames[] = { (const char *)0 }; static const char *const extnames[] = { - "lua_rawgeti", + "lua_pushvalue", + "lua_setuservalue", + "rawgeti", "push_cdata", "lua_remove", + "memcpy", + "lua_pushinteger", "lua_pushnumber", "lua_pushboolean", "push_int", "push_uint", - "lua_callk", + "lua_call", "check_typed_pointer", "lua_settop", "check_enum", @@ -143,6 +138,7 @@ static const char *const extnames[] = { "check_int64", "check_uintptr", "check_double", + "check_struct", "check_complex_float", "check_complex_double", "lua_gettop", @@ -150,10 +146,7 @@ static const char *const extnames[] = { "check_typed_cfunction", "unpack_varargs_stack", "unpack_varargs_reg", - "SetLastError", "FUNCTION", - "GetLastError", - "lua_pushinteger", (const char *)0 }; @@ -172,7 +165,6 @@ static const char *const extnames[] = { - #if defined _WIN64 || defined __amd64__ #define JUMP_SIZE 14 #else @@ -212,7 +204,7 @@ static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, u void compile_globals(struct jit* jit, lua_State* L) { struct jit* Dst = jit; - int* perr = &jit->last_errno; + //int* perr = &jit->last_errno; dasm_setup(Dst, build_actionlist); /* Note: since the return code uses EBP to reset the stack pointer, we @@ -224,9 +216,99 @@ void compile_globals(struct jit* jit, lua_State* L) * stack */ + + compile(Dst, L, NULL, LUA_NOREF); } + +#ifdef _WIN64 +#define MAX_REGISTERS(ct) 4 /* rcx, rdx, r8, r9 */ + +#elif defined __amd64__ +#define MAX_INT_REGISTERS(ct) 6 /* rdi, rsi, rdx, rcx, r8, r9 */ +#define MAX_FLOAT_REGISTERS(ct) 8 /* xmm0-7 */ + +#else +#define MAX_INT_REGISTERS(ct) ((ct)->calling_convention == FAST_CALL ? 2 /* ecx, edx */ : 0) +#define MAX_FLOAT_REGISTERS(ct) 0 +#endif + +#if defined(_WIN64)||defined(__amd64__) +#define X64 1 +#else +#define X64 0 +#endif + +struct reg_alloc { +#ifdef _WIN64 + int regs; + int is_float[4]; + int is_int[4]; +#else + int floats; + int ints; +#endif + int off; +}; + +#ifdef _WIN64 +#define REGISTER_STACK_SPACE(ct) (4*8) +#elif defined __amd64__ +#define REGISTER_STACK_SPACE(ct) (14*8) +#else +#define REGISTER_STACK_SPACE(ct) ALIGN_UP(((ct)->calling_convention == FAST_CALL ? 2*4 : 0), 15) +#endif +#if defined __amd64__ +// float struct is passed by xmm0-xmm7 +static int float_reg_size(lua_State* L,int idx, const struct ctype* ct){ + struct ctype* mt; + int i,ct_usr; + if(ct->base_size>16){ + return 0; + } + lua_getuservalue(L,idx); + ct_usr=lua_absindex(L,-1); + for (i = 1;; ++i) { + lua_rawgeti(L,ct_usr,i); + if(lua_isnil(L,-1)){ + lua_pop(L,1); + break; + } + mt=(struct ctype*)lua_touserdata(L,-1); + if((mt->pointers&&!mt->is_array)||mt->is_reference|| + !(mt->type==FLOAT_TYPE||mt->type==DOUBLE_TYPE||((mt->type==STRUCT_TYPE||mt->type==UNION_TYPE)&&float_reg_size(L,-1,mt)))){ + lua_pop(L,2); + return 0; + } + lua_pop(L,1); + } + + lua_pop(L,1); + return (ct->base_size+7)>>3; +} +#endif + +static int return_by_address(const struct ctype* mbr_ct){ + + if(mbr_ct->is_reference|| mbr_ct->pointers) return 0; +#ifdef _WIN64 + return mbr_ct->base_size!=8&&mbr_ct->base_size!=2&&mbr_ct->base_size!=1&&mbr_ct->base_size!=4&& mbr_ct->base_size != 0;; +#elif defined __amd64__ + return mbr_ct->base_size>16; +#else + if(mbr_ct->base_size>8) return 1; + if(mbr_ct->type==STRUCT_TYPE||mbr_ct->type==UNION_TYPE){ + #if defined _WIN32 + return 0; + #else + return 1; + #endif + } + return 0; +#endif +} + int x86_return_size(lua_State* L, int usr, const struct ctype* ct) { int ret = 0; @@ -265,6 +347,10 @@ int x86_return_size(lua_State* L, int usr, const struct ctype* ct) case ENUM_TYPE: ret += 4; break; + case STRUCT_TYPE: + case UNION_TYPE: + ret +=ALIGN_UP(mt->base_size,3); + break; default: return luaL_error(L, "NYI - argument type"); } @@ -277,7 +363,7 @@ int x86_return_size(lua_State* L, int usr, const struct ctype* ct) #if !defined _WIN64 && !defined __amd64__ lua_rawgeti(L, usr, 0); mt = (const struct ctype*) lua_touserdata(L, -1); - if (!mt->pointers && !mt->is_reference && mt->type == COMPLEX_DOUBLE_TYPE) { + if (return_by_address(mt)) { ret += sizeof(void*); } lua_pop(L, 1); @@ -286,37 +372,11 @@ int x86_return_size(lua_State* L, int usr, const struct ctype* ct) return ret; } -#ifdef _WIN64 -#define MAX_REGISTERS(ct) 4 /* rcx, rdx, r8, r9 */ - -#elif defined __amd64__ -#define MAX_INT_REGISTERS(ct) 6 /* rdi, rsi, rdx, rcx, r8, r9 */ -#define MAX_FLOAT_REGISTERS(ct) 8 /* xmm0-7 */ - -#else -#define MAX_INT_REGISTERS(ct) ((ct)->calling_convention == FAST_CALL ? 2 /* ecx, edx */ : 0) -#define MAX_FLOAT_REGISTERS(ct) 0 -#endif - -struct reg_alloc { -#ifdef _WIN64 - int regs; - int is_float[4]; - int is_int[4]; -#else - int floats; - int ints; -#endif - int off; -}; - -#ifdef _WIN64 -#define REGISTER_STACK_SPACE(ct) (4*8) -#elif defined __amd64__ -#define REGISTER_STACK_SPACE(ct) (14*8) -#else -#define REGISTER_STACK_SPACE(ct) ALIGN_UP(((ct)->calling_convention == FAST_CALL ? 2*4 : 0), 15) -#endif +static void fix_usr_value(Dst_DECL,lua_State* L, int num_upvals){ + if(!lua_isnil(L,-1)){ + dasm_put(Dst, 0, lua_upvalueindex(num_upvals)); + } +} /* Fastcall: * Uses ecx, edx as first two int registers @@ -332,26 +392,33 @@ static void get_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int /* grab the register from the shadow space */ #ifdef _WIN64 if (reg->regs < MAX_REGISTERS(ct)) { - dasm_put(Dst, 0, 16 + 8*reg->regs); + dasm_put(Dst, 30, 16 + 8*reg->regs); reg->regs++; } #elif __amd64__ if (reg->ints < MAX_INT_REGISTERS(ct)) { - dasm_put(Dst, 0, - 80 - 8*reg->ints); + dasm_put(Dst, 30, - 80 - 8*reg->ints); reg->ints++; } #else if (!is_int64 && reg->ints < MAX_INT_REGISTERS(ct)) { - dasm_put(Dst, 1, - 8 - 4*reg->ints); + dasm_put(Dst, 31, - 8 - 4*reg->ints); reg->ints++; } #endif - else if (is_int64) { - dasm_put(Dst, 0, reg->off); - reg->off += 8; - } else { - dasm_put(Dst, 1, reg->off); - reg->off += 4; + else { +#if X64 + if (reg->off &7) { + reg->off = ALIGN_UP(reg->off,7); + } +#endif + if (is_int64) { + dasm_put(Dst, 30, reg->off); + reg->off += 8; + } else { + dasm_put(Dst, 31, reg->off); + reg->off += 4; + } } } @@ -359,31 +426,31 @@ static void add_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int { #ifdef _WIN64 if (reg->regs < MAX_REGISTERS(ct)) { - dasm_put(Dst, 5, 32 + 8*(reg->regs)); + dasm_put(Dst, 35, 32 + 8*(reg->regs)); reg->is_int[reg->regs++] = 1; } #elif __amd64__ if (reg->ints < MAX_INT_REGISTERS(ct)) { - dasm_put(Dst, 5, 32 + 8*reg->ints); + dasm_put(Dst, 35, 32 + 8*reg->ints); reg->ints++; } #else if (!is_int64 && reg->ints < MAX_INT_REGISTERS(ct)) { - dasm_put(Dst, 5, 32 + 4*reg->ints); + dasm_put(Dst, 35, 32 + 4*reg->ints); reg->ints++; } #endif else { -#if defined _WIN64 || defined __amd64__ - if (reg->off % 8 != 0) { - reg->off += 8 - (reg->off % 8); +#if X64 + if (reg->off &7) { + reg->off = ALIGN_UP(reg->off,7); } #endif if (is_int64) { - dasm_put(Dst, 5, reg->off); + dasm_put(Dst, 35, reg->off); reg->off += 8; } else { - dasm_put(Dst, 6, reg->off); + dasm_put(Dst, 36, reg->off); reg->off += 4; } } @@ -391,13 +458,13 @@ static void add_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int static void get_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_double) { -#if !defined _WIN64 && !defined __amd64__ +#if !X64 assert(MAX_FLOAT_REGISTERS(ct) == 0); if (is_double) { - dasm_put(Dst, 12, reg->off); + dasm_put(Dst, 42, reg->off); reg->off += 8; } else { - dasm_put(Dst, 16, reg->off); + dasm_put(Dst, 46, reg->off); reg->off += 4; } #else @@ -409,20 +476,25 @@ static void get_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, i reg->regs++; } #else - if (reg->floats < MAX_FLOAT_REGISTERS(ct)) { + if (reg->floats< MAX_FLOAT_REGISTERS(ct)) { off = -16 - 8*reg->floats; reg->floats++; } #endif else { - off = reg->off; +#if X64 + if (reg->off % 8 != 0) { + reg->off += 8 - (reg->off % 8); + } +#endif + off = reg->off; reg->off += is_double ? 8 : 4; } if (is_double) { - dasm_put(Dst, 20, off); + dasm_put(Dst, 50, off); } else { - dasm_put(Dst, 27, off); + dasm_put(Dst, 57, off); } #endif } @@ -432,10 +504,10 @@ static void add_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, i #if !defined _WIN64 && !defined __amd64__ assert(MAX_FLOAT_REGISTERS(ct) == 0); if (is_double) { - dasm_put(Dst, 34, reg->off); + dasm_put(Dst, 64, reg->off); reg->off += 8; } else { - dasm_put(Dst, 40, reg->off); + dasm_put(Dst, 70, reg->off); reg->off += 4; } #else @@ -443,29 +515,35 @@ static void add_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, i #ifdef _WIN64 if (reg->regs < MAX_REGISTERS(ct)) { if (is_double) { - dasm_put(Dst, 46, 32 + 8*(reg->regs)); + dasm_put(Dst, 76, 32 + 8*(reg->regs)); } else { - dasm_put(Dst, 54, 32 + 8*(reg->regs)); + dasm_put(Dst, 84, 32 + 8*(reg->regs)); } reg->is_float[reg->regs++] = 1; } #else if (reg->floats < MAX_FLOAT_REGISTERS(ct)) { if (is_double) { - dasm_put(Dst, 46, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats)); + dasm_put(Dst, 76, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats)); } else { - dasm_put(Dst, 54, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats)); + dasm_put(Dst, 84, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats)); } reg->floats++; } #endif - - else if (is_double) { - dasm_put(Dst, 46, reg->off); - reg->off += 8; - } else { - dasm_put(Dst, 67, reg->off); - reg->off += 4; + else { +#if defined _WIN64 || defined __amd64__ + if (reg->off % 8 != 0) { + reg->off += 8 - (reg->off % 8); + } +#endif + if (is_double) { + dasm_put(Dst, 76, reg->off); + reg->off += 8; + } else { + dasm_put(Dst, 97, reg->off); + reg->off += 4; + } } #endif } @@ -520,33 +598,39 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp // setup a stack frame to hold args for the call into lua_call - dasm_put(Dst, 80, 8 + 16 + 32 + REGISTER_STACK_SPACE(ct)); + dasm_put(Dst, 110, 8 + 16 + 32 + REGISTER_STACK_SPACE(ct)); if (ct->calling_convention == FAST_CALL) { } // hardcode the lua_State* value into the assembly - dasm_put(Dst, 129, (unsigned int)((uintptr_t)(L)), (unsigned int)(((uintptr_t)(L))>>32)); + dasm_put(Dst, 159, (unsigned int)((uintptr_t)(L)), (unsigned int)(((uintptr_t)(L))>>32)); /* get the upval table */ - dasm_put(Dst, 134, ref, LUA_REGISTRYINDEX); + dasm_put(Dst, 164, ref, LUA_REGISTRYINDEX); /* get the lua function */ lua_pushvalue(L, fidx); lua_rawseti(L, -2, ++num_upvals); assert(num_upvals == CALLBACK_FUNC_USR_IDX); - dasm_put(Dst, 150, num_upvals); + dasm_put(Dst, 180, num_upvals); + -#if !defined _WIN64 && !defined __amd64__ lua_rawgeti(L, ct_usr, 0); mt = (const struct ctype*) lua_touserdata(L, -1); - if (!mt->pointers && !mt->is_reference && mt->type == COMPLEX_DOUBLE_TYPE) { + if (return_by_address(mt)) { +#if defined _WIN64 + reg.regs++; + hidden_arg_off= 16; +#elif defined __amd64__ + reg.ints++; + hidden_arg_off= -80; +#else hidden_arg_off = reg.off; reg.off += sizeof(void*); +#endif } lua_pop(L, 1); -#else - (void) hidden_arg_off; -#endif + for (i = 1; i <= nargs; i++) { lua_rawgeti(L, ct_usr, i); @@ -559,90 +643,151 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp /* on the lua stack in the callback: * upval tbl, lua func, i-1 args */ - dasm_put(Dst, 173, num_upvals-1, -i-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); + dasm_put(Dst, 203, num_upvals-1, -i-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); get_pointer(Dst, ct, ®); - dasm_put(Dst, 211); + dasm_put(Dst, 241); } else { switch (mt->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ +#if defined __amd64__ + int floats=float_reg_size(L,-1,mt); + +#endif + int size=mt->base_size; + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + /* on the lua stack in the callback: + * upval tbl, lua func, i-1 args + */ + dasm_put(Dst, 203, num_upvals-1, -i-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); +#if defined _WIN64 + { + if(size!=8&&size!=2&&size!=1&&size!=4){ + dasm_put(Dst, 263); + get_pointer(Dst, ct, ®); + dasm_put(Dst, 267, size); + }else{ + get_int(Dst, ct, ®, 1); + dasm_put(Dst, 282); + } + } + +#elif defined __amd64__ + if(floats>0){ + if(floats>1&®.floats==MAX_FLOAT_REGISTERS(ct)-1){ + reg.floats++;// ensure argument not splited + } + get_float(Dst, ct, ®, 1); + if(floats>1){ + get_float(Dst, ct, ®, 1); + } + }else if(size>16){ + reg.off+=ALIGN_UP(size,3); + }else { + if(size>8&®.ints==MAX_INT_REGISTERS(ct)-1){ + reg.ints++;// ensure argument not splited + } + get_int(Dst, ct, ®, 1); + if(size>8){ + get_int(Dst, ct, ®, 1); + } + } +#else + reg.off+=ALIGN_UP(size,3); +#endif + dasm_put(Dst, 244); + break; + } case INT64_TYPE: + #if LUA_VERSION_NUM >=503 + lua_pop(L, 1); + get_int(Dst, ct, ®, 1); + dasm_put(Dst, 286); + #else lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* mt */ lua_pop(L, 1); - dasm_put(Dst, 233, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); + dasm_put(Dst, 297, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); get_int(Dst, ct, ®, 1); - dasm_put(Dst, 252); + dasm_put(Dst, 282); + #endif break; case INTPTR_TYPE: lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* mt */ lua_pop(L, 1); - dasm_put(Dst, 233, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); + dasm_put(Dst, 297, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); get_pointer(Dst, ct, ®); - dasm_put(Dst, 252); + dasm_put(Dst, 282); break; case COMPLEX_FLOAT_TYPE: lua_pop(L, 1); -#if defined _WIN64 || defined __amd64__ + dasm_put(Dst, 297, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); +#if defined _WIN64 + /* complex floats are two floats packed into a int64_t */ + get_int(Dst, ct, ®, 1); + dasm_put(Dst, 282); +#elif defined __amd64__ /* complex floats are two floats packed into a double */ - dasm_put(Dst, 233, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); get_float(Dst, ct, ®, 1); - dasm_put(Dst, 256); #else /* complex floats are real followed by imag on the stack */ - dasm_put(Dst, 233, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); get_float(Dst, ct, ®, 0); - dasm_put(Dst, 261); get_float(Dst, ct, ®, 0); - dasm_put(Dst, 264); #endif break; case COMPLEX_DOUBLE_TYPE: lua_pop(L, 1); - dasm_put(Dst, 233, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); + dasm_put(Dst, 297, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); +#if defined _WIN64 + get_int(Dst, ct, ®, 1); + dasm_put(Dst, 316); +#else /* real */ get_float(Dst, ct, ®, 1); - dasm_put(Dst, 256); /* imag */ get_float(Dst, ct, ®, 1); - dasm_put(Dst, 268); +#endif break; case FLOAT_TYPE: case DOUBLE_TYPE: lua_pop(L, 1); get_float(Dst, ct, ®, mt->type == DOUBLE_TYPE); - dasm_put(Dst, 274); + dasm_put(Dst, 331); break; case BOOL_TYPE: lua_pop(L, 1); get_int(Dst, ct, ®, 0); - dasm_put(Dst, 287); + dasm_put(Dst, 344); break; case INT8_TYPE: lua_pop(L, 1); get_int(Dst, ct, ®, 0); if (mt->is_unsigned) { - dasm_put(Dst, 301); + dasm_put(Dst, 358); } else { - dasm_put(Dst, 305); + dasm_put(Dst, 362); } - dasm_put(Dst, 309); + dasm_put(Dst, 366); break; case INT16_TYPE: lua_pop(L, 1); get_int(Dst, ct, ®, 0); if (mt->is_unsigned) { - dasm_put(Dst, 320); + dasm_put(Dst, 377); } else { - dasm_put(Dst, 324); + dasm_put(Dst, 381); } - dasm_put(Dst, 309); + dasm_put(Dst, 366); break; case ENUM_TYPE: @@ -650,9 +795,9 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_pop(L, 1); get_int(Dst, ct, ®, 0); if (mt->is_unsigned) { - dasm_put(Dst, 328); + dasm_put(Dst, 385); } else { - dasm_put(Dst, 309); + dasm_put(Dst, 366); } break; @@ -665,7 +810,7 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_rawgeti(L, ct_usr, 0); mt = (const struct ctype*) lua_touserdata(L, -1); - dasm_put(Dst, 339, (unsigned int)((uintptr_t)(0)), (unsigned int)(((uintptr_t)(0))>>32), (mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0, nargs); + dasm_put(Dst, 396, (mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0, nargs); // Unpack the return argument if not "void", also clean-up the lua stack // to remove the return argument and bind table. Use lua_settop rather @@ -674,7 +819,7 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* usr value */ lua_rawseti(L, -2, ++num_upvals); /* mt */ - dasm_put(Dst, 359, num_upvals-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); + dasm_put(Dst, 412, num_upvals-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); } else { switch (mt->type) { @@ -682,12 +827,12 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* usr value */ lua_rawseti(L, -2, ++num_upvals); /* mt */ - dasm_put(Dst, 443, num_upvals-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); + dasm_put(Dst, 496, num_upvals-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); break; case VOID_TYPE: lua_pop(L, 1); - dasm_put(Dst, 525); + dasm_put(Dst, 578); break; case BOOL_TYPE: @@ -696,64 +841,104 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp case INT32_TYPE: lua_pop(L, 1); if (mt->is_unsigned) { - dasm_put(Dst, 544); + dasm_put(Dst, 597); } else { - dasm_put(Dst, 563); + dasm_put(Dst, 616); } - dasm_put(Dst, 582); + dasm_put(Dst, 635); break; case INT64_TYPE: lua_pop(L, 1); if (mt->is_unsigned) { - dasm_put(Dst, 609); + dasm_put(Dst, 662); } else { - dasm_put(Dst, 628); + dasm_put(Dst, 681); } - dasm_put(Dst, 647); + dasm_put(Dst, 700); break; case INTPTR_TYPE: lua_pop(L, 1); - dasm_put(Dst, 676); + dasm_put(Dst, 729); break; case FLOAT_TYPE: case DOUBLE_TYPE: lua_pop(L, 1); - dasm_put(Dst, 723); + dasm_put(Dst, 776); if (mt->type == FLOAT_TYPE) { - dasm_put(Dst, 766); + dasm_put(Dst, 819); } else { - dasm_put(Dst, 774); + dasm_put(Dst, 827); } break; - + case STRUCT_TYPE: + case UNION_TYPE:{ +#if defined __amd64__ + int floats=float_reg_size(L,-1,mt); +#endif + int size=mt->base_size; + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + dasm_put(Dst, 835, num_upvals-1, (unsigned int)((uintptr_t)(mt)), (unsigned int)(((uintptr_t)(mt))>>32)); +#if defined _WIN64 + if(!return_by_address(mt)){ + dasm_put(Dst, 919); + }else +#elif defined __amd64__ + if(floats){ + if(size<=8){ + dasm_put(Dst, 923); + }else{ + dasm_put(Dst, 929); + } + }else if(size<=16){ + if(size<=8){ + dasm_put(Dst, 919); + }else{ + dasm_put(Dst, 941); + } + }else +#else + #ifdef _WIN32 + if(size<=8){ + if(size<=4){ + dasm_put(Dst, 920); + }else{ + dasm_put(Dst, 952); + } + }else + #endif + +#endif + { + dasm_put(Dst, 960, hidden_arg_off, size, hidden_arg_off); + } + break; + } case COMPLEX_FLOAT_TYPE: lua_pop(L, 1); -#if !defined HAVE_COMPLEX - luaL_error(L, "ffi lib compiled without complex number support"); -#endif + /* on 64 bit complex floats are two floats packed into a double, * on 32 bit returned complex floats use eax and edx */ - dasm_put(Dst, 782); + dasm_put(Dst, 983); break; case COMPLEX_DOUBLE_TYPE: lua_pop(L, 1); -#if !defined HAVE_COMPLEX - luaL_error(L, "ffi lib compiled without complex number support"); -#endif + /* on 64 bit, returned complex doubles use xmm0, xmm1, on 32 bit * there is a hidden first parameter that points to 16 bytes where * the returned arg is stored which is popped by the called * function */ -#if defined _WIN64 || defined __amd64__ - dasm_put(Dst, 832); +#if defined _WIN64 + dasm_put(Dst, 1030, hidden_arg_off, hidden_arg_off); +#elif defined __amd64__ #else - dasm_put(Dst, 895, hidden_arg_off); #endif break; @@ -762,7 +947,7 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp } } - dasm_put(Dst, 944, x86_return_size(L, ct_usr, ct)); + dasm_put(Dst, 1057, x86_return_size(L, ct_usr, ct)); lua_pop(L, 1); /* upval table - already in registry */ assert(lua_gettop(L) == top); @@ -775,17 +960,47 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp return *pf; } +// leave enough stack for structs +static int caculate_extra_stack(lua_State* L,int ct_usr,size_t nargs){ + const struct ctype* mbr_ct; + int extra=0;int i; + for (i = 1; i <= nargs; i++) { + lua_rawgeti(L, ct_usr, (int) i); + mbr_ct = (const struct ctype*) lua_touserdata(L, -1); + if (!mbr_ct->pointers && !mbr_ct->is_reference) { + switch(mbr_ct->type){ + case STRUCT_TYPE: + case UNION_TYPE: + if(mbr_ct->base_size>16){ + extra+=ALIGN_UP(mbr_ct->base_size,15); + } + #if defined _WIN64 + else if(mbr_ct->base_size>8){ + extra+=16; + } + #endif + break; + #if defined _WIN64 + case COMPLEX_DOUBLE_TYPE: + extra+=16; + break; + #endif + } + } + lua_pop(L,1); + } + return extra; +} void compile_function(lua_State* L, cfunction func, int ct_usr, const struct ctype* ct) { size_t i, nargs; - int num_upvals; + int num_upvals,struct_offset; const struct ctype* mbr_ct; struct jit* Dst = get_jit(L); struct reg_alloc reg; void* p; int top = lua_gettop(L); - int* perr = &Dst->last_errno; ct_usr = lua_absindex(L, ct_usr); @@ -804,33 +1019,37 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty luaL_error(L, "vararg is only allowed with the c calling convention"); } - dasm_put(Dst, 957, nargs); - if (!ct->has_var_arg) { - dasm_put(Dst, 989, (unsigned int)((uintptr_t)(&"too few arguments")), (unsigned int)(((uintptr_t)(&"too few arguments"))>>32), (unsigned int)((uintptr_t)(&"too many arguments")), (unsigned int)(((uintptr_t)(&"too many arguments"))>>32)); - } else { - dasm_put(Dst, 1030, (unsigned int)((uintptr_t)(&"too few arguments")), (unsigned int)(((uintptr_t)(&"too few arguments"))>>32)); - } - - dasm_put(Dst, 1050); - + dasm_put(Dst, 1070); + struct_offset=16; /* no need to zero extend eax returned by lua_gettop to rax as x86-64 * preguarentees that the upper 32 bits will be zero */ - dasm_put(Dst, 1053, 32 + REGISTER_STACK_SPACE(ct)); + if (ct->has_var_arg) { + dasm_put(Dst, 1082, nargs, (unsigned int)((uintptr_t)(&"too few arguments")), (unsigned int)(((uintptr_t)(&"too few arguments"))>>32)); + }else{ + dasm_put(Dst, 1131, nargs*16); + } + + dasm_put(Dst, 1131, 32 + REGISTER_STACK_SPACE(ct)); + + i=caculate_extra_stack(L,ct_usr,nargs); + if(i>0){ + dasm_put(Dst, 1131, i); + } -#if !defined _WIN64 && !defined __amd64__ /* Returned complex doubles require a hidden first parameter where the * data is stored, which is popped by the calling code. */ - lua_rawgeti(L, ct_usr, 0); + lua_rawgeti(L, ct_usr, 0); mbr_ct = (const struct ctype*) lua_touserdata(L, -1); - if (!mbr_ct->pointers && !mbr_ct->is_reference && mbr_ct->type == COMPLEX_DOUBLE_TYPE) { + if (return_by_address(mbr_ct)) { /* we can allocate more space for arguments as long as no add_* * function has been called yet, mbr_ct will be added as an upvalue in * the return processing later */ - dasm_put(Dst, 1066, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32)); + dasm_put(Dst, 1137, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32)); add_pointer(Dst, ct, ®); } - lua_pop(L, 1); -#endif + lua_pop(L,1); + + for (i = 1; i <= nargs; i++) { lua_rawgeti(L, ct_usr, (int) i); @@ -839,117 +1058,182 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty if (mbr_ct->pointers || mbr_ct->is_reference) { lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1090, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i); + dasm_put(Dst, 1161, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i); add_pointer(Dst, ct, ®); } else { switch (mbr_ct->type) { case FUNCTION_PTR_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1110, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i); + dasm_put(Dst, 1181, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i); add_pointer(Dst, ct, ®); break; case ENUM_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1130, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i); + dasm_put(Dst, 1201, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i); add_int(Dst, ct, ®, 0); break; case INT8_TYPE: - dasm_put(Dst, 1150, i); + dasm_put(Dst, 1221, i); if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1162); + dasm_put(Dst, 1233); } else { - dasm_put(Dst, 1166); + dasm_put(Dst, 1237); } add_int(Dst, ct, ®, 0); lua_pop(L, 1); break; case INT16_TYPE: - dasm_put(Dst, 1150, i); + dasm_put(Dst, 1221, i); if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1170); + dasm_put(Dst, 1241); } else { - dasm_put(Dst, 1174); + dasm_put(Dst, 1245); } add_int(Dst, ct, ®, 0); lua_pop(L, 1); break; case BOOL_TYPE: - dasm_put(Dst, 1178, i); + dasm_put(Dst, 1249, i); add_int(Dst, ct, ®, 0); lua_pop(L, 1); break; case INT32_TYPE: if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1200, i); + dasm_put(Dst, 1271, i); } else { - dasm_put(Dst, 1150, i); + dasm_put(Dst, 1221, i); } add_int(Dst, ct, ®, 0); lua_pop(L, 1); break; case INTPTR_TYPE: - dasm_put(Dst, 1212, i); + dasm_put(Dst, 1283, i); add_pointer(Dst, ct, ®); lua_pop(L, 1); break; case INT64_TYPE: if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1224, i); + dasm_put(Dst, 1295, i); } else { - dasm_put(Dst, 1236, i); + dasm_put(Dst, 1307, i); } add_int(Dst, ct, ®, 1); lua_pop(L, 1); break; case DOUBLE_TYPE: - dasm_put(Dst, 1248, i); + dasm_put(Dst, 1319, i); add_float(Dst, ct, ®, 1); lua_pop(L, 1); break; - - case COMPLEX_DOUBLE_TYPE: - /* on 64 bit, returned complex doubles use xmm0, xmm1, on 32 bit + case STRUCT_TYPE: + case UNION_TYPE: + /*Struct/Union in win 64 is pass by integer register if less than 64bit and aligned 8 + *or it's passed by momory pointer. On amd64, it's passed by registers less than 16 bytes(32 bytes for floating aggregates) + *else it's copy to stack. On x86, it's copied to the stack. Argument can't be splited between stack and registers. + */ + lua_getuservalue(L, -1); + num_upvals += 2; + dasm_put(Dst, 1331, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals), i); +#if defined _WIN64 + { + int size=mbr_ct->base_size; + if(size!=8&&size!=2&&size!=1&&size!=4){ + struct_offset+=ALIGN_UP(size,15);//16 byte alignment required + dasm_put(Dst, 1351, -struct_offset); + add_int(Dst, ct, ®, 1); + dasm_put(Dst, 1359, size); + }else{ + dasm_put(Dst, 919); + add_int(Dst, ct, ®, 1); + } + } +#elif defined __amd64__ + { + int size=mbr_ct->base_size; + int floats=float_reg_size(L,-2,mbr_ct); + if(floats){ + if(size>8&®.floats==MAX_FLOAT_REGISTERS(ct)-1){ + reg.floats++;// the whole arguments should be in stack or registers + } + // 1st float + add_float(Dst, ct, ®, 1); + if(size>8){// 2nd float + add_float(Dst, ct, ®, 1); + } + }else if(size<=16){ + if(size>8&®.ints==MAX_INT_REGISTERS(ct)-1){ + reg.ints++;// the whole arguments should be in stack or registers + } + if(size>8){ + add_int(Dst, ct, ®, 1); + add_int(Dst, ct, ®, 1); + }else{ + add_int(Dst, ct, ®, 1); + } + }else{ //passed in stack + if(reg.off&7){ + reg.off=ALIGN_UP(reg.off,7); + } + size=ALIGN_UP(size,7); + reg.off+=size; + } + } +#else + { + int size=ALIGN_UP(mbr_ct->base_size,3); + reg.off+=size; + } +#endif + break; + case COMPLEX_DOUBLE_TYPE:// passed by memory copy pointer in win64 + /* on amd64, returned complex doubles use xmm0, xmm1, on 32 bit or win64 * there is a hidden first parameter that points to 16 bytes where * the returned arg is stored (this is popped by the called - * function) */ -#if defined _WIN64 || defined __amd64__ - dasm_put(Dst, 1260, i); + * function on 32 bit) */ +#if defined _WIN64 + struct_offset+=16; + dasm_put(Dst, 1371, -struct_offset, i); + add_int(Dst, ct, ®, 1);//save the address +#elif defined __amd64__ + if(reg.floats==MAX_FLOAT_REGISTERS(ct)-1){ + reg.floats++;// the whole arguments should be in stack or registers + } add_float(Dst, ct, ®, 1); - dasm_put(Dst, 1272); add_float(Dst, ct, ®, 1); #else - dasm_put(Dst, 1278, reg.off, i); reg.off += 16; #endif lua_pop(L, 1); break; case FLOAT_TYPE: - dasm_put(Dst, 1248, i); + dasm_put(Dst, 1319, i); add_float(Dst, ct, ®, 0); lua_pop(L, 1); break; case COMPLEX_FLOAT_TYPE: -#if defined _WIN64 || defined __amd64__ - dasm_put(Dst, 1304, i); +#if defined _WIN64 + dasm_put(Dst, 1390, i); + /* complex floats are return in rax */ + add_int(Dst, ct, ®, 1); +#elif defined __amd64__ /* complex floats are two floats packed into a double */ add_float(Dst, ct, ®, 1); + #else /* returned complex floats use eax and edx */ - dasm_put(Dst, 1316, i); add_float(Dst, ct, ®, 0); - dasm_put(Dst, 1334); add_float(Dst, ct, ®, 0); #endif lua_pop(L, 1); @@ -965,9 +1249,9 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty #ifdef _WIN64 if (reg.regs < MAX_REGISTERS(ct)) { assert(reg.regs == nargs); - dasm_put(Dst, 1341, MAX_REGISTERS(ct), 32 + 8*MAX_REGISTERS(ct), MAX_REGISTERS(ct)+1, 32 + 8*(reg.regs), MAX_REGISTERS(ct), nargs+1, 32 + 8*(reg.regs), nargs+1); + dasm_put(Dst, 1402, MAX_REGISTERS(ct), 32 + 8*MAX_REGISTERS(ct), MAX_REGISTERS(ct)+1, 32 + 8*(reg.regs), MAX_REGISTERS(ct), nargs+1, 32 + 8*(reg.regs), nargs+1); } else { - dasm_put(Dst, 1432, reg.off, nargs+1); + dasm_put(Dst, 1493, reg.off, nargs+1); } for (i = nargs; i < MAX_REGISTERS(ct); i++) { @@ -988,40 +1272,37 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty #endif } - dasm_put(Dst, 1457, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); - - /* remove the stack space to call local functions */ - dasm_put(Dst, 1471); + dasm_put(Dst, 1518); #ifdef _WIN64 switch (reg.regs) { case 4: if (reg.is_float[3]) { - dasm_put(Dst, 1476, 8*3); + dasm_put(Dst, 1523, 8*3); } if (reg.is_int[3]) { - dasm_put(Dst, 1485, 8*3); + dasm_put(Dst, 1532, 8*3); } case 3: if (reg.is_float[2]) { - dasm_put(Dst, 1492, 8*2); + dasm_put(Dst, 1539, 8*2); } if (reg.is_int[2]) { - dasm_put(Dst, 1501, 8*2); + dasm_put(Dst, 1548, 8*2); } case 2: if (reg.is_float[1]) { - dasm_put(Dst, 1508, 8*1); + dasm_put(Dst, 1555, 8*1); } if (reg.is_int[1]) { - dasm_put(Dst, 1517, 8*1); + dasm_put(Dst, 1564, 8*1); } case 1: if (reg.is_float[0]) { - dasm_put(Dst, 1524); + dasm_put(Dst, 1571); } if (reg.is_int[0]) { - dasm_put(Dst, 1531); + dasm_put(Dst, 1578); } case 0: break; @@ -1075,7 +1356,7 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty } #endif - dasm_put(Dst, 1536); + dasm_put(Dst, 1583); /* note on windows X86 the stack may be only aligned to 4 (stdcall will * have popped a multiple of 4 bytes), but we don't need 16 byte alignment on @@ -1088,90 +1369,143 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty if (mbr_ct->pointers || mbr_ct->is_reference || mbr_ct->type == INTPTR_TYPE) { lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1546, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); + dasm_put(Dst, 1593, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); } else { switch (mbr_ct->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ + lua_getuservalue(L, -1); + num_upvals += 2; + +#if defined _WIN64 + if(return_by_address(mbr_ct)){ + fix_usr_value(Dst,L,num_upvals); + }else{ + dasm_put(Dst, 1643, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); + } + +#elif defined __amd64__ + if(mbr_ct->base_size>16){ + fix_usr_value(Dst,L, num_upvals); + }else{ + int floats=float_reg_size(L,-2,mbr_ct),size=mbr_ct->base_size; + if(floats){ + if(floats>1){ + } + }else{ + if(size>8){ + } + } + if(size>8){ + } + + } +#else + { + #if defined _WIN32 + int size=ALIGN_UP(mbr_ct->base_size,3); + if(size==8){ + } + + if(size<=8){// small struct is return by value in win32 + if(size==8){ + } + }else + #endif + { + fix_usr_value(Dst,L, num_upvals); + } + + } +#endif + dasm_put(Dst, 1621); + break; + } case FUNCTION_PTR_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1546, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); + dasm_put(Dst, 1593, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); break; case INT64_TYPE: -#if LUA_VERSION_NUM == 503 +#if LUA_VERSION_NUM >= 503 lua_pop(L, 1); - if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1606, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); - } else { - dasm_put(Dst, 1606, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); - } + + dasm_put(Dst, 1677); + #else num_upvals++; - dasm_put(Dst, 1658, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32)); + dasm_put(Dst, 1709, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32)); #endif break; case COMPLEX_FLOAT_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1721, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); + dasm_put(Dst, 1593, (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); break; case COMPLEX_DOUBLE_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1782, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32), (unsigned int)((uintptr_t)(mbr_ct)), (unsigned int)(((uintptr_t)(mbr_ct))>>32), lua_upvalueindex(num_upvals)); +#if defined _WIN64 + fix_usr_value(Dst,L,num_upvals); +#elif defined __amd64__ +#else + fix_usr_value(Dst,L,num_upvals); +#endif + dasm_put(Dst, 1621); break; case VOID_TYPE: lua_pop(L, 1); - dasm_put(Dst, 1858, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); + dasm_put(Dst, 1762); break; case BOOL_TYPE: lua_pop(L, 1); - dasm_put(Dst, 1890, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); + dasm_put(Dst, 1784); break; case INT8_TYPE: lua_pop(L, 1); if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1162); + dasm_put(Dst, 1233); } else { - dasm_put(Dst, 1166); + dasm_put(Dst, 1237); } - dasm_put(Dst, 1943, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); + dasm_put(Dst, 1819); break; case INT16_TYPE: lua_pop(L, 1); if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1170); + dasm_put(Dst, 1241); } else { - dasm_put(Dst, 1174); + dasm_put(Dst, 1245); } - dasm_put(Dst, 1943, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); + dasm_put(Dst, 1819); break; case INT32_TYPE: case ENUM_TYPE: lua_pop(L, 1); if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1993, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); + dasm_put(Dst, 1851); } else { - dasm_put(Dst, 1943, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); + dasm_put(Dst, 1819); } break; case FLOAT_TYPE: lua_pop(L, 1); - dasm_put(Dst, 2043, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); + dasm_put(Dst, 1883); break; case DOUBLE_TYPE: lua_pop(L, 1); - dasm_put(Dst, 2048, (unsigned int)((uintptr_t)(perr)), (unsigned int)(((uintptr_t)(perr))>>32)); + dasm_put(Dst, 1888); break; default: diff --git a/texk/web2c/luatexdir/luaffi/call_x86.dasc b/texk/web2c/luatexdir/luaffi/call_x86.dasc index 4a72b98e4a..e25bdb2cf0 100644 --- a/texk/web2c/luatexdir/luaffi/call_x86.dasc +++ b/texk/web2c/luatexdir/luaffi/call_x86.dasc @@ -194,12 +194,6 @@ | ret |.endmacro -|.macro get_errno // note trashes registers -| call extern GetLastError -| mov64 rcx, perr -| mov dword [rcx], eax -|.endmacro - |.macro too_few_arguments | mov ax, 0 | call_rp extern luaL_error, L_ARG, &"too few arguments" @@ -216,27 +210,18 @@ |.endmacro |.macro lua_return_void -| get_errno | mov eax, 0 | epilog |.endmacro |.macro lua_return_double -|.if X64 -| movq qword [rsp+32], xmm0 -|.else -| fstp qword [rsp+4] // note get_errno doesn't require any stack on x86 -|.endif -| -| get_errno -| |.if X64WIN -| movq xmm1, qword [rsp+32] +| movq xmm1,xmm0 | mov rcx, L_ARG |.elif X64 -| movq xmm0, qword [rsp+32] | mov rdi, L_ARG |.else +| fstp qword [rsp+4] | mov [rsp], L_ARG |.endif | call extern lua_pushnumber @@ -245,44 +230,29 @@ |.macro lua_return_bool | movzx eax, al -| mov [rsp+32], eax -| get_errno -| mov eax, [rsp+32] | call_rr extern lua_pushboolean, L_ARG, rax | lua_return_arg |.endmacro |.macro lua_return_int -| mov [rsp+32], eax -| get_errno -| mov eax, [rsp+32] | call_rr extern push_int, L_ARG, rax | lua_return_arg |.endmacro |.macro lua_return_uint -| mov [rsp+32], eax -| get_errno -| mov eax, [rsp+32] | call_rr extern push_uint, L_ARG, rax | lua_return_arg |.endmacro -|.macro lua_return_long -| mov [rsp+32], rax -| get_errno -| mov rax, [rsp+32] +|.macro lua_return_int64 +|.if X64 | call_rr extern lua_pushinteger, L_ARG, rax +|.else +| call_rrr extern lua_pushinteger, L_ARG, rax, edx +|.endif | lua_return_arg |.endmacro -|.macro lua_return_ulong -| mov [rsp+32], rax -| get_errno -| mov rax, [rsp+32] -| call_rr extern lua_pushinteger, L_ARG, rax -| lua_return_arg -|.endmacro |.macro save_registers | // use rbp relative so we store values in the outer stack frame @@ -360,7 +330,7 @@ static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, u void compile_globals(struct jit* jit, lua_State* L) { struct jit* Dst = jit; - int* perr = &jit->last_errno; + //int* perr = &jit->last_errno; dasm_setup(Dst, build_actionlist); /* Note: since the return code uses EBP to reset the stack pointer, we @@ -377,6 +347,94 @@ void compile_globals(struct jit* jit, lua_State* L) compile(Dst, L, NULL, LUA_NOREF); } + +#ifdef _WIN64 +#define MAX_REGISTERS(ct) 4 /* rcx, rdx, r8, r9 */ + +#elif defined __amd64__ +#define MAX_INT_REGISTERS(ct) 6 /* rdi, rsi, rdx, rcx, r8, r9 */ +#define MAX_FLOAT_REGISTERS(ct) 8 /* xmm0-7 */ + +#else +#define MAX_INT_REGISTERS(ct) ((ct)->calling_convention == FAST_CALL ? 2 /* ecx, edx */ : 0) +#define MAX_FLOAT_REGISTERS(ct) 0 +#endif + +#if defined(_WIN64)||defined(__amd64__) +#define X64 1 +#else +#define X64 0 +#endif + +struct reg_alloc { +#ifdef _WIN64 + int regs; + int is_float[4]; + int is_int[4]; +#else + int floats; + int ints; +#endif + int off; +}; + +#ifdef _WIN64 +#define REGISTER_STACK_SPACE(ct) (4*8) +#elif defined __amd64__ +#define REGISTER_STACK_SPACE(ct) (14*8) +#else +#define REGISTER_STACK_SPACE(ct) ALIGN_UP(((ct)->calling_convention == FAST_CALL ? 2*4 : 0), 15) +#endif +#if defined __amd64__ +// float struct is passed by xmm0-xmm7 +static int float_reg_size(lua_State* L,int idx, const struct ctype* ct){ + struct ctype* mt; + int i,ct_usr; + if(ct->base_size>16){ + return 0; + } + lua_getuservalue(L,idx); + ct_usr=lua_absindex(L,-1); + for (i = 1;; ++i) { + lua_rawgeti(L,ct_usr,i); + if(lua_isnil(L,-1)){ + lua_pop(L,1); + break; + } + mt=(struct ctype*)lua_touserdata(L,-1); + if((mt->pointers&&!mt->is_array)||mt->is_reference|| + !(mt->type==FLOAT_TYPE||mt->type==DOUBLE_TYPE||((mt->type==STRUCT_TYPE||mt->type==UNION_TYPE)&&float_reg_size(L,-1,mt)))){ + lua_pop(L,2); + return 0; + } + lua_pop(L,1); + } + + lua_pop(L,1); + return (ct->base_size+7)>>3; +} +#endif + +static int return_by_address(const struct ctype* mbr_ct){ + + if(mbr_ct->is_reference|| mbr_ct->pointers) return 0; +#ifdef _WIN64 + return mbr_ct->base_size!=8&&mbr_ct->base_size!=2&&mbr_ct->base_size!=1&&mbr_ct->base_size!=4&& mbr_ct->base_size != 0;; +#elif defined __amd64__ + return mbr_ct->base_size>16; +#else + if(mbr_ct->base_size>8) return 1; + if(mbr_ct->type==STRUCT_TYPE||mbr_ct->type==UNION_TYPE){ + #if defined _WIN32 + return 0; + #else + return 1; + #endif + } + return 0; +#endif +} + int x86_return_size(lua_State* L, int usr, const struct ctype* ct) { int ret = 0; @@ -415,6 +473,10 @@ int x86_return_size(lua_State* L, int usr, const struct ctype* ct) case ENUM_TYPE: ret += 4; break; + case STRUCT_TYPE: + case UNION_TYPE: + ret +=ALIGN_UP(mt->base_size,3); + break; default: return luaL_error(L, "NYI - argument type"); } @@ -427,7 +489,7 @@ int x86_return_size(lua_State* L, int usr, const struct ctype* ct) #if !defined _WIN64 && !defined __amd64__ lua_rawgeti(L, usr, 0); mt = (const struct ctype*) lua_touserdata(L, -1); - if (!mt->pointers && !mt->is_reference && mt->type == COMPLEX_DOUBLE_TYPE) { + if (return_by_address(mt)) { ret += sizeof(void*); } lua_pop(L, 1); @@ -436,37 +498,12 @@ int x86_return_size(lua_State* L, int usr, const struct ctype* ct) return ret; } -#ifdef _WIN64 -#define MAX_REGISTERS(ct) 4 /* rcx, rdx, r8, r9 */ - -#elif defined __amd64__ -#define MAX_INT_REGISTERS(ct) 6 /* rdi, rsi, rdx, rcx, r8, r9 */ -#define MAX_FLOAT_REGISTERS(ct) 8 /* xmm0-7 */ - -#else -#define MAX_INT_REGISTERS(ct) ((ct)->calling_convention == FAST_CALL ? 2 /* ecx, edx */ : 0) -#define MAX_FLOAT_REGISTERS(ct) 0 -#endif - -struct reg_alloc { -#ifdef _WIN64 - int regs; - int is_float[4]; - int is_int[4]; -#else - int floats; - int ints; -#endif - int off; -}; - -#ifdef _WIN64 -#define REGISTER_STACK_SPACE(ct) (4*8) -#elif defined __amd64__ -#define REGISTER_STACK_SPACE(ct) (14*8) -#else -#define REGISTER_STACK_SPACE(ct) ALIGN_UP(((ct)->calling_convention == FAST_CALL ? 2*4 : 0), 15) -#endif +static void fix_usr_value(Dst_DECL,lua_State* L, int num_upvals){ + if(!lua_isnil(L,-1)){ + | call_rr extern lua_pushvalue, L_ARG,lua_upvalueindex(num_upvals) + | call_rr extern lua_setuservalue, L_ARG, -2 + } +} /* Fastcall: * Uses ecx, edx as first two int registers @@ -496,17 +533,24 @@ static void get_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int reg->ints++; } #endif - else if (is_int64) { - |.if X64 - | mov rcx, [rbp + reg->off] - |.else - | mov rcx, [rbp + reg->off] - | mov rdx, [rbp + reg->off + 4] - |.endif - reg->off += 8; - } else { - | mov ecx, [rbp + reg->off] - reg->off += 4; + else { +#if X64 + if (reg->off &7) { + reg->off = ALIGN_UP(reg->off,7); + } +#endif + if (is_int64) { + |.if X64 + | mov rcx, [rbp + reg->off] + |.else + | mov rcx, [rbp + reg->off] + | mov rdx, [rbp + reg->off + 4] + |.endif + reg->off += 8; + } else { + | mov ecx, [rbp + reg->off] + reg->off += 4; + } } } @@ -529,9 +573,9 @@ static void add_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int } #endif else { -#if defined _WIN64 || defined __amd64__ - if (reg->off % 8 != 0) { - reg->off += 8 - (reg->off % 8); +#if X64 + if (reg->off &7) { + reg->off = ALIGN_UP(reg->off,7); } #endif if (is_int64) { @@ -551,7 +595,7 @@ static void add_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int static void get_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_double) { -#if !defined _WIN64 && !defined __amd64__ +#if !X64 assert(MAX_FLOAT_REGISTERS(ct) == 0); if (is_double) { | fld qword [rbp + reg->off] @@ -569,13 +613,18 @@ static void get_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, i reg->regs++; } #else - if (reg->floats < MAX_FLOAT_REGISTERS(ct)) { + if (reg->floats< MAX_FLOAT_REGISTERS(ct)) { off = -16 - 8*reg->floats; reg->floats++; } #endif else { - off = reg->off; +#if X64 + if (reg->off % 8 != 0) { + reg->off += 8 - (reg->off % 8); + } +#endif + off = reg->off; reg->off += is_double ? 8 : 4; } @@ -621,14 +670,20 @@ static void add_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, i reg->floats++; } #endif - - else if (is_double) { - | movq qword [rsp + reg->off], xmm0 - reg->off += 8; - } else { - | cvtsd2ss xmm0, xmm0 - | movd dword [rsp + reg->off], xmm0 - reg->off += 4; + else { +#if defined _WIN64 || defined __amd64__ + if (reg->off % 8 != 0) { + reg->off += 8 - (reg->off % 8); + } +#endif + if (is_double) { + | movq qword [rsp + reg->off], xmm0 + reg->off += 8; + } else { + | cvtsd2ss xmm0, xmm0 + | movd dword [rsp + reg->off], xmm0 + reg->off += 4; + } } #endif } @@ -703,25 +758,31 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp | mov64 L_ARG, L /* get the upval table */ - | call_rrr extern lua_rawgeti, L_ARG, LUA_REGISTRYINDEX, ref + | call_rrr extern rawgeti, L_ARG, LUA_REGISTRYINDEX, ref /* get the lua function */ lua_pushvalue(L, fidx); lua_rawseti(L, -2, ++num_upvals); assert(num_upvals == CALLBACK_FUNC_USR_IDX); - | call_rrr extern lua_rawgeti, L_ARG, -1, num_upvals + | call_rrr extern rawgeti, L_ARG, -1, num_upvals + -#if !defined _WIN64 && !defined __amd64__ lua_rawgeti(L, ct_usr, 0); mt = (const struct ctype*) lua_touserdata(L, -1); - if (!mt->pointers && !mt->is_reference && mt->type == COMPLEX_DOUBLE_TYPE) { + if (return_by_address(mt)) { +#if defined _WIN64 + reg.regs++; + hidden_arg_off= 16; +#elif defined __amd64__ + reg.ints++; + hidden_arg_off= -80; +#else hidden_arg_off = reg.off; reg.off += sizeof(void*); +#endif } lua_pop(L, 1); -#else - (void) hidden_arg_off; -#endif + for (i = 1; i <= nargs; i++) { lua_rawgeti(L, ct_usr, i); @@ -734,14 +795,88 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp /* on the lua stack in the callback: * upval tbl, lua func, i-1 args */ - | call_rrr extern lua_rawgeti, L_ARG, -i-1, num_upvals-1 + | call_rrr extern rawgeti, L_ARG, -i-1, num_upvals-1 | call_rrp extern push_cdata, L_ARG, -1, mt get_pointer(Dst, ct, ®); | mov [rax], rcx | call_rr, extern lua_remove, L_ARG, -2 } else { switch (mt->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ +#if defined __amd64__ + int floats=float_reg_size(L,-1,mt); + +#endif + int size=mt->base_size; + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + /* on the lua stack in the callback: + * upval tbl, lua func, i-1 args + */ + | call_rrr extern rawgeti, L_ARG, -i-1, num_upvals-1 + | call_rrp extern push_cdata, L_ARG, -1, mt +#if defined _WIN64 + |.if X64WIN + { + if(size!=8&&size!=2&&size!=1&&size!=4){ + | mov r9, rax //avoid overwrite + get_pointer(Dst, ct, ®); + | call_rrr extern memcpy, r9, rcx, size + }else{ + get_int(Dst, ct, ®, 1); + | mov [rax], rcx + } + } + +#elif defined __amd64__ + |.elif X64 + if(floats>0){ + if(floats>1&®.floats==MAX_FLOAT_REGISTERS(ct)-1){ + reg.floats++;// ensure argument not splited + } + get_float(Dst, ct, ®, 1); + | movq qword [rax] ,xmm0 + if(floats>1){ + get_float(Dst, ct, ®, 1); + | movq qword [rax+8] ,xmm0 + } + }else if(size>16){ + | lea rcx, [rbp+reg.off] + | call_rrr extern memcpy, rax, rcx , size + reg.off+=ALIGN_UP(size,3); + }else { + if(size>8&®.ints==MAX_INT_REGISTERS(ct)-1){ + reg.ints++;// ensure argument not splited + } + get_int(Dst, ct, ®, 1); + | mov [rax] ,rcx + if(size>8){ + get_int(Dst, ct, ®, 1); + | mov [rax+8] ,rcx + } + } +#else + |.else + | lea ecx, [rbp+reg.off] + | call_rrr extern memcpy, eax, ecx , size + |.endif + reg.off+=ALIGN_UP(size,3); +#endif + | call_rr, extern lua_remove, L_ARG, -2 + break; + } case INT64_TYPE: + #if LUA_VERSION_NUM >=503 + lua_pop(L, 1); + get_int(Dst, ct, ®, 1); + |.if X64 + | call_rr extern lua_pushinteger, L_ARG, rcx + |.else + | call_rrr extern lua_pushinteger, L_ARG, ecx, edx + |.endif + #else lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* mt */ lua_pop(L, 1); @@ -753,6 +888,7 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp | mov [rax], ecx | mov [rax+4], edx |.endif + #endif break; case INTPTR_TYPE: @@ -766,24 +902,40 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp case COMPLEX_FLOAT_TYPE: lua_pop(L, 1); -#if defined _WIN64 || defined __amd64__ - /* complex floats are two floats packed into a double */ | call_rrp extern push_cdata, L_ARG, 0, mt +#if defined _WIN64 + /* complex floats are two floats packed into a int64_t */ + get_int(Dst, ct, ®, 1); + |.if X64WIN + | mov [rax], rcx +#elif defined __amd64__ + /* complex floats are two floats packed into a double */ get_float(Dst, ct, ®, 1); + |.elif X64 | movq qword [rax], xmm0 #else /* complex floats are real followed by imag on the stack */ - | call_rrp extern push_cdata, L_ARG, 0, mt + |.else get_float(Dst, ct, ®, 0); | fstp dword [rax] get_float(Dst, ct, ®, 0); | fstp dword [rax+4] + |.endif #endif break; case COMPLEX_DOUBLE_TYPE: lua_pop(L, 1); | call_rrp extern push_cdata, L_ARG, 0, mt +#if defined _WIN64 + get_int(Dst, ct, ®, 1); + |.if X64WIN + | mov rdx, [rcx] + | mov [rax], rdx + | mov rdx, [rcx+8] + | mov [rax+8], rdx + |.else +#else /* real */ get_float(Dst, ct, ®, 1); |.if X64 @@ -798,6 +950,8 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp |.else | fstp qword [rax+8] |.endif + |.endif +#endif break; case FLOAT_TYPE: @@ -866,7 +1020,7 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_rawgeti(L, ct_usr, 0); mt = (const struct ctype*) lua_touserdata(L, -1); - | call_rrrp extern lua_callk, L_ARG, nargs, (mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0, 0 + | call_rrr extern lua_call, L_ARG, nargs, (mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0 // Unpack the return argument if not "void", also clean-up the lua stack // to remove the return argument and bind table. Use lua_settop rather @@ -875,7 +1029,7 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* usr value */ lua_rawseti(L, -2, ++num_upvals); /* mt */ - | call_rrr extern lua_rawgeti, L_ARG, -2, num_upvals-1 + | call_rrr extern rawgeti, L_ARG, -2, num_upvals-1 | call_rrrp extern check_typed_pointer, L_ARG, -2, -1, mt | mov [rsp+32], rax | call_rr extern lua_settop, L_ARG, -4 @@ -887,8 +1041,8 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* usr value */ lua_rawseti(L, -2, ++num_upvals); /* mt */ - | call_rrr extern lua_rawgeti, L_ARG, -2, num_upvals-1 - | call_rrrp, extern check_enum, L_ARG, -2, -1, mt + | call_rrr extern rawgeti, L_ARG, -2, num_upvals-1 + | call_rrrp extern check_enum, L_ARG, -2, -1, mt | mov [rsp+32], eax | call_rr extern lua_settop, L_ARG, -4 | mov eax, [rsp+32] @@ -964,17 +1118,72 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp | fld qword [rsp+32] |.endif break; - + case STRUCT_TYPE: + case UNION_TYPE:{ +#if defined __amd64__ + int floats=float_reg_size(L,-1,mt); +#endif + int size=mt->base_size; + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + | call_rrr extern rawgeti, L_ARG, -2, num_upvals-1 + | call_rrrp extern check_struct, L_ARG, -2, -1, mt + | mov [rsp+32], rax + | call_rr extern lua_settop, L_ARG, -3 + | mov rax, [rsp+32] +#if defined _WIN64 + if(!return_by_address(mt)){ + | mov rax, [rax] + }else +#elif defined __amd64__ + if(floats){ + if(size<=8){ + | movq xmm0,qword [rax] + }else{ + | movq xmm0,qword [rax] + | movq xmm1,qword [rax+8] + } + }else if(size<=16){ + if(size<=8){ + | mov rax, [rax] + }else{ + | mov rdx, rax + | mov rax, [rax] + | mov rdx, [rdx+8] + } + }else +#else + #ifdef _WIN32 + if(size<=8){ + if(size<=4){ + | mov eax, [eax] + }else{ + | mov edx, eax + | mov eax, [eax] + | mov edx, [edx+4] + } + }else + #endif + +#endif + { + | lea rcx, [rbp+hidden_arg_off] + | call_rrr extern memcpy , rcx, rax, size + | lea rax, [rbp+hidden_arg_off] + } + break; + } case COMPLEX_FLOAT_TYPE: lua_pop(L, 1); -#if !defined HAVE_COMPLEX - luaL_error(L, "ffi lib compiled without complex number support"); -#endif + /* on 64 bit complex floats are two floats packed into a double, * on 32 bit returned complex floats use eax and edx */ | call_rr extern check_complex_float, L_ARG, -1 | - |.if X64 + |.if X64WIN + | mov [rsp+32], rax + |.elif X64 | movq qword [rsp+32], xmm0 |.else | mov [rsp+32], eax @@ -983,7 +1192,9 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp | | call_rr extern lua_settop, L_ARG, -3 | - |.if X64 + |.if X64WIN + | mov rax, [rsp+32] + |.elif X64 | movq xmm0, qword [rsp+32] |.else | mov eax, [rsp+32] @@ -993,14 +1204,20 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp case COMPLEX_DOUBLE_TYPE: lua_pop(L, 1); -#if !defined HAVE_COMPLEX - luaL_error(L, "ffi lib compiled without complex number support"); -#endif + /* on 64 bit, returned complex doubles use xmm0, xmm1, on 32 bit * there is a hidden first parameter that points to 16 bytes where * the returned arg is stored which is popped by the called * function */ -#if defined _WIN64 || defined __amd64__ +#if defined _WIN64 + |.if X64WIN + | mov rcx, [rbp + hidden_arg_off] + | mov rdx,L_ARG + | mov r8, -1 + | call extern check_complex_double + | mov rax, [rbp + hidden_arg_off] +#elif defined __amd64__ + |.elif X64 | call_rr extern check_complex_double, L_ARG, -1 | movq qword [rsp+32], xmm0 | movq qword [rsp+40], xmm1 @@ -1008,10 +1225,12 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp | movq xmm0, qword [rsp+32] | movq xmm1, qword [rsp+40] #else + |.else | mov rcx, [rbp + hidden_arg_off] | call_rrr extern check_complex_double, rcx, L_ARG, -1 | sub rsp, 4 // to realign from popped hidden arg | call_rr extern lua_settop, L_ARG, -3 + |.endif #endif break; @@ -1040,17 +1259,47 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp return *pf; } +// leave enough stack for structs +static int caculate_extra_stack(lua_State* L,int ct_usr,size_t nargs){ + const struct ctype* mbr_ct; + int extra=0;int i; + for (i = 1; i <= nargs; i++) { + lua_rawgeti(L, ct_usr, (int) i); + mbr_ct = (const struct ctype*) lua_touserdata(L, -1); + if (!mbr_ct->pointers && !mbr_ct->is_reference) { + switch(mbr_ct->type){ + case STRUCT_TYPE: + case UNION_TYPE: + if(mbr_ct->base_size>16){ + extra+=ALIGN_UP(mbr_ct->base_size,15); + } + #if defined _WIN64 + else if(mbr_ct->base_size>8){ + extra+=16; + } + #endif + break; + #if defined _WIN64 + case COMPLEX_DOUBLE_TYPE: + extra+=16; + break; + #endif + } + } + lua_pop(L,1); + } + return extra; +} void compile_function(lua_State* L, cfunction func, int ct_usr, const struct ctype* ct) { size_t i, nargs; - int num_upvals; + int num_upvals,struct_offset; const struct ctype* mbr_ct; struct jit* Dst = get_jit(L); struct reg_alloc reg; void* p; int top = lua_gettop(L); - int* perr = &Dst->last_errno; ct_usr = lua_absindex(L, ct_usr); @@ -1075,45 +1324,44 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty | push TOP | // stack is 0 (mod 16) (TOP, L_ARG, rbp, rip) | - | // Get L from our arguments and allocate some stack for lua_gettop + | // Get L from our arguments |.if X64WIN | mov L_ARG, rcx - | sub rsp, 32 // shadow space |.elif X64 | mov L_ARG, rdi |.else | mov L_ARG, [rbp + 8] - | sub rsp, 16 |.endif | - | call_r extern lua_gettop, L_ARG - | mov TOP, rax // no need for movzxd rax, eax - high word guarenteed to be zero by x86-64 - | cmp rax, nargs - if (!ct->has_var_arg) { - | jge >2 - | too_few_arguments - | 2: - | jle >1 - | too_many_arguments - } else { - | jge >1 - | too_few_arguments - } - - | 1: - + struct_offset=16; /* no need to zero extend eax returned by lua_gettop to rax as x86-64 * preguarentees that the upper 32 bits will be zero */ - | shl rax, 4 // reserve 16 bytes per argument - this maintains the alignment mod 16 - | sub rsp, rax + if (ct->has_var_arg) { + | sub rsp, 32 // shadow space for lua_gettop + | call_r extern lua_gettop, L_ARG + | mov TOP, rax // no need for movzxd rax, eax - high word guarenteed to be zero by x86-64 + | cmp rax, nargs + | jge >1 + | too_few_arguments + | 1: + | shl rax, 4 // reserve 16 bytes per argument - this maintains the alignment mod 16 + | sub rsp, rax + }else{ + | sub rsp, nargs*16 + } + | sub rsp, 32 + REGISTER_STACK_SPACE(ct) // reserve an extra 32 to call local functions + + i=caculate_extra_stack(L,ct_usr,nargs); + if(i>0){ + | sub rsp, i + } -#if !defined _WIN64 && !defined __amd64__ /* Returned complex doubles require a hidden first parameter where the * data is stored, which is popped by the calling code. */ - lua_rawgeti(L, ct_usr, 0); + lua_rawgeti(L, ct_usr, 0); mbr_ct = (const struct ctype*) lua_touserdata(L, -1); - if (!mbr_ct->pointers && !mbr_ct->is_reference && mbr_ct->type == COMPLEX_DOUBLE_TYPE) { + if (return_by_address(mbr_ct)) { /* we can allocate more space for arguments as long as no add_* * function has been called yet, mbr_ct will be added as an upvalue in * the return processing later */ @@ -1121,8 +1369,9 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty | sub rsp, 16 add_pointer(Dst, ct, ®); } - lua_pop(L, 1); -#endif + lua_pop(L,1); + + for (i = 1; i <= nargs; i++) { lua_rawgeti(L, ct_usr, (int) i); @@ -1211,21 +1460,109 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty add_float(Dst, ct, ®, 1); lua_pop(L, 1); break; - - case COMPLEX_DOUBLE_TYPE: - /* on 64 bit, returned complex doubles use xmm0, xmm1, on 32 bit + case STRUCT_TYPE: + case UNION_TYPE: + /*Struct/Union in win 64 is pass by integer register if less than 64bit and aligned 8 + *or it's passed by momory pointer. On amd64, it's passed by registers less than 16 bytes(32 bytes for floating aggregates) + *else it's copy to stack. On x86, it's copied to the stack. Argument can't be splited between stack and registers. + */ + lua_getuservalue(L, -1); + num_upvals += 2; + | call_rrrp extern check_struct, L_ARG, i, lua_upvalueindex(num_upvals), mbr_ct +#if defined _WIN64 + |.if X64WIN + { + int size=mbr_ct->base_size; + if(size!=8&&size!=2&&size!=1&&size!=4){ + struct_offset+=ALIGN_UP(size,15);//16 byte alignment required + | mov rdx, rax + | lea rax, [rbp-struct_offset] + add_int(Dst, ct, ®, 1); + | mov rcx, rax + | mov r8, size + | call extern memcpy + }else{ + | mov rax, [rax] + add_int(Dst, ct, ®, 1); + } + } +#elif defined __amd64__ + |.elif X64 + { + int size=mbr_ct->base_size; + int floats=float_reg_size(L,-2,mbr_ct); + if(floats){ + if(size>8&®.floats==MAX_FLOAT_REGISTERS(ct)-1){ + reg.floats++;// the whole arguments should be in stack or registers + } + // 1st float + | movq xmm0, qword [rax] + add_float(Dst, ct, ®, 1); + if(size>8){// 2nd float + | movq xmm0, qword [rax+8] + add_float(Dst, ct, ®, 1); + } + }else if(size<=16){ + if(size>8&®.ints==MAX_INT_REGISTERS(ct)-1){ + reg.ints++;// the whole arguments should be in stack or registers + } + if(size>8){ + | mov rcx, rax + | mov rax, [rcx] + add_int(Dst, ct, ®, 1); + | mov rax, [rcx+8] + add_int(Dst, ct, ®, 1); + }else{ + | mov rax,[rax] + add_int(Dst, ct, ®, 1); + } + }else{ //passed in stack + if(reg.off&7){ + reg.off=ALIGN_UP(reg.off,7); + } + size=ALIGN_UP(size,7); + | lea rdi, [rsp+reg.off] + | call_rrr extern memcpy, rdi, rax, size + reg.off+=size; + } + } +#else + { + int size=ALIGN_UP(mbr_ct->base_size,3); + |.else + | lea ecx, [rsp+reg.off] + | call_rrr extern memcpy, ecx, eax, size + |.endif + reg.off+=size; + } +#endif + break; + case COMPLEX_DOUBLE_TYPE:// passed by memory copy pointer in win64 + /* on amd64, returned complex doubles use xmm0, xmm1, on 32 bit or win64 * there is a hidden first parameter that points to 16 bytes where * the returned arg is stored (this is popped by the called - * function) */ -#if defined _WIN64 || defined __amd64__ + * function on 32 bit) */ +#if defined _WIN64 + |.if X64WIN + struct_offset+=16; + | lea rax, [rbp-struct_offset] + | call_rrr extern check_complex_double,rax, L_ARG, i + add_int(Dst, ct, ®, 1);//save the address +#elif defined __amd64__ + |.elif X64 + if(reg.floats==MAX_FLOAT_REGISTERS(ct)-1){ + reg.floats++;// the whole arguments should be in stack or registers + } | call_rr extern check_complex_double, L_ARG, i add_float(Dst, ct, ®, 1); | movq xmm0, xmm1 add_float(Dst, ct, ®, 1); #else + |.else | lea rax, [rsp+reg.off] | sub rsp, 4 | call_rrr extern check_complex_double, rax, L_ARG, i + |.endif reg.off += 16; #endif lua_pop(L, 1); @@ -1238,11 +1575,19 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty break; case COMPLEX_FLOAT_TYPE: -#if defined _WIN64 || defined __amd64__ +#if defined _WIN64 + |.if X64WIN + | call_rr extern check_complex_float, L_ARG, i + /* complex floats are return in rax */ + add_int(Dst, ct, ®, 1); +#elif defined __amd64__ + |.elif X64 | call_rr extern check_complex_float, L_ARG, i /* complex floats are two floats packed into a double */ add_float(Dst, ct, ®, 1); + #else + |.else /* returned complex floats use eax and edx */ | call_rr extern check_complex_float, L_ARG, i | mov [rsp], eax @@ -1251,6 +1596,7 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty | mov [rsp], edx | fld dword [rsp] add_float(Dst, ct, ®, 0); + |.endif #endif lua_pop(L, 1); break; @@ -1323,16 +1669,7 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty #endif } - | mov64 rcx, perr - | mov eax, dword [rcx] - | call_r extern SetLastError, rax - - /* remove the stack space to call local functions */ - |.if X32WIN - | add rsp, 28 // SetLastError will have already popped 4 - |.else | add rsp, 32 - |.endif #ifdef _WIN64 |.if X64WIN @@ -1456,7 +1793,6 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty lua_getuservalue(L, -1); num_upvals += 2; | mov [rsp+32], rax // save the pointer - | get_errno | call_rrp extern push_cdata, L_ARG, lua_upvalueindex(num_upvals), mbr_ct | mov rcx, [rsp+32] | mov [rax], rcx // *(void**) cdata = val @@ -1464,11 +1800,83 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty } else { switch (mbr_ct->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ + lua_getuservalue(L, -1); + num_upvals += 2; + +#if defined _WIN64 + |.if X64WIN + if(return_by_address(mbr_ct)){ + fix_usr_value(Dst,L,num_upvals); + }else{ + | mov [rsp+32], rax + | call_rrp extern push_cdata, L_ARG, lua_upvalueindex(num_upvals), mbr_ct + | mov rcx, [rsp+32] + | mov [rax], rcx + | mov rcx, [rsp+40] + } + +#elif defined __amd64__ + |.elif X64 + if(mbr_ct->base_size>16){ + fix_usr_value(Dst,L, num_upvals); + }else{ + int floats=float_reg_size(L,-2,mbr_ct),size=mbr_ct->base_size; + if(floats){ + | movq qword [rsp+32], xmm0 + if(floats>1){ + | movq qword [rsp+40], xmm1 + } + }else{ + | mov [rsp+32], rax + if(size>8){ + | mov [rsp+40], rdx + } + } + | call_rrp extern push_cdata, L_ARG, lua_upvalueindex(num_upvals), mbr_ct + | mov rcx, [rsp+32] + | mov [rax], rcx + if(size>8){ + | mov rcx, [rsp+40] + | mov [rax+8], rcx + } + + } +#else + |.else + { + #if defined _WIN32 + int size=ALIGN_UP(mbr_ct->base_size,3); + if(size==8){ + | mov [rsp+36], edx + } + + if(size<=8){// small struct is return by value in win32 + | mov [rsp+32], eax + | call_rrp extern push_cdata, L_ARG, lua_upvalueindex(num_upvals), mbr_ct + | mov ecx, [rsp+32] + | mov [eax], ecx + if(size==8){ + | mov ecx, [rsp+36] + | mov [eax+4], ecx + } + }else + #endif + { + fix_usr_value(Dst,L, num_upvals); + } + + } + |.endif +#endif + | lua_return_arg + break; + } case FUNCTION_PTR_TYPE: lua_getuservalue(L, -1); num_upvals += 2; | mov [rsp+32], rax // save the function pointer - | get_errno | call_rrp extern push_cdata, L_ARG, lua_upvalueindex(num_upvals), mbr_ct | mov rcx, [rsp+32] | mov [rax], rcx // *(cfunction**) cdata = val @@ -1476,13 +1884,11 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty break; case INT64_TYPE: -#if LUA_VERSION_NUM == 503 +#if LUA_VERSION_NUM >= 503 lua_pop(L, 1); - if (mbr_ct->is_unsigned) { - | lua_return_ulong - } else { - | lua_return_long - } + + | lua_return_int64 + #else num_upvals++; | // save the return value @@ -1493,7 +1899,6 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty | mov [rsp+32], eax // low |.endif | - | get_errno | call_rrp extern push_cdata, L_ARG, 0, mbr_ct | | // *(int64_t*) cdata = val @@ -1514,7 +1919,10 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty case COMPLEX_FLOAT_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - |.if X64 + |.if X64WIN + |// complex floats are returned as an eight byte struct in win64 + | mov [rsp+32], rax + |.elif X64 | // complex floats are returned as two floats packed into xmm0 | movq qword [rsp+32], xmm0 |.else @@ -1523,7 +1931,6 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty | mov [rsp+36], edx |.endif | - | get_errno | call_rrp extern push_cdata, L_ARG, lua_upvalueindex(num_upvals), mbr_ct | | // ((complex_float*) cdata) = val @@ -1543,12 +1950,15 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty case COMPLEX_DOUBLE_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - |.if X64 + |.if X64WIN +#if defined _WIN64 + fix_usr_value(Dst,L,num_upvals); + |.elif X64 +#elif defined __amd64__ | // complex doubles are returned as xmm0 and xmm1 | movq qword [rsp+40], xmm1 | movq qword [rsp+32], xmm0 | - | get_errno | call_rrp extern push_cdata, L_ARG, lua_upvalueindex(num_upvals), mbr_ct | | // ((complex_double*) cdata)->real = val0 @@ -1562,9 +1972,12 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty | // On 32 bit we have already handled this by pushing a new cdata | // and handing the cdata ptr in as the hidden first param, but | // still need to add mbr_ct as an upval as its used earlier. + | // Reset uservalue for it if not nil +#else + fix_usr_value(Dst,L,num_upvals); +#endif | // Hidden param was popped by called function, we need to realign. | sub rsp, 4 - | get_errno |.endif | | lua_return_arg diff --git a/texk/web2c/luatexdir/luaffi/call_x86.h b/texk/web2c/luatexdir/luaffi/call_x86.h index 4611a3cec0..d0029c0d5f 100644 --- a/texk/web2c/luatexdir/luaffi/call_x86.h +++ b/texk/web2c/luatexdir/luaffi/call_x86.h @@ -1,14 +1,10 @@ /* ** This file has been pre-processed with DynASM. ** http://luajit.org/dynasm.html -** DynASM version 1.3.0, DynASM x86 version 1.3.0 -** DO NOT EDIT! The original file is in "call_x86.dasc". +** DynASM version 1.4.0, DynASM x86 version 1.4.0 +** DO NOT EDIT! The original file is in "/home/luigisvn/lua/ravi-ffi-master-for-luaffi/call_x86.dasc". */ -#if DASM_VERSION != 10300 -#error "Version mismatch between DynASM and included encoding engine" -#endif - /* vim: ts=4 sw=4 sts=4 et tw=78 * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved. * Portions copyright (c) 2011 James R. McKaskill. @@ -17,111 +13,119 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +#if DASM_VERSION != 10400 +#error "Version mismatch between DynASM and included encoding engine" +#endif -static const unsigned char build_actionlist[1915] = { - 139,141,233,255,139,141,233,139,149,233,255,137,132,253,36,233,255,137,132, - 253,36,233,137,148,253,36,233,255,221,133,233,255,217,133,233,255,252,243, - 15,126,133,233,255,252,243,15,90,133,233,255,221,156,253,36,233,255,217,156, - 253,36,233,255,102,15,214,132,253,36,233,255,252,242,15,90,192,102,15,214, - 132,253,36,233,255,252,242,15,90,192,102,15,126,132,253,36,233,255,85,137, - 229,87,129,252,236,239,255,137,77,252,248,137,85,252,244,255,191,237,255, - 199,68,36,8,237,199,68,36,4,237,137,60,36,232,251,1,0,255,199,68,36,8,237, - 199,68,36,4,252,255,252,255,252,255,252,255,137,60,36,232,251,1,0,255,199, - 68,36,8,237,199,68,36,4,237,137,60,36,232,251,1,0,199,68,36,8,237,199,68, - 36,4,252,255,252,255,252,255,252,255,137,60,36,232,251,1,1,255,137,8,199, - 68,36,4,252,254,252,255,252,255,252,255,137,60,36,232,251,1,2,255,199,68, - 36,8,237,199,68,36,4,0,0,0,0,137,60,36,232,251,1,1,255,137,8,137,80,4,255, - 137,8,255,102,15,214,0,255,217,24,255,217,88,4,255,221,24,255,221,88,8,255, - 221,92,36,4,137,60,36,232,251,1,3,255,15,182,201,137,76,36,4,137,60,36,232, - 251,1,4,255,15,182,201,255,15,190,201,255,137,76,36,4,137,60,36,232,251,1, - 5,255,15,183,201,255,15,191,201,255,137,76,36,4,137,60,36,232,251,1,6,255, - 199,68,36,12,0,0,0,0,199,68,36,8,237,199,68,36,4,237,137,60,36,232,251,1, - 7,255,199,68,36,8,237,199,68,36,4,252,254,252,255,252,255,252,255,137,60, - 36,232,251,1,0,199,68,36,12,237,199,68,36,8,252,255,252,255,252,255,252,255, - 199,68,36,4,252,254,252,255,252,255,252,255,137,60,36,232,251,1,8,137,68, - 36,32,199,68,36,4,252,252,252,255,252,255,252,255,137,60,36,232,251,1,9,139, - 68,36,32,255,199,68,36,8,237,199,68,36,4,252,254,252,255,252,255,252,255, - 137,60,36,232,251,1,0,199,68,36,12,237,199,68,36,8,252,255,252,255,252,255, - 252,255,199,68,36,4,252,254,252,255,252,255,252,255,137,60,36,232,251,1,10, - 137,68,36,32,199,68,36,4,252,252,252,255,252,255,252,255,137,60,36,232,251, - 1,9,139,68,36,32,255,199,68,36,4,252,254,252,255,252,255,252,255,137,60,36, - 232,251,1,9,255,199,68,36,4,252,255,252,255,252,255,252,255,137,60,36,232, - 251,1,11,255,199,68,36,4,252,255,252,255,252,255,252,255,137,60,36,232,251, - 1,12,255,137,68,36,32,199,68,36,4,252,253,252,255,252,255,252,255,137,60, - 36,232,251,1,9,139,68,36,32,255,199,68,36,4,252,255,252,255,252,255,252,255, - 137,60,36,232,251,1,13,255,199,68,36,4,252,255,252,255,252,255,252,255,137, - 60,36,232,251,1,14,255,137,68,36,32,137,84,36,36,199,68,36,4,252,253,252, - 255,252,255,252,255,137,60,36,232,251,1,9,139,68,36,32,139,84,36,36,255,199, - 68,36,4,252,255,252,255,252,255,252,255,137,60,36,232,251,1,15,137,68,36, - 32,199,68,36,4,252,253,252,255,252,255,252,255,137,60,36,232,251,1,9,139, - 68,36,32,255,199,68,36,4,252,255,252,255,252,255,252,255,137,60,36,232,251, - 1,16,255,221,92,36,32,199,68,36,4,252,253,252,255,252,255,252,255,137,60, - 36,232,251,1,9,221,68,36,32,255,199,68,36,4,252,255,252,255,252,255,252,255, - 137,60,36,232,251,1,17,137,68,36,32,137,84,36,36,199,68,36,4,252,253,252, - 255,252,255,252,255,137,60,36,232,251,1,9,139,68,36,32,139,84,36,36,255,199, - 68,36,4,252,255,252,255,252,255,252,255,137,60,36,232,251,1,18,102,15,214, - 68,36,32,102,15,214,76,36,40,199,68,36,4,252,253,252,255,252,255,252,255, - 137,60,36,232,251,1,9,252,243,15,126,68,36,32,252,243,15,126,76,36,40,255, - 139,141,233,199,68,36,8,252,255,252,255,252,255,252,255,137,124,36,4,137, - 12,36,232,251,1,18,131,252,236,4,199,68,36,4,252,253,252,255,252,255,252, - 255,137,60,36,232,251,1,9,255,139,125,252,252,137,252,236,93,194,236,255, - 85,137,229,87,86,139,189,233,131,252,236,16,137,60,36,232,251,1,19,137,198, - 129,252,248,239,255,15,141,244,248,102,184,0,0,199,68,36,4,237,137,60,36, - 232,251,1,20,248,2,15,142,244,247,102,184,0,0,199,68,36,4,237,137,60,36,232, - 251,1,20,255,15,141,244,247,102,184,0,0,199,68,36,4,237,137,60,36,232,251, - 1,20,255,248,1,255,193,224,4,41,196,129,252,236,239,255,199,68,36,8,237,199, - 68,36,4,0,0,0,0,137,60,36,232,251,1,1,131,252,236,16,255,199,68,36,12,237, - 199,68,36,8,237,199,68,36,4,237,137,60,36,232,251,1,8,255,199,68,36,12,237, - 199,68,36,8,237,199,68,36,4,237,137,60,36,232,251,1,21,255,199,68,36,12,237, - 199,68,36,8,237,199,68,36,4,237,137,60,36,232,251,1,10,255,199,68,36,4,237, - 137,60,36,232,251,1,12,255,15,182,192,255,15,190,192,255,15,183,192,255,15, - 191,192,255,199,68,36,4,237,137,60,36,232,251,1,12,131,252,248,0,15,149,208, - 15,182,192,255,199,68,36,4,237,137,60,36,232,251,1,11,255,199,68,36,4,237, - 137,60,36,232,251,1,15,255,199,68,36,4,237,137,60,36,232,251,1,13,255,199, - 68,36,4,237,137,60,36,232,251,1,14,255,199,68,36,4,237,137,60,36,232,251, - 1,16,255,199,68,36,4,237,137,60,36,232,251,1,18,255,252,243,15,126,193,255, - 141,132,253,36,233,131,252,236,4,199,68,36,8,237,137,124,36,4,137,4,36,232, - 251,1,18,255,199,68,36,4,237,137,60,36,232,251,1,17,255,199,68,36,4,237,137, - 60,36,232,251,1,17,137,4,36,217,4,36,255,137,20,36,217,4,36,255,137,224,129, - 192,239,137,68,36,12,137,116,36,8,199,68,36,4,237,137,60,36,232,251,1,22, - 255,185,237,139,1,137,4,36,232,251,1,23,255,131,196,32,255,139,148,253,36, - 233,255,139,12,36,255,129,196,239,255,232,251,1,24,131,252,236,48,255,137, - 68,36,32,232,251,1,25,185,237,137,1,199,68,36,8,237,199,68,36,4,237,137,60, - 36,232,251,1,1,139,76,36,32,137,8,184,1,0,0,0,139,117,252,248,139,125,252, - 252,137,252,236,93,195,255,137,68,36,32,232,251,1,25,185,237,137,1,139,68, - 36,32,137,68,36,4,137,60,36,232,251,1,26,184,1,0,0,0,139,117,252,248,139, - 125,252,252,137,252,236,93,195,255,137,84,36,36,137,68,36,32,232,251,1,25, - 185,237,137,1,199,68,36,8,237,199,68,36,4,0,0,0,0,137,60,36,232,251,1,1,139, - 76,36,36,139,84,36,32,137,72,4,137,16,184,1,0,0,0,139,117,252,248,139,125, - 252,252,137,252,236,93,195,255,137,68,36,32,137,84,36,36,232,251,1,25,185, - 237,137,1,199,68,36,8,237,199,68,36,4,237,137,60,36,232,251,1,1,139,76,36, - 32,137,8,139,76,36,36,137,72,4,184,1,0,0,0,139,117,252,248,139,125,252,252, - 137,252,236,93,195,255,131,252,236,4,232,251,1,25,185,237,137,1,184,1,0,0, - 0,139,117,252,248,139,125,252,252,137,252,236,93,195,255,232,251,1,25,185, - 237,137,1,184,0,0,0,0,139,117,252,248,139,125,252,252,137,252,236,93,195, - 255,15,182,192,137,68,36,32,232,251,1,25,185,237,137,1,139,68,36,32,137,68, - 36,4,137,60,36,232,251,1,4,184,1,0,0,0,139,117,252,248,139,125,252,252,137, - 252,236,93,195,255,137,68,36,32,232,251,1,25,185,237,137,1,139,68,36,32,137, - 68,36,4,137,60,36,232,251,1,5,184,1,0,0,0,139,117,252,248,139,125,252,252, - 137,252,236,93,195,255,137,68,36,32,232,251,1,25,185,237,137,1,139,68,36, - 32,137,68,36,4,137,60,36,232,251,1,6,184,1,0,0,0,139,117,252,248,139,125, - 252,252,137,252,236,93,195,255,221,92,36,4,232,251,1,25,185,237,137,1,137, - 60,36,232,251,1,3,184,1,0,0,0,139,117,252,248,139,125,252,252,137,252,236, - 93,195,255 +static const unsigned char build_actionlist[1938] = { + 199,68,36,4,237,137,60,36,232,251,1,0,199,68,36,4,252,254,252,255,252,255, + 252,255,137,60,36,232,251,1,1,255,139,141,233,255,139,141,233,139,149,233, + 255,137,132,253,36,233,255,137,132,253,36,233,137,148,253,36,233,255,221, + 133,233,255,217,133,233,255,252,243,15,126,133,233,255,252,243,15,90,133, + 233,255,221,156,253,36,233,255,217,156,253,36,233,255,102,15,214,132,253, + 36,233,255,252,242,15,90,192,102,15,214,132,253,36,233,255,252,242,15,90, + 192,102,15,126,132,253,36,233,255,85,137,229,87,129,252,236,239,255,137,77, + 252,248,137,85,252,244,255,191,237,255,199,68,36,8,237,199,68,36,4,237,137, + 60,36,232,251,1,2,255,199,68,36,8,237,199,68,36,4,252,255,252,255,252,255, + 252,255,137,60,36,232,251,1,2,255,199,68,36,8,237,199,68,36,4,237,137,60, + 36,232,251,1,2,199,68,36,8,237,199,68,36,4,252,255,252,255,252,255,252,255, + 137,60,36,232,251,1,3,255,137,8,199,68,36,4,252,254,252,255,252,255,252,255, + 137,60,36,232,251,1,4,255,141,141,233,199,68,36,8,237,137,76,36,4,137,4,36, + 232,251,1,5,255,137,84,36,8,137,76,36,4,137,60,36,232,251,1,6,255,199,68, + 36,8,237,199,68,36,4,0,0,0,0,137,60,36,232,251,1,3,255,137,8,137,80,4,255, + 137,8,255,217,24,255,217,88,4,255,221,24,255,221,88,8,255,221,92,36,4,137, + 60,36,232,251,1,7,255,15,182,201,137,76,36,4,137,60,36,232,251,1,8,255,15, + 182,201,255,15,190,201,255,137,76,36,4,137,60,36,232,251,1,9,255,15,183,201, + 255,15,191,201,255,137,76,36,4,137,60,36,232,251,1,10,255,199,68,36,8,237, + 199,68,36,4,237,137,60,36,232,251,1,11,255,199,68,36,8,237,199,68,36,4,252, + 254,252,255,252,255,252,255,137,60,36,232,251,1,2,199,68,36,12,237,199,68, + 36,8,252,255,252,255,252,255,252,255,199,68,36,4,252,254,252,255,252,255, + 252,255,137,60,36,232,251,1,12,137,68,36,32,199,68,36,4,252,252,252,255,252, + 255,252,255,137,60,36,232,251,1,13,139,68,36,32,255,199,68,36,8,237,199,68, + 36,4,252,254,252,255,252,255,252,255,137,60,36,232,251,1,2,199,68,36,12,237, + 199,68,36,8,252,255,252,255,252,255,252,255,199,68,36,4,252,254,252,255,252, + 255,252,255,137,60,36,232,251,1,14,137,68,36,32,199,68,36,4,252,252,252,255, + 252,255,252,255,137,60,36,232,251,1,13,139,68,36,32,255,199,68,36,4,252,254, + 252,255,252,255,252,255,137,60,36,232,251,1,13,255,199,68,36,4,252,255,252, + 255,252,255,252,255,137,60,36,232,251,1,15,255,199,68,36,4,252,255,252,255, + 252,255,252,255,137,60,36,232,251,1,16,255,137,68,36,32,199,68,36,4,252,253, + 252,255,252,255,252,255,137,60,36,232,251,1,13,139,68,36,32,255,199,68,36, + 4,252,255,252,255,252,255,252,255,137,60,36,232,251,1,17,255,199,68,36,4, + 252,255,252,255,252,255,252,255,137,60,36,232,251,1,18,255,137,68,36,32,137, + 84,36,36,199,68,36,4,252,253,252,255,252,255,252,255,137,60,36,232,251,1, + 13,139,68,36,32,139,84,36,36,255,199,68,36,4,252,255,252,255,252,255,252, + 255,137,60,36,232,251,1,19,137,68,36,32,199,68,36,4,252,253,252,255,252,255, + 252,255,137,60,36,232,251,1,13,139,68,36,32,255,199,68,36,4,252,255,252,255, + 252,255,252,255,137,60,36,232,251,1,20,255,221,92,36,32,199,68,36,4,252,253, + 252,255,252,255,252,255,137,60,36,232,251,1,13,221,68,36,32,255,199,68,36, + 8,237,199,68,36,4,252,254,252,255,252,255,252,255,137,60,36,232,251,1,2,199, + 68,36,12,237,199,68,36,8,252,255,252,255,252,255,252,255,199,68,36,4,252, + 254,252,255,252,255,252,255,137,60,36,232,251,1,21,137,68,36,32,199,68,36, + 4,252,253,252,255,252,255,252,255,137,60,36,232,251,1,13,139,68,36,32,255, + 139,0,255,252,243,15,126,0,255,252,243,15,126,0,252,243,15,126,72,8,255,137, + 194,139,0,139,82,8,255,137,194,139,0,139,82,4,255,141,141,233,199,68,36,8, + 237,137,68,36,4,137,12,36,232,251,1,5,141,133,233,255,199,68,36,4,252,255, + 252,255,252,255,252,255,137,60,36,232,251,1,22,137,68,36,32,137,84,36,36, + 199,68,36,4,252,253,252,255,252,255,252,255,137,60,36,232,251,1,13,139,68, + 36,32,139,84,36,36,255,139,141,233,199,68,36,8,252,255,252,255,252,255,252, + 255,137,124,36,4,137,12,36,232,251,1,23,131,252,236,4,199,68,36,4,252,253, + 252,255,252,255,252,255,137,60,36,232,251,1,13,255,139,125,252,252,137,252, + 236,93,194,236,255,85,137,229,87,86,139,189,233,255,131,252,236,32,137,60, + 36,232,251,1,24,137,198,129,252,248,239,15,141,244,247,102,184,0,0,199,68, + 36,4,237,137,60,36,232,251,1,25,248,1,193,224,4,41,196,255,199,68,36,8,237, + 199,68,36,4,0,0,0,0,137,60,36,232,251,1,3,131,252,236,16,255,199,68,36,12, + 237,199,68,36,8,237,199,68,36,4,237,137,60,36,232,251,1,12,255,199,68,36, + 12,237,199,68,36,8,237,199,68,36,4,237,137,60,36,232,251,1,26,255,199,68, + 36,12,237,199,68,36,8,237,199,68,36,4,237,137,60,36,232,251,1,14,255,199, + 68,36,4,237,137,60,36,232,251,1,16,255,15,182,192,255,15,190,192,255,15,183, + 192,255,15,191,192,255,199,68,36,4,237,137,60,36,232,251,1,16,131,252,248, + 0,15,149,208,15,182,192,255,199,68,36,4,237,137,60,36,232,251,1,15,255,199, + 68,36,4,237,137,60,36,232,251,1,19,255,199,68,36,4,237,137,60,36,232,251, + 1,17,255,199,68,36,4,237,137,60,36,232,251,1,18,255,199,68,36,4,237,137,60, + 36,232,251,1,20,255,199,68,36,12,237,199,68,36,8,237,199,68,36,4,237,137, + 60,36,232,251,1,21,255,141,140,253,36,233,199,68,36,8,237,137,68,36,4,137, + 12,36,232,251,1,5,255,141,132,253,36,233,131,252,236,4,199,68,36,8,237,137, + 124,36,4,137,4,36,232,251,1,23,255,199,68,36,4,237,137,60,36,232,251,1,22, + 137,4,36,217,4,36,255,137,20,36,217,4,36,255,137,224,129,192,239,137,68,36, + 12,137,116,36,8,199,68,36,4,237,137,60,36,232,251,1,27,255,131,196,32,255, + 139,148,253,36,233,255,139,12,36,255,129,196,239,255,232,251,1,28,131,252, + 236,48,255,137,68,36,32,199,68,36,8,237,199,68,36,4,237,137,60,36,232,251, + 1,3,139,76,36,32,137,8,184,1,0,0,0,139,117,252,248,139,125,252,252,137,252, + 236,93,195,255,137,84,36,36,255,137,68,36,32,199,68,36,8,237,199,68,36,4, + 237,137,60,36,232,251,1,3,139,76,36,32,137,8,255,139,76,36,36,137,72,4,255, + 137,84,36,8,137,68,36,4,137,60,36,232,251,1,6,184,1,0,0,0,139,117,252,248, + 139,125,252,252,137,252,236,93,195,255,137,84,36,36,137,68,36,32,199,68,36, + 8,237,199,68,36,4,0,0,0,0,137,60,36,232,251,1,3,139,76,36,36,139,84,36,32, + 137,72,4,137,16,184,1,0,0,0,139,117,252,248,139,125,252,252,137,252,236,93, + 195,255,137,68,36,32,137,84,36,36,199,68,36,8,237,199,68,36,4,237,137,60, + 36,232,251,1,3,139,76,36,32,137,8,139,76,36,36,137,72,4,184,1,0,0,0,139,117, + 252,248,139,125,252,252,137,252,236,93,195,255,131,252,236,4,184,1,0,0,0, + 139,117,252,248,139,125,252,252,137,252,236,93,195,255,184,0,0,0,0,139,117, + 252,248,139,125,252,252,137,252,236,93,195,255,15,182,192,137,68,36,4,137, + 60,36,232,251,1,8,184,1,0,0,0,139,117,252,248,139,125,252,252,137,252,236, + 93,195,255,137,68,36,4,137,60,36,232,251,1,9,184,1,0,0,0,139,117,252,248, + 139,125,252,252,137,252,236,93,195,255,137,68,36,4,137,60,36,232,251,1,10, + 184,1,0,0,0,139,117,252,248,139,125,252,252,137,252,236,93,195,255,221,92, + 36,4,137,60,36,232,251,1,7,184,1,0,0,0,139,117,252,248,139,125,252,252,137, + 252,236,93,195,255 }; static const char *const globnames[] = { (const char *)0 }; static const char *const extnames[] = { - "lua_rawgeti", + "lua_pushvalue", + "lua_setuservalue", + "rawgeti", "push_cdata", "lua_remove", + "memcpy", + "lua_pushinteger", "lua_pushnumber", "lua_pushboolean", "push_int", "push_uint", - "lua_callk", + "lua_call", "check_typed_pointer", "lua_settop", "check_enum", @@ -131,16 +135,14 @@ static const char *const extnames[] = { "check_int64", "check_uintptr", "check_double", + "check_struct", "check_complex_float", "check_complex_double", "lua_gettop", "luaL_error", "check_typed_cfunction", "unpack_varargs_stack", - "SetLastError", "FUNCTION", - "GetLastError", - "lua_pushinteger", (const char *)0 }; @@ -159,7 +161,6 @@ static const char *const extnames[] = { - #if defined _WIN64 || defined __amd64__ #define JUMP_SIZE 14 #else @@ -199,7 +200,7 @@ static void compile_extern_jump(struct jit* jit, lua_State* L, cfunction func, u void compile_globals(struct jit* jit, lua_State* L) { struct jit* Dst = jit; - int* perr = &jit->last_errno; + //int* perr = &jit->last_errno; dasm_setup(Dst, build_actionlist); /* Note: since the return code uses EBP to reset the stack pointer, we @@ -211,9 +212,99 @@ void compile_globals(struct jit* jit, lua_State* L) * stack */ + + compile(Dst, L, NULL, LUA_NOREF); } + +#ifdef _WIN64 +#define MAX_REGISTERS(ct) 4 /* rcx, rdx, r8, r9 */ + +#elif defined __amd64__ +#define MAX_INT_REGISTERS(ct) 6 /* rdi, rsi, rdx, rcx, r8, r9 */ +#define MAX_FLOAT_REGISTERS(ct) 8 /* xmm0-7 */ + +#else +#define MAX_INT_REGISTERS(ct) ((ct)->calling_convention == FAST_CALL ? 2 /* ecx, edx */ : 0) +#define MAX_FLOAT_REGISTERS(ct) 0 +#endif + +#if defined(_WIN64)||defined(__amd64__) +#define X64 1 +#else +#define X64 0 +#endif + +struct reg_alloc { +#ifdef _WIN64 + int regs; + int is_float[4]; + int is_int[4]; +#else + int floats; + int ints; +#endif + int off; +}; + +#ifdef _WIN64 +#define REGISTER_STACK_SPACE(ct) (4*8) +#elif defined __amd64__ +#define REGISTER_STACK_SPACE(ct) (14*8) +#else +#define REGISTER_STACK_SPACE(ct) ALIGN_UP(((ct)->calling_convention == FAST_CALL ? 2*4 : 0), 15) +#endif +#if defined __amd64__ +// float struct is passed by xmm0-xmm7 +static int float_reg_size(lua_State* L,int idx, const struct ctype* ct){ + struct ctype* mt; + int i,ct_usr; + if(ct->base_size>16){ + return 0; + } + lua_getuservalue(L,idx); + ct_usr=lua_absindex(L,-1); + for (i = 1;; ++i) { + lua_rawgeti(L,ct_usr,i); + if(lua_isnil(L,-1)){ + lua_pop(L,1); + break; + } + mt=(struct ctype*)lua_touserdata(L,-1); + if((mt->pointers&&!mt->is_array)||mt->is_reference|| + !(mt->type==FLOAT_TYPE||mt->type==DOUBLE_TYPE||((mt->type==STRUCT_TYPE||mt->type==UNION_TYPE)&&float_reg_size(L,-1,mt)))){ + lua_pop(L,2); + return 0; + } + lua_pop(L,1); + } + + lua_pop(L,1); + return (ct->base_size+7)>>3; +} +#endif + +static int return_by_address(const struct ctype* mbr_ct){ + + if(mbr_ct->is_reference|| mbr_ct->pointers) return 0; +#ifdef _WIN64 + return mbr_ct->base_size!=8&&mbr_ct->base_size!=2&&mbr_ct->base_size!=1&&mbr_ct->base_size!=4&& mbr_ct->base_size != 0;; +#elif defined __amd64__ + return mbr_ct->base_size>16; +#else + if(mbr_ct->base_size>8) return 1; + if(mbr_ct->type==STRUCT_TYPE||mbr_ct->type==UNION_TYPE){ + #if defined _WIN32 + return 0; + #else + return 1; + #endif + } + return 0; +#endif +} + int x86_return_size(lua_State* L, int usr, const struct ctype* ct) { int ret = 0; @@ -252,6 +343,10 @@ int x86_return_size(lua_State* L, int usr, const struct ctype* ct) case ENUM_TYPE: ret += 4; break; + case STRUCT_TYPE: + case UNION_TYPE: + ret +=ALIGN_UP(mt->base_size,3); + break; default: return luaL_error(L, "NYI - argument type"); } @@ -264,7 +359,7 @@ int x86_return_size(lua_State* L, int usr, const struct ctype* ct) #if !defined _WIN64 && !defined __amd64__ lua_rawgeti(L, usr, 0); mt = (const struct ctype*) lua_touserdata(L, -1); - if (!mt->pointers && !mt->is_reference && mt->type == COMPLEX_DOUBLE_TYPE) { + if (return_by_address(mt)) { ret += sizeof(void*); } lua_pop(L, 1); @@ -273,37 +368,11 @@ int x86_return_size(lua_State* L, int usr, const struct ctype* ct) return ret; } -#ifdef _WIN64 -#define MAX_REGISTERS(ct) 4 /* rcx, rdx, r8, r9 */ - -#elif defined __amd64__ -#define MAX_INT_REGISTERS(ct) 6 /* rdi, rsi, rdx, rcx, r8, r9 */ -#define MAX_FLOAT_REGISTERS(ct) 8 /* xmm0-7 */ - -#else -#define MAX_INT_REGISTERS(ct) ((ct)->calling_convention == FAST_CALL ? 2 /* ecx, edx */ : 0) -#define MAX_FLOAT_REGISTERS(ct) 0 -#endif - -struct reg_alloc { -#ifdef _WIN64 - int regs; - int is_float[4]; - int is_int[4]; -#else - int floats; - int ints; -#endif - int off; -}; - -#ifdef _WIN64 -#define REGISTER_STACK_SPACE(ct) (4*8) -#elif defined __amd64__ -#define REGISTER_STACK_SPACE(ct) (14*8) -#else -#define REGISTER_STACK_SPACE(ct) ALIGN_UP(((ct)->calling_convention == FAST_CALL ? 2*4 : 0), 15) -#endif +static void fix_usr_value(Dst_DECL,lua_State* L, int num_upvals){ + if(!lua_isnil(L,-1)){ + dasm_put(Dst, 0, lua_upvalueindex(num_upvals)); + } +} /* Fastcall: * Uses ecx, edx as first two int registers @@ -319,26 +388,33 @@ static void get_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int /* grab the register from the shadow space */ #ifdef _WIN64 if (reg->regs < MAX_REGISTERS(ct)) { - dasm_put(Dst, 0, 16 + 8*reg->regs); + dasm_put(Dst, 32, 16 + 8*reg->regs); reg->regs++; } #elif __amd64__ if (reg->ints < MAX_INT_REGISTERS(ct)) { - dasm_put(Dst, 0, - 80 - 8*reg->ints); + dasm_put(Dst, 32, - 80 - 8*reg->ints); reg->ints++; } #else if (!is_int64 && reg->ints < MAX_INT_REGISTERS(ct)) { - dasm_put(Dst, 0, - 8 - 4*reg->ints); + dasm_put(Dst, 32, - 8 - 4*reg->ints); reg->ints++; } #endif - else if (is_int64) { - dasm_put(Dst, 4, reg->off, reg->off + 4); - reg->off += 8; - } else { - dasm_put(Dst, 0, reg->off); - reg->off += 4; + else { +#if X64 + if (reg->off &7) { + reg->off = ALIGN_UP(reg->off,7); + } +#endif + if (is_int64) { + dasm_put(Dst, 36, reg->off, reg->off + 4); + reg->off += 8; + } else { + dasm_put(Dst, 32, reg->off); + reg->off += 4; + } } } @@ -346,31 +422,31 @@ static void add_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int { #ifdef _WIN64 if (reg->regs < MAX_REGISTERS(ct)) { - dasm_put(Dst, 11, 32 + 8*(reg->regs)); + dasm_put(Dst, 43, 32 + 8*(reg->regs)); reg->is_int[reg->regs++] = 1; } #elif __amd64__ if (reg->ints < MAX_INT_REGISTERS(ct)) { - dasm_put(Dst, 11, 32 + 8*reg->ints); + dasm_put(Dst, 43, 32 + 8*reg->ints); reg->ints++; } #else if (!is_int64 && reg->ints < MAX_INT_REGISTERS(ct)) { - dasm_put(Dst, 11, 32 + 4*reg->ints); + dasm_put(Dst, 43, 32 + 4*reg->ints); reg->ints++; } #endif else { -#if defined _WIN64 || defined __amd64__ - if (reg->off % 8 != 0) { - reg->off += 8 - (reg->off % 8); +#if X64 + if (reg->off &7) { + reg->off = ALIGN_UP(reg->off,7); } #endif if (is_int64) { - dasm_put(Dst, 17, reg->off, reg->off + 4); + dasm_put(Dst, 49, reg->off, reg->off + 4); reg->off += 8; } else { - dasm_put(Dst, 11, reg->off); + dasm_put(Dst, 43, reg->off); reg->off += 4; } } @@ -378,13 +454,13 @@ static void add_int(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int static void get_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, int is_double) { -#if !defined _WIN64 && !defined __amd64__ +#if !X64 assert(MAX_FLOAT_REGISTERS(ct) == 0); if (is_double) { - dasm_put(Dst, 28, reg->off); + dasm_put(Dst, 60, reg->off); reg->off += 8; } else { - dasm_put(Dst, 32, reg->off); + dasm_put(Dst, 64, reg->off); reg->off += 4; } #else @@ -396,20 +472,25 @@ static void get_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, i reg->regs++; } #else - if (reg->floats < MAX_FLOAT_REGISTERS(ct)) { + if (reg->floats< MAX_FLOAT_REGISTERS(ct)) { off = -16 - 8*reg->floats; reg->floats++; } #endif else { - off = reg->off; +#if X64 + if (reg->off % 8 != 0) { + reg->off += 8 - (reg->off % 8); + } +#endif + off = reg->off; reg->off += is_double ? 8 : 4; } if (is_double) { - dasm_put(Dst, 36, off); + dasm_put(Dst, 68, off); } else { - dasm_put(Dst, 43, off); + dasm_put(Dst, 75, off); } #endif } @@ -419,10 +500,10 @@ static void add_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, i #if !defined _WIN64 && !defined __amd64__ assert(MAX_FLOAT_REGISTERS(ct) == 0); if (is_double) { - dasm_put(Dst, 50, reg->off); + dasm_put(Dst, 82, reg->off); reg->off += 8; } else { - dasm_put(Dst, 56, reg->off); + dasm_put(Dst, 88, reg->off); reg->off += 4; } #else @@ -430,29 +511,35 @@ static void add_float(Dst_DECL, const struct ctype* ct, struct reg_alloc* reg, i #ifdef _WIN64 if (reg->regs < MAX_REGISTERS(ct)) { if (is_double) { - dasm_put(Dst, 62, 32 + 8*(reg->regs)); + dasm_put(Dst, 94, 32 + 8*(reg->regs)); } else { - dasm_put(Dst, 70, 32 + 8*(reg->regs)); + dasm_put(Dst, 102, 32 + 8*(reg->regs)); } reg->is_float[reg->regs++] = 1; } #else if (reg->floats < MAX_FLOAT_REGISTERS(ct)) { if (is_double) { - dasm_put(Dst, 62, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats)); + dasm_put(Dst, 94, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats)); } else { - dasm_put(Dst, 70, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats)); + dasm_put(Dst, 102, 32 + 8*(MAX_INT_REGISTERS(ct) + reg->floats)); } reg->floats++; } #endif - - else if (is_double) { - dasm_put(Dst, 62, reg->off); - reg->off += 8; - } else { - dasm_put(Dst, 83, reg->off); - reg->off += 4; + else { +#if defined _WIN64 || defined __amd64__ + if (reg->off % 8 != 0) { + reg->off += 8 - (reg->off % 8); + } +#endif + if (is_double) { + dasm_put(Dst, 94, reg->off); + reg->off += 8; + } else { + dasm_put(Dst, 115, reg->off); + reg->off += 4; + } } #endif } @@ -507,34 +594,40 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp // setup a stack frame to hold args for the call into lua_call - dasm_put(Dst, 96, 4 + 16 + 32 + REGISTER_STACK_SPACE(ct)); + dasm_put(Dst, 128, 4 + 16 + 32 + REGISTER_STACK_SPACE(ct)); if (ct->calling_convention == FAST_CALL) { - dasm_put(Dst, 105); + dasm_put(Dst, 137); } // hardcode the lua_State* value into the assembly - dasm_put(Dst, 114, L); + dasm_put(Dst, 146, L); /* get the upval table */ - dasm_put(Dst, 117, ref, LUA_REGISTRYINDEX); + dasm_put(Dst, 149, ref, LUA_REGISTRYINDEX); /* get the lua function */ lua_pushvalue(L, fidx); lua_rawseti(L, -2, ++num_upvals); assert(num_upvals == CALLBACK_FUNC_USR_IDX); - dasm_put(Dst, 135, num_upvals); + dasm_put(Dst, 167, num_upvals); + -#if !defined _WIN64 && !defined __amd64__ lua_rawgeti(L, ct_usr, 0); mt = (const struct ctype*) lua_touserdata(L, -1); - if (!mt->pointers && !mt->is_reference && mt->type == COMPLEX_DOUBLE_TYPE) { + if (return_by_address(mt)) { +#if defined _WIN64 + reg.regs++; + hidden_arg_off= 16; +#elif defined __amd64__ + reg.ints++; + hidden_arg_off= -80; +#else hidden_arg_off = reg.off; reg.off += sizeof(void*); +#endif } lua_pop(L, 1); -#else - (void) hidden_arg_off; -#endif + for (i = 1; i <= nargs; i++) { lua_rawgeti(L, ct_usr, i); @@ -547,90 +640,151 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp /* on the lua stack in the callback: * upval tbl, lua func, i-1 args */ - dasm_put(Dst, 160, num_upvals-1, -i-1, mt); + dasm_put(Dst, 192, num_upvals-1, -i-1, mt); get_pointer(Dst, ct, ®); - dasm_put(Dst, 202); + dasm_put(Dst, 234); } else { switch (mt->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ +#if defined __amd64__ + int floats=float_reg_size(L,-1,mt); + +#endif + int size=mt->base_size; + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + /* on the lua stack in the callback: + * upval tbl, lua func, i-1 args + */ + dasm_put(Dst, 192, num_upvals-1, -i-1, mt); +#if defined _WIN64 + { + if(size!=8&&size!=2&&size!=1&&size!=4){ + get_pointer(Dst, ct, ®); + }else{ + get_int(Dst, ct, ®, 1); + } + } + +#elif defined __amd64__ + if(floats>0){ + if(floats>1&®.floats==MAX_FLOAT_REGISTERS(ct)-1){ + reg.floats++;// ensure argument not splited + } + get_float(Dst, ct, ®, 1); + if(floats>1){ + get_float(Dst, ct, ®, 1); + } + }else if(size>16){ + reg.off+=ALIGN_UP(size,3); + }else { + if(size>8&®.ints==MAX_INT_REGISTERS(ct)-1){ + reg.ints++;// ensure argument not splited + } + get_int(Dst, ct, ®, 1); + if(size>8){ + get_int(Dst, ct, ®, 1); + } + } +#else + dasm_put(Dst, 256, reg.off, size); + reg.off+=ALIGN_UP(size,3); +#endif + dasm_put(Dst, 236); + break; + } case INT64_TYPE: + #if LUA_VERSION_NUM >=503 + lua_pop(L, 1); + get_int(Dst, ct, ®, 1); + dasm_put(Dst, 276); + #else lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* mt */ lua_pop(L, 1); - dasm_put(Dst, 224, mt); + dasm_put(Dst, 292, mt); get_int(Dst, ct, ®, 1); - dasm_put(Dst, 245); + dasm_put(Dst, 313); + #endif break; case INTPTR_TYPE: lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* mt */ lua_pop(L, 1); - dasm_put(Dst, 224, mt); + dasm_put(Dst, 292, mt); get_pointer(Dst, ct, ®); - dasm_put(Dst, 251); + dasm_put(Dst, 319); break; case COMPLEX_FLOAT_TYPE: lua_pop(L, 1); -#if defined _WIN64 || defined __amd64__ + dasm_put(Dst, 292, mt); +#if defined _WIN64 + /* complex floats are two floats packed into a int64_t */ + get_int(Dst, ct, ®, 1); +#elif defined __amd64__ /* complex floats are two floats packed into a double */ - dasm_put(Dst, 224, mt); get_float(Dst, ct, ®, 1); - dasm_put(Dst, 254); #else /* complex floats are real followed by imag on the stack */ - dasm_put(Dst, 224, mt); get_float(Dst, ct, ®, 0); - dasm_put(Dst, 259); + dasm_put(Dst, 322); get_float(Dst, ct, ®, 0); - dasm_put(Dst, 262); + dasm_put(Dst, 325); #endif break; case COMPLEX_DOUBLE_TYPE: lua_pop(L, 1); - dasm_put(Dst, 224, mt); + dasm_put(Dst, 292, mt); +#if defined _WIN64 + get_int(Dst, ct, ®, 1); +#else /* real */ get_float(Dst, ct, ®, 1); - dasm_put(Dst, 266); + dasm_put(Dst, 329); /* imag */ get_float(Dst, ct, ®, 1); - dasm_put(Dst, 269); + dasm_put(Dst, 332); +#endif break; case FLOAT_TYPE: case DOUBLE_TYPE: lua_pop(L, 1); get_float(Dst, ct, ®, mt->type == DOUBLE_TYPE); - dasm_put(Dst, 273); + dasm_put(Dst, 336); break; case BOOL_TYPE: lua_pop(L, 1); get_int(Dst, ct, ®, 0); - dasm_put(Dst, 285); + dasm_put(Dst, 348); break; case INT8_TYPE: lua_pop(L, 1); get_int(Dst, ct, ®, 0); if (mt->is_unsigned) { - dasm_put(Dst, 300); + dasm_put(Dst, 363); } else { - dasm_put(Dst, 304); + dasm_put(Dst, 367); } - dasm_put(Dst, 308); + dasm_put(Dst, 371); break; case INT16_TYPE: lua_pop(L, 1); get_int(Dst, ct, ®, 0); if (mt->is_unsigned) { - dasm_put(Dst, 320); + dasm_put(Dst, 383); } else { - dasm_put(Dst, 324); + dasm_put(Dst, 387); } - dasm_put(Dst, 308); + dasm_put(Dst, 371); break; case ENUM_TYPE: @@ -638,9 +792,9 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_pop(L, 1); get_int(Dst, ct, ®, 0); if (mt->is_unsigned) { - dasm_put(Dst, 328); + dasm_put(Dst, 391); } else { - dasm_put(Dst, 308); + dasm_put(Dst, 371); } break; @@ -653,7 +807,7 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_rawgeti(L, ct_usr, 0); mt = (const struct ctype*) lua_touserdata(L, -1); - dasm_put(Dst, 340, (mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0, nargs); + dasm_put(Dst, 403, (mt->pointers || mt->is_reference || mt->type != VOID_TYPE) ? 1 : 0, nargs); // Unpack the return argument if not "void", also clean-up the lua stack // to remove the return argument and bind table. Use lua_settop rather @@ -662,7 +816,7 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* usr value */ lua_rawseti(L, -2, ++num_upvals); /* mt */ - dasm_put(Dst, 366, num_upvals-1, mt); + dasm_put(Dst, 421, num_upvals-1, mt); } else { switch (mt->type) { @@ -670,12 +824,12 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp lua_getuservalue(L, -1); lua_rawseti(L, -3, ++num_upvals); /* usr value */ lua_rawseti(L, -2, ++num_upvals); /* mt */ - dasm_put(Dst, 454, num_upvals-1, mt); + dasm_put(Dst, 509, num_upvals-1, mt); break; case VOID_TYPE: lua_pop(L, 1); - dasm_put(Dst, 542); + dasm_put(Dst, 597); break; case BOOL_TYPE: @@ -684,63 +838,103 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp case INT32_TYPE: lua_pop(L, 1); if (mt->is_unsigned) { - dasm_put(Dst, 562); + dasm_put(Dst, 617); } else { - dasm_put(Dst, 582); + dasm_put(Dst, 637); } - dasm_put(Dst, 602); + dasm_put(Dst, 657); break; case INT64_TYPE: lua_pop(L, 1); if (mt->is_unsigned) { - dasm_put(Dst, 630); + dasm_put(Dst, 685); } else { - dasm_put(Dst, 650); + dasm_put(Dst, 705); } - dasm_put(Dst, 670); + dasm_put(Dst, 725); break; case INTPTR_TYPE: lua_pop(L, 1); - dasm_put(Dst, 706); + dasm_put(Dst, 761); break; case FLOAT_TYPE: case DOUBLE_TYPE: lua_pop(L, 1); - dasm_put(Dst, 753); + dasm_put(Dst, 808); if (mt->type == FLOAT_TYPE) { } else { } - dasm_put(Dst, 773); + dasm_put(Dst, 828); break; - + case STRUCT_TYPE: + case UNION_TYPE:{ +#if defined __amd64__ + int floats=float_reg_size(L,-1,mt); +#endif + int size=mt->base_size; + lua_getuservalue(L, -1); + lua_rawseti(L, -3, ++num_upvals); /* usr value */ + lua_rawseti(L, -2, ++num_upvals); /* mt */ + dasm_put(Dst, 856, num_upvals-1, mt); +#if defined _WIN64 + if(!return_by_address(mt)){ + dasm_put(Dst, 944); + }else +#elif defined __amd64__ + if(floats){ + if(size<=8){ + dasm_put(Dst, 947); + }else{ + dasm_put(Dst, 953); + } + }else if(size<=16){ + if(size<=8){ + dasm_put(Dst, 944); + }else{ + dasm_put(Dst, 965); + } + }else +#else + #ifdef _WIN32 + if(size<=8){ + if(size<=4){ + dasm_put(Dst, 944); + }else{ + dasm_put(Dst, 973); + } + }else + #endif + +#endif + { + dasm_put(Dst, 981, hidden_arg_off, size, hidden_arg_off); + } + break; + } case COMPLEX_FLOAT_TYPE: lua_pop(L, 1); -#if !defined HAVE_COMPLEX - luaL_error(L, "ffi lib compiled without complex number support"); -#endif + /* on 64 bit complex floats are two floats packed into a double, * on 32 bit returned complex floats use eax and edx */ - dasm_put(Dst, 801); + dasm_put(Dst, 1004); break; case COMPLEX_DOUBLE_TYPE: lua_pop(L, 1); -#if !defined HAVE_COMPLEX - luaL_error(L, "ffi lib compiled without complex number support"); -#endif + /* on 64 bit, returned complex doubles use xmm0, xmm1, on 32 bit * there is a hidden first parameter that points to 16 bytes where * the returned arg is stored which is popped by the called * function */ -#if defined _WIN64 || defined __amd64__ - dasm_put(Dst, 856); +#if defined _WIN64 +#elif defined __amd64__ #else - dasm_put(Dst, 921, hidden_arg_off); + dasm_put(Dst, 1059, hidden_arg_off); #endif break; @@ -749,7 +943,7 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp } } - dasm_put(Dst, 971, x86_return_size(L, ct_usr, ct)); + dasm_put(Dst, 1109, x86_return_size(L, ct_usr, ct)); lua_pop(L, 1); /* upval table - already in registry */ assert(lua_gettop(L) == top); @@ -762,17 +956,47 @@ cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctyp return *pf; } +// leave enough stack for structs +static int caculate_extra_stack(lua_State* L,int ct_usr,size_t nargs){ + const struct ctype* mbr_ct; + int extra=0;int i; + for (i = 1; i <= nargs; i++) { + lua_rawgeti(L, ct_usr, (int) i); + mbr_ct = (const struct ctype*) lua_touserdata(L, -1); + if (!mbr_ct->pointers && !mbr_ct->is_reference) { + switch(mbr_ct->type){ + case STRUCT_TYPE: + case UNION_TYPE: + if(mbr_ct->base_size>16){ + extra+=ALIGN_UP(mbr_ct->base_size,15); + } + #if defined _WIN64 + else if(mbr_ct->base_size>8){ + extra+=16; + } + #endif + break; + #if defined _WIN64 + case COMPLEX_DOUBLE_TYPE: + extra+=16; + break; + #endif + } + } + lua_pop(L,1); + } + return extra; +} void compile_function(lua_State* L, cfunction func, int ct_usr, const struct ctype* ct) { size_t i, nargs; - int num_upvals; + int num_upvals,struct_offset; const struct ctype* mbr_ct; struct jit* Dst = get_jit(L); struct reg_alloc reg; void* p; int top = lua_gettop(L); - int* perr = &Dst->last_errno; ct_usr = lua_absindex(L, ct_usr); @@ -791,33 +1015,37 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty luaL_error(L, "vararg is only allowed with the c calling convention"); } - dasm_put(Dst, 982, 8, nargs); - if (!ct->has_var_arg) { - dasm_put(Dst, 1008, (ptrdiff_t)("too few arguments"), (ptrdiff_t)("too many arguments")); - } else { - dasm_put(Dst, 1051, (ptrdiff_t)("too few arguments")); - } - - dasm_put(Dst, 1072); - + dasm_put(Dst, 1120, 8); + struct_offset=16; /* no need to zero extend eax returned by lua_gettop to rax as x86-64 * preguarentees that the upper 32 bits will be zero */ - dasm_put(Dst, 1075, 32 + REGISTER_STACK_SPACE(ct)); + if (ct->has_var_arg) { + dasm_put(Dst, 1129, nargs, (ptrdiff_t)("too few arguments")); + }else{ + dasm_put(Dst, 132, nargs*16); + } + + dasm_put(Dst, 132, 32 + REGISTER_STACK_SPACE(ct)); + + i=caculate_extra_stack(L,ct_usr,nargs); + if(i>0){ + dasm_put(Dst, 132, i); + } -#if !defined _WIN64 && !defined __amd64__ /* Returned complex doubles require a hidden first parameter where the * data is stored, which is popped by the calling code. */ - lua_rawgeti(L, ct_usr, 0); + lua_rawgeti(L, ct_usr, 0); mbr_ct = (const struct ctype*) lua_touserdata(L, -1); - if (!mbr_ct->pointers && !mbr_ct->is_reference && mbr_ct->type == COMPLEX_DOUBLE_TYPE) { + if (return_by_address(mbr_ct)) { /* we can allocate more space for arguments as long as no add_* * function has been called yet, mbr_ct will be added as an upvalue in * the return processing later */ - dasm_put(Dst, 1085, mbr_ct); + dasm_put(Dst, 1174, mbr_ct); add_pointer(Dst, ct, ®); } - lua_pop(L, 1); -#endif + lua_pop(L,1); + + for (i = 1; i <= nargs; i++) { lua_rawgeti(L, ct_usr, (int) i); @@ -826,117 +1054,181 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty if (mbr_ct->pointers || mbr_ct->is_reference) { lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1110, mbr_ct, lua_upvalueindex(num_upvals), i); + dasm_put(Dst, 1199, mbr_ct, lua_upvalueindex(num_upvals), i); add_pointer(Dst, ct, ®); } else { switch (mbr_ct->type) { case FUNCTION_PTR_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1133, mbr_ct, lua_upvalueindex(num_upvals), i); + dasm_put(Dst, 1222, mbr_ct, lua_upvalueindex(num_upvals), i); add_pointer(Dst, ct, ®); break; case ENUM_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1156, mbr_ct, lua_upvalueindex(num_upvals), i); + dasm_put(Dst, 1245, mbr_ct, lua_upvalueindex(num_upvals), i); add_int(Dst, ct, ®, 0); break; case INT8_TYPE: - dasm_put(Dst, 1179, i); + dasm_put(Dst, 1268, i); if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1192); + dasm_put(Dst, 1281); } else { - dasm_put(Dst, 1196); + dasm_put(Dst, 1285); } add_int(Dst, ct, ®, 0); lua_pop(L, 1); break; case INT16_TYPE: - dasm_put(Dst, 1179, i); + dasm_put(Dst, 1268, i); if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1200); + dasm_put(Dst, 1289); } else { - dasm_put(Dst, 1204); + dasm_put(Dst, 1293); } add_int(Dst, ct, ®, 0); lua_pop(L, 1); break; case BOOL_TYPE: - dasm_put(Dst, 1208, i); + dasm_put(Dst, 1297, i); add_int(Dst, ct, ®, 0); lua_pop(L, 1); break; case INT32_TYPE: if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1231, i); + dasm_put(Dst, 1320, i); } else { - dasm_put(Dst, 1179, i); + dasm_put(Dst, 1268, i); } add_int(Dst, ct, ®, 0); lua_pop(L, 1); break; case INTPTR_TYPE: - dasm_put(Dst, 1244, i); + dasm_put(Dst, 1333, i); add_pointer(Dst, ct, ®); lua_pop(L, 1); break; case INT64_TYPE: if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1257, i); + dasm_put(Dst, 1346, i); } else { - dasm_put(Dst, 1270, i); + dasm_put(Dst, 1359, i); } add_int(Dst, ct, ®, 1); lua_pop(L, 1); break; case DOUBLE_TYPE: - dasm_put(Dst, 1283, i); + dasm_put(Dst, 1372, i); add_float(Dst, ct, ®, 1); lua_pop(L, 1); break; - - case COMPLEX_DOUBLE_TYPE: - /* on 64 bit, returned complex doubles use xmm0, xmm1, on 32 bit + case STRUCT_TYPE: + case UNION_TYPE: + /*Struct/Union in win 64 is pass by integer register if less than 64bit and aligned 8 + *or it's passed by momory pointer. On amd64, it's passed by registers less than 16 bytes(32 bytes for floating aggregates) + *else it's copy to stack. On x86, it's copied to the stack. Argument can't be splited between stack and registers. + */ + lua_getuservalue(L, -1); + num_upvals += 2; + dasm_put(Dst, 1385, mbr_ct, lua_upvalueindex(num_upvals), i); +#if defined _WIN64 + { + int size=mbr_ct->base_size; + if(size!=8&&size!=2&&size!=1&&size!=4){ + struct_offset+=ALIGN_UP(size,15);//16 byte alignment required + add_int(Dst, ct, ®, 1); + }else{ + add_int(Dst, ct, ®, 1); + } + } +#elif defined __amd64__ + { + int size=mbr_ct->base_size; + int floats=float_reg_size(L,-2,mbr_ct); + if(floats){ + if(size>8&®.floats==MAX_FLOAT_REGISTERS(ct)-1){ + reg.floats++;// the whole arguments should be in stack or registers + } + // 1st float + add_float(Dst, ct, ®, 1); + if(size>8){// 2nd float + add_float(Dst, ct, ®, 1); + } + }else if(size<=16){ + if(size>8&®.ints==MAX_INT_REGISTERS(ct)-1){ + reg.ints++;// the whole arguments should be in stack or registers + } + if(size>8){ + add_int(Dst, ct, ®, 1); + add_int(Dst, ct, ®, 1); + }else{ + add_int(Dst, ct, ®, 1); + } + }else{ //passed in stack + if(reg.off&7){ + reg.off=ALIGN_UP(reg.off,7); + } + size=ALIGN_UP(size,7); + reg.off+=size; + } + } +#else + { + int size=ALIGN_UP(mbr_ct->base_size,3); + dasm_put(Dst, 1408, reg.off, size); + reg.off+=size; + } +#endif + break; + case COMPLEX_DOUBLE_TYPE:// passed by memory copy pointer in win64 + /* on amd64, returned complex doubles use xmm0, xmm1, on 32 bit or win64 * there is a hidden first parameter that points to 16 bytes where * the returned arg is stored (this is popped by the called - * function) */ -#if defined _WIN64 || defined __amd64__ - dasm_put(Dst, 1296, i); + * function on 32 bit) */ +#if defined _WIN64 + struct_offset+=16; + add_int(Dst, ct, ®, 1);//save the address +#elif defined __amd64__ + if(reg.floats==MAX_FLOAT_REGISTERS(ct)-1){ + reg.floats++;// the whole arguments should be in stack or registers + } add_float(Dst, ct, ®, 1); - dasm_put(Dst, 1309); add_float(Dst, ct, ®, 1); #else - dasm_put(Dst, 1315, reg.off, i); + dasm_put(Dst, 1430, reg.off, i); reg.off += 16; #endif lua_pop(L, 1); break; case FLOAT_TYPE: - dasm_put(Dst, 1283, i); + dasm_put(Dst, 1372, i); add_float(Dst, ct, ®, 0); lua_pop(L, 1); break; case COMPLEX_FLOAT_TYPE: -#if defined _WIN64 || defined __amd64__ - dasm_put(Dst, 1341, i); +#if defined _WIN64 + /* complex floats are return in rax */ + add_int(Dst, ct, ®, 1); +#elif defined __amd64__ /* complex floats are two floats packed into a double */ add_float(Dst, ct, ®, 1); + #else /* returned complex floats use eax and edx */ - dasm_put(Dst, 1354, i); + dasm_put(Dst, 1456, i); add_float(Dst, ct, ®, 0); - dasm_put(Dst, 1373); + dasm_put(Dst, 1475); add_float(Dst, ct, ®, 0); #endif lua_pop(L, 1); @@ -970,14 +1262,11 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty reg.floats = MAX_FLOAT_REGISTERS(ct); reg.ints = MAX_INT_REGISTERS(ct); #else - dasm_put(Dst, 1380, reg.off, nargs+1); + dasm_put(Dst, 1482, reg.off, nargs+1); #endif } - dasm_put(Dst, 1406, perr); - - /* remove the stack space to call local functions */ - dasm_put(Dst, 1418); + dasm_put(Dst, 1508); #ifdef _WIN64 switch (reg.regs) { @@ -1037,14 +1326,14 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty if (ct->calling_convention == FAST_CALL) { switch (reg.ints) { case 2: - dasm_put(Dst, 1422, 4); + dasm_put(Dst, 1512, 4); case 1: - dasm_put(Dst, 1428); + dasm_put(Dst, 1518); case 0: break; } - dasm_put(Dst, 1432, REGISTER_STACK_SPACE(ct)); + dasm_put(Dst, 1522, REGISTER_STACK_SPACE(ct)); } #endif @@ -1056,7 +1345,7 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty } #endif - dasm_put(Dst, 1436); + dasm_put(Dst, 1526); /* note on windows X86 the stack may be only aligned to 4 (stdcall will * have popped a multiple of 4 bytes), but we don't need 16 byte alignment on @@ -1069,90 +1358,145 @@ void compile_function(lua_State* L, cfunction func, int ct_usr, const struct cty if (mbr_ct->pointers || mbr_ct->is_reference || mbr_ct->type == INTPTR_TYPE) { lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1445, perr, mbr_ct, lua_upvalueindex(num_upvals)); + dasm_put(Dst, 1535, mbr_ct, lua_upvalueindex(num_upvals)); } else { switch (mbr_ct->type) { + case STRUCT_TYPE: + case UNION_TYPE:{ + lua_getuservalue(L, -1); + num_upvals += 2; + +#if defined _WIN64 + if(return_by_address(mbr_ct)){ + fix_usr_value(Dst,L,num_upvals); + }else{ + } + +#elif defined __amd64__ + if(mbr_ct->base_size>16){ + fix_usr_value(Dst,L, num_upvals); + }else{ + int floats=float_reg_size(L,-2,mbr_ct),size=mbr_ct->base_size; + if(floats){ + if(floats>1){ + } + }else{ + if(size>8){ + } + } + if(size>8){ + } + + } +#else + { + #if defined _WIN32 + int size=ALIGN_UP(mbr_ct->base_size,3); + if(size==8){ + dasm_put(Dst, 1581); + } + + if(size<=8){// small struct is return by value in win32 + dasm_put(Dst, 1586, mbr_ct, lua_upvalueindex(num_upvals)); + if(size==8){ + dasm_put(Dst, 1614); + } + }else + #endif + { + fix_usr_value(Dst,L, num_upvals); + } + + } +#endif + dasm_put(Dst, 1562); + break; + } case FUNCTION_PTR_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1445, perr, mbr_ct, lua_upvalueindex(num_upvals)); + dasm_put(Dst, 1535, mbr_ct, lua_upvalueindex(num_upvals)); break; case INT64_TYPE: -#if LUA_VERSION_NUM == 503 +#if LUA_VERSION_NUM >= 503 lua_pop(L, 1); - if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1499, perr); - } else { - dasm_put(Dst, 1499, perr); - } + + dasm_put(Dst, 1622); + #else num_upvals++; - dasm_put(Dst, 1545, perr, mbr_ct); + dasm_put(Dst, 1656, mbr_ct); #endif break; case COMPLEX_FLOAT_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1613, perr, mbr_ct, lua_upvalueindex(num_upvals)); + dasm_put(Dst, 1716, mbr_ct, lua_upvalueindex(num_upvals)); break; case COMPLEX_DOUBLE_TYPE: lua_getuservalue(L, -1); num_upvals += 2; - dasm_put(Dst, 1678, perr); +#if defined _WIN64 + fix_usr_value(Dst,L,num_upvals); +#elif defined __amd64__ +#else + fix_usr_value(Dst,L,num_upvals); +#endif + dasm_put(Dst, 1773); break; case VOID_TYPE: lua_pop(L, 1); - dasm_put(Dst, 1709, perr); + dasm_put(Dst, 1796); break; case BOOL_TYPE: lua_pop(L, 1); - dasm_put(Dst, 1736, perr); + dasm_put(Dst, 1815); break; case INT8_TYPE: lua_pop(L, 1); if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1192); + dasm_put(Dst, 1281); } else { - dasm_put(Dst, 1196); + dasm_put(Dst, 1285); } - dasm_put(Dst, 1785, perr); + dasm_put(Dst, 1848); break; case INT16_TYPE: lua_pop(L, 1); if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1200); + dasm_put(Dst, 1289); } else { - dasm_put(Dst, 1204); + dasm_put(Dst, 1293); } - dasm_put(Dst, 1785, perr); + dasm_put(Dst, 1848); break; case INT32_TYPE: case ENUM_TYPE: lua_pop(L, 1); if (mbr_ct->is_unsigned) { - dasm_put(Dst, 1831, perr); + dasm_put(Dst, 1878); } else { - dasm_put(Dst, 1785, perr); + dasm_put(Dst, 1848); } break; case FLOAT_TYPE: lua_pop(L, 1); - dasm_put(Dst, 1877, perr); + dasm_put(Dst, 1908); break; case DOUBLE_TYPE: lua_pop(L, 1); - dasm_put(Dst, 1877, perr); + dasm_put(Dst, 1908); break; default: diff --git a/texk/web2c/luatexdir/luaffi/ctype.c b/texk/web2c/luatexdir/luaffi/ctype.c index f477ea5bc3..e53513eb4a 100644 --- a/texk/web2c/luatexdir/luaffi/ctype.c +++ b/texk/web2c/luatexdir/luaffi/ctype.c @@ -6,6 +6,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +#include #include "ffi.h" static int to_define_key; @@ -82,15 +83,7 @@ void set_defined(lua_State* L, int ct_usr, struct ctype* ct) lua_pop(L, 1); } } - -struct ctype* push_ctype(lua_State* L, int ct_usr, const struct ctype* ct) -{ - struct ctype* ret; - ct_usr = lua_absindex(L, ct_usr); - - ret = (struct ctype*) lua_newuserdata(L, sizeof(struct ctype)); - *ret = *ct; - +void setup_ctype(lua_State* L,int ct_usr,const struct ctype* ct){ push_upval(L, &ctype_mt_key); lua_setmetatable(L, -2); @@ -109,6 +102,29 @@ struct ctype* push_ctype(lua_State* L, int ct_usr, const struct ctype* ct) if (!ct->is_defined && ct_usr && !lua_isnil(L, ct_usr)) { update_on_definition(L, ct_usr, -1); } +} +struct member_type* push_member_type(lua_State* L, int ct_usr, const struct member_type* mt) +{ + struct member_type* ret; + ct_usr = lua_absindex(L, ct_usr); + + ret = (struct member_type*) lua_newuserdata(L, sizeof(struct member_type)); + *ret = *mt; + + setup_ctype(L,ct_usr,&mt->ct); + + return ret; +} + +struct ctype* push_ctype(lua_State* L, int ct_usr, const struct ctype* ct) +{ + struct ctype* ret; + ct_usr = lua_absindex(L, ct_usr); + + ret = (struct ctype*) lua_newuserdata(L, sizeof(struct ctype)); + *ret = *ct; + + setup_ctype(L,ct_usr,ct); return ret; } @@ -146,9 +162,11 @@ void* push_cdata(lua_State* L, int ct_usr, const struct ctype* ct) * then writing the bits back) and the read is aligned its a non-issue, * but valgrind complains nonetheless. */ - if (ct->has_bitfield) { + /* Changed:To allow fast write to memory for struct in 64-bit machine in jit + */ + //if (ct->has_bitfield) { sz = ALIGN_UP(sz, 7); - } + //} cd = (struct cdata*) lua_newuserdata(L, sizeof(struct cdata) + sz); *(struct ctype*) &cd->type = *ct; @@ -196,12 +214,16 @@ void push_callback(lua_State* L, cfunction luafunc, cfunction cfunc) void check_ctype(lua_State* L, int idx, struct ctype* ct) { if (lua_isstring(L, idx)) { - struct parser P; + struct parser P;char ch; P.line = 1; P.prev = P.next = lua_tostring(L, idx); P.align_mask = DEFAULT_ALIGN_MASK; parse_type(L, &P, ct); - parse_argument(L, &P, -1, ct, NULL, NULL); + parse_argument(L, &P, -1, ct, NULL, NULL, 0); + ch=P.next[0]; + if(ch&&!isspace(ch)){ + luaL_error(L,"unexpected end of type name :%s",P.next); + } lua_remove(L, -2); /* remove the user value from parse_type */ } else if (lua_getmetatable(L, idx)) { @@ -224,6 +246,35 @@ void check_ctype(lua_State* L, int idx, struct ctype* ct) luaL_error(L, "expected cdata, ctype or string for arg #%d", idx); } +static ALWAYS_INLINE int is_cdata(lua_State* L, int idx){ + if (!lua_isuserdata(L, idx) || !lua_getmetatable(L, idx)) { + lua_pushnil(L); + return 0; + } + + if (!equals_upval(L, -1, &cdata_mt_key)) { + lua_pop(L, 1); /* mt */ + lua_pushnil(L); + return 0; + } + lua_pop(L, 1); /* mt */ + return 1; +} + +/** + * get_ctype return the type for the c_data on idx + * @param L + * @param idx + * @return + */ +const struct ctype* get_ctype(lua_State* L, int idx){ + + if(!is_cdata(L,idx)) + return NULL; + + return &((struct cdata*) lua_touserdata(L, idx))->type; + +} /* to_cdata returns the struct cdata* and pushes the user value onto the * stack. If the index is not a ctype then ct is set to the zero value such * that ct->type is INVALID_TYPE, a nil is pushed, and NULL is returned. */ @@ -232,21 +283,11 @@ void* to_cdata(lua_State* L, int idx, struct ctype* ct) struct cdata* cd; memset(ct, 0, sizeof(struct ctype)); - if (!lua_isuserdata(L, idx) || !lua_getmetatable(L, idx)) { - lua_pushnil(L); - return NULL; - } - if (!equals_upval(L, -1, &cdata_mt_key)) { - lua_pop(L, 1); /* mt */ - lua_pushnil(L); + if(!is_cdata(L,idx)) return NULL; - } - lua_pop(L, 1); /* mt */ cd = (struct cdata*) lua_touserdata(L, idx); - - if (!cd) {lua_pushnil(L);return NULL;} *ct = cd->type; lua_getuservalue(L, idx); diff --git a/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.h b/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.h index 71a4979193..90eaef7333 100644 --- a/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.h +++ b/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.h @@ -1,7 +1,7 @@ /* ** DynASM ARM encoding engine. -** Copyright (C) 2005-2011 Mike Pall. All rights reserved. -** Released under the MIT/X license. See dynasm.lua for full copyright notice. +** Copyright (C) 2005-2017 Mike Pall. All rights reserved. +** Released under the MIT license. See dynasm.lua for full copyright notice. */ #include @@ -22,7 +22,7 @@ enum { DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, /* The following actions also have an argument. */ DASM_REL_PC, DASM_LABEL_PC, - DASM_LONG, DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, + DASM_LONG,DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, DASM_IMMV8, DASM__MAX }; @@ -211,7 +211,8 @@ void dasm_put(Dst_DECL, int start, ...) case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; case DASM_REL_LG: n = (ins & 2047) - 10; pl = D->lglabels + n; - if (n >= 0) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */ + /* Bkwd rel or global. */ + if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } pl += 10; n = *pl; if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ goto linkrel; @@ -239,7 +240,7 @@ void dasm_put(Dst_DECL, int start, ...) *pl = -pos; /* Label exists now. */ b[pos++] = ofs; /* Store pass1 offset estimate. */ break; - case DASM_LONG: + case DASM_LONG: ofs += 4; b[pos++] = n; break; @@ -254,6 +255,10 @@ void dasm_put(Dst_DECL, int start, ...) #endif b[pos++] = n; break; + case DASM_IMMV8: + CK((n & 3) == 0, RANGE_I); + n >>= 2; + /* fallthrough */ case DASM_IMML8: case DASM_IMML12: CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) : @@ -319,8 +324,8 @@ int dasm_link(Dst_DECL, size_t *szp) case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; case DASM_REL_LG: case DASM_REL_PC: pos++; break; case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; - case DASM_LONG: case DASM_IMM: case DASM_IMM12: case DASM_IMM16: - case DASM_IMML8: case DASM_IMML12: pos++; break; + case DASM_IMM: case DASM_LONG:case DASM_IMM12: case DASM_IMM16: + case DASM_IMML8: case DASM_IMML12: case DASM_IMMV8: pos++; break; } } stop: (void)0; @@ -371,6 +376,7 @@ int dasm_encode(Dst_DECL, void *buffer) break; case DASM_REL_LG: CK(n >= 0, UNDEF_LG); + /* fallthrough */ case DASM_REL_PC: CK(n >= 0, UNDEF_PC); n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4; @@ -381,17 +387,21 @@ int dasm_encode(Dst_DECL, void *buffer) } else if ((ins & 0x1000)) { CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL); goto patchimml8; - } else { + } else if ((ins & 0x2000) == 0) { CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL); - goto patchimml12; + goto patchimml; + } else { + CK((n & 3) == 0 && -1020 <= n && n <= 1020, RANGE_REL); + n >>= 2; + goto patchimml; } break; case DASM_LABEL_LG: ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); break; case DASM_LABEL_PC: break; - case DASM_LONG: - *cp++ = n; + case DASM_LONG: + *cp++ = (unsigned int) n; break; case DASM_IMM: cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31); @@ -406,7 +416,7 @@ int dasm_encode(Dst_DECL, void *buffer) cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) : ((-n & 0x0f) | ((-n & 0xf0) << 4)); break; - case DASM_IMML12: patchimml12: + case DASM_IMML12: case DASM_IMMV8: patchimml: cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n); break; default: *cp++ = ins; break; diff --git a/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.lua b/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.lua index a54230db37..9e7b45770d 100644 --- a/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.lua +++ b/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm.lua @@ -1,7 +1,7 @@ ------------------------------------------------------------------------------ -- DynASM ARM module. -- --- Copyright (C) 2005-2011 Mike Pall. All rights reserved. +-- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------ @@ -9,9 +9,9 @@ local _info = { arch = "arm", description = "DynASM ARM module", - version = "1.3.0", - vernum = 10300, - release = "2011-05-05", + version = "1.4.0", + vernum = 10400, + release = "2015-10-18", author = "Mike Pall", license = "MIT", } @@ -26,6 +26,9 @@ local _s = string local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub local concat, sort, insert = table.concat, table.sort, table.insert +local bit = bit or require("bit") +local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift +local ror, tohex = bit.ror, bit.tohex -- Inherited tables and callbacks. local g_opt, g_arch @@ -36,7 +39,7 @@ local wline, werror, wfatal, wwarn local action_names = { "STOP", "SECTION", "ESC", "REL_EXT", "ALIGN", "REL_LG", "LABEL_LG", - "REL_PC", "LABEL_PC", "LONG", "IMM", "IMM12", "IMM16", "IMML8", "IMML12", + "REL_PC", "LABEL_PC","LONG", "IMM", "IMM12", "IMM16", "IMML8", "IMML12", "IMMV8", } -- Maximum number of section buffer positions for dasm_put(). @@ -60,11 +63,6 @@ local secpos = 1 ------------------------------------------------------------------------------ --- Return 8 digit hex number. -local function tohex(x) - return sub(format("%08x", x), -8) -- Avoid 64 bit portability problem in Lua. -end - -- Dump action names and numbers. local function dumpactions(out) out:write("DynASM encoding engine action codes:\n") @@ -407,14 +405,14 @@ local map_op = { strd_2 = "e00000f0DL", strd_3 = "e00000f0DL", -- v5TE ldrsh_2 = "e01000f0DL", ldrsh_3 = "e01000f0DL", - ldm_2 = "e8900000nR", ldmia_2 = "e8900000nR", ldmfd_2 = "e8900000nR", - ldmda_2 = "e8100000nR", ldmfa_2 = "e8100000nR", - ldmdb_2 = "e9100000nR", ldmea_2 = "e9100000nR", - ldmib_2 = "e9900000nR", ldmed_2 = "e9900000nR", - stm_2 = "e8800000nR", stmia_2 = "e8800000nR", stmfd_2 = "e8800000nR", - stmda_2 = "e8000000nR", stmfa_2 = "e8000000nR", - stmdb_2 = "e9000000nR", stmea_2 = "e9000000nR", - stmib_2 = "e9800000nR", stmed_2 = "e9800000nR", + ldm_2 = "e8900000oR", ldmia_2 = "e8900000oR", ldmfd_2 = "e8900000oR", + ldmda_2 = "e8100000oR", ldmfa_2 = "e8100000oR", + ldmdb_2 = "e9100000oR", ldmea_2 = "e9100000oR", + ldmib_2 = "e9900000oR", ldmed_2 = "e9900000oR", + stm_2 = "e8800000oR", stmia_2 = "e8800000oR", stmfd_2 = "e8800000oR", + stmda_2 = "e8000000oR", stmfa_2 = "e8000000oR", + stmdb_2 = "e9000000oR", stmea_2 = "e9000000oR", + stmib_2 = "e9800000oR", stmed_2 = "e9800000oR", pop_1 = "e8bd0000R", push_1 = "e92d0000R", -- Branch instructions. @@ -430,9 +428,89 @@ local map_op = { svc_1 = "ef000000T", swi_1 = "ef000000T", ud_0 = "e7f001f0", - -- NYI: Advanced SIMD and VFP instructions. - - -- NYI instructions, since I have no need for them right now: + -- VFP instructions. + ["vadd.f32_3"] = "ee300a00dnm", + ["vadd.f64_3"] = "ee300b00Gdnm", + ["vsub.f32_3"] = "ee300a40dnm", + ["vsub.f64_3"] = "ee300b40Gdnm", + ["vmul.f32_3"] = "ee200a00dnm", + ["vmul.f64_3"] = "ee200b00Gdnm", + ["vnmul.f32_3"] = "ee200a40dnm", + ["vnmul.f64_3"] = "ee200b40Gdnm", + ["vmla.f32_3"] = "ee000a00dnm", + ["vmla.f64_3"] = "ee000b00Gdnm", + ["vmls.f32_3"] = "ee000a40dnm", + ["vmls.f64_3"] = "ee000b40Gdnm", + ["vnmla.f32_3"] = "ee100a40dnm", + ["vnmla.f64_3"] = "ee100b40Gdnm", + ["vnmls.f32_3"] = "ee100a00dnm", + ["vnmls.f64_3"] = "ee100b00Gdnm", + ["vdiv.f32_3"] = "ee800a00dnm", + ["vdiv.f64_3"] = "ee800b00Gdnm", + + ["vabs.f32_2"] = "eeb00ac0dm", + ["vabs.f64_2"] = "eeb00bc0Gdm", + ["vneg.f32_2"] = "eeb10a40dm", + ["vneg.f64_2"] = "eeb10b40Gdm", + ["vsqrt.f32_2"] = "eeb10ac0dm", + ["vsqrt.f64_2"] = "eeb10bc0Gdm", + ["vcmp.f32_2"] = "eeb40a40dm", + ["vcmp.f64_2"] = "eeb40b40Gdm", + ["vcmpe.f32_2"] = "eeb40ac0dm", + ["vcmpe.f64_2"] = "eeb40bc0Gdm", + ["vcmpz.f32_1"] = "eeb50a40d", + ["vcmpz.f64_1"] = "eeb50b40Gd", + ["vcmpze.f32_1"] = "eeb50ac0d", + ["vcmpze.f64_1"] = "eeb50bc0Gd", + + vldr_2 = "ed100a00dl|ed100b00Gdl", + vstr_2 = "ed000a00dl|ed000b00Gdl", + vldm_2 = "ec900a00or", + vldmia_2 = "ec900a00or", + vldmdb_2 = "ed100a00or", + vpop_1 = "ecbd0a00r", + vstm_2 = "ec800a00or", + vstmia_2 = "ec800a00or", + vstmdb_2 = "ed000a00or", + vpush_1 = "ed2d0a00r", + + ["vmov.f32_2"] = "eeb00a40dm|eeb00a00dY", -- #imm is VFPv3 only + ["vmov.f64_2"] = "eeb00b40Gdm|eeb00b00GdY", -- #imm is VFPv3 only + vmov_2 = "ee100a10Dn|ee000a10nD", + vmov_3 = "ec500a10DNm|ec400a10mDN|ec500b10GDNm|ec400b10GmDN", + + vmrs_0 = "eef1fa10", + vmrs_1 = "eef10a10D", + vmsr_1 = "eee10a10D", + + ["vcvt.s32.f32_2"] = "eebd0ac0dm", + ["vcvt.s32.f64_2"] = "eebd0bc0dGm", + ["vcvt.u32.f32_2"] = "eebc0ac0dm", + ["vcvt.u32.f64_2"] = "eebc0bc0dGm", + ["vcvtr.s32.f32_2"] = "eebd0a40dm", + ["vcvtr.s32.f64_2"] = "eebd0b40dGm", + ["vcvtr.u32.f32_2"] = "eebc0a40dm", + ["vcvtr.u32.f64_2"] = "eebc0b40dGm", + ["vcvt.f32.s32_2"] = "eeb80ac0dm", + ["vcvt.f64.s32_2"] = "eeb80bc0GdFm", + ["vcvt.f32.u32_2"] = "eeb80a40dm", + ["vcvt.f64.u32_2"] = "eeb80b40GdFm", + ["vcvt.f32.f64_2"] = "eeb70bc0dGm", + ["vcvt.f64.f32_2"] = "eeb70ac0GdFm", + + -- VFPv4 only: + ["vfma.f32_3"] = "eea00a00dnm", + ["vfma.f64_3"] = "eea00b00Gdnm", + ["vfms.f32_3"] = "eea00a40dnm", + ["vfms.f64_3"] = "eea00b40Gdnm", + ["vfnma.f32_3"] = "ee900a40dnm", + ["vfnma.f64_3"] = "ee900b40Gdnm", + ["vfnms.f32_3"] = "ee900a00dnm", + ["vfnms.f64_3"] = "ee900b00Gdnm", + + -- NYI: Advanced SIMD instructions. + + -- NYI: I have no need for these instructions right now: -- swp, swpb, strex, ldrex, strexd, ldrexd, strexb, ldrexb, strexh, ldrexh -- msr, nopv6, yield, wfe, wfi, sev, dbg, bxj, smc, srs, rfe -- cps, setend, pli, pld, pldw, clrex, dsb, dmb, isb @@ -478,13 +556,25 @@ local function parse_gpr_pm(expr) return parse_gpr(expr2), (pm == "-") end +local function parse_vr(expr, tp) + local t, r = match(expr, "^([sd])([0-9]+)$") + if t == tp then + r = tonumber(r) + if r <= 31 then + if t == "s" then return shr(r, 1), band(r, 1) end + return band(r, 15), shr(r, 4) + end + end + werror("bad register name `"..expr.."'") +end + local function parse_reglist(reglist) reglist = match(reglist, "^{%s*([^}]*)}$") if not reglist then werror("register list expected") end local rr = 0 for p in gmatch(reglist..",", "%s*([^,]*),") do - local rbit = 2^parse_gpr(gsub(p, "%s+$", "")) - if ((rr - (rr % rbit)) / rbit) % 2 ~= 0 then + local rbit = shl(1, parse_gpr(gsub(p, "%s+$", ""))) + if band(rr, rbit) ~= 0 then werror("duplicate register `"..p.."'") end rr = rr + rbit @@ -492,21 +582,34 @@ local function parse_reglist(reglist) return rr end +local function parse_vrlist(reglist) + local ta, ra, tb, rb = match(reglist, + "^{%s*([sd])([0-9]+)%s*%-%s*([sd])([0-9]+)%s*}$") + ra, rb = tonumber(ra), tonumber(rb) + if ta and ta == tb and ra and rb and ra <= 31 and rb <= 31 and ra <= rb then + local nr = rb+1 - ra + if ta == "s" then + return shl(shr(ra,1),12)+shl(band(ra,1),22) + nr + else + return shl(band(ra,15),12)+shl(shr(ra,4),22) + nr*2 + 0x100 + end + end + werror("register list expected") +end + local function parse_imm(imm, bits, shift, scale, signed) imm = match(imm, "^#(.*)$") if not imm then werror("expected immediate operand") end local n = tonumber(imm) if n then - if n % 2^scale == 0 then - n = n / 2^scale + local m = sar(n, scale) + if shl(m, scale) == n then if signed then - if n >= 0 then - if n < 2^(bits-1) then return n*2^shift end - else - if n >= -(2^(bits-1))-1 then return (n+2^bits)*2^shift end - end + local s = sar(m, bits-1) + if s == 0 then return shl(m, shift) + elseif s == -1 then return shl(m + shl(1, bits), shift) end else - if n >= 0 and n <= 2^bits-1 then return n*2^shift end + if sar(m, bits) == 0 then return shl(m, shift) end end end werror("out of range immediate `"..imm.."'") @@ -519,11 +622,10 @@ end local function parse_imm12(imm) local n = tonumber(imm) if n then - local m = n + local m = band(n) for i=0,-15,-1 do - if m >= 0 and m <= 255 and n % 1 == 0 then return m + (i%16) * 256 end - local t = m % 4 - m = (m - t) / 4 + t * 2^30 + if shr(m, 8) == 0 then return m + shl(band(i, 15), 8) end + m = ror(m, 2) end werror("out of range immediate `"..imm.."'") else @@ -537,10 +639,7 @@ local function parse_imm16(imm) if not imm then werror("expected immediate operand") end local n = tonumber(imm) if n then - if n >= 0 and n <= 65535 and n % 1 == 0 then - local t = n % 4096 - return (n - t) * 16 + t - end + if shr(n, 16) == 0 then return band(n, 0x0fff) + shl(band(n, 0xf000), 4) end werror("out of range immediate `"..imm.."'") else waction("IMM16", 32*16, imm) @@ -555,7 +654,7 @@ local function parse_imm_load(imm, ext) if n >= -255 and n <= 255 then local up = 0x00800000 if n < 0 then n = -n; up = 0 end - return (n-(n%16))*16+(n%16) + up + return shl(band(n, 0xf0), 4) + band(n, 0x0f) + up end else if n >= -4095 and n <= 4095 then @@ -565,7 +664,7 @@ local function parse_imm_load(imm, ext) end werror("out of range immediate `"..imm.."'") else - waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12), imm) + waction(ext and "IMML8" or "IMML12", 32768 + shl(ext and 8 or 12, 5), imm) return 0 end end @@ -578,10 +677,10 @@ local function parse_shift(shift, gprok) s = map_shift[s] if not s then werror("expected shift operand") end if sub(s2, 1, 1) == "#" then - return parse_imm(s2, 5, 7, 0, false) + s * 32 + return parse_imm(s2, 5, 7, 0, false) + shl(s, 5) else if not gprok then werror("expected immediate shift operand") end - return parse_gpr(s2) * 256 + s * 32 + 16 + return shl(parse_gpr(s2), 8) + shl(s, 5) + 16 end end end @@ -617,13 +716,13 @@ local function parse_label(label, def) end local function parse_load(params, nparams, n, op) - local oplo = op % 256 + local oplo = band(op, 255) local ext, ldrd = (oplo ~= 0), (oplo == 208) local d - if (ldrd or oplo == 240) then - d = ((op - (op % 4096)) / 4096) % 16 - if d % 2 ~= 0 then werror("odd destination register") end - end + --[[if (ldrd or oplo == 240) then + d = band(shr(op, 12), 15) + if band(d, 1) ~= 0 then werror("odd destination register") end + end]] local pn = params[n] local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") local p2 = params[n+1] @@ -640,7 +739,7 @@ local function parse_load(params, nparams, n, op) if tp then waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12), format(tp.ctypefmt, tailr)) - return op + d * 65536 + 0x01000000 + (ext and 0x00400000 or 0) + return op + shl(d, 16) + 0x01000000 + (ext and 0x00400000 or 0) end end end @@ -650,7 +749,7 @@ local function parse_load(params, nparams, n, op) if p2 then if wb == "!" then werror("bad use of '!'") end local p3 = params[n+2] - op = op + parse_gpr(p1) * 65536 + op = op + shl(parse_gpr(p1), 16) local imm = match(p2, "^#(.*)$") if imm then local m = parse_imm_load(imm, ext) @@ -664,7 +763,7 @@ local function parse_load(params, nparams, n, op) end else local p1a, p2 = match(p1, "^([^,%s]*)%s*(.*)$") - op = op + parse_gpr(p1a) * 65536 + 0x01000000 + op = op + shl(parse_gpr(p1a), 16) + 0x01000000 if p2 ~= "" then local imm = match(p2, "^,%s*#(.*)$") if imm then @@ -688,82 +787,132 @@ local function parse_load(params, nparams, n, op) return op end +local function parse_vload(q) + local reg, imm = match(q, "^%[%s*([^,%s]*)%s*(.*)%]$") + if reg then + local d = shl(parse_gpr(reg), 16) + if imm == "" then return d end + imm = match(imm, "^,%s*#(.*)$") + if imm then + local n = tonumber(imm) + if n then + if n >= -1020 and n <= 1020 and n%4 == 0 then + return d + (n >= 0 and n/4+0x00800000 or -n/4) + end + werror("out of range immediate `"..imm.."'") + else + waction("IMMV8", 32768 + 32*8, imm) + return d + end + end + else + if match(q, "^[<>=%-]") or match(q, "^extern%s+") then + local mode, n, s = parse_label(q, false) + waction("REL_"..mode, n + 0x2800, s, 1) + return 15 * 65536 + end + local reg, tailr = match(q, "^([%w_:]+)%s*(.*)$") + if reg and tailr ~= "" then + local d, tp = parse_gpr(reg) + if tp then + waction("IMMV8", 32768 + 32*8, format(tp.ctypefmt, tailr)) + return shl(d, 16) + end + end + end + werror("expected address operand") +end + ------------------------------------------------------------------------------ -- Handle opcodes defined with template strings. -map_op[".template__"] = function(params, template, nparams) - if not params then return sub(template, 9) end +local function parse_template(params, template, nparams, pos) local op = tonumber(sub(template, 1, 8), 16) local n = 1 - - -- Limit number of section buffer positions used by a single dasm_put(). - -- A single opcode needs a maximum of 3 positions. - if secpos+3 > maxsecpos then wflush() end - local pos = wpos() + local vr = "s" -- Process each character. for p in gmatch(sub(template, 9), ".") do + local q = params[n] if p == "D" then - op = op + parse_gpr(params[n]) * 4096; n = n + 1 + op = op + shl(parse_gpr(q), 12); n = n + 1 elseif p == "N" then - op = op + parse_gpr(params[n]) * 65536; n = n + 1 + op = op + shl(parse_gpr(q), 16); n = n + 1 elseif p == "S" then - op = op + parse_gpr(params[n]) * 256; n = n + 1 + op = op + shl(parse_gpr(q), 8); n = n + 1 elseif p == "M" then - op = op + parse_gpr(params[n]); n = n + 1 + op = op + parse_gpr(q); n = n + 1 + elseif p == "d" then + local r,h = parse_vr(q, vr); op = op+shl(r,12)+shl(h,22); n = n + 1 + elseif p == "n" then + local r,h = parse_vr(q, vr); op = op+shl(r,16)+shl(h,7); n = n + 1 + elseif p == "m" then + local r,h = parse_vr(q, vr); op = op+r+shl(h,5); n = n + 1 elseif p == "P" then - local imm = match(params[n], "^#(.*)$") + local imm = match(q, "^#(.*)$") if imm then op = op + parse_imm12(imm) + 0x02000000 else - op = op + parse_gpr(params[n]) + op = op + parse_gpr(q) end n = n + 1 elseif p == "p" then - op = op + parse_shift(params[n], true); n = n + 1 + op = op + parse_shift(q, true); n = n + 1 elseif p == "L" then op = parse_load(params, nparams, n, op) + elseif p == "l" then + op = op + parse_vload(q) elseif p == "B" then - local mode, n, s = parse_label(params[n], false) + local mode, n, s = parse_label(q, false) waction("REL_"..mode, n, s, 1) elseif p == "C" then -- blx gpr vs. blx label. - local p = params[n] - if match(p, "^([%w_]+):(r1?[0-9])$") or match(p, "^r(1?[0-9])$") then - op = op + parse_gpr(p) + if match(q, "^([%w_]+):(r1?[0-9])$") or match(q, "^r(1?[0-9])$") then + op = op + parse_gpr(q) else if op < 0xe0000000 then werror("unconditional instruction") end - local mode, n, s = parse_label(p, false) + local mode, n, s = parse_label(q, false) waction("REL_"..mode, n, s, 1) op = 0xfa000000 end - elseif p == "n" then - local r, wb = match(params[n], "^([^!]*)(!?)$") - op = op + parse_gpr(r) * 65536 + (wb == "!" and 0x00200000 or 0) + elseif p == "F" then + vr = "s" + elseif p == "G" then + vr = "d" + elseif p == "o" then + local r, wb = match(q, "^([^!]*)(!?)$") + op = op + shl(parse_gpr(r), 16) + (wb == "!" and 0x00200000 or 0) n = n + 1 elseif p == "R" then - op = op + parse_reglist(params[n]); n = n + 1 + op = op + parse_reglist(q); n = n + 1 + elseif p == "r" then + op = op + parse_vrlist(q); n = n + 1 elseif p == "W" then - op = op + parse_imm16(params[n]); n = n + 1 + op = op + parse_imm16(q); n = n + 1 elseif p == "v" then - op = op + parse_imm(params[n], 5, 7, 0, false); n = n + 1 + op = op + parse_imm(q, 5, 7, 0, false); n = n + 1 elseif p == "w" then - local imm = match(params[n], "^#(.*)$") + local imm = match(q, "^#(.*)$") if imm then - op = op + parse_imm(params[n], 5, 7, 0, false); n = n + 1 + op = op + parse_imm(q, 5, 7, 0, false); n = n + 1 else - op = op + parse_gpr(params[n]) * 256 + 16 + op = op + shl(parse_gpr(q), 8) + 16 end elseif p == "X" then - op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1 + op = op + parse_imm(q, 5, 16, 0, false); n = n + 1 + elseif p == "Y" then + local imm = tonumber(match(q, "^#(.*)$")); n = n + 1 + if not imm or shr(imm, 8) ~= 0 then + werror("bad immediate operand") + end + op = op + shl(band(imm, 0xf0), 12) + band(imm, 0x0f) elseif p == "K" then - local imm = tonumber(match(params[n], "^#(.*)$")); n = n + 1 - if not imm or imm % 1 ~= 0 or imm < 0 or imm > 0xffff then + local imm = tonumber(match(q, "^#(.*)$")); n = n + 1 + if not imm or shr(imm, 16) ~= 0 then werror("bad immediate operand") end - local t = imm % 16 - op = op + (imm - t) * 16 + t + op = op + shl(band(imm, 0xfff0), 4) + band(imm, 0x000f) elseif p == "T" then - op = op + parse_imm(params[n], 24, 0, 0, false); n = n + 1 + op = op + parse_imm(q, 24, 0, 0, false); n = n + 1 elseif p == "s" then -- Ignored. else @@ -773,6 +922,30 @@ map_op[".template__"] = function(params, template, nparams) wputpos(pos, op) end +map_op[".template__"] = function(params, template, nparams) + if not params then return template:gsub("%x%x%x%x%x%x%x%x", "") end + + -- Limit number of section buffer positions used by a single dasm_put(). + -- A single opcode needs a maximum of 3 positions. + if secpos+3 > maxsecpos then wflush() end + local pos = wpos() + local lpos, apos, spos = #actlist, #actargs, secpos + + local ok, err + for t in gmatch(template, "[^|]+") do + ok, err = pcall(parse_template, params, t, nparams, pos) + if ok then return end + secpos = spos + actlist[lpos+1] = nil + actlist[lpos+2] = nil + actlist[lpos+3] = nil + actargs[apos+1] = nil + actargs[apos+2] = nil + actargs[apos+3] = nil + end + error(err, 0) +end + ------------------------------------------------------------------------------ -- Pseudo-opcode to mark the position where the action list is to be emitted. @@ -826,11 +999,12 @@ map_op[".long_*"] = function(params) wputw(n) if secpos+2 > maxsecpos then wflush() end else - waction("LONG", 0, format("(uintptr_t)(%s)", p)) + waction("LONG", 0, format("(int)(%s)", p)) end end end + -- Alignment pseudo-opcode. map_op[".align_1"] = function(params) if not params then return "numpow2" end @@ -935,11 +1109,14 @@ function _M.mergemaps(map_coreop, map_def) setmetatable(map_op, { __index = function(t, k) local v = map_coreop[k] if v then return v end - local cc = sub(k, -4, -3) + local k1, cc, k2 = match(k, "^(.-)(..)([._].*)$") local cv = map_cond[cc] if cv then - local v = rawget(t, sub(k, 1, -5)..sub(k, -2)) - if type(v) == "string" then return format("%x%s", cv, sub(v, 2)) end + local v = rawget(t, k1..k2) + if type(v) == "string" then + local scv = format("%x", cv) + return gsub(scv..sub(v, 2), "|e", "|"..scv) + end end end }) setmetatable(map_def, { __index = map_archdef }) diff --git a/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm64.h b/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm64.h new file mode 100644 index 0000000000..8fda3c070e --- /dev/null +++ b/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm64.h @@ -0,0 +1,525 @@ +/* +** DynASM ARM64 encoding engine. +** Copyright (C) 2005-2017 Mike Pall. All rights reserved. +** Released under the MIT license. See dynasm.lua for full copyright notice. +*/ + +#include +#include +#include +#include + +#define DASM_ARCH "arm64" + +#ifndef DASM_EXTERN +#define DASM_EXTERN(a,b,c,d) 0 +#endif + +/* Action definitions. */ +enum { + DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, + /* The following actions need a buffer position. */ + DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, + /* The following actions also have an argument. */ + DASM_REL_PC, DASM_LABEL_PC, + DASM_LONG,DASM_IMM, DASM_IMM6, DASM_IMM12, DASM_IMM13W, DASM_IMM13X, DASM_IMML, + DASM__MAX +}; + +/* Maximum number of section buffer positions for a single dasm_put() call. */ +#define DASM_MAXSECPOS 25 + +/* DynASM encoder status codes. Action list offset or number are or'ed in. */ +#define DASM_S_OK 0x00000000 +#define DASM_S_NOMEM 0x01000000 +#define DASM_S_PHASE 0x02000000 +#define DASM_S_MATCH_SEC 0x03000000 +#define DASM_S_RANGE_I 0x11000000 +#define DASM_S_RANGE_SEC 0x12000000 +#define DASM_S_RANGE_LG 0x13000000 +#define DASM_S_RANGE_PC 0x14000000 +#define DASM_S_RANGE_REL 0x15000000 +#define DASM_S_UNDEF_LG 0x21000000 +#define DASM_S_UNDEF_PC 0x22000000 + +/* Macros to convert positions (8 bit section + 24 bit index). */ +#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) +#define DASM_POS2BIAS(pos) ((pos)&0xff000000) +#define DASM_SEC2POS(sec) ((sec)<<24) +#define DASM_POS2SEC(pos) ((pos)>>24) +#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) + +/* Action list type. */ +typedef const unsigned int *dasm_ActList; + +/* Per-section structure. */ +typedef struct dasm_Section { + int *rbuf; /* Biased buffer pointer (negative section bias). */ + int *buf; /* True buffer pointer. */ + size_t bsize; /* Buffer size in bytes. */ + int pos; /* Biased buffer position. */ + int epos; /* End of biased buffer position - max single put. */ + int ofs; /* Byte offset into section. */ +} dasm_Section; + +/* Core structure holding the DynASM encoding state. */ +struct dasm_State { + size_t psize; /* Allocated size of this structure. */ + dasm_ActList actionlist; /* Current actionlist pointer. */ + int *lglabels; /* Local/global chain/pos ptrs. */ + size_t lgsize; + int *pclabels; /* PC label chains/pos ptrs. */ + size_t pcsize; + void **globals; /* Array of globals (bias -10). */ + dasm_Section *section; /* Pointer to active section. */ + size_t codesize; /* Total size of all code sections. */ + int maxsection; /* 0 <= sectionidx < maxsection. */ + int status; /* Status code. */ + dasm_Section sections[1]; /* All sections. Alloc-extended. */ +}; + +/* The size of the core structure depends on the max. number of sections. */ +#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) + + +/* Initialize DynASM state. */ +void dasm_init(Dst_DECL, int maxsection) +{ + dasm_State *D; + size_t psz = 0; + int i; + Dst_REF = NULL; + DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); + D = Dst_REF; + D->psize = psz; + D->lglabels = NULL; + D->lgsize = 0; + D->pclabels = NULL; + D->pcsize = 0; + D->globals = NULL; + D->maxsection = maxsection; + for (i = 0; i < maxsection; i++) { + D->sections[i].buf = NULL; /* Need this for pass3. */ + D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); + D->sections[i].bsize = 0; + D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ + } +} + +/* Free DynASM state. */ +void dasm_free(Dst_DECL) +{ + dasm_State *D = Dst_REF; + int i; + for (i = 0; i < D->maxsection; i++) + if (D->sections[i].buf) + DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); + if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); + if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); + DASM_M_FREE(Dst, D, D->psize); +} + +/* Setup global label array. Must be called before dasm_setup(). */ +void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) +{ + dasm_State *D = Dst_REF; + D->globals = gl - 10; /* Negative bias to compensate for locals. */ + DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); +} + +/* Grow PC label array. Can be called after dasm_setup(), too. */ +void dasm_growpc(Dst_DECL, unsigned int maxpc) +{ + dasm_State *D = Dst_REF; + size_t osz = D->pcsize; + DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); + memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); +} + +/* Setup encoder. */ +void dasm_setup(Dst_DECL, const void *actionlist) +{ + dasm_State *D = Dst_REF; + int i; + D->actionlist = (dasm_ActList)actionlist; + D->status = DASM_S_OK; + D->section = &D->sections[0]; + memset((void *)D->lglabels, 0, D->lgsize); + if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); + for (i = 0; i < D->maxsection; i++) { + D->sections[i].pos = DASM_SEC2POS(i); + D->sections[i].ofs = 0; + } +} + + +#ifdef DASM_CHECKS +#define CK(x, st) \ + do { if (!(x)) { \ + D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) +#define CKPL(kind, st) \ + do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ + D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) +#else +#define CK(x, st) ((void)0) +#define CKPL(kind, st) ((void)0) +#endif + +static int dasm_imm12(unsigned int n) +{ + if ((n >> 12) == 0) + return n; + else if ((n & 0xff000fff) == 0) + return (n >> 12) | 0x1000; + else + return -1; +} + +static int dasm_ffs(unsigned long long x) +{ + int n = -1; + while (x) { x >>= 1; n++; } + return n; +} + +static int dasm_imm13(int lo, int hi) +{ + int inv = 0, w = 64, s = 0xfff, xa, xb; + unsigned long long n = (((unsigned long long)hi) << 32) | (unsigned int)lo; + unsigned long long m = 1ULL, a, b, c; + if (n & 1) { n = ~n; inv = 1; } + a = n & -n; b = (n+a)&-(n+a); c = (n+a-b)&-(n+a-b); + xa = dasm_ffs(a); xb = dasm_ffs(b); + if (c) { + w = dasm_ffs(c) - xa; + if (w == 32) m = 0x0000000100000001UL; + else if (w == 16) m = 0x0001000100010001UL; + else if (w == 8) m = 0x0101010101010101UL; + else if (w == 4) m = 0x1111111111111111UL; + else if (w == 2) m = 0x5555555555555555UL; + else return -1; + s = (-2*w & 0x3f) - 1; + } else if (!a) { + return -1; + } else if (xb == -1) { + xb = 64; + } + if ((b-a) * m != n) return -1; + if (inv) { + return ((w - xb) << 6) | (s+w+xa-xb); + } else { + return ((w - xa) << 6) | (s+xb-xa); + } + return -1; +} + +/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ +void dasm_put(Dst_DECL, int start, ...) +{ + va_list ap; + dasm_State *D = Dst_REF; + dasm_ActList p = D->actionlist + start; + dasm_Section *sec = D->section; + int pos = sec->pos, ofs = sec->ofs; + int *b; + + if (pos >= sec->epos) { + DASM_M_GROW(Dst, int, sec->buf, sec->bsize, + sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); + sec->rbuf = sec->buf - DASM_POS2BIAS(pos); + sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); + } + + b = sec->rbuf; + b[pos++] = start; + + va_start(ap, start); + while (1) { + unsigned int ins = *p++; + unsigned int action = (ins >> 16); + if (action >= DASM__MAX) { + ofs += 4; + } else { + int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; + switch (action) { + case DASM_STOP: goto stop; + case DASM_SECTION: + n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); + D->section = &D->sections[n]; goto stop; + case DASM_ESC: p++; ofs += 4; break; + case DASM_REL_EXT: break; + case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; + case DASM_REL_LG: + n = (ins & 2047) - 10; pl = D->lglabels + n; + /* Bkwd rel or global. */ + if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } + pl += 10; n = *pl; + if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ + goto linkrel; + case DASM_REL_PC: + pl = D->pclabels + n; CKPL(pc, PC); + putrel: + n = *pl; + if (n < 0) { /* Label exists. Get label pos and store it. */ + b[pos] = -n; + } else { + linkrel: + b[pos] = n; /* Else link to rel chain, anchored at label. */ + *pl = pos; + } + pos++; + break; + case DASM_LABEL_LG: + pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; + case DASM_LABEL_PC: + pl = D->pclabels + n; CKPL(pc, PC); + putlabel: + n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ + while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; + } + *pl = -pos; /* Label exists now. */ + b[pos++] = ofs; /* Store pass1 offset estimate. */ + break; + case DASM_LONG: + ofs += 4; + b[pos++] = n; + break; + case DASM_IMM: + CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); + n >>= ((ins>>10)&31); +#ifdef DASM_CHECKS + if ((ins & 0x8000)) + CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); + else + CK((n>>((ins>>5)&31)) == 0, RANGE_I); +#endif + b[pos++] = n; + break; + case DASM_IMM6: + CK((n >> 6) == 0, RANGE_I); + b[pos++] = n; + break; + case DASM_IMM12: + CK(dasm_imm12((unsigned int)n) != -1, RANGE_I); + b[pos++] = n; + break; + case DASM_IMM13W: + CK(dasm_imm13(n, n) != -1, RANGE_I); + b[pos++] = n; + break; + case DASM_IMM13X: { + int m = va_arg(ap, int); + CK(dasm_imm13(n, m) != -1, RANGE_I); + b[pos++] = n; + b[pos++] = m; + break; + } + case DASM_IMML: { +#ifdef DASM_CHECKS + int scale = (p[-2] >> 30); + CK((!(n & ((1<>scale) < 4096) || + (unsigned int)(n+256) < 512, RANGE_I); +#endif + b[pos++] = n; + break; + } + } + } + } +stop: + va_end(ap); + sec->pos = pos; + sec->ofs = ofs; +} +#undef CK + +/* Pass 2: Link sections, shrink aligns, fix label offsets. */ +int dasm_link(Dst_DECL, size_t *szp) +{ + dasm_State *D = Dst_REF; + int secnum; + int ofs = 0; + +#ifdef DASM_CHECKS + *szp = 0; + if (D->status != DASM_S_OK) return D->status; + { + int pc; + for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) + if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; + } +#endif + + { /* Handle globals not defined in this translation unit. */ + int idx; + for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { + int n = D->lglabels[idx]; + /* Undefined label: Collapse rel chain and replace with marker (< 0). */ + while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } + } + } + + /* Combine all code sections. No support for data sections (yet). */ + for (secnum = 0; secnum < D->maxsection; secnum++) { + dasm_Section *sec = D->sections + secnum; + int *b = sec->rbuf; + int pos = DASM_SEC2POS(secnum); + int lastpos = sec->pos; + + while (pos != lastpos) { + dasm_ActList p = D->actionlist + b[pos++]; + while (1) { + unsigned int ins = *p++; + unsigned int action = (ins >> 16); + switch (action) { + case DASM_STOP: case DASM_SECTION: goto stop; + case DASM_ESC: p++; break; + case DASM_REL_EXT: break; + case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; + case DASM_REL_LG: case DASM_REL_PC: pos++; break; + case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; + case DASM_LONG: case DASM_IMM: case DASM_IMM6: case DASM_IMM12: case DASM_IMM13W: + case DASM_IMML: pos++; break; + case DASM_IMM13X: pos += 2; break; + } + } + stop: (void)0; + } + ofs += sec->ofs; /* Next section starts right after current section. */ + } + + D->codesize = ofs; /* Total size of all code sections */ + *szp = ofs; + return DASM_S_OK; +} + +#ifdef DASM_CHECKS +#define CK(x, st) \ + do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) +#else +#define CK(x, st) ((void)0) +#endif + +/* Pass 3: Encode sections. */ +int dasm_encode(Dst_DECL, void *buffer) +{ + dasm_State *D = Dst_REF; + char *base = (char *)buffer; + unsigned int *cp = (unsigned int *)buffer; + int secnum; + + /* Encode all code sections. No support for data sections (yet). */ + for (secnum = 0; secnum < D->maxsection; secnum++) { + dasm_Section *sec = D->sections + secnum; + int *b = sec->buf; + int *endb = sec->rbuf + sec->pos; + + while (b != endb) { + dasm_ActList p = D->actionlist + *b++; + while (1) { + unsigned int ins = *p++; + unsigned int action = (ins >> 16); + int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; + switch (action) { + case DASM_STOP: case DASM_SECTION: goto stop; + case DASM_ESC: *cp++ = *p++; break; + case DASM_REL_EXT: + n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048)); + goto patchrel; + case DASM_ALIGN: + ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000; + break; + case DASM_REL_LG: + CK(n >= 0, UNDEF_LG); + case DASM_REL_PC: + CK(n >= 0, UNDEF_PC); + n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) + 4; + patchrel: + if (!(ins & 0xf800)) { /* B, BL */ + CK((n & 3) == 0 && ((n+0x08000000) >> 28) == 0, RANGE_REL); + cp[-1] |= ((n >> 2) & 0x03ffffff); + } else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */ + CK((n & 3) == 0 && ((n+0x00100000) >> 21) == 0, RANGE_REL); + cp[-1] |= ((n << 3) & 0x00ffffe0); + } else if ((ins & 0x3000) == 0x2000) { /* ADR */ + CK(((n+0x00100000) >> 21) == 0, RANGE_REL); + cp[-1] |= ((n << 3) & 0x00ffffe0) | ((n & 3) << 29); + } else if ((ins & 0x3000) == 0x3000) { /* ADRP */ + cp[-1] |= ((n >> 9) & 0x00ffffe0) | (((n >> 12) & 3) << 29); + } else if ((ins & 0x1000)) { /* TBZ, TBNZ */ + CK((n & 3) == 0 && ((n+0x00008000) >> 16) == 0, RANGE_REL); + cp[-1] |= ((n << 3) & 0x0007ffe0); + } + break; + case DASM_LABEL_LG: + ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); + break; + case DASM_LABEL_PC: break; + case DASM_LONG: + *cp++ = n; + break; + case DASM_IMM: + cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); + break; + case DASM_IMM6: + cp[-1] |= ((n&31) << 19) | ((n&32) << 26); + break; + case DASM_IMM12: + cp[-1] |= (dasm_imm12((unsigned int)n) << 10); + break; + case DASM_IMM13W: + cp[-1] |= (dasm_imm13(n, n) << 10); + break; + case DASM_IMM13X: + cp[-1] |= (dasm_imm13(n, *b++) << 10); + break; + case DASM_IMML: { + int scale = (p[-2] >> 30); + cp[-1] |= (!(n & ((1<>scale) < 4096) ? + ((n << (10-scale)) | 0x01000000) : ((n & 511) << 12); + break; + } + default: *cp++ = ins; break; + } + } + stop: (void)0; + } + } + + if (base + D->codesize != (char *)cp) /* Check for phase errors. */ + return DASM_S_PHASE; + return DASM_S_OK; +} +#undef CK + +/* Get PC label offset. */ +int dasm_getpclabel(Dst_DECL, unsigned int pc) +{ + dasm_State *D = Dst_REF; + if (pc*sizeof(int) < D->pcsize) { + int pos = D->pclabels[pc]; + if (pos < 0) return *DASM_POS2PTR(D, -pos); + if (pos > 0) return -1; /* Undefined. */ + } + return -2; /* Unused or out of range. */ +} + +#ifdef DASM_CHECKS +/* Optional sanity checker to call between isolated encoding steps. */ +int dasm_checkstep(Dst_DECL, int secmatch) +{ + dasm_State *D = Dst_REF; + if (D->status == DASM_S_OK) { + int i; + for (i = 1; i <= 9; i++) { + if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } + D->lglabels[i] = 0; + } + } + if (D->status == DASM_S_OK && secmatch >= 0 && + D->section != &D->sections[secmatch]) + D->status = DASM_S_MATCH_SEC|(D->section-D->sections); + return D->status; +} +#endif + diff --git a/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm64.lua b/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm64.lua new file mode 100644 index 0000000000..d450298db1 --- /dev/null +++ b/texk/web2c/luatexdir/luaffi/dynasm/dasm_arm64.lua @@ -0,0 +1,1177 @@ +------------------------------------------------------------------------------ +-- DynASM ARM64 module. +-- +-- Copyright (C) 2005-2017 Mike Pall. All rights reserved. +-- See dynasm.lua for full copyright notice. +------------------------------------------------------------------------------ + +-- Module information: +local _info = { + arch = "arm", + description = "DynASM ARM64 module", + version = "1.4.0", + vernum = 10400, + release = "2015-10-18", + author = "Mike Pall", + license = "MIT", +} + +-- Exported glue functions for the arch-specific module. +local _M = { _info = _info } + +-- Cache library functions. +local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs +local assert, setmetatable, rawget = assert, setmetatable, rawget +local _s = string +local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char +local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub +local concat, sort, insert = table.concat, table.sort, table.insert +local bit = bit or require("bit") +local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift +local ror, tohex = bit.ror, bit.tohex + +-- Inherited tables and callbacks. +local g_opt, g_arch +local wline, werror, wfatal, wwarn + +-- Action name list. +-- CHECK: Keep this in sync with the C code! +local action_names = { + "STOP", "SECTION", "ESC", "REL_EXT", + "ALIGN", "REL_LG", "LABEL_LG", + "REL_PC", "LABEL_PC","LONG", "IMM", "IMM6", "IMM12", "IMM13W", "IMM13X", "IMML", +} + +-- Maximum number of section buffer positions for dasm_put(). +-- CHECK: Keep this in sync with the C code! +local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. + +-- Action name -> action number. +local map_action = {} +for n,name in ipairs(action_names) do + map_action[name] = n-1 +end + +-- Action list buffer. +local actlist = {} + +-- Argument list for next dasm_put(). Start with offset 0 into action list. +local actargs = { 0 } + +-- Current number of section buffer positions for dasm_put(). +local secpos = 1 + +------------------------------------------------------------------------------ + +-- Dump action names and numbers. +local function dumpactions(out) + out:write("DynASM encoding engine action codes:\n") + for n,name in ipairs(action_names) do + local num = map_action[name] + out:write(format(" %-10s %02X %d\n", name, num, num)) + end + out:write("\n") +end + +-- Write action list buffer as a huge static C array. +local function writeactions(out, name) + local nn = #actlist + if nn == 0 then nn = 1; actlist[0] = map_action.STOP end + out:write("static const unsigned int ", name, "[", nn, "] = {\n") + for i = 1,nn-1 do + assert(out:write("0x", tohex(actlist[i]), ",\n")) + end + assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) +end + +------------------------------------------------------------------------------ + +-- Add word to action list. +local function wputxw(n) + assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") + actlist[#actlist+1] = n +end + +-- Add action to list with optional arg. Advance buffer pos, too. +local function waction(action, val, a, num) + local w = assert(map_action[action], "bad action name `"..action.."'") + wputxw(w * 0x10000 + (val or 0)) + if a then actargs[#actargs+1] = a end + if a or num then secpos = secpos + (num or 1) end +end + +-- Flush action list (intervening C code or buffer pos overflow). +local function wflush(term) + if #actlist == actargs[1] then return end -- Nothing to flush. + if not term then waction("STOP") end -- Terminate action list. + wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) + actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). + secpos = 1 -- The actionlist offset occupies a buffer position, too. +end + +-- Put escaped word. +local function wputw(n) + if n <= 0x000fffff then waction("ESC") end + wputxw(n) +end + +-- Reserve position for word. +local function wpos() + local pos = #actlist+1 + actlist[pos] = "" + return pos +end + +-- Store word to reserved position. +local function wputpos(pos, n) + assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") + if n <= 0x000fffff then + insert(actlist, pos+1, n) + n = map_action.ESC * 0x10000 + end + actlist[pos] = n +end + +------------------------------------------------------------------------------ + +-- Global label name -> global label number. With auto assignment on 1st use. +local next_global = 20 +local map_global = setmetatable({}, { __index = function(t, name) + if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end + local n = next_global + if n > 2047 then werror("too many global labels") end + next_global = n + 1 + t[name] = n + return n +end}) + +-- Dump global labels. +local function dumpglobals(out, lvl) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("Global labels:\n") + for i=20,next_global-1 do + out:write(format(" %s\n", t[i])) + end + out:write("\n") +end + +-- Write global label enum. +local function writeglobals(out, prefix) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("enum {\n") + for i=20,next_global-1 do + out:write(" ", prefix, t[i], ",\n") + end + out:write(" ", prefix, "_MAX\n};\n") +end + +-- Write global label names. +local function writeglobalnames(out, name) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("static const char *const ", name, "[] = {\n") + for i=20,next_global-1 do + out:write(" \"", t[i], "\",\n") + end + out:write(" (const char *)0\n};\n") +end + +------------------------------------------------------------------------------ + +-- Extern label name -> extern label number. With auto assignment on 1st use. +local next_extern = 0 +local map_extern_ = {} +local map_extern = setmetatable({}, { __index = function(t, name) + -- No restrictions on the name for now. + local n = next_extern + if n > 2047 then werror("too many extern labels") end + next_extern = n + 1 + t[name] = n + map_extern_[n] = name + return n +end}) + +-- Dump extern labels. +local function dumpexterns(out, lvl) + out:write("Extern labels:\n") + for i=0,next_extern-1 do + out:write(format(" %s\n", map_extern_[i])) + end + out:write("\n") +end + +-- Write extern label names. +local function writeexternnames(out, name) + out:write("static const char *const ", name, "[] = {\n") + for i=0,next_extern-1 do + out:write(" \"", map_extern_[i], "\",\n") + end + out:write(" (const char *)0\n};\n") +end + +------------------------------------------------------------------------------ + +-- Arch-specific maps. + +-- Ext. register name -> int. name. +local map_archdef = { xzr = "@x31", wzr = "@w31", lr = "x30", } + +-- Int. register name -> ext. name. +local map_reg_rev = { ["@x31"] = "xzr", ["@w31"] = "wzr", x30 = "lr", } + +local map_type = {} -- Type name -> { ctype, reg } +local ctypenum = 0 -- Type number (for Dt... macros). + +-- Reverse defines for registers. +function _M.revdef(s) + return map_reg_rev[s] or s +end + +local map_shift = { lsl = 0, lsr = 1, asr = 2, } + +local map_extend = { + uxtb = 0, uxth = 1, uxtw = 2, uxtx = 3, + sxtb = 4, sxth = 5, sxtw = 6, sxtx = 7, +} + +local map_cond = { + eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7, + hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14, + hs = 2, lo = 3, +} + +------------------------------------------------------------------------------ + +local parse_reg_type + +local function parse_reg(expr) + if not expr then werror("expected register name") end + local tname, ovreg = match(expr, "^([%w_]+):(@?%l%d+)$") + local tp = map_type[tname or expr] + if tp then + local reg = ovreg or tp.reg + if not reg then + werror("type `"..(tname or expr).."' needs a register override") + end + expr = reg + end + local ok31, rt, r = match(expr, "^(@?)([xwqdshb])([123]?[0-9])$") + if r then + r = tonumber(r) + if r <= 30 or (r == 31 and ok31 ~= "" or (rt ~= "w" and rt ~= "x")) then + if not parse_reg_type then + parse_reg_type = rt + elseif parse_reg_type ~= rt then + werror("register size mismatch") + end + return r, tp + end + end + werror("bad register name `"..expr.."'") +end + +local function parse_reg_base(expr) + if expr == "sp" then return 0x3e0 end + local base, tp = parse_reg(expr) + if parse_reg_type ~= "x" then werror("bad register type") end + parse_reg_type = false + return shl(base, 5), tp +end + +local parse_ctx = {} + +local loadenv = setfenv and function(s) + local code = loadstring(s, "") + if code then setfenv(code, parse_ctx) end + return code +end or function(s) + return load(s, "", nil, parse_ctx) +end + +-- Try to parse simple arithmetic, too, since some basic ops are aliases. +local function parse_number(n) + local x = tonumber(n) + if x then return x end + local code = loadenv("return "..n) + if code then + local ok, y = pcall(code) + if ok then return y end + end + return nil +end + +local function parse_imm(imm, bits, shift, scale, signed) + imm = match(imm, "^#(.*)$") + if not imm then werror("expected immediate operand") end + local n = parse_number(imm) + if n then + local m = sar(n, scale) + if shl(m, scale) == n then + if signed then + local s = sar(m, bits-1) + if s == 0 then return shl(m, shift) + elseif s == -1 then return shl(m + shl(1, bits), shift) end + else + if sar(m, bits) == 0 then return shl(m, shift) end + end + end + werror("out of range immediate `"..imm.."'") + else + waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) + return 0 + end +end + +local function parse_imm12(imm) + imm = match(imm, "^#(.*)$") + if not imm then werror("expected immediate operand") end + local n = parse_number(imm) + if n then + if shr(n, 12) == 0 then + return shl(n, 10) + elseif band(n, 0xff000fff) == 0 then + return shr(n, 2) + 0x00400000 + end + werror("out of range immediate `"..imm.."'") + else + waction("IMM12", 0, imm) + return 0 + end +end + +local function parse_imm13(imm) + imm = match(imm, "^#(.*)$") + if not imm then werror("expected immediate operand") end + local n = parse_number(imm) + local r64 = parse_reg_type == "x" + if n and n % 1 == 0 and n >= 0 and n <= 0xffffffff then + local inv = false + if band(n, 1) == 1 then n = bit.bnot(n); inv = true end + local t = {} + for i=1,32 do t[i] = band(n, 1); n = shr(n, 1) end + local b = table.concat(t) + b = b..(r64 and (inv and "1" or "0"):rep(32) or b) + local p0, p1, p0a, p1a = b:match("^(0+)(1+)(0*)(1*)") + if p0 then + local w = p1a == "" and (r64 and 64 or 32) or #p1+#p0a + if band(w, w-1) == 0 and b == b:sub(1, w):rep(64/w) then + local s = band(-2*w, 0x3f) - 1 + if w == 64 then s = s + 0x1000 end + if inv then + return shl(w-#p1-#p0, 16) + shl(s+w-#p1, 10) + else + return shl(w-#p0, 16) + shl(s+#p1, 10) + end + end + end + werror("out of range immediate `"..imm.."'") + elseif r64 then + waction("IMM13X", 0, format("(unsigned int)(%s)", imm)) + actargs[#actargs+1] = format("(unsigned int)((unsigned long long)(%s)>>32)", imm) + return 0 + else + waction("IMM13W", 0, imm) + return 0 + end +end + +local function parse_imm6(imm) + imm = match(imm, "^#(.*)$") + if not imm then werror("expected immediate operand") end + local n = parse_number(imm) + if n then + if n >= 0 and n <= 63 then + return shl(band(n, 0x1f), 19) + (n >= 32 and 0x80000000 or 0) + end + werror("out of range immediate `"..imm.."'") + else + waction("IMM6", 0, imm) + return 0 + end +end + +local function parse_imm_load(imm, scale) + local n = parse_number(imm) + if n then + local m = sar(n, scale) + if shl(m, scale) == n and m >= 0 and m < 0x1000 then + return shl(m, 10) + 0x01000000 -- Scaled, unsigned 12 bit offset. + elseif n >= -256 and n < 256 then + return shl(band(n, 511), 12) -- Unscaled, signed 9 bit offset. + end + werror("out of range immediate `"..imm.."'") + else + waction("IMML", 0, imm) + return 0 + end +end + +local function parse_fpimm(imm) + imm = match(imm, "^#(.*)$") + if not imm then werror("expected immediate operand") end + local n = parse_number(imm) + if n then + local m, e = math.frexp(n) + local s, e2 = 0, band(e-2, 7) + if m < 0 then m = -m; s = 0x00100000 end + m = m*32-16 + if m % 1 == 0 and m >= 0 and m <= 15 and sar(shl(e2, 29), 29)+2 == e then + return s + shl(e2, 17) + shl(m, 13) + end + werror("out of range immediate `"..imm.."'") + else + werror("NYI fpimm action") + end +end + +local function parse_shift(expr) + local s, s2 = match(expr, "^(%S+)%s*(.*)$") + s = map_shift[s] + if not s then werror("expected shift operand") end + return parse_imm(s2, 6, 10, 0, false) + shl(s, 22) +end + +local function parse_lslx16(expr) + local n = match(expr, "^lsl%s*#(%d+)$") + n = tonumber(n) + if not n then werror("expected shift operand") end + if band(n, parse_reg_type == "x" and 0xffffffcf or 0xffffffef) ~= 0 then + werror("bad shift amount") + end + return shl(n, 17) +end + +local function parse_extend(expr) + local s, s2 = match(expr, "^(%S+)%s*(.*)$") + if s == "lsl" then + s = parse_reg_type == "x" and 3 or 2 + else + s = map_extend[s] + end + if not s then werror("expected extend operand") end + return (s2 == "" and 0 or parse_imm(s2, 3, 10, 0, false)) + shl(s, 13) +end + +local function parse_cond(expr, inv) + local c = map_cond[expr] + if not c then werror("expected condition operand") end + return shl(bit.bxor(c, inv), 12) +end + +local function parse_load(params, nparams, n, op) + if params[n+2] then werror("too many operands") end + local pn, p2 = params[n], params[n+1] + local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") + if not p1 then + if not p2 then + local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") + if reg and tailr ~= "" then + local base, tp = parse_reg_base(reg) + if tp then + waction("IMML", 0, format(tp.ctypefmt, tailr)) + return op + base + end + end + end + werror("expected address operand") + end + local scale = shr(op, 30) + if p2 then + if wb == "!" then werror("bad use of '!'") end + op = op + parse_reg_base(p1) + parse_imm(p2, 9, 12, 0, true) + 0x400 + elseif wb == "!" then + local p1a, p2a = match(p1, "^([^,%s]*)%s*,%s*(.*)$") + if not p1a then werror("bad use of '!'") end + op = op + parse_reg_base(p1a) + parse_imm(p2a, 9, 12, 0, true) + 0xc00 + else + local p1a, p2a = match(p1, "^([^,%s]*)%s*(.*)$") + op = op + parse_reg_base(p1a) + if p2a ~= "" then + local imm = match(p2a, "^,%s*#(.*)$") + if imm then + op = op + parse_imm_load(imm, scale) + else + local p2b, p3b, p3s = match(p2a, "^,%s*([^,%s]*)%s*,?%s*(%S*)%s*(.*)$") + op = op + shl(parse_reg(p2b), 16) + 0x00200800 + if parse_reg_type ~= "x" and parse_reg_type ~= "w" then + werror("bad index register type") + end + if p3b == "" then + if parse_reg_type ~= "x" then werror("bad index register type") end + op = op + 0x6000 + else + if p3s == "" or p3s == "#0" then + elseif p3s == "#"..scale then + op = op + 0x1000 + else + werror("bad scale") + end + if parse_reg_type == "x" then + if p3b == "lsl" and p3s ~= "" then op = op + 0x6000 + elseif p3b == "sxtx" then op = op + 0xe000 + else + werror("bad extend/shift specifier") + end + else + if p3b == "uxtw" then op = op + 0x4000 + elseif p3b == "sxtw" then op = op + 0xc000 + else + werror("bad extend/shift specifier") + end + end + end + end + else + if wb == "!" then werror("bad use of '!'") end + op = op + 0x01000000 + end + end + return op +end + +local function parse_load_pair(params, nparams, n, op) + if params[n+2] then werror("too many operands") end + local pn, p2 = params[n], params[n+1] + local scale = shr(op, 30) == 0 and 2 or 3 + local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") + if not p1 then + if not p2 then + local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") + if reg and tailr ~= "" then + local base, tp = parse_reg_base(reg) + if tp then + waction("IMM", 32768+7*32+15+scale*1024, format(tp.ctypefmt, tailr)) + return op + base + 0x01000000 + end + end + end + werror("expected address operand") + end + if p2 then + if wb == "!" then werror("bad use of '!'") end + op = op + 0x00800000 + else + local p1a, p2a = match(p1, "^([^,%s]*)%s*,%s*(.*)$") + if p1a then p1, p2 = p1a, p2a else p2 = "#0" end + op = op + (wb == "!" and 0x01800000 or 0x01000000) + end + return op + parse_reg_base(p1) + parse_imm(p2, 7, 15, scale, true) +end + +local function parse_label(label, def) + local prefix = sub(label, 1, 2) + -- =>label (pc label reference) + if prefix == "=>" then + return "PC", 0, sub(label, 3) + end + -- ->name (global label reference) + if prefix == "->" then + return "LG", map_global[sub(label, 3)] + end + if def then + -- [1-9] (local label definition) + if match(label, "^[1-9]$") then + return "LG", 10+tonumber(label) + end + else + -- [<>][1-9] (local label reference) + local dir, lnum = match(label, "^([<>])([1-9])$") + if dir then -- Fwd: 1-9, Bkwd: 11-19. + return "LG", lnum + (dir == ">" and 0 or 10) + end + -- extern label (extern label reference) + local extname = match(label, "^extern%s+(%S+)$") + if extname then + return "EXT", map_extern[extname] + end + end + werror("bad label `"..label.."'") +end + +local function branch_type(op) + if band(op, 0x7c000000) == 0x14000000 then return 0 -- B, BL + elseif shr(op, 24) == 0x54 or band(op, 0x7e000000) == 0x34000000 or + band(op, 0x3b000000) == 0x18000000 then + return 0x800 -- B.cond, CBZ, CBNZ, LDR* literal + elseif band(op, 0x7e000000) == 0x36000000 then return 0x1000 -- TBZ, TBNZ + elseif band(op, 0x9f000000) == 0x10000000 then return 0x2000 -- ADR + elseif band(op, 0x9f000000) == band(0x90000000) then return 0x3000 -- ADRP + else + assert(false, "unknown branch type") + end +end + +------------------------------------------------------------------------------ + +local map_op, op_template + +local function op_alias(opname, f) + return function(params, nparams) + if not params then return "-> "..opname:sub(1, -3) end + f(params, nparams) + op_template(params, map_op[opname], nparams) + end +end + +local function alias_bfx(p) + p[4] = "#("..p[3]:sub(2)..")+("..p[4]:sub(2)..")-1" +end + +local function alias_bfiz(p) + parse_reg(p[1]) + if parse_reg_type == "w" then + p[3] = "#-("..p[3]:sub(2)..")%32" + p[4] = "#("..p[4]:sub(2)..")-1" + else + p[3] = "#-("..p[3]:sub(2)..")%64" + p[4] = "#("..p[4]:sub(2)..")-1" + end +end + +local alias_lslimm = op_alias("ubfm_4", function(p) + parse_reg(p[1]) + local sh = p[3]:sub(2) + if parse_reg_type == "w" then + p[3] = "#-("..sh..")%32" + p[4] = "#31-("..sh..")" + else + p[3] = "#-("..sh..")%64" + p[4] = "#63-("..sh..")" + end +end) + +-- Template strings for ARM instructions. +map_op = { + -- Basic data processing instructions. + add_3 = "0b000000DNMg|11000000pDpNIg|8b206000pDpNMx", + add_4 = "0b000000DNMSg|0b200000DNMXg|8b200000pDpNMXx|8b200000pDpNxMwX", + adds_3 = "2b000000DNMg|31000000DpNIg|ab206000DpNMx", + adds_4 = "2b000000DNMSg|2b200000DNMXg|ab200000DpNMXx|ab200000DpNxMwX", + cmn_2 = "2b00001fNMg|3100001fpNIg|ab20601fpNMx", + cmn_3 = "2b00001fNMSg|2b20001fNMXg|ab20001fpNMXx|ab20001fpNxMwX", + + sub_3 = "4b000000DNMg|51000000pDpNIg|cb206000pDpNMx", + sub_4 = "4b000000DNMSg|4b200000DNMXg|cb200000pDpNMXx|cb200000pDpNxMwX", + subs_3 = "6b000000DNMg|71000000DpNIg|eb206000DpNMx", + subs_4 = "6b000000DNMSg|6b200000DNMXg|eb200000DpNMXx|eb200000DpNxMwX", + cmp_2 = "6b00001fNMg|7100001fpNIg|eb20601fpNMx", + cmp_3 = "6b00001fNMSg|6b20001fNMXg|eb20001fpNMXx|eb20001fpNxMwX", + + neg_2 = "4b0003e0DMg", + neg_3 = "4b0003e0DMSg", + negs_2 = "6b0003e0DMg", + negs_3 = "6b0003e0DMSg", + + adc_3 = "1a000000DNMg", + adcs_3 = "3a000000DNMg", + sbc_3 = "5a000000DNMg", + sbcs_3 = "7a000000DNMg", + ngc_2 = "5a0003e0DMg", + ngcs_2 = "7a0003e0DMg", + + and_3 = "0a000000DNMg|12000000pDNig", + and_4 = "0a000000DNMSg", + orr_3 = "2a000000DNMg|32000000pDNig", + orr_4 = "2a000000DNMSg", + eor_3 = "4a000000DNMg|52000000pDNig", + eor_4 = "4a000000DNMSg", + ands_3 = "6a000000DNMg|72000000DNig", + ands_4 = "6a000000DNMSg", + tst_2 = "6a00001fNMg|7200001fNig", + tst_3 = "6a00001fNMSg", + + bic_3 = "0a200000DNMg", + bic_4 = "0a200000DNMSg", + orn_3 = "2a200000DNMg", + orn_4 = "2a200000DNMSg", + eon_3 = "4a200000DNMg", + eon_4 = "4a200000DNMSg", + bics_3 = "6a200000DNMg", + bics_4 = "6a200000DNMSg", + + movn_2 = "12800000DWg", + movn_3 = "12800000DWRg", + movz_2 = "52800000DWg", + movz_3 = "52800000DWRg", + movk_2 = "72800000DWg", + movk_3 = "72800000DWRg", + + -- TODO: this doesn't cover all valid immediates for mov reg, #imm. + mov_2 = "2a0003e0DMg|52800000DW|320003e0pDig|11000000pDpNg", + mov_3 = "2a0003e0DMSg", + mvn_2 = "2a2003e0DMg", + mvn_3 = "2a2003e0DMSg", + + adr_2 = "10000000DBx", + adrp_2 = "90000000DBx", + + csel_4 = "1a800000DNMCg", + csinc_4 = "1a800400DNMCg", + csinv_4 = "5a800000DNMCg", + csneg_4 = "5a800400DNMCg", + cset_2 = "1a9f07e0Dcg", + csetm_2 = "5a9f03e0Dcg", + cinc_3 = "1a800400DNmcg", + cinv_3 = "5a800000DNmcg", + cneg_3 = "5a800400DNmcg", + + ccmn_4 = "3a400000NMVCg|3a400800N5VCg", + ccmp_4 = "7a400000NMVCg|7a400800N5VCg", + + madd_4 = "1b000000DNMAg", + msub_4 = "1b008000DNMAg", + mul_3 = "1b007c00DNMg", + mneg_3 = "1b00fc00DNMg", + + smaddl_4 = "9b200000DxNMwAx", + smsubl_4 = "9b208000DxNMwAx", + smull_3 = "9b207c00DxNMw", + smnegl_3 = "9b20fc00DxNMw", + smulh_3 = "9b407c00DNMx", + umaddl_4 = "9ba00000DxNMwAx", + umsubl_4 = "9ba08000DxNMwAx", + umull_3 = "9ba07c00DxNMw", + umnegl_3 = "9ba0fc00DxNMw", + umulh_3 = "9bc07c00DNMx", + + udiv_3 = "1ac00800DNMg", + sdiv_3 = "1ac00c00DNMg", + + -- Bit operations. + sbfm_4 = "13000000DN12w|93400000DN12x", + bfm_4 = "33000000DN12w|b3400000DN12x", + ubfm_4 = "53000000DN12w|d3400000DN12x", + extr_4 = "13800000DNM2w|93c00000DNM2x", + + sxtb_2 = "13001c00DNw|93401c00DNx", + sxth_2 = "13003c00DNw|93403c00DNx", + sxtw_2 = "93407c00DxNw", + uxtb_2 = "53001c00DNw", + uxth_2 = "53003c00DNw", + + sbfx_4 = op_alias("sbfm_4", alias_bfx), + bfxil_4 = op_alias("bfm_4", alias_bfx), + ubfx_4 = op_alias("ubfm_4", alias_bfx), + sbfiz_4 = op_alias("sbfm_4", alias_bfiz), + bfi_4 = op_alias("bfm_4", alias_bfiz), + ubfiz_4 = op_alias("ubfm_4", alias_bfiz), + + lsl_3 = function(params, nparams) + if params and params[3]:byte() == 35 then + return alias_lslimm(params, nparams) + else + return op_template(params, "1ac02000DNMg", nparams) + end + end, + lsr_3 = "1ac02400DNMg|53007c00DN1w|d340fc00DN1x", + asr_3 = "1ac02800DNMg|13007c00DN1w|9340fc00DN1x", + ror_3 = "1ac02c00DNMg|13800000DNm2w|93c00000DNm2x", + + clz_2 = "5ac01000DNg", + cls_2 = "5ac01400DNg", + rbit_2 = "5ac00000DNg", + rev_2 = "5ac00800DNw|dac00c00DNx", + rev16_2 = "5ac00400DNg", + rev32_2 = "dac00800DNx", + + -- Loads and stores. + ["strb_*"] = "38000000DwL", + ["ldrb_*"] = "38400000DwL", + ["ldrsb_*"] = "38c00000DwL|38800000DxL", + ["strh_*"] = "78000000DwL", + ["ldrh_*"] = "78400000DwL", + ["ldrsh_*"] = "78c00000DwL|78800000DxL", + ["str_*"] = "b8000000DwL|f8000000DxL|bc000000DsL|fc000000DdL", + ["ldr_*"] = "18000000DwB|58000000DxB|1c000000DsB|5c000000DdB|b8400000DwL|f8400000DxL|bc400000DsL|fc400000DdL", + ["ldrsw_*"] = "98000000DxB|b8800000DxL", + -- NOTE: ldur etc. are handled by ldr et al. + + ["stp_*"] = "28000000DAwP|a8000000DAxP|2c000000DAsP|6c000000DAdP", + ["ldp_*"] = "28400000DAwP|a8400000DAxP|2c400000DAsP|6c400000DAdP", + ["ldpsw_*"] = "68400000DAxP", + + -- Branches. + b_1 = "14000000B", + bl_1 = "94000000B", + blr_1 = "d63f0000Nx", + br_1 = "d61f0000Nx", + ret_0 = "d65f03c0", + ret_1 = "d65f0000Nx", + -- b.cond is added below. + cbz_2 = "34000000DBg", + cbnz_2 = "35000000DBg", + tbz_3 = "36000000DTBw|36000000DTBx", + tbnz_3 = "37000000DTBw|37000000DTBx", + + -- Miscellaneous instructions. + -- TODO: hlt, hvc, smc, svc, eret, dcps[123], drps, mrs, msr + -- TODO: sys, sysl, ic, dc, at, tlbi + -- TODO: hint, yield, wfe, wfi, sev, sevl + -- TODO: clrex, dsb, dmb, isb + nop_0 = "d503201f", + brk_0 = "d4200000", + brk_1 = "d4200000W", + + -- Floating point instructions. + fmov_2 = "1e204000DNf|1e260000DwNs|1e270000DsNw|9e660000DxNd|9e670000DdNx|1e201000DFf", + fabs_2 = "1e20c000DNf", + fneg_2 = "1e214000DNf", + fsqrt_2 = "1e21c000DNf", + + fcvt_2 = "1e22c000DdNs|1e624000DsNd", + + -- TODO: half-precision and fixed-point conversions. + fcvtas_2 = "1e240000DwNs|9e240000DxNs|1e640000DwNd|9e640000DxNd", + fcvtau_2 = "1e250000DwNs|9e250000DxNs|1e650000DwNd|9e650000DxNd", + fcvtms_2 = "1e300000DwNs|9e300000DxNs|1e700000DwNd|9e700000DxNd", + fcvtmu_2 = "1e310000DwNs|9e310000DxNs|1e710000DwNd|9e710000DxNd", + fcvtns_2 = "1e200000DwNs|9e200000DxNs|1e600000DwNd|9e600000DxNd", + fcvtnu_2 = "1e210000DwNs|9e210000DxNs|1e610000DwNd|9e610000DxNd", + fcvtps_2 = "1e280000DwNs|9e280000DxNs|1e680000DwNd|9e680000DxNd", + fcvtpu_2 = "1e290000DwNs|9e290000DxNs|1e690000DwNd|9e690000DxNd", + fcvtzs_2 = "1e380000DwNs|9e380000DxNs|1e780000DwNd|9e780000DxNd", + fcvtzu_2 = "1e390000DwNs|9e390000DxNs|1e790000DwNd|9e790000DxNd", + + scvtf_2 = "1e220000DsNw|9e220000DsNx|1e620000DdNw|9e620000DdNx", + ucvtf_2 = "1e230000DsNw|9e230000DsNx|1e630000DdNw|9e630000DdNx", + + frintn_2 = "1e244000DNf", + frintp_2 = "1e24c000DNf", + frintm_2 = "1e254000DNf", + frintz_2 = "1e25c000DNf", + frinta_2 = "1e264000DNf", + frintx_2 = "1e274000DNf", + frinti_2 = "1e27c000DNf", + + fadd_3 = "1e202800DNMf", + fsub_3 = "1e203800DNMf", + fmul_3 = "1e200800DNMf", + fnmul_3 = "1e208800DNMf", + fdiv_3 = "1e201800DNMf", + + fmadd_4 = "1f000000DNMAf", + fmsub_4 = "1f008000DNMAf", + fnmadd_4 = "1f200000DNMAf", + fnmsub_4 = "1f208000DNMAf", + + fmax_3 = "1e204800DNMf", + fmaxnm_3 = "1e206800DNMf", + fmin_3 = "1e205800DNMf", + fminnm_3 = "1e207800DNMf", + + fcmp_2 = "1e202000NMf|1e202008NZf", + fcmpe_2 = "1e202010NMf|1e202018NZf", + + fccmp_4 = "1e200400NMVCf", + fccmpe_4 = "1e200410NMVCf", + + fcsel_4 = "1e200c00DNMCf", + + -- TODO: crc32*, aes*, sha*, pmull + -- TODO: SIMD instructions. +} + +for cond,c in pairs(map_cond) do + map_op["b"..cond.."_1"] = tohex(0x54000000+c).."B" +end + +------------------------------------------------------------------------------ + +-- Handle opcodes defined with template strings. +local function parse_template(params, template, nparams, pos) + local op = tonumber(sub(template, 1, 8), 16) + local n = 1 + local rtt = {} + + parse_reg_type = false + + -- Process each character. + for p in gmatch(sub(template, 9), ".") do + local q = params[n] + if p == "D" then + op = op + parse_reg(q); n = n + 1 + elseif p == "N" then + op = op + shl(parse_reg(q), 5); n = n + 1 + elseif p == "M" then + op = op + shl(parse_reg(q), 16); n = n + 1 + elseif p == "A" then + op = op + shl(parse_reg(q), 10); n = n + 1 + elseif p == "m" then + op = op + shl(parse_reg(params[n-1]), 16) + + elseif p == "p" then + if q == "sp" then params[n] = "@x31" end + elseif p == "g" then + if parse_reg_type == "x" then + op = op + 0x80000000 + elseif parse_reg_type ~= "w" then + werror("bad register type") + end + parse_reg_type = false + elseif p == "f" then + if parse_reg_type == "d" then + op = op + 0x00400000 + elseif parse_reg_type ~= "s" then + werror("bad register type") + end + parse_reg_type = false + elseif p == "x" or p == "w" or p == "d" or p == "s" then + if parse_reg_type ~= p then + werror("register size mismatch") + end + parse_reg_type = false + + elseif p == "L" then + op = parse_load(params, nparams, n, op) + elseif p == "P" then + op = parse_load_pair(params, nparams, n, op) + + elseif p == "B" then + local mode, v, s = parse_label(q, false); n = n + 1 + local m = branch_type(op) + waction("REL_"..mode, v+m, s, 1) + + elseif p == "I" then + op = op + parse_imm12(q); n = n + 1 + elseif p == "i" then + op = op + parse_imm13(q); n = n + 1 + elseif p == "W" then + op = op + parse_imm(q, 16, 5, 0, false); n = n + 1 + elseif p == "T" then + op = op + parse_imm6(q); n = n + 1 + elseif p == "1" then + op = op + parse_imm(q, 6, 16, 0, false); n = n + 1 + elseif p == "2" then + op = op + parse_imm(q, 6, 10, 0, false); n = n + 1 + elseif p == "5" then + op = op + parse_imm(q, 5, 16, 0, false); n = n + 1 + elseif p == "V" then + op = op + parse_imm(q, 4, 0, 0, false); n = n + 1 + elseif p == "F" then + op = op + parse_fpimm(q); n = n + 1 + elseif p == "Z" then + if q ~= "#0" and q ~= "#0.0" then werror("expected zero immediate") end + n = n + 1 + + elseif p == "S" then + op = op + parse_shift(q); n = n + 1 + elseif p == "X" then + op = op + parse_extend(q); n = n + 1 + elseif p == "R" then + op = op + parse_lslx16(q); n = n + 1 + elseif p == "C" then + op = op + parse_cond(q, 0); n = n + 1 + elseif p == "c" then + op = op + parse_cond(q, 1); n = n + 1 + + else + assert(false) + end + end + wputpos(pos, op) +end + +function op_template(params, template, nparams) + if not params then return template:gsub("%x%x%x%x%x%x%x%x", "") end + + -- Limit number of section buffer positions used by a single dasm_put(). + -- A single opcode needs a maximum of 3 positions. + if secpos+3 > maxsecpos then wflush() end + local pos = wpos() + local lpos, apos, spos = #actlist, #actargs, secpos + + local ok, err + for t in gmatch(template, "[^|]+") do + ok, err = pcall(parse_template, params, t, nparams, pos) + if ok then return end + secpos = spos + actlist[lpos+1] = nil + actlist[lpos+2] = nil + actlist[lpos+3] = nil + actargs[apos+1] = nil + actargs[apos+2] = nil + actargs[apos+3] = nil + end + error(err, 0) +end + +map_op[".template__"] = op_template + +------------------------------------------------------------------------------ + +-- Pseudo-opcode to mark the position where the action list is to be emitted. +map_op[".actionlist_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeactions(out, name) end) +end + +-- Pseudo-opcode to mark the position where the global enum is to be emitted. +map_op[".globals_1"] = function(params) + if not params then return "prefix" end + local prefix = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeglobals(out, prefix) end) +end + +-- Pseudo-opcode to mark the position where the global names are to be emitted. +map_op[".globalnames_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeglobalnames(out, name) end) +end + +-- Pseudo-opcode to mark the position where the extern names are to be emitted. +map_op[".externnames_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeexternnames(out, name) end) +end + +------------------------------------------------------------------------------ + +-- Label pseudo-opcode (converted from trailing colon form). +map_op[".label_1"] = function(params) + if not params then return "[1-9] | ->global | =>pcexpr" end + if secpos+1 > maxsecpos then wflush() end + local mode, n, s = parse_label(params[1], true) + if mode == "EXT" then werror("bad label definition") end + waction("LABEL_"..mode, n, s, 1) +end + +------------------------------------------------------------------------------ + +-- Pseudo-opcodes for data storage. +map_op[".long_*"] = function(params) + if not params then return "imm..." end + for _,p in ipairs(params) do + local n = tonumber(p) + if n then + if n < 0 then n = n + 2^32 end + wputw(n) + if secpos+2 > maxsecpos then wflush() end + else + waction("LONG", 0, format("(int)(%s)", p)) + end + end +end + +map_op[".long64_*"]=function(params) + if not params then return "imm..." end + for _,p in ipairs(params) do + waction("LONG",0,format("(int)(%s)",p)) + waction("LONG",0,format("(int)(((unsigned long)(%s))>>32)",p)) + end +end + +-- Alignment pseudo-opcode. +map_op[".align_1"] = function(params) + if not params then return "numpow2" end + if secpos+1 > maxsecpos then wflush() end + local align = tonumber(params[1]) + if align then + local x = align + -- Must be a power of 2 in the range (2 ... 256). + for i=1,8 do + x = x / 2 + if x == 1 then + waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. + return + end + end + end + werror("bad alignment") +end + +------------------------------------------------------------------------------ + +-- Pseudo-opcode for (primitive) type definitions (map to C types). +map_op[".type_3"] = function(params, nparams) + if not params then + return nparams == 2 and "name, ctype" or "name, ctype, reg" + end + local name, ctype, reg = params[1], params[2], params[3] + if not match(name, "^[%a_][%w_]*$") then + werror("bad type name `"..name.."'") + end + local tp = map_type[name] + if tp then + werror("duplicate type `"..name.."'") + end + -- Add #type to defines. A bit unclean to put it in map_archdef. + map_archdef["#"..name] = "sizeof("..ctype..")" + -- Add new type and emit shortcut define. + local num = ctypenum + 1 + map_type[name] = { + ctype = ctype, + ctypefmt = format("Dt%X(%%s)", num), + reg = reg, + } + wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) + ctypenum = num +end +map_op[".type_2"] = map_op[".type_3"] + +-- Dump type definitions. +local function dumptypes(out, lvl) + local t = {} + for name in pairs(map_type) do t[#t+1] = name end + sort(t) + out:write("Type definitions:\n") + for _,name in ipairs(t) do + local tp = map_type[name] + local reg = tp.reg or "" + out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) + end + out:write("\n") +end + +------------------------------------------------------------------------------ + +-- Set the current section. +function _M.section(num) + waction("SECTION", num) + wflush(true) -- SECTION is a terminal action. +end + +------------------------------------------------------------------------------ + +-- Dump architecture description. +function _M.dumparch(out) + out:write(format("DynASM %s version %s, released %s\n\n", + _info.arch, _info.version, _info.release)) + dumpactions(out) +end + +-- Dump all user defined elements. +function _M.dumpdef(out, lvl) + dumptypes(out, lvl) + dumpglobals(out, lvl) + dumpexterns(out, lvl) +end + +------------------------------------------------------------------------------ + +-- Pass callbacks from/to the DynASM core. +function _M.passcb(wl, we, wf, ww) + wline, werror, wfatal, wwarn = wl, we, wf, ww + return wflush +end + +-- Setup the arch-specific module. +function _M.setup(arch, opt) + g_arch, g_opt = arch, opt +end + +-- Merge the core maps and the arch-specific maps. +function _M.mergemaps(map_coreop, map_def) + setmetatable(map_op, { __index = map_coreop }) + setmetatable(map_def, { __index = map_archdef }) + return map_op, map_def +end + +return _M + +------------------------------------------------------------------------------ + diff --git a/texk/web2c/luatexdir/luaffi/dynasm/dasm_mips.h b/texk/web2c/luatexdir/luaffi/dynasm/dasm_mips.h new file mode 100644 index 0000000000..71a835b20a --- /dev/null +++ b/texk/web2c/luatexdir/luaffi/dynasm/dasm_mips.h @@ -0,0 +1,420 @@ +/* +** DynASM MIPS encoding engine. +** Copyright (C) 2005-2017 Mike Pall. All rights reserved. +** Released under the MIT license. See dynasm.lua for full copyright notice. +*/ + +#include +#include +#include +#include + +#define DASM_ARCH "mips" + +#ifndef DASM_EXTERN +#define DASM_EXTERN(a,b,c,d) 0 +#endif + +/* Action definitions. */ +enum { + DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, + /* The following actions need a buffer position. */ + DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, + /* The following actions also have an argument. */ + DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMS, + DASM__MAX +}; + +/* Maximum number of section buffer positions for a single dasm_put() call. */ +#define DASM_MAXSECPOS 25 + +/* DynASM encoder status codes. Action list offset or number are or'ed in. */ +#define DASM_S_OK 0x00000000 +#define DASM_S_NOMEM 0x01000000 +#define DASM_S_PHASE 0x02000000 +#define DASM_S_MATCH_SEC 0x03000000 +#define DASM_S_RANGE_I 0x11000000 +#define DASM_S_RANGE_SEC 0x12000000 +#define DASM_S_RANGE_LG 0x13000000 +#define DASM_S_RANGE_PC 0x14000000 +#define DASM_S_RANGE_REL 0x15000000 +#define DASM_S_UNDEF_LG 0x21000000 +#define DASM_S_UNDEF_PC 0x22000000 + +/* Macros to convert positions (8 bit section + 24 bit index). */ +#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) +#define DASM_POS2BIAS(pos) ((pos)&0xff000000) +#define DASM_SEC2POS(sec) ((sec)<<24) +#define DASM_POS2SEC(pos) ((pos)>>24) +#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) + +/* Action list type. */ +typedef const unsigned int *dasm_ActList; + +/* Per-section structure. */ +typedef struct dasm_Section { + int *rbuf; /* Biased buffer pointer (negative section bias). */ + int *buf; /* True buffer pointer. */ + size_t bsize; /* Buffer size in bytes. */ + int pos; /* Biased buffer position. */ + int epos; /* End of biased buffer position - max single put. */ + int ofs; /* Byte offset into section. */ +} dasm_Section; + +/* Core structure holding the DynASM encoding state. */ +struct dasm_State { + size_t psize; /* Allocated size of this structure. */ + dasm_ActList actionlist; /* Current actionlist pointer. */ + int *lglabels; /* Local/global chain/pos ptrs. */ + size_t lgsize; + int *pclabels; /* PC label chains/pos ptrs. */ + size_t pcsize; + void **globals; /* Array of globals (bias -10). */ + dasm_Section *section; /* Pointer to active section. */ + size_t codesize; /* Total size of all code sections. */ + int maxsection; /* 0 <= sectionidx < maxsection. */ + int status; /* Status code. */ + dasm_Section sections[1]; /* All sections. Alloc-extended. */ +}; + +/* The size of the core structure depends on the max. number of sections. */ +#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) + + +/* Initialize DynASM state. */ +void dasm_init(Dst_DECL, int maxsection) +{ + dasm_State *D; + size_t psz = 0; + int i; + Dst_REF = NULL; + DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); + D = Dst_REF; + D->psize = psz; + D->lglabels = NULL; + D->lgsize = 0; + D->pclabels = NULL; + D->pcsize = 0; + D->globals = NULL; + D->maxsection = maxsection; + for (i = 0; i < maxsection; i++) { + D->sections[i].buf = NULL; /* Need this for pass3. */ + D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); + D->sections[i].bsize = 0; + D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ + } +} + +/* Free DynASM state. */ +void dasm_free(Dst_DECL) +{ + dasm_State *D = Dst_REF; + int i; + for (i = 0; i < D->maxsection; i++) + if (D->sections[i].buf) + DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); + if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); + if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); + DASM_M_FREE(Dst, D, D->psize); +} + +/* Setup global label array. Must be called before dasm_setup(). */ +void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) +{ + dasm_State *D = Dst_REF; + D->globals = gl - 10; /* Negative bias to compensate for locals. */ + DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); +} + +/* Grow PC label array. Can be called after dasm_setup(), too. */ +void dasm_growpc(Dst_DECL, unsigned int maxpc) +{ + dasm_State *D = Dst_REF; + size_t osz = D->pcsize; + DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); + memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); +} + +/* Setup encoder. */ +void dasm_setup(Dst_DECL, const void *actionlist) +{ + dasm_State *D = Dst_REF; + int i; + D->actionlist = (dasm_ActList)actionlist; + D->status = DASM_S_OK; + D->section = &D->sections[0]; + memset((void *)D->lglabels, 0, D->lgsize); + if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); + for (i = 0; i < D->maxsection; i++) { + D->sections[i].pos = DASM_SEC2POS(i); + D->sections[i].ofs = 0; + } +} + + +#ifdef DASM_CHECKS +#define CK(x, st) \ + do { if (!(x)) { \ + D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) +#define CKPL(kind, st) \ + do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ + D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) +#else +#define CK(x, st) ((void)0) +#define CKPL(kind, st) ((void)0) +#endif + +/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ +void dasm_put(Dst_DECL, int start, ...) +{ + va_list ap; + dasm_State *D = Dst_REF; + dasm_ActList p = D->actionlist + start; + dasm_Section *sec = D->section; + int pos = sec->pos, ofs = sec->ofs; + int *b; + + if (pos >= sec->epos) { + DASM_M_GROW(Dst, int, sec->buf, sec->bsize, + sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); + sec->rbuf = sec->buf - DASM_POS2BIAS(pos); + sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); + } + + b = sec->rbuf; + b[pos++] = start; + + va_start(ap, start); + while (1) { + unsigned int ins = *p++; + unsigned int action = (ins >> 16) - 0xff00; + if (action >= DASM__MAX) { + ofs += 4; + } else { + int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; + switch (action) { + case DASM_STOP: goto stop; + case DASM_SECTION: + n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); + D->section = &D->sections[n]; goto stop; + case DASM_ESC: p++; ofs += 4; break; + case DASM_REL_EXT: break; + case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; + case DASM_REL_LG: + n = (ins & 2047) - 10; pl = D->lglabels + n; + /* Bkwd rel or global. */ + if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } + pl += 10; n = *pl; + if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ + goto linkrel; + case DASM_REL_PC: + pl = D->pclabels + n; CKPL(pc, PC); + putrel: + n = *pl; + if (n < 0) { /* Label exists. Get label pos and store it. */ + b[pos] = -n; + } else { + linkrel: + b[pos] = n; /* Else link to rel chain, anchored at label. */ + *pl = pos; + } + pos++; + break; + case DASM_LABEL_LG: + pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; + case DASM_LABEL_PC: + pl = D->pclabels + n; CKPL(pc, PC); + putlabel: + n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ + while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; + } + *pl = -pos; /* Label exists now. */ + b[pos++] = ofs; /* Store pass1 offset estimate. */ + break; + case DASM_IMM: case DASM_IMMS: +#ifdef DASM_CHECKS + CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); +#endif + n >>= ((ins>>10)&31); +#ifdef DASM_CHECKS + if (ins & 0x8000) + CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); + else + CK((n>>((ins>>5)&31)) == 0, RANGE_I); +#endif + b[pos++] = n; + break; + } + } + } +stop: + va_end(ap); + sec->pos = pos; + sec->ofs = ofs; +} +#undef CK + +/* Pass 2: Link sections, shrink aligns, fix label offsets. */ +int dasm_link(Dst_DECL, size_t *szp) +{ + dasm_State *D = Dst_REF; + int secnum; + int ofs = 0; + +#ifdef DASM_CHECKS + *szp = 0; + if (D->status != DASM_S_OK) return D->status; + { + int pc; + for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) + if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; + } +#endif + + { /* Handle globals not defined in this translation unit. */ + int idx; + for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { + int n = D->lglabels[idx]; + /* Undefined label: Collapse rel chain and replace with marker (< 0). */ + while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } + } + } + + /* Combine all code sections. No support for data sections (yet). */ + for (secnum = 0; secnum < D->maxsection; secnum++) { + dasm_Section *sec = D->sections + secnum; + int *b = sec->rbuf; + int pos = DASM_SEC2POS(secnum); + int lastpos = sec->pos; + + while (pos != lastpos) { + dasm_ActList p = D->actionlist + b[pos++]; + while (1) { + unsigned int ins = *p++; + unsigned int action = (ins >> 16) - 0xff00; + switch (action) { + case DASM_STOP: case DASM_SECTION: goto stop; + case DASM_ESC: p++; break; + case DASM_REL_EXT: break; + case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; + case DASM_REL_LG: case DASM_REL_PC: pos++; break; + case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; + case DASM_IMM: case DASM_IMMS: pos++; break; + } + } + stop: (void)0; + } + ofs += sec->ofs; /* Next section starts right after current section. */ + } + + D->codesize = ofs; /* Total size of all code sections */ + *szp = ofs; + return DASM_S_OK; +} + +#ifdef DASM_CHECKS +#define CK(x, st) \ + do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) +#else +#define CK(x, st) ((void)0) +#endif + +/* Pass 3: Encode sections. */ +int dasm_encode(Dst_DECL, void *buffer) +{ + dasm_State *D = Dst_REF; + char *base = (char *)buffer; + unsigned int *cp = (unsigned int *)buffer; + int secnum; + + /* Encode all code sections. No support for data sections (yet). */ + for (secnum = 0; secnum < D->maxsection; secnum++) { + dasm_Section *sec = D->sections + secnum; + int *b = sec->buf; + int *endb = sec->rbuf + sec->pos; + + while (b != endb) { + dasm_ActList p = D->actionlist + *b++; + while (1) { + unsigned int ins = *p++; + unsigned int action = (ins >> 16) - 0xff00; + int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; + switch (action) { + case DASM_STOP: case DASM_SECTION: goto stop; + case DASM_ESC: *cp++ = *p++; break; + case DASM_REL_EXT: + n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1); + goto patchrel; + case DASM_ALIGN: + ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; + break; + case DASM_REL_LG: + CK(n >= 0, UNDEF_LG); + /* fallthrough */ + case DASM_REL_PC: + CK(n >= 0, UNDEF_PC); + n = *DASM_POS2PTR(D, n); + if (ins & 2048) + n = n - (int)((char *)cp - base); + else + n = (n + (int)(size_t)base) & 0x0fffffff; + patchrel: + CK((n & 3) == 0 && + ((n + ((ins & 2048) ? 0x00020000 : 0)) >> + ((ins & 2048) ? 18 : 28)) == 0, RANGE_REL); + cp[-1] |= ((n>>2) & ((ins & 2048) ? 0x0000ffff: 0x03ffffff)); + break; + case DASM_LABEL_LG: + ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); + break; + case DASM_LABEL_PC: break; + case DASM_IMMS: + cp[-1] |= ((n>>3) & 4); n &= 0x1f; + /* fallthrough */ + case DASM_IMM: + cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); + break; + default: *cp++ = ins; break; + } + } + stop: (void)0; + } + } + + if (base + D->codesize != (char *)cp) /* Check for phase errors. */ + return DASM_S_PHASE; + return DASM_S_OK; +} +#undef CK + +/* Get PC label offset. */ +int dasm_getpclabel(Dst_DECL, unsigned int pc) +{ + dasm_State *D = Dst_REF; + if (pc*sizeof(int) < D->pcsize) { + int pos = D->pclabels[pc]; + if (pos < 0) return *DASM_POS2PTR(D, -pos); + if (pos > 0) return -1; /* Undefined. */ + } + return -2; /* Unused or out of range. */ +} + +#ifdef DASM_CHECKS +/* Optional sanity checker to call between isolated encoding steps. */ +int dasm_checkstep(Dst_DECL, int secmatch) +{ + dasm_State *D = Dst_REF; + if (D->status == DASM_S_OK) { + int i; + for (i = 1; i <= 9; i++) { + if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } + D->lglabels[i] = 0; + } + } + if (D->status == DASM_S_OK && secmatch >= 0 && + D->section != &D->sections[secmatch]) + D->status = DASM_S_MATCH_SEC|(D->section-D->sections); + return D->status; +} +#endif + diff --git a/texk/web2c/luatexdir/luaffi/dynasm/dasm_mips.lua b/texk/web2c/luatexdir/luaffi/dynasm/dasm_mips.lua new file mode 100644 index 0000000000..78a4e34a09 --- /dev/null +++ b/texk/web2c/luatexdir/luaffi/dynasm/dasm_mips.lua @@ -0,0 +1,1008 @@ +------------------------------------------------------------------------------ +-- DynASM MIPS32/MIPS64 module. +-- +-- Copyright (C) 2005-2017 Mike Pall. All rights reserved. +-- See dynasm.lua for full copyright notice. +------------------------------------------------------------------------------ + +local mips64 = mips64 + +-- Module information: +local _info = { + arch = mips64 and "mips64" or "mips", + description = "DynASM MIPS32/MIPS64 module", + version = "1.4.0", + vernum = 10400, + release = "2016-05-24", + author = "Mike Pall", + license = "MIT", +} + +-- Exported glue functions for the arch-specific module. +local _M = { _info = _info } + +-- Cache library functions. +local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs +local assert, setmetatable = assert, setmetatable +local _s = string +local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char +local match, gmatch = _s.match, _s.gmatch +local concat, sort = table.concat, table.sort +local bit = bit or require("bit") +local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift +local tohex = bit.tohex + +-- Inherited tables and callbacks. +local g_opt, g_arch +local wline, werror, wfatal, wwarn + +-- Action name list. +-- CHECK: Keep this in sync with the C code! +local action_names = { + "STOP", "SECTION", "ESC", "REL_EXT", + "ALIGN", "REL_LG", "LABEL_LG", + "REL_PC", "LABEL_PC", "IMM", "IMMS", +} + +-- Maximum number of section buffer positions for dasm_put(). +-- CHECK: Keep this in sync with the C code! +local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. + +-- Action name -> action number. +local map_action = {} +for n,name in ipairs(action_names) do + map_action[name] = n-1 +end + +-- Action list buffer. +local actlist = {} + +-- Argument list for next dasm_put(). Start with offset 0 into action list. +local actargs = { 0 } + +-- Current number of section buffer positions for dasm_put(). +local secpos = 1 + +------------------------------------------------------------------------------ + +-- Dump action names and numbers. +local function dumpactions(out) + out:write("DynASM encoding engine action codes:\n") + for n,name in ipairs(action_names) do + local num = map_action[name] + out:write(format(" %-10s %02X %d\n", name, num, num)) + end + out:write("\n") +end + +-- Write action list buffer as a huge static C array. +local function writeactions(out, name) + local nn = #actlist + if nn == 0 then nn = 1; actlist[0] = map_action.STOP end + out:write("static const unsigned int ", name, "[", nn, "] = {\n") + for i = 1,nn-1 do + assert(out:write("0x", tohex(actlist[i]), ",\n")) + end + assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) +end + +------------------------------------------------------------------------------ + +-- Add word to action list. +local function wputxw(n) + assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") + actlist[#actlist+1] = n +end + +-- Add action to list with optional arg. Advance buffer pos, too. +local function waction(action, val, a, num) + local w = assert(map_action[action], "bad action name `"..action.."'") + wputxw(0xff000000 + w * 0x10000 + (val or 0)) + if a then actargs[#actargs+1] = a end + if a or num then secpos = secpos + (num or 1) end +end + +-- Flush action list (intervening C code or buffer pos overflow). +local function wflush(term) + if #actlist == actargs[1] then return end -- Nothing to flush. + if not term then waction("STOP") end -- Terminate action list. + wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) + actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). + secpos = 1 -- The actionlist offset occupies a buffer position, too. +end + +-- Put escaped word. +local function wputw(n) + if n >= 0xff000000 then waction("ESC") end + wputxw(n) +end + +-- Reserve position for word. +local function wpos() + local pos = #actlist+1 + actlist[pos] = "" + return pos +end + +-- Store word to reserved position. +local function wputpos(pos, n) + assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") + actlist[pos] = n +end + +------------------------------------------------------------------------------ + +-- Global label name -> global label number. With auto assignment on 1st use. +local next_global = 20 +local map_global = setmetatable({}, { __index = function(t, name) + if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end + local n = next_global + if n > 2047 then werror("too many global labels") end + next_global = n + 1 + t[name] = n + return n +end}) + +-- Dump global labels. +local function dumpglobals(out, lvl) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("Global labels:\n") + for i=20,next_global-1 do + out:write(format(" %s\n", t[i])) + end + out:write("\n") +end + +-- Write global label enum. +local function writeglobals(out, prefix) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("enum {\n") + for i=20,next_global-1 do + out:write(" ", prefix, t[i], ",\n") + end + out:write(" ", prefix, "_MAX\n};\n") +end + +-- Write global label names. +local function writeglobalnames(out, name) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("static const char *const ", name, "[] = {\n") + for i=20,next_global-1 do + out:write(" \"", t[i], "\",\n") + end + out:write(" (const char *)0\n};\n") +end + +------------------------------------------------------------------------------ + +-- Extern label name -> extern label number. With auto assignment on 1st use. +local next_extern = 0 +local map_extern_ = {} +local map_extern = setmetatable({}, { __index = function(t, name) + -- No restrictions on the name for now. + local n = next_extern + if n > 2047 then werror("too many extern labels") end + next_extern = n + 1 + t[name] = n + map_extern_[n] = name + return n +end}) + +-- Dump extern labels. +local function dumpexterns(out, lvl) + out:write("Extern labels:\n") + for i=0,next_extern-1 do + out:write(format(" %s\n", map_extern_[i])) + end + out:write("\n") +end + +-- Write extern label names. +local function writeexternnames(out, name) + out:write("static const char *const ", name, "[] = {\n") + for i=0,next_extern-1 do + out:write(" \"", map_extern_[i], "\",\n") + end + out:write(" (const char *)0\n};\n") +end + +------------------------------------------------------------------------------ + +-- Arch-specific maps. +local map_archdef = { sp="r29", ra="r31" } -- Ext. register name -> int. name. + +local map_type = {} -- Type name -> { ctype, reg } +local ctypenum = 0 -- Type number (for Dt... macros). + +-- Reverse defines for registers. +function _M.revdef(s) + if s == "r29" then return "sp" + elseif s == "r31" then return "ra" end + return s +end + +------------------------------------------------------------------------------ + +-- Template strings for MIPS instructions. +local map_op = { + -- First-level opcodes. + j_1 = "08000000J", + jal_1 = "0c000000J", + b_1 = "10000000B", + beqz_2 = "10000000SB", + beq_3 = "10000000STB", + bnez_2 = "14000000SB", + bne_3 = "14000000STB", + blez_2 = "18000000SB", + bgtz_2 = "1c000000SB", + addi_3 = "20000000TSI", + li_2 = "24000000TI", + addiu_3 = "24000000TSI", + slti_3 = "28000000TSI", + sltiu_3 = "2c000000TSI", + andi_3 = "30000000TSU", + lu_2 = "34000000TU", + ori_3 = "34000000TSU", + xori_3 = "38000000TSU", + lui_2 = "3c000000TU", + beqzl_2 = "50000000SB", + beql_3 = "50000000STB", + bnezl_2 = "54000000SB", + bnel_3 = "54000000STB", + blezl_2 = "58000000SB", + bgtzl_2 = "5c000000SB", + daddi_3 = mips64 and "60000000TSI", + daddiu_3 = mips64 and "64000000TSI", + ldl_2 = mips64 and "68000000TO", + ldr_2 = mips64 and "6c000000TO", + lb_2 = "80000000TO", + lh_2 = "84000000TO", + lwl_2 = "88000000TO", + lw_2 = "8c000000TO", + lbu_2 = "90000000TO", + lhu_2 = "94000000TO", + lwr_2 = "98000000TO", + lwu_2 = mips64 and "9c000000TO", + sb_2 = "a0000000TO", + sh_2 = "a4000000TO", + swl_2 = "a8000000TO", + sw_2 = "ac000000TO", + sdl_2 = mips64 and "b0000000TO", + sdr_2 = mips64 and "b1000000TO", + swr_2 = "b8000000TO", + cache_2 = "bc000000NO", + ll_2 = "c0000000TO", + lwc1_2 = "c4000000HO", + pref_2 = "cc000000NO", + ldc1_2 = "d4000000HO", + ld_2 = mips64 and "dc000000TO", + sc_2 = "e0000000TO", + swc1_2 = "e4000000HO", + scd_2 = mips64 and "f0000000TO", + sdc1_2 = "f4000000HO", + sd_2 = mips64 and "fc000000TO", + + -- Opcode SPECIAL. + nop_0 = "00000000", + sll_3 = "00000000DTA", + sextw_2 = "00000000DT", + movf_2 = "00000001DS", + movf_3 = "00000001DSC", + movt_2 = "00010001DS", + movt_3 = "00010001DSC", + srl_3 = "00000002DTA", + rotr_3 = "00200002DTA", + sra_3 = "00000003DTA", + sllv_3 = "00000004DTS", + srlv_3 = "00000006DTS", + rotrv_3 = "00000046DTS", + drotrv_3 = mips64 and "00000056DTS", + srav_3 = "00000007DTS", + jr_1 = "00000008S", + jalr_1 = "0000f809S", + jalr_2 = "00000009DS", + movz_3 = "0000000aDST", + movn_3 = "0000000bDST", + syscall_0 = "0000000c", + syscall_1 = "0000000cY", + break_0 = "0000000d", + break_1 = "0000000dY", + sync_0 = "0000000f", + mfhi_1 = "00000010D", + mthi_1 = "00000011S", + mflo_1 = "00000012D", + mtlo_1 = "00000013S", + dsllv_3 = mips64 and "00000014DTS", + dsrlv_3 = mips64 and "00000016DTS", + dsrav_3 = mips64 and "00000017DTS", + mult_2 = "00000018ST", + multu_2 = "00000019ST", + div_2 = "0000001aST", + divu_2 = "0000001bST", + dmult_2 = mips64 and "0000001cST", + dmultu_2 = mips64 and "0000001dST", + ddiv_2 = mips64 and "0000001eST", + ddivu_2 = mips64 and "0000001fST", + add_3 = "00000020DST", + move_2 = mips64 and "00000025DS" or "00000021DS", + addu_3 = "00000021DST", + sub_3 = "00000022DST", + negu_2 = mips64 and "0000002fDT" or "00000023DT", + subu_3 = "00000023DST", + and_3 = "00000024DST", + or_3 = "00000025DST", + xor_3 = "00000026DST", + not_2 = "00000027DS", + nor_3 = "00000027DST", + slt_3 = "0000002aDST", + sltu_3 = "0000002bDST", + dadd_3 = mips64 and "0000002cDST", + daddu_3 = mips64 and "0000002dDST", + dsub_3 = mips64 and "0000002eDST", + dsubu_3 = mips64 and "0000002fDST", + tge_2 = "00000030ST", + tge_3 = "00000030STZ", + tgeu_2 = "00000031ST", + tgeu_3 = "00000031STZ", + tlt_2 = "00000032ST", + tlt_3 = "00000032STZ", + tltu_2 = "00000033ST", + tltu_3 = "00000033STZ", + teq_2 = "00000034ST", + teq_3 = "00000034STZ", + tne_2 = "00000036ST", + tne_3 = "00000036STZ", + dsll_3 = mips64 and "00000038DTa", + dsrl_3 = mips64 and "0000003aDTa", + drotr_3 = mips64 and "0020003aDTa", + dsra_3 = mips64 and "0000003bDTa", + dsll32_3 = mips64 and "0000003cDTA", + dsrl32_3 = mips64 and "0000003eDTA", + drotr32_3 = mips64 and "0020003eDTA", + dsra32_3 = mips64 and "0000003fDTA", + + -- Opcode REGIMM. + bltz_2 = "04000000SB", + bgez_2 = "04010000SB", + bltzl_2 = "04020000SB", + bgezl_2 = "04030000SB", + tgei_2 = "04080000SI", + tgeiu_2 = "04090000SI", + tlti_2 = "040a0000SI", + tltiu_2 = "040b0000SI", + teqi_2 = "040c0000SI", + tnei_2 = "040e0000SI", + bltzal_2 = "04100000SB", + bal_1 = "04110000B", + bgezal_2 = "04110000SB", + bltzall_2 = "04120000SB", + bgezall_2 = "04130000SB", + synci_1 = "041f0000O", + + -- Opcode SPECIAL2. + madd_2 = "70000000ST", + maddu_2 = "70000001ST", + mul_3 = "70000002DST", + msub_2 = "70000004ST", + msubu_2 = "70000005ST", + clz_2 = "70000020DS=", + clo_2 = "70000021DS=", + dclz_2 = mips64 and "70000024DS=", + dclo_2 = mips64 and "70000025DS=", + sdbbp_0 = "7000003f", + sdbbp_1 = "7000003fY", + + -- Opcode SPECIAL3. + ext_4 = "7c000000TSAM", -- Note: last arg is msbd = size-1 + dextm_4 = mips64 and "7c000001TSAM", -- Args: pos | size-1-32 + dextu_4 = mips64 and "7c000002TSAM", -- Args: pos-32 | size-1 + dext_4 = mips64 and "7c000003TSAM", -- Args: pos | size-1 + zextw_2 = mips64 and "7c00f803TS", + ins_4 = "7c000004TSAM", -- Note: last arg is msb = pos+size-1 + dinsm_4 = mips64 and "7c000005TSAM", -- Args: pos | pos+size-33 + dinsu_4 = mips64 and "7c000006TSAM", -- Args: pos-32 | pos+size-33 + dins_4 = mips64 and "7c000007TSAM", -- Args: pos | pos+size-1 + wsbh_2 = "7c0000a0DT", + dsbh_2 = mips64 and "7c0000a4DT", + dshd_2 = mips64 and "7c000164DT", + seb_2 = "7c000420DT", + seh_2 = "7c000620DT", + rdhwr_2 = "7c00003bTD", + + -- Opcode COP0. + mfc0_2 = "40000000TD", + mfc0_3 = "40000000TDW", + dmfc0_2 = mips64 and "40200000TD", + dmfc0_3 = mips64 and "40200000TDW", + mtc0_2 = "40800000TD", + mtc0_3 = "40800000TDW", + dmtc0_2 = mips64 and "40a00000TD", + dmtc0_3 = mips64 and "40a00000TDW", + rdpgpr_2 = "41400000DT", + di_0 = "41606000", + di_1 = "41606000T", + ei_0 = "41606020", + ei_1 = "41606020T", + wrpgpr_2 = "41c00000DT", + tlbr_0 = "42000001", + tlbwi_0 = "42000002", + tlbwr_0 = "42000006", + tlbp_0 = "42000008", + eret_0 = "42000018", + deret_0 = "4200001f", + wait_0 = "42000020", + + -- Opcode COP1. + mfc1_2 = "44000000TG", + dmfc1_2 = mips64 and "44200000TG", + cfc1_2 = "44400000TG", + mfhc1_2 = "44600000TG", + mtc1_2 = "44800000TG", + dmtc1_2 = mips64 and "44a00000TG", + ctc1_2 = "44c00000TG", + mthc1_2 = "44e00000TG", + + bc1f_1 = "45000000B", + bc1f_2 = "45000000CB", + bc1t_1 = "45010000B", + bc1t_2 = "45010000CB", + bc1fl_1 = "45020000B", + bc1fl_2 = "45020000CB", + bc1tl_1 = "45030000B", + bc1tl_2 = "45030000CB", + + ["add.s_3"] = "46000000FGH", + ["sub.s_3"] = "46000001FGH", + ["mul.s_3"] = "46000002FGH", + ["div.s_3"] = "46000003FGH", + ["sqrt.s_2"] = "46000004FG", + ["abs.s_2"] = "46000005FG", + ["mov.s_2"] = "46000006FG", + ["neg.s_2"] = "46000007FG", + ["round.l.s_2"] = "46000008FG", + ["trunc.l.s_2"] = "46000009FG", + ["ceil.l.s_2"] = "4600000aFG", + ["floor.l.s_2"] = "4600000bFG", + ["round.w.s_2"] = "4600000cFG", + ["trunc.w.s_2"] = "4600000dFG", + ["ceil.w.s_2"] = "4600000eFG", + ["floor.w.s_2"] = "4600000fFG", + ["movf.s_2"] = "46000011FG", + ["movf.s_3"] = "46000011FGC", + ["movt.s_2"] = "46010011FG", + ["movt.s_3"] = "46010011FGC", + ["movz.s_3"] = "46000012FGT", + ["movn.s_3"] = "46000013FGT", + ["recip.s_2"] = "46000015FG", + ["rsqrt.s_2"] = "46000016FG", + ["cvt.d.s_2"] = "46000021FG", + ["cvt.w.s_2"] = "46000024FG", + ["cvt.l.s_2"] = "46000025FG", + ["cvt.ps.s_3"] = "46000026FGH", + ["c.f.s_2"] = "46000030GH", + ["c.f.s_3"] = "46000030VGH", + ["c.un.s_2"] = "46000031GH", + ["c.un.s_3"] = "46000031VGH", + ["c.eq.s_2"] = "46000032GH", + ["c.eq.s_3"] = "46000032VGH", + ["c.ueq.s_2"] = "46000033GH", + ["c.ueq.s_3"] = "46000033VGH", + ["c.olt.s_2"] = "46000034GH", + ["c.olt.s_3"] = "46000034VGH", + ["c.ult.s_2"] = "46000035GH", + ["c.ult.s_3"] = "46000035VGH", + ["c.ole.s_2"] = "46000036GH", + ["c.ole.s_3"] = "46000036VGH", + ["c.ule.s_2"] = "46000037GH", + ["c.ule.s_3"] = "46000037VGH", + ["c.sf.s_2"] = "46000038GH", + ["c.sf.s_3"] = "46000038VGH", + ["c.ngle.s_2"] = "46000039GH", + ["c.ngle.s_3"] = "46000039VGH", + ["c.seq.s_2"] = "4600003aGH", + ["c.seq.s_3"] = "4600003aVGH", + ["c.ngl.s_2"] = "4600003bGH", + ["c.ngl.s_3"] = "4600003bVGH", + ["c.lt.s_2"] = "4600003cGH", + ["c.lt.s_3"] = "4600003cVGH", + ["c.nge.s_2"] = "4600003dGH", + ["c.nge.s_3"] = "4600003dVGH", + ["c.le.s_2"] = "4600003eGH", + ["c.le.s_3"] = "4600003eVGH", + ["c.ngt.s_2"] = "4600003fGH", + ["c.ngt.s_3"] = "4600003fVGH", + + ["add.d_3"] = "46200000FGH", + ["sub.d_3"] = "46200001FGH", + ["mul.d_3"] = "46200002FGH", + ["div.d_3"] = "46200003FGH", + ["sqrt.d_2"] = "46200004FG", + ["abs.d_2"] = "46200005FG", + ["mov.d_2"] = "46200006FG", + ["neg.d_2"] = "46200007FG", + ["round.l.d_2"] = "46200008FG", + ["trunc.l.d_2"] = "46200009FG", + ["ceil.l.d_2"] = "4620000aFG", + ["floor.l.d_2"] = "4620000bFG", + ["round.w.d_2"] = "4620000cFG", + ["trunc.w.d_2"] = "4620000dFG", + ["ceil.w.d_2"] = "4620000eFG", + ["floor.w.d_2"] = "4620000fFG", + ["movf.d_2"] = "46200011FG", + ["movf.d_3"] = "46200011FGC", + ["movt.d_2"] = "46210011FG", + ["movt.d_3"] = "46210011FGC", + ["movz.d_3"] = "46200012FGT", + ["movn.d_3"] = "46200013FGT", + ["recip.d_2"] = "46200015FG", + ["rsqrt.d_2"] = "46200016FG", + ["cvt.s.d_2"] = "46200020FG", + ["cvt.w.d_2"] = "46200024FG", + ["cvt.l.d_2"] = "46200025FG", + ["c.f.d_2"] = "46200030GH", + ["c.f.d_3"] = "46200030VGH", + ["c.un.d_2"] = "46200031GH", + ["c.un.d_3"] = "46200031VGH", + ["c.eq.d_2"] = "46200032GH", + ["c.eq.d_3"] = "46200032VGH", + ["c.ueq.d_2"] = "46200033GH", + ["c.ueq.d_3"] = "46200033VGH", + ["c.olt.d_2"] = "46200034GH", + ["c.olt.d_3"] = "46200034VGH", + ["c.ult.d_2"] = "46200035GH", + ["c.ult.d_3"] = "46200035VGH", + ["c.ole.d_2"] = "46200036GH", + ["c.ole.d_3"] = "46200036VGH", + ["c.ule.d_2"] = "46200037GH", + ["c.ule.d_3"] = "46200037VGH", + ["c.sf.d_2"] = "46200038GH", + ["c.sf.d_3"] = "46200038VGH", + ["c.ngle.d_2"] = "46200039GH", + ["c.ngle.d_3"] = "46200039VGH", + ["c.seq.d_2"] = "4620003aGH", + ["c.seq.d_3"] = "4620003aVGH", + ["c.ngl.d_2"] = "4620003bGH", + ["c.ngl.d_3"] = "4620003bVGH", + ["c.lt.d_2"] = "4620003cGH", + ["c.lt.d_3"] = "4620003cVGH", + ["c.nge.d_2"] = "4620003dGH", + ["c.nge.d_3"] = "4620003dVGH", + ["c.le.d_2"] = "4620003eGH", + ["c.le.d_3"] = "4620003eVGH", + ["c.ngt.d_2"] = "4620003fGH", + ["c.ngt.d_3"] = "4620003fVGH", + + ["add.ps_3"] = "46c00000FGH", + ["sub.ps_3"] = "46c00001FGH", + ["mul.ps_3"] = "46c00002FGH", + ["abs.ps_2"] = "46c00005FG", + ["mov.ps_2"] = "46c00006FG", + ["neg.ps_2"] = "46c00007FG", + ["movf.ps_2"] = "46c00011FG", + ["movf.ps_3"] = "46c00011FGC", + ["movt.ps_2"] = "46c10011FG", + ["movt.ps_3"] = "46c10011FGC", + ["movz.ps_3"] = "46c00012FGT", + ["movn.ps_3"] = "46c00013FGT", + ["cvt.s.pu_2"] = "46c00020FG", + ["cvt.s.pl_2"] = "46c00028FG", + ["pll.ps_3"] = "46c0002cFGH", + ["plu.ps_3"] = "46c0002dFGH", + ["pul.ps_3"] = "46c0002eFGH", + ["puu.ps_3"] = "46c0002fFGH", + ["c.f.ps_2"] = "46c00030GH", + ["c.f.ps_3"] = "46c00030VGH", + ["c.un.ps_2"] = "46c00031GH", + ["c.un.ps_3"] = "46c00031VGH", + ["c.eq.ps_2"] = "46c00032GH", + ["c.eq.ps_3"] = "46c00032VGH", + ["c.ueq.ps_2"] = "46c00033GH", + ["c.ueq.ps_3"] = "46c00033VGH", + ["c.olt.ps_2"] = "46c00034GH", + ["c.olt.ps_3"] = "46c00034VGH", + ["c.ult.ps_2"] = "46c00035GH", + ["c.ult.ps_3"] = "46c00035VGH", + ["c.ole.ps_2"] = "46c00036GH", + ["c.ole.ps_3"] = "46c00036VGH", + ["c.ule.ps_2"] = "46c00037GH", + ["c.ule.ps_3"] = "46c00037VGH", + ["c.sf.ps_2"] = "46c00038GH", + ["c.sf.ps_3"] = "46c00038VGH", + ["c.ngle.ps_2"] = "46c00039GH", + ["c.ngle.ps_3"] = "46c00039VGH", + ["c.seq.ps_2"] = "46c0003aGH", + ["c.seq.ps_3"] = "46c0003aVGH", + ["c.ngl.ps_2"] = "46c0003bGH", + ["c.ngl.ps_3"] = "46c0003bVGH", + ["c.lt.ps_2"] = "46c0003cGH", + ["c.lt.ps_3"] = "46c0003cVGH", + ["c.nge.ps_2"] = "46c0003dGH", + ["c.nge.ps_3"] = "46c0003dVGH", + ["c.le.ps_2"] = "46c0003eGH", + ["c.le.ps_3"] = "46c0003eVGH", + ["c.ngt.ps_2"] = "46c0003fGH", + ["c.ngt.ps_3"] = "46c0003fVGH", + + ["cvt.s.w_2"] = "46800020FG", + ["cvt.d.w_2"] = "46800021FG", + + ["cvt.s.l_2"] = "46a00020FG", + ["cvt.d.l_2"] = "46a00021FG", + + -- Opcode COP1X. + lwxc1_2 = "4c000000FX", + ldxc1_2 = "4c000001FX", + luxc1_2 = "4c000005FX", + swxc1_2 = "4c000008FX", + sdxc1_2 = "4c000009FX", + suxc1_2 = "4c00000dFX", + prefx_2 = "4c00000fMX", + ["alnv.ps_4"] = "4c00001eFGHS", + ["madd.s_4"] = "4c000020FRGH", + ["madd.d_4"] = "4c000021FRGH", + ["madd.ps_4"] = "4c000026FRGH", + ["msub.s_4"] = "4c000028FRGH", + ["msub.d_4"] = "4c000029FRGH", + ["msub.ps_4"] = "4c00002eFRGH", + ["nmadd.s_4"] = "4c000030FRGH", + ["nmadd.d_4"] = "4c000031FRGH", + ["nmadd.ps_4"] = "4c000036FRGH", + ["nmsub.s_4"] = "4c000038FRGH", + ["nmsub.d_4"] = "4c000039FRGH", + ["nmsub.ps_4"] = "4c00003eFRGH", +} + +------------------------------------------------------------------------------ + +local function parse_gpr(expr) + local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$") + local tp = map_type[tname or expr] + if tp then + local reg = ovreg or tp.reg + if not reg then + werror("type `"..(tname or expr).."' needs a register override") + end + expr = reg + end + local r = match(expr, "^r([1-3]?[0-9])$") + if r then + r = tonumber(r) + if r <= 31 then return r, tp end + end + werror("bad register name `"..expr.."'") +end + +local function parse_fpr(expr) + local r = match(expr, "^f([1-3]?[0-9])$") + if r then + r = tonumber(r) + if r <= 31 then return r end + end + werror("bad register name `"..expr.."'") +end + +local function parse_imm(imm, bits, shift, scale, signed, action) + local n = tonumber(imm) + if n then + local m = sar(n, scale) + if shl(m, scale) == n then + if signed then + local s = sar(m, bits-1) + if s == 0 then return shl(m, shift) + elseif s == -1 then return shl(m + shl(1, bits), shift) end + else + if sar(m, bits) == 0 then return shl(m, shift) end + end + end + werror("out of range immediate `"..imm.."'") + elseif match(imm, "^[rf]([1-3]?[0-9])$") or + match(imm, "^([%w_]+):([rf][1-3]?[0-9])$") then + werror("expected immediate operand, got register") + else + waction(action or "IMM", + (signed and 32768 or 0)+shl(scale, 10)+shl(bits, 5)+shift, imm) + return 0 + end +end + +local function parse_disp(disp) + local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") + if imm then + local r = shl(parse_gpr(reg), 21) + local extname = match(imm, "^extern%s+(%S+)$") + if extname then + waction("REL_EXT", map_extern[extname], nil, 1) + return r + else + return r + parse_imm(imm, 16, 0, 0, true) + end + end + local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") + if reg and tailr ~= "" then + local r, tp = parse_gpr(reg) + if tp then + waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr)) + return shl(r, 21) + end + end + werror("bad displacement `"..disp.."'") +end + +local function parse_index(idx) + local rt, rs = match(idx, "^(.*)%(([%w_:]+)%)$") + if rt then + rt = parse_gpr(rt) + rs = parse_gpr(rs) + return shl(rt, 16) + shl(rs, 21) + end + werror("bad index `"..idx.."'") +end + +local function parse_label(label, def) + local prefix = sub(label, 1, 2) + -- =>label (pc label reference) + if prefix == "=>" then + return "PC", 0, sub(label, 3) + end + -- ->name (global label reference) + if prefix == "->" then + return "LG", map_global[sub(label, 3)] + end + if def then + -- [1-9] (local label definition) + if match(label, "^[1-9]$") then + return "LG", 10+tonumber(label) + end + else + -- [<>][1-9] (local label reference) + local dir, lnum = match(label, "^([<>])([1-9])$") + if dir then -- Fwd: 1-9, Bkwd: 11-19. + return "LG", lnum + (dir == ">" and 0 or 10) + end + -- extern label (extern label reference) + local extname = match(label, "^extern%s+(%S+)$") + if extname then + return "EXT", map_extern[extname] + end + end + werror("bad label `"..label.."'") +end + +------------------------------------------------------------------------------ + +-- Handle opcodes defined with template strings. +map_op[".template__"] = function(params, template, nparams) + if not params then return sub(template, 9) end + local op = tonumber(sub(template, 1, 8), 16) + local n = 1 + + -- Limit number of section buffer positions used by a single dasm_put(). + -- A single opcode needs a maximum of 2 positions (ins/ext). + if secpos+2 > maxsecpos then wflush() end + local pos = wpos() + + -- Process each character. + for p in gmatch(sub(template, 9), ".") do + if p == "D" then + op = op + shl(parse_gpr(params[n]), 11); n = n + 1 + elseif p == "T" then + op = op + shl(parse_gpr(params[n]), 16); n = n + 1 + elseif p == "S" then + op = op + shl(parse_gpr(params[n]), 21); n = n + 1 + elseif p == "F" then + op = op + shl(parse_fpr(params[n]), 6); n = n + 1 + elseif p == "G" then + op = op + shl(parse_fpr(params[n]), 11); n = n + 1 + elseif p == "H" then + op = op + shl(parse_fpr(params[n]), 16); n = n + 1 + elseif p == "R" then + op = op + shl(parse_fpr(params[n]), 21); n = n + 1 + elseif p == "I" then + op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1 + elseif p == "U" then + op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1 + elseif p == "O" then + op = op + parse_disp(params[n]); n = n + 1 + elseif p == "X" then + op = op + parse_index(params[n]); n = n + 1 + elseif p == "B" or p == "J" then + local mode, n, s = parse_label(params[n], false) + if p == "B" then n = n + 2048 end + waction("REL_"..mode, n, s, 1) + n = n + 1 + elseif p == "A" then + op = op + parse_imm(params[n], 5, 6, 0, false); n = n + 1 + elseif p == "a" then + local m = parse_imm(params[n], 6, 6, 0, false, "IMMS"); n = n + 1 + op = op + band(m, 0x7c0) + band(shr(m, 9), 4) + elseif p == "M" then + op = op + parse_imm(params[n], 5, 11, 0, false); n = n + 1 + elseif p == "N" then + op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1 + elseif p == "C" then + op = op + parse_imm(params[n], 3, 18, 0, false); n = n + 1 + elseif p == "V" then + op = op + parse_imm(params[n], 3, 8, 0, false); n = n + 1 + elseif p == "W" then + op = op + parse_imm(params[n], 3, 0, 0, false); n = n + 1 + elseif p == "Y" then + op = op + parse_imm(params[n], 20, 6, 0, false); n = n + 1 + elseif p == "Z" then + op = op + parse_imm(params[n], 10, 6, 0, false); n = n + 1 + elseif p == "=" then + op = op + shl(band(op, 0xf800), 5) -- Copy D to T for clz, clo. + else + assert(false) + end + end + wputpos(pos, op) +end + +------------------------------------------------------------------------------ + +-- Pseudo-opcode to mark the position where the action list is to be emitted. +map_op[".actionlist_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeactions(out, name) end) +end + +-- Pseudo-opcode to mark the position where the global enum is to be emitted. +map_op[".globals_1"] = function(params) + if not params then return "prefix" end + local prefix = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeglobals(out, prefix) end) +end + +-- Pseudo-opcode to mark the position where the global names are to be emitted. +map_op[".globalnames_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeglobalnames(out, name) end) +end + +-- Pseudo-opcode to mark the position where the extern names are to be emitted. +map_op[".externnames_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeexternnames(out, name) end) +end + +------------------------------------------------------------------------------ + +-- Label pseudo-opcode (converted from trailing colon form). +map_op[".label_1"] = function(params) + if not params then return "[1-9] | ->global | =>pcexpr" end + if secpos+1 > maxsecpos then wflush() end + local mode, n, s = parse_label(params[1], true) + if mode == "EXT" then werror("bad label definition") end + waction("LABEL_"..mode, n, s, 1) +end + +------------------------------------------------------------------------------ + +-- Pseudo-opcodes for data storage. +map_op[".long_*"] = function(params) + if not params then return "imm..." end + for _,p in ipairs(params) do + local n = tonumber(p) + if not n then werror("bad immediate `"..p.."'") end + if n < 0 then n = n + 2^32 end + wputw(n) + if secpos+2 > maxsecpos then wflush() end + end +end + +-- Alignment pseudo-opcode. +map_op[".align_1"] = function(params) + if not params then return "numpow2" end + if secpos+1 > maxsecpos then wflush() end + local align = tonumber(params[1]) + if align then + local x = align + -- Must be a power of 2 in the range (2 ... 256). + for i=1,8 do + x = x / 2 + if x == 1 then + waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. + return + end + end + end + werror("bad alignment") +end + +------------------------------------------------------------------------------ + +-- Pseudo-opcode for (primitive) type definitions (map to C types). +map_op[".type_3"] = function(params, nparams) + if not params then + return nparams == 2 and "name, ctype" or "name, ctype, reg" + end + local name, ctype, reg = params[1], params[2], params[3] + if not match(name, "^[%a_][%w_]*$") then + werror("bad type name `"..name.."'") + end + local tp = map_type[name] + if tp then + werror("duplicate type `"..name.."'") + end + -- Add #type to defines. A bit unclean to put it in map_archdef. + map_archdef["#"..name] = "sizeof("..ctype..")" + -- Add new type and emit shortcut define. + local num = ctypenum + 1 + map_type[name] = { + ctype = ctype, + ctypefmt = format("Dt%X(%%s)", num), + reg = reg, + } + wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) + ctypenum = num +end +map_op[".type_2"] = map_op[".type_3"] + +-- Dump type definitions. +local function dumptypes(out, lvl) + local t = {} + for name in pairs(map_type) do t[#t+1] = name end + sort(t) + out:write("Type definitions:\n") + for _,name in ipairs(t) do + local tp = map_type[name] + local reg = tp.reg or "" + out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) + end + out:write("\n") +end + +------------------------------------------------------------------------------ + +-- Set the current section. +function _M.section(num) + waction("SECTION", num) + wflush(true) -- SECTION is a terminal action. +end + +------------------------------------------------------------------------------ + +-- Dump architecture description. +function _M.dumparch(out) + out:write(format("DynASM %s version %s, released %s\n\n", + _info.arch, _info.version, _info.release)) + dumpactions(out) +end + +-- Dump all user defined elements. +function _M.dumpdef(out, lvl) + dumptypes(out, lvl) + dumpglobals(out, lvl) + dumpexterns(out, lvl) +end + +------------------------------------------------------------------------------ + +-- Pass callbacks from/to the DynASM core. +function _M.passcb(wl, we, wf, ww) + wline, werror, wfatal, wwarn = wl, we, wf, ww + return wflush +end + +-- Setup the arch-specific module. +function _M.setup(arch, opt) + g_arch, g_opt = arch, opt +end + +-- Merge the core maps and the arch-specific maps. +function _M.mergemaps(map_coreop, map_def) + setmetatable(map_op, { __index = map_coreop }) + setmetatable(map_def, { __index = map_archdef }) + return map_op, map_def +end + +return _M + +------------------------------------------------------------------------------ + diff --git a/texk/web2c/luatexdir/luaffi/dynasm/dasm_mips64.lua b/texk/web2c/luatexdir/luaffi/dynasm/dasm_mips64.lua new file mode 100644 index 0000000000..5636b23a6e --- /dev/null +++ b/texk/web2c/luatexdir/luaffi/dynasm/dasm_mips64.lua @@ -0,0 +1,12 @@ +------------------------------------------------------------------------------ +-- DynASM MIPS64 module. +-- +-- Copyright (C) 2005-2017 Mike Pall. All rights reserved. +-- See dynasm.lua for full copyright notice. +------------------------------------------------------------------------------ +-- This module just sets 64 bit mode for the combined MIPS/MIPS64 module. +-- All the interesting stuff is there. +------------------------------------------------------------------------------ + +mips64 = true -- Using a global is an ugly, but effective solution. +return require("dasm_mips") diff --git a/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.h b/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.h index e928ffedd3..83fc030aad 100644 --- a/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.h +++ b/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.h @@ -1,7 +1,7 @@ /* -** DynASM PPC encoding engine. -** Copyright (C) 2005-2011 Mike Pall. All rights reserved. -** Released under the MIT/X license. See dynasm.lua for full copyright notice. +** DynASM PPC/PPC64 encoding engine. +** Copyright (C) 2005-2017 Mike Pall. All rights reserved. +** Released under the MIT license. See dynasm.lua for full copyright notice. */ #include @@ -21,7 +21,7 @@ enum { /* The following actions need a buffer position. */ DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, /* The following actions also have an argument. */ - DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, + DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMSH, DASM__MAX }; @@ -202,7 +202,8 @@ void dasm_put(Dst_DECL, int start, ...) case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; case DASM_REL_LG: n = (ins & 2047) - 10; pl = D->lglabels + n; - if (n >= 0) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */ + /* Bkwd rel or global. */ + if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } pl += 10; n = *pl; if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ goto linkrel; @@ -233,6 +234,9 @@ void dasm_put(Dst_DECL, int start, ...) case DASM_IMM: #ifdef DASM_CHECKS CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); +#endif + n >>= ((ins>>10)&31); +#ifdef DASM_CHECKS if (ins & 0x8000) CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); else @@ -240,6 +244,10 @@ void dasm_put(Dst_DECL, int start, ...) #endif b[pos++] = n; break; + case DASM_IMMSH: + CK((n >> 6) == 0, RANGE_I); + b[pos++] = n; + break; } } } @@ -295,7 +303,7 @@ int dasm_link(Dst_DECL, size_t *szp) case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; case DASM_REL_LG: case DASM_REL_PC: pos++; break; case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; - case DASM_IMM: pos++; break; + case DASM_IMM: case DASM_IMMSH: pos++; break; } } stop: (void)0; @@ -339,13 +347,14 @@ int dasm_encode(Dst_DECL, void *buffer) case DASM_STOP: case DASM_SECTION: goto stop; case DASM_ESC: *cp++ = *p++; break; case DASM_REL_EXT: - n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1); + n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1) - 4; goto patchrel; case DASM_ALIGN: ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; break; case DASM_REL_LG: CK(n >= 0, UNDEF_LG); + /* fallthrough */ case DASM_REL_PC: CK(n >= 0, UNDEF_PC); n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base); @@ -360,7 +369,10 @@ int dasm_encode(Dst_DECL, void *buffer) break; case DASM_LABEL_PC: break; case DASM_IMM: - cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31); + cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); + break; + case DASM_IMMSH: + cp[-1] |= (ins & 1) ? ((n&31)<<11)|((n&32)>>4) : ((n&31)<<6)|(n&32); break; default: *cp++ = ins; break; } diff --git a/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.lua b/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.lua index bb6de01e2b..f73974dd7f 100644 --- a/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.lua +++ b/texk/web2c/luatexdir/luaffi/dynasm/dasm_ppc.lua @@ -1,17 +1,19 @@ ------------------------------------------------------------------------------ --- DynASM PPC module. +-- DynASM PPC/PPC64 module. -- --- Copyright (C) 2005-2011 Mike Pall. All rights reserved. +-- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- See dynasm.lua for full copyright notice. +-- +-- Support for various extensions contributed by Caio Souza Oliveira. ------------------------------------------------------------------------------ -- Module information: local _info = { arch = "ppc", description = "DynASM PPC module", - version = "1.3.0", - vernum = 10300, - release = "2011-05-05", + version = "1.4.0", + vernum = 10400, + release = "2015-10-18", author = "Mike Pall", license = "MIT", } @@ -26,6 +28,9 @@ local _s = string local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char local match, gmatch = _s.match, _s.gmatch local concat, sort = table.concat, table.sort +local bit = bit or require("bit") +local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift +local tohex = bit.tohex -- Inherited tables and callbacks. local g_opt, g_arch @@ -36,7 +41,7 @@ local wline, werror, wfatal, wwarn local action_names = { "STOP", "SECTION", "ESC", "REL_EXT", "ALIGN", "REL_LG", "LABEL_LG", - "REL_PC", "LABEL_PC", "IMM", + "REL_PC", "LABEL_PC", "IMM", "IMMSH" } -- Maximum number of section buffer positions for dasm_put(). @@ -60,11 +65,6 @@ local secpos = 1 ------------------------------------------------------------------------------ --- Return 8 digit hex number. -local function tohex(x) - return sub(format("%08x", x), -8) -- Avoid 64 bit portability problem in Lua. -end - -- Dump action names and numbers. local function dumpactions(out) out:write("DynASM encoding engine action codes:\n") @@ -230,8 +230,18 @@ local map_cond = { ------------------------------------------------------------------------------ +local map_op, op_template + +local function op_alias(opname, f) + return function(params, nparams) + if not params then return "-> "..opname:sub(1, -3) end + f(params, nparams) + op_template(params, map_op[opname], nparams) + end +end + -- Template strings for PPC instructions. -local map_op = { +map_op = { tdi_3 = "08000000ARI", twi_3 = "0c000000ARI", mulli_3 = "1c000000RRI", @@ -299,6 +309,250 @@ local map_op = { std_2 = "f8000000RD", stdu_2 = "f8000001RD", + subi_3 = op_alias("addi_3", function(p) p[3] = "-("..p[3]..")" end), + subis_3 = op_alias("addis_3", function(p) p[3] = "-("..p[3]..")" end), + subic_3 = op_alias("addic_3", function(p) p[3] = "-("..p[3]..")" end), + ["subic._3"] = op_alias("addic._3", function(p) p[3] = "-("..p[3]..")" end), + + rotlwi_3 = op_alias("rlwinm_5", function(p) + p[4] = "0"; p[5] = "31" + end), + rotrwi_3 = op_alias("rlwinm_5", function(p) + p[3] = "32-("..p[3]..")"; p[4] = "0"; p[5] = "31" + end), + rotlw_3 = op_alias("rlwnm_5", function(p) + p[4] = "0"; p[5] = "31" + end), + slwi_3 = op_alias("rlwinm_5", function(p) + p[5] = "31-("..p[3]..")"; p[4] = "0" + end), + srwi_3 = op_alias("rlwinm_5", function(p) + p[4] = p[3]; p[3] = "32-("..p[3]..")"; p[5] = "31" + end), + clrlwi_3 = op_alias("rlwinm_5", function(p) + p[4] = p[3]; p[3] = "0"; p[5] = "31" + end), + clrrwi_3 = op_alias("rlwinm_5", function(p) + p[5] = "31-("..p[3]..")"; p[3] = "0"; p[4] = "0" + end), + + -- Primary opcode 4: + mulhhwu_3 = "10000010RRR.", + machhwu_3 = "10000018RRR.", + mulhhw_3 = "10000050RRR.", + nmachhw_3 = "1000005cRRR.", + machhwsu_3 = "10000098RRR.", + machhws_3 = "100000d8RRR.", + nmachhws_3 = "100000dcRRR.", + mulchwu_3 = "10000110RRR.", + macchwu_3 = "10000118RRR.", + mulchw_3 = "10000150RRR.", + macchw_3 = "10000158RRR.", + nmacchw_3 = "1000015cRRR.", + macchwsu_3 = "10000198RRR.", + macchws_3 = "100001d8RRR.", + nmacchws_3 = "100001dcRRR.", + mullhw_3 = "10000350RRR.", + maclhw_3 = "10000358RRR.", + nmaclhw_3 = "1000035cRRR.", + maclhwsu_3 = "10000398RRR.", + maclhws_3 = "100003d8RRR.", + nmaclhws_3 = "100003dcRRR.", + machhwuo_3 = "10000418RRR.", + nmachhwo_3 = "1000045cRRR.", + machhwsuo_3 = "10000498RRR.", + machhwso_3 = "100004d8RRR.", + nmachhwso_3 = "100004dcRRR.", + macchwuo_3 = "10000518RRR.", + macchwo_3 = "10000558RRR.", + nmacchwo_3 = "1000055cRRR.", + macchwsuo_3 = "10000598RRR.", + macchwso_3 = "100005d8RRR.", + nmacchwso_3 = "100005dcRRR.", + maclhwo_3 = "10000758RRR.", + nmaclhwo_3 = "1000075cRRR.", + maclhwsuo_3 = "10000798RRR.", + maclhwso_3 = "100007d8RRR.", + nmaclhwso_3 = "100007dcRRR.", + + vaddubm_3 = "10000000VVV", + vmaxub_3 = "10000002VVV", + vrlb_3 = "10000004VVV", + vcmpequb_3 = "10000006VVV", + vmuloub_3 = "10000008VVV", + vaddfp_3 = "1000000aVVV", + vmrghb_3 = "1000000cVVV", + vpkuhum_3 = "1000000eVVV", + vmhaddshs_4 = "10000020VVVV", + vmhraddshs_4 = "10000021VVVV", + vmladduhm_4 = "10000022VVVV", + vmsumubm_4 = "10000024VVVV", + vmsummbm_4 = "10000025VVVV", + vmsumuhm_4 = "10000026VVVV", + vmsumuhs_4 = "10000027VVVV", + vmsumshm_4 = "10000028VVVV", + vmsumshs_4 = "10000029VVVV", + vsel_4 = "1000002aVVVV", + vperm_4 = "1000002bVVVV", + vsldoi_4 = "1000002cVVVP", + vpermxor_4 = "1000002dVVVV", + vmaddfp_4 = "1000002eVVVV~", + vnmsubfp_4 = "1000002fVVVV~", + vaddeuqm_4 = "1000003cVVVV", + vaddecuq_4 = "1000003dVVVV", + vsubeuqm_4 = "1000003eVVVV", + vsubecuq_4 = "1000003fVVVV", + vadduhm_3 = "10000040VVV", + vmaxuh_3 = "10000042VVV", + vrlh_3 = "10000044VVV", + vcmpequh_3 = "10000046VVV", + vmulouh_3 = "10000048VVV", + vsubfp_3 = "1000004aVVV", + vmrghh_3 = "1000004cVVV", + vpkuwum_3 = "1000004eVVV", + vadduwm_3 = "10000080VVV", + vmaxuw_3 = "10000082VVV", + vrlw_3 = "10000084VVV", + vcmpequw_3 = "10000086VVV", + vmulouw_3 = "10000088VVV", + vmuluwm_3 = "10000089VVV", + vmrghw_3 = "1000008cVVV", + vpkuhus_3 = "1000008eVVV", + vaddudm_3 = "100000c0VVV", + vmaxud_3 = "100000c2VVV", + vrld_3 = "100000c4VVV", + vcmpeqfp_3 = "100000c6VVV", + vcmpequd_3 = "100000c7VVV", + vpkuwus_3 = "100000ceVVV", + vadduqm_3 = "10000100VVV", + vmaxsb_3 = "10000102VVV", + vslb_3 = "10000104VVV", + vmulosb_3 = "10000108VVV", + vrefp_2 = "1000010aV-V", + vmrglb_3 = "1000010cVVV", + vpkshus_3 = "1000010eVVV", + vaddcuq_3 = "10000140VVV", + vmaxsh_3 = "10000142VVV", + vslh_3 = "10000144VVV", + vmulosh_3 = "10000148VVV", + vrsqrtefp_2 = "1000014aV-V", + vmrglh_3 = "1000014cVVV", + vpkswus_3 = "1000014eVVV", + vaddcuw_3 = "10000180VVV", + vmaxsw_3 = "10000182VVV", + vslw_3 = "10000184VVV", + vmulosw_3 = "10000188VVV", + vexptefp_2 = "1000018aV-V", + vmrglw_3 = "1000018cVVV", + vpkshss_3 = "1000018eVVV", + vmaxsd_3 = "100001c2VVV", + vsl_3 = "100001c4VVV", + vcmpgefp_3 = "100001c6VVV", + vlogefp_2 = "100001caV-V", + vpkswss_3 = "100001ceVVV", + vadduhs_3 = "10000240VVV", + vminuh_3 = "10000242VVV", + vsrh_3 = "10000244VVV", + vcmpgtuh_3 = "10000246VVV", + vmuleuh_3 = "10000248VVV", + vrfiz_2 = "1000024aV-V", + vsplth_3 = "1000024cVV3", + vupkhsh_2 = "1000024eV-V", + vminuw_3 = "10000282VVV", + vminud_3 = "100002c2VVV", + vcmpgtud_3 = "100002c7VVV", + vrfim_2 = "100002caV-V", + vcmpgtsb_3 = "10000306VVV", + vcfux_3 = "1000030aVVA~", + vaddshs_3 = "10000340VVV", + vminsh_3 = "10000342VVV", + vsrah_3 = "10000344VVV", + vcmpgtsh_3 = "10000346VVV", + vmulesh_3 = "10000348VVV", + vcfsx_3 = "1000034aVVA~", + vspltish_2 = "1000034cVS", + vupkhpx_2 = "1000034eV-V", + vaddsws_3 = "10000380VVV", + vminsw_3 = "10000382VVV", + vsraw_3 = "10000384VVV", + vcmpgtsw_3 = "10000386VVV", + vmulesw_3 = "10000388VVV", + vctuxs_3 = "1000038aVVA~", + vspltisw_2 = "1000038cVS", + vminsd_3 = "100003c2VVV", + vsrad_3 = "100003c4VVV", + vcmpbfp_3 = "100003c6VVV", + vcmpgtsd_3 = "100003c7VVV", + vctsxs_3 = "100003caVVA~", + vupklpx_2 = "100003ceV-V", + vsububm_3 = "10000400VVV", + ["bcdadd._4"] = "10000401VVVy.", + vavgub_3 = "10000402VVV", + vand_3 = "10000404VVV", + ["vcmpequb._3"] = "10000406VVV", + vmaxfp_3 = "1000040aVVV", + vsubuhm_3 = "10000440VVV", + ["bcdsub._4"] = "10000441VVVy.", + vavguh_3 = "10000442VVV", + vandc_3 = "10000444VVV", + ["vcmpequh._3"] = "10000446VVV", + vminfp_3 = "1000044aVVV", + vpkudum_3 = "1000044eVVV", + vsubuwm_3 = "10000480VVV", + vavguw_3 = "10000482VVV", + vor_3 = "10000484VVV", + ["vcmpequw._3"] = "10000486VVV", + vpmsumw_3 = "10000488VVV", + ["vcmpeqfp._3"] = "100004c6VVV", + ["vcmpequd._3"] = "100004c7VVV", + vpkudus_3 = "100004ceVVV", + vavgsb_3 = "10000502VVV", + vavgsh_3 = "10000542VVV", + vorc_3 = "10000544VVV", + vbpermq_3 = "1000054cVVV", + vpksdus_3 = "1000054eVVV", + vavgsw_3 = "10000582VVV", + vsld_3 = "100005c4VVV", + ["vcmpgefp._3"] = "100005c6VVV", + vpksdss_3 = "100005ceVVV", + vsububs_3 = "10000600VVV", + mfvscr_1 = "10000604V--", + vsum4ubs_3 = "10000608VVV", + vsubuhs_3 = "10000640VVV", + mtvscr_1 = "10000644--V", + ["vcmpgtuh._3"] = "10000646VVV", + vsum4shs_3 = "10000648VVV", + vupkhsw_2 = "1000064eV-V", + vsubuws_3 = "10000680VVV", + vshasigmaw_4 = "10000682VVYp", + veqv_3 = "10000684VVV", + vsum2sws_3 = "10000688VVV", + vmrgow_3 = "1000068cVVV", + vshasigmad_4 = "100006c2VVYp", + vsrd_3 = "100006c4VVV", + ["vcmpgtud._3"] = "100006c7VVV", + vupklsw_2 = "100006ceV-V", + vupkslw_2 = "100006ceV-V", + vsubsbs_3 = "10000700VVV", + vclzb_2 = "10000702V-V", + vpopcntb_2 = "10000703V-V", + ["vcmpgtsb._3"] = "10000706VVV", + vsum4sbs_3 = "10000708VVV", + vsubshs_3 = "10000740VVV", + vclzh_2 = "10000742V-V", + vpopcnth_2 = "10000743V-V", + ["vcmpgtsh._3"] = "10000746VVV", + vsubsws_3 = "10000780VVV", + vclzw_2 = "10000782V-V", + vpopcntw_2 = "10000783V-V", + ["vcmpgtsw._3"] = "10000786VVV", + vsumsws_3 = "10000788VVV", + vmrgew_3 = "1000078cVVV", + vclzd_2 = "100007c2V-V", + vpopcntd_2 = "100007c3V-V", + ["vcmpbfp._3"] = "100007c6VVV", + ["vcmpgtsd._3"] = "100007c7VVV", + -- Primary opcode 19: mcrf_2 = "4c000000XX", isync_0 = "4c00012c", @@ -318,6 +572,8 @@ local map_op = { bclrl_2 = "4c000021AA", bcctr_2 = "4c000420AA", bcctrl_2 = "4c000421AA", + bctar_2 = "4c000460AA", + bctarl_2 = "4c000461AA", blr_0 = "4e800020", blrl_0 = "4e800021", bctr_0 = "4e800420", @@ -329,6 +585,7 @@ local map_op = { cmpd_3 = "7c200000XRR", cmpd_2 = "7c200000-RR", tw_3 = "7c000008ARR", + lvsl_3 = "7c00000cVRR", subfc_3 = "7c000010RRR.", subc_3 = "7c000010RRR~.", mulhdu_3 = "7c000012RRR.", @@ -339,7 +596,9 @@ local map_op = { iselgt_3 = "7c00005eRRR", iseleq_3 = "7c00009eRRR", mfcr_1 = "7c000026R", - -- NYI: mtcrf, mtocrf, mfocrf + mfocrf_2 = "7c100026RG", + mtcrf_2 = "7c000120GR", + mtocrf_2 = "7c100120GR", lwarx_3 = "7c000028RR0R", ldx_3 = "7c00002aRR0R", lwzx_3 = "7c00002eRR0R", @@ -351,50 +610,68 @@ local map_op = { cmplw_2 = "7c000040-RR", cmpld_3 = "7c200040XRR", cmpld_2 = "7c200040-RR", + lvsr_3 = "7c00004cVRR", subf_3 = "7c000050RRR.", sub_3 = "7c000050RRR~.", + lbarx_3 = "7c000068RR0R", ldux_3 = "7c00006aRR0R", dcbst_2 = "7c00006c-RR", lwzux_3 = "7c00006eRR0R", cntlzd_2 = "7c000074RR~", andc_3 = "7c000078RR~R.", td_3 = "7c000088ARR", + lvewx_3 = "7c00008eVRR", mulhd_3 = "7c000092RRR.", + addg6s_3 = "7c000094RRR", mulhw_3 = "7c000096RRR.", + dlmzb_3 = "7c00009cRR~R.", ldarx_3 = "7c0000a8RR0R", dcbf_2 = "7c0000ac-RR", lbzx_3 = "7c0000aeRR0R", + lvx_3 = "7c0000ceVRR", neg_2 = "7c0000d0RR.", + lharx_3 = "7c0000e8RR0R", lbzux_3 = "7c0000eeRR0R", popcntb_2 = "7c0000f4RR~", not_2 = "7c0000f8RR~%.", nor_3 = "7c0000f8RR~R.", + stvebx_3 = "7c00010eVRR", subfe_3 = "7c000110RRR.", sube_3 = "7c000110RRR~.", adde_3 = "7c000114RRR.", stdx_3 = "7c00012aRR0R", - stwcx_3 = "7c00012cRR0R.", + ["stwcx._3"] = "7c00012dRR0R.", stwx_3 = "7c00012eRR0R", prtyw_2 = "7c000134RR~", + stvehx_3 = "7c00014eVRR", stdux_3 = "7c00016aRR0R", + ["stqcx._3"] = "7c00016dR:R0R.", stwux_3 = "7c00016eRR0R", prtyd_2 = "7c000174RR~", + stvewx_3 = "7c00018eVRR", subfze_2 = "7c000190RR.", addze_2 = "7c000194RR.", - stdcx_3 = "7c0001acRR0R.", + ["stdcx._3"] = "7c0001adRR0R.", stbx_3 = "7c0001aeRR0R", + stvx_3 = "7c0001ceVRR", subfme_2 = "7c0001d0RR.", mulld_3 = "7c0001d2RRR.", addme_2 = "7c0001d4RR.", mullw_3 = "7c0001d6RRR.", dcbtst_2 = "7c0001ec-RR", stbux_3 = "7c0001eeRR0R", + bpermd_3 = "7c0001f8RR~R", + lvepxl_3 = "7c00020eVRR", add_3 = "7c000214RRR.", + lqarx_3 = "7c000228R:R0R", dcbt_2 = "7c00022c-RR", lhzx_3 = "7c00022eRR0R", + cdtbcd_2 = "7c000234RR~", eqv_3 = "7c000238RR~R.", + lvepx_3 = "7c00024eVRR", eciwx_3 = "7c00026cRR0R", lhzux_3 = "7c00026eRR0R", + cbcdtd_2 = "7c000274RR~", xor_3 = "7c000278RR~R.", mfspefscr_1 = "7c0082a6R", mfxer_1 = "7c0102a6R", @@ -404,8 +681,12 @@ local map_op = { lhax_3 = "7c0002aeRR0R", mftb_1 = "7c0c42e6R", mftbu_1 = "7c0d42e6R", + lvxl_3 = "7c0002ceVRR", lwaux_3 = "7c0002eaRR0R", lhaux_3 = "7c0002eeRR0R", + popcntw_2 = "7c0002f4RR~", + divdeu_3 = "7c000312RRR.", + divweu_3 = "7c000316RRR.", sthx_3 = "7c00032eRR0R", orc_3 = "7c000338RR~R.", ecowx_3 = "7c00036cRR0R", @@ -420,10 +701,14 @@ local map_op = { mtctr_1 = "7c0903a6R", dcbi_2 = "7c0003ac-RR", nand_3 = "7c0003b8RR~R.", + dsn_2 = "7c0003c6-RR", + stvxl_3 = "7c0003ceVRR", divd_3 = "7c0003d2RRR.", divw_3 = "7c0003d6RRR.", + popcntd_2 = "7c0003f4RR~", cmpb_3 = "7c0003f8RR~R.", mcrxr_1 = "7c000400X", + lbdx_3 = "7c000406RRR", subfco_3 = "7c000410RRR.", subco_3 = "7c000410RRR~.", addco_3 = "7c000414RRR.", @@ -433,16 +718,20 @@ local map_op = { lfsx_3 = "7c00042eFR0R", srw_3 = "7c000430RR~R.", srd_3 = "7c000436RR~R.", + lhdx_3 = "7c000446RRR", subfo_3 = "7c000450RRR.", subo_3 = "7c000450RRR~.", lfsux_3 = "7c00046eFR0R", + lwdx_3 = "7c000486RRR", lswi_3 = "7c0004aaRR0A", sync_0 = "7c0004ac", lwsync_0 = "7c2004ac", ptesync_0 = "7c4004ac", lfdx_3 = "7c0004aeFR0R", + lddx_3 = "7c0004c6RRR", nego_2 = "7c0004d0RR.", lfdux_3 = "7c0004eeFR0R", + stbdx_3 = "7c000506RRR", subfeo_3 = "7c000510RRR.", subeo_3 = "7c000510RRR~.", addeo_3 = "7c000514RRR.", @@ -450,26 +739,42 @@ local map_op = { stswx_3 = "7c00052aRR0R", stwbrx_3 = "7c00052cRR0R", stfsx_3 = "7c00052eFR0R", + sthdx_3 = "7c000546RRR", + ["stbcx._3"] = "7c00056dRRR", stfsux_3 = "7c00056eFR0R", + stwdx_3 = "7c000586RRR", subfzeo_2 = "7c000590RR.", addzeo_2 = "7c000594RR.", stswi_3 = "7c0005aaRR0A", + ["sthcx._3"] = "7c0005adRRR", stfdx_3 = "7c0005aeFR0R", + stddx_3 = "7c0005c6RRR", subfmeo_2 = "7c0005d0RR.", mulldo_3 = "7c0005d2RRR.", addmeo_2 = "7c0005d4RR.", mullwo_3 = "7c0005d6RRR.", dcba_2 = "7c0005ec-RR", stfdux_3 = "7c0005eeFR0R", + stvepxl_3 = "7c00060eVRR", addo_3 = "7c000614RRR.", lhbrx_3 = "7c00062cRR0R", + lfdpx_3 = "7c00062eF:RR", sraw_3 = "7c000630RR~R.", srad_3 = "7c000634RR~R.", + lfddx_3 = "7c000646FRR", + stvepx_3 = "7c00064eVRR", srawi_3 = "7c000670RR~A.", + sradi_3 = "7c000674RR~H.", eieio_0 = "7c0006ac", lfiwax_3 = "7c0006aeFR0R", + divdeuo_3 = "7c000712RRR.", + divweuo_3 = "7c000716RRR.", sthbrx_3 = "7c00072cRR0R", + stfdpx_3 = "7c00072eF:RR", extsh_2 = "7c000734RR~.", + stfddx_3 = "7c000746FRR", + divdeo_3 = "7c000752RRR.", + divweo_3 = "7c000756RRR.", extsb_2 = "7c000774RR~.", divduo_3 = "7c000792RRR.", divwou_3 = "7c000796RRR.", @@ -480,6 +785,76 @@ local map_op = { divwo_3 = "7c0007d6RRR.", dcbz_2 = "7c0007ec-RR", + ["tbegin._1"] = "7c00051d1", + ["tbegin._0"] = "7c00051d", + ["tend._1"] = "7c00055dY", + ["tend._0"] = "7c00055d", + ["tendall._0"] = "7e00055d", + tcheck_1 = "7c00059cX", + ["tsr._1"] = "7c0005dd1", + ["tsuspend._0"] = "7c0005dd", + ["tresume._0"] = "7c2005dd", + ["tabortwc._3"] = "7c00061dARR", + ["tabortdc._3"] = "7c00065dARR", + ["tabortwci._3"] = "7c00069dARS", + ["tabortdci._3"] = "7c0006ddARS", + ["tabort._1"] = "7c00071d-R-", + ["treclaim._1"] = "7c00075d-R", + ["trechkpt._0"] = "7c0007dd", + + lxsiwzx_3 = "7c000018QRR", + lxsiwax_3 = "7c000098QRR", + mfvsrd_2 = "7c000066-Rq", + mfvsrwz_2 = "7c0000e6-Rq", + stxsiwx_3 = "7c000118QRR", + mtvsrd_2 = "7c000166QR", + mtvsrwa_2 = "7c0001a6QR", + lxvdsx_3 = "7c000298QRR", + lxsspx_3 = "7c000418QRR", + lxsdx_3 = "7c000498QRR", + stxsspx_3 = "7c000518QRR", + stxsdx_3 = "7c000598QRR", + lxvw4x_3 = "7c000618QRR", + lxvd2x_3 = "7c000698QRR", + stxvw4x_3 = "7c000718QRR", + stxvd2x_3 = "7c000798QRR", + + -- Primary opcode 30: + rldicl_4 = "78000000RR~HM.", + rldicr_4 = "78000004RR~HM.", + rldic_4 = "78000008RR~HM.", + rldimi_4 = "7800000cRR~HM.", + rldcl_4 = "78000010RR~RM.", + rldcr_4 = "78000012RR~RM.", + + rotldi_3 = op_alias("rldicl_4", function(p) + p[4] = "0" + end), + rotrdi_3 = op_alias("rldicl_4", function(p) + p[3] = "64-("..p[3]..")"; p[4] = "0" + end), + rotld_3 = op_alias("rldcl_4", function(p) + p[4] = "0" + end), + sldi_3 = op_alias("rldicr_4", function(p) + p[4] = "63-("..p[3]..")" + end), + srdi_3 = op_alias("rldicl_4", function(p) + p[4] = p[3]; p[3] = "64-("..p[3]..")" + end), + clrldi_3 = op_alias("rldicl_4", function(p) + p[4] = p[3]; p[3] = "0" + end), + clrrdi_3 = op_alias("rldicr_4", function(p) + p[4] = "63-("..p[3]..")"; p[3] = "0" + end), + + -- Primary opcode 56: + lq_2 = "e0000000R:D", -- NYI: displacement must be divisible by 8. + + -- Primary opcode 57: + lfdp_2 = "e4000000F:D", -- NYI: displacement must be divisible by 4. + -- Primary opcode 59: fdivs_3 = "ec000024FFF.", fsubs_3 = "ec000028FFF.", @@ -492,6 +867,200 @@ local map_op = { fmadds_4 = "ec00003aFFFF~.", fnmsubs_4 = "ec00003cFFFF~.", fnmadds_4 = "ec00003eFFFF~.", + fcfids_2 = "ec00069cF-F.", + fcfidus_2 = "ec00079cF-F.", + + dadd_3 = "ec000004FFF.", + dqua_4 = "ec000006FFFZ.", + dmul_3 = "ec000044FFF.", + drrnd_4 = "ec000046FFFZ.", + dscli_3 = "ec000084FF6.", + dquai_4 = "ec000086SF~FZ.", + dscri_3 = "ec0000c4FF6.", + drintx_4 = "ec0000c61F~FZ.", + dcmpo_3 = "ec000104XFF", + dtstex_3 = "ec000144XFF", + dtstdc_3 = "ec000184XF6", + dtstdg_3 = "ec0001c4XF6", + drintn_4 = "ec0001c61F~FZ.", + dctdp_2 = "ec000204F-F.", + dctfix_2 = "ec000244F-F.", + ddedpd_3 = "ec000284ZF~F.", + dxex_2 = "ec0002c4F-F.", + dsub_3 = "ec000404FFF.", + ddiv_3 = "ec000444FFF.", + dcmpu_3 = "ec000504XFF", + dtstsf_3 = "ec000544XFF", + drsp_2 = "ec000604F-F.", + dcffix_2 = "ec000644F-F.", + denbcd_3 = "ec000684YF~F.", + diex_3 = "ec0006c4FFF.", + + -- Primary opcode 60: + xsaddsp_3 = "f0000000QQQ", + xsmaddasp_3 = "f0000008QQQ", + xxsldwi_4 = "f0000010QQQz", + xsrsqrtesp_2 = "f0000028Q-Q", + xssqrtsp_2 = "f000002cQ-Q", + xxsel_4 = "f0000030QQQQ", + xssubsp_3 = "f0000040QQQ", + xsmaddmsp_3 = "f0000048QQQ", + xxpermdi_4 = "f0000050QQQz", + xsresp_2 = "f0000068Q-Q", + xsmulsp_3 = "f0000080QQQ", + xsmsubasp_3 = "f0000088QQQ", + xxmrghw_3 = "f0000090QQQ", + xsdivsp_3 = "f00000c0QQQ", + xsmsubmsp_3 = "f00000c8QQQ", + xsadddp_3 = "f0000100QQQ", + xsmaddadp_3 = "f0000108QQQ", + xscmpudp_3 = "f0000118XQQ", + xscvdpuxws_2 = "f0000120Q-Q", + xsrdpi_2 = "f0000124Q-Q", + xsrsqrtedp_2 = "f0000128Q-Q", + xssqrtdp_2 = "f000012cQ-Q", + xssubdp_3 = "f0000140QQQ", + xsmaddmdp_3 = "f0000148QQQ", + xscmpodp_3 = "f0000158XQQ", + xscvdpsxws_2 = "f0000160Q-Q", + xsrdpiz_2 = "f0000164Q-Q", + xsredp_2 = "f0000168Q-Q", + xsmuldp_3 = "f0000180QQQ", + xsmsubadp_3 = "f0000188QQQ", + xxmrglw_3 = "f0000190QQQ", + xsrdpip_2 = "f00001a4Q-Q", + xstsqrtdp_2 = "f00001a8X-Q", + xsrdpic_2 = "f00001acQ-Q", + xsdivdp_3 = "f00001c0QQQ", + xsmsubmdp_3 = "f00001c8QQQ", + xsrdpim_2 = "f00001e4Q-Q", + xstdivdp_3 = "f00001e8XQQ", + xvaddsp_3 = "f0000200QQQ", + xvmaddasp_3 = "f0000208QQQ", + xvcmpeqsp_3 = "f0000218QQQ", + xvcvspuxws_2 = "f0000220Q-Q", + xvrspi_2 = "f0000224Q-Q", + xvrsqrtesp_2 = "f0000228Q-Q", + xvsqrtsp_2 = "f000022cQ-Q", + xvsubsp_3 = "f0000240QQQ", + xvmaddmsp_3 = "f0000248QQQ", + xvcmpgtsp_3 = "f0000258QQQ", + xvcvspsxws_2 = "f0000260Q-Q", + xvrspiz_2 = "f0000264Q-Q", + xvresp_2 = "f0000268Q-Q", + xvmulsp_3 = "f0000280QQQ", + xvmsubasp_3 = "f0000288QQQ", + xxspltw_3 = "f0000290QQg~", + xvcmpgesp_3 = "f0000298QQQ", + xvcvuxwsp_2 = "f00002a0Q-Q", + xvrspip_2 = "f00002a4Q-Q", + xvtsqrtsp_2 = "f00002a8X-Q", + xvrspic_2 = "f00002acQ-Q", + xvdivsp_3 = "f00002c0QQQ", + xvmsubmsp_3 = "f00002c8QQQ", + xvcvsxwsp_2 = "f00002e0Q-Q", + xvrspim_2 = "f00002e4Q-Q", + xvtdivsp_3 = "f00002e8XQQ", + xvadddp_3 = "f0000300QQQ", + xvmaddadp_3 = "f0000308QQQ", + xvcmpeqdp_3 = "f0000318QQQ", + xvcvdpuxws_2 = "f0000320Q-Q", + xvrdpi_2 = "f0000324Q-Q", + xvrsqrtedp_2 = "f0000328Q-Q", + xvsqrtdp_2 = "f000032cQ-Q", + xvsubdp_3 = "f0000340QQQ", + xvmaddmdp_3 = "f0000348QQQ", + xvcmpgtdp_3 = "f0000358QQQ", + xvcvdpsxws_2 = "f0000360Q-Q", + xvrdpiz_2 = "f0000364Q-Q", + xvredp_2 = "f0000368Q-Q", + xvmuldp_3 = "f0000380QQQ", + xvmsubadp_3 = "f0000388QQQ", + xvcmpgedp_3 = "f0000398QQQ", + xvcvuxwdp_2 = "f00003a0Q-Q", + xvrdpip_2 = "f00003a4Q-Q", + xvtsqrtdp_2 = "f00003a8X-Q", + xvrdpic_2 = "f00003acQ-Q", + xvdivdp_3 = "f00003c0QQQ", + xvmsubmdp_3 = "f00003c8QQQ", + xvcvsxwdp_2 = "f00003e0Q-Q", + xvrdpim_2 = "f00003e4Q-Q", + xvtdivdp_3 = "f00003e8XQQ", + xsnmaddasp_3 = "f0000408QQQ", + xxland_3 = "f0000410QQQ", + xscvdpsp_2 = "f0000424Q-Q", + xscvdpspn_2 = "f000042cQ-Q", + xsnmaddmsp_3 = "f0000448QQQ", + xxlandc_3 = "f0000450QQQ", + xsrsp_2 = "f0000464Q-Q", + xsnmsubasp_3 = "f0000488QQQ", + xxlor_3 = "f0000490QQQ", + xscvuxdsp_2 = "f00004a0Q-Q", + xsnmsubmsp_3 = "f00004c8QQQ", + xxlxor_3 = "f00004d0QQQ", + xscvsxdsp_2 = "f00004e0Q-Q", + xsmaxdp_3 = "f0000500QQQ", + xsnmaddadp_3 = "f0000508QQQ", + xxlnor_3 = "f0000510QQQ", + xscvdpuxds_2 = "f0000520Q-Q", + xscvspdp_2 = "f0000524Q-Q", + xscvspdpn_2 = "f000052cQ-Q", + xsmindp_3 = "f0000540QQQ", + xsnmaddmdp_3 = "f0000548QQQ", + xxlorc_3 = "f0000550QQQ", + xscvdpsxds_2 = "f0000560Q-Q", + xsabsdp_2 = "f0000564Q-Q", + xscpsgndp_3 = "f0000580QQQ", + xsnmsubadp_3 = "f0000588QQQ", + xxlnand_3 = "f0000590QQQ", + xscvuxddp_2 = "f00005a0Q-Q", + xsnabsdp_2 = "f00005a4Q-Q", + xsnmsubmdp_3 = "f00005c8QQQ", + xxleqv_3 = "f00005d0QQQ", + xscvsxddp_2 = "f00005e0Q-Q", + xsnegdp_2 = "f00005e4Q-Q", + xvmaxsp_3 = "f0000600QQQ", + xvnmaddasp_3 = "f0000608QQQ", + ["xvcmpeqsp._3"] = "f0000618QQQ", + xvcvspuxds_2 = "f0000620Q-Q", + xvcvdpsp_2 = "f0000624Q-Q", + xvminsp_3 = "f0000640QQQ", + xvnmaddmsp_3 = "f0000648QQQ", + ["xvcmpgtsp._3"] = "f0000658QQQ", + xvcvspsxds_2 = "f0000660Q-Q", + xvabssp_2 = "f0000664Q-Q", + xvcpsgnsp_3 = "f0000680QQQ", + xvnmsubasp_3 = "f0000688QQQ", + ["xvcmpgesp._3"] = "f0000698QQQ", + xvcvuxdsp_2 = "f00006a0Q-Q", + xvnabssp_2 = "f00006a4Q-Q", + xvnmsubmsp_3 = "f00006c8QQQ", + xvcvsxdsp_2 = "f00006e0Q-Q", + xvnegsp_2 = "f00006e4Q-Q", + xvmaxdp_3 = "f0000700QQQ", + xvnmaddadp_3 = "f0000708QQQ", + ["xvcmpeqdp._3"] = "f0000718QQQ", + xvcvdpuxds_2 = "f0000720Q-Q", + xvcvspdp_2 = "f0000724Q-Q", + xvmindp_3 = "f0000740QQQ", + xvnmaddmdp_3 = "f0000748QQQ", + ["xvcmpgtdp._3"] = "f0000758QQQ", + xvcvdpsxds_2 = "f0000760Q-Q", + xvabsdp_2 = "f0000764Q-Q", + xvcpsgndp_3 = "f0000780QQQ", + xvnmsubadp_3 = "f0000788QQQ", + ["xvcmpgedp._3"] = "f0000798QQQ", + xvcvuxddp_2 = "f00007a0Q-Q", + xvnabsdp_2 = "f00007a4Q-Q", + xvnmsubmdp_3 = "f00007c8QQQ", + xvcvsxddp_2 = "f00007e0Q-Q", + xvnegdp_2 = "f00007e4Q-Q", + + -- Primary opcode 61: + stfdp_2 = "f4000000F:D", -- NYI: displacement must be divisible by 4. + + -- Primary opcode 62: + stq_2 = "f8000002R:D", -- NYI: displacement must be divisible by 8. -- Primary opcode 63: fdiv_3 = "fc000024FFF.", @@ -517,18 +1086,53 @@ local map_op = { frsp_2 = "fc000018F-F.", fctiw_2 = "fc00001cF-F.", fctiwz_2 = "fc00001eF-F.", + ftdiv_2 = "fc000100X-F.", + fctiwu_2 = "fc00011cF-F.", + fctiwuz_2 = "fc00011eF-F.", mtfsfi_2 = "fc00010cAA", -- NYI: upshift. fnabs_2 = "fc000110F-F.", + ftsqrt_2 = "fc000140X-F.", fabs_2 = "fc000210F-F.", frin_2 = "fc000310F-F.", friz_2 = "fc000350F-F.", frip_2 = "fc000390F-F.", frim_2 = "fc0003d0F-F.", mffs_1 = "fc00048eF.", - mtfsf_1 = "fc00058eF.", + -- NYI: mtfsf, mtfsb0, mtfsb1. fctid_2 = "fc00065cF-F.", fctidz_2 = "fc00065eF-F.", + fmrgow_3 = "fc00068cFFF", fcfid_2 = "fc00069cF-F.", + fctidu_2 = "fc00075cF-F.", + fctiduz_2 = "fc00075eF-F.", + fmrgew_3 = "fc00078cFFF", + fcfidu_2 = "fc00079cF-F.", + + daddq_3 = "fc000004F:F:F:.", + dquaq_4 = "fc000006F:F:F:Z.", + dmulq_3 = "fc000044F:F:F:.", + drrndq_4 = "fc000046F:F:F:Z.", + dscliq_3 = "fc000084F:F:6.", + dquaiq_4 = "fc000086SF:~F:Z.", + dscriq_3 = "fc0000c4F:F:6.", + drintxq_4 = "fc0000c61F:~F:Z.", + dcmpoq_3 = "fc000104XF:F:", + dtstexq_3 = "fc000144XF:F:", + dtstdcq_3 = "fc000184XF:6", + dtstdgq_3 = "fc0001c4XF:6", + drintnq_4 = "fc0001c61F:~F:Z.", + dctqpq_2 = "fc000204F:-F:.", + dctfixq_2 = "fc000244F:-F:.", + ddedpdq_3 = "fc000284ZF:~F:.", + dxexq_2 = "fc0002c4F:-F:.", + dsubq_3 = "fc000404F:F:F:.", + ddivq_3 = "fc000444F:F:F:.", + dcmpuq_3 = "fc000504XF:F:", + dtstsfq_3 = "fc000544XF:F:", + drdpq_2 = "fc000604F:-F:.", + dcffixq_2 = "fc000644F:-F:.", + denbcdq_3 = "fc000684YF:~F:.", + diexq_3 = "fc0006c4F:FF:.", -- Primary opcode 4, SPE APU extension: evaddw_3 = "10000200RRR", @@ -806,16 +1410,14 @@ local map_op = { evmwlumianw_3 = "100005c8RRR", evmwlsmianw_3 = "100005c9RRR", - -- NYI: some 64 bit PowerPC and Book E instructions: - -- rldicl, rldicr, rldic, rldimi, rldcl, rldcr, sradi, 64 bit ext. add/sub, - -- extended addressing branches, cache management, loads and stores + -- NYI: Book E instructions. } -- Add mnemonics for "." variants. do local t = {} for k,v in pairs(map_op) do - if sub(v, -1) == "." then + if type(v) == "string" and sub(v, -1) == "." then local v2 = sub(v, 1, 7)..char(byte(v, 8)+1)..sub(v, 9, -2) t[sub(k, 1, -3).."."..sub(k, -2)] = v2 end @@ -828,11 +1430,13 @@ end -- Add more branch mnemonics. for cond,c in pairs(map_cond) do local b1 = "b"..cond - local c1 = (c%4)*0x00010000 + (c < 4 and 0x01000000 or 0) + local c1 = shl(band(c, 3), 16) + (c < 4 and 0x01000000 or 0) -- bX[l] map_op[b1.."_1"] = tohex(0x40800000 + c1).."K" + map_op[b1.."y_1"] = tohex(0x40a00000 + c1).."K" map_op[b1.."l_1"] = tohex(0x40800001 + c1).."K" map_op[b1.."_2"] = tohex(0x40800000 + c1).."-XK" + map_op[b1.."y_2"] = tohex(0x40a00000 + c1).."-XK" map_op[b1.."l_2"] = tohex(0x40800001 + c1).."-XK" -- bXlr[l] map_op[b1.."lr_0"] = tohex(0x4c800020 + c1) @@ -875,6 +1479,24 @@ local function parse_fpr(expr) werror("bad register name `"..expr.."'") end +local function parse_vr(expr) + local r = match(expr, "^v([1-3]?[0-9])$") + if r then + r = tonumber(r) + if r <= 31 then return r end + end + werror("bad register name `"..expr.."'") +end + +local function parse_vs(expr) + local r = match(expr, "^vs([1-6]?[0-9])$") + if r then + r = tonumber(r) + if r <= 63 then return r end + end + werror("bad register name `"..expr.."'") +end + local function parse_cr(expr) local r = match(expr, "^cr([0-7])$") if r then return tonumber(r) end @@ -891,23 +1513,44 @@ local function parse_cond(expr) werror("bad condition bit name `"..expr.."'") end +local parse_ctx = {} + +local loadenv = setfenv and function(s) + local code = loadstring(s, "") + if code then setfenv(code, parse_ctx) end + return code +end or function(s) + return load(s, "", nil, parse_ctx) +end + +-- Try to parse simple arithmetic, too, since some basic ops are aliases. +local function parse_number(n) + local x = tonumber(n) + if x then return x end + local code = loadenv("return "..n) + if code then + local ok, y = pcall(code) + if ok then return y end + end + return nil +end + local function parse_imm(imm, bits, shift, scale, signed) - local n = tonumber(imm) + local n = parse_number(imm) if n then - if n % 2^scale == 0 then - n = n / 2^scale + local m = sar(n, scale) + if shl(m, scale) == n then if signed then - if n >= 0 then - if n < 2^(bits-1) then return n*2^shift end - else - if n >= -(2^(bits-1))-1 then return (n+2^bits)*2^shift end - end + local s = sar(m, bits-1) + if s == 0 then return shl(m, shift) + elseif s == -1 then return shl(m + shl(1, bits), shift) end else - if n >= 0 and n <= 2^bits-1 then return n*2^shift end + if sar(m, bits) == 0 then return shl(m, shift) end end end werror("out of range immediate `"..imm.."'") - elseif match(imm, "^r([1-3]?[0-9])$") or + elseif match(imm, "^[rfv]([1-3]?[0-9])$") or + match(imm, "^vs([1-6]?[0-9])$") or match(imm, "^([%w_]+):(r[1-3]?[0-9])$") then werror("expected immediate operand, got register") else @@ -916,12 +1559,30 @@ local function parse_imm(imm, bits, shift, scale, signed) end end +local function parse_shiftmask(imm, isshift) + local n = parse_number(imm) + if n then + if shr(n, 6) == 0 then + local lsb = band(n, 31) + local msb = n - lsb + return isshift and (shl(lsb, 11)+shr(msb, 4)) or (shl(lsb, 6)+msb) + end + werror("out of range immediate `"..imm.."'") + elseif match(imm, "^r([1-3]?[0-9])$") or + match(imm, "^([%w_]+):(r[1-3]?[0-9])$") then + werror("expected immediate operand, got register") + else + waction("IMMSH", isshift and 1 or 0, imm) + return 0; + end +end + local function parse_disp(disp) local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") if imm then local r = parse_gpr(reg) if r == 0 then werror("cannot use r0 in displacement") end - return r*65536 + parse_imm(imm, 16, 0, 0, true) + return shl(r, 16) + parse_imm(imm, 16, 0, 0, true) end local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") if reg and tailr ~= "" then @@ -929,7 +1590,7 @@ local function parse_disp(disp) if r == 0 then werror("cannot use r0 in displacement") end if tp then waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr)) - return r*65536 + return shl(r, 16) end end werror("bad displacement `"..disp.."'") @@ -940,7 +1601,7 @@ local function parse_u5disp(disp, scale) if imm then local r = parse_gpr(reg) if r == 0 then werror("cannot use r0 in displacement") end - return r*65536 + parse_imm(imm, 5, 11, scale, false) + return shl(r, 16) + parse_imm(imm, 5, 11, scale, false) end local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") if reg and tailr ~= "" then @@ -948,7 +1609,7 @@ local function parse_u5disp(disp, scale) if r == 0 then werror("cannot use r0 in displacement") end if tp then waction("IMM", scale*1024+5*32+11, format(tp.ctypefmt, tailr)) - return r*65536 + return shl(r, 16) end end werror("bad displacement `"..disp.."'") @@ -987,7 +1648,7 @@ end ------------------------------------------------------------------------------ -- Handle opcodes defined with template strings. -map_op[".template__"] = function(params, template, nparams) +op_template = function(params, template, nparams) if not params then return sub(template, 9) end local op = tonumber(sub(template, 1, 8), 16) local n, rs = 1, 26 @@ -1000,9 +1661,18 @@ map_op[".template__"] = function(params, template, nparams) -- Process each character. for p in gmatch(sub(template, 9), ".") do if p == "R" then - rs = rs - 5; op = op + parse_gpr(params[n]) * 2^rs; n = n + 1 + rs = rs - 5; op = op + shl(parse_gpr(params[n]), rs); n = n + 1 elseif p == "F" then - rs = rs - 5; op = op + parse_fpr(params[n]) * 2^rs; n = n + 1 + rs = rs - 5; op = op + shl(parse_fpr(params[n]), rs); n = n + 1 + elseif p == "V" then + rs = rs - 5; op = op + shl(parse_vr(params[n]), rs); n = n + 1 + elseif p == "Q" then + local vs = parse_vs(params[n]); n = n + 1; rs = rs - 5 + local sh = rs == 6 and 2 or 3 + band(shr(rs, 1), 3) + op = op + shl(band(vs, 31), rs) + shr(band(vs, 32), sh) + elseif p == "q" then + local vs = parse_vs(params[n]); n = n + 1 + op = op + shl(band(vs, 31), 21) + shr(band(vs, 32), 5) elseif p == "A" then rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, false); n = n + 1 elseif p == "S" then @@ -1020,33 +1690,55 @@ map_op[".template__"] = function(params, template, nparams) elseif p == "8" then op = op + parse_u5disp(params[n], 3); n = n + 1 elseif p == "C" then - rs = rs - 5; op = op + parse_cond(params[n]) * 2^rs; n = n + 1 + rs = rs - 5; op = op + shl(parse_cond(params[n]), rs); n = n + 1 elseif p == "X" then - rs = rs - 5; op = op + parse_cr(params[n]) * 2^(rs+2); n = n + 1 + rs = rs - 5; op = op + shl(parse_cr(params[n]), rs+2); n = n + 1 + elseif p == "1" then + rs = rs - 5; op = op + parse_imm(params[n], 1, rs, 0, false); n = n + 1 + elseif p == "g" then + rs = rs - 5; op = op + parse_imm(params[n], 2, rs, 0, false); n = n + 1 + elseif p == "3" then + rs = rs - 5; op = op + parse_imm(params[n], 3, rs, 0, false); n = n + 1 + elseif p == "P" then + rs = rs - 5; op = op + parse_imm(params[n], 4, rs, 0, false); n = n + 1 + elseif p == "p" then + op = op + parse_imm(params[n], 4, rs, 0, false); n = n + 1 + elseif p == "6" then + rs = rs - 6; op = op + parse_imm(params[n], 6, rs, 0, false); n = n + 1 + elseif p == "Y" then + rs = rs - 5; op = op + parse_imm(params[n], 1, rs+4, 0, false); n = n + 1 + elseif p == "y" then + rs = rs - 5; op = op + parse_imm(params[n], 1, rs+3, 0, false); n = n + 1 + elseif p == "Z" then + rs = rs - 5; op = op + parse_imm(params[n], 2, rs+3, 0, false); n = n + 1 + elseif p == "z" then + rs = rs - 5; op = op + parse_imm(params[n], 2, rs+2, 0, false); n = n + 1 elseif p == "W" then op = op + parse_cr(params[n]); n = n + 1 + elseif p == "G" then + op = op + parse_imm(params[n], 8, 12, 0, false); n = n + 1 + elseif p == "H" then + op = op + parse_shiftmask(params[n], true); n = n + 1 + elseif p == "M" then + op = op + parse_shiftmask(params[n], false); n = n + 1 elseif p == "J" or p == "K" then local mode, n, s = parse_label(params[n], false) if p == "K" then n = n + 2048 end waction("REL_"..mode, n, s, 1) n = n + 1 elseif p == "0" then - local mm = 2^rs - local t = op % mm - if ((op - t) / mm) % 32 == 0 then werror("cannot use r0") end + if band(shr(op, rs), 31) == 0 then werror("cannot use r0") end elseif p == "=" or p == "%" then - local mm = 2^(rs + (p == "%" and 5 or 0)) - local t = ((op - op % mm) / mm) % 32 + local t = band(shr(op, p == "%" and rs+5 or rs), 31) rs = rs - 5 - op = op + t * 2^rs + op = op + shl(t, rs) elseif p == "~" then - local mm = 2^rs - local t1l = op % mm - local t1h = (op - t1l) / mm - local t2l = t1h % 32 - local t2h = (t1h - t2l) / 32 - local t3l = t2h % 32 - op = ((t2h - t3l + t2l)*32 + t3l)*mm + t1l + local mm = shl(31, rs) + local lo = band(op, mm) + local hi = band(op, shl(mm, 5)) + op = op - lo - hi + shl(lo, 5) + shr(hi, 5) + elseif p == ":" then + if band(shr(op, rs), 1) ~= 0 then werror("register pair expected") end elseif p == "-" then rs = rs - 5 elseif p == "." then @@ -1058,6 +1750,8 @@ map_op[".template__"] = function(params, template, nparams) wputpos(pos, op) end +map_op[".template__"] = op_template + ------------------------------------------------------------------------------ -- Pseudo-opcode to mark the position where the action list is to be emitted. diff --git a/texk/web2c/luatexdir/luaffi/dynasm/dasm_proto.h b/texk/web2c/luatexdir/luaffi/dynasm/dasm_proto.h index dc9ed51067..59d9e2b2dd 100644 --- a/texk/web2c/luatexdir/luaffi/dynasm/dasm_proto.h +++ b/texk/web2c/luatexdir/luaffi/dynasm/dasm_proto.h @@ -1,7 +1,7 @@ /* ** DynASM encoding engine prototypes. -** Copyright (C) 2005-2011 Mike Pall. All rights reserved. -** Released under the MIT/X license. See dynasm.lua for full copyright notice. +** Copyright (C) 2005-2017 Mike Pall. All rights reserved. +** Released under the MIT license. See dynasm.lua for full copyright notice. */ #ifndef _DASM_PROTO_H @@ -10,8 +10,8 @@ #include #include -#define DASM_IDENT "DynASM 1.3.0" -#define DASM_VERSION 10300 /* 1.3.0 */ +#define DASM_IDENT "DynASM 1.4.0" +#define DASM_VERSION 10400 /* 1.4.0 */ #ifndef Dst_DECL #define Dst_DECL dasm_State **Dst diff --git a/texk/web2c/luatexdir/luaffi/dynasm/dasm_x64.lua b/texk/web2c/luatexdir/luaffi/dynasm/dasm_x64.lua index 73e01e919a..e8bdeb37d4 100644 --- a/texk/web2c/luatexdir/luaffi/dynasm/dasm_x64.lua +++ b/texk/web2c/luatexdir/luaffi/dynasm/dasm_x64.lua @@ -1,7 +1,7 @@ ------------------------------------------------------------------------------ -- DynASM x64 module. -- --- Copyright (C) 2005-2011 Mike Pall. All rights reserved. +-- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------ -- This module just sets 64 bit mode for the combined x86/x64 module. diff --git a/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.h b/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.h index 23e213cb6e..dc14d8837e 100644 --- a/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.h +++ b/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.h @@ -1,7 +1,7 @@ /* ** DynASM x86 encoding engine. -** Copyright (C) 2005-2011 Mike Pall. All rights reserved. -** Released under the MIT/X license. See dynasm.lua for full copyright notice. +** Copyright (C) 2005-2017 Mike Pall. All rights reserved. +** Released under the MIT license. See dynasm.lua for full copyright notice. */ #include @@ -170,7 +170,7 @@ void dasm_put(Dst_DECL, int start, ...) dasm_State *D = Dst_REF; dasm_ActList p = D->actionlist + start; dasm_Section *sec = D->section; - int pos = sec->pos, ofs = sec->ofs, mrm = 4; + int pos = sec->pos, ofs = sec->ofs, mrm = -1; int *b; if (pos >= sec->epos) { @@ -193,27 +193,36 @@ void dasm_put(Dst_DECL, int start, ...) b[pos++] = n; switch (action) { case DASM_DISP: - if (n == 0) { if ((mrm&7) == 4) mrm = p[-2]; if ((mrm&7) != 5) break; } - case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob; + if (n == 0) { if (mrm < 0) mrm = p[-2]; if ((mrm&7) != 5) break; } + /* fallthrough */ + case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob; /* fallthrough */ case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */ case DASM_IMM_D: ofs += 4; break; case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob; case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break; - case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob; + case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob; /* fallthrough */ case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break; case DASM_SPACE: p++; ofs += n; break; case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */ - case DASM_VREG: CK((n&-8) == 0 && (n != 4 || (*p&1) == 0), RANGE_VREG); - if (*p++ == 1 && *p == DASM_DISP) mrm = n; continue; + case DASM_VREG: CK((n&-16) == 0 && (n != 4 || (*p>>5) != 2), RANGE_VREG); + if (*p < 0x40 && p[1] == DASM_DISP) mrm = n; + if (*p < 0x20 && (n&7) == 4) ofs++; + switch ((*p++ >> 3) & 3) { + case 3: n |= b[pos-3]; /* fallthrough */ + case 2: n |= b[pos-2]; /* fallthrough */ + case 1: if (n <= 7) { b[pos-1] |= 0x10; ofs--; } + } + continue; } - mrm = 4; + mrm = -1; } else { int *pl, n; switch (action) { case DASM_REL_LG: case DASM_IMM_LG: n = *p++; pl = D->lglabels + n; - if (n <= 246) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */ + /* Bkwd rel or global. */ + if (n <= 246) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } pl -= 246; n = *pl; if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ goto linkrel; @@ -321,11 +330,14 @@ int dasm_link(Dst_DECL, size_t *szp) pos += 2; break; } + /* fallthrough */ case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++; + /* fallthrough */ case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W: case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB: case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break; case DASM_LABEL_LG: p++; + /* fallthrough */ case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */ case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */ case DASM_EXTERN: p += 2; break; @@ -383,17 +395,42 @@ int dasm_encode(Dst_DECL, void *buffer) if (mrm != 5) { mm[-1] -= 0x80; break; } } if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40; } + /* fallthrough */ case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break; case DASM_IMM_DB: if (((n+128)&-256) == 0) { db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb; } else mark = NULL; + /* fallthrough */ case DASM_IMM_D: wd: dasmd(n); break; case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL; + /* fallthrough */ case DASM_IMM_W: dasmw(n); break; - case DASM_VREG: { int t = *p++; if (t >= 2) n<<=3; cp[-1] |= n; break; } + case DASM_VREG: { + int t = *p++; + unsigned char *ex = cp - (t&7); + if ((n & 8) && t < 0xa0) { + if (*ex & 0x80) ex[1] ^= 0x20 << (t>>6); else *ex ^= 1 << (t>>6); + n &= 7; + } else if (n & 0x10) { + if (*ex & 0x80) { + *ex = 0xc5; ex[1] = (ex[1] & 0x80) | ex[2]; ex += 2; + } + while (++ex < cp) ex[-1] = *ex; + if (mark) mark--; + cp--; + n &= 7; + } + if (t >= 0xc0) n <<= 4; + else if (t >= 0x40) n <<= 3; + else if (n == 4 && t < 0x20) { cp[-1] ^= n; *cp++ = 0x20; } + cp[-1] ^= n; + break; + } case DASM_REL_LG: p++; if (n >= 0) goto rel_pc; b++; n = (int)(ptrdiff_t)D->globals[-n]; - case DASM_REL_A: rel_a: n -= (int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */ + /* fallthrough */ + case DASM_REL_A: rel_a: + n -= (unsigned int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */ case DASM_REL_PC: rel_pc: { int shrink = *b++; int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; } @@ -404,6 +441,7 @@ int dasm_encode(Dst_DECL, void *buffer) } case DASM_IMM_LG: p++; if (n < 0) { n = (int)(ptrdiff_t)D->globals[-n]; goto wd; } + /* fallthrough */ case DASM_IMM_PC: { int *pb = DASM_POS2PTR(D, n); n = *pb < 0 ? pb[1] : (*pb + (int)(ptrdiff_t)base); @@ -424,6 +462,7 @@ int dasm_encode(Dst_DECL, void *buffer) case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd; case DASM_MARK: mark = cp; break; case DASM_ESC: action = *p++; + /* fallthrough */ default: *cp++ = action; break; case DASM_SECTION: case DASM_STOP: goto stop; } diff --git a/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.lua b/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.lua index f5c8c5208d..053e146e01 100644 --- a/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.lua +++ b/texk/web2c/luatexdir/luaffi/dynasm/dasm_x86.lua @@ -1,7 +1,7 @@ ------------------------------------------------------------------------------ -- DynASM x86/x64 module. -- --- Copyright (C) 2005-2011 Mike Pall. All rights reserved. +-- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------ @@ -11,9 +11,9 @@ local x64 = x64 local _info = { arch = x64 and "x64" or "x86", description = "DynASM x86/x64 module", - version = "1.3.0", - vernum = 10300, - release = "2011-05-05", + version = "1.4.0", + vernum = 10400, + release = "2015-10-18", author = "Mike Pall", license = "MIT", } @@ -27,7 +27,9 @@ local assert, unpack, setmetatable = assert, unpack or table.unpack, setmetatabl local _s = string local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char local find, match, gmatch, gsub = _s.find, _s.match, _s.gmatch, _s.gsub -local concat, sort = table.concat, table.sort +local concat, sort, remove = table.concat, table.sort, table.remove +local bit = bit or require("bit") +local band, bxor, shl, shr = bit.band, bit.bxor, bit.lshift, bit.rshift -- Inherited tables and callbacks. local g_opt, g_arch @@ -39,7 +41,7 @@ local action_names = { -- int arg, 1 buffer pos: "DISP", "IMM_S", "IMM_B", "IMM_W", "IMM_D", "IMM_WB", "IMM_DB", -- action arg (1 byte), int arg, 1 buffer pos (reg/num): - "VREG", "SPACE", -- !x64: VREG support NYI. + "VREG", "SPACE", -- ptrdiff_t arg, 1 buffer pos (address): !x64 "SETLABEL", "REL_A", -- action arg (1 byte) or int arg, 2 buffer pos (link, offset): @@ -81,6 +83,21 @@ local actargs = { 0 } -- Current number of section buffer positions for dasm_put(). local secpos = 1 +-- VREG kind encodings, pre-shifted by 5 bits. +local map_vreg = { + ["modrm.rm.m"] = 0x00, + ["modrm.rm.r"] = 0x20, + ["opcode"] = 0x20, + ["sib.base"] = 0x20, + ["sib.index"] = 0x40, + ["modrm.reg"] = 0x80, + ["vex.v"] = 0xa0, + ["imm.hi"] = 0xc0, +} + +-- Current number of VREG actions contributing to REX/VEX shrinkage. +local vreg_shrink_count = 0 + ------------------------------------------------------------------------------ -- Compute action numbers for action names. @@ -132,6 +149,21 @@ local function waction(action, a, num) if a or num then secpos = secpos + (num or 1) end end +-- Optionally add a VREG action. +local function wvreg(kind, vreg, psz, sk, defer) + if not vreg then return end + waction("VREG", vreg) + local b = assert(map_vreg[kind], "bad vreg kind `"..vreg.."'") + if b < (sk or 0) then + vreg_shrink_count = vreg_shrink_count + 1 + end + if not defer then + b = b + vreg_shrink_count * 8 + vreg_shrink_count = 0 + end + wputxb(b + (psz or 0)) +end + -- Add call to embedded DynASM C code. local function wcall(func, args) wline(format("dasm_%s(Dst, %s);", func, concat(args, ", ")), true) @@ -297,7 +329,7 @@ local function mkrmap(sz, cl, names) local iname = format("@%s%x%s", sz, i, needrex and "R" or "") if needrex then map_reg_needrex[iname] = true end local name - if sz == "o" then name = format("xmm%d", i) + if sz == "o" or sz == "y" then name = format("%s%d", cl, i) elseif sz == "f" then name = format("st%d", i) else name = format("r%d%s", i, sz == addrsize and "" or sz) end map_archdef[name] = iname @@ -324,6 +356,7 @@ mkrmap("w", "Rw", {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"}) mkrmap("b", "Rb", {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"}) map_reg_valid_index[map_archdef.esp] = false if x64 then map_reg_valid_index[map_archdef.rsp] = false end +if x64 then map_reg_needrex[map_archdef.Rb] = true end map_archdef["Ra"] = "@"..addrsize -- FP registers (internally tword sized, but use "f" as operand size). @@ -332,21 +365,24 @@ mkrmap("f", "Rf") -- SSE registers (oword sized, but qword and dword accessible). mkrmap("o", "xmm") +-- AVX registers (yword sized, but oword, qword and dword accessible). +mkrmap("y", "ymm") + -- Operand size prefixes to codes. local map_opsize = { - byte = "b", word = "w", dword = "d", qword = "q", oword = "o", tword = "t", - aword = addrsize, + byte = "b", word = "w", dword = "d", qword = "q", oword = "o", yword = "y", + tword = "t", aword = addrsize, } -- Operand size code to number. local map_opsizenum = { - b = 1, w = 2, d = 4, q = 8, o = 16, t = 10, + b = 1, w = 2, d = 4, q = 8, o = 16, y = 32, t = 10, } -- Operand size code to name. local map_opsizename = { - b = "byte", w = "word", d = "dword", q = "qword", o = "oword", t = "tword", - f = "fpword", + b = "byte", w = "word", d = "dword", q = "qword", o = "oword", y = "yword", + t = "tword", f = "fpword", } -- Valid index register scale factors. @@ -426,10 +462,10 @@ end -- Put unsigned word or arg. local function wputwarg(n) if type(n) == "number" then - if n < 0 or n > 65535 then + if shr(n, 16) ~= 0 then werror("unsigned immediate word out of range") end - local r = n%256; n = (n-r)/256; wputb(r); wputb(n); + wputb(band(n, 255)); wputb(shr(n, 8)); else waction("IMM_W", n) end end @@ -437,10 +473,10 @@ end local function wputdarg(n) local tn = type(n) if tn == "number" then - if n < 0 then n = n + 4294967296 end - local r = n%256; n = (n-r)/256; wputb(r); - r = n%256; n = (n-r)/256; wputb(r); - r = n%256; n = (n-r)/256; wputb(r); wputb(n); + wputb(band(n, 255)) + wputb(band(shr(n, 8), 255)) + wputb(band(shr(n, 16), 255)) + wputb(shr(n, 24)) elseif tn == "table" then wputlabel("IMM_", n[1], 1) else @@ -458,42 +494,77 @@ local function wputszarg(sz, n) end -- Put multi-byte opcode with operand-size dependent modifications. -local function wputop(sz, op, rex) +local function wputop(sz, op, rex, vex, vregr, vregxb) + local psz, sk = 0, nil + if vex then + local tail + if vex.m == 1 and band(rex, 11) == 0 then + if x64 and vregxb then + sk = map_vreg["modrm.reg"] + else + wputb(0xc5) + tail = shl(bxor(band(rex, 4), 4), 5) + psz = 3 + end + end + if not tail then + wputb(0xc4) + wputb(shl(bxor(band(rex, 7), 7), 5) + vex.m) + tail = shl(band(rex, 8), 4) + psz = 4 + end + local reg, vreg = 0, nil + if vex.v then + reg = vex.v.reg + if not reg then werror("bad vex operand") end + if reg < 0 then reg = 0; vreg = vex.v.vreg end + end + if sz == "y" or vex.l then tail = tail + 4 end + wputb(tail + shl(bxor(reg, 15), 3) + vex.p) + wvreg("vex.v", vreg) + rex = 0 + if op >= 256 then werror("bad vex opcode") end + else + if rex ~= 0 then + if not x64 then werror("bad operand size") end + elseif (vregr or vregxb) and x64 then + rex = 0x10 + sk = map_vreg["vex.v"] + end + end local r - if rex ~= 0 and not x64 then werror("bad operand size") end if sz == "w" then wputb(102) end -- Needs >32 bit numbers, but only for crc32 eax, word [ebx] if op >= 4294967296 then r = op%4294967296 wputb((op-r)/4294967296) op = r end - if op >= 16777216 then r = op % 16777216 wputb((op-r) / 16777216) op = r end + if op >= 16777216 then wputb(shr(op, 24)); op = band(op, 0xffffff) end if op >= 65536 then if rex ~= 0 then - local opc3 = op - op % 256 + local opc3 = band(op, 0xffff00) if opc3 == 0x0f3a00 or opc3 == 0x0f3800 then - wputb(64 + rex % 16); rex = 0 + wputb(64 + band(rex, 15)); rex = 0; psz = 2 end end - r = op % 65536 wputb((op-r) / 65536) op = r + wputb(shr(op, 16)); op = band(op, 0xffff); psz = psz + 1 end if op >= 256 then - r = op % 256 - local b = (op-r) / 256 - if b == 15 and rex ~= 0 then wputb(64 + rex % 16); rex = 0 end - wputb(b) - op = r + local b = shr(op, 8) + if b == 15 and rex ~= 0 then wputb(64 + band(rex, 15)); rex = 0; psz = 2 end + wputb(b); op = band(op, 255); psz = psz + 1 end - if rex ~= 0 then wputb(64 + rex % 16) end + if rex ~= 0 then wputb(64 + band(rex, 15)); psz = 2 end if sz == "b" then op = op - 1 end wputb(op) + return psz, sk end -- Put ModRM or SIB formatted byte. local function wputmodrm(m, s, rm, vs, vrm) assert(m < 4 and s < 16 and rm < 16, "bad modrm operands") - wputb(64*m + 8*(s%8) + (rm%8)) + wputb(shl(m, 6) + shl(band(s, 7), 3) + band(rm, 7)) end -- Put ModRM/SIB plus optional displacement. -local function wputmrmsib(t, imark, s, vsreg) +local function wputmrmsib(t, imark, s, vsreg, psz, sk) local vreg, vxreg local reg, xreg = t.reg, t.xreg if reg and reg < 0 then reg = 0; vreg = t.vreg end @@ -503,8 +574,8 @@ local function wputmrmsib(t, imark, s, vsreg) -- Register mode. if sub(t.mode, 1, 1) == "r" then wputmodrm(3, s, reg) - if vsreg then waction("VREG", vsreg); wputxb(2) end - if vreg then waction("VREG", vreg); wputxb(0) end + wvreg("modrm.reg", vsreg, psz+1, sk, vreg) + wvreg("modrm.rm.r", vreg, psz+1, sk) return end @@ -518,21 +589,22 @@ local function wputmrmsib(t, imark, s, vsreg) -- [xreg*xsc+disp] -> (0, s, esp) (xsc, xreg, ebp) wputmodrm(0, s, 4) if imark == "I" then waction("MARK") end - if vsreg then waction("VREG", vsreg); wputxb(2) end + wvreg("modrm.reg", vsreg, psz+1, sk, vxreg) wputmodrm(t.xsc, xreg, 5) - if vxreg then waction("VREG", vxreg); wputxb(3) end + wvreg("sib.index", vxreg, psz+2, sk) else -- Pure 32 bit displacement. if x64 and tdisp ~= "table" then wputmodrm(0, s, 4) -- [disp] -> (0, s, esp) (0, esp, ebp) + wvreg("modrm.reg", vsreg, psz+1, sk) if imark == "I" then waction("MARK") end wputmodrm(0, 4, 5) else riprel = x64 wputmodrm(0, s, 5) -- [disp|rip-label] -> (0, s, ebp) + wvreg("modrm.reg", vsreg, psz+1, sk) if imark == "I" then waction("MARK") end end - if vsreg then waction("VREG", vsreg); wputxb(2) end end if riprel then -- Emit rip-relative displacement. if match("UWSiI", imark) then @@ -548,7 +620,7 @@ local function wputmrmsib(t, imark, s, vsreg) local m if tdisp == "number" then -- Check displacement size at assembly time. - if disp == 0 and (reg%8) ~= 5 then -- [ebp] -> [ebp+0] (in SIB, too) + if disp == 0 and band(reg, 7) ~= 5 then -- [ebp] -> [ebp+0] (in SIB, too) if not vreg then m = 0 end -- Force DISP to allow [Rd(5)] -> [ebp+0] elseif disp >= -128 and disp <= 127 then m = 1 else m = 2 end @@ -557,19 +629,19 @@ local function wputmrmsib(t, imark, s, vsreg) end -- Index register present or esp as base register: need SIB encoding. - if xreg or (reg%8) == 4 then + if xreg or band(reg, 7) == 4 then wputmodrm(m or 2, s, 4) -- ModRM. if m == nil or imark == "I" then waction("MARK") end - if vsreg then waction("VREG", vsreg); wputxb(2) end + wvreg("modrm.reg", vsreg, psz+1, sk, vxreg or vreg) wputmodrm(t.xsc or 0, xreg or 4, reg) -- SIB. - if vxreg then waction("VREG", vxreg); wputxb(3) end - if vreg then waction("VREG", vreg); wputxb(1) end + wvreg("sib.index", vxreg, psz+2, sk, vreg) + wvreg("sib.base", vreg, psz+2, sk) else wputmodrm(m or 2, s, reg) -- ModRM. if (imark == "I" and (m == 1 or m == 2)) or (m == nil and (vsreg or vreg)) then waction("MARK") end - if vsreg then waction("VREG", vsreg); wputxb(2) end - if vreg then waction("VREG", vreg); wputxb(1) end + wvreg("modrm.reg", vsreg, psz+1, sk, vreg) + wvreg("modrm.rm.m", vreg, psz+1, sk) end -- Put displacement. @@ -880,9 +952,15 @@ end -- "m"/"M" generates ModRM/SIB from the 1st/2nd operand. -- The spare 3 bits are either filled with the last hex digit or -- the result from a previous "r"/"R". The opcode is restored. +-- "u" Use VEX encoding, vvvv unused. +-- "v"/"V" Use VEX encoding, vvvv from 1st/2nd operand (the operand is +-- removed from the list used by future characters). +-- "L" Force VEX.L -- -- All of the following characters force a flush of the opcode: -- "o"/"O" stores a pure 32 bit disp (offset) from the 1st/2nd operand. +-- "s" stores a 4 bit immediate from the last register operand, +-- followed by 4 zero bits. -- "S" stores a signed 8 bit immediate from the last operand. -- "U" stores an unsigned 8 bit immediate from the last operand. -- "W" stores an unsigned 16 bit immediate from the last operand. @@ -1039,7 +1117,7 @@ local map_op = { -- ED: *in Rdw,dx -- EE: *out dx,Rb -- EF: *out dx,Rdw - -- F0: *lock + lock_0 = "F0", int1_0 = "F1", repne_0 = "F2", repnz_0 = "F2", @@ -1080,7 +1158,11 @@ local map_op = { btr_2 = "mrqdw:0FB3Rm|miqdw:0FBA6mU", bts_2 = "mrqdw:0FABRm|miqdw:0FBA5mU", + shld_3 = "mriqdw:0FA4RmU|mrC/qq:0FA5Rm|mrC/dd:|mrC/ww:", + shrd_3 = "mriqdw:0FACRmU|mrC/qq:0FADRm|mrC/dd:|mrC/ww:", + rdtsc_0 = "0F31", -- P1+ + rdpmc_0 = "0F33", -- P6+ cpuid_0 = "0FA2", -- P1+ -- floating point ops @@ -1113,6 +1195,9 @@ local map_op = { fucompp_0 = "DAE9", fcompp_0 = "DED9", + fldenv_1 = "x.:D94m", + fnstenv_1 = "x.:D96m", + fstenv_1 = "x.:9BD96m", fldcw_1 = "xw:nD95m", fstcw_1 = "xw:n9BD97m", fnstcw_1 = "xw:nD97m", @@ -1183,11 +1268,13 @@ local map_op = { cvtsi2sd_2 = "rm/od:F20F2ArM|rm/oq:F20F2ArXM", cvtsi2ss_2 = "rm/od:F30F2ArM|rm/oq:F30F2ArXM", cvtss2sd_2 = "rro:F30F5ArM|rx/od:", - cvtss2si_2 = "rr/do:F20F2CrM|rr/qo:|rxd:|rx/qd:", + cvtss2si_2 = "rr/do:F30F2DrM|rr/qo:|rxd:|rx/qd:", cvttpd2dq_2 = "rmo:660FE6rM", cvttps2dq_2 = "rmo:F30F5BrM", cvttsd2si_2 = "rr/do:F20F2CrM|rr/qo:|rx/dq:|rxq:", cvttss2si_2 = "rr/do:F30F2CrM|rr/qo:|rxd:|rx/qd:", + fxsave_1 = "x.:0FAE0m", + fxrstor_1 = "x.:0FAE1m", ldmxcsr_1 = "xd:0FAE2m", lfence_0 = "0FAEE8", maskmovdqu_2 = "rro:660FF7rM", @@ -1216,46 +1303,14 @@ local map_op = { movups_2 = "rmo:0F10rM|mro:0F11Rm", orpd_2 = "rmo:660F56rM", orps_2 = "rmo:0F56rM", - packssdw_2 = "rmo:660F6BrM", - packsswb_2 = "rmo:660F63rM", - packuswb_2 = "rmo:660F67rM", - paddb_2 = "rmo:660FFCrM", - paddd_2 = "rmo:660FFErM", - paddq_2 = "rmo:660FD4rM", - paddsb_2 = "rmo:660FECrM", - paddsw_2 = "rmo:660FEDrM", - paddusb_2 = "rmo:660FDCrM", - paddusw_2 = "rmo:660FDDrM", - paddw_2 = "rmo:660FFDrM", - pand_2 = "rmo:660FDBrM", - pandn_2 = "rmo:660FDFrM", pause_0 = "F390", - pavgb_2 = "rmo:660FE0rM", - pavgw_2 = "rmo:660FE3rM", - pcmpeqb_2 = "rmo:660F74rM", - pcmpeqd_2 = "rmo:660F76rM", - pcmpeqw_2 = "rmo:660F75rM", - pcmpgtb_2 = "rmo:660F64rM", - pcmpgtd_2 = "rmo:660F66rM", - pcmpgtw_2 = "rmo:660F65rM", - pextrw_3 = "rri/do:660FC5rMU|xri/wo:660F3A15nrMU", -- Mem op: SSE4.1 only. + pextrw_3 = "rri/do:660FC5rMU|xri/wo:660F3A15nRmU", -- Mem op: SSE4.1 only. pinsrw_3 = "rri/od:660FC4rMU|rxi/ow:", - pmaddwd_2 = "rmo:660FF5rM", - pmaxsw_2 = "rmo:660FEErM", - pmaxub_2 = "rmo:660FDErM", - pminsw_2 = "rmo:660FEArM", - pminub_2 = "rmo:660FDArM", pmovmskb_2 = "rr/do:660FD7rM", - pmulhuw_2 = "rmo:660FE4rM", - pmulhw_2 = "rmo:660FE5rM", - pmullw_2 = "rmo:660FD5rM", - pmuludq_2 = "rmo:660FF4rM", - por_2 = "rmo:660FEBrM", prefetchnta_1 = "xb:n0F180m", prefetcht0_1 = "xb:n0F181m", prefetcht1_1 = "xb:n0F182m", prefetcht2_1 = "xb:n0F183m", - psadbw_2 = "rmo:660FF6rM", pshufd_3 = "rmio:660F70rMU", pshufhw_3 = "rmio:F30F70rMU", pshuflw_3 = "rmio:F20F70rMU", @@ -1269,23 +1324,6 @@ local map_op = { psrldq_2 = "rio:660F733mU", psrlq_2 = "rmo:660FD3rM|rio:660F732mU", psrlw_2 = "rmo:660FD1rM|rio:660F712mU", - psubb_2 = "rmo:660FF8rM", - psubd_2 = "rmo:660FFArM", - psubq_2 = "rmo:660FFBrM", - psubsb_2 = "rmo:660FE8rM", - psubsw_2 = "rmo:660FE9rM", - psubusb_2 = "rmo:660FD8rM", - psubusw_2 = "rmo:660FD9rM", - psubw_2 = "rmo:660FF9rM", - punpckhbw_2 = "rmo:660F68rM", - punpckhdq_2 = "rmo:660F6ArM", - punpckhqdq_2 = "rmo:660F6DrM", - punpckhwd_2 = "rmo:660F69rM", - punpcklbw_2 = "rmo:660F60rM", - punpckldq_2 = "rmo:660F62rM", - punpcklqdq_2 = "rmo:660F6CrM", - punpcklwd_2 = "rmo:660F61rM", - pxor_2 = "rmo:660FEFrM", rcpps_2 = "rmo:0F53rM", rcpss_2 = "rro:F30F53rM|rx/od:", rsqrtps_2 = "rmo:0F52rM", @@ -1343,7 +1381,7 @@ local map_op = { dpps_3 = "rmio:660F3A40rMU", extractps_3 = "mri/do:660F3A17RmU|rri/qo:660F3A17RXmU", insertps_3 = "rrio:660F3A41rMU|rxi/od:", - movntdqa_2 = "rmo:660F382ArM", + movntdqa_2 = "rxo:660F382ArM", mpsadbw_3 = "rmio:660F3A42rMU", packusdw_2 = "rmo:660F382BrM", pblendvb_3 = "rmRo:660F3810rM", @@ -1403,6 +1441,242 @@ local map_op = { movntsd_2 = "xr/qo:nF20F2BRm", movntss_2 = "xr/do:F30F2BRm", -- popcnt is also in SSE4.2 + + -- AES-NI + aesdec_2 = "rmo:660F38DErM", + aesdeclast_2 = "rmo:660F38DFrM", + aesenc_2 = "rmo:660F38DCrM", + aesenclast_2 = "rmo:660F38DDrM", + aesimc_2 = "rmo:660F38DBrM", + aeskeygenassist_3 = "rmio:660F3ADFrMU", + pclmulqdq_3 = "rmio:660F3A44rMU", + + -- AVX FP ops + vaddsubpd_3 = "rrmoy:660FVD0rM", + vaddsubps_3 = "rrmoy:F20FVD0rM", + vandpd_3 = "rrmoy:660FV54rM", + vandps_3 = "rrmoy:0FV54rM", + vandnpd_3 = "rrmoy:660FV55rM", + vandnps_3 = "rrmoy:0FV55rM", + vblendpd_4 = "rrmioy:660F3AV0DrMU", + vblendps_4 = "rrmioy:660F3AV0CrMU", + vblendvpd_4 = "rrmroy:660F3AV4BrMs", + vblendvps_4 = "rrmroy:660F3AV4ArMs", + vbroadcastf128_2 = "rx/yo:660F38u1ArM", + vcmppd_4 = "rrmioy:660FVC2rMU", + vcmpps_4 = "rrmioy:0FVC2rMU", + vcmpsd_4 = "rrrio:F20FVC2rMU|rrxi/ooq:", + vcmpss_4 = "rrrio:F30FVC2rMU|rrxi/ood:", + vcomisd_2 = "rro:660Fu2FrM|rx/oq:", + vcomiss_2 = "rro:0Fu2FrM|rx/od:", + vcvtdq2pd_2 = "rro:F30FuE6rM|rx/oq:|rm/yo:", + vcvtdq2ps_2 = "rmoy:0Fu5BrM", + vcvtpd2dq_2 = "rmoy:F20FuE6rM", + vcvtpd2ps_2 = "rmoy:660Fu5ArM", + vcvtps2dq_2 = "rmoy:660Fu5BrM", + vcvtps2pd_2 = "rro:0Fu5ArM|rx/oq:|rm/yo:", + vcvtsd2si_2 = "rr/do:F20Fu2DrM|rx/dq:|rr/qo:|rxq:", + vcvtsd2ss_3 = "rrro:F20FV5ArM|rrx/ooq:", + vcvtsi2sd_3 = "rrm/ood:F20FV2ArM|rrm/ooq:F20FVX2ArM", + vcvtsi2ss_3 = "rrm/ood:F30FV2ArM|rrm/ooq:F30FVX2ArM", + vcvtss2sd_3 = "rrro:F30FV5ArM|rrx/ood:", + vcvtss2si_2 = "rr/do:F30Fu2DrM|rxd:|rr/qo:|rx/qd:", + vcvttpd2dq_2 = "rmo:660FuE6rM|rm/oy:660FuLE6rM", + vcvttps2dq_2 = "rmoy:F30Fu5BrM", + vcvttsd2si_2 = "rr/do:F20Fu2CrM|rx/dq:|rr/qo:|rxq:", + vcvttss2si_2 = "rr/do:F30Fu2CrM|rxd:|rr/qo:|rx/qd:", + vdppd_4 = "rrmio:660F3AV41rMU", + vdpps_4 = "rrmioy:660F3AV40rMU", + vextractf128_3 = "mri/oy:660F3AuL19RmU", + vextractps_3 = "mri/do:660F3Au17RmU", + vhaddpd_3 = "rrmoy:660FV7CrM", + vhaddps_3 = "rrmoy:F20FV7CrM", + vhsubpd_3 = "rrmoy:660FV7DrM", + vhsubps_3 = "rrmoy:F20FV7DrM", + vinsertf128_4 = "rrmi/yyo:660F3AV18rMU", + vinsertps_4 = "rrrio:660F3AV21rMU|rrxi/ood:", + vldmxcsr_1 = "xd:0FuAE2m", + vmaskmovps_3 = "rrxoy:660F38V2CrM|xrroy:660F38V2ERm", + vmaskmovpd_3 = "rrxoy:660F38V2DrM|xrroy:660F38V2FRm", + vmovapd_2 = "rmoy:660Fu28rM|mroy:660Fu29Rm", + vmovaps_2 = "rmoy:0Fu28rM|mroy:0Fu29Rm", + vmovd_2 = "rm/od:660Fu6ErM|rm/oq:660FuX6ErM|mr/do:660Fu7ERm|mr/qo:", + vmovq_2 = "rro:F30Fu7ErM|rx/oq:|xr/qo:660FuD6Rm", + vmovddup_2 = "rmy:F20Fu12rM|rro:|rx/oq:", + vmovhlps_3 = "rrro:0FV12rM", + vmovhpd_2 = "xr/qo:660Fu17Rm", + vmovhpd_3 = "rrx/ooq:660FV16rM", + vmovhps_2 = "xr/qo:0Fu17Rm", + vmovhps_3 = "rrx/ooq:0FV16rM", + vmovlhps_3 = "rrro:0FV16rM", + vmovlpd_2 = "xr/qo:660Fu13Rm", + vmovlpd_3 = "rrx/ooq:660FV12rM", + vmovlps_2 = "xr/qo:0Fu13Rm", + vmovlps_3 = "rrx/ooq:0FV12rM", + vmovmskpd_2 = "rr/do:660Fu50rM|rr/dy:660FuL50rM", + vmovmskps_2 = "rr/do:0Fu50rM|rr/dy:0FuL50rM", + vmovntpd_2 = "xroy:660Fu2BRm", + vmovntps_2 = "xroy:0Fu2BRm", + vmovsd_2 = "rx/oq:F20Fu10rM|xr/qo:F20Fu11Rm", + vmovsd_3 = "rrro:F20FV10rM", + vmovshdup_2 = "rmoy:F30Fu16rM", + vmovsldup_2 = "rmoy:F30Fu12rM", + vmovss_2 = "rx/od:F30Fu10rM|xr/do:F30Fu11Rm", + vmovss_3 = "rrro:F30FV10rM", + vmovupd_2 = "rmoy:660Fu10rM|mroy:660Fu11Rm", + vmovups_2 = "rmoy:0Fu10rM|mroy:0Fu11Rm", + vorpd_3 = "rrmoy:660FV56rM", + vorps_3 = "rrmoy:0FV56rM", + vpermilpd_3 = "rrmoy:660F38V0DrM|rmioy:660F3Au05rMU", + vpermilps_3 = "rrmoy:660F38V0CrM|rmioy:660F3Au04rMU", + vperm2f128_4 = "rrmiy:660F3AV06rMU", + vptestpd_2 = "rmoy:660F38u0FrM", + vptestps_2 = "rmoy:660F38u0ErM", + vrcpps_2 = "rmoy:0Fu53rM", + vrcpss_3 = "rrro:F30FV53rM|rrx/ood:", + vrsqrtps_2 = "rmoy:0Fu52rM", + vrsqrtss_3 = "rrro:F30FV52rM|rrx/ood:", + vroundpd_3 = "rmioy:660F3Au09rMU", + vroundps_3 = "rmioy:660F3Au08rMU", + vroundsd_4 = "rrrio:660F3AV0BrMU|rrxi/ooq:", + vroundss_4 = "rrrio:660F3AV0ArMU|rrxi/ood:", + vshufpd_4 = "rrmioy:660FVC6rMU", + vshufps_4 = "rrmioy:0FVC6rMU", + vsqrtps_2 = "rmoy:0Fu51rM", + vsqrtss_2 = "rro:F30Fu51rM|rx/od:", + vsqrtpd_2 = "rmoy:660Fu51rM", + vsqrtsd_2 = "rro:F20Fu51rM|rx/oq:", + vstmxcsr_1 = "xd:0FuAE3m", + vucomisd_2 = "rro:660Fu2ErM|rx/oq:", + vucomiss_2 = "rro:0Fu2ErM|rx/od:", + vunpckhpd_3 = "rrmoy:660FV15rM", + vunpckhps_3 = "rrmoy:0FV15rM", + vunpcklpd_3 = "rrmoy:660FV14rM", + vunpcklps_3 = "rrmoy:0FV14rM", + vxorpd_3 = "rrmoy:660FV57rM", + vxorps_3 = "rrmoy:0FV57rM", + vzeroall_0 = "0FuL77", + vzeroupper_0 = "0Fu77", + + -- AVX2 FP ops + vbroadcastss_2 = "rx/od:660F38u18rM|rx/yd:|rro:|rr/yo:", + vbroadcastsd_2 = "rx/yq:660F38u19rM|rr/yo:", + -- *vgather* (!vsib) + vpermpd_3 = "rmiy:660F3AuX01rMU", + vpermps_3 = "rrmy:660F38V16rM", + + -- AVX, AVX2 integer ops + -- In general, xmm requires AVX, ymm requires AVX2. + vaesdec_3 = "rrmo:660F38VDErM", + vaesdeclast_3 = "rrmo:660F38VDFrM", + vaesenc_3 = "rrmo:660F38VDCrM", + vaesenclast_3 = "rrmo:660F38VDDrM", + vaesimc_2 = "rmo:660F38uDBrM", + vaeskeygenassist_3 = "rmio:660F3AuDFrMU", + vlddqu_2 = "rxoy:F20FuF0rM", + vmaskmovdqu_2 = "rro:660FuF7rM", + vmovdqa_2 = "rmoy:660Fu6FrM|mroy:660Fu7FRm", + vmovdqu_2 = "rmoy:F30Fu6FrM|mroy:F30Fu7FRm", + vmovntdq_2 = "xroy:660FuE7Rm", + vmovntdqa_2 = "rxoy:660F38u2ArM", + vmpsadbw_4 = "rrmioy:660F3AV42rMU", + vpabsb_2 = "rmoy:660F38u1CrM", + vpabsd_2 = "rmoy:660F38u1ErM", + vpabsw_2 = "rmoy:660F38u1DrM", + vpackusdw_3 = "rrmoy:660F38V2BrM", + vpalignr_4 = "rrmioy:660F3AV0FrMU", + vpblendvb_4 = "rrmroy:660F3AV4CrMs", + vpblendw_4 = "rrmioy:660F3AV0ErMU", + vpclmulqdq_4 = "rrmio:660F3AV44rMU", + vpcmpeqq_3 = "rrmoy:660F38V29rM", + vpcmpestri_3 = "rmio:660F3Au61rMU", + vpcmpestrm_3 = "rmio:660F3Au60rMU", + vpcmpgtq_3 = "rrmoy:660F38V37rM", + vpcmpistri_3 = "rmio:660F3Au63rMU", + vpcmpistrm_3 = "rmio:660F3Au62rMU", + vpextrb_3 = "rri/do:660F3Au14nRmU|rri/qo:|xri/bo:", + vpextrw_3 = "rri/do:660FuC5rMU|xri/wo:660F3Au15nRmU", + vpextrd_3 = "mri/do:660F3Au16RmU", + vpextrq_3 = "mri/qo:660F3Au16RmU", + vphaddw_3 = "rrmoy:660F38V01rM", + vphaddd_3 = "rrmoy:660F38V02rM", + vphaddsw_3 = "rrmoy:660F38V03rM", + vphminposuw_2 = "rmo:660F38u41rM", + vphsubw_3 = "rrmoy:660F38V05rM", + vphsubd_3 = "rrmoy:660F38V06rM", + vphsubsw_3 = "rrmoy:660F38V07rM", + vpinsrb_4 = "rrri/ood:660F3AV20rMU|rrxi/oob:", + vpinsrw_4 = "rrri/ood:660FVC4rMU|rrxi/oow:", + vpinsrd_4 = "rrmi/ood:660F3AV22rMU", + vpinsrq_4 = "rrmi/ooq:660F3AVX22rMU", + vpmaddubsw_3 = "rrmoy:660F38V04rM", + vpmaxsb_3 = "rrmoy:660F38V3CrM", + vpmaxsd_3 = "rrmoy:660F38V3DrM", + vpmaxuw_3 = "rrmoy:660F38V3ErM", + vpmaxud_3 = "rrmoy:660F38V3FrM", + vpminsb_3 = "rrmoy:660F38V38rM", + vpminsd_3 = "rrmoy:660F38V39rM", + vpminuw_3 = "rrmoy:660F38V3ArM", + vpminud_3 = "rrmoy:660F38V3BrM", + vpmovmskb_2 = "rr/do:660FuD7rM|rr/dy:660FuLD7rM", + vpmovsxbw_2 = "rroy:660F38u20rM|rx/oq:|rx/yo:", + vpmovsxbd_2 = "rroy:660F38u21rM|rx/od:|rx/yq:", + vpmovsxbq_2 = "rroy:660F38u22rM|rx/ow:|rx/yd:", + vpmovsxwd_2 = "rroy:660F38u23rM|rx/oq:|rx/yo:", + vpmovsxwq_2 = "rroy:660F38u24rM|rx/od:|rx/yq:", + vpmovsxdq_2 = "rroy:660F38u25rM|rx/oq:|rx/yo:", + vpmovzxbw_2 = "rroy:660F38u30rM|rx/oq:|rx/yo:", + vpmovzxbd_2 = "rroy:660F38u31rM|rx/od:|rx/yq:", + vpmovzxbq_2 = "rroy:660F38u32rM|rx/ow:|rx/yd:", + vpmovzxwd_2 = "rroy:660F38u33rM|rx/oq:|rx/yo:", + vpmovzxwq_2 = "rroy:660F38u34rM|rx/od:|rx/yq:", + vpmovzxdq_2 = "rroy:660F38u35rM|rx/oq:|rx/yo:", + vpmuldq_3 = "rrmoy:660F38V28rM", + vpmulhrsw_3 = "rrmoy:660F38V0BrM", + vpmulld_3 = "rrmoy:660F38V40rM", + vpshufb_3 = "rrmoy:660F38V00rM", + vpshufd_3 = "rmioy:660Fu70rMU", + vpshufhw_3 = "rmioy:F30Fu70rMU", + vpshuflw_3 = "rmioy:F20Fu70rMU", + vpsignb_3 = "rrmoy:660F38V08rM", + vpsignw_3 = "rrmoy:660F38V09rM", + vpsignd_3 = "rrmoy:660F38V0ArM", + vpslldq_3 = "rrioy:660Fv737mU", + vpsllw_3 = "rrmoy:660FVF1rM|rrioy:660Fv716mU", + vpslld_3 = "rrmoy:660FVF2rM|rrioy:660Fv726mU", + vpsllq_3 = "rrmoy:660FVF3rM|rrioy:660Fv736mU", + vpsraw_3 = "rrmoy:660FVE1rM|rrioy:660Fv714mU", + vpsrad_3 = "rrmoy:660FVE2rM|rrioy:660Fv724mU", + vpsrldq_3 = "rrioy:660Fv733mU", + vpsrlw_3 = "rrmoy:660FVD1rM|rrioy:660Fv712mU", + vpsrld_3 = "rrmoy:660FVD2rM|rrioy:660Fv722mU", + vpsrlq_3 = "rrmoy:660FVD3rM|rrioy:660Fv732mU", + vptest_2 = "rmoy:660F38u17rM", + + -- AVX2 integer ops + vbroadcasti128_2 = "rx/yo:660F38u5ArM", + vinserti128_4 = "rrmi/yyo:660F3AV38rMU", + vextracti128_3 = "mri/oy:660F3AuL39RmU", + vpblendd_4 = "rrmioy:660F3AV02rMU", + vpbroadcastb_2 = "rro:660F38u78rM|rx/ob:|rr/yo:|rx/yb:", + vpbroadcastw_2 = "rro:660F38u79rM|rx/ow:|rr/yo:|rx/yw:", + vpbroadcastd_2 = "rro:660F38u58rM|rx/od:|rr/yo:|rx/yd:", + vpbroadcastq_2 = "rro:660F38u59rM|rx/oq:|rr/yo:|rx/yq:", + vpermd_3 = "rrmy:660F38V36rM", + vpermq_3 = "rmiy:660F3AuX00rMU", + -- *vpgather* (!vsib) + vperm2i128_4 = "rrmiy:660F3AV46rMU", + vpmaskmovd_3 = "rrxoy:660F38V8CrM|xrroy:660F38V8ERm", + vpmaskmovq_3 = "rrxoy:660F38VX8CrM|xrroy:660F38VX8ERm", + vpsllvd_3 = "rrmoy:660F38V47rM", + vpsllvq_3 = "rrmoy:660F38VX47rM", + vpsravd_3 = "rrmoy:660F38V46rM", + vpsrlvd_3 = "rrmoy:660F38V45rM", + vpsrlvq_3 = "rrmoy:660F38VX45rM", + + -- Intel ADX + adcx_2 = "rmqd:660F38F6rM", + adox_2 = "rmqd:F30F38F6rM", } ------------------------------------------------------------------------------ @@ -1410,7 +1684,7 @@ local map_op = { -- Arithmetic ops. for name,n in pairs{ add = 0, ["or"] = 1, adc = 2, sbb = 3, ["and"] = 4, sub = 5, xor = 6, cmp = 7 } do - local n8 = n * 8 + local n8 = shl(n, 3) map_op[name.."_2"] = format( "mr:%02XRm|rm:%02XrM|mI1qdw:81%XmI|mS1qdw:83%XmS|Ri1qdwb:%02Xri|mi1qdwb:81%Xmi", 1+n8, 3+n8, n, n, 5+n8, n) @@ -1432,7 +1706,7 @@ end -- FP arithmetic ops. for name,n in pairs{ add = 0, mul = 1, com = 2, comp = 3, sub = 4, subr = 5, div = 6, divr = 7 } do - local nc = 192 + n * 8 + local nc = 0xc0 + shl(n, 3) local nr = nc + (n < 4 and 0 or (n % 2 == 0 and 8 or -8)) local fn = "f"..name map_op[fn.."_1"] = format("ff:D8%02Xr|xd:D8%Xm|xq:nDC%Xm", nc, n, n) @@ -1448,34 +1722,63 @@ end -- FP conditional moves. for cc,n in pairs{ b=0, e=1, be=2, u=3, nb=4, ne=5, nbe=6, nu=7 } do - local n4 = n % 4 - local nc = 56000 + n4 * 8 + (n-n4) * 64 + local nc = 0xdac0 + shl(band(n, 3), 3) + shl(band(n, 4), 6) map_op["fcmov"..cc.."_1"] = format("ff:%04Xr", nc) -- P6+ map_op["fcmov"..cc.."_2"] = format("Fff:%04XR", nc) -- P6+ end --- SSE FP arithmetic ops. +-- SSE / AVX FP arithmetic ops. for name,n in pairs{ sqrt = 1, add = 8, mul = 9, sub = 12, min = 13, div = 14, max = 15 } do map_op[name.."ps_2"] = format("rmo:0F5%XrM", n) map_op[name.."ss_2"] = format("rro:F30F5%XrM|rx/od:", n) map_op[name.."pd_2"] = format("rmo:660F5%XrM", n) map_op[name.."sd_2"] = format("rro:F20F5%XrM|rx/oq:", n) + if n ~= 1 then + map_op["v"..name.."ps_3"] = format("rrmoy:0FV5%XrM", n) + map_op["v"..name.."ss_3"] = format("rrro:F30FV5%XrM|rrx/ood:", n) + map_op["v"..name.."pd_3"] = format("rrmoy:660FV5%XrM", n) + map_op["v"..name.."sd_3"] = format("rrro:F20FV5%XrM|rrx/ooq:", n) + end +end + +-- SSE2 / AVX / AVX2 integer arithmetic ops (66 0F leaf). +for name,n in pairs{ + paddb = 0xFC, paddw = 0xFD, paddd = 0xFE, paddq = 0xD4, + paddsb = 0xEC, paddsw = 0xED, packssdw = 0x6B, + packsswb = 0x63, packuswb = 0x67, paddusb = 0xDC, + paddusw = 0xDD, pand = 0xDB, pandn = 0xDF, pavgb = 0xE0, + pavgw = 0xE3, pcmpeqb = 0x74, pcmpeqd = 0x76, + pcmpeqw = 0x75, pcmpgtb = 0x64, pcmpgtd = 0x66, + pcmpgtw = 0x65, pmaddwd = 0xF5, pmaxsw = 0xEE, + pmaxub = 0xDE, pminsw = 0xEA, pminub = 0xDA, + pmulhuw = 0xE4, pmulhw = 0xE5, pmullw = 0xD5, + pmuludq = 0xF4, por = 0xEB, psadbw = 0xF6, psubb = 0xF8, + psubw = 0xF9, psubd = 0xFA, psubq = 0xFB, psubsb = 0xE8, + psubsw = 0xE9, psubusb = 0xD8, psubusw = 0xD9, + punpckhbw = 0x68, punpckhwd = 0x69, punpckhdq = 0x6A, + punpckhqdq = 0x6D, punpcklbw = 0x60, punpcklwd = 0x61, + punpckldq = 0x62, punpcklqdq = 0x6C, pxor = 0xEF +} do + map_op[name.."_2"] = format("rmo:660F%02XrM", n) + map_op["v"..name.."_3"] = format("rrmoy:660FV%02XrM", n) end ------------------------------------------------------------------------------ +local map_vexarg = { u = false, v = 1, V = 2 } + -- Process pattern string. local function dopattern(pat, args, sz, op, needrex) - local digit, addin + local digit, addin, vex local opcode = 0 local szov = sz local narg = 1 local rex = 0 -- Limit number of section buffer positions used by a single dasm_put(). - -- A single opcode needs a maximum of 5 positions. - if secpos+5 > maxsecpos then wflush() end + -- A single opcode needs a maximum of 6 positions. + if secpos+6 > maxsecpos then wflush() end -- Process each character. for c in gmatch(pat.."|", ".") do @@ -1489,6 +1792,8 @@ local function dopattern(pat, args, sz, op, needrex) szov = nil elseif c == "X" then -- Force REX.W. rex = 8 + elseif c == "L" then -- Force VEX.L. + vex.l = true elseif c == "r" then -- Merge 1st operand regno. into opcode. addin = args[1]; opcode = opcode + (addin.reg % 8) if narg < 2 then narg = 2 end @@ -1499,10 +1804,10 @@ local function dopattern(pat, args, sz, op, needrex) local s if addin then s = addin.reg - opcode = opcode - (s%8) -- Undo regno opcode merge. + opcode = opcode - band(s, 7) -- Undo regno opcode merge. else - s = opcode % 16 -- Undo last digit. - opcode = (opcode - s) / 16 + s = band(opcode, 15) -- Undo last digit. + opcode = shr(opcode, 4) end local nn = c == "m" and 1 or 2 local t = args[nn] @@ -1512,21 +1817,42 @@ local function dopattern(pat, args, sz, op, needrex) if t.xreg and t.xreg > 7 then rex = rex + 2 end if s > 7 then rex = rex + 4 end if needrex then rex = rex + 16 end - wputop(szov, opcode, rex); opcode = nil + local psz, sk = wputop(szov, opcode, rex, vex, s < 0, t.vreg or t.vxreg) + opcode = nil local imark = sub(pat, -1) -- Force a mark (ugly). -- Put ModRM/SIB with regno/last digit as spare. - wputmrmsib(t, imark, s, addin and addin.vreg) + wputmrmsib(t, imark, s, addin and addin.vreg, psz, sk) addin = nil + elseif map_vexarg[c] ~= nil then -- Encode using VEX prefix + local b = band(opcode, 255); opcode = shr(opcode, 8) + local m = 1 + if b == 0x38 then m = 2 + elseif b == 0x3a then m = 3 end + if m ~= 1 then b = band(opcode, 255); opcode = shr(opcode, 8) end + if b ~= 0x0f then + werror("expected `0F', `0F38', or `0F3A' to precede `"..c.. + "' in pattern `"..pat.."' for `"..op.."'") + end + local v = map_vexarg[c] + if v then v = remove(args, v) end + b = band(opcode, 255) + local p = 0 + if b == 0x66 then p = 1 + elseif b == 0xf3 then p = 2 + elseif b == 0xf2 then p = 3 end + if p ~= 0 then opcode = shr(opcode, 8) end + if opcode ~= 0 then wputop(nil, opcode, 0); opcode = 0 end + vex = { m = m, p = p, v = v } else if opcode then -- Flush opcode. if szov == "q" and rex == 0 then rex = rex + 8 end if needrex then rex = rex + 16 end if addin and addin.reg == -1 then - wputop(szov, opcode - 7, rex) - waction("VREG", addin.vreg); wputxb(0) + local psz, sk = wputop(szov, opcode - 7, rex, vex, true) + wvreg("opcode", addin.vreg, psz, sk) else if addin and addin.reg > 7 then rex = rex + 1 end - wputop(szov, opcode, rex) + wputop(szov, opcode, rex, vex) end opcode = nil end @@ -1563,6 +1889,14 @@ local function dopattern(pat, args, sz, op, needrex) else wputlabel("REL_", imm, 2) end + elseif c == "s" then + local reg = a.reg + if reg < 0 then + wputb(0) + wvreg("imm.hi", a.vreg) + else + wputb(shl(reg, 4)) + end else werror("bad char `"..c.."' in pattern `"..pat.."' for `"..op.."'") end @@ -1639,11 +1973,14 @@ map_op[".template__"] = function(params, template, nparams) if pat == "" then pat = lastpat else lastpat = pat end if matchtm(tm, args) then local prefix = sub(szm, 1, 1) - if prefix == "/" then -- Match both operand sizes. - if args[1].opsize == sub(szm, 2, 2) and - args[2].opsize == sub(szm, 3, 3) then - dopattern(pat, args, sz, params.op, needrex) -- Process pattern. - return + if prefix == "/" then -- Exactly match leading operand sizes. + for i = #szm,1,-1 do + if i == 1 then + dopattern(pat, args, sz, params.op, needrex) -- Process pattern. + return + elseif args[i-1].opsize ~= sub(szm, i, i) then + break + end end else -- Match common operand size. local szp = sz @@ -1678,7 +2015,7 @@ if x64 then function map_op.mov64_2(params) if not params then return { "reg, imm", "reg, [disp]", "[disp], reg" } end if secpos+2 > maxsecpos then wflush() end - local opcode, op64, sz, rex + local opcode, op64, sz, rex, vreg local op64 = match(params[1], "^%[%s*(.-)%s*%]$") if op64 then local a = parseoperand(params[2]) @@ -1699,11 +2036,17 @@ if x64 then werror("bad operand mode") end op64 = params[2] - opcode = 0xb8 + (a.reg%8) -- !x64: no VREG support. + if a.reg == -1 then + vreg = a.vreg + opcode = 0xb8 + else + opcode = 0xb8 + band(a.reg, 7) + end rex = a.reg > 7 and 9 or 8 end end - wputop(sz, opcode, rex) + local psz, sk = wputop(sz, opcode, rex, nil, vreg) + wvreg("opcode", vreg, psz, sk) waction("IMM_D", format("(unsigned int)((uintptr_t)(%s))", op64)) waction("IMM_D", format("(unsigned int)(((uintptr_t)(%s))>>32)", op64)) end diff --git a/texk/web2c/luatexdir/luaffi/dynasm/dynasm.lua b/texk/web2c/luatexdir/luaffi/dynasm/dynasm.lua index 2c5062d30a..6dda966774 100644 --- a/texk/web2c/luatexdir/luaffi/dynasm/dynasm.lua +++ b/texk/web2c/luatexdir/luaffi/dynasm/dynasm.lua @@ -2,22 +2,22 @@ -- DynASM. A dynamic assembler for code generation engines. -- Originally designed and implemented for LuaJIT. -- --- Copyright (C) 2005-2011 Mike Pall. All rights reserved. +-- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- See below for full copyright notice. ------------------------------------------------------------------------------ -- Application information. local _info = { - name = "DynASM", - description = "A dynamic assembler for code generation engines", - version = "1.3.0", - vernum = 10300, - release = "2011-05-05", - author = "Mike Pall", - url = "http://luajit.org/dynasm.html", - license = "MIT", - copyright = [[ -Copyright (C) 2005-2011 Mike Pall. All rights reserved. + name = "DynASM", + description = "A dynamic assembler for code generation engines", + version = "1.4.0", + vernum = 10400, + release = "2015-10-18", + author = "Mike Pall", + url = "http://luajit.org/dynasm.html", + license = "MIT", + copyright = [[ +Copyright (C) 2005-2017 Mike Pall. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -70,24 +70,24 @@ local g_wbuffer, g_capbuffer -- Write an output line (or callback function) to the buffer. local function wline(line, needindent) - local buf = g_capbuffer or g_wbuffer - buf[#buf+1] = needindent and g_indent..line or line - g_synclineno = g_synclineno + 1 + local buf = g_capbuffer or g_wbuffer + buf[#buf + 1] = needindent and g_indent .. line or line + g_synclineno = g_synclineno + 1 end -- Write assembler line as a comment, if requestd. local function wcomment(aline) - if g_opt.comment then - wline(g_opt.comment..aline..g_opt.endcomment, true) - end + if g_opt.comment then + wline(g_opt.comment .. aline .. g_opt.endcomment, true) + end end -- Resync CPP line numbers. local function wsync() - if g_synclineno ~= g_lineno and g_opt.cpp then - wline("# "..g_lineno..' "'..g_fname..'"') - g_synclineno = g_lineno - end + if g_synclineno ~= g_lineno and g_opt.cpp then + wline("#line " .. g_lineno .. ' "' .. g_fname .. '"') + g_synclineno = g_lineno + end end -- Dummy action flush function. Replaced with arch-specific function later. @@ -96,55 +96,52 @@ end -- Dump all buffered output lines. local function wdumplines(out, buf) - for _,line in ipairs(buf) do - if type(line) == "string" then - assert(out:write(line, "\n")) - else - -- Special callback to dynamically insert lines after end of processing. - line(out) + for _, line in ipairs(buf) do + if type(line) == "string" then + assert(out:write(line, "\n")) + else + -- Special callback to dynamically insert lines after end of processing. + line(out) + end end - end end ------------------------------------------------------------------------------ -- Emit an error. Processing continues with next statement. local function werror(msg) - if g_opt.vserror then - error(format("%s(%s) : error: %s:\n%s", g_fname, g_lineno, msg, g_curline), 0) - else error(format("%s:%s: error: %s:\n%s", g_fname, g_lineno, msg, g_curline), 0) - end end -- Emit a fatal error. Processing stops. local function wfatal(msg) - g_errcount = "fatal" - werror(msg) + g_errcount = "fatal" + werror(msg) end -- Print a warning. Processing continues. local function wwarn(msg) - stderr:write(format("%s:%s: warning: %s:\n%s\n", - g_fname, g_lineno, msg, g_curline)) + stderr:write(format("%s:%s: warning: %s:\n%s\n", + g_fname, g_lineno, msg, g_curline)) end -- Print caught error message. But suppress excessive errors. local function wprinterr(...) - if type(g_errcount) == "number" then - -- Regular error. - g_errcount = g_errcount + 1 - if g_errcount < 21 then -- Seems to be a reasonable limit. - stderr:write(...) - elseif g_errcount == 21 then - stderr:write(g_fname, - ":*: warning: too many errors (suppressed further messages).\n") - end - else - -- Fatal error. - stderr:write(...) - return true -- Stop processing. - end + if type(g_errcount) == "number" then + -- Regular error. + g_errcount = g_errcount + 1 + if g_errcount < 21 then + -- Seems to be a reasonable limit. + stderr:write(...) + elseif g_errcount == 21 then + stderr:write(g_fname, + ":*: warning: too many errors (suppressed further messages).\n") + end + else + -- Fatal error. + stderr:write(...) + return true -- Stop processing. + end end ------------------------------------------------------------------------------ @@ -155,20 +152,20 @@ local opt_current -- Print error and exit with error status. local function opterror(...) - stderr:write("dynasm.lua: ERROR: ", ...) - stderr:write("\n") - exit(1) + stderr:write("dynasm.lua: ERROR: ", ...) + stderr:write("\n") + exit(1) end -- Get option parameter. local function optparam(args) - local argn = args.argn - local p = args[argn] - if not p then - opterror("missing parameter for option `", opt_current, "'.") - end - args.argn = argn + 1 - return p + local argn = args.argn + local p = args[argn] + if not p then + opterror("missing parameter for option `", opt_current, "'.") + end + args.argn = argn + 1 + return p end ------------------------------------------------------------------------------ @@ -189,70 +186,85 @@ local map_def = {} -- Pseudo-opcode to define a substitution. map_coreop[".define_2"] = function(params, nparams) - if not params then return nparams == 1 and "name" or "name, subst" end - local name, def = params[1], params[2] or "1" - if not match(name, "^[%a_][%w_]*$") then werror("bad or duplicate define") end - map_def[name] = def + if not params then + return nparams == 1 and "name" or "name, subst" + end + local name, def = params[1], params[2] or "1" + if not match(name, "^[%a_][%w_]*$") then + werror("bad or duplicate define") + end + map_def[name] = def end map_coreop[".define_1"] = map_coreop[".define_2"] -- Define a substitution on the command line. function opt_map.D(args) - local namesubst = optparam(args) - local name, subst = match(namesubst, "^([%a_][%w_]*)=(.*)$") - if name then - map_def[name] = subst - elseif match(namesubst, "^[%a_][%w_]*$") then - map_def[namesubst] = "1" - else - opterror("bad define") - end + local namesubst = optparam(args) + local name, subst = match(namesubst, "^([%a_][%w_]*)=(.*)$") + if name then + map_def[name] = subst + elseif match(namesubst, "^[%a_][%w_]*$") then + map_def[namesubst] = "1" + else + opterror("bad define") + end end -- Undefine a substitution on the command line. function opt_map.U(args) - local name = optparam(args) - if match(name, "^[%a_][%w_]*$") then - map_def[name] = nil - else - opterror("bad define") - end + local name = optparam(args) + if match(name, "^[%a_][%w_]*$") then + map_def[name] = nil + else + opterror("bad define") + end end -- Helper for definesubst. local gotsubst local function definesubst_one(word) - local subst = map_def[word] - if subst then gotsubst = word; return subst else return word end + local subst = map_def[word] + if subst then + gotsubst = word; + return subst + else + return word + end end -- Iteratively substitute defines. local function definesubst(stmt) - -- Limit number of iterations. - for i=1,100 do - gotsubst = false - stmt = gsub(stmt, "#?[%w_]+", definesubst_one) - if not gotsubst then break end - end - if gotsubst then wfatal("recursive define involving `"..gotsubst.."'") end - return stmt + -- Limit number of iterations. + for i = 1, 100 do + gotsubst = false + stmt = gsub(stmt, "#?[%w_]+", definesubst_one) + if not gotsubst then + break + end + end + if gotsubst then + wfatal("recursive define involving `" .. gotsubst .. "'") + end + return stmt end -- Dump all defines. local function dumpdefines(out, lvl) - local t = {} - for name in pairs(map_def) do - t[#t+1] = name - end - sort(t) - out:write("Defines:\n") - for _,name in ipairs(t) do - local subst = map_def[name] - if g_arch then subst = g_arch.revdef(subst) end - out:write(format(" %-20s %s\n", name, subst)) - end - out:write("\n") + local t = {} + for name in pairs(map_def) do + t[#t + 1] = name + end + sort(t) + out:write("Defines:\n") + for _, name in ipairs(t) do + local subst = map_def[name] + if g_arch then + subst = g_arch.revdef(subst) + end + out:write(format(" %-20s %s\n", name, subst)) + end + out:write("\n") end ------------------------------------------------------------------------------ @@ -261,129 +273,149 @@ end local condlevel = 0 local condstack = {} -local function loadin(source, env) - if setfenv then - local func, err = loadstring(source) - if func then - setfenv(func, env) - end - return func, err - else - return load(source, nil, nil, env) - end -end - -- Evaluate condition with a Lua expression. Substitutions already performed. local function cond_eval(cond) - -- No globals. All unknown identifiers evaluate to nil. - local func, err = loadin("return "..cond, {}) - if func then - local ok, res = pcall(func) - if ok then - if res == 0 then return false end -- Oh well. - return not not res + local func, err + if setfenv then + func, err = loadstring("return " .. cond, "=expr") + else + -- No globals. All unknown identifiers evaluate to nil. + func, err = load("return " .. cond, "=expr", "t", {}) + end + if func then + if setfenv then + setfenv(func, {}) -- No globals. All unknown identifiers evaluate to nil. + end + local ok, res = pcall(func) + if ok then + if res == 0 then + return false + end -- Oh well. + return not not res + end + err = res end - err = res - end - wfatal("bad condition: "..err) + wfatal("bad condition: " .. err) end -- Skip statements until next conditional pseudo-opcode at the same level. local function stmtskip() - local dostmt_save = dostmt - local lvl = 0 - dostmt = function(stmt) - local op = match(stmt, "^%s*(%S+)") - if op == ".if" then - lvl = lvl + 1 - elseif lvl ~= 0 then - if op == ".endif" then lvl = lvl - 1 end - elseif op == ".elif" or op == ".else" or op == ".endif" then - dostmt = dostmt_save - dostmt(stmt) + local dostmt_save = dostmt + local lvl = 0 + dostmt = function(stmt) + local op = match(stmt, "^%s*(%S+)") + if op == ".if" then + lvl = lvl + 1 + elseif lvl ~= 0 then + if op == ".endif" then + lvl = lvl - 1 + end + elseif op == ".elif" or op == ".else" or op == ".endif" then + dostmt = dostmt_save + dostmt(stmt) + end end - end end -- Pseudo-opcodes for conditional assembly. map_coreop[".if_1"] = function(params) - if not params then return "condition" end - local lvl = condlevel + 1 - local res = cond_eval(params[1]) - condlevel = lvl - condstack[lvl] = res - if not res then stmtskip() end + if not params then + return "condition" + end + local lvl = condlevel + 1 + local res = cond_eval(params[1]) + condlevel = lvl + condstack[lvl] = res + if not res then + stmtskip() + end end map_coreop[".elif_1"] = function(params) - if not params then return "condition" end - if condlevel == 0 then wfatal(".elif without .if") end - local lvl = condlevel - local res = condstack[lvl] - if res then - if res == "else" then wfatal(".elif after .else") end - else - res = cond_eval(params[1]) + if not params then + return "condition" + end + if condlevel == 0 then + wfatal(".elif without .if") + end + local lvl = condlevel + local res = condstack[lvl] if res then - condstack[lvl] = res - return + if res == "else" then + wfatal(".elif after .else") + end + else + res = cond_eval(params[1]) + if res then + condstack[lvl] = res + return + end end - end - stmtskip() + stmtskip() end map_coreop[".else_0"] = function(params) - if condlevel == 0 then wfatal(".else without .if") end - local lvl = condlevel - local res = condstack[lvl] - condstack[lvl] = "else" - if res then - if res == "else" then wfatal(".else after .else") end - stmtskip() - end + if condlevel == 0 then + wfatal(".else without .if") + end + local lvl = condlevel + local res = condstack[lvl] + condstack[lvl] = "else" + if res then + if res == "else" then + wfatal(".else after .else") + end + stmtskip() + end end map_coreop[".endif_0"] = function(params) - local lvl = condlevel - if lvl == 0 then wfatal(".endif without .if") end - condlevel = lvl - 1 + local lvl = condlevel + if lvl == 0 then + wfatal(".endif without .if") + end + condlevel = lvl - 1 end -- Check for unfinished conditionals. local function checkconds() - if g_errcount ~= "fatal" and condlevel ~= 0 then - wprinterr(g_fname, ":*: error: unbalanced conditional\n") - end + if g_errcount ~= "fatal" and condlevel ~= 0 then + wprinterr(g_fname, ":*: error: unbalanced conditional\n") + end end ------------------------------------------------------------------------------ -- Search for a file in the given path and open it for reading. local function pathopen(path, name) - local dirsep = match(package.path, "\\") and "\\" or "/" - for _,p in ipairs(path) do - local fullname = p == "" and name or p..dirsep..name - local fin = io.open(fullname, "r") - if fin then - g_fname = fullname - return fin + local dirsep = package and match(package.path, "\\") and "\\" or "/" + for _, p in ipairs(path) do + local fullname = p == "" and name or p .. dirsep .. name + local fin = io.open(fullname, "r") + if fin then + g_fname = fullname + return fin + end end - end end -- Include a file. map_coreop[".include_1"] = function(params) - if not params then return "filename" end - local name = params[1] - -- Save state. Ugly, I know. but upvalues are fast. - local gf, gl, gcl, gi = g_fname, g_lineno, g_curline, g_indent - -- Read the included file. - local fatal = readfile(pathopen(g_opt.include, name) or - wfatal("include file `"..name.."' not found")) - -- Restore state. - g_synclineno = -1 - g_fname, g_lineno, g_curline, g_indent = gf, gl, gcl, gi - if fatal then wfatal("in include file") end + if not params then + return "filename" + end + local name = params[1] + -- Save state. Ugly, I know. but upvalues are fast. + local gf, gl, gcl, gi = g_fname, g_lineno, g_curline, g_indent + -- Read the included file. + local fatal = readfile(pathopen(g_opt.include, name) or + wfatal("include file `" .. name .. "' not found")) + -- Restore state. + g_synclineno = -1 + g_fname, g_lineno, g_curline, g_indent = gf, gl, gcl, gi + if fatal then + wfatal("in include file") + end end -- Make .include and conditionals initially available, too. @@ -402,107 +434,126 @@ local mac_list = {} -- Pseudo-opcode to define a macro. map_coreop[".macro_*"] = function(mparams) - if not mparams then return "name [, params...]" end - -- Split off and validate macro name. - local name = remove(mparams, 1) - if not name then werror("missing macro name") end - if not (match(name, "^[%a_][%w_%.]*$") or match(name, "^%.[%w_%.]+$")) then - wfatal("bad macro name `"..name.."'") - end - -- Validate macro parameter names. - local mdup = {} - for _,mp in ipairs(mparams) do - if not match(mp, "^[%a_][%w_]*$") then - wfatal("bad macro parameter name `"..mp.."'") - end - if mdup[mp] then wfatal("duplicate macro parameter name `"..mp.."'") end - mdup[mp] = true - end - -- Check for duplicate or recursive macro definitions. - local opname = name.."_"..#mparams - if map_op[opname] or map_op[name.."_*"] then - wfatal("duplicate macro `"..name.."' ("..#mparams.." parameters)") - end - if mac_capture then wfatal("recursive macro definition") end - - -- Enable statement capture. - local lines = {} - mac_lineno = g_lineno - mac_name = name - mac_capture = function(stmt) -- Statement capture function. - -- Stop macro definition with .endmacro pseudo-opcode. - if not match(stmt, "^%s*.endmacro%s*$") then - lines[#lines+1] = stmt - return - end - mac_capture = nil - mac_lineno = nil - mac_name = nil - mac_list[#mac_list+1] = opname - -- Add macro-op definition. - map_op[opname] = function(params) - if not params then return mparams, lines end - -- Protect against recursive macro invocation. - if mac_active[opname] then wfatal("recursive macro invocation") end - mac_active[opname] = true - -- Setup substitution map. - local subst = {} - for i,mp in ipairs(mparams) do subst[mp] = params[i] end - local mcom - if g_opt.maccomment and g_opt.comment then - mcom = " MACRO "..name.." ("..#mparams..")" - wcomment("{"..mcom) - end - -- Loop through all captured statements - for _,stmt in ipairs(lines) do - -- Substitute macro parameters. - local st = gsub(stmt, "[%w_]+", subst) - st = definesubst(st) - st = gsub(st, "%s*%.%.%s*", "") -- Token paste a..b. - if mcom and sub(st, 1, 1) ~= "|" then wcomment(st) end - -- Emit statement. Use a protected call for better diagnostics. - local ok, err = pcall(dostmt, st) - if not ok then - -- Add the captured statement to the error. - wprinterr(err, "\n", g_indent, "| ", stmt, - "\t[MACRO ", name, " (", #mparams, ")]\n") - end - end - if mcom then wcomment("}"..mcom) end - mac_active[opname] = nil - end - end + if not mparams then + return "name [, params...]" + end + -- Split off and validate macro name. + local name = remove(mparams, 1) + if not name then + werror("missing macro name") + end + if not (match(name, "^[%a_][%w_%.]*$") or match(name, "^%.[%w_%.]*$")) then + wfatal("bad macro name `" .. name .. "'") + end + -- Validate macro parameter names. + local mdup = {} + for _, mp in ipairs(mparams) do + if not match(mp, "^[%a_][%w_]*$") then + wfatal("bad macro parameter name `" .. mp .. "'") + end + if mdup[mp] then + wfatal("duplicate macro parameter name `" .. mp .. "'") + end + mdup[mp] = true + end + -- Check for duplicate or recursive macro definitions. + local opname = name .. "_" .. #mparams + if map_op[opname] or map_op[name .. "_*"] then + wfatal("duplicate macro `" .. name .. "' (" .. #mparams .. " parameters)") + end + if mac_capture then + wfatal("recursive macro definition") + end + + -- Enable statement capture. + local lines = {} + mac_lineno = g_lineno + mac_name = name + mac_capture = function(stmt) + -- Statement capture function. + -- Stop macro definition with .endmacro pseudo-opcode. + if not match(stmt, "^%s*.endmacro%s*$") then + lines[#lines + 1] = stmt + return + end + mac_capture = nil + mac_lineno = nil + mac_name = nil + mac_list[#mac_list + 1] = opname + -- Add macro-op definition. + map_op[opname] = function(params) + if not params then + return mparams, lines + end + -- Protect against recursive macro invocation. + if mac_active[opname] then + wfatal("recursive macro invocation") + end + mac_active[opname] = true + -- Setup substitution map. + local subst = {} + for i, mp in ipairs(mparams) do + subst[mp] = params[i] + end + local mcom + if g_opt.maccomment and g_opt.comment then + mcom = " MACRO " .. name .. " (" .. #mparams .. ")" + wcomment("{" .. mcom) + end + -- Loop through all captured statements + for _, stmt in ipairs(lines) do + -- Substitute macro parameters. + local st = gsub(stmt, "[%w_]+", subst) + st = definesubst(st) + st = gsub(st, "%s*%.%.%s*", "") -- Token paste a..b. + if mcom and sub(st, 1, 1) ~= "|" then + wcomment(st) + end + -- Emit statement. Use a protected call for better diagnostics. + local ok, err = pcall(dostmt, st) + if not ok then + -- Add the captured statement to the error. + wprinterr(err, "\n", g_indent, "| ", stmt, + "\t[MACRO ", name, " (", #mparams, ")]\n") + end + end + if mcom then + wcomment("}" .. mcom) + end + mac_active[opname] = nil + end + end end -- An .endmacro pseudo-opcode outside of a macro definition is an error. map_coreop[".endmacro_0"] = function(params) - wfatal(".endmacro without .macro") + wfatal(".endmacro without .macro") end -- Dump all macros and their contents (with -PP only). local function dumpmacros(out, lvl) - sort(mac_list) - out:write("Macros:\n") - for _,opname in ipairs(mac_list) do - local name = sub(opname, 1, -3) - local params, lines = map_op[opname]() - out:write(format(" %-20s %s\n", name, concat(params, ", "))) - if lvl > 1 then - for _,line in ipairs(lines) do - out:write(" |", line, "\n") - end - out:write("\n") - end - end - out:write("\n") + sort(mac_list) + out:write("Macros:\n") + for _, opname in ipairs(mac_list) do + local name = sub(opname, 1, -3) + local params, lines = map_op[opname]() + out:write(format(" %-20s %s\n", name, concat(params, ", "))) + if lvl > 1 then + for _, line in ipairs(lines) do + out:write(" |", line, "\n") + end + out:write("\n") + end + end + out:write("\n") end -- Check for unfinished macro definitions. local function checkmacros() - if mac_capture then - wprinterr(g_fname, ":", mac_lineno, - ": error: unfinished .macro `", mac_name ,"'\n") - end + if mac_capture then + wprinterr(g_fname, ":", mac_lineno, + ": error: unfinished .macro `", mac_name, "'\n") + end end ------------------------------------------------------------------------------ @@ -514,79 +565,90 @@ local cap_used = {} -- Start a capture. map_coreop[".capture_1"] = function(params) - if not params then return "name" end - wflush() - local name = params[1] - if not match(name, "^[%a_][%w_]*$") then - wfatal("bad capture name `"..name.."'") - end - if cap_name then - wfatal("already capturing to `"..cap_name.."' since line "..cap_lineno) - end - cap_name = name - cap_lineno = g_lineno - -- Create or continue a capture buffer and start the output line capture. - local buf = cap_buffers[name] - if not buf then buf = {}; cap_buffers[name] = buf end - g_capbuffer = buf - g_synclineno = 0 + if not params then + return "name" + end + wflush() + local name = params[1] + if not match(name, "^[%a_][%w_]*$") then + wfatal("bad capture name `" .. name .. "'") + end + if cap_name then + wfatal("already capturing to `" .. cap_name .. "' since line " .. cap_lineno) + end + cap_name = name + cap_lineno = g_lineno + -- Create or continue a capture buffer and start the output line capture. + local buf = cap_buffers[name] + if not buf then + buf = {}; + cap_buffers[name] = buf + end + g_capbuffer = buf + g_synclineno = 0 end -- Stop a capture. map_coreop[".endcapture_0"] = function(params) - wflush() - if not cap_name then wfatal(".endcapture without a valid .capture") end - cap_name = nil - cap_lineno = nil - g_capbuffer = nil - g_synclineno = 0 + wflush() + if not cap_name then + wfatal(".endcapture without a valid .capture") + end + cap_name = nil + cap_lineno = nil + g_capbuffer = nil + g_synclineno = 0 end -- Dump a capture buffer. map_coreop[".dumpcapture_1"] = function(params) - if not params then return "name" end - wflush() - local name = params[1] - if not match(name, "^[%a_][%w_]*$") then - wfatal("bad capture name `"..name.."'") - end - cap_used[name] = true - wline(function(out) - local buf = cap_buffers[name] - if buf then wdumplines(out, buf) end - end) - g_synclineno = 0 + if not params then + return "name" + end + wflush() + local name = params[1] + if not match(name, "^[%a_][%w_]*$") then + wfatal("bad capture name `" .. name .. "'") + end + cap_used[name] = true + wline(function(out) + local buf = cap_buffers[name] + if buf then + wdumplines(out, buf) + end + end) + g_synclineno = 0 end -- Dump all captures and their buffers (with -PP only). local function dumpcaptures(out, lvl) - out:write("Captures:\n") - for name,buf in pairs(cap_buffers) do - out:write(format(" %-20s %4s)\n", name, "("..#buf)) - if lvl > 1 then - local bar = rep("=", 76) - out:write(" ", bar, "\n") - for _,line in ipairs(buf) do - out:write(" ", line, "\n") - end - out:write(" ", bar, "\n\n") + out:write("Captures:\n") + for name, buf in pairs(cap_buffers) do + out:write(format(" %-20s %4s)\n", name, "(" .. #buf)) + if lvl > 1 then + local bar = rep("=", 76) + out:write(" ", bar, "\n") + for _, line in ipairs(buf) do + out:write(" ", line, "\n") + end + out:write(" ", bar, "\n\n") + end end - end - out:write("\n") + out:write("\n") end -- Check for unfinished or unused captures. local function checkcaptures() - if cap_name then - wprinterr(g_fname, ":", cap_lineno, - ": error: unfinished .capture `", cap_name,"'\n") - return - end - for name in pairs(cap_buffers) do - if not cap_used[name] then - wprinterr(g_fname, ":*: error: missing .dumpcapture ", name ,"\n") + if cap_name then + wprinterr(g_fname, ":", cap_lineno, + ": error: unfinished .capture `", cap_name, "'\n") + return + end + for name in pairs(cap_buffers) do + if not cap_used[name] then + wprinterr(g_fname, ":*: error: missing .dumpcapture ", name, "\n") + end end - end end ------------------------------------------------------------------------------ @@ -597,136 +659,184 @@ local map_sections = {} -- Pseudo-opcode to define code sections. -- TODO: Data sections, BSS sections. Needs extra C code and API. map_coreop[".section_*"] = function(params) - if not params then return "name..." end - if #map_sections > 0 then werror("duplicate section definition") end - wflush() - for sn,name in ipairs(params) do - local opname = "."..name.."_0" - if not match(name, "^[%a][%w_]*$") or - map_op[opname] or map_op["."..name.."_*"] then - werror("bad section name `"..name.."'") - end - map_sections[#map_sections+1] = name - wline(format("#define DASM_SECTION_%s\t%d", upper(name), sn-1)) - map_op[opname] = function(params) g_arch.section(sn-1) end - end - wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections)) + if not params then + return "name..." + end + if #map_sections > 0 then + werror("duplicate section definition") + end + wflush() + for sn, name in ipairs(params) do + local opname = "." .. name .. "_0" + if not match(name, "^[%a][%w_]*$") or + map_op[opname] or map_op["." .. name .. "_*"] then + werror("bad section name `" .. name .. "'") + end + map_sections[#map_sections + 1] = name + wline(format("#define DASM_SECTION_%s\t%d", upper(name), sn - 1)) + map_op[opname] = function(params) + g_arch.section(sn - 1) + end + end + wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections)) end -- Dump all sections. local function dumpsections(out, lvl) - out:write("Sections:\n") - for _,name in ipairs(map_sections) do - out:write(format(" %s\n", name)) - end - out:write("\n") + out:write("Sections:\n") + for _, name in ipairs(map_sections) do + out:write(format(" %s\n", name)) + end + out:write("\n") end ------------------------------------------------------------------------------ +-- Replacement for customized Lua, which lacks the package library. +local prefix = "" +if not require then + function require(name) + local fp = assert(io.open(prefix .. name .. ".lua")) + local s = fp:read("*a") + assert(fp:close()) + return assert(loadstring(s, "@" .. name .. ".lua"))() + end +end + -- Load architecture-specific module. local function loadarch(arch) - if not match(arch, "^[%w_]+$") then return "bad arch name" end - local ok, m_arch = pcall(require, "dasm_"..arch) - if not ok then return "cannot load module: "..m_arch end - g_arch = m_arch - wflush = m_arch.passcb(wline, werror, wfatal, wwarn) - m_arch.setup(arch, g_opt) - map_op, map_def = m_arch.mergemaps(map_coreop, map_def) + if not match(arch, "^[%w_]+$") then + return "bad arch name" + end + local ok, m_arch = pcall(require, "dasm_" .. arch) + if not ok then + return "cannot load module: " .. m_arch + end + g_arch = m_arch + wflush = m_arch.passcb(wline, werror, wfatal, wwarn) + m_arch.setup(arch, g_opt) + map_op, map_def = m_arch.mergemaps(map_coreop, map_def) end -- Dump architecture description. function opt_map.dumparch(args) - local name = optparam(args) - if not g_arch then - local err = loadarch(name) - if err then opterror(err) end - end - - local t = {} - for name in pairs(map_coreop) do t[#t+1] = name end - for name in pairs(map_op) do t[#t+1] = name end - sort(t) - - local out = stdout - local _arch = g_arch._info - out:write(format("%s version %s, released %s, %s\n", - _info.name, _info.version, _info.release, _info.url)) - g_arch.dumparch(out) - - local pseudo = true - out:write("Pseudo-Opcodes:\n") - for _,sname in ipairs(t) do - local name, nparam = match(sname, "^(.+)_([0-9%*])$") - if name then - if pseudo and sub(name, 1, 1) ~= "." then - out:write("\nOpcodes:\n") - pseudo = false - end - local f = map_op[sname] - local s - if nparam ~= "*" then nparam = nparam + 0 end - if nparam == 0 then - s = "" - elseif type(f) == "string" then - s = map_op[".template__"](nil, f, nparam) - else - s = f(nil, nparam) - end - if type(s) == "table" then - for _,s2 in ipairs(s) do - out:write(format(" %-12s %s\n", name, s2)) - end - else - out:write(format(" %-12s %s\n", name, s)) - end - end - end - out:write("\n") - exit(0) + local name = optparam(args) + if not g_arch then + local err = loadarch(name) + if err then + opterror(err) + end + end + + local t = {} + for name in pairs(map_coreop) do + t[#t + 1] = name + end + for name in pairs(map_op) do + t[#t + 1] = name + end + sort(t) + + local out = stdout + local _arch = g_arch._info + out:write(format("%s version %s, released %s, %s\n", + _info.name, _info.version, _info.release, _info.url)) + g_arch.dumparch(out) + + local pseudo = true + out:write("Pseudo-Opcodes:\n") + for _, sname in ipairs(t) do + local name, nparam = match(sname, "^(.+)_([0-9%*])$") + if name then + if pseudo and sub(name, 1, 1) ~= "." then + out:write("\nOpcodes:\n") + pseudo = false + end + local f = map_op[sname] + local s + if nparam ~= "*" then + nparam = nparam + 0 + end + if nparam == 0 then + s = "" + elseif type(f) == "string" then + s = map_op[".template__"](nil, f, nparam) + else + s = f(nil, nparam) + end + if type(s) == "table" then + for _, s2 in ipairs(s) do + out:write(format(" %-12s %s\n", name, s2)) + end + else + out:write(format(" %-12s %s\n", name, s)) + end + end + end + out:write("\n") + exit(0) end -- Pseudo-opcode to set the architecture. -- Only initially available (map_op is replaced when called). map_op[".arch_1"] = function(params) - if not params then return "name" end - local err = loadarch(params[1]) - if err then wfatal(err) end + if not params then + return "name" + end + local err = loadarch(params[1]) + if err then + wfatal(err) + end + wline(format("#if DASM_VERSION != %d", _info.vernum)) + wline('#error "Version mismatch between DynASM and included encoding engine"') + wline("#endif") end -- Dummy .arch pseudo-opcode to improve the error report. map_coreop[".arch_1"] = function(params) - if not params then return "name" end - wfatal("duplicate .arch statement") + if not params then + return "name" + end + wfatal("duplicate .arch statement") end ------------------------------------------------------------------------------ -- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'. map_coreop[".nop_*"] = function(params) - if not params then return "[ignored...]" end + if not params then + return "[ignored...]" + end end -- Pseudo-opcodes to raise errors. map_coreop[".error_1"] = function(params) - if not params then return "message" end - werror(params[1]) + if not params then + return "message" + end + werror(params[1]) end map_coreop[".fatal_1"] = function(params) - if not params then return "message" end - wfatal(params[1]) + if not params then + return "message" + end + wfatal(params[1]) end -- Dump all user defined elements. local function dumpdef(out) - local lvl = g_opt.dumpdef - if lvl == 0 then return end - dumpsections(out, lvl) - dumpdefines(out, lvl) - if g_arch then g_arch.dumpdef(out, lvl) end - dumpmacros(out, lvl) - dumpcaptures(out, lvl) + local lvl = g_opt.dumpdef + if lvl == 0 then + return + end + dumpsections(out, lvl) + dumpdefines(out, lvl) + if g_arch then + g_arch.dumpdef(out, lvl) + end + dumpmacros(out, lvl) + dumpcaptures(out, lvl) end ------------------------------------------------------------------------------ @@ -735,138 +845,163 @@ end local splitlvl local function splitstmt_one(c) - if c == "(" then - splitlvl = ")"..splitlvl - elseif c == "[" then - splitlvl = "]"..splitlvl - elseif c == "{" then - splitlvl = "}"..splitlvl - elseif c == ")" or c == "]" or c == "}" then - if sub(splitlvl, 1, 1) ~= c then werror("unbalanced (), [] or {}") end - splitlvl = sub(splitlvl, 2) - elseif splitlvl == "" then - return " \0 " - end - return c + if c == "(" then + splitlvl = ")" .. splitlvl + elseif c == "[" then + splitlvl = "]" .. splitlvl + elseif c == "{" then + splitlvl = "}" .. splitlvl + elseif c == ")" or c == "]" or c == "}" then + if sub(splitlvl, 1, 1) ~= c then + werror("unbalanced (), [] or {}") + end + splitlvl = sub(splitlvl, 2) + elseif splitlvl == "" then + return " \0 " + end + return c end -- Split statement into (pseudo-)opcode and params. local function splitstmt(stmt) - -- Convert label with trailing-colon into .label statement. - local label = match(stmt, "^%s*(.+):%s*$") - if label then return ".label", {label} end + -- Convert label with trailing-colon into .label statement. + local label = match(stmt, "^%s*(.+):%s*$") + if label then + return ".label", { label } + end - -- Split at commas and equal signs, but obey parentheses and brackets. - splitlvl = "" - stmt = gsub(stmt, "[,%(%)%[%]{}]", splitstmt_one) - if splitlvl ~= "" then werror("unbalanced () or []") end + -- Split at commas and equal signs, but obey parentheses and brackets. + splitlvl = "" + stmt = gsub(stmt, "[,%(%)%[%]{}]", splitstmt_one) + if splitlvl ~= "" then + werror("unbalanced () or []") + end - -- Split off opcode. - local op, other = match(stmt, "^%s*([^%s%z]+)%s*(.*)$") - if not op then werror("bad statement syntax") end + -- Split off opcode. + local op, other = match(stmt, "^%s*([^%s%z]+)%s*(.*)$") + if not op then + werror("bad statement syntax") + end - -- Split parameters. - local params = {} - for p in gmatch(other, "%s*(%Z+)%z?") do - params[#params+1] = gsub(p, "%s+$", "") - end - if #params > 16 then werror("too many parameters") end + -- Split parameters. + local params = {} + for p in gmatch(other, "%s*(%Z+)%z?") do + params[#params + 1] = gsub(p, "%s+$", "") + end + if #params > 16 then + werror("too many parameters") + end - params.op = op - return op, params + params.op = op + return op, params end -- Process a single statement. dostmt = function(stmt) - -- Ignore empty statements. - if match(stmt, "^%s*$") then return end + -- Ignore empty statements. + if match(stmt, "^%s*$") then + return + end - -- Capture macro defs before substitution. - if mac_capture then return mac_capture(stmt) end - stmt = definesubst(stmt) + -- Capture macro defs before substitution. + if mac_capture then + return mac_capture(stmt) + end - -- Emit C code without parsing the line. - if sub(stmt, 1, 1) == "|" then - local tail = sub(stmt, 2) - wflush() - if sub(tail, 1, 2) == "//" then wcomment(tail) else wline(tail, true) end - return - end - - -- Split into (pseudo-)opcode and params. - local op, params = splitstmt(stmt) - - -- Get opcode handler (matching # of parameters or generic handler). - local f = map_op[op.."_"..#params] or map_op[op.."_*"] - if not f then - if not g_arch then wfatal("first statement must be .arch") end - -- Improve error report. - for i=0,9 do - if map_op[op.."_"..i] then - werror("wrong number of parameters for `"..op.."'") - end - end - werror("unknown statement `"..op.."'") - end - - -- Call opcode handler or special handler for template strings. - if type(f) == "string" then - map_op[".template__"](params, f) - else - f(params) - end + stmt = definesubst(stmt) + -- Emit C code without parsing the line. + if sub(stmt, 1, 1) == "|" then + local tail = sub(stmt, 2) + wflush() + if sub(tail, 1, 2) == "//" then + wcomment(tail) + else + wline(tail, true) + end + return + end + + -- Split into (pseudo-)opcode and params. + local op, params = splitstmt(stmt) + + -- Get opcode handler (matching # of parameters or generic handler). + local f = map_op[op .. "_" .. #params] or map_op[op .. "_*"] + + if not f then + if not g_arch then + wfatal("first statement must be .arch") + end + -- Improve error report. + for i = 0, 9 do + if map_op[op .. "_" .. i] then + werror("wrong number of parameters for `" .. op .. "'") + end + end + werror("unknown statement `" .. op .. "'") + end + + -- Call opcode handler or special handler for template strings. + if type(f) == "string" then + map_op[".template__"](params, f) + else + f(params) + end end -- Process a single line. local function doline(line) - if g_opt.flushline then wflush() end + if g_opt.flushline then + wflush() + end - -- Assembler line? - local indent, aline = match(line, "^(%s*)%|(.*)$") - if not aline then - -- No, plain C code line, need to flush first. - wflush() - wsync() - wline(line, false) - return - end - - g_indent = indent -- Remember current line indentation. - - -- Emit C code (even from macros). Avoids echo and line parsing. - if sub(aline, 1, 1) == "|" then - if not mac_capture then - wsync() - elseif g_opt.comment then - wsync() - wcomment(aline) - end - dostmt(aline) - return - end - - -- Echo assembler line as a comment. - if g_opt.comment then - wsync() - wcomment(aline) - end - - -- Strip assembler comments. - aline = gsub(aline, "//.*$", "") - - -- Split line into statements at semicolons. - if match(aline, ";") then - for stmt in gmatch(aline, "[^;]+") do dostmt(stmt) end - else - dostmt(aline) - end + -- Assembler line? + local indent, aline = match(line, "^(%s*)%|(.*)$") + if not aline then + -- No, plain C code line, need to flush first. + wflush() + wsync() + wline(line, false) + return + end + + g_indent = indent -- Remember current line indentation. + + -- Emit C code (even from macros). Avoids echo and line parsing. + if sub(aline, 1, 1) == "|" then + if not mac_capture then + wsync() + elseif g_opt.comment then + wsync() + wcomment(aline) + end + dostmt(aline) + return + end + + -- Echo assembler line as a comment. + if g_opt.comment then + wsync() + wcomment(aline) + end + + -- Strip assembler comments. + aline = gsub(aline, "//.*$", "") + + -- Split line into statements at semicolons. + if match(aline, ";") then + for stmt in gmatch(aline, "[^;]+") do + dostmt(stmt) + end + else + dostmt(aline) + end end ------------------------------------------------------------------------------ -- Write DynASM header. local function dasmhead(out) - out:write(format([[ + out:write(format([[ /* ** This file has been pre-processed with DynASM. ** %s @@ -874,103 +1009,101 @@ local function dasmhead(out) ** DO NOT EDIT! The original file is in "%s". */ -#if DASM_VERSION != %d -#error "Version mismatch between DynASM and included encoding engine" -#endif - ]], _info.url, - _info.version, g_arch._info.arch, g_arch._info.version, - g_fname, _info.vernum)) + _info.version, g_arch._info.arch, g_arch._info.version, + g_fname)) end -- Read input file. readfile = function(fin) - g_indent = "" - g_lineno = 0 - g_synclineno = -1 - - -- Process all lines. - for line in fin:lines() do - g_lineno = g_lineno + 1 - g_curline = line - local ok, err = pcall(doline, line) - if not ok and wprinterr(err, "\n") then return true end - end - wflush() + g_indent = "" + g_lineno = 0 + g_synclineno = -1 + + -- Process all lines. + for line in fin:lines() do + g_lineno = g_lineno + 1 + g_curline = line + local ok, err = pcall(doline, line) + if not ok and wprinterr(err, "\n") then + return true + end + end + wflush() - -- Close input file. - assert(fin == stdin or fin:close()) + -- Close input file. + assert(fin == stdin or fin:close()) end -- Write output file. local function writefile(outfile) - local fout + local fout - -- Open output file. - if outfile == nil or outfile == "-" then - fout = stdout - else - fout = assert(io.open(outfile, "w")) - end + -- Open output file. + if outfile == nil or outfile == "-" then + fout = stdout + else + fout = assert(io.open(outfile, "w")) + end - -- Write all buffered lines - wdumplines(fout, g_wbuffer) + -- Write all buffered lines + wdumplines(fout, g_wbuffer) - -- Close output file. - assert(fout == stdout or fout:close()) + -- Close output file. + assert(fout == stdout or fout:close()) - -- Optionally dump definitions. - dumpdef(fout == stdout and stderr or stdout) + -- Optionally dump definitions. + dumpdef(fout == stdout and stderr or stdout) end -- Translate an input file to an output file. local function translate(infile, outfile) - g_wbuffer = {} - g_indent = "" - g_lineno = 0 - g_synclineno = -1 - - -- Put header. - wline(dasmhead) - - -- Read input file. - local fin - if infile == "-" then - g_fname = "(stdin)" - fin = stdin - else - g_fname = infile - fin = assert(io.open(infile, "r")) - end - readfile(fin) - - -- Check for errors. - if not g_arch then - wprinterr(g_fname, ":*: error: missing .arch directive\n") - end - checkconds() - checkmacros() - checkcaptures() - - if g_errcount ~= 0 then - stderr:write(g_fname, ":*: info: ", g_errcount, " error", - (type(g_errcount) == "number" and g_errcount > 1) and "s" or "", - " in input file -- no output file generated.\n") - dumpdef(stderr) - exit(1) - end + g_wbuffer = {} + g_indent = "" + g_lineno = 0 + g_synclineno = -1 + + -- Put header. + wline(dasmhead) + + -- Read input file. + local fin + if infile == "-" then + g_fname = "(stdin)" + fin = stdin + else + g_fname = infile + fin = assert(io.open(infile, "r")) + end + readfile(fin) - -- Write output file. - writefile(outfile) + -- Check for errors. + if not g_arch then + wprinterr(g_fname, ":*: error: missing .arch directive\n") + end + checkconds() + checkmacros() + checkcaptures() + + if g_errcount ~= 0 then + stderr:write(g_fname, ":*: info: ", g_errcount, " error", + (type(g_errcount) == "number" and g_errcount > 1) and "s" or "", + " in input file -- no output file generated.\n") + dumpdef(stderr) + exit(1) + end + + -- Write output file. + writefile(outfile) end ------------------------------------------------------------------------------ -- Print help text. function opt_map.help() - stdout:write("DynASM -- ", _info.description, ".\n") - stdout:write("DynASM ", _info.version, " ", _info.release, " ", _info.url, "\n") - stdout:write[[ + stdout:write("DynASM -- ", _info.description, ".\n") + stdout:write("DynASM ", _info.version, " ", _info.release, " ", _info.url, "\n") + stdout:write [[ Usage: dynasm [OPTION]... INFILE.dasc|- @@ -988,96 +1121,120 @@ Usage: dynasm [OPTION]... INFILE.dasc|- -L, --nolineno Suppress CPP line number information in output. -F, --flushline Flush action list for every line. - -E, --vserror Use Visual Studio style errors file(line) vs file:line - -D NAME[=SUBST] Define a substitution. -U NAME Undefine a substitution. -P, --dumpdef Dump defines, macros, etc. Repeat for more output. -A, --dumparch ARCH Load architecture ARCH and dump description. ]] - exit(0) + exit(0) end -- Print version information. function opt_map.version() - stdout:write(format("%s version %s, released %s\n%s\n\n%s", - _info.name, _info.version, _info.release, _info.url, _info.copyright)) - exit(0) + stdout:write(format("%s version %s, released %s\n%s\n\n%s", + _info.name, _info.version, _info.release, _info.url, _info.copyright)) + exit(0) end -- Misc. options. -function opt_map.outfile(args) g_opt.outfile = optparam(args) end -function opt_map.include(args) insert(g_opt.include, 1, optparam(args)) end -function opt_map.ccomment() g_opt.comment = "/*|"; g_opt.endcomment = " */" end -function opt_map.cppcomment() g_opt.comment = "//|"; g_opt.endcomment = "" end -function opt_map.nocomment() g_opt.comment = false end -function opt_map.maccomment() g_opt.maccomment = true end -function opt_map.nolineno() g_opt.cpp = false end -function opt_map.flushline() g_opt.flushline = true end -function opt_map.vserror() g_opt.vserror = true end -function opt_map.dumpdef() g_opt.dumpdef = g_opt.dumpdef + 1 end +function opt_map.outfile(args) + g_opt.outfile = optparam(args) +end +function opt_map.include(args) + insert(g_opt.include, 1, optparam(args)) +end +function opt_map.ccomment() + g_opt.comment = "/*|"; + g_opt.endcomment = " */" +end +function opt_map.cppcomment() + g_opt.comment = "//|"; + g_opt.endcomment = "" +end +function opt_map.nocomment() + g_opt.comment = false +end +function opt_map.maccomment() + g_opt.maccomment = true +end +function opt_map.nolineno() + g_opt.cpp = false +end +function opt_map.flushline() + g_opt.flushline = true +end +function opt_map.dumpdef() + g_opt.dumpdef = g_opt.dumpdef + 1 +end ------------------------------------------------------------------------------ -- Short aliases for long options. local opt_alias = { - h = "help", ["?"] = "help", V = "version", - o = "outfile", I = "include", - c = "ccomment", C = "cppcomment", N = "nocomment", M = "maccomment", - L = "nolineno", F = "flushline", - E = "vserror", - P = "dumpdef", A = "dumparch", + h = "help", ["?"] = "help", V = "version", + o = "outfile", I = "include", + c = "ccomment", C = "cppcomment", N = "nocomment", M = "maccomment", + L = "nolineno", F = "flushline", + P = "dumpdef", A = "dumparch", } -- Parse single option. local function parseopt(opt, args) - opt_current = #opt == 1 and "-"..opt or "--"..opt - local f = opt_map[opt] or opt_map[opt_alias[opt]] - if not f then - opterror("unrecognized option `", opt_current, "'. Try `--help'.\n") - end - f(args) + opt_current = #opt == 1 and "-" .. opt or "--" .. opt + local f = opt_map[opt] or opt_map[opt_alias[opt]] + if not f then + opterror("unrecognized option `", opt_current, "'. Try `--help'.\n") + end + f(args) end -- Parse arguments. local function parseargs(args) - -- Default options. - g_opt.comment = "//|" - g_opt.endcomment = "" - g_opt.cpp = true - g_opt.dumpdef = 0 - g_opt.include = { "" } - - -- Process all option arguments. - args.argn = 1 - repeat - local a = args[args.argn] - if not a then break end - local lopt, opt = match(a, "^%-(%-?)(.+)") - if not opt then break end - args.argn = args.argn + 1 - if lopt == "" then - -- Loop through short options. - for o in gmatch(opt, ".") do parseopt(o, args) end - else - -- Long option. - parseopt(opt, args) - end - until false - - -- Check for proper number of arguments. - local nargs = #args - args.argn + 1 - if nargs ~= 1 then - if nargs == 0 then - if g_opt.dumpdef > 0 then return dumpdef(stdout) end + -- Default options. + g_opt.comment = "//|" + g_opt.endcomment = "" + g_opt.cpp = true + g_opt.dumpdef = 0 + g_opt.include = { "" } + + -- Process all option arguments. + args.argn = 1 + repeat + local a = args[args.argn] + if not a then + break + end + local lopt, opt = match(a, "^%-(%-?)(.+)") + if not opt then + break + end + args.argn = args.argn + 1 + if lopt == "" then + -- Loop through short options. + for o in gmatch(opt, ".") do + parseopt(o, args) + end + else + -- Long option. + parseopt(opt, args) + end + until false + + -- Check for proper number of arguments. + local nargs = #args - args.argn + 1 + if nargs ~= 1 then + if nargs == 0 then + if g_opt.dumpdef > 0 then + return dumpdef(stdout) + end + end + opt_map.help() end - opt_map.help() - end - -- Translate a single input file to a single output file - -- TODO: Handle multiple files? - translate(args[args.argn], g_opt.outfile) + -- Translate a single input file to a single output file + -- TODO: Handle multiple files? + translate(args[args.argn], g_opt.outfile) end ------------------------------------------------------------------------------ @@ -1085,12 +1242,14 @@ end -- Add the directory dynasm.lua resides in to the Lua module search path. local arg = arg if arg and arg[0] then - local prefix = match(arg[0], "^(.*[/\\])") - if prefix then package.path = prefix.."?.lua;"..package.path end + prefix = match(arg[0], "^(.*[/\\])") + if package and prefix then + package.path = prefix .. "?.lua;" .. package.path + end end -- Start DynASM. -parseargs{...} +parseargs { ... } ------------------------------------------------------------------------------ diff --git a/texk/web2c/luatexdir/luaffi/fake_dlfcn.c b/texk/web2c/luatexdir/luaffi/fake_dlfcn.c new file mode 100644 index 0000000000..6ee97b827a --- /dev/null +++ b/texk/web2c/luatexdir/luaffi/fake_dlfcn.c @@ -0,0 +1,165 @@ + + +#include "fake_dlfcn.h" + +#include +#include +#include +#include +#include + +#define TAG_NAME "Osl_DL" +#ifdef NDEBUG +#define log_info(fmt,args...) +#define log_err(fmt,args...) +#else +#define log_info(fmt,args...) __android_log_print(ANDROID_LOG_INFO, TAG_NAME, (const char *) fmt, ##args) +#define log_err(fmt,args...) __android_log_print(ANDROID_LOG_ERROR, TAG_NAME, (const char *) fmt, ##args) +#endif +//#ifdef LOG_DBG +#define log_dbg log_info +//#else +//#define log_dbg(...) +//#endif + +#ifdef __LP64__ +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#else +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#endif + +struct ctx { + void *load_addr; + void *dynstr; + void *dynsym; + int nsyms; + off_t bias; +}; + +//extern "C" { +void fake_dlclose(void *handle) { + if (handle) { + struct ctx *ctx = (struct ctx *) handle; + if (ctx->dynsym) free(ctx->dynsym); /* we're saving dynsym and dynstr */ + if (ctx->dynstr) free(ctx->dynstr); /* from library file just in case */ + free(ctx); + } +} + +/* flags are ignored */ + +void *fake_dlopen(const char *libpath, int flags) { + FILE *maps; + char buff[256]; + struct ctx *ctx = 0; + off_t load_addr, size; + int k, fd = -1, found = 0; + void *shoff; + Elf_Ehdr *elf = (Elf_Ehdr *) MAP_FAILED; + +#define fatal(fmt, args...) do { log_err(fmt,##args); goto err_exit; } while(0) + + maps = fopen("/proc/self/maps", "r"); + if (!maps) fatal("failed to open maps"); + + while (!found && fgets(buff, sizeof(buff), maps)) + if (strstr(buff, "r-xp") && strstr(buff, libpath)) found = 1; + + fclose(maps); + + if (!found) fatal("%s not found in my userspace", libpath); + + if (sscanf(buff, "%lx", &load_addr) != 1) + fatal("failed to read load address for %s", libpath); + + log_info("%s loaded in Android at 0x%08lx", libpath, load_addr); + + /* Now, mmap the same library once again */ + + fd = open(libpath, O_RDONLY); + if (fd < 0) fatal("failed to open %s", libpath); + + size = lseek(fd, 0, SEEK_END); + if (size <= 0) fatal("lseek() failed for %s", libpath); + + elf = (Elf_Ehdr *) mmap(0, size, PROT_READ, MAP_SHARED, fd, 0); + close(fd); + fd = -1; + + if (elf == MAP_FAILED) fatal("mmap() failed for %s", libpath); + + ctx = (struct ctx *) calloc(1, sizeof(struct ctx)); + if (!ctx) fatal("no memory for %s", libpath); + + ctx->load_addr = (void *) load_addr; + shoff = ((void *) elf) + elf->e_shoff; + for (k = 0; k < elf->e_shnum; k++, shoff += elf->e_shentsize) { + + Elf_Shdr *sh = (Elf_Shdr *) shoff; + //log_dbg("%s: k=%d shdr=%p type=%x", __func__, k, sh, sh->sh_type); + + switch (sh->sh_type) { + + case SHT_DYNSYM: + if (ctx->dynsym) fatal("%s: duplicate DYNSYM sections", libpath); /* .dynsym */ + ctx->dynsym = malloc(sh->sh_size); + if (!ctx->dynsym) fatal("%s: no memory for .dynsym", libpath); + memcpy(ctx->dynsym, ((void *) elf) + sh->sh_offset, sh->sh_size); + ctx->nsyms = (sh->sh_size / sizeof(Elf_Sym)); + break; + + case SHT_STRTAB: + if (ctx->dynstr) break; /* .dynstr is guaranteed to be the first STRTAB */ + ctx->dynstr = malloc(sh->sh_size); + if (!ctx->dynstr) fatal("%s: no memory for .dynstr", libpath); + memcpy(ctx->dynstr, ((void *) elf) + sh->sh_offset, sh->sh_size); + break; + + case SHT_PROGBITS: + if (!ctx->dynstr || !ctx->dynsym) break; + /* won't even bother checking against the section name */ + ctx->bias = (off_t) sh->sh_addr - (off_t) sh->sh_offset; + k = elf->e_shnum; /* exit for */ + break; + } + } + + munmap(elf, size); + elf = 0; + + if (!ctx->dynstr || !ctx->dynsym) fatal("dynamic sections not found in %s", libpath); + +#undef fatal + + log_dbg("%s: ok, dynsym = %p, dynstr = %p", libpath, ctx->dynsym, ctx->dynstr); + + return ctx; + + err_exit: + if (fd >= 0) close(fd); + if (elf != MAP_FAILED) munmap(elf, size); + fake_dlclose(ctx); + return 0; +} + +void *fake_dlsym(void *handle, const char *name) { + int k; + struct ctx *ctx = (struct ctx *) handle; + Elf_Sym *sym = (Elf_Sym *) ctx->dynsym; + char *strings = (char *) ctx->dynstr; + + for (k = 0; k < ctx->nsyms; k++, sym++) + if (strcmp(strings + sym->st_name, name) == 0) { + /* NB: sym->st_value is an offset into the section for relocatables, + but a VMA for shared libs or exe files, so we have to subtract the bias */ + void *ret = ctx->load_addr + sym->st_value - ctx->bias; + log_info("%s found at %p", name, ret); + return ret; + } + return 0; +} +//} \ No newline at end of file diff --git a/texk/web2c/luatexdir/luaffi/fake_dlfcn.h b/texk/web2c/luatexdir/luaffi/fake_dlfcn.h new file mode 100644 index 0000000000..f2eae6c959 --- /dev/null +++ b/texk/web2c/luatexdir/luaffi/fake_dlfcn.h @@ -0,0 +1,20 @@ + + +#ifndef HOOKMANAGER_FAKE_DLFCN_H +#define HOOKMANAGER_FAKE_DLFCN_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +__attribute__ ((visibility ("default"))) void *fake_dlopen(const char *libpath, int flags); +__attribute__ ((visibility ("default"))) void fake_dlclose(void* handle); +__attribute__ ((visibility ("default"))) void *fake_dlsym(void *handle, const char *name); +#ifdef __cplusplus +}; +#endif +#endif //HOOKMANAGER_FAKE_DLFCN_H diff --git a/texk/web2c/luatexdir/luaffi/ffi.c b/texk/web2c/luatexdir/luaffi/ffi.c index cbd57c260e..7ead6af3d2 100644 --- a/texk/web2c/luatexdir/luaffi/ffi.c +++ b/texk/web2c/luatexdir/luaffi/ffi.c @@ -8,6 +8,7 @@ */ #include "ffi.h" #include +#include #include /* Set to 1 to get extra debugging on print */ @@ -27,18 +28,56 @@ int abi_key; int next_unnamed_key; int niluv_key; int asmname_key; +typedef enum { + TM_INDEX=1, + TM_NEWINDEX, + TM_CALL, + TM_NEW, + TM_GC, + TM_TO_STRING, + TM_ADD, + TM_SUB, + TM_MUL, + TM_MOD, + TM_POW, + TM_DIV, + TM_IDIV, + /*TM_BAND, + TM_BOR, + TM_BXOR, + TM_SHL, + TM_SHR, + TM_BNOT,*/ + TM_UNM, + TM_EQ, + TM_LT, + TM_LE, + TM_CONCAT, + TM_LEN, + TM_PAIRS, + TM_IPAIRS, + TM_END /* number of elements in the enum */ +} TMK; +static const char* tm_fields[]={NULL, + "__index","__newindex","__call","__new", + "__gc","__tostring","__add","__sub", "__mul", + "__mod","__pow","__div","__idiv", "__unm","__eq","__lt","__le","__concat", + "__len", "__pairs","__ipairs"}; void push_upval(lua_State* L, int* key) { - lua_pushlightuserdata(L, key); - lua_rawget(L, LUA_REGISTRYINDEX); + lua_rawgetp(L, LUA_REGISTRYINDEX,key); } void set_upval(lua_State* L, int* key) { +#if LUA_VERSION_NUM<502 lua_pushlightuserdata(L, key); lua_insert(L, -2); lua_rawset(L, LUA_REGISTRYINDEX); +#else + lua_rawsetp(L,LUA_REGISTRYINDEX,key); +#endif } int equals_upval(lua_State* L, int idx, int* key) @@ -71,6 +110,10 @@ static int type_error(lua_State* L, int idx, const char* to_type, int to_usr, co to_usr = lua_absindex(L, to_usr); } + if(lua_isnone(L,idx)){ + luaL_error(L,"incorrect number of arguments"); + } + idx = lua_absindex(L, idx); luaL_buffinit(L, &B); @@ -102,12 +145,11 @@ static int type_error(lua_State* L, int idx, const char* to_type, int to_usr, co static void* userdata_toptr(lua_State* L, int idx) { void* ptr = lua_touserdata(L, idx); - int isfile; // check for FILE* lua_getmetatable(L, idx); luaL_getmetatable(L, LUA_FILEHANDLE); - isfile = lua_rawequal(L, -1, -2); + int isfile = lua_rawequal(L, -1, -2); lua_pop(L, 2); if (isfile) { @@ -159,7 +201,7 @@ static int64_t check_intptr(lua_State* L, int idx, void* p, struct ctype* ct) ct->base_size = 8; ct->type = INT64_TYPE; ct->is_defined = 1; - ret = luaL_checknumber(L, idx); + ret = (int64_t) luaL_checknumber(L, idx); return ret; } else if (ct->pointers) { @@ -193,9 +235,6 @@ static int get_cfunction_address(lua_State* L, int idx, cfunction* addr); #define TO_NUMBER(TYPE, ALLOW_POINTERS, LUA_TONUMBER) \ TYPE ret = 0; \ - void* p; \ - struct ctype ct; \ - cfunction f; \ \ switch (lua_type(L, idx)) { \ case LUA_TBOOLEAN: \ @@ -220,17 +259,20 @@ static int get_cfunction_address(lua_State* L, int idx, cfunction* addr); ret = (TYPE) (intptr_t) lua_topointer(L, idx); \ break; \ \ - case LUA_TFUNCTION: \ + case LUA_TFUNCTION:{ \ if (!ALLOW_POINTERS) { \ type_error(L, idx, #TYPE, 0, NULL); \ } \ + cfunction f; \ if (!get_cfunction_address(L, idx, &f)) { \ type_error(L, idx, #TYPE, 0, NULL); \ } \ ret = (TYPE) (intptr_t) f; \ break; \ - \ - case LUA_TUSERDATA: \ + } \ + case LUA_TUSERDATA: { \ + void* p; \ + struct ctype ct; \ p = to_cdata(L, idx, &ct); \ \ if (ct.type == INVALID_TYPE) { \ @@ -256,7 +298,7 @@ static int get_cfunction_address(lua_State* L, int idx, cfunction* addr); } \ lua_pop(L, 1); \ break; \ - \ + } \ case LUA_TNIL: \ ret = (TYPE) 0; \ break; \ @@ -266,11 +308,19 @@ static int get_cfunction_address(lua_State* L, int idx, cfunction* addr); } \ static int64_t cast_int64(lua_State* L, int idx, int is_cast) -{ TO_NUMBER(int64_t, is_cast, lua_tointeger); return ret; } - -static uint64_t cast_uint64(lua_State* L, int idx, int is_cast) -{ TO_NUMBER(uint64_t, is_cast, lua_tointeger); return ret; } +{ +#if LUA_VERSION_NUM>=503 + TO_NUMBER(int64_t, is_cast, lua_tointeger); +#else + TO_NUMBER(int64_t, is_cast, lua_tonumber); +#endif + return ret; +} +static ALWAYS_INLINE uint64_t cast_uint64(lua_State* L, int idx, int is_cast) +{ + return (uint64_t)cast_int64(L,idx,is_cast); +} int32_t check_int32(lua_State* L, int idx) { return (int32_t) cast_int64(L, idx, 0); } @@ -287,7 +337,7 @@ double check_double(lua_State* L, int idx) { TO_NUMBER(double, 0, lua_tonumber); return ret; } float check_float(lua_State* L, int idx) -{ TO_NUMBER(double, 0, lua_tonumber); return ret; } +{ TO_NUMBER(float, 0, lua_tonumber); return ret; } uintptr_t check_uintptr(lua_State* L, int idx) { TO_NUMBER(uintptr_t, 1, lua_tointeger); return ret; } @@ -343,7 +393,14 @@ complex_double check_complex_double(lua_State* L, int idx) complex_float check_complex_float(lua_State* L, int idx) { complex_double d = check_complex_double(L, idx); - return mk_complex_float(creal(d), cimag(d)); +#ifdef HAVE_COMPLEX + return (complex_float)d; +#else + return (complex_float) { d.real, d.imag }; +#endif + + + } static size_t unpack_vararg(lua_State* L, int i, char* to) @@ -357,8 +414,20 @@ static size_t unpack_vararg(lua_State* L, int i, char* to) return sizeof(int); case LUA_TNUMBER: - *(double*) to = lua_tonumber(L, i); // TODO in Lua 5.3: lua_tointeger sometimes should be here - return sizeof(double); +//IOS doesn't need alignment +#if defined(ARCH_ARM)&&!defined(TARGET_OS_IPHONE) +#define CHECK_ALIGN(CODE,RET_SIZE)\ + {int align=(uintptr_t)(to)&0b111?4:0;\ + to+=align;\ + {CODE;}\ + return (RET_SIZE)+align; } +#else +#define CHECK_ALIGN(CODE,RET_SIZE){\ + {CODE;}\ + return (RET_SIZE);} +#endif + + CHECK_ALIGN({ *(double*)to = lua_tonumber(L, i); }, sizeof(double)); case LUA_TSTRING: *(const char**) to = lua_tostring(L, i); @@ -385,14 +454,13 @@ static size_t unpack_vararg(lua_State* L, int i, char* to) return sizeof(int32_t); } else if (ct.type == INT64_TYPE) { - *(int64_t*) to = *(int64_t*) p; - return sizeof(int64_t); - - } else if (ct.type == FUNCTION_PTR_TYPE) { - *(cfunction *) to = *(cfunction *)p; - return sizeof(cfunction); - } - + CHECK_ALIGN(*(int64_t*) to=*(int64_t*) p ,sizeof(int64_t)); + } else if (ct.type == DOUBLE_TYPE) { + CHECK_ALIGN(*(double*) to = *(double*) p ,sizeof(double)); + } else if (ct.type == FLOAT_TYPE) { + //float should be lifted to double in var arg + CHECK_ALIGN(*(double*) to = *(float*) p ,sizeof(double)); + } goto err; case LUA_TNIL: @@ -402,7 +470,7 @@ static size_t unpack_vararg(lua_State* L, int i, char* to) default: goto err; } - +#undef CHECK_ALIGN err: return type_error(L, i, "vararg", 0, NULL); } @@ -412,8 +480,41 @@ void unpack_varargs_stack(lua_State* L, int first, int last, char* to) int i; for (i = first; i <= last; i++) { - to += unpack_vararg(L, i, to); + size_t size = unpack_vararg(L, i, to); + to += size; + } +} + +int unpack_varargs_bound(lua_State*L ,int first,char* to,char* end){ + int i; + int64_t restore=*(int64_t*)end; + for (i = first;toend){ + *(int64_t*)end=restore;// restore if overlapped; + i--; + } } + return i; +} + +// complex arg is not supported +static ALWAYS_INLINE int isFloatArg(lua_State* L,int idx){ + int type = lua_type(L,idx); + if(type==LUA_TNUMBER){ + return 1; + }else if(type == LUA_TUSERDATA){ + const struct ctype* ct=get_ctype(L,idx); + if(ct&&(ct->type==FLOAT_TYPE||ct->type==DOUBLE_TYPE)){ + return 1; + } + } + return 0; +} + +static ALWAYS_INLINE int (max)(int a,int b){ + return a>b?a:b; } void unpack_varargs_stack_skip(lua_State* L, int first, int last, int ints_to_skip, int floats_to_skip, char* to) @@ -421,15 +522,18 @@ void unpack_varargs_stack_skip(lua_State* L, int first, int last, int ints_to_sk int i; for (i = first; i <= last; i++) { - int type = lua_type(L, i); - - if (type == LUA_TNUMBER && --floats_to_skip >= 0) { + int isFloat=isFloatArg(L,i); + if (isFloat && --floats_to_skip >= 0) { continue; - } else if (type != LUA_TNUMBER && --ints_to_skip >= 0) { + } else if (!isFloat&& --ints_to_skip >= 0) { continue; } - - to += unpack_vararg(L, i, to); + //as aapcs_aarch64 says and x64 implementation, arg in stack has a minimum alignment 8; +#if defined __LP64__ || defined(__amd64__) ||defined (_WIN64) + to += max(8,unpack_vararg(L,i,to)); +#else + to += unpack_vararg(L, i, to);//never occurs +#endif } } @@ -438,7 +542,7 @@ void unpack_varargs_float(lua_State* L, int first, int last, int max, char* to) int i; for (i = first; i <= last && max > 0; i++) { - if (lua_type(L, i) == LUA_TNUMBER) { + if (isFloatArg(L,i)) { unpack_vararg(L, i, to); to += sizeof(double); max--; @@ -451,7 +555,7 @@ void unpack_varargs_int(lua_State* L, int first, int last, int max, char* to) int i; for (i = first; i <= last && max > 0; i++) { - if (lua_type(L, i) != LUA_TNUMBER) { + if (!isFloatArg(L,i)) { unpack_vararg(L, i, to); to += sizeof(void*); max--; @@ -469,7 +573,7 @@ void unpack_varargs_reg(lua_State* L, int first, int last, char* to) } } -/* to_enum tries to convert a value at idx to the enum type indicated by to_ct +/* check_enum tries to convert a value at idx to the enum type indicated by to_ct * and uv to_usr. For strings this means it will do a string lookup for the * enum type. It leaves the stack unchanged. Will throw an error if the type * at idx can't be conerted. @@ -510,7 +614,7 @@ int32_t check_enum(lua_State* L, int idx, int to_usr, const struct ctype* to_ct) return type_error(L, idx, NULL, to_usr, to_ct); } -/* to_pointer tries converts a value at idx to a pointer. It fills out ct and +/* check_pointer tries converts a value at idx to a pointer. It fills out ct and * pushes the uv of the found type. It will throw a lua error if it can not * convert the value to a pointer. */ static void* check_pointer(lua_State* L, int idx, struct ctype* ct) @@ -527,12 +631,18 @@ static void* check_pointer(lua_State* L, int idx, struct ctype* ct) lua_pushnil(L); return NULL; - case LUA_TNUMBER: - ct->type = INTPTR_TYPE; - ct->is_unsigned = 1; - ct->pointers = 0; - lua_pushnil(L); - return (void*) (uintptr_t) lua_tonumber(L, idx); // TODO in Lua 5.3: maybe change to lua_tointeger + case LUA_TNUMBER:{ + double v=lua_tonumber(L,idx); + intptr_t intV=(intptr_t )v; + if(v==intV){ + ct->type = INTPTR_TYPE; + ct->is_unsigned = 1; + ct->pointers = 0; + lua_pushnil(L); + return (void*) intV; + } else break; + } + case LUA_TLIGHTUSERDATA: ct->type = VOID_TYPE; @@ -543,7 +653,7 @@ static void* check_pointer(lua_State* L, int idx, struct ctype* ct) case LUA_TSTRING: ct->type = INT8_TYPE; ct->pointers = 1; - ct->is_unsigned = IS_CHAR_UNSIGNED; + ct->is_unsigned = IS_CHAR_UNSIGNED?1:0; ct->is_array = 1; ct->base_size = 1; ct->const_mask = 2; @@ -570,15 +680,16 @@ static void* check_pointer(lua_State* L, int idx, struct ctype* ct) return NULL; } -static int is_void_ptr(const struct ctype* ct) +static ALWAYS_INLINE int is_void_ptr(const struct ctype* ct) { return ct->type == VOID_TYPE && ct->pointers == 1; } -static int is_same_type(lua_State* L, int usr1, int usr2, const struct ctype* t1, const struct ctype* t2) +static ALWAYS_INLINE int is_same_type(lua_State* L, int usr1, int usr2, const struct ctype* t1, const struct ctype* t2) { - if (t1->type != t2->type) { + if (t1->type != t2->type + ||(t1->pointers+t1->is_reference)!=(t2->pointers+t2->is_reference)) { return 0; } @@ -600,11 +711,21 @@ static int is_same_type(lua_State* L, int usr1, int usr2, const struct ctype* t1 } #endif - return lua_rawequal(L, usr1, usr2); + int ret= lua_rawequal(L, usr1, usr2); + return ret; } static void set_struct(lua_State* L, int idx, void* to, int to_usr, const struct ctype* tt, int check_pointers); +void* check_struct(lua_State*L,int idx, int to_usr,const struct ctype* ct) +{ + if(lua_type(L,idx)==LUA_TUSERDATA){ + return check_typed_pointer(L,idx,to_usr,ct); + } + void* p=push_cdata(L,to_usr,ct); + set_struct(L,idx,p,to_usr,ct,1); + return p; +} /* to_typed_pointer converts a value at idx to a type tt with target uv to_usr * checking all types. May push a temporary value so that it can create * structs on the fly. */ @@ -649,9 +770,6 @@ void* check_typed_pointer(lua_State* L, int idx, int to_usr, const struct ctype* /* the base type is different */ goto err; - } else if (tt->pointers != ft.pointers) { - goto err; - } else if (ft.const_mask & ~tt->const_mask) { /* for every const in from it must be in to, there are further rules * for const casting (see the c++ spec), but they are hard to test @@ -672,14 +790,10 @@ void* check_typed_pointer(lua_State* L, int idx, int to_usr, const struct ctype* * and returns 1 if it exists; otherwise returns 0 and nothing is pushed */ static int get_cfunction_address(lua_State* L, int idx, cfunction* addr) { - int top, n; - cfunction* f; if (!lua_isfunction(L, idx)) return 0; - top = lua_gettop(L); - // Get the last upvalue - n = 2; + int n = 2; while (lua_getupvalue(L, idx, n)) { lua_pop(L, 1); n++; @@ -705,7 +819,7 @@ static int get_cfunction_address(lua_State* L, int idx, cfunction* addr) * callback_mt */ - f = lua_touserdata(L, -3); + cfunction* f = lua_touserdata(L, -3); *addr = f[1]; lua_pop(L, 3); return 1; @@ -907,7 +1021,8 @@ static ptrdiff_t get_member(lua_State* L, int usr, const struct ctype* ct, struc return -1; } - *mt = *(const struct ctype*) lua_touserdata(L, -1); + const struct member_type *pmt = (const struct member_type*) lua_touserdata(L, -1); + *mt = pmt->ct; lua_getuservalue(L, -1); lua_replace(L, -2); @@ -925,8 +1040,7 @@ static ptrdiff_t get_member(lua_State* L, int usr, const struct ctype* ct, struc mt->variable_increment = ct->variable_increment; } - off = mt->offset; - mt->offset = 0; + off = pmt->offset; return off; } @@ -1192,7 +1306,6 @@ static int is_scalar(struct ctype* ct) static int should_pack(lua_State *L, int ct_usr, struct ctype* ct, int idx) { struct ctype argt; - int same; ct_usr = lua_absindex(L, ct_usr); if (IS_COMPLEX(ct->type)) { @@ -1207,7 +1320,7 @@ static int should_pack(lua_State *L, int ct_usr, struct ctype* ct, int idx) case LUA_TUSERDATA: // don't pack if the argument is a cdata with the same type to_cdata(L, idx, &argt); - same = is_same_type(L, ct_usr, -1, ct, &argt); + int same = is_same_type(L, ct_usr, -1, ct, &argt); lua_pop(L, 1); return !same; default: @@ -1217,7 +1330,7 @@ static int should_pack(lua_State *L, int ct_usr, struct ctype* ct, int idx) static int do_new(lua_State* L, int is_cast) { - int cargs, i, scalar; + int cargs, i; void* p; struct ctype ct; int check_ptrs = !is_cast; @@ -1259,8 +1372,7 @@ static int do_new(lua_State* L, int is_cast) lua_pushvalue(L, -3); /* user_mt.__gc */ - lua_pushliteral(L, "__gc"); - lua_rawget(L, -4); + lua_rawgeti(L, -3,TM_GC); lua_rawset(L, -3); /* gc_upval[cdata] = user_mt.__gc */ lua_pop(L, 2); /* user_mt and gc_upval */ @@ -1279,7 +1391,7 @@ static int do_new(lua_State* L, int is_cast) return 1; } - scalar = is_scalar(&ct); + int scalar = is_scalar(&ct); if (scalar && cargs > 1) { return luaL_error(L, "too many initializers"); } @@ -1317,8 +1429,7 @@ static int ctype_call(lua_State* L) check_ctype(L, 1, &ct); if (push_user_mt(L, -1, &ct)) { - lua_pushstring(L, "__new"); - lua_rawget(L, -2); + lua_rawgeti(L, -2,TM_NEW); if (!lua_isnil(L, -1)) { lua_insert(L, 1); // function at bottom of stack under args lua_pop(L, 2); @@ -1368,7 +1479,8 @@ static int ffi_alignof(lua_State* L) static int ffi_offsetof(lua_State* L) { ptrdiff_t off; - struct ctype ct, mt; + struct ctype ct; + struct ctype mt; lua_settop(L, 2); check_ctype(L, 1, &ct); @@ -1404,18 +1516,10 @@ static int ffi_istype(lua_State* L) goto fail; } - if (tt.pointers != ft.pointers) { - goto fail; - } - - if (tt.is_array != ft.is_array) { - goto fail; - } - - if (tt.is_array && tt.array_size != ft.array_size) { + if(tt.is_array!=ft.is_array + ||(tt.is_array && tt.array_size != ft.array_size)){ goto fail; } - if (tt.calling_convention != ft.calling_convention) { goto fail; } @@ -1452,9 +1556,9 @@ static int cdata_gc(lua_State* L) static int callback_free(lua_State* L) { - cfunction* p = (cfunction*) lua_touserdata(L, 1); // FIXME: temporarily disabled to prevent SIGTRAP on exit - // free_code(get_jit(L), L, *p); + //cfunction* p = (cfunction*) lua_touserdata(L, 1); + //free_code(get_jit(L), L, *p); return 0; } @@ -1511,8 +1615,7 @@ static int cdata_call(lua_State* L) cfunction* p = (cfunction*) check_cdata(L, 1, &ct); if (push_user_mt(L, -1, &ct)) { - lua_pushliteral(L, "__call"); - lua_rawget(L, -2); + lua_rawgeti(L, -1,TM_CALL); if (!lua_isnil(L, -1)) { lua_insert(L, 1); @@ -1540,6 +1643,7 @@ static int cdata_call(lua_State* L) lua_rawset(L, lua_upvalueindex(1)); lua_replace(L, 1); + } else { lua_replace(L, 1); } @@ -1553,16 +1657,46 @@ static int cdata_call(lua_State* L) static int user_mt_key; +static void compile_user_mt(lua_State* L,int user_mt){ + if(lua_isnil(L,user_mt)) + return; + int created=0; + for (int i = TM_END; --i ;) { + lua_getfield(L,user_mt,tm_fields[i]); + if(lua_isnil(L,-1)){ + lua_pop(L,1); + continue; + } + if(!created){ + created=1; + lua_createtable(L,i,0); + lua_insert(L,-2); + } + lua_rawseti(L,-2,i); + } + if(!created){ + lua_pushnil(L); + } + lua_replace(L,user_mt); +} +static ALWAYS_INLINE int is_invalid_for_meta(const struct ctype* ct){ + return ct->type != STRUCT_TYPE && ct->type != UNION_TYPE && !IS_COMPLEX(ct->type); +} static int ffi_metatype(lua_State* L) { struct ctype ct; lua_settop(L, 2); check_ctype(L, 1, &ct); + + if ( ct.pointers||ct.is_reference||is_invalid_for_meta(&ct)) { + return luaL_argerror(L, 1, "invalid C type"); + } + if (lua_type(L, 2) != LUA_TTABLE && lua_type(L, 2) != LUA_TNIL) { return luaL_argerror(L, 2, "metatable must be a table or nil"); } - + compile_user_mt(L,2); lua_pushlightuserdata(L, &user_mt_key); lua_pushvalue(L, 2); lua_rawset(L, 3); /* user[user_mt_key] = mt */ @@ -1576,7 +1710,7 @@ static int ffi_metatype(lua_State* L) * the stack, otherwise it returns 0 and pushes nothing */ int push_user_mt(lua_State* L, int ct_usr, const struct ctype* ct) { - if (ct->type != STRUCT_TYPE && ct->type != UNION_TYPE && !IS_COMPLEX(ct->type)) { + if (is_invalid_for_meta(ct)) { return 0; } if (!lua_istable(L, ct_usr)) { @@ -1615,12 +1749,10 @@ static int ffi_gc(lua_State* L) */ static ptrdiff_t lookup_cdata_index(lua_State* L, int idx, int ct_usr, struct ctype* ct) { - struct ctype mt; ptrdiff_t off; - int type; ct_usr = lua_absindex(L, ct_usr); - type = lua_type(L, idx); + int type = lua_type(L, idx); switch (type) { case LUA_TNUMBER: @@ -1649,13 +1781,14 @@ static ptrdiff_t lookup_cdata_index(lua_State* L, int idx, int ct_usr, struct ct return (ct->pointers ? sizeof(void*) : ct->base_size) * off; - case LUA_TSTRING: + case LUA_TSTRING:{ /* possibilities are struct/union, pointer to struct/union */ if ((ct->type != STRUCT_TYPE && ct->type != UNION_TYPE) || ct->is_array || ct->pointers > 1) { return -1; } + struct ctype mt; lua_pushvalue(L, idx); off = get_member(L, ct_usr, ct, &mt); if (off < 0) { @@ -1664,7 +1797,7 @@ static ptrdiff_t lookup_cdata_index(lua_State* L, int idx, int ct_usr, struct ct *ct = mt; return off; - + } default: return -1; } @@ -1686,8 +1819,7 @@ static int cdata_newindex(lua_State* L) goto err; } - lua_pushliteral(L, "__newindex"); - lua_rawget(L, -2); + lua_rawgeti(L, -1,TM_NEWINDEX); if (lua_isnil(L, -1)) { goto err; @@ -1759,8 +1891,7 @@ static int cdata_index(lua_State* L) goto err; } - lua_pushliteral(L, "__index"); - lua_rawget(L, -2); + lua_rawgeti(L, -1,TM_INDEX); if (lua_isnil(L, -1)) { goto err; @@ -1793,7 +1924,7 @@ static int cdata_index(lua_State* L) return 1; } else if (ct.is_bitfield) { - +#if LUA_VERSION_NUM <503 if (ct.type == INT64_TYPE) { struct ctype rt; uint64_t val = *(uint64_t*) data; @@ -1811,7 +1942,9 @@ static int cdata_index(lua_State* L) return 1; - } else if (ct.type == BOOL_TYPE) { + } else +#endif + if (ct.type == BOOL_TYPE) { uint64_t val = *(uint64_t*) data; lua_pushboolean(L, (int) (val & (UINT64_C(1) << ct.bit_offset))); return 1; @@ -1827,7 +1960,7 @@ static int cdata_index(lua_State* L) } else if (ct.pointers) { #ifndef ALLOW_MISALIGNED_ACCESS union { - uint8_t c[8]; + char c[8]; void* p; } misalignbuf; @@ -1855,7 +1988,7 @@ static int cdata_index(lua_State* L) } else { #ifndef ALLOW_MISALIGNED_ACCESS union { - uint8_t c[8]; + char c[8]; double d; float f; uint64_t u64; @@ -1884,8 +2017,12 @@ static int cdata_index(lua_State* L) lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint32_t*) data : (lua_Integer) *(int32_t*) data); break; case INT64_TYPE: + #if LUA_VERSION_NUM<503 to = push_cdata(L, -1, &ct); *(int64_t*) to = *(int64_t*) data; + #else + lua_pushinteger(L, *(int64_t*) data); + #endif break; case INTPTR_TYPE: to = push_cdata(L, -1, &ct); @@ -1957,7 +2094,11 @@ static int rank(const struct ctype* ct) case COMPLEX_FLOAT_TYPE: return 6; case INTPTR_TYPE: - return sizeof(intptr_t) >= sizeof(int64_t) ? 4 : 1; +#if defined(__LP64__) || defined(__amd64__) ||defined (_WIN64) + return 4; +#else + return 1; +#endif case INT64_TYPE: return ct->is_unsigned ? 3 : 2; case INT32_TYPE: @@ -1996,13 +2137,12 @@ static void push_number(lua_State* L, int64_t val, int ct_usr, const struct ctyp } } -static int call_user_op(lua_State* L, const char* opfield, int idx, int ct_usr, const struct ctype* ct) +static int call_user_op(lua_State* L, TMK key, int idx, int ct_usr, const struct ctype* ct) { idx = lua_absindex(L, idx); if (push_user_mt(L, ct_usr, ct)) { - lua_pushstring(L, opfield); - lua_rawget(L, -2); + lua_rawgeti(L, -1,key); if (!lua_isnil(L, -1)) { int top = lua_gettop(L); lua_pushvalue(L, idx); @@ -2024,7 +2164,7 @@ static int cdata_unm(lua_State* L) lua_settop(L, 1); p = to_cdata(L, 1, &ct); - ret = call_user_op(L, "__unm", 1, 2, &ct); + ret = call_user_op(L, TM_UNM, 1, 2, &ct); if (ret >= 0) { return ret; } @@ -2046,14 +2186,13 @@ static int cdata_unm(lua_State* L) /* returns -ve if no binop was called otherwise returns the number of return * arguments */ -static int call_user_binop(lua_State* L, const char* opfield, int lidx, int lusr, const struct ctype* lt, int ridx, int rusr, const struct ctype* rt) +static int call_user_binop(lua_State* L, TMK key, int lidx, int lusr, const struct ctype* lt, int ridx, int rusr, const struct ctype* rt) { lidx = lua_absindex(L, lidx); ridx = lua_absindex(L, ridx); if (push_user_mt(L, lusr, lt)) { - lua_pushstring(L, opfield); - lua_rawget(L, -2); + lua_rawgeti(L, -1,key); if (!lua_isnil(L, -1)) { int top = lua_gettop(L); @@ -2067,8 +2206,7 @@ static int call_user_binop(lua_State* L, const char* opfield, int lidx, int lusr } if (push_user_mt(L, rusr, rt)) { - lua_pushstring(L, opfield); - lua_rawget(L, -2); + lua_rawgeti(L, -1,key); if (!lua_isnil(L, -1)) { int top = lua_gettop(L); @@ -2093,7 +2231,7 @@ static int cdata_concat(lua_State* L) to_cdata(L, 1, <); to_cdata(L, 2, &rt); - ret = call_user_binop(L, "__concat", 1, 3, <, 2, 4, &rt); + ret = call_user_binop(L, TM_CONCAT, 1, 3, <, 2, 4, &rt); if (ret >= 0) { return ret; } @@ -2109,15 +2247,34 @@ static int cdata_len(lua_State* L) lua_settop(L, 1); to_cdata(L, 1, &ct); - ret = call_user_op(L, "__len", 1, 2, &ct); + ret = call_user_op(L, TM_LEN, 1, 2, &ct); if (ret >= 0) { return ret; } - + if(ct.is_array){ + lua_pushinteger(L,ct.array_size) ; + return 1; + } push_type_name(L, 2, &ct); return luaL_error(L, "type %s does not implement the __len metamethod", lua_tostring(L, -1)); } - +static int cdata_next(lua_State* L){ + struct ctype ct; + long key; + to_cdata(L, 1, &ct); + key =lua_tointeger(L,2)+1; + if(!ct.is_array){ + luaL_error(L,"Only array type can be iterated"); + } + if(key>=ct.array_size){ + lua_pushnil(L); + return 1; + } + lua_pushinteger(L,key); + lua_pushvalue(L,-1); + lua_gettable(L,1); + return 2; +} static int cdata_pairs(lua_State* L) { struct ctype ct; @@ -2126,11 +2283,16 @@ static int cdata_pairs(lua_State* L) lua_settop(L, 1); to_cdata(L, 1, &ct); - ret = call_user_op(L, "__pairs", 1, 2, &ct); + ret = call_user_op(L, TM_PAIRS, 1, 2, &ct); if (ret >= 0) { return ret; } - + if(ct.is_array){ + lua_pushcfunction(L,cdata_next); + lua_pushvalue(L,1); + lua_pushinteger(L,-1); + return 3; + } push_type_name(L, 2, &ct); return luaL_error(L, "type %s does not implement the __pairs metamethod", lua_tostring(L, -1)); } @@ -2143,11 +2305,16 @@ static int cdata_ipairs(lua_State* L) lua_settop(L, 1); to_cdata(L, 1, &ct); - ret = call_user_op(L, "__ipairs", 1, 2, &ct); + ret = call_user_op(L, TM_IPAIRS, 1, 2, &ct); if (ret >= 0) { return ret; } - + if(ct.is_array){ + lua_pushcfunction(L,cdata_next); + lua_pushvalue(L,1); + lua_pushinteger(L,-1); + return 3; + } push_type_name(L, 2, &ct); return luaL_error(L, "type %s does not implement the __ipairs metamethod", lua_tostring(L, -1)); } @@ -2165,7 +2332,7 @@ static int cdata_add(lua_State* L) rp = to_cdata(L, 2, &rt); assert(lua_gettop(L) == 4); - ret = call_user_binop(L, "__add", 1, 3, <, 2, 4, &rt); + ret = call_user_binop(L, TM_ADD, 1, 3, <, 2, 4, &rt); if (ret >= 0) { return ret; } @@ -2232,7 +2399,7 @@ static int cdata_sub(lua_State* L) lp = to_cdata(L, 1, <); rp = to_cdata(L, 2, &rt); - ret = call_user_binop(L, "__sub", 1, 3, <, 2, 4, &rt); + ret = call_user_binop(L, TM_SUB, 1, 3, <, 2, 4, &rt); if (ret >= 0) { return ret; } @@ -2278,7 +2445,7 @@ static int cdata_sub(lua_State* L) } /* TODO fix for unsigned */ -#define NUMBER_ONLY_BINOP(OPSTR, DO_NORMAL, DO_COMPLEX) \ +#define NUMBER_ONLY_BINOP(OP, DO_NORMAL, DO_COMPLEX) \ struct ctype lt, rt, ct; \ void *lp, *rp; \ int ct_usr; \ @@ -2289,7 +2456,7 @@ static int cdata_sub(lua_State* L) lp = to_cdata(L, 1, <); \ rp = to_cdata(L, 2, &rt); \ \ - ret = call_user_binop(L, OPSTR, 1, 3, <, 2, 4, &rt); \ + ret = call_user_binop(L, OP, 1, 3, <, 2, 4, &rt); \ if (ret >= 0) { \ return ret; \ } \ @@ -2321,35 +2488,49 @@ static int cdata_sub(lua_State* L) #define MUL(l,r,s) s = l * r #define DIV(l,r,s) s = l / r +#define IDIV(l,r,s) s = (int64_t)(l / r) #define MOD(l,r,s) s = l % r #define POW(l,r,s) s = pow(l, r) -#ifdef HAVE_COMPLEX +#if defined(HAVE_COMPLEX) #define MULC(l,r,s) s = l * r #define DIVC(l,r,s) s = l / r +#define IDIVC(l,r,s) (void) l, (void) r, memset(&s, 0, sizeof(s)), luaL_error(L, "NYI: complex idiv") #define MODC(l,r,s) (void) l, (void) r, memset(&s, 0, sizeof(s)), luaL_error(L, "NYI: complex mod") #define POWC(l,r,s) s = cpow(l, r) #else #define MULC(l,r,s) s.real = l.real * r.real - l.imag * r.imag, s.imag = l.real * r.imag + l.imag * r.real #define DIVC(l,r,s) s.real = (l.real * r.real + l.imag * r.imag) / (r.real * r.real + r.imag * r.imag), \ s.imag = (l.imag * r.real - l.real * r.imag) / (r.real * r.real + r.imag * r.imag) +#define IDIVC(l,r,s) (void) l, (void) r, memset(&s, 0, sizeof(s)), luaL_error(L, "NYI: complex idiv") #define MODC(l,r,s) (void) l, (void) r, memset(&s, 0, sizeof(s)), luaL_error(L, "NYI: complex mod") -#define POWC(l,r,s) (void) l, (void) r, memset(&s, 0, sizeof(s)), luaL_error(L, "NYI: complex pow") +#define POWC(l,r,s) cpow(l, r) #endif static int cdata_mul(lua_State* L) -{ NUMBER_ONLY_BINOP("__mul", MUL, MULC); } +{ NUMBER_ONLY_BINOP(TM_MUL, MUL, MULC); } static int cdata_div(lua_State* L) -{ NUMBER_ONLY_BINOP("__div", DIV, DIVC); } - +{ NUMBER_ONLY_BINOP(TM_DIV, DIV, DIVC); } +static int cdata_idiv(lua_State* L) +{ NUMBER_ONLY_BINOP(TM_IDIV, IDIV, IDIVC); } static int cdata_mod(lua_State* L) -{ NUMBER_ONLY_BINOP("__mod", MOD, MODC); } +{ NUMBER_ONLY_BINOP(TM_MOD, MOD, MODC); } static int cdata_pow(lua_State* L) -{ NUMBER_ONLY_BINOP("__pow", POW, POWC); } +{ NUMBER_ONLY_BINOP(TM_POW, POW, POWC); } -#define COMPARE_BINOP(OPSTR, OP, OPC) \ +#define POINTER_FIX_CHECK()\ + if(lt.type==FUNCTION_PTR_TYPE)\ + lp=*(uintptr_t**)lp;\ + if(rt.type==FUNCTION_PTR_TYPE)\ + rp=*(uintptr_t**)rp;\ + if((is_void_ptr(&rt)||rt.is_null)&&(lt.pointers||lt.type==FUNCTION_PTR_TYPE)||\ + (is_void_ptr(<)||lt.is_null)&&(rt.pointers||rt.type==FUNCTION_PTR_TYPE)||\ + is_same_type(L, 3, 4, <, &rt)) + + +#define COMPARE_BINOP(OPKEY, OP, OPC) \ struct ctype lt, rt; \ void *lp, *rp; \ int ret, res; \ @@ -2359,46 +2540,33 @@ static int cdata_pow(lua_State* L) lp = to_cdata(L, 1, <); \ rp = to_cdata(L, 2, &rt); \ \ - ret = call_user_binop(L, OPSTR, 1, 3, <, 2, 4, &rt); \ + ret = call_user_binop(L, OPKEY, 1, 3, <, 2, 4, &rt); \ if (ret >= 0) { \ return ret; \ } \ \ - if (IS_COMPLEX(lt.type) || IS_COMPLEX(rt.type)) { \ - complex_double left = check_complex(L, 1, lp, <); \ - complex_double right = check_complex(L, 2, rp, &rt); \ + if (lt.pointers || lt.type==FUNCTION_PTR_TYPE|| \ + rt.pointers || rt.type==FUNCTION_PTR_TYPE) { \ + POINTER_FIX_CHECK() { \ + res = OP((char*)lp, (char*)rp); \ + } else { \ + goto err; \ + } \ \ - res = OPC(left, right); \ + }else { \ + if (IS_COMPLEX(lt.type) || IS_COMPLEX(rt.type)) { \ + complex_double left = check_complex(L, 1, lp, <); \ + complex_double right = check_complex(L, 2, rp, &rt); \ \ - lua_pushboolean(L, res); \ + res = OPC(left, right); \ + \ + lua_pushboolean(L, res); \ + return 1; \ + }; \ \ - } else { \ int64_t left = check_intptr(L, 1, lp, <); \ int64_t right = check_intptr(L, 2, rp, &rt); \ - \ - if (lt.pointers && rt.pointers) { \ - if (is_void_ptr(<) || is_void_ptr(&rt) || is_same_type(L, 3, 4, <, &rt)) { \ - res = OP((uint64_t) left, (uint64_t) right); \ - } else { \ - goto err; \ - } \ - \ - } else if (lt.is_null && rt.type == FUNCTION_PTR_TYPE) { \ - res = OP((uint64_t) left, (uint64_t) right); \ - \ - } else if (rt.is_null && lt.type == FUNCTION_PTR_TYPE) { \ - res = OP((uint64_t) left, (uint64_t) right); \ - \ - } else if (lt.pointers && rt.type == INTPTR_TYPE && rt.is_unsigned) {\ - res = OP((uint64_t) left, (uint64_t) right); \ - \ - } else if (rt.pointers && lt.type == INTPTR_TYPE && lt.is_unsigned) {\ - res = OP((uint64_t) left, (uint64_t) right); \ - \ - } else if (rt.pointers || lt.pointers) { \ - goto err; \ - \ - } else if (lt.is_unsigned && rt.is_unsigned) { \ + if (lt.is_unsigned && rt.is_unsigned) { \ res = OP((uint64_t) left, (uint64_t) right); \ \ } else if (lt.is_unsigned) { \ @@ -2411,8 +2579,8 @@ static int cdata_pow(lua_State* L) res = OP(left, right); \ } \ \ - lua_pushboolean(L, res); \ } \ + lua_pushboolean(L, res); \ return 1 #define EQ(l, r) (l) == (r) @@ -2430,7 +2598,10 @@ static int cdata_pow(lua_State* L) static int cdata_eq(lua_State* L) { - COMPARE_BINOP("__eq", EQ, EQC); + /* struct ctype l,r; + void*p = to_cdata(L, 1, &l); \ + void*p2 = to_cdata(L, 2, &r);*/ + COMPARE_BINOP(TM_EQ, EQ, EQC); err: lua_pushboolean(L, 0); return 1; @@ -2438,7 +2609,7 @@ static int cdata_eq(lua_State* L) static int cdata_lt(lua_State* L) { - COMPARE_BINOP("__lt", LT, LTC); + COMPARE_BINOP(TM_LT, LT, LTC); err: lua_getuservalue(L, 1); lua_getuservalue(L, 2); @@ -2449,7 +2620,7 @@ static int cdata_lt(lua_State* L) static int cdata_le(lua_State* L) { - COMPARE_BINOP("__le", LE, LEC); + COMPARE_BINOP(TM_LE, LE, LEC); err: lua_getuservalue(L, 1); lua_getuservalue(L, 2); @@ -2483,11 +2654,15 @@ static const char* etype_tostring(int type) static void print_type(lua_State* L, const struct ctype* ct) { - lua_pushfstring(L, " sz %d %d %d align %d ptr %d %d %d type %s%s %d %d %d name %d call %d %d var %d %d %d bit %d %d %d %d jit %d", + lua_pushfstring(L, " sz %d %d " + //"%d " + "align %d ptr %d %d %d type %s%s %d %d %d " + // "name %d " + "call %d %d var %d %d %d bit %d %d %d %d jit %d", /* sz */ ct->base_size, ct->array_size, - ct->offset, + //ct->offset, /* align */ ct->align_mask, /* ptr */ @@ -2501,7 +2676,7 @@ static void print_type(lua_State* L, const struct ctype* ct) ct->is_defined, ct->is_null, /* name */ - ct->has_member_name, + //ct->has_member_name, /* call */ ct->calling_convention, ct->has_var_arg, @@ -2539,14 +2714,13 @@ static int ctype_tostring(lua_State* L) static int cdata_tostring(lua_State* L) { struct ctype ct; - char buf[64]; void* p; int ret; lua_settop(L, 1); p = to_cdata(L, 1, &ct); - ret = call_user_op(L, "__tostring", 1, 2, &ct); + ret = call_user_op(L, TM_TO_STRING, 1, 2, &ct); if (ret >= 0) { return ret; } @@ -2564,53 +2738,80 @@ static int cdata_tostring(lua_State* L) } switch (ct.type) { - case COMPLEX_DOUBLE_TYPE: - { - complex_double c = *(complex_double*) p; - lua_pushfstring(L, "%f+%fi", creal(c), cimag(c)); + case COMPLEX_DOUBLE_TYPE: { + char buf[128]; + complex_double c = *(complex_double *) p; + snprintf(buf,128, "%g+%gi", creal(c), cimag(c)); + lua_pushstring(L, buf); + return 1; } - return 1; - case COMPLEX_FLOAT_TYPE: - { - complex_float c = *(complex_float*) p; - lua_pushfstring(L, "%f+%fi", crealf(c), cimagf(c)); + case COMPLEX_FLOAT_TYPE: { + char buf[128]; + complex_float c = *(complex_float *) p; + snprintf(buf,128, "%g+%gi", crealf(c), cimagf(c)); + lua_pushstring(L, buf); + return 1; } - return 1; - case FUNCTION_PTR_TYPE: - p = *(void**) p; - push_type_name(L, -1, &ct); - lua_pushfstring(L, "cdata<%s>: %p", lua_tostring(L, -1), *(void**) p); - return 1; + case FUNCTION_PTR_TYPE: + push_type_name(L, -1, &ct); + lua_pushfstring(L, "cdata<%s>: %p", lua_tostring(L, -1), *(void **) p); + return 1; - case INTPTR_TYPE: - lua_pushfstring(L, "%p", *(uintptr_t*) p); - return 1; + case INTPTR_TYPE: + lua_pushfstring(L, "%p", *(uintptr_t *) p); + return 1; - case INT64_TYPE: - sprintf(buf, ct.is_unsigned ? "%"PRIu64 : "%"PRId64, *(uint64_t*) p); - lua_pushstring(L, buf); - return 1; + case INT64_TYPE: { + char buf[64]; + sprintf(buf, ct.is_unsigned ? "%"PRIu64 : "%" PRId64, *(uint64_t *) p); + lua_pushstring(L, buf); + return 1; + } + + case FLOAT_TYPE: { + char buf[64]; + snprintf(buf, 64, "%g", *(float *) p); + lua_pushstring(L, buf); + return 1; + } + case DOUBLE_TYPE: { + char buf[64]; + snprintf(buf, 64, "%g", *(double *) p); + lua_pushstring(L, buf); + return 1; + } + + default: { + char buf[64]; + snprintf(buf, 64, ct.is_unsigned ? "%"PRIu64 : "%"PRId64, + (int64_t) check_intptr(L, 1, p, &ct)); + lua_pushstring(L, buf); + return 1; + } - default: - sprintf(buf, ct.is_unsigned ? "%"PRId64 : "%"PRId64, (int64_t) check_intptr(L, 1, p, &ct)); - lua_pushstring(L, buf); - return 1; } } static int ffi_errno(lua_State* L) { - struct jit* jit = get_jit(L); - +#ifdef _WIN32 + if (!lua_isnoneornil(L, 1)) { + lua_pushinteger(L, GetLastError()); + SetLastError((int)luaL_checknumber(L, 1)); + } + else { + lua_pushinteger(L, GetLastError()); + } +#else if (!lua_isnoneornil(L, 1)) { - lua_pushinteger(L, jit->last_errno); - jit->last_errno = luaL_checknumber(L, 1); + lua_pushinteger(L, errno); + errno =(int) luaL_checknumber(L, 1); } else { - lua_pushinteger(L, jit->last_errno); + lua_pushinteger(L,errno); } - +#endif return 1; } @@ -2657,36 +2858,33 @@ static int ffi_string(lua_State* L) lua_settop(L, 2); data = (char*) check_cdata(L, 1, &ct); + if(!data){ + luaL_error(L,"null pointer for string call"); + } + size_t sz; - if (is_void_ptr(&ct)) { - lua_pushlstring(L, data, (size_t) luaL_checknumber(L, 2)); - return 1; - - } else if (ct.type == INT8_TYPE && ct.pointers == 1) { - size_t sz; - - if (lua_isuserdata(L, 2)) { - ptrdiff_t val; - if (!cdata_tointeger(L, 2, &val)) { - type_error(L, 2, "int", 0, NULL); - } - sz = (size_t) val; - } else if (!lua_isnil(L, 2)) { - sz = (size_t) luaL_checknumber(L, 2); + if (lua_isuserdata(L, 2)) { + ptrdiff_t val; + if (!cdata_tointeger(L, 2, &val)) { + type_error(L, 2, "int", 0, NULL); + } + sz = (size_t) val; + } else if (!lua_isnil(L, 2)) { + sz = (size_t) luaL_checknumber(L, 2); - } else if (ct.is_array && !ct.is_variable_array) { + } else if (ct.type == INT8_TYPE && ct.pointers == 1){ + if (ct.is_array && !ct.is_variable_array) { char* nul = memchr(data, '\0', ct.array_size); sz = nul ? nul - data : ct.array_size; - } else { + }else sz = strlen(data); - } - - lua_pushlstring(L, data, sz); - return 1; + }else{ + sz =ctype_size(L,&ct); } - return luaL_error(L, "unable to convert cdata to string"); + lua_pushlstring(L, data, sz); + return 1; } static int ffi_copy(lua_State* L) @@ -2738,31 +2936,129 @@ static int ffi_abi(lua_State* L) lua_pushboolean(L, lua_toboolean(L, -1)); return 1; } +/* #ifdef FAKE_ANDROID_DL */ + +/* #include "fake_dlfcn.h" */ +/* #include "sys/system_properties.h" */ +/* static int getSDK() { */ +/* static int sdk=0; */ +/* if(sdk!=0) */ +/* return sdk; */ +/* char s[6]; */ +/* __system_property_get("ro.build.version.sdk",s); */ +/* sdk=atoi(s); */ +/* return sdk; */ +/* } */ +/* static void* android_fake_load_library(lua_State* L,const char* libname) */ +/* { */ +/* if(getSDK()<24) return NULL; */ +/* if(libname[0]=='/'){ */ +/* return fake_dlopen(libname,RTLD_LAZY); */ +/* } */ +/* static int ld_path_key; */ +/* push_upval(L,&ld_path_key); */ +/* if(lua_isnil(L,-1)){ */ +/* lua_pop(L,1); */ +/* lua_createtable(L,2,0); */ +/* const char* library_path = getenv("LD_LIBRARY_PATH"); */ +/* if (library_path == NULL) { */ +/* static const char *const kDefaultLdPaths[] = { */ +/* #if defined(__LP64__) */ +/* "/system/lib64", */ +/* "/vendor/lib64" */ +/* #else */ +/* "/system/lib", */ +/* "/vendor/lib" */ +/* #endif */ +/* }; */ +/* lua_pushstring(L,kDefaultLdPaths[0]); */ +/* lua_rawseti(L,-2,1); */ +/* lua_pushstring(L,kDefaultLdPaths[1]); */ +/* lua_rawseti(L,-2,2); */ +/* } else{ */ +/* size_t len=strlen(library_path); */ +/* char* buf=malloc(len+1); */ +/* memcpy(buf,library_path,len); */ +/* int libIndex=0; */ +/* size_t lastStart=0; */ +/* for(size_t i=0;i<=len;++i){ */ +/* if(buf[i]==':'){ */ +/* buf[i]=0; */ +/* } else if(buf[i]!=0){ */ +/* continue; */ +/* } */ +/* if(i>lastStart+1&&buf[i-1]=='/'){ */ +/* buf[i-1]=0; */ +/* } */ +/* lua_pushstring(L,buf+lastStart); */ +/* lua_rawseti(L,-2,libIndex); */ +/* lastStart=i+1; */ +/* libIndex++; */ +/* } */ +/* } */ +/* lua_pushvalue(L,-1); */ +/* set_upval(L,&ld_path_key); */ +/* } */ + +/* size_t pathLen=lua_rawlen(L,-1); */ +/* void* lib=NULL; */ +/* const char* path,*trueLib; */ +/* for (int i = 1; i <= pathLen; ++i) { */ +/* lua_rawgeti(L,-1,i); */ +/* path = lua_tostring(L, -1); */ +/* if(path==0){ */ +/* lua_pop(L,1);continue; */ +/* } */ +/* trueLib = lua_pushfstring(L, "%s/"LIB_FORMAT_1,path, libname); */ +/* if(access(trueLib,F_OK==0)) */ +/* lib = fake_dlopen(trueLib,RTLD_LAZY); */ +/* lua_pop(L, 1); */ + +/* if (!lib) { */ +/* trueLib = lua_pushfstring(L, "%s/"LIB_FORMAT_2,path, libname); */ +/* if(access(trueLib,F_OK==0)) */ +/* lib = fake_dlopen(trueLib,RTLD_LAZY); */ +/* lua_pop(L, 1); */ +/* } */ +/* lua_pop(L,1); */ +/* if(lib) break; */ +/* } */ +/* lua_pop(L,1);//pop the table; */ +/* return lib; */ +/* } */ +/* #endif */ static int ffi_load(lua_State* L) { - const char* libname = luaL_checkstring(L, 1); + const char* libname = luaL_checkstring(L, 1),*trueLib; void** lib = (void**) lua_newuserdata(L, sizeof(void*)); *lib = LoadLibraryA(libname); #ifdef LIB_FORMAT_1 if (!*lib) { - libname = lua_pushfstring(L, LIB_FORMAT_1, lua_tostring(L, 1)); - *lib = LoadLibraryA(libname); + trueLib = lua_pushfstring(L, LIB_FORMAT_1, libname); + *lib = LoadLibraryA(trueLib); lua_pop(L, 1); } #endif #ifdef LIB_FORMAT_2 if (!*lib) { - libname = lua_pushfstring(L, LIB_FORMAT_2, lua_tostring(L, 1)); - *lib = LoadLibraryA(libname); + trueLib = lua_pushfstring(L, LIB_FORMAT_2, libname); + *lib = LoadLibraryA(trueLib); lua_pop(L, 1); } #endif if (!*lib) { +/* #ifdef FAKE_ANDROID_DL */ +/* *lib=android_fake_load_library(L,libname); */ +/* if(*lib){ */ +/* lua_pushboolean(L,1); */ +/* set_upval(L,*lib); */ +/* } else */ +/* #endif */ return luaL_error(L, "could not load library %s", lua_tostring(L, 1)); } @@ -2783,9 +3079,19 @@ static void* find_symbol(lua_State* L, int modidx, const char* asmname) libs = (void**) lua_touserdata(L, modidx); num = lua_rawlen(L, modidx) / sizeof(void*); - +/* #ifdef FAKE_ANDROID_DL */ +/* push_upval(L,*libs); */ +/* int isFakeLib=!lua_isnil(L,-1); */ +/* lua_pop(L,1); */ +/* extern void *fake_dlsym(void *handle, const char *name); */ +/* #endif */ for (i = 0; i < num && sym == NULL; i++) { if (libs[i]) { +/* #ifdef FAKE_ANDROID_DL */ +/* if(isFakeLib){ */ +/* sym=fake_dlsym(libs[i],asmname); */ +/* } else */ +/* #endif */ sym = GetProcAddressA(libs[i], asmname); } } @@ -2930,7 +3236,9 @@ static int cmodule_index(lua_State* L) case COMPLEX_DOUBLE_TYPE: case COMPLEX_FLOAT_TYPE: case INTPTR_TYPE: +#if LUA_VERSION_NUM<503 case INT64_TYPE: +#endif { /* TODO: complex float/double need to be references if .re and * .imag are setable */ @@ -2938,7 +3246,12 @@ static int cmodule_index(lua_State* L) memcpy(p, sym, ct.base_size); return 1; } - +#if LUA_VERSION_NUM>=503 + case INT64_TYPE:{ + lua_pushinteger(L, *(lua_Integer *) sym); + return 1; + } +#endif case DOUBLE_TYPE: lua_pushnumber(L, *(double*) sym); return 1; @@ -2992,6 +3305,30 @@ static int cmodule_newindex(lua_State* L) return 0; } +static int cmodule_gc(lua_State* L){ + void* handle;int i; + void** libs=lua_touserdata(L,1); + size_t len=lua_rawlen(L,1)/ sizeof(void*); +/* #ifdef FAKE_ANDROID_DL */ +/* push_upval(L,*libs); */ +/* int isFakeLib=!lua_isnil(L,-1); */ +/* lua_pop(L,1); */ +/* extern void fake_dlclose(void* handle); */ +/* #endif */ + for (i = 0; i < len; ++i) { + handle = libs[i]; + if(handle){ +/* #ifdef FAKE_ANDROID_DL */ +/* if(isFakeLib){ */ +/* fake_dlclose(handle); */ +/* } else */ +/* #endif */ + FreeLibrary(handle); + } + } + return 0; +} + static int jit_gc(lua_State* L) { size_t i; @@ -3082,6 +3419,7 @@ static const luaL_Reg cdata_mt[] = { {"__sub", &cdata_sub}, {"__mul", &cdata_mul}, {"__div", &cdata_div}, + {"__idiv", &cdata_idiv}, {"__mod", &cdata_mod}, {"__pow", &cdata_pow}, {"__unm", &cdata_unm}, @@ -3111,6 +3449,7 @@ static const luaL_Reg ctype_mt[] = { static const luaL_Reg cmodule_mt[] = { {"__index", &cmodule_index}, {"__newindex", &cmodule_newindex}, + {"__gc",&cmodule_gc}, {NULL, NULL} }; @@ -3137,8 +3476,10 @@ static const luaL_Reg ffi_reg[] = { {"fill", &ffi_fill}, {"abi", &ffi_abi}, {"debug", &ffi_debug}, +#if LUA_VERSION_NUM<503 {"i64", &ffi_i64}, {"u64", &ffi_u64}, +#endif {NULL, NULL} }; @@ -3185,7 +3526,7 @@ static void add_typedef(lua_State* L, const char* from, const char* to) push_upval(L, &types_key); parse_type(L, &P, &ct); - parse_argument(L, &P, -1, &ct, NULL, NULL); + parse_argument(L, &P, -1, &ct, NULL, NULL, 0); push_ctype(L, -1, &ct); /* stack is at +4: types, type usr, arg usr, ctype */ @@ -3223,28 +3564,32 @@ static int setup_upvals(lua_State* L) memset(libs, 0, sz); /* exe */ - GetModuleHandle(NULL); + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, &libs[0]); /* lua dll */ -#ifdef LUA_DLL_NAME +#if defined(LUA_DLL_NAME) #define STR2(tok) #tok #define STR(tok) STR2(tok) libs[1] = LoadLibraryA(STR(LUA_DLL_NAME)); #undef STR #undef STR2 +#else + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS , + (const char *)&lua_newstate, &libs[1]); #endif /* crt */ #ifdef UNDER_CE libs[2] = LoadLibraryA("coredll.dll"); #else - GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (char*) &_fmode, &libs[2]); - libs[3] = LoadLibraryA("kernel32.dll"); + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + (const char *)&_fmode, &libs[2]); + libs[3] = LoadLibraryA("kernel32.dll"); libs[4] = LoadLibraryA("user32.dll"); libs[5] = LoadLibraryA("gdi32.dll"); #endif jit->lua_dll = libs[1]; - jit->kernel32_dll = libs[3]; + //jit->kernel32_dll = libs[3]; #else /* !_WIN32 */ size_t sz = sizeof(void*) * 5; @@ -3253,7 +3598,7 @@ static int setup_upvals(lua_State* L) libs[0] = LoadLibraryA(NULL); /* exe */ libs[1] = LoadLibraryA("libc.so"); -#ifdef __GNUC__ +#if defined(__GNUC__) && !defined(OS_ANDROID) libs[2] = LoadLibraryA("libgcc.so"); #endif libs[3] = LoadLibraryA("libm.so"); @@ -3338,7 +3683,10 @@ static int setup_upvals(lua_State* L) ct.base_size = sizeof(complex_double); pc = (complex_double*) push_cdata(L, 0, &ct); #ifdef HAVE_COMPLEX + /* *pc = (complex_double){0,1};*/ *pc = 1i; + +#include #else pc->real = 0; pc->imag = 1; @@ -3399,28 +3747,33 @@ static int setup_upvals(lua_State* L) #if defined ARCH_X86 || defined ARCH_ARM lua_pushboolean(L, 1); lua_setfield(L, -2, "32bit"); -#elif defined ARCH_X64 || defined ARCH_PPC64 +#elif defined ARCH_X64 || defined ARCH_PPC64 ||defined(ARCH_ARM64) lua_pushboolean(L, 1); lua_setfield(L, -2, "64bit"); #else -# define UNSUPPORTED_ARCH /* error */ +#error #endif -#if defined ARCH_X86 || defined ARCH_X64 || defined ARCH_ARM || defined ARCH_PPC64 +#if defined ARCH_X86 || defined ARCH_X64 || defined ARCH_ARM ||defined(ARCH_ARM64)|| defined ARCH_PPC64 lua_pushboolean(L, 1); lua_setfield(L, -2, "le"); #else -# define UNSUPPORTED_ARCH /*error*/ +#error #endif -#if defined ARCH_X86 || defined ARCH_X64 || defined ARCH_PPC64 +#if defined ARCH_X86 || defined ARCH_X64 || defined ARCH_PPC64 ||defined(ARCH_ARM64) lua_pushboolean(L, 1); lua_setfield(L, -2, "fpu"); #elif defined ARCH_ARM lua_pushboolean(L, 1); +#if defined(__ARM_PCS_VFP) || (GCC_VERSION==40500||defined(__clang__))&&!defined(__ARM_PCS) && !defined(__SOFTFP__) && !defined(__SOFTFP) && \ + defined(__VFP_FP__) + lua_setfield(L, -2, "hardfp"); +#else lua_setfield(L, -2, "softfp"); +#endif #else -# define UNSUPPORTED_ARCH /*error*/ +#error #endif lua_pop(L, 1); /* abi tbl */ @@ -3447,6 +3800,8 @@ static int setup_upvals(lua_State* L) lua_pushliteral(L, "BSD"); #elif defined OS_POSIX lua_pushliteral(L, "POSIX"); +#elif defined OS_ANDROID + lua_pushliteral(L,"Android"); #else lua_pushliteral(L, "Other"); #endif @@ -3460,10 +3815,12 @@ static int setup_upvals(lua_State* L) lua_pushliteral(L, "x64"); #elif defined ARCH_ARM lua_pushliteral(L, "arm"); +#elif defined ARCH_ARM64 + lua_pushliteral(L, "arm64"); #elif defined ARCH_PPC64 lua_pushliteral(L, "ppc64"); #else -# define UNSUPPORTED_ARCH /* error */ +# error #endif lua_setfield(L, 1, "arch"); @@ -3479,7 +3836,6 @@ static void setup_mt(lua_State* L, const luaL_Reg* mt, int upvals) luaL_setfuncs(L, mt, upvals); } - #if defined FFI_ENABLE_LUATEX_INTERFACE int luaopen_ffi(lua_State* L) { @@ -3518,6 +3874,8 @@ int luaopen_ffi(lua_State* L) lua_setmetatable(L, -2); set_upval(L, &jit_key); + + lua_newtable(L); set_upval(L, &constants_key); @@ -3553,13 +3911,13 @@ int luaopen_ffi(lua_State* L) lua_pushcclosure(L, &ffi_number, 1); lua_pushvalue(L, -1); lua_setglobal(L, "tonumber"); - lua_setfield(L, -2, "number"); /* ffi.number */ + lua_setfield(L, -2, "number"); // ffi.number lua_getglobal(L, "type"); lua_pushcclosure(L, &ffi_type, 1); lua_pushvalue(L, -1); lua_setglobal(L, "type"); - lua_setfield(L, -2, "type"); /* ffi.type */ + lua_setfield(L, -2, "type"); // ffi.type return 1; } #else @@ -3571,10 +3929,10 @@ int luaopen_ffi(lua_State *L) k = luaL_dostring(L, "local info = [[\n" "The ffi module is available for:\n" "\n" -" archictures : ARCH_X86 and ARCH_X64,\n" +" archictures : ARCH_X86, ARCH_X64 and ARM_64,\n" " operating systems : OS_CE, OS_WIN, OS_LINUX, OS_BSD and OS_POSIX\n" "\n" -"The ARM processor is currently not supported. There are subtle\n" +"The ARM 32bit processor is currently not supported. There are subtle\n" "differences between this module and the one in luajitTeX \n" "and we hope to be in sync around TeXLive 2025.\n" "Different OS can have different interfaces,\n" diff --git a/texk/web2c/luatexdir/luaffi/ffi.c.orig b/texk/web2c/luatexdir/luaffi/ffi.c.orig deleted file mode 100644 index 988e764b2d..0000000000 --- a/texk/web2c/luatexdir/luaffi/ffi.c.orig +++ /dev/null @@ -1,3552 +0,0 @@ -/* vim: ts=4 sw=4 sts=4 et tw=78 - * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved. - * Portions copyright (c) 2011 James R. McKaskill. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -#include "ffi.h" -#include -#include - -/* Set to 1 to get extra debugging on print */ -#define DEBUG_TOSTRING 0 - -int jit_key; -int ctype_mt_key; -int cdata_mt_key; -int callback_mt_key; -int cmodule_mt_key; -int constants_key; -int types_key; -int gc_key; -int callbacks_key; -int functions_key; -int abi_key; -int next_unnamed_key; -int niluv_key; -int asmname_key; - -void push_upval(lua_State* L, int* key) -{ - lua_pushlightuserdata(L, key); - lua_rawget(L, LUA_REGISTRYINDEX); -} - -void set_upval(lua_State* L, int* key) -{ - lua_pushlightuserdata(L, key); - lua_insert(L, -2); - lua_rawset(L, LUA_REGISTRYINDEX); -} - -int equals_upval(lua_State* L, int idx, int* key) -{ - int ret; - lua_pushvalue(L, idx); - push_upval(L, key); - ret = lua_rawequal(L, -2, -1); - lua_pop(L, 2); - return ret; -} - -struct jit* get_jit(lua_State* L) -{ - struct jit* jit; - push_upval(L, &jit_key); - jit = (struct jit*) lua_touserdata(L, -1); - jit->L = L; - lua_pop(L, 1); /* still in registry */ - return jit; -} - -static int type_error(lua_State* L, int idx, const char* to_type, int to_usr, const struct ctype* to_ct) -{ - luaL_Buffer B; - struct ctype ft; - - assert(to_type || (to_usr && to_ct)); - if (to_usr) { - to_usr = lua_absindex(L, to_usr); - } - - idx = lua_absindex(L, idx); - - luaL_buffinit(L, &B); - to_cdata(L, idx, &ft); - - if (ft.type != INVALID_TYPE) { - push_type_name(L, -1, &ft); - lua_pushfstring(L, "unable to convert argument %d from cdata<%s> to cdata<", idx, lua_tostring(L, -1)); - lua_remove(L, -2); - luaL_addvalue(&B); - } else { - lua_pushfstring(L, "unable to convert argument %d from lua<%s> to cdata<", idx, luaL_typename(L, idx)); - luaL_addvalue(&B); - } - - if (to_ct) { - push_type_name(L, to_usr, to_ct); - luaL_addvalue(&B); - } else { - luaL_addstring(&B, to_type); - } - - luaL_addchar(&B, '>'); - - luaL_pushresult(&B); - return lua_error(L); -} - -static void* userdata_toptr(lua_State* L, int idx) -{ - void* ptr = lua_touserdata(L, idx); - - // check for FILE* - lua_getmetatable(L, idx); - luaL_getmetatable(L, LUA_FILEHANDLE); - int isfile = lua_rawequal(L, -1, -2); - lua_pop(L, 2); - - if (isfile) { -#if LUA_VERSION_NUM == 501 - FILE** stream = (FILE**) ptr; - return *stream; -#else - luaL_Stream* stream = (luaL_Stream*) ptr; - return stream->f; -#endif - } - - return ptr; -} - -static int cdata_tointeger(lua_State* L, int idx, ptrdiff_t* val) -{ - struct ctype ct; - void* addr = to_cdata(L, idx, &ct); - lua_pop(L, 1); - - if (ct.pointers) { - return 0; - } - - switch (ct.type) { - case INT8_TYPE: - *val = *(int8_t*)addr; - return 1; - case INT16_TYPE: - *val = *(int16_t*)addr; - return 1; - case INT32_TYPE: - *val = *(int32_t*)addr; - return 1; - case INT64_TYPE: - *val = *(int64_t*)addr; - return 1; - default: - return 0; - } -} - -static int64_t check_intptr(lua_State* L, int idx, void* p, struct ctype* ct) -{ - if (ct->type == INVALID_TYPE) { - int64_t ret; - memset(ct, 0, sizeof(*ct)); - ct->base_size = 8; - ct->type = INT64_TYPE; - ct->is_defined = 1; - ret = luaL_checknumber(L, idx); - return ret; - - } else if (ct->pointers) { - return (intptr_t) p; - } - - switch (ct->type) { - case INTPTR_TYPE: - case FUNCTION_PTR_TYPE: - return *(intptr_t*) p; - - case INT64_TYPE: - return *(int64_t*) p; - - case INT32_TYPE: - return ct->is_unsigned ? (int64_t) *(uint32_t*) p : (int64_t) *(int32_t*) p; - - case INT16_TYPE: - return ct->is_unsigned ? (int64_t) *(uint16_t*) p : (int64_t) *(int16_t*) p; - - case INT8_TYPE: - return ct->is_unsigned ? (int64_t) *(uint8_t*) p : (int64_t) *(int8_t*) p; - - default: - type_error(L, idx, "intptr_t", 0, NULL); - return 0; - } -} - -static int get_cfunction_address(lua_State* L, int idx, cfunction* addr); - -#define TO_NUMBER(TYPE, ALLOW_POINTERS, LUA_TONUMBER) \ - TYPE ret = 0; \ - void* p; \ - struct ctype ct; \ - cfunction f; \ - \ - switch (lua_type(L, idx)) { \ - case LUA_TBOOLEAN: \ - ret = (TYPE) lua_toboolean(L, idx); \ - break; \ - \ - case LUA_TNUMBER: \ - ret = (TYPE) LUA_TONUMBER(L, idx); \ - break; \ - \ - case LUA_TSTRING: \ - if (!ALLOW_POINTERS) { \ - type_error(L, idx, #TYPE, 0, NULL); \ - } \ - ret = (TYPE) (intptr_t) lua_tostring(L, idx); \ - break; \ - \ - case LUA_TLIGHTUSERDATA: \ - if (!ALLOW_POINTERS) { \ - type_error(L, idx, #TYPE, 0, NULL); \ - } \ - ret = (TYPE) (intptr_t) lua_topointer(L, idx); \ - break; \ - \ - case LUA_TFUNCTION: \ - if (!ALLOW_POINTERS) { \ - type_error(L, idx, #TYPE, 0, NULL); \ - } \ - if (!get_cfunction_address(L, idx, &f)) { \ - type_error(L, idx, #TYPE, 0, NULL); \ - } \ - ret = (TYPE) (intptr_t) f; \ - break; \ - \ - case LUA_TUSERDATA: \ - p = to_cdata(L, idx, &ct); \ - \ - if (ct.type == INVALID_TYPE) { \ - if (!ALLOW_POINTERS) { \ - type_error(L, idx, #TYPE, 0, NULL); \ - } \ - ret = (TYPE) (intptr_t) userdata_toptr(L, idx); \ - } else if (ct.pointers || ct.type == STRUCT_TYPE || ct.type == UNION_TYPE) {\ - if (!ALLOW_POINTERS) { \ - type_error(L, idx, #TYPE, 0, NULL); \ - } \ - ret = (TYPE) (intptr_t) p; \ - } else if (ct.type == COMPLEX_DOUBLE_TYPE) { \ - ret = (TYPE) creal(*(complex_double*) p); \ - } else if (ct.type == COMPLEX_FLOAT_TYPE) { \ - ret = (TYPE) crealf(*(complex_float*) p); \ - } else if (ct.type == DOUBLE_TYPE) { \ - ret = (TYPE) *(double*) p; \ - } else if (ct.type == FLOAT_TYPE) { \ - ret = (TYPE) *(float*) p; \ - } else { \ - ret = check_intptr(L, idx, p, &ct); \ - } \ - lua_pop(L, 1); \ - break; \ - \ - case LUA_TNIL: \ - ret = (TYPE) 0; \ - break; \ - \ - default: \ - type_error(L, idx, #TYPE, 0, NULL); \ - } \ - -static int64_t cast_int64(lua_State* L, int idx, int is_cast) -{ TO_NUMBER(int64_t, is_cast, lua_tointeger); return ret; } - -static uint64_t cast_uint64(lua_State* L, int idx, int is_cast) -{ TO_NUMBER(uint64_t, is_cast, lua_tointeger); return ret; } - -int32_t check_int32(lua_State* L, int idx) -{ return (int32_t) cast_int64(L, idx, 0); } - -uint32_t check_uint32(lua_State* L, int idx) -{ return (uint32_t) cast_uint64(L, idx, 0); } - -int64_t check_int64(lua_State* L, int idx) -{ return cast_int64(L, idx, 0); } - -uint64_t check_uint64(lua_State* L, int idx) -{ return cast_uint64(L, idx, 0); } - -double check_double(lua_State* L, int idx) -{ TO_NUMBER(double, 0, lua_tonumber); return ret; } - -float check_float(lua_State* L, int idx) -{ TO_NUMBER(double, 0, lua_tonumber); return ret; } - -uintptr_t check_uintptr(lua_State* L, int idx) -{ TO_NUMBER(uintptr_t, 1, lua_tointeger); return ret; } - -complex_double check_complex_double(lua_State* L, int idx) -{ - double real = 0, imag = 0; - void* p; - struct ctype ct; - - switch (lua_type(L, idx)) { - case LUA_TNUMBER: - real = (double) lua_tonumber(L, idx); - break; - case LUA_TTABLE: - lua_rawgeti(L, idx, 1); - real = check_double(L, -1); - lua_pop(L, 1); - - lua_rawgeti(L, idx, 2); - if (lua_isnil(L, -1)) { - imag = real; - } else { - imag = check_double(L, -1); - } - lua_pop(L, 1); - break; - case LUA_TUSERDATA: - p = to_cdata(L, idx, &ct); - if (ct.type == COMPLEX_DOUBLE_TYPE) { - real = creal(*(complex_double*) p); - imag = cimag(*(complex_double*) p); - } else if (ct.type == COMPLEX_FLOAT_TYPE) { - real = crealf(*(complex_float*) p); - imag = cimagf(*(complex_float*) p); - } else if (ct.type == DOUBLE_TYPE) { - real = *(double*) p; - } else if (ct.type == FLOAT_TYPE) { - real = *(float*) p; - } else { - real = check_intptr(L, idx, p, &ct); - } - lua_pop(L, 1); - break; - - default: - type_error(L, idx, "complex", 0, NULL); - } - - return mk_complex_double(real, imag); -} - -complex_float check_complex_float(lua_State* L, int idx) -{ - complex_double d = check_complex_double(L, idx); - return mk_complex_float(creal(d), cimag(d)); -} - -static size_t unpack_vararg(lua_State* L, int i, char* to) -{ - void* p; - struct ctype ct; - - switch (lua_type(L, i)) { - case LUA_TBOOLEAN: - *(int*) to = lua_toboolean(L, i); - return sizeof(int); - - case LUA_TNUMBER: - *(double*) to = lua_tonumber(L, i); // TODO in Lua 5.3: lua_tointeger sometimes should be here - return sizeof(double); - - case LUA_TSTRING: - *(const char**) to = lua_tostring(L, i); - return sizeof(const char*); - - case LUA_TLIGHTUSERDATA: - *(void**) to = lua_touserdata(L, i); - return sizeof(void*); - - case LUA_TUSERDATA: - p = to_cdata(L, i, &ct); - lua_pop(L, 1); - - if (ct.type == INVALID_TYPE) { - *(void**) to = userdata_toptr(L, i); - return sizeof(void*); - - } else if (ct.pointers || ct.type == INTPTR_TYPE) { - *(void**) to = p; - return sizeof(void*); - - } else if (ct.type == INT32_TYPE) { - *(int32_t*) to = *(int32_t*) p; - return sizeof(int32_t); - - } else if (ct.type == INT64_TYPE) { - *(int64_t*) to = *(int64_t*) p; - return sizeof(int64_t); - } - goto err; - - case LUA_TNIL: - *(void**) to = NULL; - return sizeof(void*); - - default: - goto err; - } - -err: - return type_error(L, i, "vararg", 0, NULL); -} - -void unpack_varargs_stack(lua_State* L, int first, int last, char* to) -{ - int i; - - for (i = first; i <= last; i++) { - to += unpack_vararg(L, i, to); - } -} - -void unpack_varargs_stack_skip(lua_State* L, int first, int last, int ints_to_skip, int floats_to_skip, char* to) -{ - int i; - - for (i = first; i <= last; i++) { - int type = lua_type(L, i); - - if (type == LUA_TNUMBER && --floats_to_skip >= 0) { - continue; - } else if (type != LUA_TNUMBER && --ints_to_skip >= 0) { - continue; - } - - to += unpack_vararg(L, i, to); - } -} - -void unpack_varargs_float(lua_State* L, int first, int last, int max, char* to) -{ - int i; - - for (i = first; i <= last && max > 0; i++) { - if (lua_type(L, i) == LUA_TNUMBER) { - unpack_vararg(L, i, to); - to += sizeof(double); - max--; - } - } -} - -void unpack_varargs_int(lua_State* L, int first, int last, int max, char* to) -{ - int i; - - for (i = first; i <= last && max > 0; i++) { - if (lua_type(L, i) != LUA_TNUMBER) { - unpack_vararg(L, i, to); - to += sizeof(void*); - max--; - } - } -} - -void unpack_varargs_reg(lua_State* L, int first, int last, char* to) -{ - int i; - - for (i = first; i <= last; i++) { - unpack_vararg(L, i, to); - to += sizeof(double); - } -} - -/* to_enum tries to convert a value at idx to the enum type indicated by to_ct - * and uv to_usr. For strings this means it will do a string lookup for the - * enum type. It leaves the stack unchanged. Will throw an error if the type - * at idx can't be conerted. - */ -int32_t check_enum(lua_State* L, int idx, int to_usr, const struct ctype* to_ct) -{ - int32_t ret; - - switch (lua_type(L, idx)) { - case LUA_TSTRING: - /* lookup string in to_usr to find value */ - to_usr = lua_absindex(L, to_usr); - lua_pushvalue(L, idx); - lua_rawget(L, to_usr); - - if (lua_isnil(L, -1)) { - goto err; - } - - ret = (int32_t) lua_tointeger(L, -1); - lua_pop(L, 1); - return ret; - - case LUA_TUSERDATA: - return check_int32(L, idx); - - case LUA_TNIL: - return (int32_t) 0; - - case LUA_TNUMBER: - return (int32_t) lua_tointeger(L, idx); - - default: - goto err; - } - -err: - return type_error(L, idx, NULL, to_usr, to_ct); -} - -/* to_pointer tries converts a value at idx to a pointer. It fills out ct and - * pushes the uv of the found type. It will throw a lua error if it can not - * convert the value to a pointer. */ -static void* check_pointer(lua_State* L, int idx, struct ctype* ct) -{ - void* p; - memset(ct, 0, sizeof(*ct)); - idx = lua_absindex(L, idx); - - switch (lua_type(L, idx)) { - case LUA_TNIL: - ct->type = VOID_TYPE; - ct->pointers = 1; - ct->is_null = 1; - lua_pushnil(L); - return NULL; - - case LUA_TNUMBER: - ct->type = INTPTR_TYPE; - ct->is_unsigned = 1; - ct->pointers = 0; - lua_pushnil(L); - return (void*) (uintptr_t) lua_tonumber(L, idx); // TODO in Lua 5.3: maybe change to lua_tointeger - - case LUA_TLIGHTUSERDATA: - ct->type = VOID_TYPE; - ct->pointers = 1; - lua_pushnil(L); - return lua_touserdata(L, idx); - - case LUA_TSTRING: - ct->type = INT8_TYPE; - ct->pointers = 1; - ct->is_unsigned = IS_CHAR_UNSIGNED; - ct->is_array = 1; - ct->base_size = 1; - ct->const_mask = 2; - lua_pushnil(L); - return (void*) lua_tolstring(L, idx, &ct->array_size); - - case LUA_TUSERDATA: - p = to_cdata(L, idx, ct); - - if (ct->type == INVALID_TYPE) { - /* some other type of user data */ - ct->type = VOID_TYPE; - ct->pointers = 1; - return userdata_toptr(L, idx); - } else if (ct->type == STRUCT_TYPE || ct->type == UNION_TYPE) { - return p; - } else { - return (void*) (intptr_t) check_intptr(L, idx, p, ct); - } - break; - } - - type_error(L, idx, "pointer", 0, NULL); - return NULL; -} - -static int is_void_ptr(const struct ctype* ct) -{ - return ct->type == VOID_TYPE - && ct->pointers == 1; -} - -static int is_same_type(lua_State* L, int usr1, int usr2, const struct ctype* t1, const struct ctype* t2) -{ - if (t1->type != t2->type) { - return 0; - } - -#if LUA_VERSION_NUM == 501 - if (lua_isnil(L, usr1) != lua_isnil(L, usr2)) { - int ret; - usr1 = lua_absindex(L, usr1); - usr2 = lua_absindex(L, usr2); - push_upval(L, &niluv_key); - - ret = lua_rawequal(L, usr1, -1) - || lua_rawequal(L, usr2, -1); - - lua_pop(L, 1); - - if (ret) { - return 1; - } - } -#endif - - return lua_rawequal(L, usr1, usr2); -} - -static void set_struct(lua_State* L, int idx, void* to, int to_usr, const struct ctype* tt, int check_pointers); - -/* to_typed_pointer converts a value at idx to a type tt with target uv to_usr - * checking all types. May push a temporary value so that it can create - * structs on the fly. */ -void* check_typed_pointer(lua_State* L, int idx, int to_usr, const struct ctype* tt) -{ - struct ctype ft; - void* p; - - to_usr = lua_absindex(L, to_usr); - idx = lua_absindex(L, idx); - - if (tt->pointers == 1 && (tt->type == STRUCT_TYPE || tt->type == UNION_TYPE) && lua_type(L, idx) == LUA_TTABLE) { - /* need to construct a struct of the target type */ - struct ctype ct = *tt; - ct.pointers = ct.is_array = 0; - p = push_cdata(L, to_usr, &ct); - set_struct(L, idx, p, to_usr, &ct, 1); - return p; - } - - p = check_pointer(L, idx, &ft); - - if (tt->pointers == 1 && ft.pointers == 0 && (ft.type == STRUCT_TYPE || ft.type == UNION_TYPE)) { - /* auto dereference structs */ - ft.pointers = 1; - ft.const_mask <<= 1; - } - - if (is_void_ptr(tt)) { - /* any pointer can convert to void* */ - goto suc; - - } else if (is_void_ptr(&ft) && (ft.pointers || ft.is_reference)) { - /* void* can convert to any pointer */ - goto suc; - - } else if (ft.is_null) { - /* NULL can convert to any pointer */ - goto suc; - - } else if (!is_same_type(L, to_usr, -1, tt, &ft)) { - /* the base type is different */ - goto err; - - } else if (tt->pointers != ft.pointers) { - goto err; - - } else if (ft.const_mask & ~tt->const_mask) { - /* for every const in from it must be in to, there are further rules - * for const casting (see the c++ spec), but they are hard to test - * quickly */ - goto err; - } - -suc: - return p; - -err: - type_error(L, idx, NULL, to_usr, tt); - return NULL; -} - -/** - * gets the address of the wrapped C function for the lua function value at idx - * and returns 1 if it exists; otherwise returns 0 and nothing is pushed */ -static int get_cfunction_address(lua_State* L, int idx, cfunction* addr) -{ - if (!lua_isfunction(L, idx)) return 0; - - int top = lua_gettop(L); - - // Get the last upvalue - int n = 2; - while (lua_getupvalue(L, idx, n)) { - lua_pop(L, 1); - n++; - } - - if (!lua_getupvalue(L, idx, n - 1)) - return 0; - - if (!lua_isuserdata(L, -1) || !lua_getmetatable(L, -1)) { - lua_pop(L, 1); - return 0; - } - - push_upval(L, &callback_mt_key); - if (!lua_rawequal(L, -1, -2)) { - lua_pop(L, 3); - return 0; - } - - /* stack is: - * userdata upval - * metatable - * callback_mt - */ - - cfunction* f = lua_touserdata(L, -3); - *addr = f[1]; - lua_pop(L, 3); - return 1; -} - -/* to_cfunction converts a value at idx with usr table at to_usr and type tt - * into a function. Leaves the stack unchanged. */ -static cfunction check_cfunction(lua_State* L, int idx, int to_usr, const struct ctype* tt, int check_pointers) -{ - void* p; - struct ctype ft; - cfunction f; - int top = lua_gettop(L); - - idx = lua_absindex(L, idx); - to_usr = lua_absindex(L, to_usr); - - switch (lua_type(L, idx)) { - case LUA_TFUNCTION: - if (get_cfunction_address(L, idx, &f)) { - return f; - } - - /* Function cdatas are pinned and must be manually cleaned up by - * calling func:free(). */ - push_upval(L, &callbacks_key); - f = compile_callback(L, idx, to_usr, tt); - lua_pushboolean(L, 1); - lua_rawset(L, -3); - lua_pop(L, 1); /* callbacks tbl */ - return f; - - case LUA_TNIL: - return NULL; - - case LUA_TLIGHTUSERDATA: - if (check_pointers) { - goto err; - } else { - return (cfunction) lua_touserdata(L, idx); - } - - case LUA_TUSERDATA: - p = to_cdata(L, idx, &ft); - assert(lua_gettop(L) == top + 1); - - if (ft.type == INVALID_TYPE) { - if (check_pointers) { - goto err; - } else { - lua_pop(L, 1); - return (cfunction) lua_touserdata(L, idx); - } - - } else if (ft.is_null) { - lua_pop(L, 1); - return NULL; - - } else if (!check_pointers && (ft.pointers || ft.type == INTPTR_TYPE)) { - lua_pop(L, 1); - return (cfunction) *(void**) p; - - } else if (ft.type != FUNCTION_PTR_TYPE) { - goto err; - - } else if (!check_pointers) { - lua_pop(L, 1); - return *(cfunction*) p; - - } else if (ft.calling_convention != tt->calling_convention) { - goto err; - - } else if (!is_same_type(L, -1, to_usr, &ft, tt)) { - goto err; - - } else { - lua_pop(L, 1); - return *(cfunction*) p; - } - - default: - goto err; - } - -err: - type_error(L, idx, NULL, to_usr, tt); - return NULL; -} - -/* to_type_cfunction converts a value at idx with uv at to_usr and type tt to - * a cfunction. Leaves the stack unchanged. */ -cfunction check_typed_cfunction(lua_State* L, int idx, int to_usr, const struct ctype* tt) -{ return check_cfunction(L, idx, to_usr, tt, 1); } - -static void set_value(lua_State* L, int idx, void* to, int to_usr, const struct ctype* tt, int check_pointers); - -static void set_array(lua_State* L, int idx, void* to, int to_usr, const struct ctype* tt, int check_pointers) -{ - size_t i, sz, esz; - struct ctype et; - - idx = lua_absindex(L, idx); - to_usr = lua_absindex(L, to_usr); - - switch (lua_type(L, idx)) { - case LUA_TSTRING: - if (tt->pointers == 1 && tt->type == INT8_TYPE) { - const char* str = lua_tolstring(L, idx, &sz); - - if (!tt->is_variable_array && sz >= tt->array_size) { - memcpy(to, str, tt->array_size); - } else { - /* include nul terminator */ - memcpy(to, str, sz+1); - } - } else { - goto err; - } - break; - - case LUA_TTABLE: - et = *tt; - et.pointers--; - et.const_mask >>= 1; - et.is_array = 0; - esz = et.pointers ? sizeof(void*) : et.base_size; - - lua_rawgeti(L, idx, 2); - - if (tt->is_variable_array) { - /* we have no idea how big the array is, so set values based off - * how many items were given to us */ - lua_pop(L, 1); - for (i = 0; i < lua_rawlen(L, idx); i++) { - lua_rawgeti(L, idx, (int) i + 1); - set_value(L, -1, (char*) to + esz * i, to_usr, &et, check_pointers); - lua_pop(L, 1); - } - - } else if (lua_isnil(L, -1)) { - /* there is no second element, so we set the whole array to the - * first element (or nil - ie 0) if there is no first element) */ - lua_pop(L, 1); - lua_rawgeti(L, idx, 1); - - if (lua_isnil(L, -1)) { - memset(to, 0, ctype_size(L, tt)); - } else { - /* if its still variable we have no idea how many values to set */ - for (i = 0; i < tt->array_size; i++) { - set_value(L, -1, (char*) to + esz * i, to_usr, &et, check_pointers); - } - } - - lua_pop(L, 1); - - } else { - /* there is a second element, so we set each element using the - * equiv index in the table initializer */ - lua_pop(L, 1); - for (i = 0; i < tt->array_size; i++) { - lua_rawgeti(L, idx, (int) (i+1)); - - if (lua_isnil(L, -1)) { - /* we've hit the end of the values provided in the - * initializer, so memset the rest to zero */ - lua_pop(L, 1); - memset((char*) to + esz * i, 0, (tt->array_size - i) * esz); - break; - - } else { - set_value(L, -1, (char*) to + esz * i, to_usr, &et, check_pointers); - lua_pop(L, 1); - } - } - } - break; - - default: - goto err; - } - - return; - -err: - type_error(L, idx, NULL, to_usr, tt); -} - -/* pops the member key from the stack, leaves the member user value on the - * stack. Returns the member offset. Returns -ve if the member can not be - * found. */ -static ptrdiff_t get_member(lua_State* L, int usr, const struct ctype* ct, struct ctype* mt) -{ - ptrdiff_t off; - lua_rawget(L, usr); - - if (lua_isnil(L, -1)) { - lua_pop(L, 1); - return -1; - } - - *mt = *(const struct ctype*) lua_touserdata(L, -1); - lua_getuservalue(L, -1); - lua_replace(L, -2); - - if (mt->is_variable_array && ct->variable_size_known) { - /* eg char mbr[?] */ - size_t sz = (mt->pointers > 1) ? sizeof(void*) : mt->base_size; - assert(ct->is_variable_struct && mt->is_array); - mt->array_size = ct->variable_increment / sz; - mt->is_variable_array = 0; - - } else if (mt->is_variable_struct && ct->variable_size_known) { - /* eg struct {char a; char b[?]} mbr; */ - assert(ct->is_variable_struct); - mt->variable_size_known = 1; - mt->variable_increment = ct->variable_increment; - } - - off = mt->offset; - mt->offset = 0; - return off; -} - -static void set_struct(lua_State* L, int idx, void* to, int to_usr, const struct ctype* tt, int check_pointers) -{ - int have_first = 0; - int have_other = 0; - struct ctype mt; - void* p; - - to_usr = lua_absindex(L, to_usr); - idx = lua_absindex(L, idx); - - switch (lua_type(L, idx)) { - case LUA_TTABLE: - /* match up to the members based off the table initializers key - this - * will match both numbered and named members in the user table - * we need a special case for when no entries in the initializer - - * zero initialize the c struct, and only one entry in the initializer - * - set all members to this value */ - memset(to, 0, ctype_size(L, tt)); - lua_pushnil(L); - while (lua_next(L, idx)) { - ptrdiff_t off; - - if (!have_first && lua_tonumber(L, -2) == 1 && lua_tonumber(L, -1) != 0) { - have_first = 1; - } else if (!have_other && (lua_type(L, -2) != LUA_TNUMBER || lua_tonumber(L, -2) != 1)) { - have_other = 1; - } - - lua_pushvalue(L, -2); - off = get_member(L, to_usr, tt, &mt); - assert(off >= 0); - set_value(L, -2, (char*) to + off, -1, &mt, check_pointers); - - /* initializer value, mt usr */ - lua_pop(L, 2); - } - - /* if we only had a single non zero value then initialize all members to that value */ - if (!have_other && have_first && tt->type != UNION_TYPE) { - size_t i, sz; - ptrdiff_t off; - lua_rawgeti(L, idx, 1); - sz = lua_rawlen(L, to_usr); - - for (i = 2; i < sz; i++) { - lua_pushinteger(L, i); - off = get_member(L, to_usr, tt, &mt); - assert(off >= 0); - set_value(L, -2, (char*) to + off, -1, &mt, check_pointers); - lua_pop(L, 1); /* mt usr */ - } - - lua_pop(L, 1); /* initializer table */ - } - break; - - case LUA_TUSERDATA: - if (check_pointers) { - p = check_typed_pointer(L, idx, to_usr, tt); - } else { - struct ctype ct; - p = check_pointer(L, idx, &ct); - } - memcpy(to, p, tt->base_size); - lua_pop(L, 1); - break; - - default: - goto err; - } - - return; - -err: - type_error(L, idx, NULL, to_usr, tt); -} - -static void set_value(lua_State* L, int idx, void* to, int to_usr, const struct ctype* tt, int check_pointers) -{ - int top = lua_gettop(L); - - if (tt->is_array) { - set_array(L, idx, to, to_usr, tt, check_pointers); - - } else if (tt->pointers || tt->is_reference) { - union { - uint8_t c[sizeof(void*)]; - void* p; - } u; - - if (lua_istable(L, idx)) { - luaL_error(L, "Can't set a pointer member to a struct that's about to be freed"); - } - - if (check_pointers) { - u.p = check_typed_pointer(L, idx, to_usr, tt); - } else { - struct ctype ct; - u.p = check_pointer(L, idx, &ct); - } - -#ifndef ALLOW_MISALIGNED_ACCESS - if ((uintptr_t) to & PTR_ALIGN_MASK) { - memcpy(to, u.c, sizeof(void*)); - } else -#endif - { - *(void**) to = u.p; - } - - lua_pop(L, 1); - - } else if (tt->is_bitfield) { - - uint64_t hi_mask = UINT64_C(0) - (UINT64_C(1) << (tt->bit_offset + tt->bit_size)); - uint64_t low_mask = (UINT64_C(1) << tt->bit_offset) - UINT64_C(1); - uint64_t val = check_uint64(L, idx); - val &= (UINT64_C(1) << tt->bit_size) - 1; - val <<= tt->bit_offset; - *(uint64_t*) to = val | (*(uint64_t*) to & (hi_mask | low_mask)); - - } else if (tt->type == STRUCT_TYPE || tt->type == UNION_TYPE) { - set_struct(L, idx, to, to_usr, tt, check_pointers); - - } else { - -#ifndef ALLOW_MISALIGNED_ACCESS - union { - uint8_t c[8]; - _Bool b; - uint64_t u64; - float f; - double d; - cfunction func; - } misalign; - - void* origto = to; - - if ((uintptr_t) origto & (tt->base_size - 1)) { - to = misalign.c; - } -#endif - - switch (tt->type) { - case BOOL_TYPE: - *(_Bool*) to = (cast_int64(L, idx, !check_pointers) != 0); - break; - case INT8_TYPE: - if (tt->is_unsigned) { - *(uint8_t*) to = (uint8_t) cast_uint64(L, idx, !check_pointers); - } else { - *(int8_t*) to = (int8_t) cast_int64(L, idx, !check_pointers); - } - break; - case INT16_TYPE: - if (tt->is_unsigned) { - *(uint16_t*) to = (uint16_t) cast_uint64(L, idx, !check_pointers); - } else { - *(int16_t*) to = (int16_t) cast_int64(L, idx, !check_pointers); - } - break; - case INT32_TYPE: - if (tt->is_unsigned) { - *(uint32_t*) to = (uint32_t) cast_uint64(L, idx, !check_pointers); - } else { - *(int32_t*) to = (int32_t) cast_int64(L, idx, !check_pointers); - } - break; - case INT64_TYPE: - if (tt->is_unsigned) { - *(uint64_t*) to = cast_uint64(L, idx, !check_pointers); - } else { - *(int64_t*) to = cast_int64(L, idx, !check_pointers); - } - break; - case FLOAT_TYPE: - *(float*) to = (float) check_double(L, idx); - break; - case DOUBLE_TYPE: - *(double*) to = check_double(L, idx); - break; - case COMPLEX_FLOAT_TYPE: - *(complex_float*) to = check_complex_float(L, idx); - break; - case COMPLEX_DOUBLE_TYPE: - *(complex_double*) to = check_complex_double(L, idx); - break; - case INTPTR_TYPE: - *(uintptr_t*) to = check_uintptr(L, idx); - break; - case ENUM_TYPE: - *(int32_t*) to = check_enum(L, idx, to_usr, tt); - break; - case FUNCTION_PTR_TYPE: - *(cfunction*) to = check_cfunction(L, idx, to_usr, tt, check_pointers); - break; - default: - goto err; - } - -#ifndef ALLOW_MISALIGNED_ACCESS - if ((uintptr_t) origto & (tt->base_size - 1)) { - memcpy(origto, misalign.c, tt->base_size); - } -#endif - } - - assert(lua_gettop(L) == top); - return; -err: - type_error(L, idx, NULL, to_usr, tt); -} - -static int ffi_typeof(lua_State* L) -{ - struct ctype ct; - check_ctype(L, 1, &ct); - push_ctype(L, -1, &ct); - return 1; -} - -static void setmintop(lua_State* L, int idx) -{ - if (lua_gettop(L) < idx) { - lua_settop(L, idx); - } -} - -/* warning: in the case that it finds an array size, it removes that index */ -static void get_variable_array_size(lua_State* L, int idx, struct ctype* ct) -{ - /* we only care about the variable buisness for the variable array - * directly ie ffi.new('char[?]') or the struct that contains the variable - * array ffi.new('struct {char v[?]}'). A pointer to the struct doesn't - * care about the variable size (it treats it as a zero sized array). */ - - if (ct->is_variable_array) { - assert(ct->is_array); - ct->array_size = (size_t) luaL_checknumber(L, idx); - ct->is_variable_array = 0; - lua_remove(L, idx); - - } else if (ct->is_variable_struct && !ct->variable_size_known) { - assert(ct->type == STRUCT_TYPE && !ct->is_array); - ct->variable_increment *= (size_t) luaL_checknumber(L, idx); - ct->variable_size_known = 1; - lua_remove(L, idx); - } -} - -static int is_scalar(struct ctype* ct) -{ - int type = ct->type; - if (ct->pointers || ct->is_reference) { - return !ct->is_array; - } - return type != STRUCT_TYPE && type != UNION_TYPE && !IS_COMPLEX(type); -} - -static int should_pack(lua_State *L, int ct_usr, struct ctype* ct, int idx) -{ - struct ctype argt; - ct_usr = lua_absindex(L, ct_usr); - - if (IS_COMPLEX(ct->type)) { - return 0; - } - - switch (lua_type(L, idx)) { - case LUA_TTABLE: - return 0; - case LUA_TSTRING: - return ct->type == STRUCT_TYPE; - case LUA_TUSERDATA: - // don't pack if the argument is a cdata with the same type - to_cdata(L, idx, &argt); - int same = is_same_type(L, ct_usr, -1, ct, &argt); - lua_pop(L, 1); - return !same; - default: - return 1; - } -} - -static int do_new(lua_State* L, int is_cast) -{ - int cargs, i; - void* p; - struct ctype ct; - int check_ptrs = !is_cast; - - check_ctype(L, 1, &ct); - - /* don't push a callback when we have a c function, as cb:set needs a - * compiled callback from a lua function to work */ - if (!ct.pointers && ct.type == FUNCTION_PTR_TYPE && (lua_isnil(L, 2) || lua_isfunction(L, 2))) { - // Get the bound C function if this is a ffi lua function - cfunction func; - if (get_cfunction_address(L, 2, &func)) { - p = push_cdata(L, -1, &ct); - *(cfunction*) p = func; - return 1; - } - - /* Function cdatas are pinned and must be manually cleaned up by - * calling func:free(). */ - compile_callback(L, 2, -1, &ct); - push_upval(L, &callbacks_key); - lua_pushvalue(L, -2); - lua_pushboolean(L, 1); - lua_rawset(L, -3); - lua_pop(L, 1); /* callbacks tbl */ - return 1; - } - - /* this removes the vararg argument if its needed, and errors if its invalid */ - if (!is_cast) { - get_variable_array_size(L, 2, &ct); - } - - p = push_cdata(L, -1, &ct); - - /* if the user mt has a __gc function then call ffi.gc on this value */ - if (push_user_mt(L, -2, &ct)) { - push_upval(L, &gc_key); - lua_pushvalue(L, -3); - - /* user_mt.__gc */ - lua_pushliteral(L, "__gc"); - lua_rawget(L, -4); - - lua_rawset(L, -3); /* gc_upval[cdata] = user_mt.__gc */ - lua_pop(L, 2); /* user_mt and gc_upval */ - } - - /* stack is: - * ctype arg - * ctor args ... 0+ - * ctype usr - * cdata - */ - - cargs = lua_gettop(L) - 3; - - if (cargs == 0) { - return 1; - } - - int scalar = is_scalar(&ct); - if (scalar && cargs > 1) { - return luaL_error(L, "too many initializers"); - } - - if (cargs > 1 || (!scalar && should_pack(L, -2, &ct, 2))) { - lua_createtable(L, cargs, 0); - lua_replace(L, 1); - for (i = 1; i <= cargs; i++) { - lua_pushvalue(L, i + 1); - lua_rawseti(L, 1, i); - } - assert(lua_gettop(L) == cargs + 3); - set_value(L, 1, p, -2, &ct, check_ptrs); - return 1; - } - - set_value(L, 2, p, -2, &ct, check_ptrs); - return 1; -} - -static int ffi_new(lua_State* L) -{ return do_new(L, 0); } - -static int ffi_cast(lua_State* L) -{ return do_new(L, 1); } - -static int ctype_new(lua_State* L) -{ return do_new(L, 0); } - -static int ctype_call(lua_State* L) -{ - struct ctype ct; - int top = lua_gettop(L); - - check_ctype(L, 1, &ct); - - if (push_user_mt(L, -1, &ct)) { - lua_pushstring(L, "__new"); - lua_rawget(L, -2); - if (!lua_isnil(L, -1)) { - lua_insert(L, 1); // function at bottom of stack under args - lua_pop(L, 2); - lua_call(L, top, 1); - return 1; - } - lua_pop(L, 2); - } - lua_pop(L, 1); - - assert(lua_gettop(L) == top); - return do_new(L, 0); -} - -static int ffi_sizeof(lua_State* L) -{ - struct ctype ct; - check_ctype(L, 1, &ct); - get_variable_array_size(L, 2, &ct); - lua_pushinteger(L, ctype_size(L, &ct)); - return 1; -} - -static int ffi_alignof(lua_State* L) -{ - struct ctype ct, mt; - lua_settop(L, 2); - check_ctype(L, 1, &ct); - - /* if no member is specified then we return the alignment of the type */ - if (lua_isnil(L, 2)) { - lua_pushinteger(L, ct.align_mask + 1); - return 1; - } - - /* get the alignment of the member */ - lua_pushvalue(L, 2); - if (get_member(L, -2, &ct, &mt) < 0) { - push_type_name(L, 3, &ct); - return luaL_error(L, "type %s has no member %s", lua_tostring(L, -1), lua_tostring(L, 2)); - } - - lua_pushinteger(L, mt.align_mask + 1); - return 1; -} - -static int ffi_offsetof(lua_State* L) -{ - ptrdiff_t off; - struct ctype ct, mt; - lua_settop(L, 2); - check_ctype(L, 1, &ct); - - lua_pushvalue(L, 2); - off = get_member(L, -2, &ct, &mt); /* this replaces the member key at -1 with the mbr usr value */ - if (off < 0) { - push_type_name(L, 3, &ct); - return luaL_error(L, "type %s has no member %s", lua_tostring(L, -1), lua_tostring(L, 2)); - } - - lua_pushinteger(L, off); - - if (!mt.is_bitfield) { - return 1; - } - - lua_pushinteger(L, mt.bit_offset); - lua_pushinteger(L, mt.bit_size); - return 3; -} - -static int ffi_istype(lua_State* L) -{ - struct ctype tt, ft; - check_ctype(L, 1, &tt); - to_cdata(L, 2, &ft); - - if (ft.type == INVALID_TYPE) { - goto fail; - } - - if (!is_same_type(L, 3, 4, &tt, &ft)) { - goto fail; - } - - if (tt.pointers != ft.pointers) { - goto fail; - } - - if (tt.is_array != ft.is_array) { - goto fail; - } - - if (tt.is_array && tt.array_size != ft.array_size) { - goto fail; - } - - if (tt.calling_convention != ft.calling_convention) { - goto fail; - } - - lua_pushboolean(L, 1); - return 1; - -fail: - lua_pushboolean(L, 0); - return 1; -} - -static int cdata_gc(lua_State* L) -{ - struct ctype ct; - check_cdata(L, 1, &ct); - lua_settop(L, 1); - - /* call the gc func if there is any registered */ - lua_pushvalue(L, 1); - lua_rawget(L, lua_upvalueindex(2)); - if (!lua_isnil(L, -1)) { - lua_pushvalue(L, 1); - lua_pcall(L, 1, 0, 0); - } - - /* unset the closure */ - lua_pushvalue(L, 1); - lua_pushnil(L); - lua_rawset(L, lua_upvalueindex(1)); - - return 0; -} - -static int callback_free(lua_State* L) -{ - cfunction* p = (cfunction*) lua_touserdata(L, 1); - // FIXME: temporarily disabled to prevent SIGTRAP on exit - // free_code(get_jit(L), L, *p); - return 0; -} - -static int cdata_free(lua_State* L) -{ - struct ctype ct; - cfunction* p = (cfunction*) check_cdata(L, 1, &ct); - lua_settop(L, 1); - - /* unset the closure */ - lua_pushvalue(L, 1); - lua_pushnil(L); - lua_rawset(L, lua_upvalueindex(1)); - - if (ct.is_jitted) { - free_code(get_jit(L), L, *p); - *p = NULL; - } - - return 0; -} - -static int cdata_set(lua_State* L) -{ - struct ctype ct; - cfunction* p = (cfunction*) check_cdata(L, 1, &ct); - luaL_checktype(L, 2, LUA_TFUNCTION); - - if (!ct.is_jitted) { - luaL_error(L, "can't set the function for a non-lua callback"); - } - - if (*p == NULL) { - luaL_error(L, "can't set the function for a free'd callback"); - } - - push_func_ref(L, *p); - lua_pushvalue(L, 2); - lua_rawseti(L, -2, CALLBACK_FUNC_USR_IDX); - - /* remove the closure for this callback as it embeds the function pointer - * value */ - lua_pushvalue(L, 1); - lua_pushboolean(L, 1); - lua_rawset(L, lua_upvalueindex(1)); - - return 0; -} - -static int cdata_call(lua_State* L) -{ - struct ctype ct; - int top = lua_gettop(L); - cfunction* p = (cfunction*) check_cdata(L, 1, &ct); - - if (push_user_mt(L, -1, &ct)) { - lua_pushliteral(L, "__call"); - lua_rawget(L, -2); - - if (!lua_isnil(L, -1)) { - lua_insert(L, 1); - lua_pop(L, 2); /* ct_usr, user_mt */ - lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); - return lua_gettop(L); - } - } - if (ct.pointers || ct.type != FUNCTION_PTR_TYPE) { - return luaL_error(L, "only function callbacks are callable"); - } - - lua_pushvalue(L, 1); - lua_rawget(L, lua_upvalueindex(1)); - - if (!lua_isfunction(L, -1)) { - lua_pop(L, 1); - compile_function(L, *p, -1, &ct); - - assert(lua_gettop(L) == top + 2); /* uv, closure */ - - /* closures[func] = closure */ - lua_pushvalue(L, 1); - lua_pushvalue(L, -2); - lua_rawset(L, lua_upvalueindex(1)); - - lua_replace(L, 1); - } else { - lua_replace(L, 1); - } - - lua_pop(L, 1); /* uv */ - assert(lua_gettop(L) == top); - - lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); - return lua_gettop(L); -} - -static int user_mt_key; - -static int ffi_metatype(lua_State* L) -{ - struct ctype ct; - lua_settop(L, 2); - - check_ctype(L, 1, &ct); - if (lua_type(L, 2) != LUA_TTABLE && lua_type(L, 2) != LUA_TNIL) { - return luaL_argerror(L, 2, "metatable must be a table or nil"); - } - - lua_pushlightuserdata(L, &user_mt_key); - lua_pushvalue(L, 2); - lua_rawset(L, 3); /* user[user_mt_key] = mt */ - - /* return the passed in ctype */ - push_ctype(L, 3, &ct); - return 1; -} - -/* push_user_mt returns 1 if the type has a user metatable and pushes it onto - * the stack, otherwise it returns 0 and pushes nothing */ -int push_user_mt(lua_State* L, int ct_usr, const struct ctype* ct) -{ - if (ct->type != STRUCT_TYPE && ct->type != UNION_TYPE && !IS_COMPLEX(ct->type)) { - return 0; - } - if (!lua_istable(L, ct_usr)) { - return 0; - } - - ct_usr = lua_absindex(L, ct_usr); - lua_pushlightuserdata(L, &user_mt_key); - lua_rawget(L, ct_usr); - - if (lua_isnil(L, -1)) { - lua_pop(L, 1); - return 0; - } - return 1; -} - -static int ffi_gc(lua_State* L) -{ - struct ctype ct; - lua_settop(L, 2); - check_cdata(L, 1, &ct); - - push_upval(L, &gc_key); - lua_pushvalue(L, 1); - lua_pushvalue(L, 2); - lua_rawset(L, -3); - - /* return the cdata back */ - lua_settop(L, 1); - return 1; -} - -/* lookup_cdata_index returns the offset of the found type and user value on - * the stack if valid. Otherwise returns -ve and doesn't touch the stack. - */ -static ptrdiff_t lookup_cdata_index(lua_State* L, int idx, int ct_usr, struct ctype* ct) -{ - struct ctype mt; - ptrdiff_t off; - - ct_usr = lua_absindex(L, ct_usr); - int type = lua_type(L, idx); - - switch (type) { - case LUA_TNUMBER: - case LUA_TUSERDATA: - /* possibilities are array, pointer */ - - if (!ct->pointers || is_void_ptr(ct)) { - return -1; - } - - // unbox cdata - if (type == LUA_TUSERDATA) { - if (!cdata_tointeger(L, idx, &off)) { - return -1; - } - } else { - off = lua_tointeger(L, idx); - } - - ct->is_array = 0; - ct->pointers--; - ct->const_mask >>= 1; - ct->is_reference = 0; - - lua_pushvalue(L, ct_usr); - - return (ct->pointers ? sizeof(void*) : ct->base_size) * off; - - case LUA_TSTRING: - /* possibilities are struct/union, pointer to struct/union */ - - if ((ct->type != STRUCT_TYPE && ct->type != UNION_TYPE) || ct->is_array || ct->pointers > 1) { - return -1; - } - - lua_pushvalue(L, idx); - off = get_member(L, ct_usr, ct, &mt); - if (off < 0) { - return -1; - } - - *ct = mt; - return off; - - default: - return -1; - } -} - -static int cdata_newindex(lua_State* L) -{ - struct ctype tt; - char* to; - ptrdiff_t off; - - lua_settop(L, 3); - - to = (char*) check_cdata(L, 1, &tt); - off = lookup_cdata_index(L, 2, -1, &tt); - - if (off < 0) { - if (!push_user_mt(L, -1, &tt)) { - goto err; - } - - lua_pushliteral(L, "__newindex"); - lua_rawget(L, -2); - - if (lua_isnil(L, -1)) { - goto err; - } - - lua_insert(L, 1); - lua_settop(L, 4); - lua_call(L, 3, LUA_MULTRET); - return lua_gettop(L); - } - - if (tt.const_mask & 1) { - return luaL_error(L, "can't set const data"); - } - - set_value(L, 3, to + off, -1, &tt, 1); - return 0; - -err: - push_type_name(L, 4, &tt); - return luaL_error(L, "type %s has no member %s", lua_tostring(L, -1), lua_tostring(L, 2)); -} - -static int cdata_index(lua_State* L) -{ - void* to; - struct ctype ct; - char* data; - ptrdiff_t off; - - lua_settop(L, 2); - data = (char*) check_cdata(L, 1, &ct); - assert(lua_gettop(L) == 3); - - if (!ct.pointers) { - switch (ct.type) { - case FUNCTION_PTR_TYPE: - /* Callbacks use the same metatable as standard cdata values, but have set - * and free members. So instead of mt.__index = mt, we do the equiv here. */ - lua_getmetatable(L, 1); - lua_pushvalue(L, 2); - lua_rawget(L, -2); - return 1; - - /* This provides the .re and .im virtual members */ - case COMPLEX_DOUBLE_TYPE: - case COMPLEX_FLOAT_TYPE: - if (!lua_isstring(L, 2)) { - luaL_error(L, "invalid member for complex number"); - - } else if (strcmp(lua_tostring(L, 2), "re") == 0) { - lua_pushnumber(L, ct.type == COMPLEX_DOUBLE_TYPE ? creal(*(complex_double*) data) : crealf(*(complex_float*) data)); - - } else if (strcmp(lua_tostring(L, 2), "im") == 0) { - lua_pushnumber(L, ct.type == COMPLEX_DOUBLE_TYPE ? cimag(*(complex_double*) data) : cimagf(*(complex_float*) data)); - - } else { - luaL_error(L, "invalid member for complex number"); - } - return 1; - } - } - - off = lookup_cdata_index(L, 2, -1, &ct); - - if (off < 0) { - assert(lua_gettop(L) == 3); - if (!push_user_mt(L, -1, &ct)) { - goto err; - } - - lua_pushliteral(L, "__index"); - lua_rawget(L, -2); - - if (lua_isnil(L, -1)) { - goto err; - } - - if (lua_istable(L, -1)) { - lua_pushvalue(L, 2); - lua_gettable(L, -2); - return 1; - } - - lua_insert(L, 1); - lua_settop(L, 3); - lua_call(L, 2, LUA_MULTRET); - return lua_gettop(L); - -err: - push_type_name(L, 3, &ct); - return luaL_error(L, "type %s has no member %s", lua_tostring(L, -1), lua_tostring(L, 2)); - } - - assert(lua_gettop(L) == 4); /* ct, key, ct_usr, mbr_usr */ - data += off; - - if (ct.is_array) { - /* push a reference to the array */ - ct.is_reference = 1; - to = push_cdata(L, -1, &ct); - *(void**) to = data; - return 1; - - } else if (ct.is_bitfield) { - - if (ct.type == INT64_TYPE) { - struct ctype rt; - uint64_t val = *(uint64_t*) data; - val >>= ct.bit_offset; - val &= (UINT64_C(1) << ct.bit_size) - 1; - - memset(&rt, 0, sizeof(rt)); - rt.base_size = 8; - rt.type = INT64_TYPE; - rt.is_unsigned = 1; - rt.is_defined = 1; - - to = push_cdata(L, 0, &rt); - *(uint64_t*) to = val; - - return 1; - - } else if (ct.type == BOOL_TYPE) { - uint64_t val = *(uint64_t*) data; - lua_pushboolean(L, (int) (val & (UINT64_C(1) << ct.bit_offset))); - return 1; - - } else { - uint64_t val = *(uint64_t*) data; - val >>= ct.bit_offset; - val &= (UINT64_C(1) << ct.bit_size) - 1; - lua_pushinteger(L, val); - return 1; - } - - } else if (ct.pointers) { -#ifndef ALLOW_MISALIGNED_ACCESS - union { - uint8_t c[8]; - void* p; - } misalignbuf; - - if ((uintptr_t) data & PTR_ALIGN_MASK) { - memcpy(misalignbuf.c, data, sizeof(void*)); - data = misalignbuf.c; - } -#endif - to = push_cdata(L, -1, &ct); - *(void**) to = *(void**) data; - return 1; - - } else if (ct.type == STRUCT_TYPE || ct.type == UNION_TYPE) { - /* push a reference to the member */ - ct.is_reference = 1; - to = push_cdata(L, -1, &ct); - *(void**) to = data; - return 1; - - } else if (ct.type == FUNCTION_PTR_TYPE) { - cfunction* pf = (cfunction*) push_cdata(L, -1, &ct); - *pf = *(cfunction*) data; - return 1; - - } else { -#ifndef ALLOW_MISALIGNED_ACCESS - union { - uint8_t c[8]; - double d; - float f; - uint64_t u64; - } misalignbuf; - - assert(ct.base_size <= 8); - - if ((uintptr_t) data & (ct.base_size - 1)) { - memcpy(misalignbuf.c, data, ct.base_size); - data = misalignbuf.c; - } -#endif - - switch (ct.type) { - case BOOL_TYPE: - lua_pushboolean(L, *(_Bool*) data); - break; - case INT8_TYPE: - lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint8_t*) data : (lua_Integer) *(int8_t*) data); - break; - case INT16_TYPE: - lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint16_t*) data : (lua_Integer) *(int16_t*) data); - break; - case ENUM_TYPE: - case INT32_TYPE: - lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint32_t*) data : (lua_Integer) *(int32_t*) data); - break; - case INT64_TYPE: - to = push_cdata(L, -1, &ct); - *(int64_t*) to = *(int64_t*) data; - break; - case INTPTR_TYPE: - to = push_cdata(L, -1, &ct); - *(intptr_t*) to = *(intptr_t*) data; - break; - case FLOAT_TYPE: - lua_pushnumber(L, *(float*) data); - break; - case DOUBLE_TYPE: - lua_pushnumber(L, *(double*) data); - break; - case COMPLEX_DOUBLE_TYPE: - to = push_cdata(L, -1, &ct); - *(complex_double*) to = *(complex_double*) data; - break; - case COMPLEX_FLOAT_TYPE: - to = push_cdata(L, -1, &ct); - *(complex_float*) to = *(complex_float*) data; - break; - default: - luaL_error(L, "internal error: invalid member type"); - } - - return 1; - } -} - -static complex_double check_complex(lua_State* L, int idx, void* p, struct ctype* ct) -{ - if (ct->type == INVALID_TYPE) { - double d = luaL_checknumber(L, idx); -#ifdef HAVE_COMPLEX - return d; -#else - complex_double c; - c.real = d; - c.imag = 0; - return c; -#endif - } else if (ct->type == COMPLEX_DOUBLE_TYPE) { - return *(complex_double*) p; - } else if (ct->type == COMPLEX_FLOAT_TYPE) { - complex_float* f = (complex_float*) p; -#ifdef HAVE_COMPLEX - return *f; -#else - complex_double d; - d.real = f->real; - d.imag = f->imag; - return d; -#endif - } else { - complex_double dummy; - type_error(L, idx, "complex", 0, NULL); - memset(&dummy, 0, sizeof(dummy)); - return dummy; - } -} - -static int rank(const struct ctype* ct) -{ - if (ct->pointers) { - return 5; - } - - switch (ct->type) { - case COMPLEX_DOUBLE_TYPE: - return 7; - case COMPLEX_FLOAT_TYPE: - return 6; - case INTPTR_TYPE: - return sizeof(intptr_t) >= sizeof(int64_t) ? 4 : 1; - case INT64_TYPE: - return ct->is_unsigned ? 3 : 2; - case INT32_TYPE: - case INT16_TYPE: - case INT8_TYPE: - return 2; - default: - return 0; - } -} - -static void push_complex(lua_State* L, complex_double res, int ct_usr, const struct ctype* ct) -{ - if (ct->type == COMPLEX_DOUBLE_TYPE) { - complex_double* p = (complex_double*) push_cdata(L, ct_usr, ct); - *p = res; - } else { - complex_float* p = (complex_float*) push_cdata(L, ct_usr, ct); -#ifdef HAVE_COMPLEX - *p = (complex float) res; -#else - p->real = (float) res.real; - p->imag = (float) res.imag; -#endif - } -} - -static void push_number(lua_State* L, int64_t val, int ct_usr, const struct ctype* ct) -{ - if ((ct->pointers || ct->type == INTPTR_TYPE) && sizeof(intptr_t) != sizeof(int64_t)) { - intptr_t* p = (intptr_t*) push_cdata(L, ct_usr, ct); - *p = val; - } else { - int64_t* p = (int64_t*) push_cdata(L, ct_usr, ct); - *p = val; - } -} - -static int call_user_op(lua_State* L, const char* opfield, int idx, int ct_usr, const struct ctype* ct) -{ - idx = lua_absindex(L, idx); - - if (push_user_mt(L, ct_usr, ct)) { - lua_pushstring(L, opfield); - lua_rawget(L, -2); - if (!lua_isnil(L, -1)) { - int top = lua_gettop(L); - lua_pushvalue(L, idx); - lua_call(L, 1, LUA_MULTRET); - return lua_gettop(L) - top + 1; - } - lua_pop(L, 2); - } - return -1; -} - -static int cdata_unm(lua_State* L) -{ - struct ctype ct; - void* p; - int64_t val; - int ret; - - lua_settop(L, 1); - p = to_cdata(L, 1, &ct); - - ret = call_user_op(L, "__unm", 1, 2, &ct); - if (ret >= 0) { - return ret; - } - - val = check_intptr(L, 1, p, &ct); - - if (ct.pointers) { - luaL_error(L, "can't negate a pointer value"); - } else { - memset(&ct, 0, sizeof(ct)); - ct.type = INT64_TYPE; - ct.base_size = 8; - ct.is_defined = 1; - push_number(L, -val, 0, &ct); - } - - return 1; -} - -/* returns -ve if no binop was called otherwise returns the number of return - * arguments */ -static int call_user_binop(lua_State* L, const char* opfield, int lidx, int lusr, const struct ctype* lt, int ridx, int rusr, const struct ctype* rt) -{ - lidx = lua_absindex(L, lidx); - ridx = lua_absindex(L, ridx); - - if (push_user_mt(L, lusr, lt)) { - lua_pushstring(L, opfield); - lua_rawget(L, -2); - - if (!lua_isnil(L, -1)) { - int top = lua_gettop(L); - lua_pushvalue(L, lidx); - lua_pushvalue(L, ridx); - lua_call(L, 2, LUA_MULTRET); - return lua_gettop(L) - top + 1; - } - - lua_pop(L, 2); /* user_mt and user_mt.op */ - } - - if (push_user_mt(L, rusr, rt)) { - lua_pushstring(L, opfield); - lua_rawget(L, -2); - - if (!lua_isnil(L, -1)) { - int top = lua_gettop(L); - lua_pushvalue(L, lidx); - lua_pushvalue(L, ridx); - lua_call(L, 2, LUA_MULTRET); - return lua_gettop(L) - top + 1; - } - - lua_pop(L, 2); /* user_mt and user_mt.op */ - } - - return -1; -} - -static int cdata_concat(lua_State* L) -{ - struct ctype lt, rt; - int ret; - - lua_settop(L, 2); - to_cdata(L, 1, <); - to_cdata(L, 2, &rt); - - ret = call_user_binop(L, "__concat", 1, 3, <, 2, 4, &rt); - if (ret >= 0) { - return ret; - } - - return luaL_error(L, "NYI"); -} - -static int cdata_len(lua_State* L) -{ - struct ctype ct; - int ret; - - lua_settop(L, 1); - to_cdata(L, 1, &ct); - - ret = call_user_op(L, "__len", 1, 2, &ct); - if (ret >= 0) { - return ret; - } - - push_type_name(L, 2, &ct); - return luaL_error(L, "type %s does not implement the __len metamethod", lua_tostring(L, -1)); -} - -static int cdata_pairs(lua_State* L) -{ - struct ctype ct; - int ret; - - lua_settop(L, 1); - to_cdata(L, 1, &ct); - - ret = call_user_op(L, "__pairs", 1, 2, &ct); - if (ret >= 0) { - return ret; - } - - push_type_name(L, 2, &ct); - return luaL_error(L, "type %s does not implement the __pairs metamethod", lua_tostring(L, -1)); -} - -static int cdata_ipairs(lua_State* L) -{ - struct ctype ct; - int ret; - - lua_settop(L, 1); - to_cdata(L, 1, &ct); - - ret = call_user_op(L, "__ipairs", 1, 2, &ct); - if (ret >= 0) { - return ret; - } - - push_type_name(L, 2, &ct); - return luaL_error(L, "type %s does not implement the __ipairs metamethod", lua_tostring(L, -1)); -} - -static int cdata_add(lua_State* L) -{ - struct ctype lt, rt, ct; - void *lp, *rp; - int ct_usr; - int ret; - - lua_settop(L, 2); - - lp = to_cdata(L, 1, <); - rp = to_cdata(L, 2, &rt); - assert(lua_gettop(L) == 4); - - ret = call_user_binop(L, "__add", 1, 3, <, 2, 4, &rt); - if (ret >= 0) { - return ret; - } - assert(lua_gettop(L) == 4); - - ct_usr = rank(<) > rank(&rt) ? 3 : 4; - ct = rank(<) > rank(&rt) ? lt : rt; - - if (IS_COMPLEX(ct.type)) { - complex_double left, right, res; - - left = check_complex(L, 1, lp, <); - right = check_complex(L, 2, rp, &rt); - assert(lua_gettop(L) == 4); - -#ifdef HAVE_COMPLEX - res = left + right; -#else - res.real = left.real + right.real; - res.imag = left.imag + right.imag; -#endif - - push_complex(L, res, ct_usr, &ct); - return 1; - - } else { - int64_t left = check_intptr(L, 1, lp, <); - int64_t right = check_intptr(L, 2, rp, &rt); - assert(lua_gettop(L) == 4); - - /* note due to 2s complement it doesn't matter if we do the addition as int or uint, - * but the result needs to be uint64_t if either of the sources are */ - - if (lt.pointers && rt.pointers) { - luaL_error(L, "can't add two pointers"); - - } else if (lt.pointers) { - int64_t res = left + (lt.pointers > 1 ? sizeof(void*) : lt.base_size) * right; - lt.is_array = 0; - push_number(L, res, 3, <); - - } else if (rt.pointers) { - int64_t res = right + (rt.pointers > 1 ? sizeof(void*) : rt.base_size) * left; - rt.is_array = 0; - push_number(L, res, 4, &rt); - - } else { - push_number(L, left + right, ct_usr, &ct); - } - - return 1; - } -} - -static int cdata_sub(lua_State* L) -{ - struct ctype lt, rt, ct; - void *lp, *rp; - int ct_usr; - int ret; - - lua_settop(L, 2); - - lp = to_cdata(L, 1, <); - rp = to_cdata(L, 2, &rt); - - ret = call_user_binop(L, "__sub", 1, 3, <, 2, 4, &rt); - if (ret >= 0) { - return ret; - } - - ct_usr = rank(<) > rank(&rt) ? 3 : 4; - ct = rank(<) > rank(&rt) ? lt : rt; - - if (IS_COMPLEX(ct.type)) { - complex_double left, right, res; - - left = check_complex(L, 1, lp, <); - right = check_complex(L, 2, rp, &rt); - -#ifdef HAVE_COMPLEX - res = left - right; -#else - res.real = left.real - right.real; - res.imag = left.imag - right.imag; -#endif - - push_complex(L, res, ct_usr, &ct); - return 1; - - } else { - int64_t left = check_intptr(L, 1, lp, <); - int64_t right = check_intptr(L, 2, rp, &rt); - - if (rt.pointers) { - luaL_error(L, "NYI: can't subtract a pointer value"); - - } else if (lt.pointers) { - int64_t res = left - (lt.pointers > 1 ? sizeof(void*) : lt.base_size) * right; - lt.is_array = 0; - push_number(L, res, 3, <); - - } else { - int64_t res = left - right; - push_number(L, res, ct_usr, &ct); - } - - return 1; - } -} - -/* TODO fix for unsigned */ -#define NUMBER_ONLY_BINOP(OPSTR, DO_NORMAL, DO_COMPLEX) \ - struct ctype lt, rt, ct; \ - void *lp, *rp; \ - int ct_usr; \ - int ret; \ - \ - lua_settop(L, 2); \ - \ - lp = to_cdata(L, 1, <); \ - rp = to_cdata(L, 2, &rt); \ - \ - ret = call_user_binop(L, OPSTR, 1, 3, <, 2, 4, &rt); \ - if (ret >= 0) { \ - return ret; \ - } \ - \ - ct_usr = rank(<) > rank(&rt) ? 3 : 4; \ - ct = rank(<) > rank(&rt) ? lt : rt; \ - \ - if (IS_COMPLEX(ct.type)) { \ - complex_double res; \ - complex_double left = check_complex(L, 1, lp, <); \ - complex_double right = check_complex(L, 2, rp, &rt); \ - \ - DO_COMPLEX(left, right, res); \ - push_complex(L, res, ct_usr, &ct); \ - \ - } else if (lt.pointers || rt.pointers) { \ - luaL_error(L, "can't operate on a pointer value"); \ - \ - } else { \ - int64_t res; \ - int64_t left = check_intptr(L, 1, lp, <); \ - int64_t right = check_intptr(L, 2, rp, &rt); \ - \ - DO_NORMAL(left, right, res); \ - push_number(L, res, ct_usr, &ct); \ - } \ - \ - return 1 - -#define MUL(l,r,s) s = l * r -#define DIV(l,r,s) s = l / r -#define MOD(l,r,s) s = l % r -#define POW(l,r,s) s = pow(l, r) - -#ifdef HAVE_COMPLEX -#define MULC(l,r,s) s = l * r -#define DIVC(l,r,s) s = l / r -#define MODC(l,r,s) (void) l, (void) r, memset(&s, 0, sizeof(s)), luaL_error(L, "NYI: complex mod") -#define POWC(l,r,s) s = cpow(l, r) -#else -#define MULC(l,r,s) s.real = l.real * r.real - l.imag * r.imag, s.imag = l.real * r.imag + l.imag * r.real -#define DIVC(l,r,s) s.real = (l.real * r.real + l.imag * r.imag) / (r.real * r.real + r.imag * r.imag), \ - s.imag = (l.imag * r.real - l.real * r.imag) / (r.real * r.real + r.imag * r.imag) -#define MODC(l,r,s) (void) l, (void) r, memset(&s, 0, sizeof(s)), luaL_error(L, "NYI: complex mod") -#define POWC(l,r,s) (void) l, (void) r, memset(&s, 0, sizeof(s)), luaL_error(L, "NYI: complex pow") -#endif - -static int cdata_mul(lua_State* L) -{ NUMBER_ONLY_BINOP("__mul", MUL, MULC); } - -static int cdata_div(lua_State* L) -{ NUMBER_ONLY_BINOP("__div", DIV, DIVC); } - -static int cdata_mod(lua_State* L) -{ NUMBER_ONLY_BINOP("__mod", MOD, MODC); } - -static int cdata_pow(lua_State* L) -{ NUMBER_ONLY_BINOP("__pow", POW, POWC); } - -#define COMPARE_BINOP(OPSTR, OP, OPC) \ - struct ctype lt, rt; \ - void *lp, *rp; \ - int ret, res; \ - \ - lua_settop(L, 2); \ - \ - lp = to_cdata(L, 1, <); \ - rp = to_cdata(L, 2, &rt); \ - \ - ret = call_user_binop(L, OPSTR, 1, 3, <, 2, 4, &rt); \ - if (ret >= 0) { \ - return ret; \ - } \ - \ - if (IS_COMPLEX(lt.type) || IS_COMPLEX(rt.type)) { \ - complex_double left = check_complex(L, 1, lp, <); \ - complex_double right = check_complex(L, 2, rp, &rt); \ - \ - res = OPC(left, right); \ - \ - lua_pushboolean(L, res); \ - \ - } else { \ - int64_t left = check_intptr(L, 1, lp, <); \ - int64_t right = check_intptr(L, 2, rp, &rt); \ - \ - if (lt.pointers && rt.pointers) { \ - if (is_void_ptr(<) || is_void_ptr(&rt) || is_same_type(L, 3, 4, <, &rt)) { \ - res = OP((uint64_t) left, (uint64_t) right); \ - } else { \ - goto err; \ - } \ - \ - } else if (lt.is_null && rt.type == FUNCTION_PTR_TYPE) { \ - res = OP((uint64_t) left, (uint64_t) right); \ - \ - } else if (rt.is_null && lt.type == FUNCTION_PTR_TYPE) { \ - res = OP((uint64_t) left, (uint64_t) right); \ - \ - } else if (lt.pointers && rt.type == INTPTR_TYPE && rt.is_unsigned) {\ - res = OP((uint64_t) left, (uint64_t) right); \ - \ - } else if (rt.pointers && lt.type == INTPTR_TYPE && lt.is_unsigned) {\ - res = OP((uint64_t) left, (uint64_t) right); \ - \ - } else if (rt.pointers || lt.pointers) { \ - goto err; \ - \ - } else if (lt.is_unsigned && rt.is_unsigned) { \ - res = OP((uint64_t) left, (uint64_t) right); \ - \ - } else if (lt.is_unsigned) { \ - res = OP((int64_t) (uint64_t) left, right); \ - \ - } else if (rt.is_unsigned) { \ - res = OP(left, (int64_t) (uint64_t) right); \ - \ - } else { \ - res = OP(left, right); \ - } \ - \ - lua_pushboolean(L, res); \ - } \ - return 1 - -#define EQ(l, r) (l) == (r) -#define LT(l, r) (l) < (r) -#define LE(l, r) (l) <= (r) - -#ifdef HAVE_COMPLEX -#define EQC(l, r) (l) == (r) -#else -#define EQC(l, r) (l).real == (r).real && (l).imag == (r).imag -#endif - -#define LEC(l, r) EQC(l, r), luaL_error(L, "complex numbers are non-orderable") -#define LTC(l, r) EQC(l, r), luaL_error(L, "complex numbers are non-orderable") - -static int cdata_eq(lua_State* L) -{ - COMPARE_BINOP("__eq", EQ, EQC); -err: - lua_pushboolean(L, 0); - return 1; -} - -static int cdata_lt(lua_State* L) -{ - COMPARE_BINOP("__lt", LT, LTC); -err: - lua_getuservalue(L, 1); - lua_getuservalue(L, 2); - push_type_name(L, -2, <); - push_type_name(L, -2, <); - return luaL_error(L, "trying to compare incompatible types %s and %s", lua_tostring(L, -2), lua_tostring(L, -1)); -} - -static int cdata_le(lua_State* L) -{ - COMPARE_BINOP("__le", LE, LEC); -err: - lua_getuservalue(L, 1); - lua_getuservalue(L, 2); - push_type_name(L, -2, <); - push_type_name(L, -2, <); - return luaL_error(L, "trying to compare incompatible types %s and %s", lua_tostring(L, -2), lua_tostring(L, -1)); -} - -static const char* etype_tostring(int type) -{ - switch (type) { - case VOID_TYPE: return "void"; - case DOUBLE_TYPE: return "double"; - case FLOAT_TYPE: return "float"; - case COMPLEX_DOUBLE_TYPE: return "complex double"; - case COMPLEX_FLOAT_TYPE: return "complex float"; - case BOOL_TYPE: return "bool"; - case INT8_TYPE: return "int8"; - case INT16_TYPE: return "int16"; - case INT32_TYPE: return "int32"; - case INT64_TYPE: return "int64"; - case INTPTR_TYPE: return "intptr"; - case ENUM_TYPE: return "enum"; - case UNION_TYPE: return "union"; - case STRUCT_TYPE: return "struct"; - case FUNCTION_PTR_TYPE: return "function ptr"; - case FUNCTION_TYPE: return "function"; - default: return "invalid"; - } -} - -static void print_type(lua_State* L, const struct ctype* ct) -{ - lua_pushfstring(L, " sz %d %d %d align %d ptr %d %d %d type %s%s %d %d %d name %d call %d %d var %d %d %d bit %d %d %d %d jit %d", - /* sz */ - ct->base_size, - ct->array_size, - ct->offset, - /* align */ - ct->align_mask, - /* ptr */ - ct->is_array, - ct->pointers, - ct->const_mask, - /* type */ - ct->is_unsigned ? "u" : "", - etype_tostring(ct->type), - ct->is_reference, - ct->is_defined, - ct->is_null, - /* name */ - ct->has_member_name, - /* call */ - ct->calling_convention, - ct->has_var_arg, - /* var */ - ct->is_variable_array, - ct->is_variable_struct, - ct->variable_size_known, - /* bit */ - ct->is_bitfield, - ct->has_bitfield, - ct->bit_offset, - ct->bit_size, - /* jit */ - ct->is_jitted); -} - -static int ctype_tostring(lua_State* L) -{ - struct ctype ct; - assert(lua_type(L, 1) == LUA_TUSERDATA); - lua_settop(L, 1); - check_ctype(L, 1, &ct); - assert(lua_gettop(L) == 2); - push_type_name(L, -1, &ct); - lua_pushfstring(L, "ctype<%s>", lua_tostring(L, -1)); - - if (DEBUG_TOSTRING) { - print_type(L, &ct); - lua_concat(L, 2); - } - - return 1; -} - -static int cdata_tostring(lua_State* L) -{ - struct ctype ct; - char buf[64]; - void* p; - int ret; - - lua_settop(L, 1); - p = to_cdata(L, 1, &ct); - - ret = call_user_op(L, "__tostring", 1, 2, &ct); - if (ret >= 0) { - return ret; - } - - if (ct.pointers > 0 || ct.is_reference || ct.type == STRUCT_TYPE || ct.type == UNION_TYPE) { - push_type_name(L, -1, &ct); - lua_pushfstring(L, "cdata<%s>: %p", lua_tostring(L, -1), p); - - if (DEBUG_TOSTRING) { - print_type(L, &ct); - lua_concat(L, 2); - } - - return 1; - } - - switch (ct.type) { - case COMPLEX_DOUBLE_TYPE: - { - complex_double c = *(complex_double*) p; - lua_pushfstring(L, "%f+%fi", creal(c), cimag(c)); - } - return 1; - - case COMPLEX_FLOAT_TYPE: - { - complex_float c = *(complex_float*) p; - lua_pushfstring(L, "%f+%fi", crealf(c), cimagf(c)); - } - return 1; - - case FUNCTION_PTR_TYPE: - p = *(void**) p; - push_type_name(L, -1, &ct); - lua_pushfstring(L, "cdata<%s>: %p", lua_tostring(L, -1), *(void**) p); - return 1; - - case INTPTR_TYPE: - lua_pushfstring(L, "%p", *(uintptr_t*) p); - return 1; - - case INT64_TYPE: - sprintf(buf, ct.is_unsigned ? "%"PRIu64 : "%"PRId64, *(uint64_t*) p); - lua_pushstring(L, buf); - return 1; - - default: - sprintf(buf, ct.is_unsigned ? "%"PRId64 : "%"PRId64, (int64_t) check_intptr(L, 1, p, &ct)); - lua_pushstring(L, buf); - return 1; - } -} - -static int ffi_errno(lua_State* L) -{ - struct jit* jit = get_jit(L); - - if (!lua_isnoneornil(L, 1)) { - lua_pushinteger(L, jit->last_errno); - jit->last_errno = luaL_checknumber(L, 1); - } else { - lua_pushinteger(L, jit->last_errno); - } - - return 1; -} - -static int ffi_type(lua_State* L) -{ - if (lua_isuserdata(L, 1) && lua_getmetatable(L, 1)) { - if (equals_upval(L, -1, &cdata_mt_key) || equals_upval(L, -1, &ctype_mt_key)) { - lua_pushstring(L, "cdata"); - return 1; - } - lua_pop(L, 1); /* mt */ - } - - /* call the old _G.type, we use an upvalue as _G.type is set - * to this function */ - lua_pushvalue(L, lua_upvalueindex(1)); - lua_insert(L, 1); - lua_call(L, lua_gettop(L)-1, LUA_MULTRET); - return lua_gettop(L); -} - -static int ffi_number(lua_State* L) -{ - struct ctype ct; - void* data = to_cdata(L, 1, &ct); - - if (ct.type != INVALID_TYPE) { - lua_pushinteger(L, check_intptr(L, 1, data, &ct)); - return 1; - } else { - /* call the old _G.tonumber, we use an upvalue as _G.tonumber is set - * to this function */ - lua_pushvalue(L, lua_upvalueindex(1)); - lua_insert(L, 1); - lua_call(L, lua_gettop(L)-1, LUA_MULTRET); - return lua_gettop(L); - } -} - -static int ffi_string(lua_State* L) -{ - struct ctype ct; - char* data; - lua_settop(L, 2); - - data = (char*) check_cdata(L, 1, &ct); - - if (is_void_ptr(&ct)) { - lua_pushlstring(L, data, (size_t) luaL_checknumber(L, 2)); - return 1; - - } else if (ct.type == INT8_TYPE && ct.pointers == 1) { - size_t sz; - - if (lua_isuserdata(L, 2)) { - ptrdiff_t val; - if (!cdata_tointeger(L, 2, &val)) { - type_error(L, 2, "int", 0, NULL); - } - sz = (size_t) val; - } else if (!lua_isnil(L, 2)) { - sz = (size_t) luaL_checknumber(L, 2); - - } else if (ct.is_array && !ct.is_variable_array) { - char* nul = memchr(data, '\0', ct.array_size); - sz = nul ? nul - data : ct.array_size; - - } else { - sz = strlen(data); - } - - lua_pushlstring(L, data, sz); - return 1; - } - - return luaL_error(L, "unable to convert cdata to string"); -} - -static int ffi_copy(lua_State* L) -{ - struct ctype ft, tt; - char *to, *from; - - setmintop(L, 3); - to = (char*) check_pointer(L, 1, &tt); - from = (char*) check_pointer(L, 2, &ft); - - if (!lua_isnoneornil(L, 3)) { - memcpy(to, from, (size_t) luaL_checknumber(L, 3)); - - } else if (ft.type == INT8_TYPE && ft.pointers == 1) { - size_t sz = ft.is_array ? ft.array_size : strlen(from); - memcpy(to, from, sz); - to[sz] = '\0'; - } - - return 0; -} - -static int ffi_fill(lua_State* L) -{ - struct ctype ct; - void* to; - size_t sz; - int val = 0; - - setmintop(L, 3); - to = check_pointer(L, 1, &ct); - sz = (size_t) luaL_checknumber(L, 2); - - if (!lua_isnoneornil(L, 3)) { - val = (int) luaL_checkinteger(L, 3); - } - - memset(to, val, sz); - return 0; -} - -static int ffi_abi(lua_State* L) -{ - luaL_checkstring(L, 1); - push_upval(L, &abi_key); - lua_pushvalue(L, 1); - lua_rawget(L, -2); - lua_pushboolean(L, lua_toboolean(L, -1)); - return 1; -} - -static int ffi_load(lua_State* L) -{ - const char* libname = luaL_checkstring(L, 1); - void** lib = (void**) lua_newuserdata(L, sizeof(void*)); - - *lib = LoadLibraryA(libname); - -#ifdef LIB_FORMAT_1 - if (!*lib) { - libname = lua_pushfstring(L, LIB_FORMAT_1, lua_tostring(L, 1)); - *lib = LoadLibraryA(libname); - lua_pop(L, 1); - } -#endif - -#ifdef LIB_FORMAT_2 - if (!*lib) { - libname = lua_pushfstring(L, LIB_FORMAT_2, lua_tostring(L, 1)); - *lib = LoadLibraryA(libname); - lua_pop(L, 1); - } -#endif - - if (!*lib) { - return luaL_error(L, "could not load library %s", lua_tostring(L, 1)); - } - - lua_newtable(L); - lua_setuservalue(L, -2); - - push_upval(L, &cmodule_mt_key); - lua_setmetatable(L, -2); - return 1; -} - -static void* find_symbol(lua_State* L, int modidx, const char* asmname) -{ - size_t i; - void** libs; - size_t num; - void* sym = NULL; - - libs = (void**) lua_touserdata(L, modidx); - num = lua_rawlen(L, modidx) / sizeof(void*); - - for (i = 0; i < num && sym == NULL; i++) { - if (libs[i]) { - sym = GetProcAddressA(libs[i], asmname); - } - } - - return sym; -} - -/* pushes the user table */ -static void* lookup_global(lua_State* L, int modidx, int nameidx, const char** pname, struct ctype* ct) -{ - int top = lua_gettop(L); - void* sym; - - modidx = lua_absindex(L, modidx); - nameidx = lua_absindex(L, nameidx); - - *pname = luaL_checkstring(L, nameidx); - - /* get the ctype */ - push_upval(L, &functions_key); - lua_pushvalue(L, nameidx); - lua_rawget(L, -2); - if (lua_isnil(L, -1)) { - luaL_error(L, "missing declaration for function/global %s", *pname); - return NULL; - } - - /* leave just the ct_usr on the stack */ - *ct = *(const struct ctype*) lua_touserdata(L, -1); - lua_getuservalue(L, -1); - lua_replace(L, top + 1); - lua_pop(L, 1); - - assert(lua_gettop(L) == top + 1); - - /* get the assembly name */ - push_upval(L, &asmname_key); - lua_pushvalue(L, nameidx); - lua_rawget(L, -2); - if (lua_isstring(L, -1)) { - *pname = lua_tostring(L, -1); - } - lua_pop(L, 2); - - sym = find_symbol(L, modidx, *pname); - - assert(lua_gettop(L) == top + 1); - return sym; -} - -static int cmodule_index(lua_State* L) -{ - const char* asmname; - struct ctype ct; - void *sym; - - lua_settop(L, 2); - - /* see if we have already loaded the function */ - lua_getuservalue(L, 1); - lua_pushvalue(L, 2); - lua_rawget(L, -2); - if (!lua_isnil(L, -1)) { - return 1; - } - lua_pop(L, 2); - - /* check the constants table */ - push_upval(L, &constants_key); - lua_pushvalue(L, 2); - lua_rawget(L, -2); - if (!lua_isnil(L, -1)) { - return 1; - } - lua_pop(L, 2); - - /* lookup_global pushes the ct_usr */ - sym = lookup_global(L, 1, 2, &asmname, &ct); - -#if defined _WIN32 && !defined _WIN64 && (defined __i386__ || defined _M_IX86) - if (!sym && ct.type == FUNCTION_TYPE) { - ct.calling_convention = STD_CALL; - lua_pushfstring(L, "_%s@%d", asmname, x86_return_size(L, -1, &ct)); - sym = find_symbol(L, 1, lua_tostring(L, -1)); - lua_pop(L, 1); - } - - if (!sym && ct.type == FUNCTION_TYPE) { - ct.calling_convention = FAST_CALL; - lua_pushfstring(L, "@%s@%d", asmname, x86_return_size(L, -1, &ct)); - sym = find_symbol(L, 1, lua_tostring(L, -1)); - lua_pop(L, 1); - } -#endif - - if (!sym) { - return luaL_error(L, "failed to find function/global %s", asmname); - } - - assert(lua_gettop(L) == 3); /* module, name, ct_usr */ - - if (ct.type == FUNCTION_TYPE) { - compile_function(L, (cfunction) sym, -1, &ct); - assert(lua_gettop(L) == 4); /* module, name, ct_usr, function */ - - /* set module usr value[luaname] = function to cache for next time */ - lua_getuservalue(L, 1); - lua_pushvalue(L, 2); - lua_pushvalue(L, -3); - lua_rawset(L, -3); - lua_pop(L, 1); /* module uv */ - return 1; - } - - /* extern const char* foo; and extern const char foo[]; */ - if (ct.pointers == 1 && ct.type == INT8_TYPE) { - char* str = (char*) sym; - if (!ct.is_array) { - str = *(char**) sym; - } - lua_pushstring(L, str); - return 1; - } - - /* extern struct foo foo[], extern void* foo[]; and extern struct foo foo; */ - if (ct.is_array || (!ct.pointers && (ct.type == UNION_TYPE || ct.type == STRUCT_TYPE))) { - void* p; - ct.is_reference = 1; - p = push_cdata(L, -1, &ct); - *(void**) p = sym; - return 1; - } - - /* extern void* foo; and extern void (*foo)(); */ - if (ct.pointers || ct.type == FUNCTION_PTR_TYPE) { - void* p = push_cdata(L, -1, &ct); - *(void**) p = *(void**) sym; - return 1; - } - - switch (ct.type) { - case COMPLEX_DOUBLE_TYPE: - case COMPLEX_FLOAT_TYPE: - case INTPTR_TYPE: - case INT64_TYPE: - { - /* TODO: complex float/double need to be references if .re and - * .imag are setable */ - void* p = push_cdata(L, -1, &ct); - memcpy(p, sym, ct.base_size); - return 1; - } - - case DOUBLE_TYPE: - lua_pushnumber(L, *(double*) sym); - return 1; - - case FLOAT_TYPE: - lua_pushnumber(L, *(float*) sym); - return 1; - - case BOOL_TYPE: - lua_pushboolean(L, *(bool*) sym); - return 1; - - case INT8_TYPE: - lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint8_t*) sym : (lua_Integer) *(int8_t*) sym); - return 1; - - case INT16_TYPE: - lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint16_t*) sym : (lua_Integer) *(int16_t*) sym); - return 1; - - case INT32_TYPE: - case ENUM_TYPE: - lua_pushinteger(L, ct.is_unsigned ? (lua_Integer) *(uint32_t*) sym : (lua_Integer) *(int32_t*) sym); - return 1; - } - - return luaL_error(L, "NYI - global value type"); -} - -static int cmodule_newindex(lua_State* L) -{ - const char* name; - void* sym; - struct ctype ct; - - lua_settop(L, 3); - - /* pushes the ct_usr */ - sym = lookup_global(L, 1, 2, &name, &ct); - assert(lua_gettop(L) == 4); /* module, name, value, ct_usr */ - - if (sym == NULL) { - return luaL_error(L, "failed to find global %s", name); - } - - if (ct.type == FUNCTION_TYPE || ct.is_array || (ct.const_mask & 1)) { - return luaL_error(L, "can not set global %s", name); - } - - set_value(L, 3, sym, -1, &ct, 1); - return 0; -} - -static int jit_gc(lua_State* L) -{ - size_t i; - struct jit* jit = get_jit(L); - dasm_free(jit); - for (i = 0; i < jit->pagenum; i++) { - FreePage(jit->pages[i], jit->pages[i]->size); - } - free(jit->pages); - free(jit->globals); - return 0; -} - -static int ffi_debug(lua_State* L) -{ - lua_newtable(L); - push_upval(L, &ctype_mt_key); - lua_setfield(L, -2, "ctype_mt"); - push_upval(L, &cdata_mt_key); - lua_setfield(L, -2, "cdata_mt"); - push_upval(L, &cmodule_mt_key); - lua_setfield(L, -2, "cmodule_mt"); - push_upval(L, &constants_key); - lua_setfield(L, -2, "constants"); - push_upval(L, &types_key); - lua_setfield(L, -2, "types"); - push_upval(L, &jit_key); - lua_setfield(L, -2, "jit"); - push_upval(L, &gc_key); - lua_setfield(L, -2, "gc"); - push_upval(L, &callbacks_key); - lua_setfield(L, -2, "callbacks"); - push_upval(L, &functions_key); - lua_setfield(L, -2, "functions"); - push_upval(L, &abi_key); - lua_setfield(L, -2, "abi"); - push_upval(L, &next_unnamed_key); - lua_setfield(L, -2, "next_unnamed"); - return 1; -} - -static int do64(lua_State* L, int is_unsigned) -{ - lua_Number low, high; - struct ctype ct; - int64_t val; - - lua_settop(L, 2); - - if (!lua_isnil(L, 2)) { - high = luaL_checknumber(L, 1); - low = luaL_checknumber(L, 2); - } else { - high = 0; - low = luaL_checknumber(L, 1); - } - - val = ((int64_t) (uint32_t) high << 32) | (int64_t) (uint32_t) low; - - if (!is_unsigned && (high < 0 || low < 0)) { - val = -val; - } - - memset(&ct, 0, sizeof(ct)); - ct.type = INT64_TYPE; - ct.is_unsigned = is_unsigned; - ct.is_defined = 1; - ct.base_size = sizeof(int64_t); - push_number(L, (int64_t) val, 0, &ct); - - return 1; -} - -static int ffi_i64(lua_State* L) -{ return do64(L, 0); } - -static int ffi_u64(lua_State* L) -{ return do64(L, 1); } - -static const luaL_Reg cdata_mt[] = { - {"__gc", &cdata_gc}, - {"__call", &cdata_call}, - {"free", &cdata_free}, - {"set", &cdata_set}, - {"__index", &cdata_index}, - {"__newindex", &cdata_newindex}, - {"__add", &cdata_add}, - {"__sub", &cdata_sub}, - {"__mul", &cdata_mul}, - {"__div", &cdata_div}, - {"__mod", &cdata_mod}, - {"__pow", &cdata_pow}, - {"__unm", &cdata_unm}, - {"__eq", &cdata_eq}, - {"__lt", &cdata_lt}, - {"__le", &cdata_le}, - {"__tostring", &cdata_tostring}, - {"__concat", &cdata_concat}, - {"__len", &cdata_len}, - {"__pairs", &cdata_pairs}, - {"__ipairs", &cdata_ipairs}, - {NULL, NULL} -}; - -static const luaL_Reg callback_mt[] = { - {"__gc", &callback_free}, - {NULL, NULL} -}; - -static const luaL_Reg ctype_mt[] = { - {"__call", &ctype_call}, - {"__new", &ctype_new}, - {"__tostring", &ctype_tostring}, - {NULL, NULL} -}; - -static const luaL_Reg cmodule_mt[] = { - {"__index", &cmodule_index}, - {"__newindex", &cmodule_newindex}, - {NULL, NULL} -}; - -static const luaL_Reg jit_mt[] = { - {"__gc", &jit_gc}, - {NULL, NULL} -}; - -static const luaL_Reg ffi_reg[] = { - {"cdef", &ffi_cdef}, - {"load", &ffi_load}, - {"new", &ffi_new}, - {"typeof", &ffi_typeof}, - {"cast", &ffi_cast}, - {"metatype", &ffi_metatype}, - {"gc", &ffi_gc}, - {"sizeof", &ffi_sizeof}, - {"alignof", &ffi_alignof}, - {"offsetof", &ffi_offsetof}, - {"istype", &ffi_istype}, - {"errno", &ffi_errno}, - {"string", &ffi_string}, - {"copy", &ffi_copy}, - {"fill", &ffi_fill}, - {"abi", &ffi_abi}, - {"debug", &ffi_debug}, - {"i64", &ffi_i64}, - {"u64", &ffi_u64}, - {NULL, NULL} -}; - -/* leaves the usr table on the stack */ -static void push_builtin(lua_State* L, struct ctype* ct, const char* name, int type, int size, int align, int is_unsigned) -{ - memset(ct, 0, sizeof(*ct)); - ct->type = type; - ct->base_size = size; - ct->align_mask = align; - ct->is_defined = 1; - ct->is_unsigned = is_unsigned; - - if (IS_COMPLEX(type)) { - lua_newtable(L); - } else { - lua_pushnil(L); - } - - push_upval(L, &types_key); - push_ctype(L, -2, ct); - lua_setfield(L, -2, name); - lua_pop(L, 2); /* types, usr table */ -} - -static void push_builtin_undef(lua_State* L, struct ctype* ct, const char* name, int type) -{ - memset(ct, 0, sizeof(*ct)); - ct->type = type; - - push_upval(L, &types_key); - push_ctype(L, 0, ct); - lua_setfield(L, -2, name); - lua_pop(L, 1); /* types */ -} - -static void add_typedef(lua_State* L, const char* from, const char* to) -{ - struct ctype ct; - struct parser P; - P.line = 1; - P.align_mask = DEFAULT_ALIGN_MASK; - P.next = P.prev = from; - - push_upval(L, &types_key); - parse_type(L, &P, &ct); - parse_argument(L, &P, -1, &ct, NULL, NULL); - push_ctype(L, -1, &ct); - - /* stack is at +4: types, type usr, arg usr, ctype */ - - lua_setfield(L, -4, to); - lua_pop(L, 3); /* types, type usr, arg usr */ -} - -static int setup_upvals(lua_State* L) -{ - struct jit* jit = get_jit(L); - - /* jit setup */ - { - dasm_init(jit, 64); -#ifdef _WIN32 - { - SYSTEM_INFO si; - GetSystemInfo(&si); - jit->align_page_size = si.dwAllocationGranularity - 1; - } -#else - jit->align_page_size = sysconf(_SC_PAGE_SIZE) - 1; -#endif - jit->globals = (void**) malloc(64 * sizeof(void*)); - dasm_setupglobal(jit, jit->globals, 64); - compile_globals(jit, L); - } - - /* ffi.C */ - { -#ifdef _WIN32 - size_t sz = sizeof(HMODULE) * 6; - HMODULE* libs = lua_newuserdata(L, sz); - memset(libs, 0, sz); - - /* exe */ - GetModuleHandle(NULL); - /* lua dll */ -#ifdef LUA_DLL_NAME -#define STR2(tok) #tok -#define STR(tok) STR2(tok) - libs[1] = LoadLibraryA(STR(LUA_DLL_NAME)); -#undef STR -#undef STR2 -#endif - - /* crt */ -#ifdef UNDER_CE - libs[2] = LoadLibraryA("coredll.dll"); -#else - GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (char*) &_fmode, &libs[2]); - libs[3] = LoadLibraryA("kernel32.dll"); - libs[4] = LoadLibraryA("user32.dll"); - libs[5] = LoadLibraryA("gdi32.dll"); -#endif - - jit->lua_dll = libs[1]; - jit->kernel32_dll = libs[3]; - -#else /* !_WIN32 */ - size_t sz = sizeof(void*) * 5; - void** libs = lua_newuserdata(L, sz); - memset(libs, 0, sz); - - libs[0] = LoadLibraryA(NULL); /* exe */ - libs[1] = LoadLibraryA("libc.so"); -#ifdef __GNUC__ - libs[2] = LoadLibraryA("libgcc.so"); -#endif - libs[3] = LoadLibraryA("libm.so"); - libs[4] = LoadLibraryA("libdl.so"); -#endif - - lua_newtable(L); - lua_setuservalue(L, -2); - - push_upval(L, &cmodule_mt_key); - lua_setmetatable(L, -2); - - lua_setfield(L, 1, "C"); - } - - /* setup builtin types */ - { - complex_double* pc; - struct {char ch; uint16_t v;} a16; - struct {char ch; uint32_t v;} a32; - struct {char ch; uint64_t v;} a64; - struct {char ch; float v;} af; - struct {char ch; double v;} ad; -#ifdef HAVE_LONG_DOUBLE - struct {char ch; long double v;} ald; -#endif - struct {char ch; uintptr_t v;} aptr; - struct ctype ct; - struct {char ch; complex_float v;} cf; - struct {char ch; complex_double v;} cd; -#if defined HAVE_LONG_DOUBLE && defined HAVE_COMPLEX - struct {char ch; complex long double v;} cld; -#endif - - push_builtin(L, &ct, "void", VOID_TYPE, 0, 0, 0); - push_builtin(L, &ct, "bool", BOOL_TYPE, sizeof(_Bool), sizeof(_Bool) -1, 1); - push_builtin(L, &ct, "uint8_t", INT8_TYPE, sizeof(uint8_t), 0, 1); - push_builtin(L, &ct, "int8_t", INT8_TYPE, sizeof(int8_t), 0, 0); - push_builtin(L, &ct, "uint16_t", INT16_TYPE, sizeof(uint16_t), ALIGNOF(a16), 1); - push_builtin(L, &ct, "int16_t", INT16_TYPE, sizeof(int16_t), ALIGNOF(a16), 0); - push_builtin(L, &ct, "uint32_t", INT32_TYPE, sizeof(uint32_t), ALIGNOF(a32), 1); - push_builtin(L, &ct, "int32_t", INT32_TYPE, sizeof(int32_t), ALIGNOF(a32), 0); - push_builtin(L, &ct, "uint64_t", INT64_TYPE, sizeof(uint64_t), ALIGNOF(a64), 1); - push_builtin(L, &ct, "int64_t", INT64_TYPE, sizeof(int64_t), ALIGNOF(a64), 0); - push_builtin(L, &ct, "float", FLOAT_TYPE, sizeof(float), ALIGNOF(af), 0); - push_builtin(L, &ct, "double", DOUBLE_TYPE, sizeof(double), ALIGNOF(ad), 0); -#ifdef HAVE_LONG_DOUBLE - push_builtin(L, &ct, "long double", LONG_DOUBLE_TYPE, sizeof(long double), ALIGNOF(ald), 0); -#else - push_builtin_undef(L, &ct, "long double", LONG_DOUBLE_TYPE); -#endif - push_builtin(L, &ct, "uintptr_t", INTPTR_TYPE, sizeof(uintptr_t), ALIGNOF(aptr), 1); - push_builtin(L, &ct, "intptr_t", INTPTR_TYPE, sizeof(uintptr_t), ALIGNOF(aptr), 0); - push_builtin(L, &ct, "complex float", COMPLEX_FLOAT_TYPE, sizeof(complex_float), ALIGNOF(cf), 0); - push_builtin(L, &ct, "complex double", COMPLEX_DOUBLE_TYPE, sizeof(complex_double), ALIGNOF(cd), 0); -#if defined HAVE_LONG_DOUBLE && defined HAVE_COMPLEX - push_builtin(L, &ct, "complex long double", COMPLEX_LONG_DOUBLE_TYPE, sizeof(complex long double), ALIGNOF(cld), 0); -#else - push_builtin_undef(L, &ct, "complex long double", COMPLEX_LONG_DOUBLE_TYPE); -#endif - - /* add NULL and i constants */ - push_upval(L, &constants_key); - - memset(&ct, 0, sizeof(ct)); - ct.type = VOID_TYPE; - ct.is_defined = 1; - ct.pointers = 1; - ct.is_null = 1; - - /* add ffi.C.NULL */ - push_cdata(L, 0, &ct); - lua_setfield(L, -2, "NULL"); - - /* add ffi.NULL */ - push_cdata(L, 0, &ct); - lua_setfield(L, 1, "NULL"); - - memset(&ct, 0, sizeof(ct)); - ct.type = COMPLEX_DOUBLE_TYPE; - ct.is_defined = 1; - ct.base_size = sizeof(complex_double); - pc = (complex_double*) push_cdata(L, 0, &ct); -#ifdef HAVE_COMPLEX - *pc = 1i; -#else - pc->real = 0; - pc->imag = 1; -#endif - lua_setfield(L, -2, "i"); - - lua_pop(L, 1); /* constants */ - } - - assert(lua_gettop(L) == 1); - - /* setup builtin typedefs */ - { - add_typedef(L, "bool", "_Bool"); - - if (sizeof(uint32_t) == sizeof(size_t)) { - add_typedef(L, "uint32_t", "size_t"); - add_typedef(L, "int32_t", "ssize_t"); - } else if (sizeof(uint64_t) == sizeof(size_t)) { - add_typedef(L, "uint64_t", "size_t"); - add_typedef(L, "int64_t", "ssize_t"); - } - - if (sizeof(int32_t) == sizeof(intptr_t)) { - add_typedef(L, "int32_t", "intptr_t"); - add_typedef(L, "int32_t", "ptrdiff_t"); - } else if (sizeof(int64_t) == sizeof(intptr_t)) { - add_typedef(L, "int64_t", "intptr_t"); - add_typedef(L, "int64_t", "ptrdiff_t"); - } - - if (sizeof(uint8_t) == sizeof(wchar_t)) { - add_typedef(L, "uint8_t", "wchar_t"); - } else if (sizeof(uint16_t) == sizeof(wchar_t)) { - add_typedef(L, "uint16_t", "wchar_t"); - } else if (sizeof(uint32_t) == sizeof(wchar_t)) { - add_typedef(L, "uint32_t", "wchar_t"); - } - - if (sizeof(va_list) == sizeof(char*)) { - add_typedef(L, "char*", "va_list"); - } else { - struct {char ch; va_list v;} av; - lua_pushfstring(L, "struct {char data[%d] __attribute__((align(%d)));}", (int) sizeof(va_list), (int) ALIGNOF(av) + 1); - add_typedef(L, lua_tostring(L, -1), "va_list"); - lua_pop(L, 1); - } - - add_typedef(L, "va_list", "__builtin_va_list"); - add_typedef(L, "va_list", "__gnuc_va_list"); - } - - assert(lua_gettop(L) == 1); - - /* setup ABI params table */ - push_upval(L, &abi_key); - -#if defined ARCH_X86 || defined ARCH_ARM - lua_pushboolean(L, 1); - lua_setfield(L, -2, "32bit"); -#elif defined ARCH_X64 || defined ARCH_PPC64 - lua_pushboolean(L, 1); - lua_setfield(L, -2, "64bit"); -#else -#error -#endif - -#if defined ARCH_X86 || defined ARCH_X64 || defined ARCH_ARM || defined ARCH_PPC64 - lua_pushboolean(L, 1); - lua_setfield(L, -2, "le"); -#else -#error -#endif - -#if defined ARCH_X86 || defined ARCH_X64 || defined ARCH_PPC64 - lua_pushboolean(L, 1); - lua_setfield(L, -2, "fpu"); -#elif defined ARCH_ARM - lua_pushboolean(L, 1); - lua_setfield(L, -2, "softfp"); -#else -#error -#endif - lua_pop(L, 1); /* abi tbl */ - - - /* GC table - shouldn't pin cdata values */ - push_upval(L, &gc_key); - lua_newtable(L); - lua_pushliteral(L, "k"); - lua_setfield(L, -2, "__mode"); - lua_setmetatable(L, -2); - lua_pop(L, 1); /* gc table */ - - - /* ffi.os */ -#if defined OS_CE - lua_pushliteral(L, "WindowsCE"); -#elif defined OS_WIN - lua_pushliteral(L, "Windows"); -#elif defined OS_OSX - lua_pushliteral(L, "OSX"); -#elif defined OS_LINUX - lua_pushliteral(L, "Linux"); -#elif defined OS_BSD - lua_pushliteral(L, "BSD"); -#elif defined OS_POSIX - lua_pushliteral(L, "POSIX"); -#else - lua_pushliteral(L, "Other"); -#endif - lua_setfield(L, 1, "os"); - - - /* ffi.arch */ -#if defined ARCH_X86 - lua_pushliteral(L, "x86"); -#elif defined ARCH_X64 - lua_pushliteral(L, "x64"); -#elif defined ARCH_ARM - lua_pushliteral(L, "arm"); -#elif defined ARCH_PPC64 - lua_pushliteral(L, "ppc64"); -#else -# error -#endif - lua_setfield(L, 1, "arch"); - - assert(lua_gettop(L) == 1); - - return 0; -} - -static void setup_mt(lua_State* L, const luaL_Reg* mt, int upvals) -{ - lua_pushboolean(L, 1); - lua_setfield(L, -upvals-2, "__metatable"); - luaL_setfuncs(L, mt, upvals); -} - -int luaopen_ffi(lua_State* L) -{ - lua_settop(L, 0); - - lua_newtable(L); - set_upval(L, &niluv_key); - - lua_newtable(L); - setup_mt(L, ctype_mt, 0); - set_upval(L, &ctype_mt_key); - - lua_newtable(L); - set_upval(L, &callbacks_key); - - lua_newtable(L); - set_upval(L, &gc_key); - - lua_newtable(L); - push_upval(L, &callbacks_key); - push_upval(L, &gc_key); - setup_mt(L, cdata_mt, 2); - set_upval(L, &cdata_mt_key); - - lua_newtable(L); - setup_mt(L, callback_mt, 0); - set_upval(L, &callback_mt_key); - - lua_newtable(L); - setup_mt(L, cmodule_mt, 0); - set_upval(L, &cmodule_mt_key); - - memset(lua_newuserdata(L, sizeof(struct jit)), 0, sizeof(struct jit)); - lua_newtable(L); - setup_mt(L, jit_mt, 0); - lua_setmetatable(L, -2); - set_upval(L, &jit_key); - - lua_newtable(L); - set_upval(L, &constants_key); - - lua_newtable(L); - set_upval(L, &types_key); - - lua_newtable(L); - set_upval(L, &functions_key); - - lua_newtable(L); - set_upval(L, &asmname_key); - - lua_newtable(L); - set_upval(L, &abi_key); - - lua_pushinteger(L, 1); - set_upval(L, &next_unnamed_key); - - assert(lua_gettop(L) == 0); - - /* ffi table */ - lua_newtable(L); - luaL_setfuncs(L, ffi_reg, 0); - - /* setup_upvals(ffi tbl) */ - lua_pushcfunction(L, &setup_upvals); - lua_pushvalue(L, 1); - lua_call(L, 1, 0); - - assert(lua_gettop(L) == 1); - - lua_getglobal(L, "tonumber"); - lua_pushcclosure(L, &ffi_number, 1); - lua_pushvalue(L, -1); - lua_setglobal(L, "tonumber"); - lua_setfield(L, -2, "number"); /* ffi.number */ - - lua_getglobal(L, "type"); - lua_pushcclosure(L, &ffi_type, 1); - lua_pushvalue(L, -1); - lua_setglobal(L, "type"); - lua_setfield(L, -2, "type"); /* ffi.type */ - return 1; -} diff --git a/texk/web2c/luatexdir/luaffi/ffi.h b/texk/web2c/luatexdir/luaffi/ffi.h index 8190a97389..5555894e0c 100644 --- a/texk/web2c/luatexdir/luaffi/ffi.h +++ b/texk/web2c/luatexdir/luaffi/ffi.h @@ -9,7 +9,7 @@ #pragma once -#ifdef _MSC_VER +#if defined(_MSC_VER) #define _CRT_SECURE_NO_WARNINGS #endif @@ -42,15 +42,13 @@ extern "C" { #include #endif -#if ( defined( _WIN32) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__bsdi__) || defined(__DragonFly__)) -/* We should include something equivalent to */ -/* complex.h */ -#else +#if __STDC_VERSION__+0 >= 199901L + #include #define HAVE_COMPLEX #define HAVE_LONG_DOUBLE -#endif +#endif #ifndef NDEBUG #define DASM_CHECKS @@ -70,7 +68,66 @@ struct jit; #else # define EXPORT #endif +#ifdef __ANDROID_API__ +#include +#define LOGE(msg, ...) __android_log_print(ANDROID_LOG_ERROR,"FFI",msg,##__VA_ARGS__) +#define LOGV(msg, ...) __android_log_print(ANDROID_LOG_VERBOSE,"FFI",msg,##__VA_ARGS__) +#define LOGI(msg, ...) __android_log_print(ANDROID_LOG_INFO,"FFI",msg,##__VA_ARGS__) +#define LOGW(msg, ...) __android_log_print(ANDROID_LOG_WARN,"FFI",msg,##__VA_ARGS__) +#endif +/* architectures */ +#if defined _WIN32 && defined UNDER_CE +# define OS_CE +#elif defined _WIN32 +# define OS_WIN +#elif defined __APPLE__ && defined __MACH__ +# define OS_OSX +#elif defined __ANDROID_API__ +#define OS_ANDROID +#elif defined __linux__ +# define OS_LINUX +#elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ +# define OS_BSD +#elif defined unix || defined __unix__ || defined __unix || defined _POSIX_VERSION || defined _XOPEN_VERSION +# define OS_POSIX +#endif +/* architecture */ +#if defined __i386__ || defined _M_IX86 +# define ARCH_X86 +#elif defined __amd64__ || defined _M_X64 +# define ARCH_X64 +#elif defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm +# define ARCH_ARM +#elif defined __aarch64__ +# define ARCH_ARM64 +#elif defined __powerpc64__ +# define ARCH_PPC64 +#else +# UNSUPPORTED_ARCH /*error*/ +#endif + +/* See ffi.c: replace luaopen_ffi with a stub */ +/* if FFI_ENABLE_LUATEX_INTERFACE is not defined */ +#if (defined ARCH_X86 || defined ARCH_X64) && (defined OS_CE || defined OS_WIN || defined OS_LINUX || defined OS_BSD || defined OS_POSIX || defined OS_OSX) || ( defined ARCH_ARM64 && (defined OS_LINUX ||defined OS_POSIX )) +#define FFI_ENABLE_LUATEX_INTERFACE +#endif +/* for the moment */ +#if (defined __CYGWIN__) +#undef FFI_ENABLE_LUATEX_INTERFACE +#endif + + +#if defined ARCH_X86 || defined ARCH_X64 +#define ALLOW_MISALIGNED_ACCESS +#endif +#ifdef OS_WIN +#define ALWAYS_INLINE __forceinline +#elif defined(__GNUC__) +#define ALWAYS_INLINE __attribute__ ((always_inline)) +#else +#define ALWAYS_INLINE inline +#endif EXTERN_C EXPORT int luaopen_ffi(lua_State* L); static int lua_absindex2(lua_State* L, int idx) { @@ -80,12 +137,15 @@ static int lua_absindex2(lua_State* L, int idx) { } /* use our own version of lua_absindex such that lua_absindex(L, 0) == 0 */ #define lua_absindex(L, idx) lua_absindex2(L, idx) - -#if LUA_VERSION_NUM == 501 -static void lua_callk(lua_State *L, int nargs, int nresults, int ctx, lua_CFunction k) +#if LUA_VERSION_NUM>501 +static void (lua_call)(lua_State *L, int nargs, int nresults) { lua_call(L, nargs, nresults); } +#endif + +#if LUA_VERSION_NUM == 501 + /* ** set functions from list 'l' into table at top - 'nup'; each ** function gets the 'nup' elements at the top as upvalues. @@ -111,54 +171,18 @@ static char* luaL_prepbuffsize(luaL_Buffer* B, size_t sz) { } return luaL_prepbuffer(B); } -#elif LUA_VERSION_NUM == 503 + +static ALWAYS_INLINE void lua_rawgetp(lua_State *L, int idx,void* p){ + lua_pushlightuserdata(L, p); + lua_rawget(L, idx); +} + +#elif LUA_VERSION_NUM >= 503 static void (lua_remove)(lua_State *L, int idx) { lua_remove(L, idx); } #endif -/* architectures */ -#if defined _WIN32 && defined UNDER_CE -# define OS_CE -#elif defined _WIN32 -# define OS_WIN -#elif defined __APPLE__ && defined __MACH__ -# define OS_OSX -#elif defined __linux__ -# define OS_LINUX -#elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ -# define OS_BSD -#elif defined unix || defined __unix__ || defined __unix || defined _POSIX_VERSION || defined _XOPEN_VERSION -# define OS_POSIX -#endif - -/* architecture */ -#if defined __i386__ || defined _M_IX86 -# define ARCH_X86 -#elif defined __amd64__ || defined _M_X64 -# define ARCH_X64 -#elif defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __aarch64__ -# define ARCH_ARM -#elif defined __powerpc64__ -# define ARCH_PPC64 -#else -# define UNSUPPORTED_ARCH -#endif - - -/* See ffi.c: replace luaopen_ffi with a stub */ -/* if FFI_ENABLE_LUATEX_INTERFACE is not defined */ -#if (defined ARCH_X86 || defined ARCH_X64) && (defined OS_CE || defined OS_WIN || defined OS_LINUX || defined OS_BSD || defined OS_POSIX || defined OS_OSX) -#define FFI_ENABLE_LUATEX_INTERFACE -#endif -/* for the moment */ -#if (defined __CYGWIN__) -#undef FFI_ENABLE_LUATEX_INTERFACE -#endif - - - - #ifdef _WIN32 # ifdef UNDER_CE @@ -191,16 +215,43 @@ static void (lua_remove)(lua_State *L, int idx) { # define LIB_FORMAT_1 "%s.so" # define LIB_FORMAT_2 "lib%s.so" #endif +#if defined (__GNUC__) +#define GCC_VERSION ((__GNUC__*10000) + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) +#endif +//Only arm need cache flush +#if defined(OS_ANDROID)|| (defined(__GNUC__) && GCC_VERSION>=40300) +#define CacheFlush(st,size) __builtin___clear_cache((char*)(st),(size)+(char*)(st)) +#elif defined(ARCH_ARM64)||defined(ARCH_ARM) +#if defined(OS_OSX) + void sys_icache_invalidate(void *start, size_t len); + #define CacheFlush(st,size) sys_icache_invalidate((char*)(st),size) +#else + #define CacheFlush(st,size) __clear_cache((char*)(st),(size)+(char*)(st)) +# endif +#else +#define CacheFlush(st,size) +#endif # define LoadLibraryA(name) dlopen(name, RTLD_LAZY | RTLD_GLOBAL) # define GetProcAddressA(lib, name) dlsym(lib, name) +# define FreeLibrary(lib) dlclose(lib) # define AllocPage(size) mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0) # define FreePage(data, size) munmap(data, size) -# define EnableExecute(data, size) mprotect(data, size, PROT_READ|PROT_EXEC) +# define EnableExecute(data, size) do{mprotect(data, size, PROT_READ|PROT_EXEC);CacheFlush(data,size);}while(0) # define EnableWrite(data, size) mprotect(data, size, PROT_READ|PROT_WRITE) #endif -#if defined ARCH_X86 || defined ARCH_X64 -#define ALLOW_MISALIGNED_ACCESS + + +// Since arm jump range is always small, so bl extern is hardly compiled +// as an direct offset to the destination. Unlike global extern functions which +//will be re-use many times, FUNCTION stub is only use one time, therefore, +// no need to keep it for arm +#if defined(ARCH_ARM64)|| defined(ARCH_ARM) +#define NO_FUNCTION_EXTERN +#endif + +#ifndef bool +#define bool _Bool #endif struct token; @@ -220,15 +271,18 @@ struct page { struct jit { lua_State* L; - int32_t last_errno; + //int32_t last_errno; dasm_State* ctx; size_t pagenum; +#ifndef NO_FUNCTION_EXTERN + int function_extern; +#endif struct page** pages; size_t align_page_size; void** globals; - int function_extern; + uint8_t* default_functions; void* lua_dll; - void* kernel32_dll; + //void* kernel32_dll; }; #define ALIGN_DOWN(PTR, MASK) \ @@ -246,11 +300,18 @@ struct jit { /* TODO: figure out why the alignof trick doesn't work on OS X */ #define ALIGNED_DEFAULT 7 #elif defined __GNUC__ -#define ALIGNED_DEFAULT (__alignof__(void* __attribute__((aligned))) - 1) +#define ALIGNED_DEFAULT (__alignof__(void*) - 1) #else #define ALIGNED_DEFAULT PTR_ALIGN_MASK #endif +#ifdef ARCH_ARM +#define ALIGNED_MAX 7 +#else//for arm64 x86 x64 +#define ALIGNED_MAX 15 +#endif + + extern int jit_key; extern int ctype_mt_key; extern int cdata_mt_key; @@ -343,16 +404,15 @@ struct ctype { */ size_t variable_increment; }; - size_t offset; unsigned align_mask : 4; /* as (align bytes - 1) eg 7 gives 8 byte alignment */ unsigned pointers : POINTER_BITS; /* number of dereferences to get to the base type including +1 for arrays */ + unsigned is_empty :1; unsigned const_mask : POINTER_MAX + 1; /* const pointer mask, LSB is current pointer, +1 for the whether the base type is const */ unsigned type : 5; /* value given by type enum above */ unsigned is_reference : 1; unsigned is_array : 1; unsigned is_defined : 1; unsigned is_null : 1; - unsigned has_member_name : 1; unsigned calling_convention : 2; unsigned has_var_arg : 1; unsigned is_variable_array : 1; /* set for variable array types where we don't know the variable size yet */ @@ -365,28 +425,80 @@ struct ctype { unsigned is_unsigned : 1; }; +struct member_type{ + struct ctype ct; + unsigned has_member_name : 1; + size_t offset; +}; #ifdef _MSC_VER __declspec(align(16)) #endif struct cdata { const struct ctype type -/*#ifdef __GNUC__*/ -/* __attribute__ ((aligned(16)))*/ -/*#endif*/ +#ifdef __GNUC__ + __attribute__ ((aligned(16))) +#endif ; }; typedef void (*cfunction)(void); #ifdef HAVE_COMPLEX +#if defined(_MSC_VER) +typedef _Dcomplex complex_double; +typedef _Fcomplex complex_float; +static ALWAYS_INLINE complex_double mk_complex_double(double real, double imag) { + return (complex_double){real , imag }; +} +static ALWAYS_INLINE complex_float mk_complex_float(double real, double imag) { + return (complex_float){real , imag}; +} +#else typedef double complex complex_double; typedef float complex complex_float; -static complex_double mk_complex_double(double real, double imag) { - return real + imag * 1i; +static ALWAYS_INLINE complex_double mk_complex_double(double real, double imag) { + return real + imag * 1i; } -static complex_double mk_complex_float(double real, double imag) { +static ALWAYS_INLINE complex_float mk_complex_float(double real, double imag) { return real + imag * 1i; } +#endif +/* static ALWAYS_INLINE complex_double mk_complex_double(double real, double imag) { */ +/* return (complex_double){real , imag }; */ +/* } */ +/* static ALWAYS_INLINE complex_float mk_complex_float(double real, double imag) { */ +/* return (complex_float){real , imag}; */ +/* } */ + + +extern float cimagf(complex_float); +extern float crealf(complex_float); +extern double cimag(complex_double); +extern double creal(complex_double); + + +#if defined(OS_ANDROID) && __ANDROID_API__<26 +#include + +#define cabs(f) ((double (*)(complex_double))hypot)(f); + +static complex_double cpow(complex_double f,complex_double s){ + if(cimag(s)==0){ + double real = creal(s); + double r=cabs(f); + r = pow(r, real); + double theta = atan2(creal(f), cimag(f)) * real; + return mk_complex_double(r*cos(theta),r*sin(theta)); + } + double r= cabs(f); + double theta = atan2(creal(f), cimag(f)); + r = log(r); + f= s*mk_complex_double(r,theta); + r = exp(creal(f)); + theta=cimag(f); + return mk_complex_double(r*cos(theta),r*sin(theta)); +} +#endif #else typedef struct { double real, imag; @@ -396,44 +508,61 @@ typedef struct { float real, imag; } complex_float; -static complex_double mk_complex_double(double real, double imag) { - complex_double ret = { real, imag }; - return ret; +static ALWAYS_INLINE complex_double mk_complex_double(double real, double imag) { + return (complex_double){ real, imag }; } -static complex_float mk_complex_float(double real, double imag) { - complex_float ret = { real, imag }; - return ret; +static ALWAYS_INLINE complex_float mk_complex_float(double real, double imag) { + return (complex_float){ real, imag }; } -//#if !defined(__MINGW64__) -static double creal(complex_double c) { +static ALWAYS_INLINE double creal(complex_double c) { return c.real; } -static float crealf(complex_float c) { +static ALWAYS_INLINE float crealf(complex_float c) { return c.real; } -static double cimag(complex_double c) { +static ALWAYS_INLINE double cimag(complex_double c) { return c.imag; } -static float cimagf(complex_float c) { +static ALWAYS_INLINE float cimagf(complex_float c) { return c.imag; } -//#endif + +#include "math.h" +static complex_double cpow(complex_double f, complex_double s) { + if (s.imag == 0) { + double real = s.real; + double r = hypot(f.real, f.imag); + r = pow(r, real); + double theta = atan2(f.imag, f.real) * real; + return (complex_double){ r*cos(theta),r*sin(theta) }; + } + double r= hypot(f.real, f.imag); + double theta = atan2(f.imag, f.real); + r = log(r); + f = (complex_double) { r * s.real - theta * s.imag ,r * s.imag + s.real*theta}; + r = exp(f.real); + return (complex_double) {r*cos(f.imag),r*sin(f.imag)}; +} #endif #define CALLBACK_FUNC_USR_IDX 1 void set_defined(lua_State* L, int ct_usr, struct ctype* ct); struct ctype* push_ctype(lua_State* L, int ct_usr, const struct ctype* ct); +struct member_type* push_member_type(lua_State* L, int ct_usr, const struct member_type* mt); void* push_cdata(lua_State* L, int ct_usr, const struct ctype* ct); /* called from asm */ void push_callback(lua_State* L, cfunction luafunc, cfunction cfunc); void check_ctype(lua_State* L, int idx, struct ctype* ct); void* to_cdata(lua_State* L, int idx, struct ctype* ct); +const struct ctype* get_ctype(lua_State* L, int idx); void* check_cdata(lua_State* L, int idx, struct ctype* ct); size_t ctype_size(lua_State* L, const struct ctype* ct); int parse_type(lua_State* L, struct parser* P, struct ctype* type); -void parse_argument(lua_State* L, struct parser* P, int ct_usr, struct ctype* type, struct token* name, struct parser* asmname); +void parse_argument(lua_State *L, struct parser *P, int ct_usr, struct ctype *type, + struct token *name, + struct parser *asmname, bool ignore_name); void push_type_name(lua_State* L, int usr, const struct ctype* ct); int push_user_mt(lua_State* L, int ct_usr, const struct ctype* ct); @@ -449,9 +578,7 @@ void compile_globals(struct jit* jit, lua_State* L); int get_extern(struct jit* jit, uint8_t* addr, int idx, int type); /* WARNING: assembly needs to be updated for prototype changes of these functions */ -int check_bool(lua_State* L, int idx); double check_double(lua_State* L, int idx); -double check_complex_imag(lua_State* L, int idx); float check_float(lua_State* L, int idx); uint64_t check_uint64(lua_State* L, int idx); int64_t check_int64(lua_State* L, int idx); @@ -459,6 +586,7 @@ int32_t check_int32(lua_State* L, int idx); uint32_t check_uint32(lua_State* L, int idx); uintptr_t check_uintptr(lua_State* L, int idx); int32_t check_enum(lua_State* L, int idx, int to_usr, const struct ctype* tt); +void* check_struct(lua_State*L,int idx, int to_usr,const struct ctype* ct); /* these two will always push a value so that we can create structs/functions on the fly */ void* check_typed_pointer(lua_State* L, int idx, int to_usr, const struct ctype* tt); cfunction check_typed_cfunction(lua_State* L, int idx, int to_usr, const struct ctype* tt); @@ -472,5 +600,4 @@ void unpack_varargs_stack_skip(lua_State* L, int first, int last, int ints_to_sk void unpack_varargs_float(lua_State* L, int first, int last, int max, char* to); void unpack_varargs_int(lua_State* L, int first, int last, int max, char* to); - - +int unpack_varargs_bound(lua_State* L, int first, char* to,char* end); diff --git a/texk/web2c/luatexdir/luaffi/ffi.h.orig b/texk/web2c/luatexdir/luaffi/ffi.h.orig deleted file mode 100644 index dabdc9b38b..0000000000 --- a/texk/web2c/luatexdir/luaffi/ffi.h.orig +++ /dev/null @@ -1,455 +0,0 @@ -/* vim: ts=4 sw=4 sts=4 et tw=78 - * Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved. - * Portions copyright (c) 2011 James R. McKaskill. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#pragma once - -#ifdef _MSC_VER -#define _CRT_SECURE_NO_WARNINGS -#endif - -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -# include -# include -# include -} -# define EXTERN_C extern "C" -#else -# include -# include -# include -# define EXTERN_C extern -#endif - -#ifdef _WIN32 -#include -#else -#include -#include -#include -#include -#endif - -#include -#define HAVE_COMPLEX -#define HAVE_LONG_DOUBLE - -#ifndef NDEBUG -#define DASM_CHECKS -#endif - -struct jit; -#define Dst_DECL struct jit* Dst -#define Dst_REF (Dst->ctx) -#define DASM_EXTERN(a,b,c,d) get_extern(a,b,c,d) - -#include "dynasm/dasm_proto.h" - -#if defined LUA_FFI_BUILD_AS_DLL -# define EXPORT __declspec(dllexport) -#elif defined __GNUC__ -# define EXPORT __attribute__((visibility("default"))) -#else -# define EXPORT -#endif - -EXTERN_C EXPORT int luaopen_ffi(lua_State* L); - -static int lua_absindex2(lua_State* L, int idx) { - return (LUA_REGISTRYINDEX <= idx && idx < 0) - ? lua_gettop(L) + idx + 1 - : idx; -} -/* use our own version of lua_absindex such that lua_absindex(L, 0) == 0 */ -#define lua_absindex(L, idx) lua_absindex2(L, idx) - -#if LUA_VERSION_NUM == 501 -static void lua_callk(lua_State *L, int nargs, int nresults, int ctx, lua_CFunction k) -{ - lua_call(L, nargs, nresults); -} -/* -** set functions from list 'l' into table at top - 'nup'; each -** function gets the 'nup' elements at the top as upvalues. -** Returns with only the table at the stack. -*/ -static void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { - luaL_checkstack(L, nup, "too many upvalues"); - for (; l && l->name; l++) { /* fill the table with given functions */ - int i; - for (i = 0; i < nup; i++) /* copy upvalues to the top */ - lua_pushvalue(L, -nup); - lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ - lua_setfield(L, -(nup + 2), l->name); - } - lua_pop(L, nup); /* remove upvalues */ -} -#define lua_setuservalue lua_setfenv -#define lua_getuservalue lua_getfenv -#define lua_rawlen lua_objlen -static char* luaL_prepbuffsize(luaL_Buffer* B, size_t sz) { - if (sz > LUAL_BUFFERSIZE) { - luaL_error(B->L, "string too long"); - } - return luaL_prepbuffer(B); -} -#elif LUA_VERSION_NUM == 503 -static void (lua_remove)(lua_State *L, int idx) { - lua_remove(L, idx); -} -#endif - -/* architectures */ -#if defined _WIN32 && defined UNDER_CE -# define OS_CE -#elif defined _WIN32 -# define OS_WIN -#elif defined __APPLE__ && defined __MACH__ -# define OS_OSX -#elif defined __linux__ -# define OS_LINUX -#elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ -# define OS_BSD -#elif defined unix || defined __unix__ || defined __unix || defined _POSIX_VERSION || defined _XOPEN_VERSION -# define OS_POSIX -#endif - -/* architecture */ -#if defined __i386__ || defined _M_IX86 -# define ARCH_X86 -#elif defined __amd64__ || defined _M_X64 -# define ARCH_X64 -#elif defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __aarch64__ -# define ARCH_ARM -#elif defined __powerpc64__ -# define ARCH_PPC64 -#else -# error -#endif - - -#ifdef _WIN32 - -# ifdef UNDER_CE - static void* DoLoadLibraryA(const char* name) { - wchar_t buf[MAX_PATH]; - int sz = MultiByteToWideChar(CP_UTF8, 0, name, -1, buf, 512); - if (sz > 0) { - buf[sz] = 0; - return LoadLibraryW(buf); - } else { - return NULL; - } - } -# define LoadLibraryA DoLoadLibraryA -# else -# define GetProcAddressA GetProcAddress -# endif - -# define LIB_FORMAT_1 "%s.dll" -# define AllocPage(size) VirtualAlloc(NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE) -# define FreePage(data, size) VirtualFree(data, 0, MEM_RELEASE) -# define EnableExecute(data, size) do {DWORD old; VirtualProtect(data, size, PAGE_EXECUTE, &old); FlushInstructionCache(GetCurrentProcess(), data, size);} while (0) -# define EnableWrite(data, size) do {DWORD old; VirtualProtect(data, size, PAGE_READWRITE, &old);} while (0) - -#else -#ifdef OS_OSX -# define LIB_FORMAT_1 "%s.dylib" -# define LIB_FORMAT_2 "lib%s.dylib" -#else -# define LIB_FORMAT_1 "%s.so" -# define LIB_FORMAT_2 "lib%s.so" -#endif -# define LoadLibraryA(name) dlopen(name, RTLD_LAZY | RTLD_GLOBAL) -# define GetProcAddressA(lib, name) dlsym(lib, name) -# define AllocPage(size) mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0) -# define FreePage(data, size) munmap(data, size) -# define EnableExecute(data, size) mprotect(data, size, PROT_READ|PROT_EXEC) -# define EnableWrite(data, size) mprotect(data, size, PROT_READ|PROT_WRITE) -#endif - -#if defined ARCH_X86 || defined ARCH_X64 -#define ALLOW_MISALIGNED_ACCESS -#endif - -struct token; - -struct parser { - int line; - const char* next; - const char* prev; - unsigned align_mask; -}; - -struct page { - size_t size; - size_t off; - size_t freed; -}; - -struct jit { - lua_State* L; - int32_t last_errno; - dasm_State* ctx; - size_t pagenum; - struct page** pages; - size_t align_page_size; - void** globals; - int function_extern; - void* lua_dll; - void* kernel32_dll; -}; - -#define ALIGN_DOWN(PTR, MASK) \ - (((uintptr_t) (PTR)) & (~ ((uintptr_t) (MASK)) )) -#define ALIGN_UP(PTR, MASK) \ - (( ((uintptr_t) (PTR)) + ((uintptr_t) (MASK)) ) & (~ ((uintptr_t) (MASK)) )) - -/* struct cdata/struct ctype */ - -#define PTR_ALIGN_MASK (sizeof(void*) - 1) -#define FUNCTION_ALIGN_MASK (sizeof(void (*)()) - 1) -#define DEFAULT_ALIGN_MASK 7 - -#ifdef OS_OSX -/* TODO: figure out why the alignof trick doesn't work on OS X */ -#define ALIGNED_DEFAULT 7 -#elif defined __GNUC__ -#define ALIGNED_DEFAULT (__alignof__(void* __attribute__((aligned))) - 1) -#else -#define ALIGNED_DEFAULT PTR_ALIGN_MASK -#endif - -extern int jit_key; -extern int ctype_mt_key; -extern int cdata_mt_key; -extern int cmodule_mt_key; -extern int callback_mt_key; -extern int constants_key; -extern int types_key; -extern int gc_key; -extern int callbacks_key; -extern int functions_key; -extern int abi_key; -extern int next_unnamed_key; -extern int niluv_key; -extern int asmname_key; - -int equals_upval(lua_State* L, int idx, int* key); -void push_upval(lua_State* L, int* key); -void set_upval(lua_State* L, int* key); -struct jit* get_jit(lua_State* L); - -/* both ctype and cdata are stored as userdatas - * - * usr value is a table shared between the related subtypes which has: - * name -> member ctype (for structs and unions) - * +ves -> member ctype - in memory order (for structs) - * +ves -> argument ctype (for function prototypes) - * 0 -> return ctype (for function prototypes) - * light userdata -> misc - */ - -enum { - C_CALL, - STD_CALL, - FAST_CALL, -}; - -enum { - INVALID_TYPE, - VOID_TYPE, - FLOAT_TYPE, - DOUBLE_TYPE, - LONG_DOUBLE_TYPE, - COMPLEX_FLOAT_TYPE, - COMPLEX_DOUBLE_TYPE, - COMPLEX_LONG_DOUBLE_TYPE, - BOOL_TYPE, - INT8_TYPE, - INT16_TYPE, - INT32_TYPE, - INT64_TYPE, - INTPTR_TYPE, - ENUM_TYPE, - UNION_TYPE, - STRUCT_TYPE, - FUNCTION_TYPE, - FUNCTION_PTR_TYPE, -}; - -#define IS_CHAR_UNSIGNED (((char) -1) > 0) -#define IS_COMPLEX(type) ((type) == COMPLEX_FLOAT_TYPE || (type) == COMPLEX_DOUBLE_TYPE) - -#define POINTER_BITS 2 -#define POINTER_MAX ((1 << POINTER_BITS) - 1) - -#define ALIGNOF(S) ((int) ((char*) &S.v - (char*) &S - 1)) - -/* Note: if adding a new member that is associated with a struct/union - * definition then it needs to be copied over in ctype.c:set_defined for when - * we create types based off of the declaration alone. - * - * Since this is used as a header for every ctype and cdata, and we create a - * ton of them on the stack, we try and minimise its size. - */ -struct ctype { - size_t base_size; /* size of the base type in bytes */ - - union { - /* valid if is_bitfield */ - struct { - /* size of bitfield in bits */ - unsigned bit_size : 7; - /* offset within the current byte between 0-63 */ - unsigned bit_offset : 6; - }; - /* Valid if is_array */ - size_t array_size; - /* Valid for is_variable_struct or is_variable_array. If - * variable_size_known (only used for is_variable_struct) then this is - * the total increment otherwise this is the per element increment. - */ - size_t variable_increment; - }; - size_t offset; - unsigned align_mask : 4; /* as (align bytes - 1) eg 7 gives 8 byte alignment */ - unsigned pointers : POINTER_BITS; /* number of dereferences to get to the base type including +1 for arrays */ - unsigned const_mask : POINTER_MAX + 1; /* const pointer mask, LSB is current pointer, +1 for the whether the base type is const */ - unsigned type : 5; /* value given by type enum above */ - unsigned is_reference : 1; - unsigned is_array : 1; - unsigned is_defined : 1; - unsigned is_null : 1; - unsigned has_member_name : 1; - unsigned calling_convention : 2; - unsigned has_var_arg : 1; - unsigned is_variable_array : 1; /* set for variable array types where we don't know the variable size yet */ - unsigned is_variable_struct : 1; - unsigned variable_size_known : 1; /* used for variable structs after we know the variable size */ - unsigned is_bitfield : 1; - unsigned has_bitfield : 1; - unsigned is_jitted : 1; - unsigned is_packed : 1; - unsigned is_unsigned : 1; -}; - -#ifdef _MSC_VER -__declspec(align(16)) -#endif -struct cdata { - const struct ctype type -#ifdef __GNUC__ - __attribute__ ((aligned(16))) -#endif - ; -}; - -typedef void (*cfunction)(void); - -#ifdef HAVE_COMPLEX -typedef double complex complex_double; -typedef float complex complex_float; -static complex_double mk_complex_double(double real, double imag) { - return real + imag * 1i; -} -static complex_double mk_complex_float(double real, double imag) { - return real + imag * 1i; -} -#else -typedef struct { - double real, imag; -} complex_double; - -typedef struct { - float real, imag; -} complex_float; - -static complex_double mk_complex_double(double real, double imag) { - complex_double ret = { real, imag }; - return ret; -} -static complex_float mk_complex_float(double real, double imag) { - complex_float ret = { real, imag }; - return ret; -} -static double creal(complex_double c) { - return c.real; -} -static float crealf(complex_float c) { - return c.real; -} - -static double cimag(complex_double c) { - return c.imag; -} -static float cimagf(complex_float c) { - return c.imag; -} -#endif - -#define CALLBACK_FUNC_USR_IDX 1 - -void set_defined(lua_State* L, int ct_usr, struct ctype* ct); -struct ctype* push_ctype(lua_State* L, int ct_usr, const struct ctype* ct); -void* push_cdata(lua_State* L, int ct_usr, const struct ctype* ct); /* called from asm */ -void push_callback(lua_State* L, cfunction luafunc, cfunction cfunc); -void check_ctype(lua_State* L, int idx, struct ctype* ct); -void* to_cdata(lua_State* L, int idx, struct ctype* ct); -void* check_cdata(lua_State* L, int idx, struct ctype* ct); -size_t ctype_size(lua_State* L, const struct ctype* ct); - -int parse_type(lua_State* L, struct parser* P, struct ctype* type); -void parse_argument(lua_State* L, struct parser* P, int ct_usr, struct ctype* type, struct token* name, struct parser* asmname); -void push_type_name(lua_State* L, int usr, const struct ctype* ct); - -int push_user_mt(lua_State* L, int ct_usr, const struct ctype* ct); - -int ffi_cdef(lua_State* L); - -void push_func_ref(lua_State* L, cfunction func); -void free_code(struct jit* jit, lua_State* L, cfunction func); -int x86_return_size(lua_State* L, int usr, const struct ctype* ct); -void compile_function(lua_State* L, cfunction f, int ct_usr, const struct ctype* ct); -cfunction compile_callback(lua_State* L, int fidx, int ct_usr, const struct ctype* ct); -void compile_globals(struct jit* jit, lua_State* L); -int get_extern(struct jit* jit, uint8_t* addr, int idx, int type); - -/* WARNING: assembly needs to be updated for prototype changes of these functions */ -int check_bool(lua_State* L, int idx); -double check_double(lua_State* L, int idx); -double check_complex_imag(lua_State* L, int idx); -float check_float(lua_State* L, int idx); -uint64_t check_uint64(lua_State* L, int idx); -int64_t check_int64(lua_State* L, int idx); -int32_t check_int32(lua_State* L, int idx); -uint32_t check_uint32(lua_State* L, int idx); -uintptr_t check_uintptr(lua_State* L, int idx); -int32_t check_enum(lua_State* L, int idx, int to_usr, const struct ctype* tt); -/* these two will always push a value so that we can create structs/functions on the fly */ -void* check_typed_pointer(lua_State* L, int idx, int to_usr, const struct ctype* tt); -cfunction check_typed_cfunction(lua_State* L, int idx, int to_usr, const struct ctype* tt); -complex_double check_complex_double(lua_State* L, int idx); -complex_float check_complex_float(lua_State* L, int idx); - -void unpack_varargs_stack(lua_State* L, int first, int last, char* to); -void unpack_varargs_reg(lua_State* L, int first, int last, char* to); - -void unpack_varargs_stack_skip(lua_State* L, int first, int last, int ints_to_skip, int floats_to_skip, char* to); -void unpack_varargs_float(lua_State* L, int first, int last, int max, char* to); -void unpack_varargs_int(lua_State* L, int first, int last, int max, char* to); - - - diff --git a/texk/web2c/luatexdir/luaffi/generate_call_h.bat b/texk/web2c/luatexdir/luaffi/generate_call_h.bat deleted file mode 100644 index bb8ce26188..0000000000 --- a/texk/web2c/luatexdir/luaffi/generate_call_h.bat +++ /dev/null @@ -1,4 +0,0 @@ -lua.exe dynasm\dynasm.lua -LNE -D X32WIN -o call_x86.h call_x86.dasc -lua.exe dynasm\dynasm.lua -LNE -D X64 -o call_x64.h call_x86.dasc -lua.exe dynasm\dynasm.lua -LNE -D X64 -D X64WIN -o call_x64win.h call_x86.dasc -lua.exe dynasm\dynasm.lua -LNE -o call_arm.h call_arm.dasc diff --git a/texk/web2c/luatexdir/luaffi/luaffi-scm-1.rockspec b/texk/web2c/luatexdir/luaffi/luaffi-scm-1.rockspec deleted file mode 100644 index 42cea90e6c..0000000000 --- a/texk/web2c/luatexdir/luaffi/luaffi-scm-1.rockspec +++ /dev/null @@ -1,34 +0,0 @@ -package = "luaffi" -version = "scm-1" - -source = { - url = "git://github.com/facebook/luaffifb.git", -} - -description = { - summary = "FFI library for calling C functions from lua", - detailed = [[ - ]], - homepage = "https://github.com/facebook/luaffifb", - license = "BSD" -} - -dependencies = { - "lua >= 5.1", -} - -build = { - type = "builtin", - modules = { - ['ffi'] = { - incdirs = { - "dynasm" - }, - sources = { - "call.c", "ctype.c", "ffi.c", "parser.c", - } - }, - ['ffi.libtest'] = 'test.c', - ['ffi.test'] = 'test.lua', - } -} diff --git a/texk/web2c/luatexdir/luaffi/msvc/inttypes.h b/texk/web2c/luatexdir/luaffi/msvc/inttypes.h deleted file mode 100644 index d137c703f4..0000000000 --- a/texk/web2c/luatexdir/luaffi/msvc/inttypes.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -/* Signed integers */ -#define PRId8 "d" -#define PRId16 "d" -#define PRId32 "d" -#define PRId64 "I64d" -#define PRIi8 "i" -#define PRIi16 "i" -#define PRIi32 "i" -#define PRIi64 "I64i" - -/* Unsigned integers */ -#define PRIo8 "o" -#define PRIo16 "o" -#define PRIo32 "o" -#define PRIo64 "I64o" -#define PRIu8 "u" -#define PRIu16 "u" -#define PRIu32 "u" -#define PRIu64 "I64u" -#define PRIx8 "x" -#define PRIx16 "x" -#define PRIx32 "x" -#define PRIx64 "I64x" -#define PRIX8 "X" -#define PRIX16 "X" -#define PRIX32 "X" -#define PRIX64 "I64X" -#define PRIxPTR PRIx32 -#define PRIXPTR PRIX32 diff --git a/texk/web2c/luatexdir/luaffi/msvc/stdbool.h b/texk/web2c/luatexdir/luaffi/msvc/stdbool.h deleted file mode 100644 index 0bf760b059..0000000000 --- a/texk/web2c/luatexdir/luaffi/msvc/stdbool.h +++ /dev/null @@ -1,42 +0,0 @@ -/* vim: ts=4 sw=4 sts=4 et - * - * Copyright (c) 2009 James R. McKaskill - * - * This software is licensed under the stock MIT license: - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * ---------------------------------------------------------------------------- - */ - -#pragma once - - -#if defined __cplusplus -typedef bool _Bool; - -#else -#pragma warning(disable:4244) /* conversion from int to _Bool */ -typedef unsigned char _Bool; -#define bool _Bool -#define true 1 -#define false 0 -#define __bool_true_false_are_defined 1 - -#endif diff --git a/texk/web2c/luatexdir/luaffi/msvc/stdint.h b/texk/web2c/luatexdir/luaffi/msvc/stdint.h deleted file mode 100644 index 627d30eb68..0000000000 --- a/texk/web2c/luatexdir/luaffi/msvc/stdint.h +++ /dev/null @@ -1,174 +0,0 @@ -// boost cstdint.hpp header file ------------------------------------------// - -// (C) Copyright Beman Dawes 1999. -// (C) Copyright Jens Mauer 2001 -// (C) Copyright John Maddock 2001 -// Distributed under the Boost -// Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See http://www.boost.org/libs/integer for documentation. - -// Revision History -// 31 Oct 01 use BOOST_HAS_LONG_LONG to check for "long long" (Jens M.) -// 16 Apr 01 check LONGLONG_MAX when looking for "long long" (Jens Maurer) -// 23 Jan 01 prefer "long" over "int" for int32_t and intmax_t (Jens Maurer) -// 12 Nov 00 Merged (Jens Maurer) -// 23 Sep 00 Added INTXX_C macro support (John Maddock). -// 22 Sep 00 Better 64-bit support (John Maddock) -// 29 Jun 00 Reimplement to avoid including stdint.h within namespace boost -// 8 Aug 99 Initial version (Beman Dawes) - - -#ifndef STDINT_H -#define STDINT_H - -#ifndef UNDER_CE -#include -#endif - -#include - -// These are fairly safe guesses for some 16-bit, and most 32-bit and 64-bit -// platforms. For other systems, they will have to be hand tailored. -// -// Because the fast types are assumed to be the same as the undecorated types, -// it may be possible to hand tailor a more efficient implementation. Such -// an optimization may be illusionary; on the Intel x86-family 386 on, for -// example, byte arithmetic and load/stores are as fast as "int" sized ones. - -// 8-bit types ------------------------------------------------------------// - -# if UCHAR_MAX == 0xff - typedef signed char int8_t; - typedef signed char int_least8_t; - typedef signed char int_fast8_t; - typedef unsigned char uint8_t; - typedef unsigned char uint_least8_t; - typedef unsigned char uint_fast8_t; -# else -# error defaults not correct; you must hand modify boost/cstdint.hpp -# endif - -// 16-bit types -----------------------------------------------------------// - -# if USHRT_MAX == 0xffff -# if defined(__crayx1) - // The Cray X1 has a 16-bit short, however it is not recommend - // for use in performance critical code. - typedef short int16_t; - typedef short int_least16_t; - typedef int int_fast16_t; - typedef unsigned short uint16_t; - typedef unsigned short uint_least16_t; - typedef unsigned int uint_fast16_t; -# else - typedef short int16_t; - typedef short int_least16_t; - typedef short int_fast16_t; - typedef unsigned short uint16_t; - typedef unsigned short uint_least16_t; - typedef unsigned short uint_fast16_t; -# endif -# elif (USHRT_MAX == 0xffffffff) && defined(CRAY) - // no 16-bit types on Cray: - typedef short int_least16_t; - typedef short int_fast16_t; - typedef unsigned short uint_least16_t; - typedef unsigned short uint_fast16_t; -# else -# error defaults not correct; you must hand modify boost/cstdint.hpp -# endif - -// 32-bit types -----------------------------------------------------------// - -# if ULONG_MAX == 0xffffffff - typedef long int32_t; - typedef long int_least32_t; - typedef long int_fast32_t; - typedef unsigned long uint32_t; - typedef unsigned long uint_least32_t; - typedef unsigned long uint_fast32_t; -# elif UINT_MAX == 0xffffffff - typedef int int32_t; - typedef int int_least32_t; - typedef int int_fast32_t; - typedef unsigned int uint32_t; - typedef unsigned int uint_least32_t; - typedef unsigned int uint_fast32_t; -# else -# error defaults not correct; you must hand modify boost/cstdint.hpp -# endif - -// 64-bit types + intmax_t and uintmax_t ----------------------------------// - - // - // we have Borland/Intel/Microsoft __int64: - // - typedef __int64 intmax_t; - typedef unsigned __int64 uintmax_t; - typedef __int64 int64_t; - typedef __int64 int_least64_t; - typedef __int64 int_fast64_t; - typedef unsigned __int64 uint64_t; - typedef unsigned __int64 uint_least64_t; - typedef unsigned __int64 uint_fast64_t; - - - -/**************************************************** - -Macro definition section: - -Define various INTXX_C macros only if -__STDC_CONSTANT_MACROS is defined. - -Undefine the macros if __STDC_CONSTANT_MACROS is -not defined and the macros are (cf ). - -Added 23rd September 2000 (John Maddock). -Modified 11th September 2001 to be excluded when -BOOST_HAS_STDINT_H is defined (John Maddock). - -******************************************************/ - -#if defined(__STDC_CONSTANT_MACROS) || !defined(__cplusplus) -// -// Borland/Intel/Microsoft compilers have width specific suffixes: -// -# define INT8_C(value) value##i8 -# define INT16_C(value) value##i16 -# define INT32_C(value) value##i32 -# define INT64_C(value) value##i64 -# define UINT8_C(value) value##ui8 -# define UINT16_C(value) value##ui16 -# define UINT32_C(value) value##ui32 -# define UINT64_C(value) value##ui64 -# define INTMAX_C(value) value##i64 -# define UINTMAX_C(value) value##ui64 - -#endif // __STDC_CONSTANT_MACROS_DEFINED etc. - -#if defined(__STDC_LIMIT_MACROS) || !defined(__cplusplus) -# define INT8_MIN INT8_C(-127)-1 -# define INT8_MAX INT8_C(127) -# define INT16_MIN INT16_C(-32767)-1 -# define INT16_MAX INT16_C(32767) -# define INT32_MIN INT32_C(-2147483647)-1 -# define INT32_MAX INT32_C(2147483647) -# define INT64_MAX INT64_C(9223372036854775807) -# define UINT8_MAX UINT8_C(255) -# define UINT16_MAX UINT16_C(65535) -# define UINT32_MAX UINT32_C(4294967295) -# define UINT64_MAX UINT64_C(18446744073709551615) -#endif - -#ifdef UNDER_CE -typedef unsigned long uintptr_t; -typedef long intptr_t; -#endif - - - -#endif // BOOST_CSTDINT_HPP - diff --git a/texk/web2c/luatexdir/luaffi/msvcbuild.bat b/texk/web2c/luatexdir/luaffi/msvcbuild.bat deleted file mode 100644 index 79c11eb19f..0000000000 --- a/texk/web2c/luatexdir/luaffi/msvcbuild.bat +++ /dev/null @@ -1,76 +0,0 @@ -@if not defined INCLUDE goto :FAIL - -@setlocal - -@if "%1"=="debug-5.1" goto :DEBUG_5_1 - -rem These should not have quotes -@set LUA_INCLUDE=Z:\c\lua-5.2.0\src -@set LUA_LIB=Z:\c\lua-5.2.0\lua5.2.lib -@set LUA_EXE=Z:\c\lua-5.2.0\lua.exe -rem This the name of the dll that can be handed to LoadLibrary. This should not have a path. -@set LUA_DLL=lua5.2.dll -@goto :DEBUG - -:DEBUG_5_1 -@set LUA_INCLUDE=Z:\c\lua-5.1.4\src -@set LUA_LIB=Z:\c\lua-5.1.4\lua5.1.lib -@set LUA_EXE=Z:\c\lua-5.1.4\lua.exe -@set LUA_DLL=lua5.1.dll - -:DEBUG -@set DO_CL=cl.exe /nologo /c /MDd /FC /Zi /Od /W3 /WX /D_CRT_SECURE_NO_DEPRECATE /DLUA_FFI_BUILD_AS_DLL /I"msvc" -@set DO_LINK=link /nologo /debug -@set DO_MT=mt /nologo - -@if "%1"=="debug" goto :COMPILE -@if "%1"=="debug-5.1" goto :COMPILE -@if "%1"=="test" goto :COMPILE -@if "%1"=="clean" goto :CLEAN -@if "%1"=="release" goto :RELEASE -@if "%1"=="test-release" goto :RELEASE - -:RELEASE -@set DO_CL=cl.exe /nologo /c /MD /Ox /W3 /Zi /WX /D_CRT_SECURE_NO_DEPRECATE /DLUA_FFI_BUILD_AS_DLL /I"msvc" -@set DO_LINK=link.exe /nologo /debug -@set DO_MT=mt.exe /nologo -@goto :COMPILE - -:COMPILE -"%LUA_EXE%" dynasm\dynasm.lua -LNE -D X32WIN -o call_x86.h call_x86.dasc -"%LUA_EXE%" dynasm\dynasm.lua -LNE -D X64 -o call_x64.h call_x86.dasc -"%LUA_EXE%" dynasm\dynasm.lua -LNE -D X64 -D X64WIN -o call_x64win.h call_x86.dasc -"%LUA_EXE%" dynasm\dynasm.lua -LNE -o call_arm.h call_arm.dasc -%DO_CL% /I"." /I"%LUA_INCLUDE%" /DLUA_DLL_NAME="%LUA_DLL%" call.c ctype.c ffi.c parser.c -%DO_LINK% /DLL /OUT:ffi.dll "%LUA_LIB%" *.obj -if exist ffi.dll.manifest^ - %DO_MT% -manifest ffi.dll.manifest -outputresource:"ffi.dll;2" - -%DO_CL% /Gd test.c /Fo"test_cdecl.obj" -%DO_CL% /Gz test.c /Fo"test_stdcall.obj" -%DO_CL% /Gr test.c /Fo"test_fastcall.obj" -%DO_LINK% /DLL /OUT:test_cdecl.dll test_cdecl.obj -%DO_LINK% /DLL /OUT:test_stdcall.dll test_stdcall.obj -%DO_LINK% /DLL /OUT:test_fastcall.dll test_fastcall.obj -if exist test_cdecl.dll.manifest^ - %DO_MT% -manifest test_cdecl.dll.manifest -outputresource:"test_cdecl.dll;2" -if exist test_stdcall.dll.manifest^ - %DO_MT% -manifest test_stdcall.dll.manifest -outputresource:"test_stdcall.dll;2" -if exist test_fastcall.dll.manifest^ - %DO_MT% -manifest test_fastcall.dll.manifest -outputresource:"test_fastcall.dll;2" - -@if "%1"=="test" "%LUA_EXE%" test.lua -@if "%1"=="test-5.2" "%LUA_EXE%" test.lua -@if "%1"=="test-release" "%LUA_EXE%" test.lua -@goto :CLEAN_OBJ - -:CLEAN -del *.dll -:CLEAN_OBJ -del *.obj *.manifest -@goto :END - -:FAIL -@echo You must open a "Visual Studio .NET Command Prompt" to run this script -:END - diff --git a/texk/web2c/luatexdir/luaffi/parser.c b/texk/web2c/luatexdir/luaffi/parser.c index dceb84550b..660f026d50 100644 --- a/texk/web2c/luatexdir/luaffi/parser.c +++ b/texk/web2c/luatexdir/luaffi/parser.c @@ -72,7 +72,7 @@ static char tok1[] = { static int next_token(lua_State* L, struct parser* P, struct token* tok) { - size_t i; + size_t i; char ch; const char* s = P->next; /* UTF8 BOM */ @@ -83,7 +83,7 @@ static int next_token(lua_State* L, struct parser* P, struct token* tok) /* consume whitespace and comments */ for (;;) { /* consume whitespace */ - while(*s == '\t' || *s == '\n' || *s == ' ' || *s == '\v' || *s == '\r') { + while((ch=*s) == '\t' || ch == '\n' || ch == ' ' || ch == '\v' || ch == '\r') { if (*s == '\n') { P->line++; } @@ -91,14 +91,14 @@ static int next_token(lua_State* L, struct parser* P, struct token* tok) } /* consume comments */ - if (*s == '/' && *(s+1) == '/') { + if ((ch=*s) == '/' && *(s+1) == '/') { s = strchr(s, '\n'); if (!s) { luaL_error(L, "non-terminated comment"); } - } else if (*s == '/' && *(s+1) == '*') { + } else if (ch == '/' && *(s+1) == '*') { s += 2; for (;;) { @@ -113,7 +113,7 @@ static int next_token(lua_State* L, struct parser* P, struct token* tok) s++; } - } else if (*s == '\0') { + } else if (ch == '\0') { tok->type = TOK_NIL; return 0; @@ -123,9 +123,9 @@ static int next_token(lua_State* L, struct parser* P, struct token* tok) } P->prev = s; - + ch=s[0]; for (i = 0; i < sizeof(tok3) / sizeof(tok3[0]); i++) { - if (s[0] == tok3[i][0] && s[1] == tok3[i][1] && s[2] == tok3[i][2]) { + if (ch == tok3[i][0] && s[1] == tok3[i][1] && s[2] == tok3[i][2]) { tok->type = (enum etoken) (TOK_3_BEGIN + 1 + i); P->next = s + 3; goto end; @@ -133,7 +133,7 @@ static int next_token(lua_State* L, struct parser* P, struct token* tok) } for (i = 0; i < sizeof(tok2) / sizeof(tok2[0]); i++) { - if (s[0] == tok2[i][0] && s[1] == tok2[i][1]) { + if (ch == tok2[i][0] && s[1] == tok2[i][1]) { tok->type = (enum etoken) (TOK_2_BEGIN + 1 + i); P->next = s + 2; goto end; @@ -141,48 +141,50 @@ static int next_token(lua_State* L, struct parser* P, struct token* tok) } for (i = 0; i < sizeof(tok1) / sizeof(tok1[0]); i++) { - if (s[0] == tok1[i]) { + if (ch == tok1[i]) { tok->type = (enum etoken) (TOK_1_BEGIN + 1 + i); P->next = s + 1; goto end; } } - if (*s == '.' || *s == '-' || ('0' <= *s && *s <= '9')) { + if (ch == '.' || ch == '-' || ('0' <= ch && ch <= '9')) { /* number */ tok->type = TOK_NUMBER; + tok->str=s; /* split out the negative case so we get the full range of bits for * unsigned (eg to support 0xFFFFFFFF where sizeof(long) == 4) */ - if (*s == '-') { + if (ch == '-') { tok->integer = strtol(s, (char**) &s, 0); } else { tok->integer = strtoul(s, (char**) &s, 0); } + tok->size=s-tok->str; - while (*s == 'u' || *s == 'U' || *s == 'l' || *s == 'L') { + while ((ch=*s) == 'u' || ch == 'U' || ch == 'l' || ch == 'L') { s++; } P->next = s; goto end; - } else if (*s == '\'' || *s == '\"') { + } else if (ch == '\'' || ch == '\"') { /* "..." or '...' */ - char quote = *s; + char quote = ch; s++; /* jump over " */ tok->type = TOK_STRING; tok->str = s; - while (*s != quote) { + while ((ch=*s) != quote) { - if (*s == '\0' || (*s == '\\' && *(s+1) == '\0')) { + if (ch == '\0' || (ch == '\\' && *(s+1) == '\0')) { return luaL_error(L, "string not finished"); } - if (*s == '\\') { + if (ch == '\\') { s++; } @@ -194,12 +196,14 @@ static int next_token(lua_State* L, struct parser* P, struct token* tok) P->next = s; goto end; - } else if (('a' <= *s && *s <= 'z') || ('A' <= *s && *s <= 'Z') || *s == '_') { + } else if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '_' || + ((signed char)ch)<0/*support for non-ascii charsets*/) { /* tokens */ tok->type = TOK_TOKEN; tok->str = s; - while (('a' <= *s && *s <= 'z') || ('A' <= *s && *s <= 'Z') || *s == '_' || ('0' <= *s && *s <= '9')) { + while (('a' <= (ch=*s) && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '_' + || ('0' <= ch && ch <= '9')|| ((signed char)ch)<0/*support for non-ascii charsets*/) { s++; } @@ -208,7 +212,7 @@ static int next_token(lua_State* L, struct parser* P, struct token* tok) goto end; } else { - return luaL_error(L, "invalid character %d", P->line); + return luaL_error(L, "invalid character %c on line %d",ch, P->line); } end: @@ -216,27 +220,45 @@ static int next_token(lua_State* L, struct parser* P, struct token* tok) return 1; } -#define require_token(L, P, tok) require_token_line(L, P, tok, __FILE__, __LINE__) +static const char* token_str(lua_State* L,struct token* tk){ + switch(tk->type){ + case TOK_TOKEN: + case TOK_STRING: + case TOK_NUMBER: + lua_pushlstring(L,tk->str,tk->size); + return lua_tostring(L,-1); + case TOK_NIL: + return ""; + default: + if(tk->typetype-TOK_3_BEGIN-1]; + } else if(tk->typetype-TOK_2_BEGIN-1]; + }else { + lua_pushlstring(L,&tok1[tk->type-TOK_1_BEGIN-1],1); + return lua_tostring(L,-1); + } + } + +} +//#define require_token(L, P, tok) require_token_line(L, P, tok, __FILE__, __LINE__) -static void require_token_line(lua_State* L, struct parser* P, struct token* tok, const char* file, int line) +static void require_token(lua_State* L, struct parser* P, struct token* tok) { if (!next_token(L, P, tok)) { - luaL_error(L, "unexpected end on line %s:%d", file, line); + luaL_error(L, "unexpected end '%s' on line %d",token_str(L,tok), P->line); } } -static void check_token(lua_State* L, struct parser* P, int type, const char* str, const char* err, ...) +static void check_token(lua_State* L, struct parser* P, int type, const char* str, const char* err) { struct token tok; if (!next_token(L, P, &tok) || tok.type != type || (tok.type == TOK_TOKEN && (tok.size != strlen(str) || memcmp(tok.str, str, tok.size) != 0))) { - va_list ap; - va_start(ap, err); - lua_pushvfstring(L, err, ap); - lua_error(L); + luaL_error(L,err,token_str(L,&tok),P->line); } } -static void put_back(struct parser* P) +static ALWAYS_INLINE void put_back(struct parser* P) { P->next = P->prev; } @@ -273,7 +295,7 @@ static int parse_enum(lua_State* L, struct parser* P, struct ctype* type) if (tok.type == TOK_CLOSE_CURLY) { break; } else if (tok.type != TOK_TOKEN) { - return luaL_error(L, "unexpected token in enum at line %d", P->line); + return luaL_error(L, "unexpected token '%s' in enum at line %d",token_str(L,&tok), P->line); } lua_pushlstring(L, tok.str, tok.size); @@ -288,7 +310,7 @@ static int parse_enum(lua_State* L, struct parser* P, struct ctype* type) value = (int) calculate_constant(L, P); require_token(L, P, &tok); } else { - return luaL_error(L, "unexpected token in enum at line %d", P->line); + return luaL_error(L, "unexpected token '%s' in enum at line %d",token_str(L,&tok), P->line); } assert(lua_gettop(L) == ct_usr + 1); @@ -309,7 +331,7 @@ static int parse_enum(lua_State* L, struct parser* P, struct ctype* type) if (tok.type == TOK_CLOSE_CURLY) { break; } else if (tok.type != TOK_COMMA) { - return luaL_error(L, "unexpected token in enum at line %d", P->line); + return luaL_error(L, "unexpected token '%s' in enum at line %d",token_str(L,&tok), P->line); } } @@ -320,38 +342,35 @@ static int parse_enum(lua_State* L, struct parser* P, struct ctype* type) return 0; } -static void calculate_member_position(lua_State* L, struct parser* P, struct ctype* ct, struct ctype* mt, int* pbit_offset, int* pbitfield_type) +static void calculate_member_position(lua_State* L, struct parser* P, struct ctype* ct, struct member_type* mt, int* pbit_offset, int* pbitfield_type) { int bit_offset = *pbit_offset; if (ct->type == UNION_TYPE) { size_t msize; - if (mt->is_variable_struct || mt->is_variable_array) { + if (mt->ct.is_variable_struct || mt->ct.is_variable_array) { luaL_error(L, "NYI: variable sized members in unions"); return; - } else if (mt->is_bitfield) { - msize = (mt->align_mask + 1); + } else if (mt->ct.is_bitfield) { + msize = (mt->ct.align_mask + 1); #ifdef _WIN32 /* MSVC has a bug where it doesn't update the alignment of * a union for bitfield members. */ - mt->align_mask = 0; + mt->ct.align_mask = 0; #endif - } else if (mt->is_array) { - msize = mt->array_size * (mt->pointers > 1 ? sizeof(void*) : mt->base_size); + } else if (mt->ct.is_array) { + msize = mt->ct.array_size * (mt->ct.pointers > 1 ? sizeof(void*) : mt->ct.base_size); } else { - msize = mt->pointers ? sizeof(void*) : mt->base_size; + msize = mt->ct.pointers ? sizeof(void*) : mt->ct.base_size; } ct->base_size = max(ct->base_size, msize); - } else if (mt->is_bitfield) { - if (mt->has_member_name && mt->bit_size == 0) { - luaL_error(L, "zero length bitfields must be unnamed on line %d", P->line); - } + } else if (mt->ct.is_bitfield) { #if defined _WIN32 /* MSVC uses a seperate storage unit for each size. This is aligned @@ -361,30 +380,30 @@ static void calculate_member_position(lua_State* L, struct parser* P, struct cty * unit, but not necesserily using it yet. */ - if (*pbitfield_type == -1 && mt->bit_size == 0) { + if (*pbitfield_type == -1 && mt->ct.bit_size == 0) { /* :0 not after a bitfield are ignored */ return; } { - int different_storage = mt->align_mask != *pbitfield_type; - int no_room_left = bit_offset + mt->bit_size > (mt->align_mask + 1) * CHAR_BIT; + int different_storage = mt->ct.align_mask != *pbitfield_type; + int no_room_left = bit_offset + mt->ct.bit_size > (mt->ct.align_mask + 1) * CHAR_BIT; - if (different_storage || no_room_left || !mt->bit_size) { + if (different_storage || no_room_left || !mt->ct.bit_size) { ct->base_size += (bit_offset + CHAR_BIT - 1) / CHAR_BIT; bit_offset = 0; if (*pbitfield_type >= 0) { ct->base_size = ALIGN_UP(ct->base_size, *pbitfield_type); } - ct->base_size = ALIGN_UP(ct->base_size, mt->align_mask); + ct->base_size = ALIGN_UP(ct->base_size, mt->ct.align_mask); } } - mt->bit_offset = bit_offset; + mt->ct.bit_offset = bit_offset; mt->offset = ct->base_size; - *pbitfield_type = mt->align_mask; - bit_offset += mt->bit_size; + *pbitfield_type = mt->ct.align_mask; + bit_offset += mt->ct.bit_size; // #elif defined OS_OSX // /* OSX doesn't use containers and bitfields are not aligned. So @@ -413,26 +432,29 @@ static void calculate_member_position(lua_State* L, struct parser* P, struct cty * :0 forces an alignment based off the type used with the :0 */ - int bits_used = (ct->base_size - ALIGN_DOWN(ct->base_size, mt->align_mask)) * CHAR_BIT + bit_offset; - int need_to_realign = bits_used + mt->bit_size > mt->base_size * CHAR_BIT; + int bits_used = (ct->base_size - ALIGN_DOWN(ct->base_size, mt->ct.align_mask)) * CHAR_BIT + bit_offset; + int need_to_realign = bits_used + mt->ct.bit_size > mt->ct.base_size * CHAR_BIT; - if (!mt->is_packed && (!mt->bit_size || need_to_realign)) { + if (!mt->ct.is_packed && (!mt->ct.bit_size || need_to_realign)) { ct->base_size += (bit_offset + CHAR_BIT - 1) / CHAR_BIT; - ct->base_size = ALIGN_UP(ct->base_size, mt->align_mask); + ct->base_size = ALIGN_UP(ct->base_size, mt->ct.align_mask); bit_offset = 0; } - mt->bit_offset = bit_offset; + mt->ct.bit_offset = bit_offset; mt->offset = ct->base_size; - bit_offset += mt->bit_size; + bit_offset += mt->ct.bit_size; ct->base_size += bit_offset / CHAR_BIT; bit_offset = bit_offset % CHAR_BIT; +//arm ignored it +#if !defined(ARCH_ARM64) &&!defined(ARCH_ARM) /* unnamed bitfields don't update the struct alignment */ if (!mt->has_member_name) { - mt->align_mask = 0; + mt->ct.align_mask = 0; } +#endif #else #error #endif @@ -448,42 +470,42 @@ static void calculate_member_position(lua_State* L, struct parser* P, struct cty *pbitfield_type = -1; - ct->base_size = ALIGN_UP(ct->base_size, mt->align_mask); + ct->base_size = ALIGN_UP(ct->base_size, mt->ct.align_mask); mt->offset = ct->base_size; - if (mt->is_variable_array) { + if (mt->ct.is_variable_array) { ct->is_variable_struct = 1; - ct->variable_increment = mt->pointers > 1 ? sizeof(void*) : mt->base_size; + ct->variable_increment = mt->ct.pointers > 1 ? sizeof(void*) : mt->ct.base_size; - } else if (mt->is_variable_struct) { - assert(!mt->variable_size_known && !mt->is_array && !mt->pointers); - ct->base_size += mt->base_size; + } else if (mt->ct.is_variable_struct) { + assert(!mt->ct.variable_size_known && !mt->ct.is_array && !mt->ct.pointers); + ct->base_size += mt->ct.base_size; ct->is_variable_struct = 1; - ct->variable_increment = mt->variable_increment; + ct->variable_increment = mt->ct.variable_increment; - } else if (mt->is_array) { - ct->base_size += mt->array_size * (mt->pointers > 1 ? sizeof(void*) : mt->base_size); + } else if (mt->ct.is_array) { + ct->base_size += mt->ct.array_size * (mt->ct.pointers > 1 ? sizeof(void*) : mt->ct.base_size); } else { - ct->base_size += mt->pointers ? sizeof(void*) : mt->base_size; + ct->base_size += mt->ct.pointers ? sizeof(void*) : mt->ct.base_size; } } /* increase the outer struct/union alignment if needed */ - if (mt->align_mask > (int) ct->align_mask) { - ct->align_mask = mt->align_mask; + if (mt->ct.align_mask > (int) ct->align_mask) { + ct->align_mask = mt->ct.align_mask; } - if (mt->has_bitfield || mt->is_bitfield) { + if (mt->ct.has_bitfield || mt->ct.is_bitfield) { ct->has_bitfield = 1; } *pbit_offset = bit_offset; } -static int copy_submembers(lua_State* L, int to_usr, int from_usr, const struct ctype* ft, int* midx) +static int copy_submembers(lua_State* L, int to_usr, int from_usr, const struct member_type* ft, int* midx) { - struct ctype ct; + struct member_type ct; int i, sublen; from_usr = lua_absindex(L, from_usr); @@ -494,11 +516,11 @@ static int copy_submembers(lua_State* L, int to_usr, int from_usr, const struct for (i = 1; i <= sublen; i++) { lua_rawgeti(L, from_usr, i); - ct = *(const struct ctype*) lua_touserdata(L, -1); + ct = *(const struct member_type*) lua_touserdata(L, -1); ct.offset += ft->offset; lua_getuservalue(L, -1); - push_ctype(L, -1, &ct); + push_member_type(L, -1, &ct); lua_rawseti(L, to_usr, (*midx)++); lua_pop(L, 2); /* ctype, user value */ @@ -508,13 +530,13 @@ static int copy_submembers(lua_State* L, int to_usr, int from_usr, const struct lua_pushnil(L); while (lua_next(L, from_usr)) { if (lua_type(L, -2) == LUA_TSTRING) { - struct ctype ct = *(const struct ctype*) lua_touserdata(L, -1); + ct = *(const struct member_type*) lua_touserdata(L, -1); ct.offset += ft->offset; lua_getuservalue(L, -1); /* uservalue[sub_mname] = new_sub_mtype */ lua_pushvalue(L, -3); - push_ctype(L, -2, &ct); + push_member_type(L, -2, &ct); lua_rawset(L, to_usr); lua_pop(L, 1); /* remove submember user value */ @@ -525,12 +547,12 @@ static int copy_submembers(lua_State* L, int to_usr, int from_usr, const struct return 0; } -static int add_member(lua_State* L, int ct_usr, int mname, int mbr_usr, const struct ctype* mt, int* midx) +static int add_member(lua_State* L, int ct_usr, int mname, int mbr_usr, const struct member_type* mt, int* midx) { ct_usr = lua_absindex(L, ct_usr); mname = lua_absindex(L, mname); - push_ctype(L, mbr_usr, mt); + push_member_type(L, mbr_usr, mt); /* usrvalue[mbr index] = pushed mtype */ lua_pushvalue(L, -1); @@ -589,7 +611,7 @@ static int parse_struct(lua_State* L, struct parser* P, int tmp_usr, const struc for (;;) { struct token mname; - struct ctype mt = mbase; + struct member_type mt={mbase}; memset(&mname, 0, sizeof(mname)); @@ -598,14 +620,14 @@ static int parse_struct(lua_State* L, struct parser* P, int tmp_usr, const struc } assert(lua_gettop(L) == top + 1); - parse_argument(L, P, -1, &mt, &mname, NULL); + parse_argument(L, P, -1, &mt.ct, &mname, NULL, 0); assert(lua_gettop(L) == top + 2); - if (!mt.is_defined && (mt.pointers - mt.is_array) == 0) { + if (!mt.ct.is_defined && (mt.ct.pointers - mt.ct.is_array) == 0) { return luaL_error(L, "member type is undefined on line %d", P->line); } - if (mt.type == VOID_TYPE && (mt.pointers - mt.is_array) == 0) { + if (mt.ct.type == VOID_TYPE && (mt.ct.pointers - mt.ct.is_array) == 0) { return luaL_error(L, "member type can not be void on line %d", P->line); } @@ -622,7 +644,7 @@ static int parse_struct(lua_State* L, struct parser* P, int tmp_usr, const struc if (tok.type == TOK_SEMICOLON) { break; } else if (tok.type != TOK_COMMA) { - luaL_error(L, "unexpected token in struct definition on line %d", P->line); + luaL_error(L, "unexpected token '%s' in struct definition on line %d", token_str(L,&tok), P->line); } } @@ -646,11 +668,11 @@ static int calculate_struct_offsets(lua_State* L, struct parser* P, int ct_usr, tmp_usr = lua_absindex(L, tmp_usr); for (i = 1; i <= sz; i++) { - struct ctype mt; + struct member_type mt; /* get the member type */ lua_rawgeti(L, tmp_usr, i); - mt = *(const struct ctype*) lua_touserdata(L, -1); + mt = *(const struct member_type*) lua_touserdata(L, -1); /* get the member user table */ lua_getuservalue(L, -1); @@ -665,7 +687,7 @@ static int calculate_struct_offsets(lua_State* L, struct parser* P, int ct_usr, assert(!lua_isnil(L, -1)); add_member(L, ct_usr, -1, -2, &mt, &midx); - } else if (mt.type == STRUCT_TYPE || mt.type == UNION_TYPE) { + } else if (mt.ct.type == STRUCT_TYPE || mt.ct.type == UNION_TYPE) { /* With an unnamed member we copy all of the submembers into our * usr value adjusting the offset as necessary. Note ctypes are * immutable so need to push a new ctype to update the offset. @@ -686,6 +708,7 @@ static int calculate_struct_offsets(lua_State* L, struct parser* P, int ct_usr, /* only void is allowed 0 size */ if (ct->base_size == 0) { ct->base_size = 1; + ct->is_empty=1; } ct->base_size = ALIGN_UP(ct->base_size, ct->align_mask); @@ -847,22 +870,24 @@ static int parse_type_name(lua_State* L, struct parser* P) { struct token tok; int flags = 0; + const char* st=P->next; enum { - UNSIGNED = 0x01, - SIGNED = 0x02, - LONG = 0x04, - SHORT = 0x08, - INT = 0x10, - CHAR = 0x20, - LONG_LONG = 0x40, - INT8 = 0x80, - INT16 = 0x100, - INT32 = 0x200, - INT64 = 0x400, - DOUBLE = 0x800, - FLOAT = 0x1000, - COMPLEX = 0x2000, + REGISTER= 1, + UNSIGNED = 1<<1, + SIGNED = 1<<2, + COMPLEX = 1<<3, + LONG = 1<<4, + LONG_LONG = 1<<5, + SHORT = 1<<6, + INT = 1<<7, + CHAR = 1<<8, + INT8 = 1<<9, + INT16 = 1<<10, + INT32 = 1<<11, + INT64 = 1<<12, + DOUBLE = 1<<13, + FLOAT = 1<<14, }; require_token(L, P, &tok); @@ -874,44 +899,70 @@ static int parse_type_name(lua_State* L, struct parser* P) if (tok.type != TOK_TOKEN) { break; } else if (IS_LITERAL(tok, "unsigned")) { + if(flags&(SIGNED|UNSIGNED)) goto invalid_type; flags |= UNSIGNED; } else if (IS_LITERAL(tok, "signed")) { + if(flags&(SIGNED|UNSIGNED)) goto invalid_type; flags |= SIGNED; } else if (IS_LITERAL(tok, "short")) { + if(flags&~(SIGNED|UNSIGNED|INT|REGISTER)) goto invalid_type; flags |= SHORT; } else if (IS_LITERAL(tok, "char")) { + if(flags&~(SIGNED|UNSIGNED|REGISTER)) goto invalid_type; flags |= CHAR; } else if (IS_LITERAL(tok, "long")) { - flags |= (flags & LONG) ? LONG_LONG : LONG; + if(flags&~(SIGNED|UNSIGNED|REGISTER|LONG|DOUBLE|INT)) goto invalid_type; + if(flags & LONG) { + flags &=~LONG; + flags |=LONG_LONG; + } else flags |= LONG; } else if (IS_LITERAL(tok, "int")) { + if(flags&~(SIGNED|UNSIGNED|REGISTER|SHORT|LONG|LONG_LONG)) goto invalid_type; flags |= INT; } else if (IS_LITERAL(tok, "__int8")) { + if(flags&~(SIGNED|UNSIGNED|REGISTER)) goto invalid_type; flags |= INT8; } else if (IS_LITERAL(tok, "__int16")) { + if(flags&~(SIGNED|UNSIGNED|REGISTER)) goto invalid_type; flags |= INT16; } else if (IS_LITERAL(tok, "__int32")) { + if(flags&~(SIGNED|UNSIGNED|REGISTER)) goto invalid_type; flags |= INT32; } else if (IS_LITERAL(tok, "__int64")) { + if(flags&~(SIGNED|UNSIGNED|REGISTER)) goto invalid_type; flags |= INT64; } else if (IS_LITERAL(tok, "double")) { + if(flags&~(COMPLEX|REGISTER|LONG)) goto invalid_type; flags |= DOUBLE; } else if (IS_LITERAL(tok, "float")) { + if(flags&~(COMPLEX|REGISTER)) goto invalid_type; flags |= FLOAT; } else if (IS_LITERAL(tok, "complex") || IS_LITERAL(tok, "_Complex")) { + if(flags&~(FLOAT|DOUBLE|REGISTER)) goto invalid_type; flags |= COMPLEX; } else if (IS_LITERAL(tok, "register")) { - /* ignore */ + if(flags®ISTER) goto invalid_type; + flags |=REGISTER; } else { break; + invalid_type: + { + lua_pushliteral(L,"Invalid type: "); + lua_pushlstring(L,st,P->next-st); + lua_concat(L,2); + luaL_error(L,lua_tostring(L,-1)); + }; + } if (!next_token(L, P, &tok)) { - break; + goto handle_register; } } - + if(flags) put_back(P); + handle_register: if (flags) { - put_back(P); + flags&=~REGISTER;//ignored; } if (flags & CHAR) { @@ -940,16 +991,24 @@ static int parse_type_name(lua_State* L, struct parser* P) } else { lua_pushliteral(L, "complex double"); } +#define CHECK_SIGN_FLOAT()\ + if((flags&SIGNED)||(flags&UNSIGNED)){\ + luaL_error(L,"Error: '%s' cannot be signed or unsigned",lua_tostring(L,-1));\ + } + CHECK_SIGN_FLOAT(); } else if (flags & DOUBLE) { + if (flags & LONG) { lua_pushliteral(L, "long double"); } else { lua_pushliteral(L, "double"); } + CHECK_SIGN_FLOAT(); } else if (flags & FLOAT) { lua_pushliteral(L, "float"); + CHECK_SIGN_FLOAT(); } else if (flags & SHORT) { #define SHORT_TYPE(u) (sizeof(short) == sizeof(int64_t) ? u "int64_t" : sizeof(short) == sizeof(int32_t) ? u "int32_t" : u "int16_t") @@ -997,7 +1056,7 @@ static int parse_attribute(lua_State* L, struct parser* P, struct token* tok, st return 0; } else if (asmname && (IS_LITERAL(*tok, "__asm__") || IS_LITERAL(*tok, "__asm"))) { - check_token(L, P, TOK_OPEN_PAREN, NULL, "unexpected token after __asm__ on line %d", P->line); + check_token(L, P, TOK_OPEN_PAREN, NULL, "unexpected token '%s' after __asm__ on line %d"); *asmname = *P; require_token(L, P, tok); @@ -1006,13 +1065,13 @@ static int parse_attribute(lua_State* L, struct parser* P, struct token* tok, st } if (tok->type != TOK_CLOSE_PAREN) { - luaL_error(L, "unexpected token after __asm__ on line %d", P->line); + luaL_error(L, "unexpected token '%s' after __asm__ on line %d",token_str(L,tok), P->line); } return 1; } else if (IS_LITERAL(*tok, "__attribute__") || IS_LITERAL(*tok, "__declspec")) { int parens = 1; - check_token(L, P, TOK_OPEN_PAREN, NULL, "expected parenthesis after __attribute__ or __declspec on line %d", P->line); + check_token(L, P, TOK_OPEN_PAREN, NULL, "expected parenthesis but got '%s' after __attribute__ or __declspec on line %d"); for (;;) { require_token(L, P, tok); @@ -1032,7 +1091,9 @@ static int parse_attribute(lua_State* L, struct parser* P, struct token* tok, st switch (tok->type) { case TOK_CLOSE_PAREN: - align = ALIGNED_DEFAULT; + //__attribute__((algined)) indicates max alignment + //it only works for gcc + align = ALIGNED_MAX; put_back(P); break; @@ -1053,7 +1114,7 @@ static int parse_attribute(lua_State* L, struct parser* P, struct token* tok, st luaL_error(L, "unsupported align size on line %d", P->line); } - check_token(L, P, TOK_CLOSE_PAREN, NULL, "expected align(#) on line %d", P->line); + check_token(L, P, TOK_CLOSE_PAREN, NULL, "expected align(#) but got '%s' on line %d"); break; default: @@ -1069,11 +1130,11 @@ static int parse_attribute(lua_State* L, struct parser* P, struct token* tok, st } else if (IS_LITERAL(*tok, "mode") || IS_LITERAL(*tok, "__mode__")) { - check_token(L, P, TOK_OPEN_PAREN, NULL, "expected mode(MODE) on line %d", P->line); + check_token(L, P, TOK_OPEN_PAREN, NULL, "expected mode(MODE) but got '%s' on line %d"); require_token(L, P, tok); if (tok->type != TOK_TOKEN) { - luaL_error(L, "expected mode(MODE) on line %d", P->line); + luaL_error(L, "expected mode(MODE) but got %s on line %d"); } if (ct->type == FLOAT_TYPE || ct->type == DOUBLE_TYPE) { @@ -1122,7 +1183,7 @@ static int parse_attribute(lua_State* L, struct parser* P, struct token* tok, st ct->align_mask = ALIGNOF(a32); } else if (IS_LITERAL(*tok, "DI") || IS_LITERAL(*tok, "__DI__") -#if defined ARCH_X64 || defined ARCH_PPC64 +#if defined ARCH_X64 || defined ARCH_PPC64 ||defined(ARCH_ARM64) || IS_LITERAL(*tok, "word") || IS_LITERAL(*tok, "__word__") || IS_LITERAL(*tok, "pointer") || IS_LITERAL(*tok, "__pointer__") #endif @@ -1136,7 +1197,7 @@ static int parse_attribute(lua_State* L, struct parser* P, struct token* tok, st } } - check_token(L, P, TOK_CLOSE_PAREN, NULL, "expected mode(MODE) on line %d", P->line); + check_token(L, P, TOK_CLOSE_PAREN, NULL, "expected mode(MODE) but got '%s' on line %d"); } else if (IS_LITERAL(*tok, "cdecl") || IS_LITERAL(*tok, "__cdecl__")) { ct->calling_convention = C_CALL; @@ -1496,7 +1557,7 @@ static void parse_function_arguments(lua_State* L, struct parser* P, int ct_usr, if (args) { if (tok.type != TOK_COMMA) { - luaL_error(L, "unexpected token in function argument %d on line %d", args, P->line); + luaL_error(L, "unexpected token '%s' in function argument %d on line %d",token_str(L,&tok), args, P->line); } require_token(L, P, &tok); @@ -1504,7 +1565,7 @@ static void parse_function_arguments(lua_State* L, struct parser* P, int ct_usr, if (tok.type == TOK_VA_ARG) { ct->has_var_arg = true; - check_token(L, P, TOK_CLOSE_PAREN, "", "unexpected token after ... in function on line %d", P->line); + check_token(L, P, TOK_CLOSE_PAREN, "", "unexpected token '%s' after ... in function on line %d"); break; } else if (tok.type == TOK_TOKEN) { @@ -1512,7 +1573,7 @@ static void parse_function_arguments(lua_State* L, struct parser* P, int ct_usr, put_back(P); parse_type(L, P, &at); - parse_argument(L, P, -1, &at, NULL, NULL); + parse_argument(L, P, -1, &at, NULL, NULL, 1); assert(lua_gettop(L) == top + 2); @@ -1525,7 +1586,7 @@ static void parse_function_arguments(lua_State* L, struct parser* P, int ct_usr, luaL_error(L, "can't have argument of type void on line %d", P->line); } - check_token(L, P, TOK_CLOSE_PAREN, "", "unexpected void in function on line %d", P->line); + check_token(L, P, TOK_CLOSE_PAREN, "", "unexpected token '%s' after void in function on line %d"); lua_pop(L, 2); break; } @@ -1562,7 +1623,9 @@ static int max_bitfield_size(int type) } } -static struct ctype* parse_argument2(lua_State* L, struct parser* P, int ct_usr, struct ctype* ct, struct token* name, struct parser* asmname); +static struct ctype * +parse_argument2(lua_State *L, struct parser *P, int ct_usr, struct ctype *ct, struct token *name, + struct parser *asmname, bool ignore_name); /* parses from after the first ( in a function declaration or function pointer * can be one of: @@ -1591,39 +1654,43 @@ static struct ctype* parse_function(lua_State* L, struct parser* P, int ct_usr, ct->type = FUNCTION_TYPE; ct->is_defined = 1; - if (name->type == TOK_NIL) { - for (;;) { - require_token(L, P, &tok); - - if (tok.type == TOK_STAR) { - - if (ct->type == FUNCTION_TYPE) { - ct->type = FUNCTION_PTR_TYPE; - } else if (ct->pointers == POINTER_MAX) { - luaL_error(L, "maximum number of pointer derefs reached - use a struct to break up the pointers on line %d", P->line); - } else { - ct->pointers++; - ct->const_mask <<= 1; - } + for (;;) { + require_token(L, P, &tok); - } else if (parse_attribute(L, P, &tok, ct, asmname)) { - /* parse_attribute sets the appropriate fields */ + if (tok.type == TOK_STAR) { + if (ct->type == FUNCTION_TYPE) { + ct->type = FUNCTION_PTR_TYPE; + } else if (ct->pointers == POINTER_MAX) { + luaL_error(L, + "maximum number of pointer derefs reached - use a struct to break up the pointers on line %d", + P->line); } else { - /* call parse_argument to handle the inner contents - * e.g. the <> in "void (* <>) (...)". Note that the - * inner contents can itself be a function, a function - * ptr, array, etc (e.g. "void (*signal(int sig, void - * (*func)(int)))(int)" ). - */ - put_back(P); - ct = parse_argument2(L, P, ct_usr, ct, name, asmname); - break; + ct->pointers++; + ct->const_mask <<= 1; } - } - check_token(L, P, TOK_CLOSE_PAREN, NULL, "unexpected token in function on line %d", P->line); - check_token(L, P, TOK_OPEN_PAREN, NULL, "unexpected token in function on line %d", P->line); + } else if (parse_attribute(L, P, &tok, ct, asmname)) { + /* parse_attribute sets the appropriate fields */ + + } else if (ct->type == FUNCTION_PTR_TYPE) { + /* call parse_argument to handle the inner contents + * e.g. the <> in "void (* <>) (...)". Note that the + * inner contents can itself be a function, a function + * ptr, array, etc (e.g. "void (*signal(int sig, void + * (*func)(int)))(int)" ). + */ + put_back(P); + ct = parse_argument2(L, P, ct_usr, ct, name, asmname, 1); + check_token(L, P, TOK_CLOSE_PAREN, NULL, "unexpected token '%s' in function on line %d"); + check_token(L, P, TOK_OPEN_PAREN, NULL, "unexpected token '%s' in function on line %d"); + break; + } else { + //when the type is not a function ptr type like the inner '()' in + //void (* ())(), directly parse its arguments. + put_back(P); + break; + } } parse_function_arguments(L, P, ct_usr, ct); @@ -1641,7 +1708,9 @@ static struct ctype* parse_function(lua_State* L, struct parser* P, int ct_usr, return ret; } -static struct ctype* parse_argument2(lua_State* L, struct parser* P, int ct_usr, struct ctype* ct, struct token* name, struct parser* asmname) +static struct ctype * +parse_argument2(lua_State *L, struct parser *P, int ct_usr, struct ctype *ct, struct token *name, + struct parser *asmname, bool ignore_name) { struct token tok; int top = lua_gettop(L); @@ -1675,6 +1744,9 @@ static struct ctype* parse_argument2(lua_State* L, struct parser* P, int ct_usr, /* parse attribute has filled out appropriate fields in type */ } else if (tok.type == TOK_OPEN_PAREN) { + if(ft_usr!=0){ + luaL_error(L,"duplicated '(' in function on line %d",P->line); + } ct = parse_function(L, P, ct_usr, ct, name, asmname); ft_usr = lua_gettop(L); @@ -1699,7 +1771,7 @@ static struct ctype* parse_argument2(lua_State* L, struct parser* P, int ct_usr, if (tok.type == TOK_QUESTION) { ct->is_variable_array = 1; ct->variable_increment = (ct->pointers > 1) ? sizeof(void*) : ct->base_size; - check_token(L, P, TOK_CLOSE_SQUARE, "", "invalid character in array on line %d", P->line); + check_token(L, P, TOK_CLOSE_SQUARE, "", "invalid character '%s' in array on line %d"); } else if (tok.type == TOK_CLOSE_SQUARE) { ct->array_size = 0; @@ -1707,7 +1779,7 @@ static struct ctype* parse_argument2(lua_State* L, struct parser* P, int ct_usr, } else if (tok.type == TOK_TOKEN && IS_RESTRICT(tok)) { /* odd gcc extension foo[__restrict] for arguments */ ct->array_size = 0; - check_token(L, P, TOK_CLOSE_SQUARE, "", "invalid character in array on line %d", P->line); + check_token(L, P, TOK_CLOSE_SQUARE, "", "invalid character '%s' in array on line %d"); } else { int64_t asize; @@ -1717,7 +1789,7 @@ static struct ctype* parse_argument2(lua_State* L, struct parser* P, int ct_usr, luaL_error(L, "array size can not be negative on line %d", P->line); } ct->array_size = (size_t) asize; - check_token(L, P, TOK_CLOSE_SQUARE, "", "invalid character in array on line %d", P->line); + check_token(L, P, TOK_CLOSE_SQUARE, "", "invalid character '%s' in array on line %d"); } } else if (tok.type == TOK_COLON) { @@ -1727,6 +1799,10 @@ static struct ctype* parse_argument2(lua_State* L, struct parser* P, int ct_usr, luaL_error(L, "invalid bitfield on line %d", P->line); } + if (name->size && bsize == 0) { + luaL_error(L, "zero length bitfields must be unnamed on line %d", P->line); + } + ct->is_bitfield = 1; ct->bit_size = (unsigned) bsize; @@ -1741,8 +1817,10 @@ static struct ctype* parse_argument2(lua_State* L, struct parser* P, int ct_usr, } else if (IS_VOLATILE(tok) || IS_RESTRICT(tok)) { /* ignored for now */ - } else { + } else if(name){ *name = tok; + } else if(!ignore_name){ + luaL_error(L,"argument name '%s' not expected on line %d",token_str(L,&tok),P->line); } } @@ -1839,13 +1917,14 @@ static void find_canonical_usr(lua_State* L, int ct_usr, const struct ctype *ct) * * pushes the updated user value on the top of the stack */ -void parse_argument(lua_State* L, struct parser* P, int ct_usr, struct ctype* ct, struct token* pname, struct parser* asmname) +void parse_argument(lua_State *L, struct parser *P, int ct_usr, struct ctype *ct, + struct token *pname, + struct parser *asmname, bool ignore_name) { - struct token tok, name; + struct token tok; int top = lua_gettop(L); - memset(&name, 0, sizeof(name)); - parse_argument2(L, P, ct_usr, ct, &name, asmname); + parse_argument2(L, P, ct_usr, ct, pname, asmname, ignore_name); for (;;) { if (!next_token(L, P, &tok)) { @@ -1864,9 +1943,6 @@ void parse_argument(lua_State* L, struct parser* P, int ct_usr, struct ctype* ct find_canonical_usr(L, -1, ct); - if (pname) { - *pname = name; - } } static void parse_typedef(lua_State* L, struct parser* P) @@ -1884,7 +1960,7 @@ static void parse_typedef(lua_State* L, struct parser* P) memset(&name, 0, sizeof(name)); assert(lua_gettop(L) == top + 1); - parse_argument(L, P, -1, &arg_type, &name, NULL); + parse_argument(L, P, -1, &arg_type, &name, NULL, 0); assert(lua_gettop(L) == top + 2); if (!name.size) { @@ -2014,7 +2090,7 @@ static void parse_constant_assignemnt(lua_State* L, { int64_t val = calculate_constant(L, P); - check_token(L, P, TOK_SEMICOLON, "", "expected ; after constant definition on line %d", P->line); + check_token(L, P, TOK_SEMICOLON, "", "expected ';' but got '%s' after constant definition on line %d"); push_upval(L, &constants_key); lua_pushlstring(L, name->str, name->size); @@ -2063,25 +2139,25 @@ static int parse_root(lua_State* L, struct parser* P) } else if (tok.type == TOK_POUND) { - check_token(L, P, TOK_TOKEN, "pragma", "unexpected pre processor directive on line %d", P->line); - check_token(L, P, TOK_TOKEN, "pack", "unexpected pre processor directive on line %d", P->line); - check_token(L, P, TOK_OPEN_PAREN, "", "invalid pack directive on line %d", P->line); + check_token(L, P, TOK_TOKEN, "pragma", "unexpected pre processor directive '%s' on line %d"); + check_token(L, P, TOK_TOKEN, "pack", "unexpected pre processor directive '%s' on line %d"); + check_token(L, P, TOK_OPEN_PAREN, "", "invalid pack directive '%s' on line %d"); require_token(L, P, &tok); if (tok.type == TOK_NUMBER) { if (tok.integer != 1 && tok.integer != 2 && tok.integer != 4 && tok.integer != 8 && tok.integer != 16) { - luaL_error(L, "pack directive with invalid pack size on line %d", P->line); + luaL_error(L, "pack directive with invalid pack size %d on line %d",tok.integer, P->line); } P->align_mask = (unsigned) (tok.integer - 1); - check_token(L, P, TOK_CLOSE_PAREN, "", "invalid pack directive on line %d", P->line); + check_token(L, P, TOK_CLOSE_PAREN, "", "invalid pack directive '%s' on line %d"); } else if (tok.type == TOK_TOKEN && IS_LITERAL(tok, "push")) { int line = P->line; unsigned previous_alignment = P->align_mask; - check_token(L, P, TOK_CLOSE_PAREN, "", "invalid pack directive on line %d", P->line); + check_token(L, P, TOK_CLOSE_PAREN, "", "invalid pack directive '%s' on line %d"); if (parse_root(L, P) != PRAGMA_POP) { luaL_error(L, "reached end of string without a pragma pop to match the push on line %d", line); @@ -2090,16 +2166,16 @@ static int parse_root(lua_State* L, struct parser* P) P->align_mask = previous_alignment; } else if (tok.type == TOK_TOKEN && IS_LITERAL(tok, "pop")) { - check_token(L, P, TOK_CLOSE_PAREN, "", "invalid pack directive on line %d", P->line); + check_token(L, P, TOK_CLOSE_PAREN, "", "invalid pack directive '%s' on line %d"); return PRAGMA_POP; } else { - luaL_error(L, "invalid pack directive on line %d", P->line); + luaL_error(L, "invalid pack directive %s on line %d",token_str(L,&tok), P->line); } } else if (tok.type != TOK_TOKEN) { - return luaL_error(L, "unexpected character on line %d", P->line); + return luaL_error(L, "unexpected character '%s' on line %d",token_str(L,&tok), P->line); } else if (IS_LITERAL(tok, "__extension__")) { /* ignore */ @@ -2125,7 +2201,7 @@ static int parse_root(lua_State* L, struct parser* P) parse_type(L, P, &type); for (;;) { - parse_argument(L, P, -1, &type, &name, &asmname); + parse_argument(L, P, -1, &type, &name, &asmname, 0); if (name.size) { /* global/function declaration */ @@ -2257,7 +2333,7 @@ static int try_cast(lua_State* L) memset(&name, 0, sizeof(name)); parse_type(L, P, &ct); - parse_argument(L, P, -1, &ct, &name, NULL); + parse_argument(L, P, -1, &ct, &name, NULL, 0); require_token(L, P, &tok); if (tok.type != TOK_CLOSE_PAREN || name.size) { @@ -2291,8 +2367,7 @@ static int64_t calculate_constant1(lua_State* L, struct parser* P, struct token* lua_remove(L, -2); /* constants table */ if (!lua_isnumber(L, -1)) { - lua_pushlstring(L, tok->str, tok->size); - luaL_error(L, "use of undefined constant %s on line %d", lua_tostring(L, -1), P->line); + luaL_error(L, "use of undefined constant %s on line %d", token_str(L,tok), P->line); } ret = (int64_t) lua_tonumber(L, -1); @@ -2331,7 +2406,7 @@ static int64_t calculate_constant1(lua_State* L, struct parser* P, struct token* return ret; } else { - return luaL_error(L, "unexpected token whilst parsing constant at line %d", P->line); + return luaL_error(L, "unexpected token '%s' whilst parsing constant at line %d",token_str(L,tok), P->line); } } @@ -2369,7 +2444,7 @@ static int64_t calculate_constant2(lua_State* L, struct parser* P, struct token* } parse_type(L, P, &type); - parse_argument(L, P, -1, &type, NULL, NULL); + parse_argument(L, P, -1, &type, NULL, NULL, 0); lua_pop(L, 2); require_token(L, P, tok); diff --git a/texk/web2c/luatexdir/luaffi/test.c b/texk/web2c/luatexdir/luaffi/test.c index 20f5d136f2..31901f826d 100644 --- a/texk/web2c/luatexdir/luaffi/test.c +++ b/texk/web2c/luatexdir/luaffi/test.c @@ -19,8 +19,22 @@ #include #endif +#if __STDC_VERSION__+0 >= 199901L #include + #define HAVE_COMPLEX +typedef double _Complex double_complex; +typedef float _Complex float_complex; +#else +typedef struct{ + float re; + float im; +} float_complex; +typedef struct{ + double re; + double im; +} double_complex; +#endif #ifdef __cplusplus # define EXTERN_C extern "C" @@ -90,8 +104,11 @@ ADD(uint64_t, add_u64) ADD(double, add_d) ADD(float, add_f) #ifdef HAVE_COMPLEX -ADD(double complex, add_dc) -ADD(float complex, add_fc) +ADD(double_complex, add_dc) +ADD(float_complex, add_fc) +#else +EXPORT double_complex add_dc(double_complex a, double_complex b) { return (double_complex){a.re + b.re,a.im+b.im}; } +EXPORT float_complex add_fc(float_complex a, float_complex b) { return (float_complex){a.re + b.re,a.im+b.im}; } #endif EXPORT enum e8 inc_e8(enum e8 v); @@ -127,12 +144,26 @@ PRINT(enum e8, print_e8, "d") PRINT(enum e16, print_e16, "d") PRINT(enum e32, print_e32, "d") -#ifdef HAVE_COMPLEX -EXPORT int print_dc(char* buf, double complex val); -EXPORT int print_fc(char* buf, float complex val); -int print_dc(char* buf, double complex val) {return sprintf(buf, "%g+%gi", creal(val), cimag(val));} -int print_fc(char* buf, float complex val) {return sprintf(buf, "%g+%gi", creal(val), cimag(val));} -#endif + +EXPORT int print_dc(char* buf, double_complex val); +EXPORT int print_fc(char* buf, float_complex val); +/* +static double creal(double_complex a){ + return *((double*)&a); +} +static double cimag(double_complex a){ + return ((double*)&a)[1]; +} +static float crealf(float_complex a){ + return *((float *)&a); +} +static float cimagf(float_complex a){ + return ((float*)&a)[1]; +} +*/ +int print_dc(char* buf, double_complex val) {return sprintf(buf, "%g+%gi", creal(val), cimag(val));} +int print_fc(char* buf, float_complex val) {return sprintf(buf, "%g+%gi", crealf(val), cimagf(val));} + EXPORT int print_b(char* buf, _Bool val); EXPORT int print_b2(char* buf, _Bool val); @@ -140,7 +171,7 @@ int print_b(char* buf, _Bool val) {return sprintf(buf, "%s", val ? "true" : "fal int print_b2(char* buf, _Bool val) {return sprintf(buf, "%s", val ? "true" : "false");} EXPORT bool (*ret_fp(bool (*val)(bool)))(bool); -bool (*ret_fp(bool (*val)(bool)))(bool) +bool (*ret_fp(bool (*val)(bool)))(bool b) {return val;} #define OFFSETOF(STRUCT, MEMBER) ((int) ((char*) &STRUCT.MEMBER - (char*) &S - 1)) @@ -160,13 +191,10 @@ bool (*ret_fp(bool (*val)(bool)))(bool) return print_##SUFFIX(buf+off, p->v); \ } -#ifdef HAVE_COMPLEX + #define COMPLEX_ALIGN(ALIGNMENT, ATTR) \ - ALIGN_UP(ATTR(double complex), ALIGNMENT, dc) \ - ALIGN_UP(ATTR(float complex), ALIGNMENT, fc) -#else -#define COMPLEX_ALIGN(ALIGNMENT, ATTR) -#endif + ALIGN_UP(ATTR(double_complex), ALIGNMENT, dc) \ + ALIGN_UP(ATTR(float_complex), ALIGNMENT, fc) /* MSVC doesn't support __declspec(aligned(#)) on enums see C4329 */ #define ENUM_ALIGN2(ALIGNMENT, ATTR) \ @@ -230,8 +258,11 @@ ALIGN_NO_ATTR(16) #define ATTR4(TYPE) ATTR_(TYPE, 4) #define ATTR8(TYPE) ATTR_(TYPE, 8) #define ATTR16(TYPE) ATTR_(TYPE, 16) - +#if defined __clang__ && (defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm) +#define ATTR_DEF(TYPE) TYPE v __attribute__((aligned(__BIGGEST_ALIGNMENT__))) +#else #define ATTR_DEF(TYPE) TYPE v __attribute__((aligned)) +#endif ALIGN2(attr_1, ATTR1) ALIGN2(attr_2, ATTR2) @@ -588,10 +619,10 @@ CALL(_Bool, b) CALL(enum e8, e8) CALL(enum e16, e16) CALL(enum e32, e32) -#ifdef HAVE_COMPLEX -CALL(double complex, dc) -CALL(float complex, fc) -#endif + +CALL(double_complex, dc) +CALL(float_complex, fc) + struct fptr { #ifdef _MSC_VER @@ -618,10 +649,9 @@ EXPORT uint32_t g_u32; EXPORT uint64_t g_u64; EXPORT float g_f; EXPORT double g_d; -#ifdef HAVE_COMPLEX -EXPORT double complex g_dc; -EXPORT float complex g_fc; -#endif +EXPORT double_complex g_dc; +EXPORT float_complex g_fc; + EXPORT bool (*g_fp)(bool); EXPORT const char g_s[]; EXPORT const char* g_sp; @@ -643,8 +673,11 @@ uint64_t g_u64 = 64; float g_f = 3; double g_d = 5; #ifdef HAVE_COMPLEX -double complex g_dc = 7+8i; -float complex g_fc = 6+9i; +double_complex g_dc = 7+8i; +float_complex g_fc = 6+9i; +#else +double_complex g_dc = {7,8}; +float_complex g_fc = {6,9}; #endif bool (*g_fp)(bool) = ¬_b; void* g_p = (void*) ¬_b; @@ -691,30 +724,65 @@ void test_call_echo(char* c) EXPORT void test_call_pppppii(void* a, void* b, void* c, void* d, void* e, int f, int g); void test_call_pppppii(void* a, void* b, void* c, void* d, void* e, int f, int g) { - sprintf(buf, "%p %p %p %p %p %d %d", a, b, c, d, e, f, g); + sprintf(buf, "%lu %lu %lu %lu %lu %d %d", (unsigned long)a, (unsigned long)b, (unsigned long)c, (unsigned long)d, (unsigned long)e, f, g); } EXPORT void test_call_pppppiiiiii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, int i3, int i4, int i5, int i6); void test_call_pppppiiiiii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, int i3, int i4, int i5, int i6) { - sprintf(buf, "%p %p %p %p %p %d %d %d %d %d %d", p1, p2, p3, p4, p5, i1, i2, i3, i4, i5, i6); + sprintf(buf, "%lu %lu %lu %lu %lu %d %d %d %d %d %d", (unsigned long)p1, (unsigned long)p2, (unsigned long)p3, (unsigned long)p4, (unsigned long)p5, i1, i2, i3, i4, i5, i6); } EXPORT void test_call_pppppffffff(void* p1, void* p2, void* p3, void* p4, void* p5, float f1, float f2, float f3, float f4, float f5, float f6); void test_call_pppppffffff(void* p1, void* p2, void* p3, void* p4, void* p5, float f1, float f2, float f3, float f4, float f5, float f6) { - sprintf(buf, "%p %p %p %p %p %0.1f %0.1f %0.1f %0.1f %0.1f %0.1f", p1, p2, p3, p4, p5, f1, f2, f3, f4, f5, f6); + sprintf(buf, "%lu %lu %lu %lu %lu %0.1f %0.1f %0.1f %0.1f %0.1f %0.1f", (unsigned long)p1, (unsigned long)p2, (unsigned long)p3, (unsigned long)p4, (unsigned long)p5, f1, f2, f3, f4, f5, f6); } EXPORT void test_call_pppppiifiii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, float f3, int i4, int i5, int i6); void test_call_pppppiifiii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, float f3, int i4, int i5, int i6) { - sprintf(buf, "%p %p %p %p %p %d %d %0.1f %d %d %d", p1, p2, p3, p4, p5, i1, i2, f3, i4, i5, i6); + sprintf(buf, "%lu %lu %lu %lu %lu %d %d %0.1f %d %d %d", (unsigned long)p1, (unsigned long)p2, (unsigned long)p3, (unsigned long)p4, (unsigned long)p5, i1, i2, f3, i4, i5, i6); } EXPORT void test_call_pppppiiifii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, int i3, float f4, int i5, int i6); void test_call_pppppiiifii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, int i3, float f4, int i5, int i6) { - sprintf(buf, "%p %p %p %p %p %d %d %d %0.1f %d %d", p1, p2, p3, p4, p5, i1, i2, i3, f4, i5, i6); + sprintf(buf, "%lu %lu %lu %lu %lu %d %d %d %0.1f %d %d", (unsigned long)p1, (unsigned long)p2, (unsigned long)p3, (unsigned long)p4, (unsigned long)p5, i1, i2, i3, f4, i5, i6); +} +#define ADD_STRUCT_FUNC(type,count)\ +struct type##count{\ + type ele[count];\ +};\ +EXPORT struct type##count test_call_##type##count##type##count(struct type##count (*f)(struct type##count),struct type##count p){\ + return f(p);\ } +ADD_STRUCT_FUNC(float,1) +ADD_STRUCT_FUNC(float,2) +ADD_STRUCT_FUNC(float,3) +ADD_STRUCT_FUNC(float,4) +ADD_STRUCT_FUNC(float,5) +ADD_STRUCT_FUNC(double,1) +ADD_STRUCT_FUNC(double,2) +ADD_STRUCT_FUNC(double,3) +ADD_STRUCT_FUNC(double,4) +ADD_STRUCT_FUNC(double,5) +ADD_STRUCT_FUNC(int,1) +ADD_STRUCT_FUNC(int64_t ,1) +ADD_STRUCT_FUNC(int64_t ,2) +ADD_STRUCT_FUNC(int64_t ,3) + +EXPORT struct int64_t2 test_call_int64_t2_stack1( + struct int64_t2 (*f)(struct int64_t2),int64_t i1,int64_t i2,int64_t i3,int64_t i4,int64_t i5,int64_t i6,struct int64_t2 p){ + return f(p); +} +EXPORT struct double2 test_call_double2_stack1( + struct double2 (*f)(struct double2),double d1,double d2,double d3,double d4,double d5,double d6,double d7,struct double2 p){ + p= f(p); + return p; +} +EXPORT struct int64_t2 test_call_int64_t2_stack2( + struct int64_t2 (*f)(struct int64_t2),int64_t i1,int64_t i2,int64_t i3,int64_t i4,struct int64_t2 p){ + return f(p); +} \ No newline at end of file diff --git a/texk/web2c/luatexdir/luaffi/test.lua b/texk/web2c/luatexdir/luaffi/test.lua index 8a9b7189f0..fb04ec820f 100644 --- a/texk/web2c/luatexdir/luaffi/test.lua +++ b/texk/web2c/luatexdir/luaffi/test.lua @@ -21,15 +21,13 @@ local function loadlib(lib) error("Unable to load", lib) end -if _VERSION == 'Lua 5.1' then - dlls.__cdecl = loadlib('ffi/libtest') -else - dlls.__cdecl = ffi.load(package.searchpath('ffi.libtest', package.cpath)) +if ffi.debug then + dlls.__cdecl = ffi.load('./libffitest') end if ffi.arch == 'x86' and ffi.os == 'Windows' then - dlls.__stdcall = ffi.load('test_stdcall') - dlls.__fastcall = ffi.load('test_fastcall') + --dlls.__stdcall = ffi.load('ffitest_stdcall') + --dlls.__fastcall = ffi.load('ffitest_fastcall') end local function check(a, b, msg) @@ -326,14 +324,14 @@ local buf = ffi.new('char[256]') local function checkbuf(type, ret, msg) local str = tostring(test_values[type]):gsub('^cdata%b<>: ', '') - check(ffi.string(buf), str, msg) + check(string.lower(ffi.string(buf)), string.lower(str), msg) check(ret, #str, msg) end local function checkalign(type, v, ret) --print(v) - local str = tostring(test_values[type]):gsub('^cdata%b<>: ', '') - check(ffi.string(buf), ('size %d offset %d align %d value %s'):format(ffi.sizeof(v), ffi.offsetof(v, 'v'), ffi.alignof(v, 'v'), str)) + local str = string.lower(tostring(test_values[type]):gsub('^cdata%b<>: ', '')) + check(string.lower(ffi.string(buf)), ('size %d offset %d align %d value %s'):format(ffi.sizeof(v), ffi.offsetof(v, 'v'), ffi.alignof(v, 'v'), str)) check(ret, #str) end @@ -343,6 +341,8 @@ local i64 = ffi.typeof('int64_t') local first = true for convention,c in pairs(dlls) do + + check(c.add_i8(1,1), 2) check(c.add_i8(256,1), 1) check(c.add_i8(127,1), -128) @@ -360,21 +360,17 @@ for convention,c in pairs(dlls) do check(c.inc_e32(c.FOO32), c.BAR32) check(c.ret_fp(c.g_fp), c.g_fp) check(c.ret_fp2(c.g_fp), c.g_fp) + print("on line",debug.getinfo(1).currentline) + + check(c.add_dc(3+4*i, 4+5*i), 7+9*i) + check(c.add_fc(2+4*i, 6+8*i), 8+12*i) + types.dc = 'double complex' + types.fc = 'float complex' - if c.have_complex() then - check(c.add_dc(3+4*i, 4+5*i), 7+9*i) - check(c.add_fc(2+4*i, 6+8*i), 8+12*i) - types.dc = 'double complex' - types.fc = 'float complex' - else - types.dc = nil - types.fc = nil - end check((3+4*i).re, 3) check((3+4*i).im, 4) check(ffi.new('complex float', 2+8*i).re, 2) check(ffi.new('complex float', 5+6*i).im, 6) - check(c.have_complex(), c.have_complex2()) check(c.is_msvc, c.is_msvc2) @@ -382,17 +378,26 @@ for convention,c in pairs(dlls) do check(c.g_i8, -8) check(c.g_i16, -16) check(c.g_i32, -32) - check(c.g_i64, i64(-64)) + if _VERSION=='Lua 5.1' or _VERSION=='Lua 5.2' then + check(c.g_i64, i64(-64)) + else + check(c.g_i64, -64) + end + print("on line",debug.getinfo(1).currentline) check(c.g_u8, 8) check(c.g_u16, 16) check(c.g_u32, 32) - check(c.g_u64, u64(64)) + if _VERSION=='Lua 5.1' or _VERSION=='Lua 5.2' then + check(c.g_u64, u64(64)) + else + check(c.g_u64, 64) + end + check(c.g_f, 3) check(c.g_d, 5) - if c.have_complex() then - check(c.g_dc, 7 + 8*i) - check(c.g_fc, 6 + 9*i) - end + check(c.g_dc, 7 + 8*i) + check(c.g_fc, 6 + 9*i) + check(ffi.cast('void*', c.g_fp), c.g_p) check(c.g_s, 'g_s') check(c.g_sp, 'g_sp') @@ -403,28 +408,38 @@ for convention,c in pairs(dlls) do check(c.g_date.nMonthDay, 2) check(c.g_date.nMonth, 3) check(c.g_date.nYear, 4) - + c.g_b = false; check(c.g_b, false) c.g_i8 = -108; check(c.g_i8, -108) c.g_i16 = -1016; check(c.g_i16, -1016) c.g_i32 = -1032; check(c.g_i32, -1032) - c.g_i64 = -1064; check(c.g_i64, i64(-1064)) + c.g_i64 = -1064; + if _VERSION=='Lua 5.1' or _VERSION=='Lua 5.2' then + check(c.g_i64, i64(-1064)) + else + check(c.g_i64, -1064) + end c.g_u8 = 208; check(c.g_u8, 208) c.g_u16 = 2016; check(c.g_u16, 2016) c.g_u32 = 2032; check(c.g_u32, 2032) - c.g_u64 = 2064; check(c.g_u64, u64(2064)) + c.g_u64 = 2064; + if _VERSION=='Lua 5.1' or _VERSION=='Lua 5.2' then + check(c.g_u64, u64(2064)) + else + check(c.g_u64, 2064) + end c.g_f = 13; check(c.g_f, 13) c.g_d = 15; check(c.g_d, 15) - if c.have_complex() then - c.g_dc = 17+18*i; check(c.g_dc, 17+18*i) - c.g_fc = 16+19*i; check(c.g_fc, 16+19*i) - end + + c.g_dc = 17+18*i; check(c.g_dc, 17+18*i) + c.g_fc = 16+19*i; check(c.g_fc, 16+19*i) + c.g_sp = 'foo'; check(c.g_sp, 'foo') c.g_e8 = c.BAR8; check(c.g_e8, c.BAR8) c.g_e16 = c.BAR16; check(c.g_e16, c.BAR16) c.g_e32 = c.BAR32; check(c.g_e32, c.BAR32) c.g_date.nWeekDay = 3; check(c.g_date.nWeekDay, 3) - + print("on line",debug.getinfo(1).currentline) local align_attr = c.is_msvc and [[ struct align_attr_ALIGN_SUFFIX { char pad; @@ -440,7 +455,8 @@ for convention,c in pairs(dlls) do int print_align_attr_ALIGN_SUFFIX(char* buf, struct align_attr_ALIGN_SUFFIX* p); ]] - + + for suffix, type in pairs(types) do local test = test_values[type] --print('checkbuf', suffix, type, buf, test) @@ -452,27 +468,27 @@ for convention,c in pairs(dlls) do local v = ffi.new('struct align_0_' .. suffix, {0, test}) checkalign(type, v, c['print_align_0_' .. suffix](buf, v)) - + for _,align in ipairs{1,2,4,8,16} do + if align > c.max_alignment() then break end - + if first then ffi.cdef(palign:gsub('SUFFIX', suffix):gsub('TYPE', type):gsub('ALIGN', align)) ffi.cdef(align_attr:gsub('SUFFIX', suffix):gsub('TYPE', type):gsub('ALIGN', align)) end - + local v = ffi.new('struct align_' .. align .. '_' .. suffix, {0, test}) checkalign(type, v, c['print_align_' .. align .. '_' .. suffix](buf, v)) - + -- MSVC doesn't support aligned attributes on enums if not type:match('^enum e[0-9]*$') or not c.is_msvc then local v2 = ffi.new('struct align_attr_' .. align .. '_' .. suffix, {0, test}) checkalign(type, v2, c['print_align_attr_' .. align .. '_' .. suffix](buf, v2)) end - end - + end if not c.is_msvc then if first then local h = [[ @@ -486,23 +502,21 @@ for convention,c in pairs(dlls) do end local v = ffi.new('struct align_attr_def_' .. suffix, {0, test}) - -- print(type) - -- print("Align " .. c['print_align_attr_def_' .. suffix](buf, v)) - -- print(ffi.string(buf)) - -- checkalign(type, v, c['print_align_attr_def_' .. suffix](buf, v)) - end + checkalign(type, v, c['print_align_attr_def_' .. suffix](buf, v)) + end end - + print("on line",debug.getinfo(1).currentline) local psz = ffi.new('size_t[1]') local palign = ffi.new('size_t[1]') local function check_align(type, test, ret) - --print('check_align', type, test, ret, ffi.string(buf), psz[0], palign[0]) + print('check_align', type, palign[0],ffi.alignof(type)) check(tonumber(palign[0]), ffi.alignof(type)) check(tonumber(psz[0]), ffi.sizeof(type)) + print('***',psz[0], palign[0], buf[0],tostring(test)..":"..tostring(ffi.string(buf))) check(ret, #test) check(test, ffi.string(buf)) end - + for _, tnum in ipairs{8, 16, 32, 64} do if first then ffi.cdef(bitfields:gsub('TNUM',tnum)) @@ -533,7 +547,7 @@ for convention,c in pairs(dlls) do check_align('struct ba_'..tnum..'_'..bnum, '1 2', c['print_ba_'..tnum..'_'..bnum](psz, palign, buf, {1,2})) end end - + check_align('struct Date', '1 2 3 4', c.print_date(psz, palign, buf, {1,2,3,4})) check_align('struct Date2', '1 2 3 4', c.print_date2(psz, palign, buf, {1,2,3,4})) check_align('struct sysv1', '1 2 3', c.print_sysv1(psz, palign, buf, {1,2,3})) @@ -543,7 +557,7 @@ for convention,c in pairs(dlls) do check_align('struct sysv5', '1 2 3', c.print_sysv5(psz, palign, buf, {1,2,3})) check_align('struct sysv6', '1 2 3', c.print_sysv6(psz, palign, buf, {1,2,3})) check_align('struct sysv7', '1 2 3 4 5', c.print_sysv7(psz, palign, buf, {1,2,3,4,5})) - + local cbs = [[ typedef const char* (*__cdecl sfunc)(const char*); int call_i(int (*__cdecl func)(int), int arg); @@ -557,9 +571,9 @@ for convention,c in pairs(dlls) do enum e16 call_e16(enum e16 (*__cdecl func)(enum e16), enum e16 arg); enum e32 call_e32(enum e32 (*__cdecl func)(enum e32), enum e32 arg); ]] - + print("on line",debug.getinfo(1).currentline) ffi.cdef(cbs:gsub('__cdecl', convention)) - + local u3 = ffi.new('uint64_t', 3) check(c.call_i(function(a) return 2*a end, 3), 6) assert(math.abs(c.call_d(function(a) return 2*a end, 3.2) - 6.4) < 0.0000000001) @@ -570,10 +584,11 @@ for convention,c in pairs(dlls) do check(c.call_e16(function(v) return v + 1 end, c.FOO16), c.BAR16) check(c.call_e32(function(v) return v + 1 end, c.FOO32), c.BAR32) - if c.have_complex() then - check(c.call_dc(function(v) return v + 2+3*i end, 4+6*i), 6+9*i) - check(c.call_fc(function(v) return v + 1+2*i end, 7+4*i), 8+6*i) - end + + check(c.call_dc(function(v) return v + 2+3*i end, 4+6*i), 6+9*i) + check(c.call_fc(function(v) return v + 1+2*i end, 7+4*i), 8+6*i) + + local u2 = ffi.new('uint64_t', 2) local cb = ffi.new('sfunc', function(s) return s + u3 end) @@ -592,7 +607,7 @@ for convention,c in pairs(dlls) do check(err:gsub('^.*: ',''), "can't set the function for a non-lua callback") check(c.call_fptr({function(a) return 3*a end}, 5), 15) - + local suc, err = pcall(c.call_s, function(s) error(ffi.string(s), 0) end, 'my error') check(suc, false) check(err, 'my error') @@ -604,7 +619,7 @@ for convention,c in pairs(dlls) do check(ffi.errno(4), 3) check(ffi.errno(), 4) check(c.get_errno(), 4) - + print("on line",debug.getinfo(1).currentline) local gccattr = { __cdecl = 'int test_pow(int v) __attribute__((cdecl));', __stdcall = 'int test_pow(int v) __attribute__(stdcall);', @@ -613,7 +628,7 @@ for convention,c in pairs(dlls) do ffi.cdef(gccattr[convention]) check(c.test_pow(5), 25) - + ffi.cdef [[ int va_list_size, va_list_align; int vsnprintf(char* buf, size_t sz, const char* fmt, va_list ap); @@ -624,7 +639,7 @@ for convention,c in pairs(dlls) do assert(ffi.istype('va_list', ffi.new('__gnuc_va_list'))) check(ffi.sizeof('va_list'), c.va_list_size) check(ffi.alignof('va_list'), c.va_list_align) - + print("on line",debug.getinfo(1).currentline) first = false end @@ -671,17 +686,19 @@ assert(not pcall(function() end)) local mt = {} -local vls = ffi.new(ffi.metatype('struct vls', mt), 1) +local vls0 = ffi.new(ffi.metatype('struct vls', mt), 1) -assert(not pcall(function() return vls.key end)) +assert(not pcall(function() return vls0.key end)) mt.__index = function(vls, key) return function(vls, a, b) return 'in index ' .. key .. ' ' .. vls.d.a .. ' ' .. a .. ' ' .. b end end +local vls = ffi.new(ffi.metatype('struct vls', mt), 1) vls.d.a = 3 +--for k,v in pairs(vls) do print("=", k,v) end check(vls:key('a', 'b'), 'in index key 3 a b') assert(not pcall(function() vls.k = 3 end)) @@ -689,6 +706,7 @@ assert(not pcall(function() vls.k = 3 end)) mt.__newindex = function(vls, key, val) error('in newindex ' .. key .. ' ' .. vls.d.a .. ' ' .. val, 0) end +ffi.metatype('struct vls', mt) vls.d.a = 4 local suc, err = pcall(function() vls.key = 'val' end) @@ -709,6 +727,7 @@ mt.__unm = function(vls) return -vls.d.a end mt.__concat = function(vls, a) return vls.d.a .. a end mt.__len = function(vls) return vls.d.a end mt.__tostring = function(vls) return 'string ' .. vls.d.a end +ffi.metatype('struct vls', mt) vls.d.a = 5 check(vls + 5, 10) @@ -736,7 +755,7 @@ if _VERSION ~= 'Lua 5.1' then check(vls .. 'str', '5str') check(#vls, 5) end - +print("on line",debug.getinfo(1).currentline) check(tostring(1.1+3.2*i), '1.1+3.2i') check((1+3*i)*(2+4*i), -10+10*i) check((3+2*i)*(3-2*i), 13+0*i) @@ -757,24 +776,26 @@ if _VERSION == "Lua 5.3" then local native_80 = 0x8000000000000000 - for _, func in ipairs{ffi.C.add_i64, ffi.C.add_u64} do - -- 0x7FFFFFFFFFFFFFFF (native) + 1 == 0x8000000000000000 (native) - local res = func(native_7F, 1) - assert(type(res) == "number", "native_7F: returned value not a number") - assert(res == native_80, "native_7F: math error") - - -- 0x7FFFFFFFFFFFFFFF (cdata int64_t) + 1 == 0x8000000000000000 (native) - local res = func(cdata_long_7F, 1) - assert(type(res) == "number", "cdata_long_7F: returned value not a number") - assert(res == native_80, "cdata_long_7F: math error") - - -- 0x7FFFFFFFFFFFFFFF (cdata uint64_t) + 1 == 0x8000000000000000 (native) - local res = func(cdata_ulong_7F, 1) - assert(type(res) == "number", "cdata_ulong_7F: returned value not a number") - assert(res == native_80, "cdata_ulong_7F: math error") + for _, c in pairs(dlls) do + for _, func in ipairs{c.add_i64, c.add_u64} do + -- 0x7FFFFFFFFFFFFFFF (native) + 1 == 0x8000000000000000 (native) + local res = func(native_7F, 1) + check(type(res) , "number", "native_7F: returned value not a number") + check(res , native_80, "native_7F: math error") + + -- 0x7FFFFFFFFFFFFFFF (cdata int64_t) + 1 == 0x8000000000000000 (native) + local res = func(cdata_long_7F, 1) + check(type(res) , "number", "cdata_long_7F: returned value not a number") + check(res , native_80, "cdata_long_7F: math error") + + -- 0x7FFFFFFFFFFFFFFF (cdata uint64_t) + 1 == 0x8000000000000000 (native) + local res = func(cdata_ulong_7F, 1) + check(type(res) , "number", "cdata_ulong_7F: returned value not a number") + check(res , native_80, "cdata_ulong_7F: math error") + end end end - +print("on line",debug.getinfo(1).currentline) -- Long double is not supported yet but it should be parsed ffi.cdef('long double foo(long double val);') check(tostring(ffi.debug().functions.foo):match('ctype(%b<>)'), '') @@ -874,7 +895,7 @@ struct newtest { int c; }; ]] - +print("on line",debug.getinfo(1).currentline) local tp = ffi.metatype("struct newtest", {__new = function(tp, x, y, z) tp = ffi.new(tp) @@ -903,7 +924,7 @@ if _VERSION ~= 'Lua 5.1' then x, y = ipairs(v) assert(x == 2 and y == 3) end - +print("on line",debug.getinfo(1).currentline) -- test for pointer to struct having same metamethods local st = ffi.cdef "struct ptest {int a, b;};" local tp = ffi.metatype("struct ptest", {__index = function(s, k) return k end, __len = function(s) return 3 end}) @@ -915,7 +936,7 @@ local b = ffi.new("int[2]") local c = ffi.cast("struct ptest *", b) assert(c.banana == "banana") -- should have same methods assert(#c == 3) - +print("on line",debug.getinfo(1).currentline) ffi.cdef [[ char buf[512]; @@ -927,31 +948,35 @@ void test_call_pppppiifiii(void* p1, void* p2, void* p3, void* p4, void* p5, int void test_call_pppppiiifii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, int i3, float i4, int i5, int i6); ]] -ffi.C.test_call_echo("input") -assert(ffi.C.buf == "input") +for _, c in pairs(dlls) do + c.test_call_echo("input") + assert(c.buf == "input") + + local function ptr(x) return ffi.new('void*', x) end -local function ptr(x) return ffi.new('void*', x) end + c.test_call_pppppii(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6, 7) + assert(c.buf == "1 2 3 4 5 6 7") -ffi.C.test_call_pppppii(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6, 7) -assert(ffi.C.buf == "0x1 0x2 0x3 0x4 0x5 6 7") + c.test_call_pppppiiiiii(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6, 7, 8, 9, 10, 11) + assert(c.buf == "1 2 3 4 5 6 7 8 9 10 11") -ffi.C.test_call_pppppiiiiii(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6, 7, 8, 9, 10, 11) -assert(ffi.C.buf == "0x1 0x2 0x3 0x4 0x5 6 7 8 9 10 11") + c.test_call_pppppffffff(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6.5, 7.5, 8.5, 9.5, 10.5, 11.5) + assert(c.buf == "1 2 3 4 5 6.5 7.5 8.5 9.5 10.5 11.5") -ffi.C.test_call_pppppffffff(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6.5, 7.5, 8.5, 9.5, 10.5, 11.5) -assert(ffi.C.buf == "0x1 0x2 0x3 0x4 0x5 6.5 7.5 8.5 9.5 10.5 11.5") + c.test_call_pppppiifiii(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6, 7, 8.5, 9, 10, 11) + assert(c.buf == "1 2 3 4 5 6 7 8.5 9 10 11") -ffi.C.test_call_pppppiifiii(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6, 7, 8.5, 9, 10, 11) -assert(ffi.C.buf == "0x1 0x2 0x3 0x4 0x5 6 7 8.5 9 10 11") + c.test_call_pppppiiifii(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6, 7, 8, 9.5, 10, 11) + assert(c.buf == "1 2 3 4 5 6 7 8 9.5 10 11") -ffi.C.test_call_pppppiiifii(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6, 7, 8, 9.5, 10, 11) -assert(ffi.C.buf == "0x1 0x2 0x3 0x4 0x5 6 7 8 9.5 10 11") -local sum = ffi.C.add_dc(ffi.new('complex', 1, 2), ffi.new('complex', 3, 5)) -assert(ffi.istype('complex', sum)) + local sum = c.add_dc(ffi.new('complex', 1, 2), ffi.new('complex', 3, 5)) + assert(ffi.istype('complex', sum)) -sum = ffi.C.add_fc(ffi.new('complex float', 1, 2), ffi.new('complex float', 3, 5)) -assert(ffi.istype('complex float', sum)) + sum = c.add_fc(ffi.new('complex float', 1, 2), ffi.new('complex float', 3, 5)) + assert(ffi.istype('complex float', sum)) + +end ffi.cdef [[ struct Arrays { @@ -1000,4 +1025,36 @@ local str = f:read('*l') assert(str == 'test: foo', str) f:close() +print("on line",debug.getinfo(1).currentline) +--long arg Callback test + +function printArgs(...) + local t={} + for i, v in ipairs(table.pack(...)) do + t[i]=tostring(v); + end + return table.concat(t,',') +end + +local test_func=ffi.new("const char* (*)(int8_t,int16_t,complex float)",printArgs) +assert(ffi.string(test_func(1,2,ffi.new("complex float",7,8)))=="1,2,7+8i") +test_func:free() +test_func=ffi.new("const char* (*)(int8_t,int16_t,int,complex float)",printArgs) +assert(ffi.string(test_func(1,2,6,ffi.new("complex float",7,8)))=="1,2,6,7+8i") +test_func:free() +test_func=ffi.new("const char* (*)(int8_t,int16_t,complex double)",printArgs) +assert(ffi.string(test_func(1,2,ffi.new("complex float",7,8)))=="1,2,7+8i") +test_func:free() +test_func=ffi.new("const char* (*)(int8_t,int16_t,int,complex double)",printArgs) +assert(ffi.string(test_func(1,2,6,ffi.new("complex float",7,8)))=="1,2,6,7+8i") +test_func:free() +test_func=ffi.new("const char* (*)(int8_t,int16_t,long,complex double,int8_t,int16_t,long,complex double,int8_t,int16_t,long,complex double,double,double,float)",printArgs) +local exp1="1,2,6,7+8i,1,2,6,7+8i,1,2,6,7+8i,9,9,4"; +local exp2="1,2,6,7+8i,1,2,6,7+8i,1,2,6,7+8i,9.0,9.0,4.0"; +local real=ffi.string(test_func(1,2,6,ffi.new("complex float",7,8),1,2,6,ffi.new("complex float",7,8),1,2,6,ffi.new("complex float",7,8),9,9,4)); +if(not (real==exp1 or real==exp2))then + check(real,exp1) + check(real,exp2) +end +test_func:free() print('Test PASSED') diff --git a/texk/web2c/luatexdir/luaffi/test.lua.orig b/texk/web2c/luatexdir/luaffi/test.lua.orig new file mode 100644 index 0000000000..39e12a3e4f --- /dev/null +++ b/texk/web2c/luatexdir/luaffi/test.lua.orig @@ -0,0 +1,1060 @@ +-- vim: ts=4 sw=4 sts=4 et tw=78 +-- Portions copyright (c) 2015-present, Facebook, Inc. All rights reserved. +-- Portions copyright (c) 2011 James R. McKaskill. +-- +-- This source code is licensed under the BSD-style license found in the +-- LICENSE file in the root directory of this source tree. An additional grant +-- of patent rights can be found in the PATENTS file in the same directory. +-- +io.stdout:setvbuf('no') +local ffi = require 'ffi' +local dlls = {} + +local function loadlib(lib) + for pattern in package.cpath:gmatch('[^;]+') do + local path = pattern:gsub('?', lib) + local ok, lib = pcall(ffi.load, path) + if ok then + return lib + end + end + error("Unable to load", lib) +end + +if ffi.debug then + dlls.__cdecl = ffi.load('ffi/libffitest') +end + +if ffi.arch == 'x86' and ffi.os == 'Windows' then + --dlls.__stdcall = ffi.load('ffitest_stdcall') + --dlls.__fastcall = ffi.load('ffitest_fastcall') +end + +local function check(a, b, msg) + if a ~= b then + print('check', a, b) + end + return _G.assert(a == b, msg) +end + +print('Running test') + +ffi.cdef [[ +enum e8 { + FOO8, + BAR8, +}; +enum e16 { + FOO16 = 1 << 8, + BAR16, + BIG16 = 1 << 14, +}; +enum e32 { + FOO32 = 1 << 16, + BAR32, + BIG32 = 1 << 30, +}; +int max_alignment(); +bool is_msvc, is_msvc2 __asm__("is_msvc"); +bool have_complex(void); +bool have_complex2() __asm__("have" /*foo*/ "\x5F" "complex"); // 5F is _ + +int8_t add_i8(int8_t a, int8_t b); +uint8_t add_u8(uint8_t a, uint8_t b); +int16_t add_i16(int16_t a, int16_t b); +uint16_t add_i16(uint16_t a, uint16_t b); +int32_t add_i32(int32_t a, int32_t b); +uint32_t add_u32(uint32_t a, uint32_t b); +int64_t add_i64(int64_t a, int64_t b); +uint64_t add_u64(uint64_t a, uint64_t b); +double add_d(double a, double b); +float add_f(float a, float b); +double complex add_dc(double complex a, double complex b); +float complex add_fc(float complex a, float complex b); +enum e8 inc_e8(enum e8); +enum e16 inc_e16(enum e16); +enum e32 inc_e32(enum e32); +bool not_b(bool v); +_Bool not_b2(_Bool v); +typedef bool (*fp)(bool); +fp ret_fp(fp v); +bool (*ret_fp2(bool (*)(bool)))(bool) __asm("ret_fp"); + +int print_i8(char* buf, int8_t val); +int print_u8(char* buf, uint8_t val); +int print_i16(char* buf, int16_t val); +int print_u16(char* buf, uint16_t val); +int print_i32(char* buf, int32_t val); +int print_u32(char* buf, uint32_t val); +int print_i64(char* buf, int64_t val); +int print_u64(char* buf, uint64_t val); +int print_s(char* buf, const char* val); +int print_b(char* buf, bool val); +int print_b2(char* buf, _Bool val); +int print_d(char* buf, double val); +int print_f(char* buf, float val); +int print_p(char* buf, void* val); +int print_dc(char* buf, double complex val); +int print_fc(char* buf, float complex val); +int print_e8(char* buf, enum e8 val); +int print_e16(char* buf, enum e16 val); +int print_e32(char* buf, enum e32 val); +int sprintf(char* buf, const char* format, ...); + +// Examples from MSDN + +// bit_fields1.cpp +// compile with: /LD +struct Date { + unsigned short nWeekDay : 3; // 0..7 (3 bits) + unsigned short nMonthDay : 6; // 0..31 (6 bits) + unsigned short nMonth : 5; // 0..12 (5 bits) + unsigned short nYear : 8; // 0..100 (8 bits) +}; + +// bit_fields2.cpp +// compile with: /LD +struct Date2 { + unsigned nWeekDay : 3; // 0..7 (3 bits) + unsigned nMonthDay : 6; // 0..31 (6 bits) + unsigned : 0; // Force alignment to next boundary. + unsigned nMonth : 5; // 0..12 (5 bits) + unsigned nYear : 8; // 0..100 (8 bits) +}; + +// For checking the alignment of short bitfields +struct Date3 { + char pad; + unsigned short nWeekDay : 3; // 0..7 (3 bits) + unsigned short nMonthDay : 6; // 0..31 (6 bits) + unsigned short nMonth : 5; // 0..12 (5 bits) + unsigned short nYear : 8; // 0..100 (8 bits) +}; + +// For checking the alignment and container of int64 bitfields +struct bit64 { + char pad; + uint64_t a : 15; + uint64_t b : 14; + uint64_t c : 13; + uint64_t d : 12; +}; + +// Examples from SysV X86 ABI +struct sysv1 { + int j:5; + int k:6; + int m:7; +}; + +struct sysv2 { + short s:9; + int j:9; + char c; + short t:9; + short u:9; + char d; +}; + +struct sysv3 { + char c; + short s:8; +}; + +union sysv4 { + char c; + short s:8; +}; + +struct sysv5 { + char c; + int :0; + char d; + short :9; + char e; + char :0; +}; + +struct sysv6 { + char c; + int :0; + char d; + int :9; + char e; +}; + +struct sysv7 { + int j:9; + short s:9; + char c; + short t:9; + short u:9; +}; + +int print_date(size_t* sz, size_t* align, char* buf, struct Date* s); +int print_date2(size_t* sz, size_t* align, char* buf, struct Date2* s); +int print_date3(size_t* sz, size_t* align, char* buf, struct Date3* d); +int print_bit64(size_t* sz, size_t* align, char* buf, struct bit64* d); +int print_sysv1(size_t* sz, size_t* align, char* buf, struct sysv1* s); +int print_sysv2(size_t* sz, size_t* align, char* buf, struct sysv2* s); +int print_sysv3(size_t* sz, size_t* align, char* buf, struct sysv3* s); +int print_sysv4(size_t* sz, size_t* align, char* buf, union sysv4* s); +int print_sysv5(size_t* sz, size_t* align, char* buf, struct sysv5* s); +int print_sysv6(size_t* sz, size_t* align, char* buf, struct sysv6* s); +int print_sysv7(size_t* sz, size_t* align, char* buf, struct sysv7* s); + +struct fptr { + int (__cdecl *p)(int); +}; +int call_fptr(struct fptr* s, int val); + +bool g_b; +int8_t g_i8; +int16_t g_i16; +int32_t g_i32; +int64_t g_i64; +uint8_t g_u8; +uint16_t g_u16; +uint32_t g_u32; +uint64_t g_u64; +float g_f; +double g_d; +double complex g_dc; +float complex g_fc; +bool (*g_fp)(bool); +const char g_s[]; +const char* g_sp; +void* g_p; +enum e8 g_e8; +enum e16 g_e16; +enum e32 g_e32; +struct Date g_date; + +void set_errno(int val); +int get_errno(void); +]] + +local align = [[ +struct align_ALIGN_SUFFIX { + char pad; + TYPE v; +}; + +int print_align_ALIGN_SUFFIX(char* buf, struct align_ALIGN_SUFFIX* p); +]] + +local palign = [[ +#pragma pack(push) +#pragma pack(ALIGN) +]] .. align .. [[ +#pragma pack(pop) +]] + +local bitfields = [[ +struct bcTNUM { + uintTNUM_t a : 3; + intTNUM_t b : 3; +}; +struct blzTNUM { + uintTNUM_t a; + uintTNUM_t :0; + uintTNUM_t b; +}; +int print_bcTNUM(size_t* sz, size_t* align, char* buf, struct bcTNUM* s); +int print_blzTNUM(size_t* sz, size_t* align, char* buf, struct blzTNUM* s); +]] + +local bitalign = [[ +struct ba_TNUM_BNUM { + char a; + uintTNUM_t b : BNUM; +}; +struct bu_TNUM_BNUM { + char a; + uintTNUM_t :BNUM; + char b; +}; +int print_ba_TNUM_BNUM(size_t* sz, size_t* align, char* buf, struct ba_TNUM_BNUM* s); +]] + +local bitzero = [[ +struct bz_TNUM_ZNUM_BNUM { + uint8_t a; + uintTNUM_t b : 3; + uintZNUM_t :BNUM; + uintTNUM_t c : 3; +}; +int print_bz_TNUM_ZNUM_BNUM(size_t* sz, size_t* align, char* buf, struct bz_TNUM_ZNUM_BNUM* s); +]] + +local i = ffi.C.i +local test_values = { + ['void*'] = ffi.new('char[3]'), + ['const char*'] = 'foo', + float = 3.4, + double = 5.6, + uint16_t = 65000, + uint32_t = ffi.new('uint32_t', 700000056), + uint64_t = 12345678901234, + bool = true, + _Bool = false, + ['float complex'] = 3.1+4.2*i, + ['double complex'] = 5.1+6.2*i, + ['enum e8'] = ffi.C.FOO8, + ['enum e16'] = ffi.C.FOO16, + ['enum e32'] = ffi.C.FOO32, +} + +local types = { + b = 'bool', + b2 = '_Bool', + d = 'double', + f = 'float', + u64 = 'uint64_t', + u32 = 'uint32_t', + u16 = 'uint16_t', + s = 'const char*', + p = 'void*', + e8 = 'enum e8', + e16 = 'enum e16', + e32 = 'enum e32', +} + +local buf = ffi.new('char[256]') + +local function checkbuf(type, ret, msg) + local str = tostring(test_values[type]):gsub('^cdata%b<>: ', '') + check(string.lower(ffi.string(buf)), string.lower(str), msg) + check(ret, #str, msg) +end + +local function checkalign(type, v, ret) + --print(v) + local str = string.lower(tostring(test_values[type]):gsub('^cdata%b<>: ', '')) + check(string.lower(ffi.string(buf)), ('size %d offset %d align %d value %s'):format(ffi.sizeof(v), ffi.offsetof(v, 'v'), ffi.alignof(v, 'v'), str)) + check(ret, #str) +end + +local u64 = ffi.typeof('uint64_t') +local i64 = ffi.typeof('int64_t') + +local first = true + +for convention,c in pairs(dlls) do + + + check(c.add_i8(1,1), 2) + check(c.add_i8(256,1), 1) + check(c.add_i8(127,1), -128) + check(c.add_i8(-120,120), 0) + check(c.add_u8(255,1), 0) + check(c.add_u8(120,120), 240) + check(c.add_i16(2000,4000), 6000) + check(c.add_d(20, 12), 32) + check(c.add_f(40, 32), 72) + check(c.not_b(true), false) + check(c.not_b2(false), true) + check(c.inc_e8(c.FOO8), c.BAR8) + check(c.inc_e8('FOO8'), c.BAR8) + check(c.inc_e16(c.FOO16), c.BAR16) + check(c.inc_e32(c.FOO32), c.BAR32) + check(c.ret_fp(c.g_fp), c.g_fp) + check(c.ret_fp2(c.g_fp), c.g_fp) + print("on line",debug.getinfo(1).currentline) + + check(c.add_dc(3+4*i, 4+5*i), 7+9*i) + check(c.add_fc(2+4*i, 6+8*i), 8+12*i) + types.dc = 'double complex' + types.fc = 'float complex' + + check((3+4*i).re, 3) + check((3+4*i).im, 4) + check(ffi.new('complex float', 2+8*i).re, 2) + check(ffi.new('complex float', 5+6*i).im, 6) + check(c.have_complex(), c.have_complex2()) + check(c.is_msvc, c.is_msvc2) + + check(c.g_b, true) + check(c.g_i8, -8) + check(c.g_i16, -16) + check(c.g_i32, -32) + if _VERSION=='Lua 5.1' or _VERSION=='Lua 5.2' then + check(c.g_i64, i64(-64)) + else + check(c.g_i64, -64) + end + print("on line",debug.getinfo(1).currentline) + check(c.g_u8, 8) + check(c.g_u16, 16) + check(c.g_u32, 32) + if _VERSION=='Lua 5.1' or _VERSION=='Lua 5.2' then + check(c.g_u64, u64(64)) + else + check(c.g_u64, 64) + end + + check(c.g_f, 3) + check(c.g_d, 5) + check(c.g_dc, 7 + 8*i) + check(c.g_fc, 6 + 9*i) + + check(ffi.cast('void*', c.g_fp), c.g_p) + check(c.g_s, 'g_s') + check(c.g_sp, 'g_sp') + check(c.g_e8, c.FOO8) + check(c.g_e16, c.FOO16) + check(c.g_e32, c.FOO32) + check(c.g_date.nWeekDay, 1) + check(c.g_date.nMonthDay, 2) + check(c.g_date.nMonth, 3) + check(c.g_date.nYear, 4) + + c.g_b = false; check(c.g_b, false) + c.g_i8 = -108; check(c.g_i8, -108) + c.g_i16 = -1016; check(c.g_i16, -1016) + c.g_i32 = -1032; check(c.g_i32, -1032) + c.g_i64 = -1064; + if _VERSION=='Lua 5.1' or _VERSION=='Lua 5.2' then + check(c.g_i64, i64(-1064)) + else + check(c.g_i64, -1064) + end + c.g_u8 = 208; check(c.g_u8, 208) + c.g_u16 = 2016; check(c.g_u16, 2016) + c.g_u32 = 2032; check(c.g_u32, 2032) + c.g_u64 = 2064; + if _VERSION=='Lua 5.1' or _VERSION=='Lua 5.2' then + check(c.g_u64, u64(2064)) + else + check(c.g_u64, 2064) + end + c.g_f = 13; check(c.g_f, 13) + c.g_d = 15; check(c.g_d, 15) + + c.g_dc = 17+18*i; check(c.g_dc, 17+18*i) + c.g_fc = 16+19*i; check(c.g_fc, 16+19*i) + + c.g_sp = 'foo'; check(c.g_sp, 'foo') + c.g_e8 = c.BAR8; check(c.g_e8, c.BAR8) + c.g_e16 = c.BAR16; check(c.g_e16, c.BAR16) + c.g_e32 = c.BAR32; check(c.g_e32, c.BAR32) + c.g_date.nWeekDay = 3; check(c.g_date.nWeekDay, 3) + print("on line",debug.getinfo(1).currentline) + local align_attr = c.is_msvc and [[ + struct align_attr_ALIGN_SUFFIX { + char pad; + __declspec(align(ALIGN)) TYPE v; + }; + + int print_align_attr_ALIGN_SUFFIX(char* buf, struct align_attr_ALIGN_SUFFIX* p); + ]] or [[ + struct align_attr_ALIGN_SUFFIX { + char pad; + TYPE v __attribute__(aligned(ALIGN)); + }; + + int print_align_attr_ALIGN_SUFFIX(char* buf, struct align_attr_ALIGN_SUFFIX* p); + ]] + + + for suffix, type in pairs(types) do + local test = test_values[type] + --print('checkbuf', suffix, type, buf, test) + checkbuf(type, c['print_' .. suffix](buf, test), suffix) + + if first then + ffi.cdef(align:gsub('SUFFIX', suffix):gsub('TYPE', type):gsub('ALIGN', 0)) + end + + local v = ffi.new('struct align_0_' .. suffix, {0, test}) + checkalign(type, v, c['print_align_0_' .. suffix](buf, v)) + + for _,align in ipairs{1,2,4,8,16} do + + if align > c.max_alignment() then + break + end + + if first then + ffi.cdef(palign:gsub('SUFFIX', suffix):gsub('TYPE', type):gsub('ALIGN', align)) + ffi.cdef(align_attr:gsub('SUFFIX', suffix):gsub('TYPE', type):gsub('ALIGN', align)) + end + + local v = ffi.new('struct align_' .. align .. '_' .. suffix, {0, test}) + checkalign(type, v, c['print_align_' .. align .. '_' .. suffix](buf, v)) + + -- MSVC doesn't support aligned attributes on enums + if not type:match('^enum e[0-9]*$') or not c.is_msvc then + local v2 = ffi.new('struct align_attr_' .. align .. '_' .. suffix, {0, test}) + checkalign(type, v2, c['print_align_attr_' .. align .. '_' .. suffix](buf, v2)) + end + end + if not c.is_msvc then + if first then + local h = [[ + struct align_attr_def_SUFFIX { + char pad; + TYPE v __attribute__(aligned); + }; + int print_align_attr_def_SUFFIX(char* buf, struct align_attr_def_SUFFIX* p); + ]] + ffi.cdef(h:gsub('SUFFIX', suffix):gsub('TYPE', type)) + end + + local v = ffi.new('struct align_attr_def_' .. suffix, {0, test}) + checkalign(type, v, c['print_align_attr_def_' .. suffix](buf, v)) + end + end + print("on line",debug.getinfo(1).currentline) + local psz = ffi.new('size_t[1]') + local palign = ffi.new('size_t[1]') + local function check_align(type, test, ret) + print('check_align', type, palign[0],ffi.alignof(type)) + check(tonumber(palign[0]), ffi.alignof(type)) + check(tonumber(psz[0]), ffi.sizeof(type)) + print('***',psz[0], palign[0], buf[0],tostring(test)..":"..tostring(ffi.string(buf))) + check(ret, #test) + check(test, ffi.string(buf)) + end + + for _, tnum in ipairs{8, 16, 32, 64} do + if first then + ffi.cdef(bitfields:gsub('TNUM',tnum)) + end + + check_align('struct bc'..tnum, '1 2', c['print_bc'..tnum](psz, palign, buf, {1,2})) + check_align('struct blz'..tnum, '1 2', c['print_blz'..tnum](psz, palign, buf, {1,2})) + + for _, znum in ipairs{8, 16, 32, 64} do + for _, bnum in ipairs{7, 15, 31, 63} do + if bnum > znum then + break + end + if first then + ffi.cdef(bitzero:gsub('TNUM',tnum):gsub('ZNUM',znum):gsub('BNUM', bnum)) + end + check_align('struct bz_'..tnum..'_'..znum..'_'..bnum, '1 2 3', c['print_bz_'..tnum..'_'..znum..'_'..bnum](psz, palign, buf, {1,2,3})) + end + end + + for _, bnum in ipairs{7, 15, 31, 63} do + if bnum > tnum then + break + end + if first then + ffi.cdef(bitalign:gsub('TNUM',tnum):gsub('BNUM',bnum)) + end + check_align('struct ba_'..tnum..'_'..bnum, '1 2', c['print_ba_'..tnum..'_'..bnum](psz, palign, buf, {1,2})) + end + end + + check_align('struct Date', '1 2 3 4', c.print_date(psz, palign, buf, {1,2,3,4})) + check_align('struct Date2', '1 2 3 4', c.print_date2(psz, palign, buf, {1,2,3,4})) + check_align('struct sysv1', '1 2 3', c.print_sysv1(psz, palign, buf, {1,2,3})) + check_align('struct sysv2', '1 2 3 4 5 6', c.print_sysv2(psz, palign, buf, {1,2,3,4,5,6})) + check_align('struct sysv3', '1 2', c.print_sysv3(psz, palign, buf, {1,2})) + check_align('union sysv4', '1', c.print_sysv4(psz, palign, buf, {1})) + check_align('struct sysv5', '1 2 3', c.print_sysv5(psz, palign, buf, {1,2,3})) + check_align('struct sysv6', '1 2 3', c.print_sysv6(psz, palign, buf, {1,2,3})) + check_align('struct sysv7', '1 2 3 4 5', c.print_sysv7(psz, palign, buf, {1,2,3,4,5})) + + local cbs = [[ + typedef const char* (*__cdecl sfunc)(const char*); + int call_i(int (*__cdecl func)(int), int arg); + float call_f(float (*__cdecl func)(float), float arg); + double call_d(double (*__cdecl func)(double), double arg); + const char* call_s(sfunc func, const char* arg); + _Bool call_b(_Bool (*__cdecl func)(_Bool), _Bool arg); + double complex call_dc(double complex (*__cdecl func)(double complex), double complex arg); + float complex call_fc(float complex (*__cdecl func)(float complex), float complex arg); + enum e8 call_e8(enum e8 (*__cdecl func)(enum e8), enum e8 arg); + enum e16 call_e16(enum e16 (*__cdecl func)(enum e16), enum e16 arg); + enum e32 call_e32(enum e32 (*__cdecl func)(enum e32), enum e32 arg); + ]] + print("on line",debug.getinfo(1).currentline) + ffi.cdef(cbs:gsub('__cdecl', convention)) + + local u3 = ffi.new('uint64_t', 3) + check(c.call_i(function(a) return 2*a end, 3), 6) + assert(math.abs(c.call_d(function(a) return 2*a end, 3.2) - 6.4) < 0.0000000001) + assert(math.abs(c.call_f(function(a) return 2*a end, 3.2) - 6.4) < 0.000001) + check(ffi.string(c.call_s(function(s) return s + u3 end, 'foobar')), 'bar') + check(c.call_b(function(v) return not v end, true), false) + check(c.call_e8(function(v) return v + 1 end, c.FOO8), c.BAR8) + check(c.call_e16(function(v) return v + 1 end, c.FOO16), c.BAR16) + check(c.call_e32(function(v) return v + 1 end, c.FOO32), c.BAR32) + + + check(c.call_dc(function(v) return v + 2+3*i end, 4+6*i), 6+9*i) + check(c.call_fc(function(v) return v + 1+2*i end, 7+4*i), 8+6*i) + + + + local u2 = ffi.new('uint64_t', 2) + local cb = ffi.new('sfunc', function(s) return s + u3 end) + check(ffi.string(cb('foobar')), 'bar') + check(ffi.string(c.call_s(cb, 'foobar')), 'bar') + cb:set(function(s) return s + u2 end) + check(ffi.string(c.call_s(cb, 'foobar')), 'obar') + + local fp = ffi.new('struct fptr') + assert(fp.p == ffi.C.NULL) + fp.p = function(a) return 2*a end + assert(fp.p ~= ffi.C.NULL) + check(c.call_fptr(fp, 4), 8) + local suc, err = pcall(function() fp.p:set(function() end) end) + assert(not suc) + check(err:gsub('^.*: ',''), "can't set the function for a non-lua callback") + + check(c.call_fptr({function(a) return 3*a end}, 5), 15) + + local suc, err = pcall(c.call_s, function(s) error(ffi.string(s), 0) end, 'my error') + check(suc, false) + check(err, 'my error') + + check(ffi.errno(), c.get_errno()) + c.set_errno(3) + check(ffi.errno(), 3) + check(c.get_errno(), 3) + check(ffi.errno(4), 3) + check(ffi.errno(), 4) + check(c.get_errno(), 4) + print("on line",debug.getinfo(1).currentline) + local gccattr = { + __cdecl = 'int test_pow(int v) __attribute__((cdecl));', + __stdcall = 'int test_pow(int v) __attribute__(stdcall);', + __fastcall = '__attribute__(fastcall) int test_pow(int v);', + } + + ffi.cdef(gccattr[convention]) + check(c.test_pow(5), 25) + + ffi.cdef [[ + int va_list_size, va_list_align; + int vsnprintf(char* buf, size_t sz, const char* fmt, va_list ap); + ]] + ffi.new('va_list') + assert(ffi.debug().functions.vsnprintf ~= nil) + assert(ffi.istype('va_list', ffi.new('__builtin_va_list'))) + assert(ffi.istype('va_list', ffi.new('__gnuc_va_list'))) + check(ffi.sizeof('va_list'), c.va_list_size) + check(ffi.alignof('va_list'), c.va_list_align) + print("on line",debug.getinfo(1).currentline) + first = false +end + +local c = ffi.C + +assert(c.sprintf(buf, "%g", 5.3) == 3 and ffi.string(buf) == '5.3') +assert(c.sprintf(buf, "%d", false) == 1 and ffi.string(buf) == '0') +assert(c.sprintf(buf, "%d%g", false, 6.7) == 4 and ffi.string(buf) == '06.7') + +assert(ffi.sizeof('uint32_t[?]', 32) == 32 * 4) +assert(ffi.sizeof(ffi.new('uint32_t[?]', 32)) == 32 * 4) + +ffi.cdef [[ +struct vls { + struct { + char a; + struct { + char b; + char v[?]; + } c; + } d; +}; +struct vls2 { + char pad; + union { + uint8_t a; + uint16_t b; + }; +}; +]] + +assert(ffi.sizeof('struct vls', 3) == 5) +assert(ffi.sizeof(ffi.new('struct vls', 4).d.c) == 5) +assert(ffi.offsetof('struct vls2', 'a') == 2) +assert(ffi.sizeof('struct vls2') == 4) + +ffi.cdef [[ static const int DUMMY = 8 << 2; ]] +assert(ffi.C.DUMMY == 32) + +ffi.new('struct {const char* foo;}', {'foo'}) + +assert(not pcall(function() + ffi.new('struct {char* foo;}', {'ff'}) +end)) + +local mt = {} +local vls0 = ffi.new(ffi.metatype('struct vls', mt), 1) + +assert(not pcall(function() return vls0.key end)) + +mt.__index = function(vls, key) + return function(vls, a, b) + return 'in index ' .. key .. ' ' .. vls.d.a .. ' ' .. a .. ' ' .. b + end +end +local vls = ffi.new(ffi.metatype('struct vls', mt), 1) + +vls.d.a = 3 +--for k,v in pairs(vls) do print("=", k,v) end +check(vls:key('a', 'b'), 'in index key 3 a b') + +assert(not pcall(function() vls.k = 3 end)) + +mt.__newindex = function(vls, key, val) + error('in newindex ' .. key .. ' ' .. vls.d.a .. ' ' .. val, 0) +end +ffi.metatype('struct vls', mt) + +vls.d.a = 4 +local suc, err = pcall(function() vls.key = 'val' end) +assert(not suc) +check(err, 'in newindex key 4 val') + +mt.__add = function(vls, a) return vls.d.a + a end +mt.__sub = function(vls, a) return vls.d.a - a end +mt.__mul = function(vls, a) return vls.d.a * a end +mt.__div = function(vls, a) return vls.d.a / a end +mt.__mod = function(vls, a) return vls.d.a % a end +mt.__pow = function(vls, a) return vls.d.a ^ a end +mt.__eq = function(vls, a) return u64(vls.d.a) == a end +mt.__lt = function(vls, a) return u64(vls.d.a) < a end +mt.__le = function(vls, a) return u64(vls.d.a) <= a end +mt.__call = function(vls, a, b) return '__call', vls.d.a .. a .. (b or 'nil') end +mt.__unm = function(vls) return -vls.d.a end +mt.__concat = function(vls, a) return vls.d.a .. a end +mt.__len = function(vls) return vls.d.a end +mt.__tostring = function(vls) return 'string ' .. vls.d.a end +ffi.metatype('struct vls', mt) + +vls.d.a = 5 +check(vls + 5, 10) +check(vls - 5, 0) +check(vls * 5, 25) +check(vls / 5, 1) +check(vls % 3, 2) +check(vls ^ 3, 125) +check(vls == u64(4), false) +check(vls == u64(5), true) +check(vls == u64(6), false) +check(vls < u64(4), false) +check(vls < u64(5), false) +check(vls < u64(6), true) +check(vls <= u64(4), false) +check(vls <= u64(5), true) +check(vls <= u64(6), true) +check(-vls, -5) +local a,b = vls('6') +check(a, '__call') +check(b, '56nil') +check(tostring(vls), 'string 5') + +if _VERSION ~= 'Lua 5.1' then + check(vls .. 'str', '5str') + check(#vls, 5) +end +print("on line",debug.getinfo(1).currentline) +check(tostring(1.1+3.2*i), '1.1+3.2i') +check((1+3*i)*(2+4*i), -10+10*i) +check((3+2*i)*(3-2*i), 13+0*i) + +-- Should ignore unknown attributes +ffi.cdef [[ +typedef int ALenum; +__attribute__((dllimport)) void __attribute__((__cdecl__)) alEnable( ALenum capability ); +]] + +check(ffi.sizeof('struct {char foo[alignof(uint64_t)];}'), ffi.alignof('uint64_t')) + +-- Check native number type for int64_t/uint64_t function args/returns in Lua 5.3 +if _VERSION == "Lua 5.3" then + local native_7F = 0x7FFFFFFFFFFFFFFF + local cdata_long_7F = ffi.new("int64_t", 0x7FFFFFFFFFFFFFFF) + local cdata_ulong_7F = ffi.new("uint64_t", 0x7FFFFFFFFFFFFFFF) + + local native_80 = 0x8000000000000000 + + for _, c in pairs(dlls) do + for _, func in ipairs{c.add_i64, c.add_u64} do + -- 0x7FFFFFFFFFFFFFFF (native) + 1 == 0x8000000000000000 (native) + local res = func(native_7F, 1) + check(type(res) , "number", "native_7F: returned value not a number") + check(res , native_80, "native_7F: math error") + + -- 0x7FFFFFFFFFFFFFFF (cdata int64_t) + 1 == 0x8000000000000000 (native) + local res = func(cdata_long_7F, 1) + check(type(res) , "number", "cdata_long_7F: returned value not a number") + check(res , native_80, "cdata_long_7F: math error") + + -- 0x7FFFFFFFFFFFFFFF (cdata uint64_t) + 1 == 0x8000000000000000 (native) + local res = func(cdata_ulong_7F, 1) + check(type(res) , "number", "cdata_ulong_7F: returned value not a number") + check(res , native_80, "cdata_ulong_7F: math error") + end + end +end +print("on line",debug.getinfo(1).currentline) +-- Long double is not supported yet but it should be parsed +ffi.cdef('long double foo(long double val);') +check(tostring(ffi.debug().functions.foo):match('ctype(%b<>)'), '') + +ffi.cdef [[ +typedef int byte1 __attribute__(mode(QI)); +typedef int byte2 __attribute__(mode(HI)); +typedef int byte4 __attribute__(mode(SI)); +typedef int byte8 __attribute__(mode(DI)); +typedef unsigned ubyte8 __attribute__(mode(DI)); +typedef int word __attribute__(mode(word)); +typedef int pointer __attribute__(mode(pointer)); +typedef int byte __attribute__(mode(byte)); +typedef float float4 __attribute__(mode(SF)); +typedef float float8 __attribute__(mode(DF)); +]] +assert(ffi.istype('int8_t', ffi.new('byte1'))) +assert(ffi.istype('int16_t', ffi.new('byte2'))) +assert(ffi.istype('int32_t', ffi.new('byte4'))) +assert(ffi.istype('int64_t', ffi.new('byte8'))) +assert(ffi.istype('uint64_t', ffi.new('ubyte8'))) +check(ffi.sizeof('void*'), ffi.sizeof('pointer')) +check(ffi.alignof('void*'), ffi.alignof('pointer')) +check(ffi.sizeof('void*'), ffi.sizeof('word')) +check(ffi.alignof('void*'), ffi.alignof('word')) +assert(ffi.istype('int8_t', ffi.new('byte'))) +assert(ffi.istype('float', ffi.new('float4'))) +assert(ffi.istype('double', ffi.new('float8'))) + +ffi.cdef('void register_foo(register int val);') +check(tostring(ffi.debug().functions.register_foo):match('%b<>'), '') + +ffi.cdef [[ + typedef struct __sFILE FILE; +]] + +assert(not ffi.istype('int', ffi.new('int*'))) +assert(not ffi.istype('int[]', ffi.new('int*'))) +assert(not ffi.istype('int[3]', ffi.new('int*'))) +assert(not ffi.istype('int[3]', ffi.new('int[2]'))) +assert(ffi.istype('const int[3]', ffi.new('const int[3]'))) +assert(ffi.istype('int[3]', ffi.new('const int[3]'))) + +-- Crazy function pointer that takes an int and a function pointer and returns +-- a function pointer. Type of &signal. +check(tostring(ffi.typeof('void (*foo(int, void(*)(int)))(int)')):match('%b<>'), '') + +-- Make sure we pass all arguments to tonumber +check(tonumber('FE', 16), 0xFE) + +-- Allow casts from pointer to numeric types +ffi.cast('long', ffi.C.NULL) +ffi.cast('int8_t', ffi.C.NULL) +assert(not pcall(function() ffi.new('long', ffi.C.NULL) end)) + +-- ffi.new and ffi.cast allow unpacked struct/arrays +assert(ffi.new('int[3]', 1)[0] == 1) +assert(ffi.new('int[3]', {1})[0] == 1) +assert(ffi.new('int[3]', 1, 2)[1] == 2) +assert(ffi.new('int[3]', {1, 2})[1] == 2) + +ffi.cdef[[ +struct var { + char ch[?]; +}; +]] +local d = ffi.new('char[4]') +local v = ffi.cast('struct var*', d) +v.ch = {1,2,3,4} +assert(v.ch[3] == 4) +v.ch = "bar" +assert(v.ch[3] == 0) +assert(v.ch[2] == string.byte('r')) +assert(d[1] == string.byte('a')) + +ffi.cast('char*', 1) + +-- 2 arg form of ffi.copy +ffi.copy(d, 'bar') + +-- unsigned should be ignored for pointer rules +ffi.cdef[[ +int strncmp(const signed char *s1, const unsigned char *s2, size_t n); +]] +assert(ffi.C.strncmp("two", "three", 3) ~= 0) + +ffi.fill(d, 3, 1) +assert(d[2] == 1) +ffi.fill(d, 3) +assert(d[2] == 0) + +-- tests for __new +ffi.cdef[[ +struct newtest { + int a; + int b; + int c; +}; +]] +print("on line",debug.getinfo(1).currentline) +local tp = ffi.metatype("struct newtest", {__new = + function(tp, x, y, z) + tp = ffi.new(tp) + tp.a, tp.b, tp.c = x, y, z + return tp + end}) +local v = tp(1, 2, 3) +assert(v.a == 1 and v.b == 2 and v.c == 3) + +local tp = ffi.metatype("struct newtest", {__new = + function(tp, x, y, z) + tp = ffi.new(tp, {a = x, b = y, c = z}) + return tp + end}) +local v = tp(1, 2, 3) +assert(v.a == 1 and v.b == 2 and v.c == 3) + +-- tests for __pairs and __ipairs; not iterating just testing what is returned +local tp = ffi.metatype("struct newtest", + {__pairs = function(tp) return tp.a, tp.b end, __ipairs = function(tp) return tp.b, tp.c end} +) +if _VERSION ~= 'Lua 5.1' then + local v = tp(1, 2, 3) + x, y = pairs(v) + assert(x == 1 and y == 2) + x, y = ipairs(v) + assert(x == 2 and y == 3) +end +print("on line",debug.getinfo(1).currentline) +-- test for pointer to struct having same metamethods +local st = ffi.cdef "struct ptest {int a, b;};" +local tp = ffi.metatype("struct ptest", {__index = function(s, k) return k end, __len = function(s) return 3 end}) + +local a = tp(1, 2) +assert(a.banana == "banana") +assert(#a == 3) +local b = ffi.new("int[2]") +local c = ffi.cast("struct ptest *", b) +assert(c.banana == "banana") -- should have same methods +assert(#c == 3) +print("on line",debug.getinfo(1).currentline) + +ffi.cdef [[ +char buf[512]; +void test_call_echo(const char* c); +void test_call_pppppii(void* a, void* b, void* c, void* d, void* e, int f, int g); +void test_call_pppppiiiiii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, int i3, int i4, int i5, int i6); +void test_call_pppppffffff(void* p1, void* p2, void* p3, void* p4, void* p5, float f1, float f2, float f3, float f4, float f5, float f6); +void test_call_pppppiifiii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, float f3, int i4, int i5, int i6); +void test_call_pppppiiifii(void* p1, void* p2, void* p3, void* p4, void* p5, int i1, int i2, int i3, float i4, int i5, int i6); +]] + +for _, c in pairs(dlls) do + c.test_call_echo("input") + assert(c.buf == "input") + + local function ptr(x) return ffi.new('void*', x) end + + c.test_call_pppppii(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6, 7) + assert(c.buf == "1 2 3 4 5 6 7") + + c.test_call_pppppiiiiii(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6, 7, 8, 9, 10, 11) + assert(c.buf == "1 2 3 4 5 6 7 8 9 10 11") + + c.test_call_pppppffffff(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6.5, 7.5, 8.5, 9.5, 10.5, 11.5) + assert(c.buf == "1 2 3 4 5 6.5 7.5 8.5 9.5 10.5 11.5") + + c.test_call_pppppiifiii(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6, 7, 8.5, 9, 10, 11) + assert(c.buf == "1 2 3 4 5 6 7 8.5 9 10 11") + + c.test_call_pppppiiifii(ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), 6, 7, 8, 9.5, 10, 11) + assert(c.buf == "1 2 3 4 5 6 7 8 9.5 10 11") + + + local sum = c.add_dc(ffi.new('complex', 1, 2), ffi.new('complex', 3, 5)) + assert(ffi.istype('complex', sum)) + + sum = c.add_fc(ffi.new('complex float', 1, 2), ffi.new('complex float', 3, 5)) + assert(ffi.istype('complex float', sum)) + +end + +ffi.cdef [[ +struct Arrays { + int ints[3]; + unsigned int uints[3]; +}; +struct ArrayOfArrays { + struct Arrays arrays[3]; +}; +]] + +local struct = ffi.new('struct Arrays') +local structOfStructs = ffi.new('struct ArrayOfArrays') +for i=0,2 do + struct.ints[i] = i + struct.uints[i] = i + structOfStructs.arrays[0].ints[i] = i +end +for i=0,2 do + assert(struct.ints[i] == i) + assert(struct.uints[i] == i) + assert(structOfStructs.arrays[0].ints[i] == i) +end + +-- Test ffi.string +local buf = ffi.new('char[5]') +ffi.fill(buf, 4, 97) +buf[4] = 0 + +assert(ffi.string(buf) == 'aaaa') +assert(ffi.string(buf, 4) == 'aaaa') +assert(ffi.string(buf, 2) == 'aa') +assert(ffi.string(buf, 0) == '') +assert(ffi.string(buf, ffi.new('long long', 2)) == 'aa') +assert(ffi.string(buf, ffi.new('int', 2)) == 'aa') + +-- Test io.tmpfile() +ffi.cdef [[ + int fprintf ( FILE * stream, const char * format, ... ); +]] +local f = io.tmpfile() +ffi.C.fprintf(f, "test: %s\n", "foo") + +f:seek("set", 0) +local str = f:read('*l') +assert(str == 'test: foo', str) +f:close() + +print("on line",debug.getinfo(1).currentline) +--long arg Callback test + +function printArgs(...) + local t={} + for i, v in ipairs(table.pack(...)) do + t[i]=tostring(v); + end + return table.concat(t,',') +end + +local test_func=ffi.new("const char* (*)(int8_t,int16_t,complex float)",printArgs) +assert(ffi.string(test_func(1,2,ffi.new("complex float",7,8)))=="1,2,7+8i") +test_func:free() +test_func=ffi.new("const char* (*)(int8_t,int16_t,int,complex float)",printArgs) +assert(ffi.string(test_func(1,2,6,ffi.new("complex float",7,8)))=="1,2,6,7+8i") +test_func:free() +test_func=ffi.new("const char* (*)(int8_t,int16_t,complex double)",printArgs) +assert(ffi.string(test_func(1,2,ffi.new("complex float",7,8)))=="1,2,7+8i") +test_func:free() +test_func=ffi.new("const char* (*)(int8_t,int16_t,int,complex double)",printArgs) +assert(ffi.string(test_func(1,2,6,ffi.new("complex float",7,8)))=="1,2,6,7+8i") +test_func:free() +test_func=ffi.new("const char* (*)(int8_t,int16_t,long,complex double,int8_t,int16_t,long,complex double,int8_t,int16_t,long,complex double,double,double,float)",printArgs) +local exp1="1,2,6,7+8i,1,2,6,7+8i,1,2,6,7+8i,9,9,4"; +local exp2="1,2,6,7+8i,1,2,6,7+8i,1,2,6,7+8i,9.0,9.0,4.0"; +local real=ffi.string(test_func(1,2,6,ffi.new("complex float",7,8),1,2,6,ffi.new("complex float",7,8),1,2,6,ffi.new("complex float",7,8),9,9,4)); +if(not (real==exp1 or real==exp2))then + check(real,exp1) + check(real,exp2) +end +test_func:free() +print('Test PASSED') diff --git a/texk/web2c/luatexdir/luatex.c b/texk/web2c/luatexdir/luatex.c index 63fec84360..413ddfd77e 100644 --- a/texk/web2c/luatexdir/luatex.c +++ b/texk/web2c/luatexdir/luatex.c @@ -32,9 +32,9 @@ stick to "0" upto "9" so users can expect a number represented as string. */ -int luatex_version = 119; -int luatex_revision = '4'; -const char *luatex_version_string = "1.19.4"; +int luatex_version = 120; +int luatex_revision = '0'; +const char *luatex_version_string = "1.20.0"; const char *engine_name = my_name; #include diff --git a/texk/web2c/luatexdir/luatex_svnversion.h b/texk/web2c/luatexdir/luatex_svnversion.h index 9c1feb3d39..e88e01b487 100644 --- a/texk/web2c/luatexdir/luatex_svnversion.h +++ b/texk/web2c/luatexdir/luatex_svnversion.h @@ -1,4 +1,4 @@ #ifndef luatex_svn_revision_h #define luatex_svn_revision_h -#define luatex_svn_revision 7633 +#define luatex_svn_revision 7635 #endif