Compare commits

...

22 Commits

Author SHA1 Message Date
Dibyendu Majumdar 68b0359383 resolve merge conflict
6 years ago
Dibyendu Majumdar be17c645c3 merge master
6 years ago
Dibyendu Majumdar 56c3af3285 merge master
6 years ago
Dibyendu Majumdar 320e6b5da6 issue #145 merge into lua54 branch
6 years ago
Dibyendu Majumdar e75b146bfc issue #140 missed change!
6 years ago
Dibyendu Majumdar 6cea3bc383 Merge branch 'master' into lua54
6 years ago
Dibyendu Majumdar 64dfadd3a6 tools update
6 years ago
Dibyendu Majumdar 6bbfb88799 issue #141 remove calls to GC from inside JIT compiler
6 years ago
Dibyendu Majumdar b450f3dac3 fix issue with recursive compiles
6 years ago
dylan ef7a270433 issue #139 maybe a bug in recursive compilation plus avoid requiring C++14
6 years ago
Dibyendu Majumdar 3426e55dd8 issue #139 some more merge
6 years ago
Dibyendu Majumdar 7c8e9bcf27 issue #139 In Ravi table has two additional sub types that need to be handled in GC
6 years ago
Dibyendu Majumdar 60b75db2ed issue #139 merge gc related changes
6 years ago
Dibyendu Majumdar bc68457199 issue #139 merge gc related changes
6 years ago
Dibyendu Majumdar 6bdfe1fbd2 issue #139 merge gc related changes
6 years ago
Dibyendu Majumdar 123fb4079a issue #139 lost in translation
6 years ago
Dibyendu Majumdar 7c5b846a7b issue #139 various bug fixes
6 years ago
Dibyendu Majumdar 971b548f1b issue #139 work in progress
6 years ago
Dibyendu Majumdar 157bc43162 issue #139 work in progress
6 years ago
Dibyendu Majumdar caf59c84a7 issue #139 refactor to enable upcoming changes in GC
6 years ago
Dibyendu Majumdar 136dd5623b issue #139 lua 5.4 merge e6c1e6005a
6 years ago
Dibyendu Majumdar 87cf534302 issue #139 lua 5.4 merge d266d40dea
6 years ago

@ -3,5 +3,6 @@ cd llvm64
rem pre LLVM 3.9 rem pre LLVM 3.9
rem cmake -DCMAKE_INSTALL_PREFIX=c:\ravi -G "Visual Studio 14 Win64" -DLLVM_JIT=ON -DLLVM_DIR=c:\LLVM37\share\llvm\cmake .. rem cmake -DCMAKE_INSTALL_PREFIX=c:\ravi -G "Visual Studio 14 Win64" -DLLVM_JIT=ON -DLLVM_DIR=c:\LLVM37\share\llvm\cmake ..
rem cmake -DCMAKE_INSTALL_PREFIX=c:\ravi -G "Visual Studio 15 2017 Win64" -DLLVM_JIT=ON -DLLVM_DIR=c:\d\LLVM40_64\lib\cmake\llvm .. rem cmake -DCMAKE_INSTALL_PREFIX=c:\ravi -G "Visual Studio 15 2017 Win64" -DLLVM_JIT=ON -DLLVM_DIR=c:\d\LLVM40_64\lib\cmake\llvm ..
cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -G "Visual Studio 15 2017 Win64" -DSTATIC_BUILD=ON -DLLVM_JIT=ON -DLLVM_DIR=c:\Software\llvm501r\lib\cmake\llvm .. cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -G "Visual Studio 15 2017 Win64" -DCMAKE_BUILD_TYPE=Release -DLLVM_JIT=ON -DLLVM_DIR=c:\Software\llvm501r\lib\cmake\llvm ..
cd .. rem cmake -DCMAKE_INSTALL_PREFIX=c:\Software\ravi -G "Visual Studio 15 2017 Win64" -DSTATIC_BUILD=ON -DLLVM_JIT=ON -DLLVM_DIR=c:\Software\llvm501r\lib\cmake\llvm ..
cd ..

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

@ -1,17 +1,14 @@
#include "lua_hdr.h" #include "lua_hdr.h"
extern int printf(const char *, ...); extern int printf(const char *, ...);
extern void luaC_upvalbarrier_ (struct lua_State *L, struct UpVal *uv); extern void luaC_upvalbarrier_ (struct lua_State *L, struct GCObject *o, struct GCObject *v);
void luaV_op_call(struct lua_State *L, struct LClosure *cl, struct TValue *ra, int b, int c) { void luaV_op_call(struct lua_State *L, struct LClosure *cl, struct TValue *ra, int b, int c) {
struct UpVal *uv = cl->upvals[b]; struct UpVal *uv = cl->upvals[b];
uv->v->tt_ = ra->tt_; int ra_iscollectable = iscollectable(ra);
uv->v->value_.n = ra->value_.n; int uv_isblack = isblack(uv);
int b1 = iscollectable(uv->v); int rav_iswhite = iswhite(gcvalue(ra));
uv->u.value.tt_ = 1; if (ra_iscollectable && uv_isblack && rav_iswhite)
struct TValue *value = &uv->u.value; luaC_upvalbarrier_(L,(struct GCObject *)uv, ra->value_.gc);
int b2 = uv->v != value;
if (b1 && !b2)
luaC_upvalbarrier_(L,uv);
} }

@ -1,83 +1,79 @@
; ModuleID = 'lua_upval.c' ; ModuleID = 'lua_upval.c'
target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32" source_filename = "lua_upval.c"
target triple = "i686-pc-windows-gnu" 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.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.CallInfoL = type { %struct.TValue*, i32*, i64 }
%struct.UpVal = type { %struct.TValue*, i64, %union.anon.0 } %struct.UpVal = type { %struct.GCObject*, i8, i8, %struct.TValue*, %union.anon.0 }
%union.anon.0 = type { %struct.TValue } %union.anon.0 = type { %struct.anon }
%struct.TValue = type { %union.Value, i32 } %struct.anon = type { %struct.UpVal*, %struct.UpVal** }
%union.Value = type { i64 }
%struct.GCObject = type { %struct.GCObject*, i8, i8 } %struct.GCObject = type { %struct.GCObject*, i8, i8 }
%struct.lua_longjmp = type opaque %struct.lua_longjmp = type opaque
%struct.CallInfo = type { %struct.TValue*, %struct.TValue*, %struct.CallInfo*, %struct.CallInfo*, %union.anon, i64, i16, i8, i8 } %struct.CallInfo = type { %struct.TValue*, %struct.TValue*, %struct.CallInfo*, %struct.CallInfo*, %union.anon, i64, i16, i8, i8 }
%union.anon = type { %struct.CallInfoC } %union.anon = type { %struct.CallInfoL }
%struct.CallInfoC = type { i32 (%struct.lua_State*, i32, i64)*, i64, i64 }
%struct.lua_Debug = type opaque %struct.lua_Debug = type opaque
%struct.LClosure = type { %struct.GCObject*, i8, i8, i8, %struct.GCObject*, %struct.Proto*, [1 x %struct.UpVal*] } %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.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*, i32, i32, i32 } %struct.LocVar = type { %struct.TString*, %struct.TString*, i32, i32, i8 }
%struct.Upvaldesc = type { %struct.TString*, i32, i8, i8 } %struct.Upvaldesc = type { %struct.TString*, %struct.TString*, i8, i8, i8 }
%struct.TString = type { %struct.GCObject*, i8, i8, i8, i32, i64, %struct.TString* } %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.RaviJITProto = type { i8, i8*, i32 (%struct.lua_State*)* }
%struct.TValue = type { %union.Value, i8 }
%union.Value = type { %struct.GCObject* }
; Function Attrs: nounwind ; 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: entry:
%arrayidx = getelementptr inbounds %struct.LClosure* %cl, i32 0, i32 6, i32 %b %idxprom = sext i32 %b to i64
%0 = load %struct.UpVal** %arrayidx, align 4, !tbaa !1 %arrayidx = getelementptr inbounds %struct.LClosure, %struct.LClosure* %cl, i64 0, i32 6, i64 %idxprom
%tt_ = getelementptr inbounds %struct.TValue* %ra, i32 0, i32 1 %0 = load %struct.UpVal*, %struct.UpVal** %arrayidx, align 8, !tbaa !1
%1 = load i32* %tt_, align 4, !tbaa !5 %tt_ = getelementptr inbounds %struct.TValue, %struct.TValue* %ra, i64 0, i32 1
%v = getelementptr inbounds %struct.UpVal* %0, i32 0, i32 0 %1 = load i8, i8* %tt_, align 8, !tbaa !5
%2 = load %struct.TValue** %v, align 4, !tbaa !8 %2 = and i8 %1, 64
%tt_1 = getelementptr inbounds %struct.TValue* %2, i32 0, i32 1 %marked = getelementptr inbounds %struct.UpVal, %struct.UpVal* %0, i64 0, i32 2
store i32 %1, i32* %tt_1, align 4, !tbaa !5 %3 = load i8, i8* %marked, align 1, !tbaa !7
%n = bitcast %struct.TValue* %ra to double* %4 = and i8 %3, 32
%3 = load double* %n, align 8, !tbaa !11 %gc = getelementptr inbounds %struct.TValue, %struct.TValue* %ra, i64 0, i32 0, i32 0
%4 = bitcast %struct.UpVal* %0 to double** %5 = load %struct.GCObject*, %struct.GCObject** %gc, align 8, !tbaa !1
%5 = load double** %4, align 4, !tbaa !8 %marked3 = getelementptr inbounds %struct.GCObject, %struct.GCObject* %5, i64 0, i32 2
store double %3, double* %5, align 8, !tbaa !11 %6 = load i8, i8* %marked3, align 1, !tbaa !9
%6 = load %struct.TValue** %v, align 4, !tbaa !8 %7 = and i8 %6, 24
%tt_6 = getelementptr inbounds %struct.TValue* %6, i32 0, i32 1 %tobool = icmp ne i8 %2, 0
%7 = load i32* %tt_6, align 4, !tbaa !5 %tobool6 = icmp ne i8 %4, 0
%and = and i32 %7, 64 %or.cond = and i1 %tobool, %tobool6
%value = getelementptr inbounds %struct.UpVal* %0, i32 0, i32 2, i32 0 %tobool8 = icmp ne i8 %7, 0
%tt_7 = getelementptr inbounds %struct.UpVal* %0, i32 0, i32 2, i32 0, i32 1 %or.cond11 = and i1 %or.cond, %tobool8
store i32 1, i32* %tt_7, align 4, !tbaa !5 br i1 %or.cond11, label %if.then, label %if.end
%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
if.then: ; preds = %entry if.then: ; preds = %entry
tail call void @luaC_upvalbarrier_(%struct.lua_State* %L, %struct.UpVal* %0) #2 %8 = bitcast %struct.UpVal* %0 to %struct.GCObject*
tail call void @luaC_upvalbarrier_(%struct.lua_State* %L, %struct.GCObject* %8, %struct.GCObject* %5) #2
br label %if.end br label %if.end
if.end: ; preds = %entry, %if.then if.end: ; preds = %if.then, %entry
ret void ret void
} }
declare void @luaC_upvalbarrier_(%struct.lua_State*, %struct.UpVal*) #1 declare void @luaC_upvalbarrier_(%struct.lua_State*, %struct.GCObject*, %struct.GCObject*) 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 #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 = { "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 = { "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 } attributes #2 = { nounwind }
!llvm.ident = !{!0} !llvm.ident = !{!0}
!0 = metadata !{metadata !"clang version 3.6.0 (trunk)"} !0 = !{!"clang version 4.0.0 (tags/RELEASE_400/final)"}
!1 = metadata !{metadata !2, metadata !2, i64 0} !1 = !{!2, !2, i64 0}
!2 = metadata !{metadata !"any pointer", metadata !3, i64 0} !2 = !{!"any pointer", !3, i64 0}
!3 = metadata !{metadata !"omnipotent char", metadata !4, i64 0} !3 = !{!"omnipotent char", !4, i64 0}
!4 = metadata !{metadata !"Simple C/C++ TBAA"} !4 = !{!"Simple C/C++ TBAA"}
!5 = metadata !{metadata !6, metadata !7, i64 8} !5 = !{!6, !3, i64 8}
!6 = metadata !{metadata !"TValue", metadata !3, i64 0, metadata !7, i64 8} !6 = !{!"TValue", !3, i64 0, !3, i64 8}
!7 = metadata !{metadata !"int", metadata !3, i64 0} !7 = !{!8, !3, i64 9}
!8 = metadata !{metadata !9, metadata !2, i64 0} !8 = !{!"UpVal", !2, i64 0, !3, i64 8, !3, i64 9, !2, i64 16, !3, i64 24}
!9 = metadata !{metadata !"UpVal", metadata !2, i64 0, metadata !10, i64 8, metadata !3, i64 16} !9 = !{!10, !3, i64 9}
!10 = metadata !{metadata !"long long", metadata !3, i64 0} !10 = !{!"GCObject", !2, i64 0, !3, i64 8, !3, i64 9}
!11 = metadata !{metadata !12, metadata !12, i64 0}
!12 = metadata !{metadata !"double", metadata !3, i64 0}

@ -29,23 +29,17 @@
#define MAXUPVAL 125 #define MAXUPVAL 125
/* RAVI change; #define MAXUPVAL 255 */ /* 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 { #define MAXMISS 10
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)
LUAI_FUNC Proto *luaF_newproto (lua_State *L); 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 void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (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); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
/* The additional type argument is a Ravi extension */ /* The additional type argument is a Ravi extension */
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, 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 ** Possible states of the Garbage Collector
*/ */
#define GCSpropagate 0 #define GCSpropagate 0
#define GCSatomic 1 #define GCSenteratomic 1
#define GCSswpallgc 2 #define GCSatomic 2
#define GCSswpfinobj 3 #define GCSswpallgc 3
#define GCSswptobefnz 4 #define GCSswpfinobj 4
#define GCSswpend 5 #define GCSswptobefnz 5
#define GCScallfin 6 #define GCSswpend 6
#define GCSpause 7 #define GCScallfin 7
#define GCSpause 8
#define issweepphase(g) \ #define issweepphase(g) \
@ -74,12 +67,16 @@
#define testbit(x,b) testbits(x, bitmask(b)) #define testbit(x,b) testbits(x, bitmask(b))
/* Layout for bit use in 'marked' field: */ /*
#define WHITE0BIT 0 /* object is white (type 0) */ ** Layout for bit use in 'marked' field. First three bits are
#define WHITE1BIT 1 /* object is white (type 1) */ ** used for object "age" in generational mode.
#define BLACKBIT 2 /* object is black */ */
#define FINALIZEDBIT 3 /* object has been marked for finalization */ #define WHITE0BIT 3 /* object is white (type 0) */
/* bit 7 is currently used by tests (luaL_checkmemory) */ #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 WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
@ -92,7 +89,7 @@
#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) #define tofinalize(x) testbit((x)->marked, FINALIZEDBIT)
#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS) #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 isdead(g,v) isdeadm(otherwhite(g), (v)->marked)
#define changewhite(x) ((x)->marked ^= WHITEBITS) #define changewhite(x) ((x)->marked ^= WHITEBITS)
@ -101,6 +98,45 @@
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) #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 12
/* wait memory to double before starting new cycle */
#define LUAI_GCPAUSE 200 /* 200% */
/*
** gc parameters ae stored divided by 4 to allow a maximum value larger
** than 1000 in an 'lu_byte'.
*/
#define getgcparam(p) ((p) * 4)
#define setgcparam(p,v) ((p) = (v) / 4)
#define LUAI_GCMUL 100
/* 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' ** Does one step of collection when debt becomes positive. 'pre'/'pos'
** allows some adjustments to be done only when needed. macro ** allows some adjustments to be done only when needed. macro
@ -127,9 +163,8 @@
(isblack(p) && iswhite(o)) ? \ (isblack(p) && iswhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
#define luaC_upvalbarrier(L,uv) ( \ #define luaC_protobarrier(L,p,o) \
(iscollectable((uv)->v) && !upisopen(uv)) ? \ (isblack(p) ? luaC_protobarrier_(L,p) : cast_void(0))
luaC_upvalbarrier_(L,uv) : cast_void(0))
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L); LUAI_FUNC void luaC_freeallobjects (lua_State *L);
@ -139,9 +174,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 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_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o); 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_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 #endif

@ -33,6 +33,7 @@ typedef long l_mem;
/* chars used as small naturals (so that 'char' is reserved for characters) */ /* chars used as small naturals (so that 'char' is reserved for characters) */
typedef unsigned char lu_byte; typedef unsigned char lu_byte;
typedef signed char ls_byte;
/* maximum value for size_t */ /* maximum value for size_t */
@ -51,6 +52,13 @@ typedef unsigned char lu_byte;
#define MAX_INT INT_MAX /* maximum value of an int */ #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: ** conversion of pointer to unsigned integer:
** this is for hashing only; there is no problem if the integer ** this is for hashing only; there is no problem if the integer

@ -19,11 +19,11 @@
/* /*
** Extra tags for non-values ** Extra tags for non-values
*/ */
#define LUA_TPROTO LUA_NUMTAGS /* function prototypes */ #define LUA_TUPVAL LUA_NUMTAGS /* upvalues */
#define LUA_TDEADKEY (LUA_NUMTAGS+1) /* removed keys in tables */ #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) #define LUA_TOTALTAGS (LUA_TPROTO + 2)
@ -124,6 +124,7 @@ typedef struct lua_TValue {
#define val_(o) ((o)->value_) #define val_(o) ((o)->value_)
#define valraw(o) (&val_(o))
/* raw type tag of a TValue */ /* raw type tag of a TValue */
@ -133,7 +134,8 @@ typedef struct lua_TValue {
#define novariant(x) ((x) & 0x0F) #define novariant(x) ((x) & 0x0F)
/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */ /* 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) */ /* type tag of a TValue with no variants (bits 0-3) */
#define ttnov(o) (novariant(rttype(o))) #define ttnov(o) (novariant(rttype(o)))
@ -169,7 +171,19 @@ typedef struct lua_TValue {
#define ttislcf(o) checktag((o), LUA_TLCF) #define ttislcf(o) checktag((o), LUA_TLCF)
#define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA)) #define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA))
#define ttisthread(o) checktag((o), ctb(LUA_TTHREAD)) #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 */ /* Macros to access values */
@ -188,8 +202,6 @@ typedef struct lua_TValue {
#define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc)) #define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc))
#define bvalue(o) check_exp(ttisboolean(o), val_(o).b) #define bvalue(o) check_exp(ttisboolean(o), val_(o).b)
#define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc)) #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)) #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) #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 */ /* Macros for internal tests */
#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt) #define righttt(obj) (ttype(obj) == gcvalue(obj)->tt)
@ -277,10 +295,6 @@ typedef struct lua_TValue {
val_(io).gc = obj2gco(x_); settt_(io, ctb(RAVI_TFARRAY)); \ val_(io).gc = obj2gco(x_); settt_(io, ctb(RAVI_TFARRAY)); \
checkliveness(L,io); } checkliveness(L,io); }
#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY)
#define setobj(L,obj1,obj2) \ #define setobj(L,obj1,obj2) \
{ TValue *io1=(obj1); const TValue *io2=(obj2); \ { TValue *io1=(obj1); const TValue *io2=(obj2); \
io1->value_ = io2->value_; io1->tt_ = io2->tt_; \ io1->value_ = io2->value_; io1->tt_ = io2->tt_; \
@ -297,7 +311,9 @@ typedef struct lua_TValue {
#define setobj2s setobj #define setobj2s setobj
#define setsvalue2s setsvalue #define setsvalue2s setsvalue
#define sethvalue2s sethvalue #define sethvalue2s sethvalue
#define setthvalue2s setthvalue
#define setptvalue2s setptvalue #define setptvalue2s setptvalue
#define setclLvalue2s setclLvalue
/* from table to same table */ /* from table to same table */
#define setobjt2t setobj #define setobjt2t setobj
/* to new object */ /* to new object */
@ -494,6 +510,7 @@ typedef struct Proto {
struct LClosure *cache; /* last-created closure with this prototype */ struct LClosure *cache; /* last-created closure with this prototype */
TString *source; /* used for debug information */ TString *source; /* used for debug information */
GCObject *gclist; GCObject *gclist;
lu_byte cachemiss; /* count for successive misses for 'cache' field */
/* RAVI extension */ /* RAVI extension */
RaviJITProto ravi_jit; RaviJITProto ravi_jit;
} Proto; } 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 ** Tables
*/ */
typedef union TKey {
struct { /*
TValuefields; ** Nodes for Hash tables. A pack of two TValue's (key-value pairs)
int next; /* for chaining (offset for next node) */ ** plus a 'next' field to link colliding entries. The distribution
} nk; ** of the key's fields ('key_tt' and 'key_val') not forming a proper
TValue tvk; ** 'TValue' allows for a smaller size for 'Node' both in 4-byte
} TKey; ** 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' */ /* copy a value into a key */
#define setnodekey(L,key,obj) \ #define setnodekey(L,node,obj) \
{ TKey *k_=(key); const TValue *io_=(obj); \ { Node *n_=(node); const TValue *io_=(obj); \
k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \ n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; \
(void)L; checkliveness(L,io_); } (void)L; checkliveness(L,io_); }
typedef struct Node { /* copy a value from a key */
TValue i_val; #define getnodekey(L,obj,node) \
TKey i_key; { TValue *io_=(obj); const Node *n_=(node); \
} Node; io_->value_ = n_->u.key_val; io_->tt_ = n_->u.key_tt; \
(void)L; checkliveness(L,io_); }
/** RAVI extension */ /** RAVI extension */
typedef enum RaviArrayModifer { typedef enum RaviArrayModifer {
@ -597,6 +637,36 @@ typedef struct Table {
} 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) ** 'module' operation for hashing (size is always a power of 2)

@ -26,6 +26,25 @@
** 'tobefnz': all objects ready to be finalized; ** 'tobefnz': all objects ready to be finalized;
** 'fixedgc': all objects that are not to be collected (currently ** 'fixedgc': all objects that are not to be collected (currently
** only small strings, such as reserved words). ** only small strings, such as reserved words).
**
** Moreover, there is another set of lists that control gray objects.
** These lists are linked by fields 'gclist'. (All objects that
** can become gray have such a field. The field is not the same
** in all objects, but it always has this name.) Any gray object
** must belong to one of these lists, and all objects in these lists
** must be gray:
**
** 'gray': regular gray objects, still waiting to be visited.
** 'grayagain': objects that must be revisited at the atomic phase.
** That includes
** - black objects got in a write barrier;
** - all kinds of weak tables during propagation phase;
** - all threads.
** 'weak': tables with weak values to be cleared;
** 'ephemeron': ephemeron tables with white->white entries;
** 'allweak': tables with weak keys and/or weak values to be cleared.
** There is also a list 'protogray' for prototypes that need to have
** their caches cleared.
*/ */
@ -51,8 +70,8 @@ struct lua_longjmp; /* defined in ldo.c */
/* kinds of Garbage Collection */ /* kinds of Garbage Collection */
#define KGC_NORMAL 0 #define KGC_INC 0 /* incremental gc */
#define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */ #define KGC_GEN 1 /* generational gc */
typedef struct stringtable { typedef struct stringtable {
@ -128,7 +147,6 @@ typedef struct global_State {
void *ud; /* auxiliary data to 'frealloc' */ void *ud; /* auxiliary data to 'frealloc' */
l_mem totalbytes; /* number of bytes currently allocated - GCdebt */ l_mem totalbytes; /* number of bytes currently allocated - GCdebt */
l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ 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 */ lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
stringtable strt; /* hash table for strings */ stringtable strt; /* hash table for strings */
TValue l_registry; TValue l_registry;
@ -136,7 +154,13 @@ typedef struct global_State {
lu_byte currentwhite; lu_byte currentwhite;
lu_byte gcstate; /* state of garbage collector */ lu_byte gcstate; /* state of garbage collector */
lu_byte gckind; /* kind of GC running */ 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 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 *allgc; /* list of all collectable objects */
GCObject **sweepgc; /* current position of sweep in list */ GCObject **sweepgc; /* current position of sweep in list */
GCObject *finobj; /* list of collectable objects with finalizers */ GCObject *finobj; /* list of collectable objects with finalizers */
@ -145,12 +169,17 @@ typedef struct global_State {
GCObject *weak; /* list of tables with weak values */ GCObject *weak; /* list of tables with weak values */
GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
GCObject *allweak; /* list of all-weak tables */ GCObject *allweak; /* list of all-weak tables */
GCObject *protogray; /* list of prototypes with "new" caches */
GCObject *tobefnz; /* list of userdata to be GC */ GCObject *tobefnz; /* list of userdata to be GC */
GCObject *fixedgc; /* list of objects not to be collected */ 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 */ 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 */ lua_CFunction panic; /* to be called in unprotected errors */
struct lua_State *mainthread; struct lua_State *mainthread;
const lua_Number *version; /* pointer to version number */ const lua_Number *version; /* pointer to version number */
@ -227,6 +256,7 @@ union GCUnion {
struct Table h; struct Table h;
struct Proto p; struct Proto p;
struct lua_State th; /* thread */ struct lua_State th; /* thread */
struct UpVal upv;
}; };
@ -244,11 +274,11 @@ union GCUnion {
#define gco2t(o) check_exp(novariant((o)->tt) == LUA_TTABLE, &((cast_u(o))->h)) #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 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 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 */ /* macro to convert a Lua object into a GCObject */
#define obj2gco(v) \ #define obj2gco(v) (&(cast_u(v)->gc))
check_exp(novariant((v)->tt) < LUA_TDEADKEY, (&(cast_u(v)->gc)))
/* actual number of total bytes allocated */ /* actual number of total bytes allocated */

@ -12,18 +12,9 @@
#define gnode(t,i) (&(t)->node[i]) #define gnode(t,i) (&(t)->node[i])
#define gval(n) (&(n)->i_val) #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) #define invalidateTMcache(t) ((t)->flags = 0)
@ -35,9 +26,8 @@
#define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t)) #define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t))
/* returns the key, given the value of a table entry */ /* returns the Node, given the value of a table entry */
#define keyfromval(v) \ #define nodefromval(v) cast(Node *, (v))
(gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val))))
LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); 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 #else
#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
#define hashstr(t,str) hashpow2(t, (str)->hash) #define hashstr(t,str) hashpow2(t, (str)->hash)
#define hashboolean(t,p) hashpow2(t, p) #define hashboolean(t,p) hashpow2(t, p)
#define hashint(t,i) hashpow2(t, i) #define hashint(t,i) hashpow2(t, i)
/* /*
** for some types, it is better to avoid modulus by power of 2, as ** for some types, it is better to avoid modulus by power of 2, as
** they tend to have many 2 factors. ** they tend to have many 2 factors.
*/ */
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) #define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
#define hashpointer(t,p) hashmod(t, point2uint(p)) #define hashpointer(t,p) hashmod(t, point2uint(p))
#endif #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); 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_getstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *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); 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_resizearray (lua_State *L, Table *t, unsigned int nasize);
LUAI_FUNC void luaH_free (lua_State *L, Table *t); 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_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 */ /* RAVI array specialization */

@ -8,6 +8,7 @@
#define ltests_h #define ltests_h
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
/* test Lua with no compatibility code */ /* test Lua with no compatibility code */
@ -32,6 +33,7 @@
#include <assert.h> #include <assert.h>
#define lua_assert(c) assert(c) #define lua_assert(c) assert(c)
#if !defined(RAVI_OPTION_STRING1) #if !defined(RAVI_OPTION_STRING1)
#define RAVI_OPTION_STRING1 " assertions" #define RAVI_OPTION_STRING1 " assertions"
#endif #endif
@ -57,6 +59,7 @@ typedef struct Memcontrol {
unsigned long total; unsigned long total;
unsigned long maxmem; unsigned long maxmem;
unsigned long memlimit; unsigned long memlimit;
unsigned long countlimit;
unsigned long objcount[LUA_NUMTAGS]; unsigned long objcount[LUA_NUMTAGS];
} Memcontrol; } Memcontrol;

@ -318,8 +318,10 @@ LUA_API int (lua_isyieldable) (lua_State *L);
#define LUA_GCSETPAUSE 6 #define LUA_GCSETPAUSE 6
#define LUA_GCSETSTEPMUL 7 #define LUA_GCSETSTEPMUL 7
#define LUA_GCISRUNNING 9 #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) \ #define tonumber(o,n) \
(RAVI_LIKELY(ttisfloat(o)) ? (*(n) = fltvalue(o), 1) : luaV_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) \ #define tointeger(o,i) \
(RAVI_LIKELY(ttisinteger(o)) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I)) (RAVI_LIKELY(ttisinteger(o)) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))

@ -168,6 +168,8 @@ struct LuaLLVMTypes {
llvm::PointerType *pGCObjectT; llvm::PointerType *pGCObjectT;
llvm::StructType *ValueT; llvm::StructType *ValueT;
llvm::StructType *TValueGCT;
llvm::PointerType *pTValueGCT;
llvm::StructType *TValueT; llvm::StructType *TValueT;
llvm::PointerType *pTValueT; llvm::PointerType *pTValueT;
llvm::StructType *TStringT; llvm::StructType *TStringT;
@ -206,9 +208,6 @@ struct LuaLLVMTypes {
llvm::StructType *CClosureT; llvm::StructType *CClosureT;
llvm::PointerType *pCClosureT; llvm::PointerType *pCClosureT;
llvm::StructType *TKeyT;
llvm::PointerType *pTKeyT;
llvm::StructType *NodeT; llvm::StructType *NodeT;
llvm::PointerType *pNodeT; llvm::PointerType *pNodeT;
@ -230,7 +229,7 @@ struct LuaLLVMTypes {
llvm::FunctionType *jitFunctionT; llvm::FunctionType *jitFunctionT;
llvm::FunctionType *luaC_upvalbarrierT; llvm::FunctionType *luaC_barrierT;
llvm::FunctionType *luaD_poscallT; llvm::FunctionType *luaD_poscallT;
llvm::FunctionType *luaD_precallT; llvm::FunctionType *luaD_precallT;
llvm::FunctionType *luaD_callT; llvm::FunctionType *luaD_callT;
@ -396,8 +395,8 @@ class RaviJITState {
// all the IR in modules get released after compilation // all the IR in modules get released after compilation
// MCJIT is also likely to be removed at some time in // MCJIT is also likely to be removed at some time in
// future so we needed to migrate anyway // future so we needed to migrate anyway
// We don't use ORC apis in earlier versions because // We don't use ORC apis in earlier versions because
// the apis have changed over the releases so it // the apis have changed over the releases so it
// is simpler to use them in 5.0 and above. // is simpler to use them in 5.0 and above.
// The ORC usage here is heavily based upon the kaleidoscope // The ORC usage here is heavily based upon the kaleidoscope
// sample, with some adjustments. // sample, with some adjustments.
@ -436,7 +435,7 @@ class RaviJITState {
// Size level (LLVM PassManagerBuilder) // Size level (LLVM PassManagerBuilder)
unsigned int size_level_ : 2; unsigned int size_level_ : 2;
// Verbosity // Verbosity
unsigned int verbosity_ : 3; unsigned int verbosity_ : 3;
@ -447,7 +446,7 @@ class RaviJITState {
// Enable extra validation such as IR verification // Enable extra validation such as IR verification
// May slow down compilation // May slow down compilation
unsigned int validation_ : 1; unsigned int validation_ : 1;
// Flag to control calls to collect // Flag to control calls to collect
int gcstep_; int gcstep_;
@ -460,7 +459,7 @@ class RaviJITState {
// Count of modules allocated // Count of modules allocated
// Used to debug module deallocation // Used to debug module deallocation
size_t allocated_modules_; size_t allocated_modules_;
// flag to help avoid recursion // flag to help avoid recursion
int compiling_; int compiling_;
@ -509,9 +508,7 @@ class RaviJITState {
int get_validation() const { return validation_; } int get_validation() const { return validation_; }
void set_validation(bool value) { validation_ = value; } void set_validation(bool value) { validation_ = value; }
int get_gcstep() const { return gcstep_; } int get_gcstep() const { return gcstep_; }
void set_gcstep(int value) { void set_gcstep(int value) { gcstep_ = value > 0 ? value : gcstep_; }
gcstep_ = value > 0 ? value : gcstep_;
}
bool is_tracehook_enabled() const { return tracehook_enabled_; } bool is_tracehook_enabled() const { return tracehook_enabled_; }
void set_tracehook_enabled(bool value) { tracehook_enabled_ = value; } void set_tracehook_enabled(bool value) { tracehook_enabled_ = value; }
void incr_allocated_modules() { allocated_modules_++; } void incr_allocated_modules() { allocated_modules_++; }
@ -565,7 +562,7 @@ class RaviJITModule {
llvm::Module *module() const { return module_; } llvm::Module *module() const { return module_; }
llvm::ExecutionEngine *engine() const { return engine_; } llvm::ExecutionEngine *engine() const { return engine_; }
#else #else
// Note that this can return nullptr // Note that this can return nullptr
llvm::Module *module() const { return module_.get(); } llvm::Module *module() const { return module_.get(); }
#endif #endif
RaviJITState *owner() const { return owner_; } RaviJITState *owner() const { return owner_; }
@ -727,7 +724,7 @@ struct RaviFunctionDef {
llvm::Function *luaV_modF; llvm::Function *luaV_modF;
llvm::Function *luaV_divF; llvm::Function *luaV_divF;
llvm::Function *luaV_objlenF; llvm::Function *luaV_objlenF;
llvm::Function *luaC_upvalbarrierF; llvm::Function *luaC_barrierF;
llvm::Function *luaH_getstrF; llvm::Function *luaH_getstrF;
llvm::Function *luaH_getintF; llvm::Function *luaH_getintF;
llvm::Function *luaH_setintF; llvm::Function *luaH_setintF;
@ -1073,10 +1070,6 @@ class RaviCodeGenerator {
llvm::Instruction *emit_load_upval_v(RaviFunctionDef *def, llvm::Instruction *emit_load_upval_v(RaviFunctionDef *def,
llvm::Instruction *pupval); 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
// !(isnil(reg) || isboolean(reg) && reg.value == 0) // !(isnil(reg) || isboolean(reg) && reg.value == 0)
llvm::Value *emit_boolean_testfalse(RaviFunctionDef *def, llvm::Value *reg, llvm::Value *emit_boolean_testfalse(RaviFunctionDef *def, llvm::Value *reg,
@ -1274,6 +1267,9 @@ class RaviCodeGenerator {
void emit_SETUPVAL(RaviFunctionDef *def, int A, int B, int pc); void emit_SETUPVAL(RaviFunctionDef *def, int A, int B, int pc);
void emit_GC_barrier(RaviFunctionDef *def, llvm::Value *upval,
llvm::Value *v);
void emit_SETUPVAL_Specific(RaviFunctionDef *def, int A, int B, int pc, void emit_SETUPVAL_Specific(RaviFunctionDef *def, int A, int B, int pc,
OpCode op, llvm::Function *f); 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"); api_check(from, to->ci->top - to->top >= n, "stack overflow");
from->top -= n; from->top -= n;
for (i = 0; i < n; i++) { 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' */ to->top++; /* stack already checked by previous 'api_check' */
} }
lua_unlock(to); lua_unlock(to);
@ -194,6 +194,8 @@ LUA_API void lua_settop (lua_State *L, int idx) {
/* /*
** Reverse the stack segment from 'from' to 'to' ** Reverse the stack segment from 'from' to 'to'
** (auxiliary to 'lua_rotate') ** (auxiliary to 'lua_rotate')
** Note that we move(copy) only the value inside the stack.
** (We do not move additional fields that may exist.)
*/ */
static void reverse (lua_State *L, StkId from, StkId to) { static void reverse (lua_State *L, StkId from, StkId to) {
for (; from < to; from++, to--) { for (; from < to; from++, to--) {
@ -571,6 +573,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
lua_lock(L); lua_lock(L);
if (n == 0) { if (n == 0) {
setfvalue(L->top, fn); setfvalue(L->top, fn);
api_incr_top(L);
} }
else { else {
CClosure *cl; CClosure *cl;
@ -586,9 +589,9 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
/* does not need barrier because closure is white */ /* does not need barrier because closure is white */
} }
setclCvalue(L, L->top, cl); setclCvalue(L, L->top, cl);
api_incr_top(L);
luaC_checkGC(L);
} }
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
} }
@ -1325,7 +1328,7 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
setobj(L, f->upvals[0]->v, gt); setobj(L, f->upvals[0]->v, gt);
luaC_upvalbarrier(L, f->upvals[0]); luaC_barrier(L, f->upvals[0], gt);
} }
} }
lua_unlock(L); lua_unlock(L);
@ -1356,12 +1359,12 @@ LUA_API int lua_status (lua_State *L) {
/* /*
** Garbage-collection function ** Garbage-collection function
*/ */
LUA_API int lua_gc (lua_State *L, int what, ...) {
LUA_API int lua_gc (lua_State *L, int what, int data) { va_list argp;
int res = 0; int res = 0;
global_State *g; global_State *g = G(L);
lua_lock(L); lua_lock(L);
g = G(L); va_start(argp, what);
switch (what) { switch (what) {
case LUA_GCSTOP: { case LUA_GCSTOP: {
g->gcrunning = 0; g->gcrunning = 0;
@ -1386,11 +1389,12 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
break; break;
} }
case LUA_GCSTEP: { case LUA_GCSTEP: {
int data = va_arg(argp, int);
l_mem debt = 1; /* =1 to signal that it did an actual step */ l_mem debt = 1; /* =1 to signal that it did an actual step */
lu_byte oldrunning = g->gcrunning; lu_byte oldrunning = g->gcrunning;
g->gcrunning = 1; /* allow GC to run */ g->gcrunning = 1; /* allow GC to run */
if (data == 0) { if (data == 0) {
luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */ luaE_setdebt(g, 0); /* do a basic step */
luaC_step(L); luaC_step(L);
} }
else { /* add 'data' to total debt */ else { /* add 'data' to total debt */
@ -1404,22 +1408,47 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
break; break;
} }
case LUA_GCSETPAUSE: { case LUA_GCSETPAUSE: {
res = g->gcpause; int data = va_arg(argp, int);
g->gcpause = data; res = getgcparam(g->gcpause);
setgcparam(g->gcpause, data);
break; break;
} }
case LUA_GCSETSTEPMUL: { case LUA_GCSETSTEPMUL: {
res = g->gcstepmul; int data = va_arg(argp, int);
if (data < 40) data = 40; /* avoid ridiculous low values (and 0) */ res = getgcparam(g->gcstepmul);
g->gcstepmul = data; setgcparam(g->gcstepmul, data);
break; break;
} }
case LUA_GCISRUNNING: { case LUA_GCISRUNNING: {
res = g->gcrunning; res = g->gcrunning;
break; break;
} }
case LUA_GCGEN: {
int minormul = va_arg(argp, int);
int majormul = va_arg(argp, int);
if (minormul != 0)
g->genminormul = minormul;
if (majormul != 0)
setgcparam(g->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);
if (pause != 0)
setgcparam(g->gcpause, pause);
if (stepmul != 0)
setgcparam(g->gcstepmul, stepmul);
if (stepsize != 0)
g->gcstepsize = stepsize;
luaC_changemode(L, KGC_INC);
break;
}
default: res = -1; /* invalid option */ default: res = -1; /* invalid option */
} }
va_end(argp);
lua_unlock(L); lua_unlock(L);
return res; return res;
} }
@ -1515,14 +1544,14 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
static const char *aux_upvalue (StkId fi, int n, TValue **val, static const char *aux_upvalue (StkId fi, int n, TValue **val,
CClosure **owner, UpVal **uv, ravitype_t *type) { GCObject **owner, ravitype_t *type) {
*type = RAVI_TANY; *type = RAVI_TANY;
switch (ttype(fi)) { switch (ttype(fi)) {
case LUA_TCCL: { /* C closure */ case LUA_TCCL: { /* C closure */
CClosure *f = clCvalue(fi); CClosure *f = clCvalue(fi);
if (!(1 <= n && n <= f->nupvalues)) return NULL; if (!(1 <= n && n <= f->nupvalues)) return NULL;
*val = &f->upvalue[n-1]; *val = &f->upvalue[n-1];
if (owner) *owner = f; if (owner) *owner = obj2gco(f);
return ""; return "";
} }
case LUA_TLCL: { /* Lua closure */ case LUA_TLCL: { /* Lua closure */
@ -1531,7 +1560,7 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val,
Proto *p = f->p; Proto *p = f->p;
if (!(1 <= n && n <= p->sizeupvalues)) return NULL; if (!(1 <= n && n <= p->sizeupvalues)) return NULL;
*val = f->upvals[n-1]->v; *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; name = p->upvalues[n-1].name;
*type = p->upvalues[n - 1].ravi_type; *type = p->upvalues[n - 1].ravi_type;
return (name == NULL) ? "(*no name)" : getstr(name); return (name == NULL) ? "(*no name)" : getstr(name);
@ -1546,7 +1575,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
ravitype_t type; ravitype_t type;
TValue *val = NULL; /* to avoid warnings */ TValue *val = NULL; /* to avoid warnings */
lua_lock(L); lua_lock(L);
name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL, &type); name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, &type);
if (name) { if (name) {
setobj2s(L, L->top, val); setobj2s(L, L->top, val);
api_incr_top(L); api_incr_top(L);
@ -1559,14 +1588,13 @@ 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) { LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
const char *name; const char *name;
TValue *val = NULL; /* to avoid warnings */ TValue *val = NULL; /* to avoid warnings */
CClosure *owner = NULL; GCObject *owner = NULL; /* to avoid warnings */
UpVal *uv = NULL;
StkId fi; StkId fi;
ravitype_t type; /* RAVI upvalue type will be obtained if possible */ ravitype_t type; /* RAVI upvalue type will be obtained if possible */
lua_lock(L); lua_lock(L);
fi = index2addr(L, funcindex); fi = index2addr(L, funcindex);
api_checknelems(L, 1); api_checknelems(L, 1);
name = aux_upvalue(fi, n, &val, &owner, &uv, &type); name = aux_upvalue(fi, n, &val, &owner, &type);
if (name) { if (name) {
/* RAVI extension /* RAVI extension
** We need to ensure that this function does ** We need to ensure that this function does
@ -1591,8 +1619,7 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
if (name) { if (name) {
L->top--; L->top--;
setobj(L, val, L->top); setobj(L, val, L->top);
if (owner) { luaC_barrier(L, owner, L->top); } luaC_barrier(L, owner, val);
else if (uv) { luaC_upvalbarrier(L, uv); }
} }
lua_unlock(L); lua_unlock(L);
return name; return name;
@ -1637,11 +1664,8 @@ LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
UpVal **up1 = getupvalref(L, fidx1, n1, &f1, &t1); UpVal **up1 = getupvalref(L, fidx1, n1, &f1, &t1);
UpVal **up2 = getupvalref(L, fidx2, n2, NULL, &t2); UpVal **up2 = getupvalref(L, fidx2, n2, NULL, &t2);
if (t1 == t2) { if (t1 == t2) {
luaC_upvdeccount(L, *up1);
*up1 = *up2; *up1 = *up2;
(*up1)->refcount++; luaC_objbarrier(L, f1, *up1);
if (upisopen(*up1)) (*up1)->u.open.touched = 1;
luaC_upvalbarrier(L, *up1);
} }
} }

@ -173,24 +173,51 @@ static int luaB_rawset (lua_State *L) {
static int luaB_collectgarbage (lua_State *L) { static int luaB_collectgarbage (lua_State *L) {
static const char *const opts[] = {"stop", "restart", "collect", static const char *const opts[] = {"stop", "restart", "collect",
"count", "step", "setpause", "setstepmul", "count", "step", "setpause", "setstepmul",
"isrunning", NULL}; "isrunning", "generational", "incremental", NULL};
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, 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 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) { switch (o) {
case LUA_GCCOUNT: { case LUA_GCCOUNT: {
int b = lua_gc(L, LUA_GCCOUNTB, 0); int k = lua_gc(L, o);
lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024)); int b = lua_gc(L, LUA_GCCOUNTB);
lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024));
return 1; 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); lua_pushboolean(L, res);
return 1; 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: { default: {
int res = lua_gc(L, o);
lua_pushinteger(L, res); lua_pushinteger(L, res);
return 1; return 1;
} }

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

File diff suppressed because it is too large Load Diff

@ -206,11 +206,16 @@ static int aux_close (lua_State *L) {
} }
static int f_close (lua_State *L) {
tofile(L); /* make sure argument is an open stream */
return aux_close(L);
}
static int io_close (lua_State *L) { static int io_close (lua_State *L) {
if (lua_isnone(L, 1)) /* no argument? */ if (lua_isnone(L, 1)) /* no argument? */
lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */
tofile(L); /* make sure argument is an open stream */ return f_close(L);
return aux_close(L);
} }
@ -713,7 +718,7 @@ static const luaL_Reg iolib[] = {
** methods for file handles ** methods for file handles
*/ */
static const luaL_Reg flib[] = { static const luaL_Reg flib[] = {
{"close", io_close}, {"close", f_close},
{"flush", f_flush}, {"flush", f_flush},
{"lines", f_lines}, {"lines", f_lines},
{"read", f_read}, {"read", f_read},

@ -139,7 +139,7 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
luaC_checkGC(L); luaC_checkGC(L);
} }
else { /* string already present */ 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 */ L->top--; /* remove string from stack */
return ts; return ts;

@ -35,13 +35,6 @@
#include "ravijit.h" #include "ravijit.h"
#include "ravi_profile.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
/* /*
@ -221,6 +214,7 @@ static void f_luaopen (lua_State *L, void *ud) {
luaT_init(L); luaT_init(L);
luaX_init(L); luaX_init(L);
g->gcrunning = 1; /* allow gc */ g->gcrunning = 1; /* allow gc */
g->gcemergency = 0;
g->version = lua_version(NULL); g->version = lua_version(NULL);
luai_userstateopen(L); luai_userstateopen(L);
} }
@ -344,7 +338,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
int i; int i;
lua_State *L; lua_State *L;
global_State *g; global_State *g;
LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG))); LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG)));
if (l == NULL) return NULL; if (l == NULL) return NULL;
L = &l->l.l; L = &l->l.l;
@ -353,34 +346,38 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->ravi_writestring = raviE_default_writestring; g->ravi_writestring = raviE_default_writestring;
g->ravi_writestringerror = raviE_default_writestringerror; g->ravi_writestringerror = raviE_default_writestringerror;
g->ravi_debugger_data = NULL; g->ravi_debugger_data = NULL;
L->next = NULL;
L->tt = LUA_TTHREAD; L->tt = LUA_TTHREAD;
g->currentwhite = bitmask(WHITE0BIT); g->currentwhite = bitmask(WHITE0BIT);
L->marked = luaC_white(g); L->marked = luaC_white(g);
preinit_thread(L, g); preinit_thread(L, g);
g->allgc = obj2gco(L); /* by now, only object is the main thread */
L->next = NULL;
g->frealloc = f; g->frealloc = f;
g->ud = ud; g->ud = ud;
g->mainthread = L; g->mainthread = L;
g->seed = makeseed(L); g->seed = makeseed(L);
g->gcrunning = 0; /* no GC while building state */ g->gcrunning = 0; /* no GC while building state */
g->GCestimate = 0;
g->strt.size = g->strt.nuse = 0; g->strt.size = g->strt.nuse = 0;
g->strt.hash = NULL; g->strt.hash = NULL;
setnilvalue(&g->l_registry); setnilvalue(&g->l_registry);
g->panic = NULL; g->panic = NULL;
g->version = NULL; g->version = NULL;
g->gcstate = GCSpause; g->gcstate = GCSpause;
g->gckind = KGC_NORMAL; g->gckind = KGC_INC;
g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL; 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->sweepgc = NULL;
g->gray = g->grayagain = 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->twups = NULL;
g->totalbytes = sizeof(LG); g->totalbytes = sizeof(LG);
g->GCdebt = 0; g->GCdebt = 0;
g->gcfinnum = 0; setgcparam(g->gcpause, LUAI_GCPAUSE);
g->gcpause = LUAI_GCPAUSE; setgcparam(g->gcstepmul, LUAI_GCMUL);
g->gcstepmul = LUAI_GCMUL; g->gcstepsize = LUAI_GCSTEPSIZE;
setgcparam(g->genmajormul, LUAI_GENMAJORMUL);
g->genminormul = LUAI_GENMINORMUL;
g->ravi_state = NULL; g->ravi_state = NULL;
for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL;
raviV_initjit(L); raviV_initjit(L);

@ -59,8 +59,8 @@
#define dummynode (&dummynode_) #define dummynode (&dummynode_)
static const Node dummynode_ = { static const Node dummynode_ = {
{NILCONSTANT}, /* value */ {{NULL}, LUA_TNIL, /* value's value and type */
{{NILCONSTANT, 0}} /* key */ 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 ** returns the 'main' position of an element in a table (that is,
** of its hash value) ** 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) { static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
switch (ttype(key)) { switch (ttyperaw(ktt)) {
case LUA_TNUMINT: case LUA_TNUMINT:
return hashint(t, ivalue(key)); return hashint(t, ivalueraw(*kvl));
case LUA_TNUMFLT: case LUA_TNUMFLT:
return hashmod(t, l_hashfloat(fltvalue(key))); return hashmod(t, l_hashfloat(fltvalueraw(*kvl)));
case LUA_TSHRSTR: case LUA_TSHRSTR:
return hashstr(t, tsvalue(key)); return hashstr(t, tsvalueraw(*kvl));
case LUA_TLNGSTR: case LUA_TLNGSTR:
return hashpow2(t, luaS_hashlongstr(tsvalue(key))); return hashpow2(t, luaS_hashlongstr(tsvalueraw(*kvl)));
case LUA_TBOOLEAN: case LUA_TBOOLEAN:
return hashboolean(t, bvalue(key)); return hashboolean(t, bvalueraw(*kvl));
case LUA_TLIGHTUSERDATA: case LUA_TLIGHTUSERDATA:
return hashpointer(t, pvalue(key)); return hashpointer(t, pvalueraw(*kvl));
case LUA_TLCF: case LUA_TLCF:
return hashpointer(t, fvalue(key)); return hashpointer(t, fvalueraw(*kvl));
default: default:
lua_assert(!ttisdeadkey(key)); return hashpointer(t, gcvalueraw(*kvl));
return hashpointer(t, gcvalue(key));
} }
} }
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 ** Check whether key 'k1' is equal to the key in node 'n2'.
** the array part of the table, 0 otherwise. ** 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) { static int equalkey (const TValue *k1, const Node *n2) {
if (ttisinteger(key)) { if (rttype(k1) != keytt(n2)) /* not the same variants? */
lua_Integer k = ivalue(key); return 0; /* cannot be same key */
if (0 < k && (lua_Unsigned)k <= MAXASIZE) switch (ttype(k1)) {
return cast(unsigned int, k); /* 'key' is an appropriate array index */ 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 ** elements in the array part, then elements in the hash part. The
** beginning of a traversal is signaled by 0. ** 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; unsigned int i;
if (ttisnil(key)) return 0; /* first iteration */ 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? */ if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */
return i; /* yes; that's the index */ return i; /* yes; that's the index */
else { else {
int nx; const TValue *n = getgeneric(t, key);
Node *n = mainposition(t, key); if (n == luaO_nilobject)
for (;;) { /* check whether 'key' is somewhere in the chain */ luaG_runerror(L, "invalid key to 'next'"); /* key not found */
/* key may be dead already, but it is ok to use it in 'next' */ i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */
if (luaV_rawequalobj(gkey(n), key) || /* hash elements are numbered after array ones */
(ttisdeadkey(gkey(n)) && iscollectable(key) && return (i + 1) + t->sizearray;
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;
}
} }
} }
@ -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 */ for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */
if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */
setobj2s(L, key, gkey(gnode(t, i))); Node *n = gnode(t, i);
setobj2s(L, key + 1, gval(gnode(t, i))); getnodekey(L, key, n);
setobj2s(L, key + 1, gval(n));
return 1; 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 ** "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 ** 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 ** 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) { static unsigned int computesizes (unsigned int nums[], unsigned int *pna) {
int i; 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 na = 0; /* number of elements to go to array part */
unsigned int optimal = 0; /* optimal size for array part */ unsigned int optimal = 0; /* optimal size for array part */
/* loop while keys can fill more than half of total size */ /* loop while keys can fill more than half of total size */
for (i = 0, twotoi = 1; *pna > twotoi / 2; i++, twotoi *= 2) { for (i = 0, twotoi = 1;
if (nums[i] > 0) { twotoi > 0 && *pna > twotoi / 2;
a += nums[i]; i++, twotoi *= 2) {
if (a > twotoi/2) { /* more than half elements present? */ a += nums[i];
optimal = twotoi; /* optimal size (till now) */ if (a > twotoi/2) { /* more than half elements present? */
na = a; /* all elements up to 'optimal' will go to array part */ 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); 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); unsigned int k = arrayindex(key);
if (k != 0) { /* is 'key' an appropriate array index? */ if (k != 0) { /* is 'key' an appropriate array index? */
nums[luaO_ceillog2(k)]++; /* count as such */ 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--) { while (i--) {
Node *n = &t->node[i]; Node *n = &t->node[i];
if (!ttisnil(gval(n))) { if (!ttisnil(gval(n))) {
ause += countint(gkey(n), nums); if (keyisinteger(n))
ause += countint(keyival(n), nums);
totaluse++; totaluse++;
} }
} }
@ -342,7 +390,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
for (i = 0; i < (int)size; i++) { for (i = 0; i < (int)size; i++) {
Node *n = gnode(t, i); Node *n = gnode(t, i);
gnext(n) = 0; gnext(n) = 0;
setnilvalue(wgkey(n)); setnilkey(n);
setnilvalue(gval(n)); setnilvalue(gval(n));
} }
t->lsizenode = cast_byte(lsize); t->lsizenode = cast_byte(lsize);
@ -381,7 +429,8 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
if (!ttisnil(gval(old))) { if (!ttisnil(gval(old))) {
/* doesn't need barrier/invalidate cache, as entry was /* doesn't need barrier/invalidate cache, as entry was
already present in the table */ 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? */ 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 = na; /* all those keys are integer keys */
totaluse += numusehash(t, nums, &na); /* count keys in hash part */ totaluse += numusehash(t, nums, &na); /* count keys in hash part */
/* count extra key */ /* count extra key */
na += countint(ek, nums); if (ttisinteger(ek))
na += countint(ivalue(ek), nums);
totaluse++; totaluse++;
/* compute new size for array part */ /* compute new size for array part */
asize = computesizes(nums, &na); asize = computesizes(nums, &na);
@ -487,7 +537,7 @@ static Node *getfreepos (Table *t) {
if (!isdummy(t)) { if (!isdummy(t)) {
while (t->lastfree > t->node) { while (t->lastfree > t->node) {
t->lastfree--; t->lastfree--;
if (ttisnil(gkey(t->lastfree))) if (keyisnil(t->lastfree))
return 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))) else if (luai_numisnan(fltvalue(key)))
luaG_runerror(L, "table index is NaN"); 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? */ if (!ttisnil(gval(mp)) || isdummy(t)) { /* main position is taken? */
Node *othern; Node *othern;
Node *f = getfreepos(t); /* get a free place */ 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 */ return luaH_set(L, t, key); /* insert key into grown table */
} }
lua_assert(!isdummy(t)); 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? */ if (othern != mp) { /* is colliding node out of its main position? */
/* yes; move colliding node into free position */ /* yes; move colliding node into free position */
while (othern + gnext(othern) != mp) /* find previous */ while (othern + gnext(othern) != mp) /* find previous */
@ -548,7 +598,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
mp = f; mp = f;
} }
} }
setnodekey(L, &mp->i_key, key); setnodekey(L, mp, key);
luaC_barrierback(L, t, key); luaC_barrierback(L, t, key);
lua_assert(ttisnil(gval(mp))); lua_assert(ttisnil(gval(mp)));
return 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) { const TValue *luaH_getint (Table *t, lua_Integer key) {
/* (1 <= key && key <= t->sizearray) */ /* (1 <= key && key <= t->sizearray) */
if (l_castS2U(key) - 1 < t->sizearray) if (l_castS2U(key) - 1u < t->sizearray)
return &t->array[key - 1]; return &t->array[key - 1];
else { else {
Node *n = hashint(t, key); Node *n = hashint(t, key);
for (;;) { /* check whether 'key' is somewhere in the chain */ 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 */ return gval(n); /* that's it */
else { else {
int nx = gnext(n); 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 ** search function for short strings
*/ */
@ -585,27 +635,7 @@ const TValue *luaH_getshortstr (Table *t, TString *key) {
Node *n = hashstr(t, key); Node *n = hashstr(t, key);
lua_assert(key->tt == LUA_TSHRSTR); lua_assert(key->tt == LUA_TSHRSTR);
for (;;) { /* check whether 'key' is somewhere in the chain */ for (;;) { /* check whether 'key' is somewhere in the chain */
const TValue *k = gkey(n); if (keyisshrstr(n) && eqshrstr(keystrval(n), key))
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))
return gval(n); /* that's it */ return gval(n); /* that's it */
else { else {
int nx = gnext(n); int nx = gnext(n);
@ -631,8 +661,7 @@ const TValue *luaH_getstr (Table *t, TString *key) {
/* /*
** main search function ** main search function
*/ */
const TValue *luaH_get(Table *t, const TValue *key) { const TValue *luaH_get (Table *t, const TValue *key) {
#if 1
switch (ttype(key)) { switch (ttype(key)) {
case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key)); case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key));
case LUA_TNUMINT: return luaH_getint(t, ivalue(key)); case LUA_TNUMINT: return luaH_getint(t, ivalue(key));
@ -646,27 +675,9 @@ const TValue *luaH_get(Table *t, const TValue *key) {
default: default:
return getgeneric(t, key); 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 ** beware: when using this function you probably need to check a GC
** barrier and invalidate the TM cache. ** 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 */ ** Try to find a boundary in the hash part of table 't'. From the
j++; ** caller, we know that 'j' is zero or present and that 'j + 1' is
/* find 'i' and 'j' such that i is present and j is not */ ** present. We want to find a larger key that is absent from the
while (!ttisnil(luaH_getint(t, j))) { ** table, so that we can do a binary search between the two keys to
i = j; ** find a boundary. We keep doubling 'j' until we get an absent index.
if (j > cast(unsigned int, MAX_INT)/2) { /* overflow? */ ** If the doubling would overflow, we try LUA_MAXINTEGER. If it is
/* table was built with bad purposes: resort to linear search */ ** absent, we are ready for the binary search. ('j', being max integer,
i = 1; ** is larger or equal to 'i', but it cannot be equal because it is
while (!ttisnil(luaH_getint(t, i))) i++; ** absent while 'i' is present; so 'j > i'.) Otherwise, 'j' is a
return i - 1; ** 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; } while (!ttisnil(luaH_getint(t, j))); /* repeat until t[j] == nil */
} /* i < j && t[i] !? nil && t[j] == nil */
/* now do a binary search between them */ while (j - i > 1u) { /* do a binary search between them */
while (j - i > 1) { lua_Unsigned m = (i + j) / 2;
unsigned int m = (i+j)/2;
if (ttisnil(luaH_getint(t, m))) j = m; if (ttisnil(luaH_getint(t, m))) j = m;
else i = 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 ** 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). ** 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) { lua_Unsigned luaH_getn (Table *t) {
unsigned int j; unsigned int j = t->sizearray;
/* 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;
if (j > 0 && ttisnil(&t->array[j - 1])) { if (j > 0 && ttisnil(&t->array[j - 1])) {
/* there is a boundary in the array part: (binary) search for it */
unsigned int i = 0; unsigned int i = 0;
while (j - i > 1) { while (j - i > 1u) { /* binary search */
unsigned int m = (i+j)/2; unsigned int m = (i + j) / 2;
if (ttisnil(&t->array[m - 1])) j = m; if (ttisnil(&t->array[m - 1])) j = m;
else i = m; else i = m;
} }
return i; return i;
} }
/* else must find a boundary in hash part */ else { /* 'j' is zero or present in table */
else if (isdummy(t)) /* hash part is empty? */ if (isdummy(t) || ttisnil(luaH_getint(t, l_castU2S(j + 1))))
return j; /* that is easy... */ return j; /* 'j + 1' is absent... */
else return unbound_search(t, j); else /* 'j + 1' is also present */
return hash_search(t, j);
}
} }
/* RAVI array specialization */ /* RAVI array specialization */
@ -935,7 +960,7 @@ const TValue *raviH_slice_parent(lua_State *L, TValue *slice) {
#if defined(LUA_DEBUG) #if defined(LUA_DEBUG)
Node *luaH_mainposition (const Table *t, const TValue *key) { 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); } int luaH_isdummy (const Table *t) { return isdummy(t); }

@ -105,7 +105,7 @@ typedef union Header {
static Memcontrol l_memcontrol = static Memcontrol l_memcontrol =
{0L, 0L, 0L, 0L, {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}}; {0L, 0L, 0L, 0L, (~0L), {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}};
LUA_API Memcontrol* luaB_getmemcontrol(void) { LUA_API Memcontrol* luaB_getmemcontrol(void) {
return &l_memcontrol; return &l_memcontrol;
@ -147,7 +147,12 @@ LUA_API void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) {
freeblock(mc, block); freeblock(mc, block);
return NULL; return NULL;
} }
else if (size > oldsize && mc->total+size-oldsize > mc->memlimit) if (mc->countlimit != ~0UL && size > 0) { /* count limit in use? */
if (mc->countlimit == 0)
return NULL; /* fake a memory allocation error */
mc->countlimit--;
}
if (size > oldsize && mc->total+size-oldsize > mc->memlimit)
return NULL; /* fake a memory allocation error */ return NULL; /* fake a memory allocation error */
else { else {
Header *newblock; Header *newblock;
@ -189,18 +194,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) { static int testobjref1 (global_State *g, GCObject *f, GCObject *t) {
if (isdead(g,t)) return 0; if (isdead(g,t)) return 0;
if (!issweepphase(g)) if (issweepphase(g))
return !(isblack(f) && iswhite(t)); return 1; /* no invariants */
else return 1; 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) { 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, 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 +261,10 @@ static void checktable (global_State *g, Table *h) {
checkvalref(g, hgc, &h->array[i]); checkvalref(g, hgc, &h->array[i]);
for (n = gnode(h, 0); n < limit; n++) { for (n = gnode(h, 0); n < limit; n++) {
if (!ttisnil(gval(n))) { if (!ttisnil(gval(n))) {
lua_assert(!ttisnil(gkey(n))); TValue k;
checkvalref(g, hgc, gkey(n)); getnodekey(g->mainthread, &k, n);
lua_assert(!keyisnil(n));
checkvalref(g, hgc, &k);
checkvalref(g, hgc, gval(n)); checkvalref(g, hgc, gval(n));
} }
} }
@ -281,9 +309,9 @@ static void checkLclosure (global_State *g, LClosure *cl) {
for (i=0; i<cl->nupvalues; i++) { for (i=0; i<cl->nupvalues; i++) {
UpVal *uv = cl->upvals[i]; UpVal *uv = cl->upvals[i];
if (uv) { if (uv) {
if (!upisopen(uv)) /* only closed upvalues matter to invariant */ checkobjref(g, clgc, uv);
checkvalref(g, clgc, uv->v); if (!upisopen(uv))
lua_assert(uv->refcount > 0); checkvalref(g, obj2gco(uv), uv->v);
} }
} }
} }
@ -322,57 +350,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)) if (isdead(g, o))
lua_assert(maybedead); lua_assert(maybedead);
else { else {
lua_assert(g->gcstate != GCSpause || iswhite(o)); lua_assert(g->gcstate != GCSpause || iswhite(o));
switch (o->tt) { if (g->gckind == KGC_GEN) { /* generational mode? */
case LUA_TUSERDATA: { lua_assert(getage(o) >= listage);
TValue uservalue; lua_assert(!iswhite(o) || !isold(o));
Table *mt = gco2u(o)->metatable; if (isold(o)) {
checkobjref(g, o, mt); lua_assert(isblack(o) ||
getuservalue(g->mainthread, gco2u(o), &uservalue); getage(o) == G_TOUCHED1 ||
checkvalref(g, o, &uservalue); getage(o) == G_OLD0 ||
break; o->tt == LUA_TTHREAD ||
} (o->tt == LUA_TPROTO &&
case LUA_TTABLE: { (gco2p(o)->cache != NULL || gco2p(o)->cachemiss >= MAXMISS)) ||
checktable(g, gco2t(o)); (o->tt == LUA_TUPVAL && upisopen(gco2upv(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);
} }
checkrefs(g, o);
} }
} }
#define TESTGRAYBIT 7
static void checkgraylist (global_State *g, GCObject *o) { static void checkgraylist (global_State *g, GCObject *o) {
((void)g); /* better to keep it available if we need to print an object */ ((void)g); /* better to keep it available if we need to print an object */
while (o) { while (o) {
lua_assert(isgray(o)); lua_assert(isgray(o) || getage(o) == G_TOUCHED2);
lua_assert(!testbit(o->marked, TESTGRAYBIT)); lua_assert(!testbit(o->marked, TESTGRAYBIT));
l_setbit(o->marked, TESTGRAYBIT); l_setbit(o->marked, TESTGRAYBIT);
switch (o->tt) { switch (o->tt) {
@ -381,7 +441,7 @@ static void checkgraylist (global_State *g, GCObject *o) {
case LUA_TCCL: o = gco2ccl(o)->gclist; break; case LUA_TCCL: o = gco2ccl(o)->gclist; break;
case LUA_TTHREAD: o = gco2th(o)->gclist; break; case LUA_TTHREAD: o = gco2th(o)->gclist; break;
case LUA_TPROTO: o = gco2p(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 +457,13 @@ static void markgrays (global_State *g) {
checkgraylist(g, g->grayagain); checkgraylist(g, g->grayagain);
checkgraylist(g, g->weak); checkgraylist(g, g->weak);
checkgraylist(g, g->ephemeron); checkgraylist(g, g->ephemeron);
checkgraylist(g, g->allweak); checkgraylist(g, g->protogray);
} }
static void checkgray (global_State *g, GCObject *o) { static void checkgray (global_State *g, GCObject *o) {
for (; o != NULL; o = o->next) { 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)); lua_assert(!keepinvariant(g) || testbit(o->marked, TESTGRAYBIT));
resetbit(o->marked, TESTGRAYBIT); resetbit(o->marked, TESTGRAYBIT);
} }
@ -412,6 +472,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) { int lua_checkmemory (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
GCObject *o; GCObject *o;
@ -421,32 +503,27 @@ int lua_checkmemory (lua_State *L) {
lua_assert(!iswhite(gcvalue(&g->l_registry))); lua_assert(!iswhite(gcvalue(&g->l_registry)));
} }
lua_assert(!isdead(g, 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)); lua_assert(g->sweepgc == NULL || issweepphase(g));
markgrays(g); markgrays(g);
/* check 'fixedgc' list */ /* check 'fixedgc' list */
for (o = g->fixedgc; o != NULL; o = o->next) { 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 */ /* check 'allgc' list */
checkgray(g, g->allgc); checkgray(g, g->allgc);
maybedead = (GCSatomic < g->gcstate && g->gcstate <= GCSswpallgc); maybedead = (GCSatomic < g->gcstate && g->gcstate <= GCSswpallgc);
for (o = g->allgc; o != NULL; o = o->next) { checklist(g, maybedead, 0, g->allgc, g->survival, g->old, g->reallyold);
checkobject(g, o, maybedead);
lua_assert(!tofinalize(o));
}
/* check 'finobj' list */ /* check 'finobj' list */
checkgray(g, g->finobj); checkgray(g, g->finobj);
for (o = g->finobj; o != NULL; o = o->next) { checklist(g, 0, 1, g->finobj, g->finobjsur, g->finobjold, g->finobjrold);
checkobject(g, o, 0);
lua_assert(tofinalize(o));
lua_assert(o->tt == LUA_TUSERDATA || o->tt == LUA_TTABLE);
}
/* check 'tobefnz' list */ /* check 'tobefnz' list */
checkgray(g, g->tobefnz); checkgray(g, g->tobefnz);
for (o = g->tobefnz; o != NULL; o = o->next) { 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(tofinalize(o));
lua_assert(o->tt == LUA_TUSERDATA || o->tt == LUA_TTABLE); lua_assert(o->tt == LUA_TUSERDATA || o->tt == LUA_TTABLE);
} }
@ -526,6 +603,22 @@ static int listcode (lua_State *L) {
} }
static int printcode (lua_State *L) {
int pc;
Proto *p;
luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
1, "Lua function expected");
p = getproto(obj_at(L, 1));
printf("maxstack: %d\n", p->maxstacksize);
printf("numparams: %d\n", p->numparams);
for (pc=0; pc<p->sizecode; pc++) {
char buff[100];
printf("%d\t%s\n", pc + 1, buildop(p, pc, buff));
}
return 0;
}
static int listk (lua_State *L) { static int listk (lua_State *L) {
Proto *p; Proto *p;
int i; int i;
@ -610,6 +703,15 @@ static int mem_query (lua_State *L) {
} }
static int alloc_count (lua_State *L) {
if (lua_isnone(L, 1))
l_memcontrol.countlimit = ~0L;
else
l_memcontrol.countlimit = luaL_checkinteger(L, 1);
return 0;
}
static int settrick (lua_State *L) { static int settrick (lua_State *L) {
if (ttisnil(obj_at(L, 1))) if (ttisnil(obj_at(L, 1)))
l_Trick = NULL; l_Trick = NULL;
@ -635,11 +737,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 int gc_state (lua_State *L) {
static const char *statenames[] = {"propagate", "atomic", "sweepallgc", static const char *statenames[] = {
"sweepfinobj", "sweeptobefnz", "sweepend", "pause", ""}; "propagate", "atomic", "enteratomic", "sweepallgc", "sweepfinobj",
static const int states[] = {GCSpropagate, GCSatomic, GCSswpallgc, "sweeptobefnz", "sweepend", "callfin", "pause", ""};
GCSswpfinobj, GCSswptobefnz, GCSswpend, GCSpause, -1}; static const int states[] = {
GCSpropagate, GCSenteratomic, GCSatomic, GCSswpallgc, GCSswpfinobj,
GCSswptobefnz, GCSswpend, GCScallfin, GCSpause, -1};
int option = states[luaL_checkoption(L, 1, "", statenames)]; int option = states[luaL_checkoption(L, 1, "", statenames)];
if (option == -1) { if (option == -1) {
lua_pushstring(L, statenames[G(L)->gcstate]); lua_pushstring(L, statenames[G(L)->gcstate]);
@ -647,6 +782,8 @@ static int gc_state (lua_State *L) {
} }
else { else {
global_State *g = G(L); global_State *g = G(L);
if (G(L)->gckind == KGC_GEN)
luaL_error(L, "cannot change states in generational mode");
lua_lock(L); lua_lock(L);
if (option < g->gcstate) { /* must cross 'pause'? */ if (option < g->gcstate) { /* must cross 'pause'? */
luaC_runtilstate(L, bitmask(GCSpause)); /* run until pause */ luaC_runtilstate(L, bitmask(GCSpause)); /* run until pause */
@ -679,8 +816,10 @@ static int stacklevel (lua_State *L) {
unsigned long a = 0; unsigned long a = 0;
lua_pushinteger(L, (L->top - L->stack)); lua_pushinteger(L, (L->top - L->stack));
lua_pushinteger(L, (L->stack_last - L->stack)); lua_pushinteger(L, (L->stack_last - L->stack));
lua_pushinteger(L, (intptr_t)&a); lua_pushinteger(L, L->nCcalls);
return 3; lua_pushinteger(L, L->nci);
lua_pushinteger(L, (unsigned long)&a);
return 5;
} }
@ -700,10 +839,12 @@ static int table_query (lua_State *L) {
lua_pushnil(L); lua_pushnil(L);
} }
else if ((i -= t->sizearray) < sizenode(t)) { else if ((i -= t->sizearray) < sizenode(t)) {
TValue k;
getnodekey(L, &k, gnode(t, i));
if (!ttisnil(gval(gnode(t, i))) || if (!ttisnil(gval(gnode(t, i))) ||
ttisnil(gkey(gnode(t, i))) || ttisnil(&k) ||
ttisnumber(gkey(gnode(t, i)))) { ttisnumber(&k)) {
pushobject(L, gkey(gnode(t, i))); pushobject(L, &k);
} }
else else
lua_pushliteral(L, "<undef>"); lua_pushliteral(L, "<undef>");
@ -863,6 +1004,7 @@ static int loadlib (lua_State *L) {
{"math", luaopen_math}, {"math", luaopen_math},
{"string", luaopen_string}, {"string", luaopen_string},
{"table", luaopen_table}, {"table", luaopen_table},
{"T", luaB_opentests},
{NULL, NULL} {NULL, NULL}
}; };
lua_State *L1 = getstate(L); lua_State *L1 = getstate(L);
@ -1117,6 +1259,10 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
msg = NULL; /* to test 'luaL_checkstack' with no message */ msg = NULL; /* to test 'luaL_checkstack' with no message */
luaL_checkstack(L1, sz, msg); luaL_checkstack(L1, sz, msg);
} }
else if EQ("rawcheckstack") {
int sz = getnum;
lua_pushboolean(L1, lua_checkstack(L1, sz));
}
else if EQ("compare") { else if EQ("compare") {
const char *opt = getstring; /* EQ, LT, or LE */ const char *opt = getstring; /* EQ, LT, or LE */
int op = (opt[0] == 'E') ? LUA_OPEQ int op = (opt[0] == 'E') ? LUA_OPEQ
@ -1234,7 +1380,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
else if EQ("pop") { else if EQ("pop") {
lua_pop(L1, getnum); lua_pop(L1, getnum);
} }
else if EQ("print") { else if EQ("printstack") {
int n = getnum; int n = getnum;
if (n != 0) { if (n != 0) {
printf("%s\n", luaL_tolstring(L1, n, NULL)); printf("%s\n", luaL_tolstring(L1, n, NULL));
@ -1242,6 +1388,10 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
} }
else printstack(L1); else printstack(L1);
} }
else if EQ("print") {
const char *msg = getstring;
printf("%s\n", msg);
}
else if EQ("pushbool") { else if EQ("pushbool") {
lua_pushboolean(L1, getnum); lua_pushboolean(L1, getnum);
} }
@ -1295,8 +1445,17 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
int n = getnum; int n = getnum;
if (L1 != L) { if (L1 != L) {
int i; int i;
for (i = 0; i < n; i++) for (i = 0; i < n; i++) {
lua_pushstring(L, lua_tostring(L1, -(n - i))); int idx = -(n - i);
switch (lua_type(L1, idx)) {
case LUA_TBOOLEAN:
lua_pushboolean(L, lua_toboolean(L1, idx));
break;
default:
lua_pushstring(L, lua_tostring(L1, idx));
break;
}
}
} }
return n; return n;
} }
@ -1520,13 +1679,16 @@ static const struct luaL_Reg tests_funcs[] = {
{"doonnewstack", doonnewstack}, {"doonnewstack", doonnewstack},
{"doremote", doremote}, {"doremote", doremote},
{"gccolor", gc_color}, {"gccolor", gc_color},
{"gcage", gc_age},
{"gcstate", gc_state}, {"gcstate", gc_state},
{"pobj", gc_printobj},
{"getref", getref}, {"getref", getref},
{"hash", hash_query}, {"hash", hash_query},
{"int2fb", int2fb_aux}, {"int2fb", int2fb_aux},
{"log2", log2_aux}, {"log2", log2_aux},
{"limits", get_limits}, {"limits", get_limits},
{"listcode", listcode}, {"listcode", listcode},
{"printcode", printcode},
{"listk", listk}, {"listk", listk},
{"listlocals", listlocals}, {"listlocals", listlocals},
{"loadlib", loadlib}, {"loadlib", loadlib},
@ -1545,6 +1707,7 @@ static const struct luaL_Reg tests_funcs[] = {
{"testC", testC}, {"testC", testC},
{"makeCfunc", makeCfunc}, {"makeCfunc", makeCfunc},
{"totalmem", mem_query}, {"totalmem", mem_query},
{"alloccount", alloc_count},
{"trick", settrick}, {"trick", settrick},
{"udataval", udataval}, {"udataval", udataval},
{"unref", unref}, {"unref", unref},

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

@ -214,7 +214,7 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
** would have done the job.) ** would have done the job.)
*/ */
void luaV_finishset (lua_State *L, const TValue *t, TValue *key, 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 */ int loop; /* counter to avoid infinite loops */
for (loop = 0; loop < MAXTAGLOOP; loop++) { for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm; /* '__newindex' metamethod */ const TValue *tm; /* '__newindex' metamethod */
@ -887,6 +887,7 @@ static LClosure *getcached (Proto *p, UpVal **encup, StkId base) {
if (c->upvals[i]->v != v) if (c->upvals[i]->v != v)
return NULL; /* wrong upvalue; cannot reuse closure */ return NULL; /* wrong upvalue; cannot reuse closure */
} }
p->cachemiss = 0; /* got a hit */
} }
return c; /* return cached closure (or NULL if no cached closure) */ return c; /* return cached closure (or NULL if no cached closure) */
} }
@ -894,9 +895,7 @@ static LClosure *getcached (Proto *p, UpVal **encup, StkId base) {
/* /*
** create a new Lua closure, push it in the stack, and initialize ** create a new Lua closure, push it in the stack, and initialize
** its upvalues. Note that the closure is not cached if prototype is ** its upvalues. ???
** already black (which means that 'cache' was already cleared by the
** GC).
*/ */
static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
StkId ra) { StkId ra) {
@ -905,17 +904,21 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
int i; int i;
LClosure *ncl = luaF_newLclosure(L, nup); LClosure *ncl = luaF_newLclosure(L, nup);
ncl->p = p; 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 */ for (i = 0; i < nup; i++) { /* fill in its upvalues */
if (uv[i].instack) /* upvalue refers to local variable? */ if (uv[i].instack) /* upvalue refers to local variable? */
ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx); ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx);
else /* get upvalue from enclosing function */ else /* get upvalue from enclosing function */
ncl->upvals[i] = encup[uv[i].idx]; ncl->upvals[i] = encup[uv[i].idx];
ncl->upvals[i]->refcount++;
/* new closure is white, so we do not need a barrier here */ /* 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 */ p->cache = ncl; /* save it on cache for reuse */
luaC_protobarrier(L, p, ncl);
p->cachemiss++;
}
} }
@ -956,13 +959,13 @@ void luaV_finishOp (lua_State *L) {
StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */ StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */
int b = GETARG_B(inst); /* first element to concatenate */ int b = GETARG_B(inst); /* first element to concatenate */
int total = cast_int(top - 1 - (base + b)); /* yet 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? */ if (total > 1) { /* are there elements to concat? */
L->top = top - 1; /* top is one after last element (at top-2) */ L->top = top - 1; /* top is one after last element (at top-2) */
luaV_concat(L, total); /* concat them (may yield again) */ luaV_concat(L, total); /* concat them (may yield again) */
} }
/* move final result to final position */ /* 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 */ L->top = ci->top; /* restore top */
break; break;
} }
@ -1318,6 +1321,12 @@ int luaV_execute (lua_State *L) {
setobj2s(L, ra, cl->upvals[b]->v); setobj2s(L, ra, cl->upvals[b]->v);
vmbreak; 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) { vmcase(OP_GETTABUP) {
TValue *upval = cl->upvals[GETARG_B(i)]->v; /* table */ TValue *upval = cl->upvals[GETARG_B(i)]->v; /* table */
TValue *rc = RKC(i); /* key */ TValue *rc = RKC(i); /* key */
@ -1337,12 +1346,6 @@ int luaV_execute (lua_State *L) {
SETTABLE_INLINE_PROTECTED(L, upval, rb, rc); SETTABLE_INLINE_PROTECTED(L, upval, rb, rc);
vmbreak; vmbreak;
} }
vmcase(OP_SETUPVAL) {
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv);
vmbreak;
}
vmcase(OP_SETTABLE) { vmcase(OP_SETTABLE) {
TValue *rb = RKB(i); TValue *rb = RKB(i);
TValue *rc = RKC(i); TValue *rc = RKC(i);
@ -2198,7 +2201,7 @@ int luaV_execute (lua_State *L) {
if (tointeger(ra, &ia)) { if (tointeger(ra, &ia)) {
UpVal *uv = cl->upvals[GETARG_B(i)]; UpVal *uv = cl->upvals[GETARG_B(i)];
setivalue(uv->v, ia); setivalue(uv->v, ia);
luaC_upvalbarrier(L, uv); luaC_barrier(L, uv, ra);
} }
else else
luaG_runerror( luaG_runerror(
@ -2210,7 +2213,7 @@ int luaV_execute (lua_State *L) {
if (tonumber(ra, &na)) { if (tonumber(ra, &na)) {
UpVal *uv = cl->upvals[GETARG_B(i)]; UpVal *uv = cl->upvals[GETARG_B(i)];
setfltvalue(uv->v, na); setfltvalue(uv->v, na);
luaC_upvalbarrier(L, uv); luaC_barrier(L, uv, ra);
} }
else else
luaG_runerror( luaG_runerror(
@ -2224,7 +2227,7 @@ int luaV_execute (lua_State *L) {
"integer[] value"); "integer[] value");
UpVal *uv = cl->upvals[GETARG_B(i)]; UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra); setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv); luaC_barrier(L, uv, ra);
vmbreak; vmbreak;
} }
vmcase(OP_RAVI_SETUPVALAF) { vmcase(OP_RAVI_SETUPVALAF) {
@ -2234,7 +2237,7 @@ int luaV_execute (lua_State *L) {
"upvalue of number[] type, cannot be set to non number[] value"); "upvalue of number[] type, cannot be set to non number[] value");
UpVal *uv = cl->upvals[GETARG_B(i)]; UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra); setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv); luaC_barrier(L, uv, ra);
vmbreak; vmbreak;
} }
vmcase(OP_RAVI_SETUPVALT) { vmcase(OP_RAVI_SETUPVALT) {
@ -2243,7 +2246,7 @@ int luaV_execute (lua_State *L) {
L, "upvalue of table type, cannot be set to non table value"); L, "upvalue of table type, cannot be set to non table value");
UpVal *uv = cl->upvals[GETARG_B(i)]; UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra); setobj(L, uv->v, ra);
luaC_upvalbarrier(L, uv); luaC_barrier(L, uv, ra);
vmbreak; vmbreak;
} }
vmcase(OP_RAVI_LOADIZ) { vmcase(OP_RAVI_LOADIZ) {
@ -2740,7 +2743,7 @@ void raviV_op_setupvali(lua_State *L, LClosure *cl, TValue *ra, int b) {
if (tointeger(ra, &ia)) { if (tointeger(ra, &ia)) {
UpVal *uv = cl->upvals[b]; UpVal *uv = cl->upvals[b];
setivalue(uv->v, ia); setivalue(uv->v, ia);
luaC_upvalbarrier(L, uv); luaC_barrier(L, uv, ra);
} }
else else
luaG_runerror( luaG_runerror(
@ -2752,7 +2755,7 @@ void raviV_op_setupvalf(lua_State *L, LClosure *cl, TValue *ra, int b) {
if (tonumber(ra, &na)) { if (tonumber(ra, &na)) {
UpVal *uv = cl->upvals[b]; UpVal *uv = cl->upvals[b];
setfltvalue(uv->v, na); setfltvalue(uv->v, na);
luaC_upvalbarrier(L, uv); luaC_barrier(L, uv, ra);
} }
else else
luaG_runerror(L, luaG_runerror(L,
@ -2765,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"); L, "upvalue of integer[] type, cannot be set to non integer[] value");
UpVal *uv = cl->upvals[b]; UpVal *uv = cl->upvals[b];
setobj(L, uv->v, ra); 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) { void raviV_op_setupvalaf(lua_State *L, LClosure *cl, TValue *ra, int b) {
@ -2774,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"); L, "upvalue of number[] type, cannot be set to non number[] value");
UpVal *uv = cl->upvals[b]; UpVal *uv = cl->upvals[b];
setobj(L, uv->v, ra); 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) { void raviV_op_setupvalt(lua_State *L, LClosure *cl, TValue *ra, int b) {
@ -2782,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"); luaG_runerror(L, "upvalue of table type, cannot be set to non table value");
UpVal *uv = cl->upvals[b]; UpVal *uv = cl->upvals[b];
setobj(L, uv->v, ra); 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) { void raviV_op_setupval(lua_State *L, LClosure *cl, TValue *ra, int b) {
UpVal *uv = cl->upvals[b]; UpVal *uv = cl->upvals[b];
setobj(L, uv->v, ra); 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) { void raviV_op_add(lua_State *L, TValue *ra, TValue *rb, TValue *rc) {

@ -106,9 +106,11 @@ static const char Lua_header[] = ""
"} TValue;\n" "} TValue;\n"
"#define NILCONSTANT {NULL}, LUA_TNIL\n" "#define NILCONSTANT {NULL}, LUA_TNIL\n"
"#define val_(o) ((o)->value_)\n" "#define val_(o) ((o)->value_)\n"
"#define valraw(o) (&val_(o))\n"
"#define rttype(o) ((o)->tt_)\n" "#define rttype(o) ((o)->tt_)\n"
"#define novariant(x) ((x) & 0x0F)\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 ttnov(o) (novariant(rttype(o)))\n"
"#define checktag(o,t) (rttype(o) == (t))\n" "#define checktag(o,t) (rttype(o) == (t))\n"
"#define checktype(o,t) (ttnov(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 ttislcf(o) checktag((o), LUA_TLCF)\n"
"#define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA))\n" "#define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA))\n"
"#define ttisthread(o) checktag((o), ctb(LUA_TTHREAD))\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 ivalue(o) check_exp(ttisinteger(o), val_(o).i)\n"
"#define fltvalue(o) check_exp(ttisfloat(o), val_(o).n)\n" "#define fltvalue(o) check_exp(ttisfloat(o), val_(o).n)\n"
"#define nvalue(o) check_exp(ttisnumber(o), \\\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 hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc))\n"
"#define bvalue(o) check_exp(ttisboolean(o), val_(o).b)\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 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 l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))\n"
"#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE)\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 righttt(obj) (ttype(obj) == gcvalue(obj)->tt)\n"
"#define checkliveness(L,obj) \\\n" "#define checkliveness(L,obj) \\\n"
" lua_longassert(!iscollectable(obj) || \\\n" " lua_longassert(!iscollectable(obj) || \\\n"
@ -206,7 +214,6 @@ static const char Lua_header[] = ""
" { TValue *io = (obj); Table *x_ = (x); \\\n" " { TValue *io = (obj); Table *x_ = (x); \\\n"
" val_(io).gc = obj2gco(x_); settt_(io, ctb(RAVI_TFARRAY)); \\\n" " val_(io).gc = obj2gco(x_); settt_(io, ctb(RAVI_TFARRAY)); \\\n"
" checkliveness(L,io); }\n" " checkliveness(L,io); }\n"
"#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY)\n"
"#define setobj(L,obj1,obj2) \\\n" "#define setobj(L,obj1,obj2) \\\n"
// NOTE we cannot use aggregate assign so following assigns by field but assumes // NOTE we cannot use aggregate assign so following assigns by field but assumes
// n covers all value types // n covers all value types
@ -216,7 +223,9 @@ static const char Lua_header[] = ""
"#define setobj2s setobj\n" "#define setobj2s setobj\n"
"#define setsvalue2s setsvalue\n" "#define setsvalue2s setsvalue\n"
"#define sethvalue2s sethvalue\n" "#define sethvalue2s sethvalue\n"
"#define setthvalue2s setthvalue\n"
"#define setptvalue2s setptvalue\n" "#define setptvalue2s setptvalue\n"
"#define setclLvalue2s setclLvalue\n"
"#define setobjt2t setobj\n" "#define setobjt2t setobj\n"
"#define setobj2n setobj\n" "#define setobj2n setobj\n"
"#define setsvalue2n setsvalue\n" "#define setsvalue2n setsvalue\n"
@ -327,9 +336,20 @@ static const char Lua_header[] = ""
" struct LClosure *cache;\n" " struct LClosure *cache;\n"
" TString *source;\n" " TString *source;\n"
" GCObject *gclist;\n" " GCObject *gclist;\n"
" lu_byte cachemiss;\n"
" RaviJITProto ravi_jit;\n" " RaviJITProto ravi_jit;\n"
"} Proto;\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" "#define ClosureHeader \\\n"
" CommonHeader; lu_byte nupvalues; GCObject *gclist\n" " CommonHeader; lu_byte nupvalues; GCObject *gclist\n"
"typedef struct CClosure {\n" "typedef struct CClosure {\n"
@ -348,21 +368,23 @@ static const char Lua_header[] = ""
"} Closure;\n" "} Closure;\n"
"#define isLfunction(o) ttisLclosure(o)\n" "#define isLfunction(o) ttisLclosure(o)\n"
"#define getproto(o) (clLvalue(o)->p)\n" "#define getproto(o) (clLvalue(o)->p)\n"
"typedef union TKey {\n" "typedef union Node {\n"
" struct {\n" " struct NodeKey {\n"
" TValuefields;\n" " TValuefields;\n"
" lu_byte key_tt;\n"
" int next;\n" " int next;\n"
" } nk;\n" " Value key_val;\n"
" TValue tvk;\n" " } u;\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"
" TValue i_val;\n" " TValue i_val;\n"
" TKey i_key;\n"
"} Node;\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" "typedef enum RaviArrayModifer {\n"
" RAVI_ARRAY_SLICE = 1,\n" " RAVI_ARRAY_SLICE = 1,\n"
" RAVI_ARRAY_FIXEDSIZE = 2\n" " RAVI_ARRAY_FIXEDSIZE = 2\n"
@ -389,6 +411,18 @@ static const char Lua_header[] = ""
" unsigned int hmask;\n" " unsigned int hmask;\n"
#endif #endif
"} Table;\n" "} 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" "typedef struct Mbuffer {\n"
" char *buffer;\n" " char *buffer;\n"
" size_t n;\n" " size_t n;\n"
@ -475,17 +509,6 @@ static const char Lua_header[] = ""
" struct Proto p;\n" " struct Proto p;\n"
" struct lua_State th;\n" " struct lua_State th;\n"
"};\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 cast_u(o) cast(union GCUnion *, (o))\n"
"#define gco2ts(o) \\\n" "#define gco2ts(o) \\\n"
" check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts))\n" " check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts))\n"

@ -404,7 +404,7 @@ llvm::Value *RaviCodeGenerator::emit_table_get_nodearray(RaviFunctionDef *def,
llvm::Value *RaviCodeGenerator::emit_table_get_keytype(RaviFunctionDef *def, llvm::Value *RaviCodeGenerator::emit_table_get_keytype(RaviFunctionDef *def,
llvm::Value *node, llvm::Value *node,
llvm::Value *index) { 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, 2);
llvm::Instruction *ktype = def->builder->CreateLoad(ktype_ptr); llvm::Instruction *ktype = def->builder->CreateLoad(ktype_ptr);
ktype->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_ttT); ktype->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_ttT);
return ktype; return ktype;
@ -416,7 +416,7 @@ llvm::Value *RaviCodeGenerator::emit_table_get_keytype(RaviFunctionDef *def,
llvm::Value *RaviCodeGenerator::emit_table_get_strkey(RaviFunctionDef *def, llvm::Value *RaviCodeGenerator::emit_table_get_strkey(RaviFunctionDef *def,
llvm::Value *node, llvm::Value *node,
llvm::Value *index) { 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, 4);
llvm::Value *sptr = llvm::Value *sptr =
def->builder->CreateBitCast(value_ptr, def->types->ppTStringT); def->builder->CreateBitCast(value_ptr, def->types->ppTStringT);
llvm::Instruction *keyvalue = def->builder->CreateLoad(sptr); llvm::Instruction *keyvalue = def->builder->CreateLoad(sptr);
@ -430,7 +430,10 @@ llvm::Value *RaviCodeGenerator::emit_table_get_strkey(RaviFunctionDef *def,
llvm::Value *RaviCodeGenerator::emit_table_get_value(RaviFunctionDef *def, llvm::Value *RaviCodeGenerator::emit_table_get_value(RaviFunctionDef *def,
llvm::Value *node, llvm::Value *node,
llvm::Value *index) { 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 // Gets the size of the table's array part
@ -712,6 +715,61 @@ llvm::Value *RaviCodeGenerator::emit_ci_is_Lua(RaviFunctionDef *def,
} }
#endif #endif
// FIXME below is broken
void RaviCodeGenerator::emit_GC_barrier(RaviFunctionDef *def,
llvm::Value *upval, llvm::Value *ra) {
// 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, (GCObject *)uv, ra->value_.gc);
// is ra collectible?
llvm::Value *type = emit_load_type(def, ra);
llvm::Value *is_collectible =
def->builder->CreateAnd(type, def->types->kByte[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->kByte[bitmask(BLACKBIT)]);
llvm::Value *valuegc = def->builder->CreateBitCast(ra, def->types->pTValueGCT, "value_gc");
llvm::Value *gcobj_ptr = emit_gep(def, "v_gcobj_ptr", valuegc, 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->kByte[WHITEBITS]);
llvm::Value *cmp1 = def->builder->CreateICmpNE(
is_collectible, def->types->kByte[0], "tobool1");
llvm::Value *cmp2 =
def->builder->CreateICmpNE(is_black, def->types->kByte[0], "tobool2");
llvm::Value *and1 = def->builder->CreateAnd(cmp1, cmp2);
llvm::Value *cmp3 =
def->builder->CreateICmpNE(is_white, def->types->kByte[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 *end =
llvm::BasicBlock::Create(def->jitState->context(), "if.end");
def->builder->CreateCondBr(and2, then, end);
def->builder->SetInsertPoint(then);
// FIXME
CreateCall3(def->builder, def->luaC_barrierF, def->L,
def->builder->CreateBitCast(upval, def->types->pGCObjectT),
gcobj);
def->builder->CreateBr(end);
def->f->getBasicBlockList().push_back(end);
def->builder->SetInsertPoint(end);
}
llvm::Value *RaviCodeGenerator::emit_load_ci(RaviFunctionDef *def) { llvm::Value *RaviCodeGenerator::emit_load_ci(RaviFunctionDef *def) {
llvm::Value *L_ci = emit_gep(def, "L_ci", def->L, 0, 6); llvm::Value *L_ci = emit_gep(def, "L_ci", def->L, 0, 6);
@ -1094,9 +1152,9 @@ void RaviCodeGenerator::emit_extern_declarations(RaviFunctionDef *def) {
def->luaV_objlenF = def->raviF->addExternFunction( def->luaV_objlenF = def->raviF->addExternFunction(
def->types->luaV_objlenT, reinterpret_cast<void *>(&luaV_objlen), def->types->luaV_objlenT, reinterpret_cast<void *>(&luaV_objlen),
"luaV_objlen"); "luaV_objlen");
def->luaC_upvalbarrierF = def->raviF->addExternFunction( def->luaC_barrierF = def->raviF->addExternFunction(
def->types->luaC_upvalbarrierT, def->types->luaC_barrierT, reinterpret_cast<void *>(&luaC_barrier_),
reinterpret_cast<void *>(&luaC_upvalbarrier_), "luaC_upvalbarrier_"); "luaC_barrier_");
def->raviV_op_concatF = def->raviF->addExternFunction( def->raviV_op_concatF = def->raviF->addExternFunction(
def->types->raviV_op_concatT, reinterpret_cast<void *>(&raviV_op_concat), def->types->raviV_op_concatT, reinterpret_cast<void *>(&raviV_op_concat),
"raviV_op_concat"); "raviV_op_concat");
@ -1293,13 +1351,7 @@ llvm::Instruction *RaviCodeGenerator::emit_load_upval_v(
// Get &upval->v // Get &upval->v
llvm::Value *RaviCodeGenerator::emit_gep_upval_v(RaviFunctionDef *def, llvm::Value *RaviCodeGenerator::emit_gep_upval_v(RaviFunctionDef *def,
llvm::Instruction *pupval) { llvm::Instruction *pupval) {
return emit_gep(def, "v", pupval, 0, 0); return emit_gep(def, "v", pupval, 0, 3);
}
// 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);
} }
bool RaviCodeGenerator::compile(lua_State *L, Proto *p, bool RaviCodeGenerator::compile(lua_State *L, Proto *p,

@ -764,30 +764,7 @@ void RaviCodeGenerator::emit_SETUPVAL(RaviFunctionDef *def, int A, int B,
llvm::Value *v = emit_load_upval_v(def, upval); llvm::Value *v = emit_load_upval_v(def, upval);
emit_assign(def, v, ra); emit_assign(def, v, ra);
llvm::Value *type = emit_load_type(def, v); emit_GC_barrier(def, upval, ra);
llvm::Value *is_collectible =
def->builder->CreateAnd(type, def->types->kByte[BIT_ISCOLLECTABLE]);
llvm::Value *value = emit_gep_upval_value(def, upval);
llvm::Value *cmp = def->builder->CreateICmpNE(v, value, "v.ne.value");
llvm::Value *tobool = def->builder->CreateICmpEQ(
is_collectible, def->types->kByte[0], "not.collectible");
llvm::Value *orcond =
def->builder->CreateOr(cmp, tobool, "v.ne.value.or.not.collectible");
llvm::BasicBlock *then =
llvm::BasicBlock::Create(def->jitState->context(), "if.then", def->f);
llvm::BasicBlock *end =
llvm::BasicBlock::Create(def->jitState->context(), "if.end");
def->builder->CreateCondBr(orcond, end, then);
def->builder->SetInsertPoint(then);
CreateCall2(def->builder, def->luaC_upvalbarrierF, def->L, upval);
def->builder->CreateBr(end);
def->f->getBasicBlockList().push_back(end);
def->builder->SetInsertPoint(end);
} }
// R(A) := UpValue[B][RK(C)] // R(A) := UpValue[B][RK(C)]

@ -168,7 +168,13 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
elements.push_back(lua_NumberT); elements.push_back(lua_NumberT);
ValueT->setBody(elements); ValueT->setBody(elements);
// NOTE: Following structure changes when NaN tagging is enabled // Create a synonym type with gc member
TValueGCT = llvm::StructType::create(context, "union.ValueGC");
elements.clear();
elements.push_back(pGCObjectT);
TValueGCT->setBody(elements);
pTValueGCT = llvm::PointerType::get(TValueGCT, 0);
// struct TValue { // struct TValue {
// union Value value_; // union Value value_;
// lu_byte tt_; // lu_byte tt_;
@ -253,44 +259,14 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
///* ///*
//** Description of an upvalue for function prototypes //** 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"); 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); pUpvaldescT = llvm::PointerType::get(UpvaldescT, 0);
///* ///*
//** Description of a local variable for function prototypes //** Description of a local variable for function prototypes
//** (used for debug information) //** (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"); 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); pLocVarT = llvm::PointerType::get(LocVarT, 0);
LClosureT = llvm::StructType::create(context, "struct.LClosure"); LClosureT = llvm::StructType::create(context, "struct.LClosure");
@ -333,6 +309,7 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
// struct LClosure *cache; /* last created closure with this prototype */ // struct LClosure *cache; /* last created closure with this prototype */
// TString *source; /* used for debug information */ // TString *source; /* used for debug information */
// GCObject *gclist; // GCObject *gclist;
// lu_byte cachemiss; /* count for successive misses for 'cache' field */
// /* RAVI */ // /* RAVI */
// RaviJITProto ravi_jit; // RaviJITProto ravi_jit;
//} Proto; //} Proto;
@ -364,6 +341,7 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
elements.push_back(pLClosureT); /* cache */ elements.push_back(pLClosureT); /* cache */
elements.push_back(pTStringT); /* source */ elements.push_back(pTStringT); /* source */
elements.push_back(pGCObjectT); /* gclist */ elements.push_back(pGCObjectT); /* gclist */
elements.push_back(lu_byteT); /* cachemiss */
elements.push_back(RaviJITProtoT); /* ravi_jit */ elements.push_back(RaviJITProtoT); /* ravi_jit */
ProtoT->setBody(elements); ProtoT->setBody(elements);
@ -417,31 +395,20 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
//** Tables //** Tables
//*/ //*/
// NOTE following structure changes when NaN Tagging is enabled // We ignore the union in Node definition
//struct NodeKey {
// typedef union TKey { // TValuefields; /* fields for value */
// struct { // lu_byte key_tt; /* key type */
// TValuefields; // int next; /* for chaining */
// int next; /* for chaining (offset for next node) */ // Value key_val; /* key value */
// } nk; //};
// TValue tvk;
//} TKey;
TKeyT = llvm::StructType::create(context, "struct.TKey");
elements.clear();
elements.push_back(ValueT);
elements.push_back(lu_byteT);
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;
NodeT = llvm::StructType::create(context, "struct.Node"); NodeT = llvm::StructType::create(context, "struct.Node");
elements.clear(); elements.clear();
elements.push_back(TValueT); /* i_val */ elements.push_back(ValueT); /* Value fields */
elements.push_back(TKeyT); /* i_key */ 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); NodeT->setBody(elements);
pNodeT = llvm::PointerType::get(NodeT, 0); pNodeT = llvm::PointerType::get(NodeT, 0);
@ -692,20 +659,22 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
elements.push_back(C_shortT); elements.push_back(C_shortT);
lua_StateT->setBody(elements); lua_StateT->setBody(elements);
// struct UpVal { //typedef struct UpVal {
// struct TValue *v; /* points to stack or to its own value */ // CommonHeader;
// unsigned long long refcount; /* reference counter */ // TValue *v; /* points to stack or to its own value */
// union { // union {
// struct { /* (when open) */ // struct { /* (when open) */
// struct UpVal *next; /* linked list */ // struct UpVal *next; /* linked list */
// int touched; /* mark to avoid cycles with dead threads */ // struct UpVal **previous;
// } open; // } open;
// struct TValue value; /* the value (when closed) */ // TValue value; /* the value (when closed) */
// } u; // } u;
//}; //} UpVal;
elements.clear(); elements.clear();
elements.push_back(pGCObjectT);
elements.push_back(lu_byteT);
elements.push_back(lu_byteT);
elements.push_back(pTValueT); elements.push_back(pTValueT);
elements.push_back(C_size_t);
elements.push_back(TValueT); elements.push_back(TValueT);
UpValT->setBody(elements); UpValT->setBody(elements);
@ -717,11 +686,12 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
elements.push_back(C_intT); elements.push_back(C_intT);
luaD_poscallT = llvm::FunctionType::get(C_intT, elements, false); 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.clear();
elements.push_back(plua_StateT); elements.push_back(plua_StateT);
elements.push_back(pUpValT); elements.push_back(pGCObjectT);
luaC_upvalbarrierT = elements.push_back(pGCObjectT);
luaC_barrierT =
llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false); llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false);
// int luaD_precall (lua_State *L, StkId func, int nresults, int op_call); // int luaD_precall (lua_State *L, StkId func, int nresults, int op_call);
@ -1258,11 +1228,13 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
nodes.clear(); nodes.clear();
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_pointerT, 0)); 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_charT, 8));
nodes.push_back(std::pair<llvm::MDNode *, uint64_t>(tbaa_TValueT, 16)); 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_UpValT = mdbuilder.createTBAAStructTypeNode("UpVal", nodes);
tbaa_UpVal_vT = tbaa_UpVal_vT =
mdbuilder.createTBAAStructTagNode(tbaa_UpValT, tbaa_pointerT, 0); mdbuilder.createTBAAStructTagNode(tbaa_UpValT, tbaa_pointerT, 16);
// RaviArray // RaviArray
nodes.clear(); nodes.clear();

Loading…
Cancel
Save