📄 ljitlib.c
字号:
/*** Lua library for the JIT engine.** Copyright (C) 2005-2008 Mike Pall. See Copyright Notice in luajit.h*/#include <stdio.h>#include <string.h>#define ljitlib_c#define LUA_LIB#include "lua.h"#include "lauxlib.h"#include "luajit.h"#include "lualib.h"/* This file is not a pure C API user. Some internals are required. */#include "lobject.h"#include "lstate.h"#include "lstring.h"#include "ltable.h"#include "lfunc.h"#include "lgc.h"#include "lopcodes.h"#include "ljit.h"#include "ljit_hints.h"#define STRING_HINTS#include "ljit_hints.h"/* ------------------------------------------------------------------------ *//* Static pointer addresses used as registry keys. *//* The values do not matter, but must be different to prevent joining. */static const int regkey_frontend = 0x6c6a6c01;static const int regkey_comthread = 0x6c6a6c02;/* Check that the first argument is a Lua function and return its closure. */static Closure *check_LCL(lua_State *L){ StkId o = L->base; switch (lua_type(L, 1)) { case LUA_TBOOLEAN: o = (L->ci-1)->func; case LUA_TFUNCTION: if (isLfunction(o)) return clvalue(o); break; } luaL_argerror(L, 1, "Lua function expected"); return NULL;}/* Create a new closure from a prototype. *//* Note: upvalues are assumed to be after first two slots. */static void push_LCL(lua_State *L, Proto *pt, Table *env){ Closure *cl; int i, nup = pt->nups; /* Adjust the number of stack slots to the number of upvalues. */ luaL_checkstack(L, nup, "too many upvalues"); lua_settop(L, 2+nup); /* Create a closure from the subroutine prototype. */ cl = luaF_newLclosure(L, nup, env); cl->l.p = pt; /* Allocate new upvalues and close them. */ for (i = 0; i < nup; i++) cl->l.upvals[i] = luaF_findupval(L, L->base + (2+i)); luaF_close(L, L->base + 2); lua_settop(L, 2); /* Remove upvalues. */ setclvalue(L, L->top++, cl); /* Return closure on top of stack. */ luaC_checkGC(L);}/* ------------------------------------------------------------------------ *//* Set JIT mode for the engine or a closure and/or its subroutines. */static int setmode(lua_State *L, int mode){ int idx = 0; switch (lua_type(L, 1)) { case LUA_TNONE: /* jit.on/off() */ case LUA_TNIL: /* jit.on/off(nil) */ luaJIT_setmode(L, 0, mode | LUAJIT_MODE_ENGINE); break; case LUA_TFUNCTION: /* jit.on/off(func, nil|true|false) */ idx = 1; case LUA_TBOOLEAN: /* jit.on/off(true, nil|true|false) (parent frame) */ if (lua_isboolean(L, 2)) mode |= lua_toboolean(L, 2)?LUAJIT_MODE_ALLFUNC:LUAJIT_MODE_ALLSUBFUNC; else mode |= LUAJIT_MODE_FUNC; if (luaJIT_setmode(L, idx, mode) == 1) /* Ok? */ break; default: luaL_argerror(L, 1, "Lua function expected"); break; } return 0;}/* Set JIT mode to on: (re-)enable compilation. */static int j_on(lua_State *L){ return setmode(L, LUAJIT_MODE_ON);}/* Set JIT mode to off: disable compilation. */static int j_off(lua_State *L){ return setmode(L, LUAJIT_MODE_OFF);}/* Set JIT debug level. Defaults to maximum level for use with -j. */static int j_debug(lua_State *L){ luaJIT_setmode(L, luaL_optinteger(L, 1, 100), LUAJIT_MODE_DEBUG); return 0;}/* ------------------------------------------------------------------------ *//* Report the compilation status. */static int compstatus(lua_State *L, int status){ if (status == -1) return luaL_argerror(L, 1, "Lua function expected"); else if (status == JIT_S_OK) return 0; else { lua_pushinteger(L, status); return 1; }}/* Compile a function. Pass typical args to help the optimizer. */static int j_compile(lua_State *L){ int nargs = lua_gettop(L) - 1; return compstatus(L, nargs >= 0 ? luaJIT_compile(L, nargs) : -1);}/* Recursively compile all subroutine prototypes. */static int rec_compile(lua_State *L, Proto *pt, Table *env, int stoponerror){ int rstatus = JIT_S_OK; int i; for (i = 0; i < pt->sizep; i++) { Proto *pti = pt->p[i]; int status; push_LCL(L, pti, env); /* Assumes stack is at 2 (no upvalues). */ status = luaJIT_compile(L, 0); lua_settop(L, 2); /* Clear stack */ if (status != JIT_S_OK) { rstatus = status; if (stoponerror) break; } status = rec_compile(L, pti, env, stoponerror); if (status != JIT_S_OK) { rstatus = status; if (stoponerror) break; } } return rstatus;}/* Compile all subroutines of a function. *//* Note: the function itself is _not_ compiled (use jit.compile()). */static int j_compilesub(lua_State *L){ Closure *cl = check_LCL(L); int stoponerror = lua_toboolean(L, 2); /* Stop on first error? */ lua_settop(L, 2); return compstatus(L, rec_compile(L, cl->l.p, cl->l.env, stoponerror));}/* jit.* functions. */static const luaL_Reg jitlib[] = { { "on", j_on }, { "off", j_off }, { "debug", j_debug }, { "compile", j_compile }, { "compilesub", j_compilesub }, /* j_attach is added below. */ { NULL, NULL }};/* ------------------------------------------------------------------------ *//* Get the compiler pipeline table from an upvalue (j_attach, j_frontend). */#define COMPIPE lua_upvalueindex(1)/* Attach/detach handler to/from compiler pipeline. */static int j_attach(lua_State *L){ int pipesz; luaL_checktype(L, 1, LUA_TFUNCTION); pipesz = lua_objlen(L, COMPIPE); if (lua_isnoneornil(L, 2)) { /* Detach if no priority given. */ int i; for (i = 1; i <= pipesz; i += 2) { lua_rawgeti(L, COMPIPE, i); if (lua_rawequal(L, 1, -1)) { /* Found: delete from pipeline. */ for (; i+2 <= pipesz; i++) { /* Shift down. */ lua_rawgeti(L, COMPIPE, i+2); lua_rawseti(L, COMPIPE, i); } /* Clear last two elements. */ lua_pushnil(L); lua_rawseti(L, COMPIPE, i); lua_pushnil(L); lua_rawseti(L, COMPIPE, i+1); return 0; } lua_pop(L, 1); } return 0; /* Not found: ignore detach request. */ } else { /* Attach if priority given. */ int prio = luaL_checkint(L, 2); int pos, i; for (pos = 2; pos <= pipesz; pos += 2) { lua_rawgeti(L, COMPIPE, pos); if (prio > (int)lua_tointeger(L, -1)) break; /* Insertion point found. */ lua_pop(L, 1); } for (i = pipesz+2; i > pos; i--) { /* Shift up. */ lua_rawgeti(L, COMPIPE, i-2); lua_rawseti(L, COMPIPE, i); } /* Set handler and priority. */ lua_pushvalue(L, 1); lua_rawseti(L, COMPIPE, i-1); lua_pushvalue(L, 2); lua_rawseti(L, COMPIPE, i); return 0; }}/* Compiler frontend. Runs in the compiler thread. *//* First and only arg is the compiler state table. */static int j_frontend(lua_State *L){ int status = JIT_S_OK; int pos; /* Loop through all handlers in the compiler pipeline. */ for (pos = 1; ; pos += 2) { if (status != JIT_S_OK) { /* Pending failure? */ int prio; lua_rawgeti(L, COMPIPE, pos+1); /* Must check for odd/even priority. */ if (lua_isnil(L, -1)) break; /* End of pipeline. */ prio = (int)lua_tointeger(L, -1); lua_pop(L, 1); if ((prio & 1) == 0) continue; /* Skip handlers with even priority. */ } /* Call handler with compiler state table and optional failure status. */ lua_rawgeti(L, COMPIPE, pos); if (lua_isnil(L, -1)) break; /* End of pipeline. */ lua_pushvalue(L, 1); if (status != JIT_S_OK) lua_pushinteger(L, status); lua_call(L, status ? 2 : 1, 1); if (!lua_isnil(L, -1)) /* Remember failure status. */ status = (int)lua_tointeger(L, -1); lua_pop(L, 1); } lua_pushinteger(L, status); return 1;}/* Compiler frontend wrapper. */static int frontwrap(lua_State *L, Table *st){ jit_State *J = G(L)->jit_state; lua_State *JL; int status; /* Allocate compiler thread on demand. */ if (J->L == NULL) { if (!lua_checkstack(L, 3)) return JIT_S_COMPILER_ERROR; sethvalue(L, L->top++, st); /* Prevent GC of state table. */ lua_pushlightuserdata(L, (void *)®key_comthread); /* Cannot use C stack, since it's deallocated early in Coco. */ /* But we don't need one -- the compiler thread never yields, anyway. */ J->L = lua_newthread(L); lua_rawset(L, LUA_REGISTRYINDEX); L->top--; /* Remove state table from this stack. */ } JL = J->L; /* Initialize compiler thread stack with frontend and state table. */ lua_settop(JL, 0); lua_pushlightuserdata(JL, (void *)®key_frontend); lua_rawget(JL, LUA_REGISTRYINDEX); sethvalue(JL, JL->top, st); JL->top++; /* Start the frontend by resuming the compiler thread. */ if (lua_resume(JL, 1) != 0) { /* Failed? */ /* Note: LUA_YIELD is treated like any other error. */ J->L = NULL; /* Get a new thread next time. */ fprintf(stderr, "[LuaJIT frontend failed: %s]\n", lua_isstring(JL, -1) ? lua_tostring(JL, -1) : "(unknown error)"); return JIT_S_COMPILER_ERROR; } /* Get status from terminated thread. */ status = (int)lua_tointeger(JL, -1); lua_settop(JL, 0); /* Help the GC. */ return status;}/* Create the compiler pipeline and register it. */static void makepipeline(lua_State *L){ lua_createtable(L, 20, 0); /* 10 handlers+priorities should be enough. */ lua_pushcfunction(L, luaJIT_backend); lua_rawseti(L, -2, 1); lua_pushinteger(L, 0); /* Fill in the backend at prio 0. */ lua_rawseti(L, -2, 2); /* Store the compiler frontend in the registry. */ lua_pushlightuserdata(L, (void *)®key_frontend);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -