issue #139 work in progress

lua54
Dibyendu Majumdar 6 years ago
parent caf59c84a7
commit 157bc43162

@ -3,6 +3,7 @@
struct lua_State;
typedef unsigned char lu_byte;
typedef signed char ls_byte;
typedef int (*lua_CFunction) (struct lua_State *L);
#if 1 /* 64bit */
@ -36,7 +37,7 @@ union Value {
struct TValue {
union Value value_;
int tt_;
lu_byte tt_;
};
struct TString {
@ -141,6 +142,7 @@ struct Proto {
struct LClosure *cache; /* last created closure with this prototype */
struct TString *source; /* used for debug information */
struct GCObject *gclist;
lu_byte cachemiss;
struct RaviJITProto ravi_jit;
};
@ -171,18 +173,15 @@ union Closure {
struct LClosure l;
};
union TKey {
struct {
union Node {
struct NodeKey {
union Value value_;
int tt_;
int next; /* for chaining (offset for next node) */
} nk;
struct TValue tvk;
};
struct Node {
struct TValue i_val;
union TKey i_key;
lu_byte tt_;
lu_byte key_tt; /* key type */
int next; /* for chaining */
union Value key_val; /* key value */
} u;
struct TValue i_val; /* direct access to node's value as a proper 'TValue' */
};
struct RaviArray {
@ -192,7 +191,6 @@ struct RaviArray {
unsigned int size; /* amount of memory allocated */
};
struct Table {
struct GCObject *next;
lu_byte tt;
@ -201,8 +199,8 @@ struct Table {
lu_byte lsizenode; /* log2 of size of 'node' array */
unsigned int sizearray; /* size of 'array' array */
struct TValue *array; /* array part */
struct Node *node;
struct Node *lastfree; /* any free position is before this position */
union Node *node;
union Node *lastfree; /* any free position is before this position */
struct Table *metatable;
struct GCObject *gclist;
struct RaviArray ravi_array;
@ -304,12 +302,14 @@ struct lua_State {
/* lfunc.h */
struct UpVal {
struct GCObject *next;
lu_byte tt;
lu_byte marked;
struct TValue *v; /* points to stack or to its own value */
lu_mem refcount; /* reference counter */
union {
struct { /* (when open) */
struct UpVal *next; /* linked list */
int touched; /* mark to avoid cycles with dead threads */
struct UpVal **previous;
} open;
struct TValue value; /* the value (when closed) */
} u;
@ -332,11 +332,26 @@ union GCUnion {
#define rttype(o) ((o)->tt_)
#define BIT_ISCOLLECTABLE (1 << 6)
#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE)
#define upisopen(up) ((up)->v != &(up)->u.value)
#define bitmask(b) (1<<(b))
#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2))
#define testbits(x,m) ((x) & (m))
#define testbit(x,b) testbits(x, bitmask(b))
#define WHITE0BIT 3 /* object is white (type 0) */
#define WHITE1BIT 4 /* object is white (type 1) */
#define BLACKBIT 5 /* object is black */
#define FINALIZEDBIT 6 /* object has been marked for finalization */
#define TESTGRAYBIT 7 /* used by tests (luaL_checkmemory) */
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
#define isblack(x) testbit((x)->marked, BLACKBIT)
#define iswhite(x) testbits((x)->marked, WHITEBITS)
#define val_(o) ((o)->value_)
#define cast(t, exp) ((t)(exp))
#define cast_u(o) cast(union GCUnion *, (o))
#define gco2t(o) &((cast_u(o))->h)
#define hvalue(o) gco2t(val_(o).gc)
#define gcvalue(o) (val_(o).gc)
#endif

@ -6,12 +6,9 @@ extern void luaC_upvalbarrier_ (struct lua_State *L, struct UpVal *uv);
void luaV_op_call(struct lua_State *L, struct LClosure *cl, struct TValue *ra, int b, int c) {
struct UpVal *uv = cl->upvals[b];
uv->v->tt_ = ra->tt_;
uv->v->value_.n = ra->value_.n;
int b1 = iscollectable(uv->v);
uv->u.value.tt_ = 1;
struct TValue *value = &uv->u.value;
int b2 = uv->v != value;
if (b1 && !b2)
int ra_iscollectable = iscollectable(ra);
int uv_isblack = isblack(uv);
int rav_iswhite = iswhite(gcvalue(ra));
if (ra_iscollectable && uv_isblack && rav_iswhite)
luaC_upvalbarrier_(L,uv);
}

@ -1,83 +1,78 @@
; ModuleID = 'lua_upval.c'
target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
target triple = "i686-pc-windows-gnu"
source_filename = "lua_upval.c"
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
%struct.lua_State = type { %struct.GCObject*, i8, i8, i8, %struct.TValue*, %struct.global_State*, %struct.CallInfoLua*, i32*, %struct.TValue*, %struct.TValue*, %struct.UpVal*, %struct.GCObject*, %struct.lua_State*, %struct.lua_longjmp*, %struct.CallInfo, void (%struct.lua_State*, %struct.lua_Debug*)*, i64, i32, i32, i32, i16, i16, i8, i8 }
%struct.lua_State = type { %struct.GCObject*, i8, i8, i8, %struct.TValue*, %struct.global_State*, %struct.CallInfoLua*, i32*, %struct.TValue*, %struct.TValue*, %struct.UpVal*, %struct.GCObject*, %struct.lua_State*, %struct.lua_longjmp*, %struct.CallInfo, void (%struct.lua_State*, %struct.lua_Debug*)*, i64, i32, i32, i32, i16, i16, i8, i8, i16 }
%struct.global_State = type opaque
%struct.CallInfoLua = type { %struct.TValue*, %struct.TValue*, %struct.CallInfo*, %struct.CallInfo*, %struct.CallInfoL, i64, i16, i8, i8 }
%struct.CallInfoLua = type { %struct.TValue*, %struct.TValue*, %struct.CallInfo*, %struct.CallInfo*, %struct.CallInfoL, i64, i16, i8, i8, i16 }
%struct.CallInfoL = type { %struct.TValue*, i32*, i64 }
%struct.UpVal = type { %struct.TValue*, i64, %union.anon.0 }
%union.anon.0 = type { %struct.TValue }
%struct.TValue = type { %union.Value, i32 }
%union.Value = type { i64 }
%struct.UpVal = type { %struct.GCObject*, i8, i8, %struct.TValue*, %union.anon.0 }
%union.anon.0 = type { %struct.anon }
%struct.anon = type { %struct.UpVal*, %struct.UpVal** }
%struct.GCObject = type { %struct.GCObject*, i8, i8 }
%struct.lua_longjmp = type opaque
%struct.CallInfo = type { %struct.TValue*, %struct.TValue*, %struct.CallInfo*, %struct.CallInfo*, %union.anon, i64, i16, i8, i8 }
%union.anon = type { %struct.CallInfoC }
%struct.CallInfoC = type { i32 (%struct.lua_State*, i32, i64)*, i64, i64 }
%union.anon = type { %struct.CallInfoL }
%struct.lua_Debug = type opaque
%struct.LClosure = type { %struct.GCObject*, i8, i8, i8, %struct.GCObject*, %struct.Proto*, [1 x %struct.UpVal*] }
%struct.Proto = type { %struct.GCObject*, i8, i8, i8, i8, i8, i32, i32, i32, i32, i32, i32, i32, i32, %struct.TValue*, i32*, %struct.Proto**, i32*, %struct.LocVar*, %struct.Upvaldesc*, %struct.LClosure*, %struct.TString*, %struct.GCObject*, %struct.RaviJITProto }
%struct.LocVar = type { %struct.TString*, i32, i32, i32 }
%struct.Upvaldesc = type { %struct.TString*, i32, i8, i8 }
%struct.TString = type { %struct.GCObject*, i8, i8, i8, i32, i64, %struct.TString* }
%struct.Proto = type { %struct.GCObject*, i8, i8, i8, i8, i8, i32, i32, i32, i32, i32, i32, i32, i32, %struct.TValue*, i32*, %struct.Proto**, i32*, %struct.LocVar*, %struct.Upvaldesc*, %struct.LClosure*, %struct.TString*, %struct.GCObject*, i8, %struct.RaviJITProto }
%struct.LocVar = type { %struct.TString*, %struct.TString*, i32, i32, i8 }
%struct.Upvaldesc = type { %struct.TString*, %struct.TString*, i8, i8, i8 }
%struct.TString = type { %struct.GCObject*, i8, i8, i8, i8, i32, %union.anon.1 }
%union.anon.1 = type { i64 }
%struct.RaviJITProto = type { i8, i8*, i32 (%struct.lua_State*)* }
%struct.TValue = type { %union.Value, i8 }
%union.Value = type { %struct.GCObject* }
; Function Attrs: nounwind
define void @luaV_op_call(%struct.lua_State* %L, %struct.LClosure* nocapture readonly %cl, %struct.TValue* nocapture readonly %ra, i32 %b, i32 %c) #0 {
define void @luaV_op_call(%struct.lua_State* %L, %struct.LClosure* nocapture readonly %cl, %struct.TValue* nocapture readonly %ra, i32 %b, i32 %c) local_unnamed_addr #0 {
entry:
%arrayidx = getelementptr inbounds %struct.LClosure* %cl, i32 0, i32 6, i32 %b
%0 = load %struct.UpVal** %arrayidx, align 4, !tbaa !1
%tt_ = getelementptr inbounds %struct.TValue* %ra, i32 0, i32 1
%1 = load i32* %tt_, align 4, !tbaa !5
%v = getelementptr inbounds %struct.UpVal* %0, i32 0, i32 0
%2 = load %struct.TValue** %v, align 4, !tbaa !8
%tt_1 = getelementptr inbounds %struct.TValue* %2, i32 0, i32 1
store i32 %1, i32* %tt_1, align 4, !tbaa !5
%n = bitcast %struct.TValue* %ra to double*
%3 = load double* %n, align 8, !tbaa !11
%4 = bitcast %struct.UpVal* %0 to double**
%5 = load double** %4, align 4, !tbaa !8
store double %3, double* %5, align 8, !tbaa !11
%6 = load %struct.TValue** %v, align 4, !tbaa !8
%tt_6 = getelementptr inbounds %struct.TValue* %6, i32 0, i32 1
%7 = load i32* %tt_6, align 4, !tbaa !5
%and = and i32 %7, 64
%value = getelementptr inbounds %struct.UpVal* %0, i32 0, i32 2, i32 0
%tt_7 = getelementptr inbounds %struct.UpVal* %0, i32 0, i32 2, i32 0, i32 1
store i32 1, i32* %tt_7, align 4, !tbaa !5
%8 = load %struct.TValue** %v, align 4, !tbaa !8
%cmp = icmp ne %struct.TValue* %8, %value
%tobool = icmp eq i32 %and, 0
%or.cond = or i1 %tobool, %cmp
br i1 %or.cond, label %if.end, label %if.then
%idxprom = sext i32 %b to i64
%arrayidx = getelementptr inbounds %struct.LClosure, %struct.LClosure* %cl, i64 0, i32 6, i64 %idxprom
%0 = load %struct.UpVal*, %struct.UpVal** %arrayidx, align 8, !tbaa !1
%tt_ = getelementptr inbounds %struct.TValue, %struct.TValue* %ra, i64 0, i32 1
%1 = load i8, i8* %tt_, align 8, !tbaa !5
%2 = and i8 %1, 64
%marked = getelementptr inbounds %struct.UpVal, %struct.UpVal* %0, i64 0, i32 2
%3 = load i8, i8* %marked, align 1, !tbaa !7
%4 = and i8 %3, 32
%gc = getelementptr inbounds %struct.TValue, %struct.TValue* %ra, i64 0, i32 0, i32 0
%5 = load %struct.GCObject*, %struct.GCObject** %gc, align 8, !tbaa !1
%marked3 = getelementptr inbounds %struct.GCObject, %struct.GCObject* %5, i64 0, i32 2
%6 = load i8, i8* %marked3, align 1, !tbaa !9
%7 = and i8 %6, 24
%tobool = icmp ne i8 %2, 0
%tobool6 = icmp ne i8 %4, 0
%or.cond = and i1 %tobool, %tobool6
%tobool8 = icmp ne i8 %7, 0
%or.cond9 = and i1 %or.cond, %tobool8
br i1 %or.cond9, label %if.then, label %if.end
if.then: ; preds = %entry
tail call void @luaC_upvalbarrier_(%struct.lua_State* %L, %struct.UpVal* %0) #2
br label %if.end
if.end: ; preds = %entry, %if.then
if.end: ; preds = %if.then, %entry
ret void
}
declare void @luaC_upvalbarrier_(%struct.lua_State*, %struct.UpVal*) #1
declare void @luaC_upvalbarrier_(%struct.lua_State*, %struct.UpVal*) local_unnamed_addr #1
attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind }
!llvm.ident = !{!0}
!0 = metadata !{metadata !"clang version 3.6.0 (trunk)"}
!1 = metadata !{metadata !2, metadata !2, i64 0}
!2 = metadata !{metadata !"any pointer", metadata !3, i64 0}
!3 = metadata !{metadata !"omnipotent char", metadata !4, i64 0}
!4 = metadata !{metadata !"Simple C/C++ TBAA"}
!5 = metadata !{metadata !6, metadata !7, i64 8}
!6 = metadata !{metadata !"TValue", metadata !3, i64 0, metadata !7, i64 8}
!7 = metadata !{metadata !"int", metadata !3, i64 0}
!8 = metadata !{metadata !9, metadata !2, i64 0}
!9 = metadata !{metadata !"UpVal", metadata !2, i64 0, metadata !10, i64 8, metadata !3, i64 16}
!10 = metadata !{metadata !"long long", metadata !3, i64 0}
!11 = metadata !{metadata !12, metadata !12, i64 0}
!12 = metadata !{metadata !"double", metadata !3, i64 0}
!0 = !{!"clang version 4.0.0 (tags/RELEASE_400/final)"}
!1 = !{!2, !2, i64 0}
!2 = !{!"any pointer", !3, i64 0}
!3 = !{!"omnipotent char", !4, i64 0}
!4 = !{!"Simple C/C++ TBAA"}
!5 = !{!6, !3, i64 8}
!6 = !{!"TValue", !3, i64 0, !3, i64 8}
!7 = !{!8, !3, i64 9}
!8 = !{!"UpVal", !2, i64 0, !3, i64 8, !3, i64 9, !2, i64 16, !3, i64 24}
!9 = !{!10, !3, i64 9}
!10 = !{!"GCObject", !2, i64 0, !3, i64 8, !3, i64 9}

@ -29,23 +29,17 @@
#define MAXUPVAL 125
/* RAVI change; #define MAXUPVAL 255 */
#define upisopen(up) ((up)->v != &(up)->u.value)
#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v))
/*
** Upvalues for Lua closures
** maximum number of misses before giving up the cache of closures
** in prototypes
*/
struct UpVal {
TValue *v; /* points to stack or to its own value */
lu_mem refcount; /* reference counter */
union {
struct { /* (when open) */
UpVal *next; /* linked list */
int touched; /* mark to avoid cycles with dead threads */
} open;
TValue value; /* the value (when closed) */
} u;
};
#define upisopen(up) ((up)->v != &(up)->u.value)
#define MAXMISS 10
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
@ -54,6 +48,7 @@ LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems);
LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (lua_State *L, StkId level);
LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
/* The additional type argument is a Ravi extension */
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,

@ -25,25 +25,18 @@
*/
/* how much to allocate before next GC step */
#if !defined(GCSTEPSIZE)
/* ~100 small strings */
#define GCSTEPSIZE (cast_int(100 * sizeof(TString)))
#endif
/*
** Possible states of the Garbage Collector
*/
#define GCSpropagate 0
#define GCSatomic 1
#define GCSswpallgc 2
#define GCSswpfinobj 3
#define GCSswptobefnz 4
#define GCSswpend 5
#define GCScallfin 6
#define GCSpause 7
#define GCSenteratomic 1
#define GCSatomic 2
#define GCSswpallgc 3
#define GCSswpfinobj 4
#define GCSswptobefnz 5
#define GCSswpend 6
#define GCScallfin 7
#define GCSpause 8
#define issweepphase(g) \
@ -74,12 +67,16 @@
#define testbit(x,b) testbits(x, bitmask(b))
/* Layout for bit use in 'marked' field: */
#define WHITE0BIT 0 /* object is white (type 0) */
#define WHITE1BIT 1 /* object is white (type 1) */
#define BLACKBIT 2 /* object is black */
#define FINALIZEDBIT 3 /* object has been marked for finalization */
/* bit 7 is currently used by tests (luaL_checkmemory) */
/*
** Layout for bit use in 'marked' field. First three bits are
** used for object "age" in generational mode.
*/
#define WHITE0BIT 3 /* object is white (type 0) */
#define WHITE1BIT 4 /* object is white (type 1) */
#define BLACKBIT 5 /* object is black */
#define FINALIZEDBIT 6 /* object has been marked for finalization */
#define TESTGRAYBIT 7 /* used by tests (luaL_checkmemory) */
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
@ -92,7 +89,7 @@
#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT)
#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS)
#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow)))
#define isdeadm(ow,m) ((m) & (ow))
#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked)
#define changewhite(x) ((x)->marked ^= WHITEBITS)
@ -101,6 +98,35 @@
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
/* object age in generational mode */
#define G_NEW 0 /* created in current cycle */
#define G_SURVIVAL 1 /* created in previous cycle */
#define G_OLD0 2 /* marked old by frw. barrier in this cycle */
#define G_OLD1 3 /* first full cycle as old */
#define G_OLD 4 /* really old object (not to be visited) */
#define G_TOUCHED1 5 /* old object touched this cycle */
#define G_TOUCHED2 6 /* old object touched in previous cycle */
#define AGEBITS 7 /* all age bits (111) */
#define getage(o) ((o)->marked & AGEBITS)
#define setage(o,a) ((o)->marked = cast_byte(((o)->marked & (~AGEBITS)) | a))
#define isold(o) (getage(o) > G_SURVIVAL)
#define changeage(o,f,t) \
check_exp(getage(o) == (f), (o)->marked ^= ((f)^(t)))
/* Default Values for GC parameters */
#define LUAI_GENMAJORMUL 100
#define LUAI_GENMINORMUL 5
#define LUAI_GCPAUSE 100 /* 100% */
#define LUAI_GCMUL 10
/* how much to allocate before next GC step (log2) */
#define LUAI_GCSTEPSIZE 13 /* 8 KB */
/*
** Does one step of collection when debt becomes positive. 'pre'/'pos'
** allows some adjustments to be done only when needed. macro
@ -127,9 +153,8 @@
(isblack(p) && iswhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
#define luaC_upvalbarrier(L,uv) ( \
(iscollectable((uv)->v) && !upisopen(uv)) ? \
luaC_upvalbarrier_(L,uv) : cast_void(0))
#define luaC_protobarrier(L,p,o) \
(isblack(p) ? luaC_protobarrier_(L,p) : cast_void(0))
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
@ -139,9 +164,9 @@ LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o);
LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv);
LUAI_FUNC void luaC_protobarrier_ (lua_State *L, Proto *p);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv);
LUAI_FUNC void luaC_changemode (lua_State *L, int newmode);
#endif

@ -33,6 +33,7 @@ typedef long l_mem;
/* chars used as small naturals (so that 'char' is reserved for characters) */
typedef unsigned char lu_byte;
typedef signed char ls_byte;
/* maximum value for size_t */
@ -51,6 +52,13 @@ typedef unsigned char lu_byte;
#define MAX_INT INT_MAX /* maximum value of an int */
/*
** floor of the log2 of the maximum signed value for integral type 't'.
** (That is, maximum 'n' such that '2^n' fits in the given signed type.)
*/
#define log2maxs(t) (sizeof(t) * 8 - 2)
/*
** conversion of pointer to unsigned integer:
** this is for hashing only; there is no problem if the integer

@ -19,11 +19,11 @@
/*
** Extra tags for non-values
*/
#define LUA_TPROTO LUA_NUMTAGS /* function prototypes */
#define LUA_TDEADKEY (LUA_NUMTAGS+1) /* removed keys in tables */
#define LUA_TUPVAL LUA_NUMTAGS /* upvalues */
#define LUA_TPROTO (LUA_NUMTAGS+1) /* function prototypes */
/*
** number of all possible tags (including LUA_TNONE but excluding DEADKEY)
** number of all possible tags (including LUA_TNONE)
*/
#define LUA_TOTALTAGS (LUA_TPROTO + 2)
@ -124,6 +124,7 @@ typedef struct lua_TValue {
#define val_(o) ((o)->value_)
#define valraw(o) (&val_(o))
/* raw type tag of a TValue */
@ -133,7 +134,8 @@ typedef struct lua_TValue {
#define novariant(x) ((x) & 0x0F)
/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */
#define ttype(o) (rttype(o) & 0x3F)
#define ttyperaw(t) ((t) & 0x3F)
#define ttype(o) ttyperaw(rttype(o))
/* type tag of a TValue with no variants (bits 0-3) */
#define ttnov(o) (novariant(rttype(o)))
@ -169,7 +171,19 @@ typedef struct lua_TValue {
#define ttislcf(o) checktag((o), LUA_TLCF)
#define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA))
#define ttisthread(o) checktag((o), ctb(LUA_TTHREAD))
#define ttisdeadkey(o) checktag((o), LUA_TDEADKEY)
/*
** Macros to access unstructured values (may come both from
** 'TValue's and table keys)
*/
#define ivalueraw(v) ((v).i)
#define fltvalueraw(v) ((v).n)
#define gcvalueraw(v) ((v).gc)
#define pvalueraw(v) ((v).p)
#define tsvalueraw(v) (gco2ts((v).gc))
#define fvalueraw(v) ((v).f)
#define bvalueraw(v) ((v).b)
/* Macros to access values */
@ -188,8 +202,6 @@ typedef struct lua_TValue {
#define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc))
#define bvalue(o) check_exp(ttisboolean(o), val_(o).b)
#define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc))
/* a dead value may get the 'gc' field, but cannot access its contents */
#define deadvalue(o) check_exp(ttisdeadkey(o), cast(void *, val_(o).gc))
#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
@ -197,6 +209,12 @@ typedef struct lua_TValue {
#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE)
/*
** Protected access to objects in values
*/
#define gcvalueN(o) (iscollectable(o) ? gcvalue(o) : NULL)
/* Macros for internal tests */
#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt)
@ -277,12 +295,9 @@ typedef struct lua_TValue {
val_(io).gc = obj2gco(x_); settt_(io, ctb(RAVI_TFARRAY)); \
checkliveness(L,io); }
#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY)
#define setobj(L,obj1,obj2) \
{ TValue *io1=(obj1); *io1 = *(obj2); \
{ TValue *io1=(obj1); const TValue *io2=(obj2); \
io1->value_ = io2->value_; io1->tt_ = io2->tt_; \
(void)L; checkliveness(L,io1); }
@ -296,15 +311,16 @@ typedef struct lua_TValue {
#define setobj2s setobj
#define setsvalue2s setsvalue
#define sethvalue2s sethvalue
#define setthvalue2s setthvalue
#define setptvalue2s setptvalue
#define setclLvalue2s setclLvalue
/* from table to same table */
#define setobjt2t setobj
/* to new object */
#define setobj2n setobj
#define setsvalue2n setsvalue
/* to table (define it as an expression to be used in macros) */
#define setobj2t(L,o1,o2) ((void)L, *(o1)=*(o2), checkliveness(L,(o1)))
/* to table */
#define setobj2t setobj
@ -494,6 +510,7 @@ typedef struct Proto {
struct LClosure *cache; /* last-created closure with this prototype */
TString *source; /* used for debug information */
GCObject *gclist;
lu_byte cachemiss; /* count for successive misses for 'cache' field */
/* RAVI extension */
RaviJITProto ravi_jit;
} Proto;
@ -501,9 +518,20 @@ typedef struct Proto {
/*
** Lua Upvalues
** Upvalues for Lua closures
*/
typedef struct UpVal UpVal;
typedef struct UpVal {
CommonHeader;
TValue *v; /* points to stack or to its own value */
union {
struct { /* (when open) */
struct UpVal *next; /* linked list */
struct UpVal **previous;
} open;
TValue value; /* the value (when closed) */
} u;
} UpVal;
/*
@ -542,26 +570,38 @@ typedef union Closure {
** Tables
*/
typedef union TKey {
struct {
TValuefields;
int next; /* for chaining (offset for next node) */
} nk;
TValue tvk;
} TKey;
/*
** Nodes for Hash tables. A pack of two TValue's (key-value pairs)
** plus a 'next' field to link colliding entries. The distribuition
** of the key's fields ('key_tt' and 'key_val') not forming a proper
** 'TValue' allows for a smaller size for 'Node' both in 4-byte
** and 8-byte alignments.
*/
typedef union Node {
struct NodeKey {
TValuefields; /* fields for value */
lu_byte key_tt; /* key type */
int next; /* for chaining */
Value key_val; /* key value */
} u;
TValue i_val; /* direct access to node's value as a proper 'TValue' */
} Node;
/* copy a value into a key without messing up field 'next' */
#define setnodekey(L,key,obj) \
{ TKey *k_=(key); const TValue *io_=(obj); \
k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \
/* copy a value into a key */
#define setnodekey(L,node,obj) \
{ Node *n_=(node); const TValue *io_=(obj); \
n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; \
(void)L; checkliveness(L,io_); }
typedef struct Node {
TValue i_val;
TKey i_key;
} Node;
/* copy a value from a key */
#define getnodekey(L,obj,node) \
{ TValue *io_=(obj); const Node *n_=(node); \
io_->value_ = n_->u.key_val; io_->tt_ = n_->u.key_tt; \
(void)L; checkliveness(L,io_); }
/** RAVI extension */
typedef enum RaviArrayModifer {
@ -597,6 +637,36 @@ typedef struct Table {
} Table;
/*
** Macros to manipulate keys inserted in nodes
*/
#define keytt(node) ((node)->u.key_tt)
#define keyval(node) ((node)->u.key_val)
#define keyisnil(node) (keytt(node) == LUA_TNIL)
#define keyisinteger(node) (keytt(node) == LUA_TNUMINT)
#define keyival(node) (keyval(node).i)
#define keyisshrstr(node) (keytt(node) == ctb(LUA_TSHRSTR))
#define keystrval(node) (gco2ts(keyval(node).gc))
#define setnilkey(node) (keytt(node) = LUA_TNIL)
#define keyiscollectable(n) (keytt(n) & BIT_ISCOLLECTABLE)
#define gckey(n) (keyval(n).gc)
#define gckeyN(n) (keyiscollectable(n) ? gckey(n) : NULL)
/*
** Use a "nil table" to mark dead keys in a table. Those keys serve
** only to keep space for removed entries, which may still be part of
** chains. Note that the 'keytt' does not have the BIT_ISCOLLECTABLE
** set, so these values are considered not collectable and are different
** from any valid value.
*/
#define setdeadkey(n) (keytt(n) = LUA_TTABLE, gckey(n) = NULL)
/*
** 'module' operation for hashing (size is always a power of 2)

@ -70,8 +70,8 @@ struct lua_longjmp; /* defined in ldo.c */
/* kinds of Garbage Collection */
#define KGC_NORMAL 0
#define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */
#define KGC_INC 0 /* incremental gc */
#define KGC_GEN 1 /* generational gc */
typedef struct stringtable {
@ -146,7 +146,6 @@ typedef struct global_State {
void *ud; /* auxiliary data to 'frealloc' */
l_mem totalbytes; /* number of bytes currently allocated - GCdebt */
l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
lu_mem GCmemtrav; /* memory traversed by the GC */
lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
stringtable strt; /* hash table for strings */
TValue l_registry;
@ -154,7 +153,13 @@ typedef struct global_State {
lu_byte currentwhite;
lu_byte gcstate; /* state of garbage collector */
lu_byte gckind; /* kind of GC running */
lu_byte genminormul; /* control for minor generational collections */
lu_byte genmajormul; /* control for major generational collections */
lu_byte gcrunning; /* true if GC is running */
lu_byte gcemergency; /* true if this is an emergency collection */
lu_byte gcpause; /* size of pause between successive GCs */
lu_byte gcstepmul; /* GC "speed" */
lu_byte gcstepsize; /* (log2 of) GC granularity */
GCObject *allgc; /* list of all collectable objects */
GCObject **sweepgc; /* current position of sweep in list */
GCObject *finobj; /* list of collectable objects with finalizers */
@ -163,12 +168,17 @@ typedef struct global_State {
GCObject *weak; /* list of tables with weak values */
GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
GCObject *allweak; /* list of all-weak tables */
GCObject *protogray; /* list of prototypes with "new" caches */
GCObject *tobefnz; /* list of userdata to be GC */
GCObject *fixedgc; /* list of objects not to be collected */
/* fields for generational collector */
GCObject *survival; /* start of objects that survived one GC cycle */
GCObject *old; /* start of old objects */
GCObject *reallyold; /* old objects with more than one cycle */
GCObject *finobjsur; /* list of survival objects with finalizers */
GCObject *finobjold; /* list of old objects with finalizers */
GCObject *finobjrold; /* list of really old objects with finalizers */
struct lua_State *twups; /* list of threads with open upvalues */
unsigned int gcfinnum; /* number of finalizers to call in each GC step */
int gcpause; /* size of pause between successive GCs */
int gcstepmul; /* GC 'granularity' */
lua_CFunction panic; /* to be called in unprotected errors */
struct lua_State *mainthread;
const lua_Number *version; /* pointer to version number */
@ -244,6 +254,7 @@ union GCUnion {
struct Table h;
struct Proto p;
struct lua_State th; /* thread */
struct UpVal upv;
};
@ -261,11 +272,11 @@ union GCUnion {
#define gco2t(o) check_exp(novariant((o)->tt) == LUA_TTABLE, &((cast_u(o))->h))
#define gco2p(o) check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p))
#define gco2th(o) check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th))
#define gco2upv(o) check_exp((o)->tt == LUA_TUPVAL, &((cast_u(o))->upv))
/* macro to convert a Lua object into a GCObject */
#define obj2gco(v) \
check_exp(novariant((v)->tt) < LUA_TDEADKEY, (&(cast_u(v)->gc)))
#define obj2gco(v) (&(cast_u(v)->gc))
/* actual number of total bytes allocated */

@ -12,18 +12,9 @@
#define gnode(t,i) (&(t)->node[i])
#define gval(n) (&(n)->i_val)
#define gnext(n) ((n)->i_key.nk.next)
#define gnext(n) ((n)->u.next)
/* 'const' to avoid wrong writings that can mess up field 'next' */
#define gkey(n) cast(const TValue*, (&(n)->i_key.tvk))
/*
** writable version of 'gkey'; allows updates to individual fields,
** but not to the whole (which has incompatible type)
*/
#define wgkey(n) (&(n)->i_key.nk)
#define invalidateTMcache(t) ((t)->flags = 0)
@ -35,9 +26,8 @@
#define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t))
/* returns the key, given the value of a table entry */
#define keyfromval(v) \
(gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val))))
/* returns the Node, given the value of a table entry */
#define nodefromval(v) cast(Node *, (v))
LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
@ -65,40 +55,22 @@ required to get to a node in the hash table
#else
#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
#define hashstr(t,str) hashpow2(t, (str)->hash)
#define hashboolean(t,p) hashpow2(t, p)
#define hashint(t,i) hashpow2(t, i)
/*
** for some types, it is better to avoid modulus by power of 2, as
** they tend to have many 2 factors.
*/
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
#define hashpointer(t,p) hashmod(t, point2uint(p))
#endif
#if defined(RAVI_ENABLED)
/*
** search function for short strings
*/
static RAVI_ALWAYS_INLINE const TValue *luaH_getshortstr(Table *t, TString *key) {
Node *n = hashstr(t, key);
lua_assert(key->tt == LUA_TSHRSTR);
for (;;) { /* check whether 'key' is somewhere in the chain */
const TValue *k = gkey(n);
if (ttisshrstring(k) && eqshrstr(tsvalue(k), key))
return gval(n); /* that's it */
else {
int nx = gnext(n);
if (nx == 0)
return luaO_nilobject; /* not found */
n += nx;
}
}
}
#else
LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
#endif
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key);
@ -109,7 +81,7 @@ LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize);
LUAI_FUNC void luaH_free (lua_State *L, Table *t);
LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key);
LUAI_FUNC int luaH_getn (Table *t);
LUAI_FUNC lua_Unsigned luaH_getn (Table *t);
/* RAVI array specialization */

@ -318,8 +318,10 @@ LUA_API int (lua_isyieldable) (lua_State *L);
#define LUA_GCSETPAUSE 6
#define LUA_GCSETSTEPMUL 7
#define LUA_GCISRUNNING 9
#define LUA_GCGEN 10
#define LUA_GCINC 11
LUA_API int (lua_gc) (lua_State *L, int what, int data);
LUA_API int (lua_gc) (lua_State *L, int what, ...);
/*

@ -40,6 +40,14 @@
#define tonumber(o,n) \
(RAVI_LIKELY(ttisfloat(o)) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))
/* convert an object to a float (without string coercion) */
#define tonumberns(o,n) \
(ttisfloat(o) ? ((n) = fltvalue(o), 1) : \
(ttisinteger(o) ? ((n) = cast_num(ivalue(o)), 1) : 0))
/* convert an object to an integer (including string coercion) */
#define tointeger(o,i) \
(RAVI_LIKELY(ttisinteger(o)) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))
@ -50,10 +58,10 @@
/*
** fast track for 'gettable': if 't' is a table and 't[k]' is not nil,
** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise,
** return 0 (meaning it will have to check metamethod) with 'slot'
** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise).
** 'f' is the raw get function to use.
** return 1 with 'slot' pointing to 't[k]' (position of final result).
** Otherwise, return 0 (meaning it will have to check metamethod)
** with 'slot' pointing to a nil 't[k]' (if 't' is a table) or NULL
** (otherwise). 'f' is the raw get function to use.
*/
#define luaV_fastget(L,t,k,slot,f) \
(!ttistable(t) \
@ -61,41 +69,28 @@
: (slot = f(hvalue(t), k), /* else, do raw access */ \
!ttisnil(slot))) /* result not nil? */
/*
** standard implementation for 'gettable'
** RAVI change - renamed as we need luaV_gettable to be
** an exported function
** Special case of 'luaV_fastget' for integers, inlining the fast case
** of 'luaH_getint'.
*/
#define luaV_fastgettable(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
else luaV_finishget(L,t,k,v,slot); }
#define luaV_fastgeti(L,t,k,slot) \
(!ttistable(t) \
? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
: (slot = (l_castS2U(k) - 1u < hvalue(t)->sizearray) \
? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \
!ttisnil(slot))) /* result not nil? */
/*
** Fast track for set table. If 't' is a table and 't[k]' is not nil,
** call GC barrier, do a raw 't[k]=v', and return true; otherwise,
** return false with 'slot' equal to NULL (if 't' is not a table) or
** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro
** returns true, there is no need to 'invalidateTMcache', because the
** call is not creating a new entry.
** Finish a fast set operation (when fast get succeeds). In that case,
** 'slot' points to the place to put the value.
*/
#define luaV_fastset(L,t,k,slot,f,v) \
(!ttistable(t) \
? (slot = NULL, 0) \
: (slot = f(hvalue(t), k), \
ttisnil(slot) ? 0 \
: (luaC_barrierback(L, hvalue(t), v), \
setobj2t(L, cast(TValue *,slot), v), \
1)))
#define luaV_finishfastset(L,t,slot,v) \
{ setobj2t(L, cast(TValue *,slot), v); \
luaC_barrierback(L, hvalue(t), v); }
/*
** RAVI change - renamed as we need luaV_settable to be
** an exported function
*/
#define luaV_fastsettable(L,t,k,v) { const TValue *slot; \
if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
luaV_finishset(L,t,k,v,slot); }
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);

@ -168,6 +168,7 @@ struct LuaLLVMTypes {
llvm::PointerType *pGCObjectT;
llvm::StructType *ValueT;
llvm::StructType *ValueGCT;
llvm::StructType *TValueT;
llvm::PointerType *pTValueT;
llvm::StructType *TStringT;
@ -206,9 +207,6 @@ struct LuaLLVMTypes {
llvm::StructType *CClosureT;
llvm::PointerType *pCClosureT;
llvm::StructType *TKeyT;
llvm::PointerType *pTKeyT;
llvm::StructType *NodeT;
llvm::PointerType *pNodeT;
@ -230,7 +228,7 @@ struct LuaLLVMTypes {
llvm::FunctionType *jitFunctionT;
llvm::FunctionType *luaC_upvalbarrierT;
llvm::FunctionType *luaC_barrierT;
llvm::FunctionType *luaD_poscallT;
llvm::FunctionType *luaD_precallT;
llvm::FunctionType *luaD_callT;
@ -722,7 +720,7 @@ struct RaviFunctionDef {
llvm::Function *luaV_modF;
llvm::Function *luaV_divF;
llvm::Function *luaV_objlenF;
llvm::Function *luaC_upvalbarrierF;
llvm::Function *luaC_barrierF;
llvm::Function *luaH_getstrF;
llvm::Function *luaH_getintF;
llvm::Function *luaH_setintF;
@ -1067,10 +1065,6 @@ class RaviCodeGenerator {
llvm::Instruction *emit_load_upval_v(RaviFunctionDef *def,
llvm::Instruction *pupval);
// Get &upval->value -> result is TValue *
llvm::Value *emit_gep_upval_value(RaviFunctionDef *def,
llvm::Instruction *pupval);
// isnil(reg) || isboolean(reg) && reg.value == 0
// !(isnil(reg) || isboolean(reg) && reg.value == 0)
llvm::Value *emit_boolean_testfalse(RaviFunctionDef *def, llvm::Value *reg,
@ -1268,7 +1262,7 @@ class RaviCodeGenerator {
void emit_SETUPVAL(RaviFunctionDef *def, int A, int B, int pc);
void emit_GC_upvalbarrier(RaviFunctionDef *def, llvm::Instruction *upval, llvm::Value *v);
void emit_GC_barrier(RaviFunctionDef *def, llvm::Value *upval, llvm::Value *v);
void emit_SETUPVAL_Specific(RaviFunctionDef *def, int A, int B, int pc,
OpCode op, llvm::Function *f);

@ -129,7 +129,7 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
api_check(from, to->ci->top - to->top >= n, "stack overflow");
from->top -= n;
for (i = 0; i < n; i++) {
setobj2s(to, to->top, from->top + i);
setobjs2s(to, to->top, from->top + i);
to->top++; /* stack already checked by previous 'api_check' */
}
lua_unlock(to);
@ -670,14 +670,13 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L);
t = index2addr(L, idx);
if (ttisLtable(t) || !ttistable(t)) {
if (luaV_fastget(L, t, n, slot, luaH_getint)) {
if (luaV_fastgeti(L, t, n, slot)) {
setobj2s(L, L->top, slot);
api_incr_top(L);
}
else {
setivalue(L->top, n);
api_incr_top(L);
luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
TValue aux;
setivalue(&aux, n);
luaV_finishget(L, t, &aux, L->top, slot);
}
}
else {
@ -694,8 +693,8 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
setnilvalue(L->top);
}
}
api_incr_top(L);
}
api_incr_top(L);
lua_unlock(L);
return ttnov(L->top - 1);
}
@ -964,8 +963,10 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot;
TString *str = luaS_new(L, k);
api_checknelems(L, 1);
if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1))
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
luaV_finishfastset(L, t, slot, L->top - 1);
L->top--; /* pop value */
}
else {
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
api_incr_top(L);
@ -1007,13 +1008,13 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
api_checknelems(L, 1);
t = index2addr(L, idx);
if (ttisLtable(t) || !ttistable(t)) {
if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1))
L->top--; /* pop value */
if (luaV_fastgeti(L, t, n, slot)) {
luaV_finishfastset(L, t, slot, L->top - 1);
}
else {
setivalue(L->top, n);
api_incr_top(L);
luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
L->top -= 2; /* pop value and key */
TValue aux;
setivalue(&aux, n);
luaV_finishset(L, t, &aux, L->top - 1, slot);
}
}
else {
@ -1041,8 +1042,8 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
luaG_runerror(L, "value cannot be converted to integer");
}
}
L->top--;
}
L->top--; /* pop value */
lua_unlock(L);
}
@ -1324,7 +1325,7 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
setobj(L, f->upvals[0]->v, gt);
luaC_upvalbarrier(L, f->upvals[0]);
luaC_barrier(L, f->upvals[0], gt);
}
}
lua_unlock(L);
@ -1355,12 +1356,12 @@ LUA_API int lua_status (lua_State *L) {
/*
** Garbage-collection function
*/
LUA_API int lua_gc (lua_State *L, int what, int data) {
LUA_API int lua_gc (lua_State *L, int what, ...) {
va_list argp;
int res = 0;
global_State *g;
global_State *g = G(L);
lua_lock(L);
g = G(L);
va_start(argp, what);
switch (what) {
case LUA_GCSTOP: {
g->gcrunning = 0;
@ -1385,11 +1386,12 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
break;
}
case LUA_GCSTEP: {
int data = va_arg(argp, int);
l_mem debt = 1; /* =1 to signal that it did an actual step */
lu_byte oldrunning = g->gcrunning;
g->gcrunning = 1; /* allow GC to run */
if (data == 0) {
luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */
luaE_setdebt(g, 0); /* do a basic step */
luaC_step(L);
}
else { /* add 'data' to total debt */
@ -1403,22 +1405,42 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
break;
}
case LUA_GCSETPAUSE: {
res = g->gcpause;
g->gcpause = data;
int data = va_arg(argp, int);
res = g->gcpause + 100;
g->gcpause = (data >= 100) ? data - 100 : 0;
break;
}
case LUA_GCSETSTEPMUL: {
res = g->gcstepmul;
if (data < 40) data = 40; /* avoid ridiculous low values (and 0) */
g->gcstepmul = data;
int data = va_arg(argp, int);
res = g->gcstepmul * 10;
g->gcstepmul = data / 10;
break;
}
case LUA_GCISRUNNING: {
res = g->gcrunning;
break;
}
case LUA_GCGEN: {
int minormul = va_arg(argp, int);
int majormul = va_arg(argp, int);
g->genminormul = (minormul == 0) ? LUAI_GENMINORMUL : minormul;
g->genmajormul = (majormul == 0) ? LUAI_GENMAJORMUL : majormul;
luaC_changemode(L, KGC_GEN);
break;
}
case LUA_GCINC: {
int pause = va_arg(argp, int);
int stepmul = va_arg(argp, int);
int stepsize = va_arg(argp, int);
g->gcpause = (pause == 0) ? LUAI_GCPAUSE : pause;
g->gcstepmul = (stepmul == 0) ? LUAI_GCMUL : stepmul;
g->gcstepsize = (stepsize == 0) ? LUAI_GCSTEPSIZE : stepsize;
luaC_changemode(L, KGC_INC);
break;
}
default: res = -1; /* invalid option */
}
va_end(argp);
lua_unlock(L);
return res;
}
@ -1514,14 +1536,14 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
static const char *aux_upvalue (StkId fi, int n, TValue **val,
CClosure **owner, UpVal **uv, ravitype_t *type) {
GCObject **owner, UpVal **uv, ravitype_t *type) {
*type = RAVI_TANY;
switch (ttype(fi)) {
case LUA_TCCL: { /* C closure */
CClosure *f = clCvalue(fi);
if (!(1 <= n && n <= f->nupvalues)) return NULL;
*val = &f->upvalue[n-1];
if (owner) *owner = f;
if (owner) *owner = obj2gco(f);
return "";
}
case LUA_TLCL: { /* Lua closure */
@ -1530,7 +1552,7 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val,
Proto *p = f->p;
if (!(1 <= n && n <= p->sizeupvalues)) return NULL;
*val = f->upvals[n-1]->v;
if (uv) *uv = f->upvals[n - 1];
if (owner) *owner = obj2gco(f->upvals[n - 1]);
name = p->upvalues[n-1].name;
*type = p->upvalues[n - 1].ravi_type;
return (name == NULL) ? "(*no name)" : getstr(name);
@ -1558,7 +1580,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
const char *name;
TValue *val = NULL; /* to avoid warnings */
CClosure *owner = NULL;
GCObject *owner = NULL; /* to avoid warnings */
UpVal *uv = NULL;
StkId fi;
ravitype_t type; /* RAVI upvalue type will be obtained if possible */
@ -1590,8 +1612,7 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
if (name) {
L->top--;
setobj(L, val, L->top);
if (owner) { luaC_barrier(L, owner, L->top); }
else if (uv) { luaC_upvalbarrier(L, uv); }
luaC_barrier(L, owner, val);
}
lua_unlock(L);
return name;
@ -1635,13 +1656,8 @@ LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
ravitype_t t1, t2;
UpVal **up1 = getupvalref(L, fidx1, n1, &f1, &t1);
UpVal **up2 = getupvalref(L, fidx2, n2, NULL, &t2);
if (t1 == t2) {
luaC_upvdeccount(L, *up1);
*up1 = *up2;
(*up1)->refcount++;
if (upisopen(*up1)) (*up1)->u.open.touched = 1;
luaC_upvalbarrier(L, *up1);
}
*up1 = *up2;
luaC_objbarrier(L, f1, *up1);
}
/* API to set the output functions used by Lua / Ravi

@ -173,24 +173,51 @@ static int luaB_rawset (lua_State *L) {
static int luaB_collectgarbage (lua_State *L) {
static const char *const opts[] = {"stop", "restart", "collect",
"count", "step", "setpause", "setstepmul",
"isrunning", NULL};
"isrunning", "generational", "incremental", NULL};
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
LUA_GCISRUNNING};
LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC};
int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
int ex = (int)luaL_optinteger(L, 2, 0);
int res = lua_gc(L, o, ex);
switch (o) {
case LUA_GCCOUNT: {
int b = lua_gc(L, LUA_GCCOUNTB, 0);
lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024));
int k = lua_gc(L, o);
int b = lua_gc(L, LUA_GCCOUNTB);
lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024));
return 1;
}
case LUA_GCSTEP: case LUA_GCISRUNNING: {
case LUA_GCSTEP: {
int step = (int)luaL_optinteger(L, 2, 0);
int res = lua_gc(L, o, step);
lua_pushboolean(L, res);
return 1;
}
case LUA_GCSETPAUSE:
case LUA_GCSETSTEPMUL: {
int p = (int)luaL_optinteger(L, 2, 0);
int previous = lua_gc(L, o, p);
lua_pushinteger(L, previous);
return 1;
}
case LUA_GCISRUNNING: {
int res = lua_gc(L, o);
lua_pushboolean(L, res);
return 1;
}
case LUA_GCGEN: {
int minormul = (int)luaL_optinteger(L, 2, 0);
int majormul = (int)luaL_optinteger(L, 3, 0);
lua_gc(L, o, minormul, majormul);
return 0;
}
case LUA_GCINC: {
int pause = (int)luaL_optinteger(L, 2, 0);
int stepmul = (int)luaL_optinteger(L, 3, 0);
int stepsize = (int)luaL_optinteger(L, 4, 0);
lua_gc(L, o, pause, stepmul, stepsize);
return 0;
}
default: {
int res = lua_gc(L, o);
lua_pushinteger(L, res);
return 1;
}

@ -50,31 +50,34 @@ LClosure *luaF_newLclosure (lua_State *L, int n) {
void luaF_initupvals (lua_State *L, LClosure *cl) {
int i;
for (i = 0; i < cl->nupvalues; i++) {
UpVal *uv = luaM_new(L, UpVal);
uv->refcount = 1;
GCObject *o = luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o);
uv->v = &uv->u.value; /* make it closed */
setnilvalue(uv->v);
cl->upvals[i] = uv;
luaC_objbarrier(L, cl, o);
}
}
UpVal *luaF_findupval (lua_State *L, StkId level) {
UpVal **pp = &L->openupval;
GCObject *o;
UpVal *p;
UpVal *uv;
lua_assert(isintwups(L) || L->openupval == NULL);
while (*pp != NULL && (p = *pp)->v >= level) {
lua_assert(upisopen(p));
if (p->v == level) /* found a corresponding upvalue? */
while ((p = *pp) != NULL && uplevel(p) >= level) {
if (uplevel(p) == level && !isdead(G(L), p)) /* corresponding upvalue? */
return p; /* return it */
pp = &p->u.open.next;
}
/* not found: create a new upvalue */
uv = luaM_new(L, UpVal);
uv->refcount = 0;
uv->u.open.next = *pp; /* link it to list of open upvalues */
uv->u.open.touched = 1;
/* not found: create a new upvalue between 'pp' and 'p' */
o = luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal));
uv = gco2upv(o);
uv->u.open.next = p; /* link it to list of open upvalues */
uv->u.open.previous = pp;
if (p)
p->u.open.previous = &uv->u.open.next;
*pp = uv;
uv->v = level; /* current value lives in the stack */
if (!isintwups(L)) { /* thread not in list of threads with upvalues? */
@ -85,18 +88,25 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
}
void luaF_unlinkupval (UpVal *uv) {
lua_assert(upisopen(uv));
*uv->u.open.previous = uv->u.open.next;
if (uv->u.open.next)
uv->u.open.next->u.open.previous = uv->u.open.previous;
}
void luaF_close (lua_State *L, StkId level) {
UpVal *uv;
while (L->openupval != NULL && (uv = L->openupval)->v >= level) {
lua_assert(upisopen(uv));
L->openupval = uv->u.open.next; /* remove from 'open' list */
if (uv->refcount == 0) /* no references? */
luaM_free(L, uv); /* free upvalue */
else {
setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */
uv->v = &uv->u.value; /* now current value lives here */
luaC_upvalbarrier(L, uv);
}
while (L->openupval != NULL &&
(uv = L->openupval, uplevel(uv) >= level)) {
TValue *slot = &uv->u.value; /* new position for value */
luaF_unlinkupval(uv);
setobj(L, slot, uv->v); /* move value to upvalue slot */
uv->v = slot; /* now current value lives here */
if (!iswhite(uv))
gray2black(uv); /* closed upvalues cannot be gray */
luaC_barrier(L, uv, slot);
}
}
@ -110,6 +120,7 @@ Proto *luaF_newproto (lua_State *L) {
f->sizep = 0;
f->code = NULL;
f->cache = NULL;
f->cachemiss = 0;
f->sizecode = 0;
f->lineinfo = NULL;
f->sizelineinfo = 0;

File diff suppressed because it is too large Load Diff

@ -139,7 +139,7 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
luaC_checkGC(L);
}
else { /* string already present */
ts = tsvalue(keyfromval(o)); /* re-use value previously stored */
ts = keystrval(nodefromval(o)); /* re-use value previously stored */
}
L->top--; /* remove string from stack */
return ts;

@ -35,13 +35,6 @@
#include "ravijit.h"
#include "ravi_profile.h"
#if !defined(LUAI_GCPAUSE)
#define LUAI_GCPAUSE 200 /* 200% */
#endif
#if !defined(LUAI_GCMUL)
#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */
#endif
/*
@ -219,6 +212,7 @@ static void f_luaopen (lua_State *L, void *ud) {
luaT_init(L);
luaX_init(L);
g->gcrunning = 1; /* allow gc */
g->gcemergency = 0;
g->version = lua_version(NULL);
luai_userstateopen(L);
}
@ -340,7 +334,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
int i;
lua_State *L;
global_State *g;
LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG)));
if (l == NULL) return NULL;
L = &l->l.l;
@ -349,35 +342,36 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->ravi_writestring = raviE_default_writestring;
g->ravi_writestringerror = raviE_default_writestringerror;
g->ravi_debugger_data = NULL;
L->next = NULL;
L->tt = LUA_TTHREAD;
g->currentwhite = bitmask(WHITE0BIT);
L->marked = luaC_white(g);
preinit_thread(L, g);
g->allgc = obj2gco(L); /* by now, only object is the main thread */
L->next = NULL;
g->frealloc = f;
g->ud = ud;
g->mainthread = L;
g->seed = makeseed(L);
g->gcrunning = 0; /* no GC while building state */
g->GCestimate = 0;
g->strt.size = g->strt.nuse = 0;
g->strt.hash = NULL;
setnilvalue(&g->l_registry);
g->panic = NULL;
g->version = NULL;
g->gcstate = GCSpause;
g->gckind = KGC_NORMAL;
g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL;
g->gckind = KGC_INC;
g->finobj = g->tobefnz = g->fixedgc = NULL;
g->survival = g->old = g->reallyold = NULL;
g->finobjsur = g->finobjold = g->finobjrold = NULL;
g->sweepgc = NULL;
g->gray = g->grayagain = NULL;
g->weak = g->ephemeron = g->allweak = NULL;
g->weak = g->ephemeron = g->allweak = g->protogray = NULL;
g->twups = NULL;
g->totalbytes = sizeof(LG);
g->GCdebt = 0;
g->gcfinnum = 0;
g->gcpause = LUAI_GCPAUSE;
g->gcstepmul = LUAI_GCMUL;
g->ravi_state = NULL;
g->gcstepsize = LUAI_GCSTEPSIZE;
for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL;
raviV_initjit(L);
if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {

@ -59,8 +59,8 @@
#define dummynode (&dummynode_)
static const Node dummynode_ = {
{NILCONSTANT}, /* value */
{{NILCONSTANT, 0}} /* key */
{{NULL}, LUA_TNIL, /* value's value and type */
LUA_TNIL, 0, {NULL}} /* key type, next, and key value */
};
@ -95,43 +95,98 @@ static int l_hashfloat (lua_Number n) {
/*
** returns the 'main' position of an element in a table (that is, the index
** of its hash value)
** returns the 'main' position of an element in a table (that is,
** the index of its hash value). The key comes broken (tag in 'ktt'
** and value in 'vkl') so that we can call it on keys inserted into
** nodes.
*/
static Node *mainposition (const Table *t, const TValue *key) {
switch (ttype(key)) {
static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
switch (ttyperaw(ktt)) {
case LUA_TNUMINT:
return hashint(t, ivalue(key));
return hashint(t, ivalueraw(*kvl));
case LUA_TNUMFLT:
return hashmod(t, l_hashfloat(fltvalue(key)));
return hashmod(t, l_hashfloat(fltvalueraw(*kvl)));
case LUA_TSHRSTR:
return hashstr(t, tsvalue(key));
return hashstr(t, tsvalueraw(*kvl));
case LUA_TLNGSTR:
return hashpow2(t, luaS_hashlongstr(tsvalue(key)));
return hashpow2(t, luaS_hashlongstr(tsvalueraw(*kvl)));
case LUA_TBOOLEAN:
return hashboolean(t, bvalue(key));
return hashboolean(t, bvalueraw(*kvl));
case LUA_TLIGHTUSERDATA:
return hashpointer(t, pvalue(key));
return hashpointer(t, pvalueraw(*kvl));
case LUA_TLCF:
return hashpointer(t, fvalue(key));
return hashpointer(t, fvalueraw(*kvl));
default:
lua_assert(!ttisdeadkey(key));
return hashpointer(t, gcvalue(key));
return hashpointer(t, gcvalueraw(*kvl));
}
}
static Node *mainpositionTV (const Table *t, const TValue *key) {
return mainposition(t, rttype(key), valraw(key));
}
/*
** returns the index for 'key' if 'key' is an appropriate key to live in
** the array part of the table, 0 otherwise.
** Check whether key 'k1' is equal to the key in node 'n2'.
** This equality is raw, so there are no metamethods. Floats
** with integer values have been normalized, so integers cannot
** be equal to floats. It is assumed that 'eqshrstr' is simply
** pointer equality, so that short strings are handled in the
** default case.
*/
static unsigned int arrayindex (const TValue *key) {
if (ttisinteger(key)) {
lua_Integer k = ivalue(key);
if (0 < k && (lua_Unsigned)k <= MAXASIZE)
return cast(unsigned int, k); /* 'key' is an appropriate array index */
static int equalkey (const TValue *k1, const Node *n2) {
if (rttype(k1) != keytt(n2)) /* not the same variants? */
return 0; /* cannot be same key */
switch (ttype(k1)) {
case LUA_TNIL:
return 1;
case LUA_TNUMINT:
return (ivalue(k1) == keyival(n2));
case LUA_TNUMFLT:
return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2)));
case LUA_TBOOLEAN:
return bvalue(k1) == bvalueraw(keyval(n2));
case LUA_TLIGHTUSERDATA:
return pvalue(k1) == pvalueraw(keyval(n2));
case LUA_TLCF:
return fvalue(k1) == fvalueraw(keyval(n2));
case LUA_TLNGSTR:
return luaS_eqlngstr(tsvalue(k1), keystrval(n2));
default:
return gcvalue(k1) == gcvalueraw(keyval(n2));
}
return 0; /* 'key' did not match some condition */
}
/*
** "Generic" get version. (Not that generic: not valid for integers,
** which may be in array part, nor for floats with integral values.)
*/
static const TValue *getgeneric (Table *t, const TValue *key) {
Node *n = mainpositionTV(t, key);
for (;;) { /* check whether 'key' is somewhere in the chain */
if (equalkey(key, n))
return gval(n); /* that's it */
else {
int nx = gnext(n);
if (nx == 0)
return luaO_nilobject; /* not found */
n += nx;
}
}
}
/*
** returns the index for 'k' if 'k' is an appropriate key to live in
** the array part of a table, 0 otherwise.
*/
static unsigned int arrayindex (lua_Integer k) {
if (0 < k && l_castS2U(k) <= MAXASIZE)
return cast(unsigned int, k); /* 'key' is an appropriate array index */
else
return 0;
}
@ -140,29 +195,19 @@ static unsigned int arrayindex (const TValue *key) {
** elements in the array part, then elements in the hash part. The
** beginning of a traversal is signaled by 0.
*/
static unsigned int findindex (lua_State *L, Table *t, StkId key) {
static unsigned int findindex (lua_State *L, Table *t, TValue *key) {
unsigned int i;
if (ttisnil(key)) return 0; /* first iteration */
i = arrayindex(key);
i = ttisinteger(key) ? arrayindex(ivalue(key)) : 0;
if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */
return i; /* yes; that's the index */
else {
int nx;
Node *n = mainposition(t, key);
for (;;) { /* check whether 'key' is somewhere in the chain */
/* key may be dead already, but it is ok to use it in 'next' */
if (luaV_rawequalobj(gkey(n), key) ||
(ttisdeadkey(gkey(n)) && iscollectable(key) &&
deadvalue(gkey(n)) == gcvalue(key))) {
i = cast_int(n - gnode(t, 0)); /* key index in hash table */
/* hash elements are numbered after array ones */
return (i + 1) + t->sizearray;
}
nx = gnext(n);
if (nx == 0)
luaG_runerror(L, "invalid key to 'next'"); /* key not found */
else n += nx;
}
const TValue *n = getgeneric(t, key);
if (n == luaO_nilobject)
luaG_runerror(L, "invalid key to 'next'"); /* key not found */
i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */
/* hash elements are numbered after array ones */
return (i + 1) + t->sizearray;
}
}
@ -212,8 +257,9 @@ int luaH_next (lua_State *L, Table *t, StkId key) {
}
for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */
if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */
setobj2s(L, key, gkey(gnode(t, i)));
setobj2s(L, key + 1, gval(gnode(t, i)));
Node *n = gnode(t, i);
getnodekey(L, key, n);
setobj2s(L, key + 1, gval(n));
return 1;
}
}
@ -232,7 +278,8 @@ int luaH_next (lua_State *L, Table *t, StkId key) {
** "count array" where 'nums[i]' is the number of integers in the table
** between 2^(i - 1) + 1 and 2^i. 'pna' enters with the total number of
** integer keys in the table and leaves with the number of keys that
** will go to the array part; return the optimal size.
** will go to the array part; return the optimal size. (The condition
** 'twotoi > 0' in the for loop stops the loop if 'twotoi' overflows.)
*/
static unsigned int computesizes (unsigned int nums[], unsigned int *pna) {
int i;
@ -241,13 +288,13 @@ static unsigned int computesizes (unsigned int nums[], unsigned int *pna) {
unsigned int na = 0; /* number of elements to go to array part */
unsigned int optimal = 0; /* optimal size for array part */
/* loop while keys can fill more than half of total size */
for (i = 0, twotoi = 1; *pna > twotoi / 2; i++, twotoi *= 2) {
if (nums[i] > 0) {
a += nums[i];
if (a > twotoi/2) { /* more than half elements present? */
optimal = twotoi; /* optimal size (till now) */
na = a; /* all elements up to 'optimal' will go to array part */
}
for (i = 0, twotoi = 1;
twotoi > 0 && *pna > twotoi / 2;
i++, twotoi *= 2) {
a += nums[i];
if (a > twotoi/2) { /* more than half elements present? */
optimal = twotoi; /* optimal size (till now) */
na = a; /* all elements up to 'optimal' will go to array part */
}
}
lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal);
@ -256,7 +303,7 @@ static unsigned int computesizes (unsigned int nums[], unsigned int *pna) {
}
static int countint (const TValue *key, unsigned int *nums) {
static int countint (lua_Integer key, unsigned int *nums) {
unsigned int k = arrayindex(key);
if (k != 0) { /* is 'key' an appropriate array index? */
nums[luaO_ceillog2(k)]++; /* count as such */
@ -305,7 +352,8 @@ static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) {
while (i--) {
Node *n = &t->node[i];
if (!ttisnil(gval(n))) {
ause += countint(gkey(n), nums);
if (keyisinteger(n))
ause += countint(keyival(n), nums);
totaluse++;
}
}
@ -342,7 +390,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
for (i = 0; i < (int)size; i++) {
Node *n = gnode(t, i);
gnext(n) = 0;
setnilvalue(wgkey(n));
setnilkey(n);
setnilvalue(gval(n));
}
t->lsizenode = cast_byte(lsize);
@ -381,7 +429,8 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
if (!ttisnil(gval(old))) {
/* doesn't need barrier/invalidate cache, as entry was
already present in the table */
setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old));
TValue k; getnodekey(L, &k, old);
setobjt2t(L, luaH_set(L, t, &k), gval(old));
}
}
if (oldhsize > 0) /* not the dummy node? */
@ -408,7 +457,8 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) {
totaluse = na; /* all those keys are integer keys */
totaluse += numusehash(t, nums, &na); /* count keys in hash part */
/* count extra key */
na += countint(ek, nums);
if (ttisinteger(ek))
na += countint(ivalue(ek), nums);
totaluse++;
/* compute new size for array part */
asize = computesizes(nums, &na);
@ -487,7 +537,7 @@ static Node *getfreepos (Table *t) {
if (!isdummy(t)) {
while (t->lastfree > t->node) {
t->lastfree--;
if (ttisnil(gkey(t->lastfree)))
if (keyisnil(t->lastfree))
return t->lastfree;
}
}
@ -516,7 +566,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
else if (luai_numisnan(fltvalue(key)))
luaG_runerror(L, "table index is NaN");
}
mp = mainposition(t, key);
mp = mainpositionTV(t, key);
if (!ttisnil(gval(mp)) || isdummy(t)) { /* main position is taken? */
Node *othern;
Node *f = getfreepos(t); /* get a free place */
@ -526,7 +576,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
return luaH_set(L, t, key); /* insert key into grown table */
}
lua_assert(!isdummy(t));
othern = mainposition(t, gkey(mp));
othern = mainposition(t, keytt(mp), &keyval(mp));
if (othern != mp) { /* is colliding node out of its main position? */
/* yes; move colliding node into free position */
while (othern + gnext(othern) != mp) /* find previous */
@ -548,7 +598,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
mp = f;
}
}
setnodekey(L, &mp->i_key, key);
setnodekey(L, mp, key);
luaC_barrierback(L, t, key);
lua_assert(ttisnil(gval(mp)));
return gval(mp);
@ -560,12 +610,12 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
*/
const TValue *luaH_getint (Table *t, lua_Integer key) {
/* (1 <= key && key <= t->sizearray) */
if (l_castS2U(key) - 1 < t->sizearray)
if (l_castS2U(key) - 1u < t->sizearray)
return &t->array[key - 1];
else {
Node *n = hashint(t, key);
for (;;) { /* check whether 'key' is somewhere in the chain */
if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key)
if (keyisinteger(n) && keyival(n) == key)
return gval(n); /* that's it */
else {
int nx = gnext(n);
@ -577,7 +627,7 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
}
}
#if !defined(RAVI_ENABLED)
/*
** search function for short strings
*/
@ -585,27 +635,7 @@ const TValue *luaH_getshortstr (Table *t, TString *key) {
Node *n = hashstr(t, key);
lua_assert(key->tt == LUA_TSHRSTR);
for (;;) { /* check whether 'key' is somewhere in the chain */
const TValue *k = gkey(n);
if (ttisshrstring(k) && eqshrstr(tsvalue(k), key))
return gval(n); /* that's it */
else {
int nx = gnext(n);
if (nx == 0)
return luaO_nilobject; /* not found */
n += nx;
}
}
}
#endif
/*
** "Generic" get version. (Not that generic: not valid for integers,
** which may be in array part, nor for floats with integral values.)
*/
static const TValue *getgeneric (Table *t, const TValue *key) {
Node *n = mainposition(t, key);
for (;;) { /* check whether 'key' is somewhere in the chain */
if (luaV_rawequalobj(gkey(n), key))
if (keyisshrstr(n) && eqshrstr(keystrval(n), key))
return gval(n); /* that's it */
else {
int nx = gnext(n);
@ -631,8 +661,7 @@ const TValue *luaH_getstr (Table *t, TString *key) {
/*
** main search function
*/
const TValue *luaH_get(Table *t, const TValue *key) {
#if 1
const TValue *luaH_get (Table *t, const TValue *key) {
switch (ttype(key)) {
case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key));
case LUA_TNUMINT: return luaH_getint(t, ivalue(key));
@ -646,27 +675,9 @@ const TValue *luaH_get(Table *t, const TValue *key) {
default:
return getgeneric(t, key);
}
#else
int tt = ttype(key);
if (RAVI_LIKELY(tt == LUA_TNUMINT))
return luaH_getint(t, ivalue(key));
else if (tt == LUA_TSHRSTR)
return luaH_getshortstr(t, tsvalue(key));
else if (tt == LUA_TNIL)
return luaO_nilobject;
else if (tt == LUA_TNUMFLT) {
lua_Integer k;
if (luaV_tointeger(key, &k, 0)) /* index is int? */
return luaH_getint(t, k); /* use specialized version */
/* else... */
return getgeneric(t, key);
} /* FALLTHROUGH */
else {
return getgeneric(t, key);
}
#endif
}
/*
** beware: when using this function you probably need to check a GC
** barrier and invalidate the TM cache.
@ -693,23 +704,37 @@ void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {
}
static int unbound_search (Table *t, unsigned int j) {
unsigned int i = j; /* i is zero or a present index */
j++;
/* find 'i' and 'j' such that i is present and j is not */
while (!ttisnil(luaH_getint(t, j))) {
i = j;
if (j > cast(unsigned int, MAX_INT)/2) { /* overflow? */
/* table was built with bad purposes: resort to linear search */
i = 1;
while (!ttisnil(luaH_getint(t, i))) i++;
return i - 1;
/*
** Try to find a boundary in the hash part of table 't'. From the
** caller, we know that 'j' is zero or present and that 'j + 1' is
** present. We want to find a larger key that is absent from the
** table, so that we can do a binary search between the two keys to
** find a boundary. We keep doubling 'j' until we get an absent index.
** If the doubling would overflow, we try LUA_MAXINTEGER. If it is
** absent, we are ready for the binary search. ('j', being max integer,
** is larger or equal to 'i', but it cannot be equal because it is
** absent while 'i' is present; so 'j > i'.) Otherwise, 'j' is a
** boundary. ('j + 1' cannot be a present integer key because it is
** not a valid integer in Lua.)
*/
static lua_Unsigned hash_search (Table *t, lua_Unsigned j) {
lua_Unsigned i;
if (j == 0) j++; /* the caller ensures 'j + 1' is present */
do {
i = j; /* 'i' is a present index */
if (j <= l_castS2U(LUA_MAXINTEGER) / 2)
j *= 2;
else {
j = LUA_MAXINTEGER;
if (ttisnil(luaH_getint(t, j))) /* t[j] == nil? */
break; /* 'j' now is an absent index */
else /* weird case */
return j; /* well, max integer is a boundary... */
}
j *= 2;
}
/* now do a binary search between them */
while (j - i > 1) {
unsigned int m = (i+j)/2;
} while (!ttisnil(luaH_getint(t, j))); /* repeat until t[j] == nil */
/* i < j && t[i] !? nil && t[j] == nil */
while (j - i > 1u) { /* do a binary search between them */
lua_Unsigned m = (i + j) / 2;
if (ttisnil(luaH_getint(t, m))) j = m;
else i = m;
}
@ -718,32 +743,32 @@ static int unbound_search (Table *t, unsigned int j) {
/*
** Try to find a boundary in table 't'. A 'boundary' is an integer index
** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
** Try to find a boundary in table 't'. (A 'boundary' is an integer index
** such that t[i] is non-nil and t[i+1] is nil, plus 0 if t[1] is nil
** and 'maxinteger' if t[maxinteger] is not nil.)
** First, try the array part: if there is an array part and its last
** element is nil, there must be a boundary there; a binary search
** finds that boundary. Otherwise, if the hash part is empty or does not
** contain 'j + 1', 'j' is a boundary. Othersize, call 'hash_search'
** to find a boundary in the hash part.
*/
int luaH_getn (Table *t) {
unsigned int j;
/* if this is a RAVI array then use specialized function */
if (t->ravi_array.array_type != RAVI_TTABLE) {
lua_assert(t->ravi_array.array_type == RAVI_TARRAYFLT ||
t->ravi_array.array_type == RAVI_TARRAYINT);
return t->ravi_array.len;
}
j = t->sizearray;
lua_Unsigned luaH_getn (Table *t) {
unsigned int j = t->sizearray;
if (j > 0 && ttisnil(&t->array[j - 1])) {
/* there is a boundary in the array part: (binary) search for it */
unsigned int i = 0;
while (j - i > 1) {
unsigned int m = (i+j)/2;
while (j - i > 1u) { /* binary search */
unsigned int m = (i + j) / 2;
if (ttisnil(&t->array[m - 1])) j = m;
else i = m;
}
return i;
}
/* else must find a boundary in hash part */
else if (isdummy(t)) /* hash part is empty? */
return j; /* that is easy... */
else return unbound_search(t, j);
else { /* 'j' is zero or present in table */
if (isdummy(t) || ttisnil(luaH_getint(t, l_castU2S(j + 1))))
return j; /* 'j + 1' is absent... */
else /* 'j + 1' is also present */
return hash_search(t, j);
}
}
/* RAVI array specialization */
@ -935,7 +960,7 @@ const TValue *raviH_slice_parent(lua_State *L, TValue *slice) {
#if defined(LUA_DEBUG)
Node *luaH_mainposition (const Table *t, const TValue *key) {
return mainposition(t, key);
return mainpositionTV(t, key);
}
int luaH_isdummy (const Table *t) { return isdummy(t); }

@ -189,18 +189,39 @@ LUA_API void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) {
*/
/*
** Check GC invariants. For incremental mode, a black object cannot
** point to a white one. For generational mode, really old objects
** cannot point to young objects. Both old1 and touched2 objects
** cannot point to new objects (but can point to survivals).
** (Threads and open upvalues, despite being marked "really old",
** continue to be visited in all collections, and therefore can point to
** new objects. They, and only they, are old but gray.)
*/
static int testobjref1 (global_State *g, GCObject *f, GCObject *t) {
if (isdead(g,t)) return 0;
if (!issweepphase(g))
return !(isblack(f) && iswhite(t));
else return 1;
if (issweepphase(g))
return 1; /* no invariants */
else if (g->gckind == KGC_INC)
return !(isblack(f) && iswhite(t)); /* basic incremental invariant */
else { /* generational mode */
if ((getage(f) == G_OLD && isblack(f)) && !isold(t))
return 0;
if (((getage(f) == G_OLD1 || getage(f) == G_TOUCHED2) && isblack(f)) &&
getage(t) == G_NEW)
return 0;
return 1;
}
}
static void printobj (global_State *g, GCObject *o) {
printf("||%s(%p)-%c(%02X)||",
printf("||%s(%p)-%c%c(%02X)||",
ttypename(novariant(o->tt)), (void *)o,
isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', o->marked);
isdead(g,o) ? 'd' : isblack(o) ? 'b' : iswhite(o) ? 'w' : 'g',
"ns01oTt"[getage(o)], o->marked);
if (o->tt == LUA_TSHRSTR || o->tt == LUA_TLNGSTR)
printf(" '%s'", getstr(gco2ts(o)));
}
@ -235,8 +256,10 @@ static void checktable (global_State *g, Table *h) {
checkvalref(g, hgc, &h->array[i]);
for (n = gnode(h, 0); n < limit; n++) {
if (!ttisnil(gval(n))) {
lua_assert(!ttisnil(gkey(n)));
checkvalref(g, hgc, gkey(n));
TValue k;
getnodekey(g->mainthread, &k, n);
lua_assert(!keyisnil(n));
checkvalref(g, hgc, &k);
checkvalref(g, hgc, gval(n));
}
}
@ -281,9 +304,9 @@ static void checkLclosure (global_State *g, LClosure *cl) {
for (i=0; i<cl->nupvalues; i++) {
UpVal *uv = cl->upvals[i];
if (uv) {
if (!upisopen(uv)) /* only closed upvalues matter to invariant */
checkvalref(g, clgc, uv->v);
lua_assert(uv->refcount > 0);
checkobjref(g, clgc, uv);
if (!upisopen(uv))
checkvalref(g, obj2gco(uv), uv->v);
}
}
}
@ -322,57 +345,89 @@ static void checkstack (global_State *g, lua_State *L1) {
}
static void checkobject (global_State *g, GCObject *o, int maybedead) {
static void checkrefs (global_State *g, GCObject *o) {
switch (o->tt) {
case LUA_TUSERDATA: {
TValue uservalue;
Table *mt = gco2u(o)->metatable;
checkobjref(g, o, mt);
getuservalue(g->mainthread, gco2u(o), &uservalue);
checkvalref(g, o, &uservalue);
break;
}
case LUA_TUPVAL: {
checkvalref(g, o, gco2upv(o)->v);
break;
}
case LUA_TTABLE: {
checktable(g, gco2t(o));
break;
}
case LUA_TTHREAD: {
checkstack(g, gco2th(o));
break;
}
case LUA_TLCL: {
checkLclosure(g, gco2lcl(o));
break;
}
case LUA_TCCL: {
checkCclosure(g, gco2ccl(o));
break;
}
case LUA_TPROTO: {
checkproto(g, gco2p(o));
break;
}
case LUA_TSHRSTR:
case LUA_TLNGSTR: {
lua_assert(!isgray(o)); /* strings are never gray */
break;
}
default: lua_assert(0);
}
}
/*
** Check consistency of an object:
** - Dead objects can only happen in the 'allgc' list during a sweep
** phase (controled by the caller through 'maybedead').
** - During pause, all objects must be white.
** - In generational mode:
** * objects must be old enough for their lists ('listage').
** * old objects cannot be white.
** * old objects must be black, except for 'touched1', 'old0',
** threads, and open upvalues.
*/
static void checkobject (global_State *g, GCObject *o, int maybedead,
int listage) {
if (isdead(g, o))
lua_assert(maybedead);
else {
lua_assert(g->gcstate != GCSpause || iswhite(o));
switch (o->tt) {
case LUA_TUSERDATA: {
TValue uservalue;
Table *mt = gco2u(o)->metatable;
checkobjref(g, o, mt);
getuservalue(g->mainthread, gco2u(o), &uservalue);
checkvalref(g, o, &uservalue);
break;
}
case LUA_TTABLE: {
checktable(g, gco2t(o));
break;
if (g->gckind == KGC_GEN) { /* generational mode? */
lua_assert(getage(o) >= listage);
lua_assert(!iswhite(o) || !isold(o));
if (isold(o)) {
lua_assert(isblack(o) ||
getage(o) == G_TOUCHED1 ||
getage(o) == G_OLD0 ||
o->tt == LUA_TTHREAD ||
(o->tt == LUA_TPROTO &&
(gco2p(o)->cache != NULL || gco2p(o)->cachemiss >= MAXMISS)) ||
(o->tt == LUA_TUPVAL && upisopen(gco2upv(o))));
}
case LUA_TTHREAD: {
checkstack(g, gco2th(o));
break;
}
case LUA_TLCL: {
checkLclosure(g, gco2lcl(o));
break;
}
case LUA_TCCL: {
checkCclosure(g, gco2ccl(o));
break;
}
case LUA_TPROTO: {
checkproto(g, gco2p(o));
break;
}
case LUA_TSHRSTR:
case LUA_TLNGSTR: {
lua_assert(!isgray(o)); /* strings are never gray */
break;
}
default: lua_assert(0);
}
checkrefs(g, o);
}
}
#define TESTGRAYBIT 7
static void checkgraylist (global_State *g, GCObject *o) {
((void)g); /* better to keep it available if we need to print an object */
while (o) {
lua_assert(isgray(o));
lua_assert(isgray(o) || getage(o) == G_TOUCHED2);
lua_assert(!testbit(o->marked, TESTGRAYBIT));
l_setbit(o->marked, TESTGRAYBIT);
switch (o->tt) {
@ -381,7 +436,7 @@ static void checkgraylist (global_State *g, GCObject *o) {
case LUA_TCCL: o = gco2ccl(o)->gclist; break;
case LUA_TTHREAD: o = gco2th(o)->gclist; break;
case LUA_TPROTO: o = gco2p(o)->gclist; break;
default: lua_assert(0); /* other objects cannot be gray */
default: lua_assert(0); /* other objects cannot be in a gray list */
}
}
}
@ -397,13 +452,13 @@ static void markgrays (global_State *g) {
checkgraylist(g, g->grayagain);
checkgraylist(g, g->weak);
checkgraylist(g, g->ephemeron);
checkgraylist(g, g->allweak);
checkgraylist(g, g->protogray);
}
static void checkgray (global_State *g, GCObject *o) {
for (; o != NULL; o = o->next) {
if (isgray(o)) {
if ((isgray(o) && o->tt != LUA_TUPVAL) || getage(o) == G_TOUCHED2) {
lua_assert(!keepinvariant(g) || testbit(o->marked, TESTGRAYBIT));
resetbit(o->marked, TESTGRAYBIT);
}
@ -412,6 +467,28 @@ static void checkgray (global_State *g, GCObject *o) {
}
static void checklist (global_State *g, int maybedead, int tof,
GCObject *newl, GCObject *survival, GCObject *old, GCObject *reallyold) {
GCObject *o;
for (o = newl; o != survival; o = o->next) {
checkobject(g, o, maybedead, G_NEW);
lua_assert(!tof == !tofinalize(o));
}
for (o = survival; o != old; o = o->next) {
checkobject(g, o, 0, G_SURVIVAL);
lua_assert(!tof == !tofinalize(o));
}
for (o = old; o != reallyold; o = o->next) {
checkobject(g, o, 0, G_OLD1);
lua_assert(!tof == !tofinalize(o));
}
for (o = reallyold; o != NULL; o = o->next) {
checkobject(g, o, 0, G_OLD);
lua_assert(!tof == !tofinalize(o));
}
}
int lua_checkmemory (lua_State *L) {
global_State *g = G(L);
GCObject *o;
@ -421,32 +498,27 @@ int lua_checkmemory (lua_State *L) {
lua_assert(!iswhite(gcvalue(&g->l_registry)));
}
lua_assert(!isdead(g, gcvalue(&g->l_registry)));
checkstack(g, g->mainthread);
resetbit(g->mainthread->marked, TESTGRAYBIT);
lua_assert(g->sweepgc == NULL || issweepphase(g));
markgrays(g);
/* check 'fixedgc' list */
for (o = g->fixedgc; o != NULL; o = o->next) {
lua_assert(o->tt == LUA_TSHRSTR && isgray(o));
lua_assert(o->tt == LUA_TSHRSTR && isgray(o) && getage(o) == G_OLD);
}
/* check 'allgc' list */
checkgray(g, g->allgc);
maybedead = (GCSatomic < g->gcstate && g->gcstate <= GCSswpallgc);
for (o = g->allgc; o != NULL; o = o->next) {
checkobject(g, o, maybedead);
lua_assert(!tofinalize(o));
}
checklist(g, maybedead, 0, g->allgc, g->survival, g->old, g->reallyold);
/* check 'finobj' list */
checkgray(g, g->finobj);
for (o = g->finobj; o != NULL; o = o->next) {
checkobject(g, o, 0);
lua_assert(tofinalize(o));
lua_assert(o->tt == LUA_TUSERDATA || o->tt == LUA_TTABLE);
}
checklist(g, 0, 1, g->finobj, g->finobjsur, g->finobjold, g->finobjrold);
/* check 'tobefnz' list */
checkgray(g, g->tobefnz);
for (o = g->tobefnz; o != NULL; o = o->next) {
checkobject(g, o, 0);
checkobject(g, o, 0, G_NEW);
lua_assert(tofinalize(o));
lua_assert(o->tt == LUA_TUSERDATA || o->tt == LUA_TTABLE);
}
@ -635,11 +707,44 @@ static int gc_color (lua_State *L) {
}
static int gc_age (lua_State *L) {
TValue *o;
luaL_checkany(L, 1);
o = obj_at(L, 1);
if (!iscollectable(o))
lua_pushstring(L, "no collectable");
else {
static const char *gennames[] = {"new", "survival", "old0", "old1",
"old", "touched1", "touched2"};
GCObject *obj = gcvalue(o);
lua_pushstring(L, gennames[getage(obj)]);
}
return 1;
}
static int gc_printobj (lua_State *L) {
TValue *o;
luaL_checkany(L, 1);
o = obj_at(L, 1);
if (!iscollectable(o))
printf("no collectable\n");
else {
GCObject *obj = gcvalue(o);
printobj(G(L), obj);
printf("\n");
}
return 0;
}
static int gc_state (lua_State *L) {
static const char *statenames[] = {"propagate", "atomic", "sweepallgc",
"sweepfinobj", "sweeptobefnz", "sweepend", "pause", ""};
static const int states[] = {GCSpropagate, GCSatomic, GCSswpallgc,
GCSswpfinobj, GCSswptobefnz, GCSswpend, GCSpause, -1};
static const char *statenames[] = {
"propagate", "atomic", "enteratomic", "sweepallgc", "sweepfinobj",
"sweeptobefnz", "sweepend", "callfin", "pause", ""};
static const int states[] = {
GCSpropagate, GCSenteratomic, GCSatomic, GCSswpallgc, GCSswpfinobj,
GCSswptobefnz, GCSswpend, GCScallfin, GCSpause, -1};
int option = states[luaL_checkoption(L, 1, "", statenames)];
if (option == -1) {
lua_pushstring(L, statenames[G(L)->gcstate]);
@ -647,6 +752,8 @@ static int gc_state (lua_State *L) {
}
else {
global_State *g = G(L);
if (G(L)->gckind == KGC_GEN)
luaL_error(L, "cannot change states in generational mode");
lua_lock(L);
if (option < g->gcstate) { /* must cross 'pause'? */
luaC_runtilstate(L, bitmask(GCSpause)); /* run until pause */
@ -700,10 +807,12 @@ static int table_query (lua_State *L) {
lua_pushnil(L);
}
else if ((i -= t->sizearray) < sizenode(t)) {
TValue k;
getnodekey(L, &k, gnode(t, i));
if (!ttisnil(gval(gnode(t, i))) ||
ttisnil(gkey(gnode(t, i))) ||
ttisnumber(gkey(gnode(t, i)))) {
pushobject(L, gkey(gnode(t, i)));
ttisnil(&k) ||
ttisnumber(&k)) {
pushobject(L, &k);
}
else
lua_pushliteral(L, "<undef>");
@ -1520,7 +1629,9 @@ static const struct luaL_Reg tests_funcs[] = {
{"doonnewstack", doonnewstack},
{"doremote", doremote},
{"gccolor", gc_color},
{"gcage", gc_age},
{"gcstate", gc_state},
{"pobj", gc_printobj},
{"getref", getref},
{"hash", hash_query},
{"int2fb", int2fb_aux},

@ -30,7 +30,7 @@ LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = {
"no value",
"nil", "boolean", udatatypename, "number",
"string", "table", "function", udatatypename, "thread",
"proto" /* this last case is used for tests only */
"upvalue", "proto" /* these last cases are used for tests only */
};

@ -196,7 +196,7 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
return;
}
t = tm; /* else try to access 'tm[key]' */
if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */
if (luaV_fastget(L, t, key, slot, luaH_get)) { /* fast track? */
setobj2s(L, val, slot); /* done */
return;
}
@ -210,11 +210,11 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
** Finish a table assignment 't[key] = val'.
** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points
** to the entry 't[key]', or to 'luaO_nilobject' if there is no such
** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset'
** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastget'
** would have done the job.)
*/
void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *slot) {
TValue *val, const TValue *slot) {
int loop; /* counter to avoid infinite loops */
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm; /* '__newindex' metamethod */
@ -243,9 +243,11 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
return;
}
t = tm; /* else repeat assignment over 'tm' */
if (luaV_fastset(L, t, key, slot, luaH_get, val))
if (luaV_fastget(L, t, key, slot, luaH_get)) {
luaV_finishfastset(L, t, slot, val);
return; /* done */
/* else loop */
}
/* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */
}
luaG_runerror(L, "'__newindex' chain too long; possible loop");
}
@ -885,6 +887,7 @@ static LClosure *getcached (Proto *p, UpVal **encup, StkId base) {
if (c->upvals[i]->v != v)
return NULL; /* wrong upvalue; cannot reuse closure */
}
p->cachemiss = 0; /* got a hit */
}
return c; /* return cached closure (or NULL if no cached closure) */
}
@ -892,9 +895,7 @@ static LClosure *getcached (Proto *p, UpVal **encup, StkId base) {
/*
** create a new Lua closure, push it in the stack, and initialize
** its upvalues. Note that the closure is not cached if prototype is
** already black (which means that 'cache' was already cleared by the
** GC).
** its upvalues. ???
*/
static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
StkId ra) {
@ -903,17 +904,21 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
int i;
LClosure *ncl = luaF_newLclosure(L, nup);
ncl->p = p;
setclLvalue(L, ra, ncl); /* anchor new closure in stack */
setclLvalue2s(L, ra, ncl); /* anchor new closure in stack */
for (i = 0; i < nup; i++) { /* fill in its upvalues */
if (uv[i].instack) /* upvalue refers to local variable? */
ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx);
else /* get upvalue from enclosing function */
ncl->upvals[i] = encup[uv[i].idx];
ncl->upvals[i]->refcount++;
/* new closure is white, so we do not need a barrier here */
}
if (!isblack(p)) /* cache will not break GC invariant? */
if (p->cachemiss >= MAXMISS) /* too many missings? */
p->cache = NULL; /* give up cache */
else {
p->cache = ncl; /* save it on cache for reuse */
luaC_protobarrier(L, p, ncl);
p->cachemiss++;
}
}
@ -954,13 +959,13 @@ void luaV_finishOp (lua_State *L) {
StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */
int b = GETARG_B(inst); /* first element to concatenate */
int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */
setobj2s(L, top - 2, top); /* put TM result in proper position */
setobjs2s(L, top - 2, top); /* put TM result in proper position */
if (total > 1) { /* are there elements to concat? */
L->top = top - 1; /* top is one after last element (at top-2) */
luaV_concat(L, total); /* concat them (may yield again) */
}
/* move final result to final position */
setobj2s(L, ci->u.l.base + GETARG_A(inst), L->top - 1);
setobjs2s(L, ci->u.l.base + GETARG_A(inst), L->top - 1);
L->top = ci->top; /* restore top */
break;
}
@ -1048,6 +1053,7 @@ void luaV_finishOp (lua_State *L) {
L->top = ci->top); /* restore top */ \
luai_threadyield(L); }
#ifndef RAVI_USE_COMPUTED_GOTO
#if RAVI_BYTECODE_PROFILING_ENABLED
@ -1315,6 +1321,12 @@ int luaV_execute (lua_State *L) {
setobj2s(L, ra, cl->upvals[b]->v);
vmbreak;
}
vmcase(OP_SETUPVAL) {
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra);
luaC_barrier(L, uv, ra);
vmbreak;
}
vmcase(OP_GETTABUP) {
TValue *upval = cl->upvals[GETARG_B(i)]->v; /* table */
TValue *rc = RKC(i); /* key */
@ -1334,12 +1346,6 @@ int luaV_execute (lua_State *L) {
SETTABLE_INLINE_PROTECTED(L, upval, rb, rc);
vmbreak;
}
vmcase(OP_SETUPVAL) {
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
vmbreak;
}
vmcase(OP_SETTABLE) {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
@ -2077,8 +2083,8 @@ int luaV_execute (lua_State *L) {
vmcase(OP_RAVI_GETTABLE_I) {
TValue *rb = RB(i);
TValue *rc = RKC(i);
GETTABLE_INLINE_PROTECTED_I(L, rb, rc, ra);
vmbreak;
GETTABLE_INLINE_PROTECTED_I(L, rb, rc, ra);
vmbreak;
}
/* This opcode is used when the key is known to be
short string but the variable may or may not be
@ -2195,7 +2201,7 @@ int luaV_execute (lua_State *L) {
if (tointeger(ra, &ia)) {
UpVal *uv = cl->upvals[GETARG_B(i)];
setivalue(uv->v, ia);
luaC_upvalbarrier(L, uv);
luaC_barrier(L, uv, ra);
}
else
luaG_runerror(
@ -2207,7 +2213,7 @@ int luaV_execute (lua_State *L) {
if (tonumber(ra, &na)) {
UpVal *uv = cl->upvals[GETARG_B(i)];
setfltvalue(uv->v, na);
luaC_upvalbarrier(L, uv);
luaC_barrier(L, uv, ra);
}
else
luaG_runerror(
@ -2221,7 +2227,7 @@ int luaV_execute (lua_State *L) {
"integer[] value");
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
luaC_barrier(L, uv, ra);
vmbreak;
}
vmcase(OP_RAVI_SETUPVALAF) {
@ -2231,7 +2237,7 @@ int luaV_execute (lua_State *L) {
"upvalue of number[] type, cannot be set to non number[] value");
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
luaC_barrier(L, uv, ra);
vmbreak;
}
vmcase(OP_RAVI_SETUPVALT) {
@ -2240,7 +2246,7 @@ int luaV_execute (lua_State *L) {
L, "upvalue of table type, cannot be set to non table value");
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
luaC_barrier(L, uv, ra);
vmbreak;
}
vmcase(OP_RAVI_LOADIZ) {
@ -2737,7 +2743,7 @@ void raviV_op_setupvali(lua_State *L, LClosure *cl, TValue *ra, int b) {
if (tointeger(ra, &ia)) {
UpVal *uv = cl->upvals[b];
setivalue(uv->v, ia);
luaC_upvalbarrier(L, uv);
luaC_barrier(L, uv, ra);
}
else
luaG_runerror(
@ -2749,7 +2755,7 @@ void raviV_op_setupvalf(lua_State *L, LClosure *cl, TValue *ra, int b) {
if (tonumber(ra, &na)) {
UpVal *uv = cl->upvals[b];
setfltvalue(uv->v, na);
luaC_upvalbarrier(L, uv);
luaC_barrier(L, uv, ra);
}
else
luaG_runerror(L,
@ -2762,7 +2768,7 @@ void raviV_op_setupvalai(lua_State *L, LClosure *cl, TValue *ra, int b) {
L, "upvalue of integer[] type, cannot be set to non integer[] value");
UpVal *uv = cl->upvals[b];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
luaC_barrier(L, uv, ra);
}
void raviV_op_setupvalaf(lua_State *L, LClosure *cl, TValue *ra, int b) {
@ -2771,7 +2777,7 @@ void raviV_op_setupvalaf(lua_State *L, LClosure *cl, TValue *ra, int b) {
L, "upvalue of number[] type, cannot be set to non number[] value");
UpVal *uv = cl->upvals[b];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
luaC_barrier(L, uv, ra);
}
void raviV_op_setupvalt(lua_State *L, LClosure *cl, TValue *ra, int b) {
@ -2779,13 +2785,13 @@ void raviV_op_setupvalt(lua_State *L, LClosure *cl, TValue *ra, int b) {
luaG_runerror(L, "upvalue of table type, cannot be set to non table value");
UpVal *uv = cl->upvals[b];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
luaC_barrier(L, uv, ra);
}
void raviV_op_setupval(lua_State *L, LClosure *cl, TValue *ra, int b) {
UpVal *uv = cl->upvals[b];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
luaC_barrier(L, uv, ra);
}
void raviV_op_add(lua_State *L, TValue *ra, TValue *rb, TValue *rc) {

@ -100,15 +100,17 @@ static const char Lua_header[] = ""
" lua_Integer i;\n"
" lua_Number n;\n"
"} Value;\n"
"#define TValuefields Value value_; int tt_\n"
"#define TValuefields Value value_; lu_byte tt_\n"
"typedef struct lua_TValue {\n"
" TValuefields;\n"
"} TValue;\n"
"#define NILCONSTANT {NULL}, LUA_TNIL\n"
"#define val_(o) ((o)->value_)\n"
"#define valraw(o) (&val_(o))\n"
"#define rttype(o) ((o)->tt_)\n"
"#define novariant(x) ((x) & 0x0F)\n"
"#define ttype(o) (rttype(o) & 0x3F)\n"
"#define ttyperaw(t) ((t) & 0x3F)\n"
"#define ttype(o) ttyperaw(rttype(o))\n"
"#define ttnov(o) (novariant(rttype(o)))\n"
"#define checktag(o,t) (rttype(o) == (t))\n"
"#define checktype(o,t) (ttnov(o) == (t))\n"
@ -132,7 +134,13 @@ static const char Lua_header[] = ""
"#define ttislcf(o) checktag((o), LUA_TLCF)\n"
"#define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA))\n"
"#define ttisthread(o) checktag((o), ctb(LUA_TTHREAD))\n"
"#define ttisdeadkey(o) checktag((o), LUA_TDEADKEY)\n"
"#define ivalueraw(v) ((v).i)\n"
"#define fltvalueraw(v) ((v).n)\n"
"#define gcvalueraw(v) ((v).gc)\n"
"#define pvalueraw(v) ((v).p)\n"
"#define tsvalueraw(v) (gco2ts((v).gc))\n"
"#define fvalueraw(v) ((v).f)\n"
"#define bvalueraw(v) ((v).b)\n"
"#define ivalue(o) check_exp(ttisinteger(o), val_(o).i)\n"
"#define fltvalue(o) check_exp(ttisfloat(o), val_(o).n)\n"
"#define nvalue(o) check_exp(ttisnumber(o), \\\n"
@ -148,9 +156,9 @@ static const char Lua_header[] = ""
"#define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc))\n"
"#define bvalue(o) check_exp(ttisboolean(o), val_(o).b)\n"
"#define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc))\n"
"#define deadvalue(o) check_exp(ttisdeadkey(o), cast(void *, val_(o).gc))\n"
"#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))\n"
"#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE)\n"
"#define gcvalueN(o) (iscollectable(o) ? gcvalue(o) : NULL)\n"
"#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt)\n"
"#define checkliveness(L,obj) \\\n"
" lua_longassert(!iscollectable(obj) || \\\n"
@ -206,7 +214,6 @@ static const char Lua_header[] = ""
" { TValue *io = (obj); Table *x_ = (x); \\\n"
" val_(io).gc = obj2gco(x_); settt_(io, ctb(RAVI_TFARRAY)); \\\n"
" checkliveness(L,io); }\n"
"#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY)\n"
"#define setobj(L,obj1,obj2) \\\n"
// NOTE we cannot use aggregate assign so following assigns by field but assumes
// n covers all value types
@ -216,11 +223,13 @@ static const char Lua_header[] = ""
"#define setobj2s setobj\n"
"#define setsvalue2s setsvalue\n"
"#define sethvalue2s sethvalue\n"
"#define setthvalue2s setthvalue\n"
"#define setptvalue2s setptvalue\n"
"#define setclLvalue2s setclLvalue\n"
"#define setobjt2t setobj\n"
"#define setobj2n setobj\n"
"#define setsvalue2n setsvalue\n"
"#define setobj2t(L,o1,o2) ((void)L, *(o1)=*(o2), checkliveness(L,(o1)))\n"
"#define setobj2t setobj\n"
"typedef TValue *StkId;\n"
"typedef struct TString {\n"
" CommonHeader;\n"
@ -327,9 +336,20 @@ static const char Lua_header[] = ""
" struct LClosure *cache;\n"
" TString *source;\n"
" GCObject *gclist;\n"
" lu_byte cachemiss;\n"
" RaviJITProto ravi_jit;\n"
"} Proto;\n"
"typedef struct UpVal UpVal;\n"
"typedef struct UpVal {\n"
" CommonHeader;\n"
" TValue *v;\n"
" union {\n"
" struct {\n"
" struct UpVal *next;\n"
" struct UpVal **previous;\n"
" } open;\n"
" TValue value;\n"
" } u;\n"
"} UpVal;\n"
"#define ClosureHeader \\\n"
" CommonHeader; lu_byte nupvalues; GCObject *gclist\n"
"typedef struct CClosure {\n"
@ -348,21 +368,23 @@ static const char Lua_header[] = ""
"} Closure;\n"
"#define isLfunction(o) ttisLclosure(o)\n"
"#define getproto(o) (clLvalue(o)->p)\n"
"typedef union TKey {\n"
" struct {\n"
"typedef union Node {\n"
" struct NodeKey {\n"
" TValuefields;\n"
" lu_byte key_tt;\n"
" int next;\n"
" } nk;\n"
" TValue tvk;\n"
"} TKey;\n"
"#define setnodekey(L,key,obj) \\\n"
" { TKey *k_=(key); const TValue *io_=(obj); \\\n"
" k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \\\n"
" (void)L; checkliveness(L,io_); }\n"
"typedef struct Node {\n"
" Value key_val;\n"
" } u;\n"
" TValue i_val;\n"
" TKey i_key;\n"
"} Node;\n"
"#define setnodekey(L,node,obj) \\\n"
" { Node *n_=(node); const TValue *io_=(obj); \\\n"
" n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; \\\n"
" (void)L; checkliveness(L,io_); }\n"
"#define getnodekey(L,obj,node) \\\n"
" { TValue *io_=(obj); const Node *n_=(node); \\\n"
" io_->value_ = n_->u.key_val; io_->tt_ = n_->u.key_tt; \\\n"
" (void)L; checkliveness(L,io_); }\n"
"typedef enum RaviArrayModifer {\n"
" RAVI_ARRAY_SLICE = 1,\n"
" RAVI_ARRAY_FIXEDSIZE = 2\n"
@ -389,6 +411,18 @@ static const char Lua_header[] = ""
" unsigned int hmask;\n"
#endif
"} Table;\n"
"#define keytt(node) ((node)->u.key_tt)\n"
"#define keyval(node) ((node)->u.key_val)\n"
"#define keyisnil(node) (keytt(node) == LUA_TNIL)\n"
"#define keyisinteger(node) (keytt(node) == LUA_TNUMINT)\n"
"#define keyival(node) (keyval(node).i)\n"
"#define keyisshrstr(node) (keytt(node) == ctb(LUA_TSHRSTR))\n"
"#define keystrval(node) (gco2ts(keyval(node).gc))\n"
"#define setnilkey(node) (keytt(node) = LUA_TNIL)\n"
"#define keyiscollectable(n) (keytt(n) & BIT_ISCOLLECTABLE)\n"
"#define gckey(n) (keyval(n).gc)\n"
"#define gckeyN(n) (keyiscollectable(n) ? gckey(n) : NULL)\n"
"#define setdeadkey(n) (keytt(n) = LUA_TTABLE, gckey(n) = NULL)\n"
"typedef struct Mbuffer {\n"
" char *buffer;\n"
" size_t n;\n"
@ -475,17 +509,6 @@ static const char Lua_header[] = ""
" struct Proto p;\n"
" struct lua_State th;\n"
"};\n"
"struct UpVal {\n"
" TValue *v;\n"
" lu_mem refcount;\n"
" union {\n"
" struct {\n"
" UpVal *next;\n"
" int touched;\n"
" } open;\n"
" TValue value;\n"
" } u;\n"
"};\n"
"#define cast_u(o) cast(union GCUnion *, (o))\n"
"#define gco2ts(o) \\\n"
" check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts))\n"

@ -397,7 +397,7 @@ llvm::Value *RaviCodeGenerator::emit_table_get_nodearray(RaviFunctionDef *def,
llvm::Value *RaviCodeGenerator::emit_table_get_keytype(RaviFunctionDef *def,
llvm::Value *node,
llvm::Value *index) {
llvm::Value *ktype_ptr = emit_gep(def, "keytype", node, index, 1, 1);
llvm::Value *ktype_ptr = emit_gep(def, "keytype", node, index, 0, 2);
llvm::Instruction *ktype = def->builder->CreateLoad(ktype_ptr);
ktype->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_ttT);
return ktype;
@ -409,7 +409,7 @@ llvm::Value *RaviCodeGenerator::emit_table_get_keytype(RaviFunctionDef *def,
llvm::Value *RaviCodeGenerator::emit_table_get_strkey(RaviFunctionDef *def,
llvm::Value *node,
llvm::Value *index) {
llvm::Value *value_ptr = emit_gep(def, "keyvalue", node, index, 1, 0);
llvm::Value *value_ptr = emit_gep(def, "keyvalue", node, index, 1, 4);
llvm::Value *sptr =
def->builder->CreateBitCast(value_ptr, def->types->ppTStringT);
llvm::Instruction *keyvalue = def->builder->CreateLoad(sptr);
@ -423,7 +423,11 @@ llvm::Value *RaviCodeGenerator::emit_table_get_strkey(RaviFunctionDef *def,
llvm::Value *RaviCodeGenerator::emit_table_get_value(RaviFunctionDef *def,
llvm::Value *node,
llvm::Value *index) {
return emit_gep(def, "nodeval", node, index, 0);
llvm::Value *value = emit_gep(def, "nodeval", node, index, 0);
// We need to cast it to TValue *
llvm::Value *ptr =
def->builder->CreateBitCast(value, def->types->pTValueT);
return ptr;
}
// Gets the size of the table's array part
@ -705,50 +709,48 @@ llvm::Value *RaviCodeGenerator::emit_ci_is_Lua(RaviFunctionDef *def,
}
#endif
void RaviCodeGenerator::emit_GC_upvalbarrier(RaviFunctionDef *def,
llvm::Instruction *upval,
llvm::Value *v) {
// Parameters:
// UpVal *upval = cl->upvals[GETARG_B(i)];
// v = uv->v;
//
// Goal is to generate:
// #define upisopen(up) ((up)->v != &(up)->u.value)
// #define luaC_upvalbarrier(L,uv) ( \
// (iscollectable((uv)->v) && !upisopen(uv)) ? \
// luaC_upvalbarrier_(L,uv) : cast_void(0))
//
// is uv->v collectible?
llvm::Value *type = emit_load_type(def, v);
// FIXME below is broken
void RaviCodeGenerator::emit_GC_barrier(RaviFunctionDef *def,
llvm::Value *upval,
llvm::Value *ra) {
//Goal is to generate:
//int ra_iscollectable = iscollectable(ra);
//int uv_isblack = isblack(uv);
//int rav_iswhite = iswhite(gcvalue(ra));
//if (ra_iscollectable && uv_isblack && rav_iswhite)
// luaC_barrier_(L, uv, ra);
// is ra collectible?
llvm::Value *type = emit_load_type(def, ra);
llvm::Value *is_collectible =
def->builder->CreateAnd(type, def->types->kInt[BIT_ISCOLLECTABLE]);
// Is uv->v != uv->u.value?
llvm::Value *value = emit_gep_upval_value(def, upval); // get uv->u.value
llvm::Value *cmp = def->builder->CreateICmpNE(v, value, "v.ne.value");
// What we do here is:
// if (!collectible(v) || upisopen(uv)) {
// goto end;
// }
// else {
// luaC_upvalbarrier_(L,uv);
// }
// end:
llvm::Value *tobool = def->builder->CreateICmpEQ(
is_collectible, def->types->kInt[0], "not.collectible");
llvm::Value *orcond =
def->builder->CreateOr(cmp, tobool, "v.ne.value.or.not.collectible");
def->builder->CreateAnd(type, def->types->kInt[BIT_ISCOLLECTABLE]);
llvm::Value *upval_marked_ptr = emit_gep(def, "o_marked_ptr", upval, 0, 2);
llvm::Value *upval_marked = def->builder->CreateLoad(upval_marked_ptr, "o_marked");
llvm::Value *is_black = def->builder->CreateAnd(upval_marked, def->types->kInt[bitmask(BLACKBIT)]);
llvm::Value *gcobj_ptr = emit_gep(def, "v_gcobj_ptr", ra, 0, 0, 0);
llvm::Value *gcobj = def->builder->CreateLoad(gcobj_ptr, "v_gcobj");
llvm::Value *marked3_ptr = emit_gep(def, "marked3", gcobj, 0, 2);
llvm::Value *marked3 = def->builder->CreateLoad(marked3_ptr, "marked3");
llvm::Value *is_white = def->builder->CreateAnd(marked3, def->types->kInt[WHITEBITS]);
llvm::Value *cmp1 = def->builder->CreateICmpNE(is_collectible, def->types->kInt[0], "tobool1");
llvm::Value *cmp2 = def->builder->CreateICmpNE(is_black, def->types->kInt[0], "tobool2");
llvm::Value *and1 = def->builder->CreateAnd(cmp1, cmp2);
llvm::Value *cmp3 = def->builder->CreateICmpNE(is_white, def->types->kInt[0], "tobool3");
llvm::Value *and2 = def->builder->CreateAnd(and1, cmp3);
llvm::BasicBlock *then =
llvm::BasicBlock::Create(def->jitState->context(), "if.then", def->f);
llvm::BasicBlock::Create(def->jitState->context(), "if.then", def->f);
llvm::BasicBlock *end =
llvm::BasicBlock::Create(def->jitState->context(), "if.end");
llvm::BasicBlock::Create(def->jitState->context(), "if.end");
def->builder->CreateCondBr(orcond, end, then);
def->builder->CreateCondBr(and2, then, end);
def->builder->SetInsertPoint(then);
CreateCall2(def->builder, def->luaC_upvalbarrierF, def->L, upval);
// FIXME
CreateCall3(def->builder, def->luaC_barrierF, def->L, def->builder->CreateBitCast(upval, def->types->pGCObjectT), gcobj_ptr);
def->builder->CreateBr(end);
def->f->getBasicBlockList().push_back(end);
@ -1137,9 +1139,9 @@ void RaviCodeGenerator::emit_extern_declarations(RaviFunctionDef *def) {
def->luaV_objlenF = def->raviF->addExternFunction(
def->types->luaV_objlenT, reinterpret_cast<void *>(&luaV_objlen),
"luaV_objlen");
def->luaC_upvalbarrierF = def->raviF->addExternFunction(
def->types->luaC_upvalbarrierT,
reinterpret_cast<void *>(&luaC_upvalbarrier_), "luaC_upvalbarrier_");
def->luaC_barrierF = def->raviF->addExternFunction(
def->types->luaC_barrierT,
reinterpret_cast<void *>(&luaC_barrier_), "luaC_barrier_");
def->raviV_op_concatF = def->raviF->addExternFunction(
def->types->raviV_op_concatT, reinterpret_cast<void *>(&raviV_op_concat),
"raviV_op_concat");
@ -1336,13 +1338,7 @@ llvm::Instruction *RaviCodeGenerator::emit_load_upval_v(
// Get &upval->v
llvm::Value *RaviCodeGenerator::emit_gep_upval_v(RaviFunctionDef *def,
llvm::Instruction *pupval) {
return emit_gep(def, "v", pupval, 0, 0);
}
// Get &upval->value -> result is TValue *
llvm::Value *RaviCodeGenerator::emit_gep_upval_value(
RaviFunctionDef *def, llvm::Instruction *pupval) {
return emit_gep(def, "value", pupval, 0, 2);
return emit_gep(def, "v", pupval, 0, 3);
}
bool RaviCodeGenerator::compile(lua_State *L, Proto *p,

@ -764,7 +764,7 @@ void RaviCodeGenerator::emit_SETUPVAL(RaviFunctionDef *def, int A, int B,
llvm::Value *v = emit_load_upval_v(def, upval);
emit_assign(def, v, ra);
emit_GC_upvalbarrier(def, upval, v);
emit_GC_barrier(def, upval, ra);
}
// R(A) := UpValue[B][RK(C)]

@ -168,15 +168,20 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
elements.push_back(lua_NumberT);
ValueT->setBody(elements);
// NOTE: Following structure changes when NaN tagging is enabled
// Create a synonym type with gc member
ValueGCT = llvm::StructType::create(context, "union.ValueGC");
elements.clear();
elements.push_back(pGCObjectT);
ValueGCT->setBody(elements);
// struct TValue {
// union Value value_;
// int tt_;
// lu_byte tt_;
// };
TValueT = llvm::StructType::create(context, "struct.TValue");
elements.clear();
elements.push_back(ValueT);
elements.push_back(C_intT);
elements.push_back(lu_byteT);
TValueT->setBody(elements);
pTValueT = llvm::PointerType::get(TValueT, 0);
@ -253,44 +258,14 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
///*
//** Description of an upvalue for function prototypes
//*/
// typedef struct Upvaldesc {
// TString *name; /* upvalue name (for debug information) */
// ravitype_t type;
// lu_byte instack; /* whether it is in stack */
// lu_byte idx; /* index of upvalue (in stack or in outer function's list)
// */
//}Upvaldesc;
UpvaldescT = llvm::StructType::create(context, "struct.Upvaldesc");
// FIXME (issue #136) this structure is changing hence better to keep it
// opaque
// elements.clear();
// elements.push_back(pTStringT); /* name */
// elements.push_back(ravitype_tT); /* type */
// elements.push_back(lu_byteT); /* instack */
// elements.push_back(lu_byteT); /* idx */
// UpvaldescT->setBody(elements);
pUpvaldescT = llvm::PointerType::get(UpvaldescT, 0);
///*
//** Description of a local variable for function prototypes
//** (used for debug information)
//*/
// typedef struct LocVar {
// TString *varname;
// int startpc; /* first point where variable is active */
// int endpc; /* first point where variable is dead */
// ravitype_t ravi_type; /* RAVI type of the variable - RAVI_TANY if unknown
// */
//} LocVar;
LocVarT = llvm::StructType::create(context, "struct.LocVar");
// FIXME (issue #136) this structure is changing hence better to keep it
// opaque
// elements.clear();
// elements.push_back(pTStringT); /* varname */
// elements.push_back(C_intT); /* startpc */
// elements.push_back(C_intT); /* endpc */
// elements.push_back(ravitype_tT); /* ravi_type */
// LocVarT->setBody(elements);
pLocVarT = llvm::PointerType::get(LocVarT, 0);
LClosureT = llvm::StructType::create(context, "struct.LClosure");
@ -333,6 +308,7 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
// struct LClosure *cache; /* last created closure with this prototype */
// TString *source; /* used for debug information */
// GCObject *gclist;
// lu_byte cachemiss; /* count for successive misses for 'cache' field */
// /* RAVI */
// RaviJITProto ravi_jit;
//} Proto;
@ -364,6 +340,7 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
elements.push_back(pLClosureT); /* cache */
elements.push_back(pTStringT); /* source */
elements.push_back(pGCObjectT); /* gclist */
elements.push_back(lu_byteT); /* cachemiss */
elements.push_back(RaviJITProtoT); /* ravi_jit */
ProtoT->setBody(elements);
@ -417,31 +394,20 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
//** Tables
//*/
// NOTE following structure changes when NaN Tagging is enabled
// typedef union TKey {
// struct {
// TValuefields;
// int next; /* for chaining (offset for next node) */
// } nk;
// TValue tvk;
//} TKey;
TKeyT = llvm::StructType::create(context, "struct.TKey");
elements.clear();
elements.push_back(ValueT);
elements.push_back(C_intT);
elements.push_back(C_intT); /* next */
TKeyT->setBody(elements);
pTKeyT = llvm::PointerType::get(TKeyT, 0);
// typedef struct Node {
// TValue i_val;
// TKey i_key;
//} Node;
// We ignore the union in Node definition
//struct NodeKey {
// TValuefields; /* fields for value */
// lu_byte key_tt; /* key type */
// int next; /* for chaining */
// Value key_val; /* key value */
//};
NodeT = llvm::StructType::create(context, "struct.Node");
elements.clear();
elements.push_back(TValueT); /* i_val */
elements.push_back(TKeyT); /* i_key */
elements.push_back(ValueT); /* Value fields */
elements.push_back(lu_byteT);
elements.push_back(lu_byteT); /* key_tt */
elements.push_back(C_intT); /* next */
elements.push_back(ValueT); /* key_val */
NodeT->setBody(elements);
pNodeT = llvm::PointerType::get(NodeT, 0);
@ -692,20 +658,22 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
elements.push_back(C_shortT);
lua_StateT->setBody(elements);
// struct UpVal {
// struct TValue *v; /* points to stack or to its own value */
// unsigned long long refcount; /* reference counter */
// union {
// struct { /* (when open) */
// struct UpVal *next; /* linked list */
// int touched; /* mark to avoid cycles with dead threads */
// } open;
// struct TValue value; /* the value (when closed) */
// } u;
//};
//typedef struct UpVal {
// CommonHeader;
// TValue *v; /* points to stack or to its own value */
// union {
// struct { /* (when open) */
// struct UpVal *next; /* linked list */
// struct UpVal **previous;
// } open;
// TValue value; /* the value (when closed) */
// } u;
//} UpVal;
elements.clear();
elements.push_back(pGCObjectT);
elements.push_back(lu_byteT);
elements.push_back(lu_byteT);
elements.push_back(pTValueT);
elements.push_back(C_size_t);
elements.push_back(TValueT);
UpValT->setBody(elements);
@ -717,11 +685,12 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
elements.push_back(C_intT);
luaD_poscallT = llvm::FunctionType::get(C_intT, elements, false);
// void luaC_upvalbarrier_ (lua_State *L, UpVal *uv)
// void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
elements.clear();
elements.push_back(plua_StateT);
elements.push_back(pUpValT);
luaC_upvalbarrierT =
elements.push_back(pGCObjectT);
elements.push_back(pGCObjectT);
luaC_barrierT =
llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false);
// int luaD_precall (lua_State *L, StkId func, int nresults, int op_call);
@ -1243,7 +1212,7 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
nodes.clear();
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_longlongT, 0));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_intT, 8));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_charT, 8));
tbaa_TValueT = mdbuilder.createTBAAStructTypeNode("TValue", nodes);
tbaa_TValue_nT =
@ -1251,18 +1220,20 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
tbaa_TValue_hT =
mdbuilder.createTBAAStructTagNode(tbaa_pointerT, tbaa_pointerT, 0);
tbaa_TValue_ttT =
mdbuilder.createTBAAStructTagNode(tbaa_TValueT, tbaa_intT, 8);
mdbuilder.createTBAAStructTagNode(tbaa_TValueT, tbaa_charT, 8);
tbaa_luaState_topT =
mdbuilder.createTBAAStructTagNode(tbaa_luaStateT, tbaa_pointerT, 8);
nodes.clear();
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_pointerT, 0));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_longlongT, 8));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_TValueT, 16));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_charT, 8));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_charT, 9));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_pointerT, 16));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_TValueT, 24));
tbaa_UpValT = mdbuilder.createTBAAStructTypeNode("UpVal", nodes);
tbaa_UpVal_vT =
mdbuilder.createTBAAStructTagNode(tbaa_UpValT, tbaa_pointerT, 0);
mdbuilder.createTBAAStructTagNode(tbaa_UpValT, tbaa_pointerT, 16);
// RaviArray
nodes.clear();

Loading…
Cancel
Save