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

@ -1,17 +1,14 @@
#include "lua_hdr.h"
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) {
struct UpVal *uv = cl->upvals[b];
uv->v->tt_ = ra->tt_;
uv->v->value_.n = ra->value_.n;
int b1 = iscollectable(uv->v);
uv->u.value.tt_ = 1;
struct TValue *value = &uv->u.value;
int b2 = uv->v != value;
if (b1 && !b2)
luaC_upvalbarrier_(L,uv);
int ra_iscollectable = iscollectable(ra);
int uv_isblack = isblack(uv);
int rav_iswhite = iswhite(gcvalue(ra));
if (ra_iscollectable && uv_isblack && rav_iswhite)
luaC_upvalbarrier_(L,(struct GCObject *)uv, ra->value_.gc);
}

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

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

@ -25,25 +25,18 @@
*/
/* how much to allocate before next GC step */
#if !defined(GCSTEPSIZE)
/* ~100 small strings */
#define GCSTEPSIZE (cast_int(100 * sizeof(TString)))
#endif
/*
** Possible states of the Garbage Collector
*/
#define GCSpropagate 0
#define GCSatomic 1
#define GCSswpallgc 2
#define GCSswpfinobj 3
#define GCSswptobefnz 4
#define GCSswpend 5
#define GCScallfin 6
#define GCSpause 7
#define GCSenteratomic 1
#define GCSatomic 2
#define GCSswpallgc 3
#define GCSswpfinobj 4
#define GCSswptobefnz 5
#define GCSswpend 6
#define GCScallfin 7
#define GCSpause 8
#define issweepphase(g) \
@ -74,12 +67,16 @@
#define testbit(x,b) testbits(x, bitmask(b))
/* Layout for bit use in 'marked' field: */
#define WHITE0BIT 0 /* object is white (type 0) */
#define WHITE1BIT 1 /* object is white (type 1) */
#define BLACKBIT 2 /* object is black */
#define FINALIZEDBIT 3 /* object has been marked for finalization */
/* bit 7 is currently used by tests (luaL_checkmemory) */
/*
** Layout for bit use in 'marked' field. First three bits are
** used for object "age" in generational mode.
*/
#define WHITE0BIT 3 /* object is white (type 0) */
#define WHITE1BIT 4 /* object is white (type 1) */
#define BLACKBIT 5 /* object is black */
#define FINALIZEDBIT 6 /* object has been marked for finalization */
#define TESTGRAYBIT 7 /* used by tests (luaL_checkmemory) */
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
@ -92,7 +89,7 @@
#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT)
#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS)
#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow)))
#define isdeadm(ow,m) ((m) & (ow))
#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked)
#define changewhite(x) ((x)->marked ^= WHITEBITS)
@ -101,6 +98,45 @@
#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'
** allows some adjustments to be done only when needed. macro
@ -127,9 +163,8 @@
(isblack(p) && iswhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
#define luaC_upvalbarrier(L,uv) ( \
(iscollectable((uv)->v) && !upisopen(uv)) ? \
luaC_upvalbarrier_(L,uv) : cast_void(0))
#define luaC_protobarrier(L,p,o) \
(isblack(p) ? luaC_protobarrier_(L,p) : cast_void(0))
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
@ -139,9 +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 void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o);
LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv);
LUAI_FUNC void luaC_protobarrier_ (lua_State *L, Proto *p);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv);
LUAI_FUNC void luaC_changemode (lua_State *L, int newmode);
#endif

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

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

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

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

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

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

@ -40,6 +40,14 @@
#define tonumber(o,n) \
(RAVI_LIKELY(ttisfloat(o)) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))
/* convert an object to a float (without string coercion) */
#define tonumberns(o,n) \
(ttisfloat(o) ? ((n) = fltvalue(o), 1) : \
(ttisinteger(o) ? ((n) = cast_num(ivalue(o)), 1) : 0))
/* convert an object to an integer (including string coercion) */
#define tointeger(o,i) \
(RAVI_LIKELY(ttisinteger(o)) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))

@ -168,6 +168,8 @@ struct LuaLLVMTypes {
llvm::PointerType *pGCObjectT;
llvm::StructType *ValueT;
llvm::StructType *TValueGCT;
llvm::PointerType *pTValueGCT;
llvm::StructType *TValueT;
llvm::PointerType *pTValueT;
llvm::StructType *TStringT;
@ -206,9 +208,6 @@ struct LuaLLVMTypes {
llvm::StructType *CClosureT;
llvm::PointerType *pCClosureT;
llvm::StructType *TKeyT;
llvm::PointerType *pTKeyT;
llvm::StructType *NodeT;
llvm::PointerType *pNodeT;
@ -230,7 +229,7 @@ struct LuaLLVMTypes {
llvm::FunctionType *jitFunctionT;
llvm::FunctionType *luaC_upvalbarrierT;
llvm::FunctionType *luaC_barrierT;
llvm::FunctionType *luaD_poscallT;
llvm::FunctionType *luaD_precallT;
llvm::FunctionType *luaD_callT;
@ -396,8 +395,8 @@ class RaviJITState {
// all the IR in modules get released after compilation
// MCJIT is also likely to be removed at some time in
// future so we needed to migrate anyway
// We don't use ORC apis in earlier versions because
// the apis have changed over the releases so it
// We don't use ORC apis in earlier versions because
// the apis have changed over the releases so it
// is simpler to use them in 5.0 and above.
// The ORC usage here is heavily based upon the kaleidoscope
// sample, with some adjustments.
@ -436,7 +435,7 @@ class RaviJITState {
// Size level (LLVM PassManagerBuilder)
unsigned int size_level_ : 2;
// Verbosity
unsigned int verbosity_ : 3;
@ -447,7 +446,7 @@ class RaviJITState {
// Enable extra validation such as IR verification
// May slow down compilation
unsigned int validation_ : 1;
// Flag to control calls to collect
int gcstep_;
@ -460,7 +459,7 @@ class RaviJITState {
// Count of modules allocated
// Used to debug module deallocation
size_t allocated_modules_;
// flag to help avoid recursion
int compiling_;
@ -509,9 +508,7 @@ class RaviJITState {
int get_validation() const { return validation_; }
void set_validation(bool value) { validation_ = value; }
int get_gcstep() const { return gcstep_; }
void set_gcstep(int value) {
gcstep_ = value > 0 ? value : gcstep_;
}
void set_gcstep(int value) { gcstep_ = value > 0 ? value : gcstep_; }
bool is_tracehook_enabled() const { return tracehook_enabled_; }
void set_tracehook_enabled(bool value) { tracehook_enabled_ = value; }
void incr_allocated_modules() { allocated_modules_++; }
@ -565,7 +562,7 @@ class RaviJITModule {
llvm::Module *module() const { return module_; }
llvm::ExecutionEngine *engine() const { return engine_; }
#else
// Note that this can return nullptr
// Note that this can return nullptr
llvm::Module *module() const { return module_.get(); }
#endif
RaviJITState *owner() const { return owner_; }
@ -727,7 +724,7 @@ struct RaviFunctionDef {
llvm::Function *luaV_modF;
llvm::Function *luaV_divF;
llvm::Function *luaV_objlenF;
llvm::Function *luaC_upvalbarrierF;
llvm::Function *luaC_barrierF;
llvm::Function *luaH_getstrF;
llvm::Function *luaH_getintF;
llvm::Function *luaH_setintF;
@ -1073,10 +1070,6 @@ class RaviCodeGenerator {
llvm::Instruction *emit_load_upval_v(RaviFunctionDef *def,
llvm::Instruction *pupval);
// Get &upval->value -> result is TValue *
llvm::Value *emit_gep_upval_value(RaviFunctionDef *def,
llvm::Instruction *pupval);
// isnil(reg) || isboolean(reg) && reg.value == 0
// !(isnil(reg) || isboolean(reg) && reg.value == 0)
llvm::Value *emit_boolean_testfalse(RaviFunctionDef *def, llvm::Value *reg,
@ -1274,6 +1267,9 @@ class RaviCodeGenerator {
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,
OpCode op, llvm::Function *f);

@ -129,7 +129,7 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
api_check(from, to->ci->top - to->top >= n, "stack overflow");
from->top -= n;
for (i = 0; i < n; i++) {
setobj2s(to, to->top, from->top + i);
setobjs2s(to, to->top, from->top + i);
to->top++; /* stack already checked by previous 'api_check' */
}
lua_unlock(to);
@ -194,6 +194,8 @@ LUA_API void lua_settop (lua_State *L, int idx) {
/*
** Reverse the stack segment from 'from' to 'to'
** (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) {
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);
if (n == 0) {
setfvalue(L->top, fn);
api_incr_top(L);
}
else {
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 */
}
setclCvalue(L, L->top, cl);
api_incr_top(L);
luaC_checkGC(L);
}
api_incr_top(L);
luaC_checkGC(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);
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
setobj(L, f->upvals[0]->v, gt);
luaC_upvalbarrier(L, f->upvals[0]);
luaC_barrier(L, f->upvals[0], gt);
}
}
lua_unlock(L);
@ -1356,12 +1359,12 @@ LUA_API int lua_status (lua_State *L) {
/*
** Garbage-collection function
*/
LUA_API int lua_gc (lua_State *L, int what, int data) {
LUA_API int lua_gc (lua_State *L, int what, ...) {
va_list argp;
int res = 0;
global_State *g;
global_State *g = G(L);
lua_lock(L);
g = G(L);
va_start(argp, what);
switch (what) {
case LUA_GCSTOP: {
g->gcrunning = 0;
@ -1386,11 +1389,12 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
break;
}
case LUA_GCSTEP: {
int data = va_arg(argp, int);
l_mem debt = 1; /* =1 to signal that it did an actual step */
lu_byte oldrunning = g->gcrunning;
g->gcrunning = 1; /* allow GC to run */
if (data == 0) {
luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */
luaE_setdebt(g, 0); /* do a basic step */
luaC_step(L);
}
else { /* add 'data' to total debt */
@ -1404,22 +1408,47 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
break;
}
case LUA_GCSETPAUSE: {
res = g->gcpause;
g->gcpause = data;
int data = va_arg(argp, int);
res = getgcparam(g->gcpause);
setgcparam(g->gcpause, data);
break;
}
case LUA_GCSETSTEPMUL: {
res = g->gcstepmul;
if (data < 40) data = 40; /* avoid ridiculous low values (and 0) */
g->gcstepmul = data;
int data = va_arg(argp, int);
res = getgcparam(g->gcstepmul);
setgcparam(g->gcstepmul, data);
break;
}
case LUA_GCISRUNNING: {
res = g->gcrunning;
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 */
}
va_end(argp);
lua_unlock(L);
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,
CClosure **owner, UpVal **uv, ravitype_t *type) {
GCObject **owner, ravitype_t *type) {
*type = RAVI_TANY;
switch (ttype(fi)) {
case LUA_TCCL: { /* C closure */
CClosure *f = clCvalue(fi);
if (!(1 <= n && n <= f->nupvalues)) return NULL;
*val = &f->upvalue[n-1];
if (owner) *owner = f;
if (owner) *owner = obj2gco(f);
return "";
}
case LUA_TLCL: { /* Lua closure */
@ -1531,7 +1560,7 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val,
Proto *p = f->p;
if (!(1 <= n && n <= p->sizeupvalues)) return NULL;
*val = f->upvals[n-1]->v;
if (uv) *uv = f->upvals[n - 1];
if (owner) *owner = obj2gco(f->upvals[n - 1]);
name = p->upvalues[n-1].name;
*type = p->upvalues[n - 1].ravi_type;
return (name == NULL) ? "(*no name)" : getstr(name);
@ -1546,7 +1575,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
ravitype_t type;
TValue *val = NULL; /* to avoid warnings */
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) {
setobj2s(L, L->top, val);
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) {
const char *name;
TValue *val = NULL; /* to avoid warnings */
CClosure *owner = NULL;
UpVal *uv = NULL;
GCObject *owner = NULL; /* to avoid warnings */
StkId fi;
ravitype_t type; /* RAVI upvalue type will be obtained if possible */
lua_lock(L);
fi = index2addr(L, funcindex);
api_checknelems(L, 1);
name = aux_upvalue(fi, n, &val, &owner, &uv, &type);
name = aux_upvalue(fi, n, &val, &owner, &type);
if (name) {
/* RAVI extension
** 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) {
L->top--;
setobj(L, val, L->top);
if (owner) { luaC_barrier(L, owner, L->top); }
else if (uv) { luaC_upvalbarrier(L, uv); }
luaC_barrier(L, owner, val);
}
lua_unlock(L);
return name;
@ -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 **up2 = getupvalref(L, fidx2, n2, NULL, &t2);
if (t1 == t2) {
luaC_upvdeccount(L, *up1);
*up1 = *up2;
(*up1)->refcount++;
if (upisopen(*up1)) (*up1)->u.open.touched = 1;
luaC_upvalbarrier(L, *up1);
luaC_objbarrier(L, f1, *up1);
}
}

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

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

File diff suppressed because it is too large Load Diff

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

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

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

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

@ -105,7 +105,7 @@ typedef union Header {
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) {
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);
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 */
else {
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) {
if (isdead(g,t)) return 0;
if (!issweepphase(g))
return !(isblack(f) && iswhite(t));
else return 1;
if (issweepphase(g))
return 1; /* no invariants */
else if (g->gckind == KGC_INC)
return !(isblack(f) && iswhite(t)); /* basic incremental invariant */
else { /* generational mode */
if ((getage(f) == G_OLD && isblack(f)) && !isold(t))
return 0;
if (((getage(f) == G_OLD1 || getage(f) == G_TOUCHED2) && isblack(f)) &&
getage(t) == G_NEW)
return 0;
return 1;
}
}
static void printobj (global_State *g, GCObject *o) {
printf("||%s(%p)-%c(%02X)||",
printf("||%s(%p)-%c%c(%02X)||",
ttypename(novariant(o->tt)), (void *)o,
isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', o->marked);
isdead(g,o) ? 'd' : isblack(o) ? 'b' : iswhite(o) ? 'w' : 'g',
"ns01oTt"[getage(o)], o->marked);
if (o->tt == LUA_TSHRSTR || o->tt == LUA_TLNGSTR)
printf(" '%s'", getstr(gco2ts(o)));
}
@ -235,8 +261,10 @@ static void checktable (global_State *g, Table *h) {
checkvalref(g, hgc, &h->array[i]);
for (n = gnode(h, 0); n < limit; n++) {
if (!ttisnil(gval(n))) {
lua_assert(!ttisnil(gkey(n)));
checkvalref(g, hgc, gkey(n));
TValue k;
getnodekey(g->mainthread, &k, n);
lua_assert(!keyisnil(n));
checkvalref(g, hgc, &k);
checkvalref(g, hgc, gval(n));
}
}
@ -281,9 +309,9 @@ static void checkLclosure (global_State *g, LClosure *cl) {
for (i=0; i<cl->nupvalues; i++) {
UpVal *uv = cl->upvals[i];
if (uv) {
if (!upisopen(uv)) /* only closed upvalues matter to invariant */
checkvalref(g, clgc, uv->v);
lua_assert(uv->refcount > 0);
checkobjref(g, clgc, uv);
if (!upisopen(uv))
checkvalref(g, obj2gco(uv), uv->v);
}
}
}
@ -322,57 +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))
lua_assert(maybedead);
else {
lua_assert(g->gcstate != GCSpause || iswhite(o));
switch (o->tt) {
case LUA_TUSERDATA: {
TValue uservalue;
Table *mt = gco2u(o)->metatable;
checkobjref(g, o, mt);
getuservalue(g->mainthread, gco2u(o), &uservalue);
checkvalref(g, o, &uservalue);
break;
}
case LUA_TTABLE: {
checktable(g, gco2t(o));
break;
}
case LUA_TTHREAD: {
checkstack(g, gco2th(o));
break;
}
case LUA_TLCL: {
checkLclosure(g, gco2lcl(o));
break;
if (g->gckind == KGC_GEN) { /* generational mode? */
lua_assert(getage(o) >= listage);
lua_assert(!iswhite(o) || !isold(o));
if (isold(o)) {
lua_assert(isblack(o) ||
getage(o) == G_TOUCHED1 ||
getage(o) == G_OLD0 ||
o->tt == LUA_TTHREAD ||
(o->tt == LUA_TPROTO &&
(gco2p(o)->cache != NULL || gco2p(o)->cachemiss >= MAXMISS)) ||
(o->tt == LUA_TUPVAL && upisopen(gco2upv(o))));
}
case LUA_TCCL: {
checkCclosure(g, gco2ccl(o));
break;
}
case LUA_TPROTO: {
checkproto(g, gco2p(o));
break;
}
case LUA_TSHRSTR:
case LUA_TLNGSTR: {
lua_assert(!isgray(o)); /* strings are never gray */
break;
}
default: lua_assert(0);
}
checkrefs(g, o);
}
}
#define TESTGRAYBIT 7
static void checkgraylist (global_State *g, GCObject *o) {
((void)g); /* better to keep it available if we need to print an object */
while (o) {
lua_assert(isgray(o));
lua_assert(isgray(o) || getage(o) == G_TOUCHED2);
lua_assert(!testbit(o->marked, TESTGRAYBIT));
l_setbit(o->marked, TESTGRAYBIT);
switch (o->tt) {
@ -381,7 +441,7 @@ static void checkgraylist (global_State *g, GCObject *o) {
case LUA_TCCL: o = gco2ccl(o)->gclist; break;
case LUA_TTHREAD: o = gco2th(o)->gclist; break;
case LUA_TPROTO: o = gco2p(o)->gclist; break;
default: lua_assert(0); /* other objects cannot be gray */
default: lua_assert(0); /* other objects cannot be in a gray list */
}
}
}
@ -397,13 +457,13 @@ static void markgrays (global_State *g) {
checkgraylist(g, g->grayagain);
checkgraylist(g, g->weak);
checkgraylist(g, g->ephemeron);
checkgraylist(g, g->allweak);
checkgraylist(g, g->protogray);
}
static void checkgray (global_State *g, GCObject *o) {
for (; o != NULL; o = o->next) {
if (isgray(o)) {
if ((isgray(o) && o->tt != LUA_TUPVAL) || getage(o) == G_TOUCHED2) {
lua_assert(!keepinvariant(g) || testbit(o->marked, TESTGRAYBIT));
resetbit(o->marked, TESTGRAYBIT);
}
@ -412,6 +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) {
global_State *g = G(L);
GCObject *o;
@ -421,32 +503,27 @@ int lua_checkmemory (lua_State *L) {
lua_assert(!iswhite(gcvalue(&g->l_registry)));
}
lua_assert(!isdead(g, gcvalue(&g->l_registry)));
checkstack(g, g->mainthread);
resetbit(g->mainthread->marked, TESTGRAYBIT);
lua_assert(g->sweepgc == NULL || issweepphase(g));
markgrays(g);
/* check 'fixedgc' list */
for (o = g->fixedgc; o != NULL; o = o->next) {
lua_assert(o->tt == LUA_TSHRSTR && isgray(o));
lua_assert(o->tt == LUA_TSHRSTR && isgray(o) && getage(o) == G_OLD);
}
/* check 'allgc' list */
checkgray(g, g->allgc);
maybedead = (GCSatomic < g->gcstate && g->gcstate <= GCSswpallgc);
for (o = g->allgc; o != NULL; o = o->next) {
checkobject(g, o, maybedead);
lua_assert(!tofinalize(o));
}
checklist(g, maybedead, 0, g->allgc, g->survival, g->old, g->reallyold);
/* check 'finobj' list */
checkgray(g, g->finobj);
for (o = g->finobj; o != NULL; o = o->next) {
checkobject(g, o, 0);
lua_assert(tofinalize(o));
lua_assert(o->tt == LUA_TUSERDATA || o->tt == LUA_TTABLE);
}
checklist(g, 0, 1, g->finobj, g->finobjsur, g->finobjold, g->finobjrold);
/* check 'tobefnz' list */
checkgray(g, g->tobefnz);
for (o = g->tobefnz; o != NULL; o = o->next) {
checkobject(g, o, 0);
checkobject(g, o, 0, G_NEW);
lua_assert(tofinalize(o));
lua_assert(o->tt == LUA_TUSERDATA || o->tt == LUA_TTABLE);
}
@ -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) {
Proto *p;
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) {
if (ttisnil(obj_at(L, 1)))
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 const char *statenames[] = {"propagate", "atomic", "sweepallgc",
"sweepfinobj", "sweeptobefnz", "sweepend", "pause", ""};
static const int states[] = {GCSpropagate, GCSatomic, GCSswpallgc,
GCSswpfinobj, GCSswptobefnz, GCSswpend, GCSpause, -1};
static const char *statenames[] = {
"propagate", "atomic", "enteratomic", "sweepallgc", "sweepfinobj",
"sweeptobefnz", "sweepend", "callfin", "pause", ""};
static const int states[] = {
GCSpropagate, GCSenteratomic, GCSatomic, GCSswpallgc, GCSswpfinobj,
GCSswptobefnz, GCSswpend, GCScallfin, GCSpause, -1};
int option = states[luaL_checkoption(L, 1, "", statenames)];
if (option == -1) {
lua_pushstring(L, statenames[G(L)->gcstate]);
@ -647,6 +782,8 @@ static int gc_state (lua_State *L) {
}
else {
global_State *g = G(L);
if (G(L)->gckind == KGC_GEN)
luaL_error(L, "cannot change states in generational mode");
lua_lock(L);
if (option < g->gcstate) { /* must cross 'pause'? */
luaC_runtilstate(L, bitmask(GCSpause)); /* run until pause */
@ -679,8 +816,10 @@ static int stacklevel (lua_State *L) {
unsigned long a = 0;
lua_pushinteger(L, (L->top - L->stack));
lua_pushinteger(L, (L->stack_last - L->stack));
lua_pushinteger(L, (intptr_t)&a);
return 3;
lua_pushinteger(L, L->nCcalls);
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);
}
else if ((i -= t->sizearray) < sizenode(t)) {
TValue k;
getnodekey(L, &k, gnode(t, i));
if (!ttisnil(gval(gnode(t, i))) ||
ttisnil(gkey(gnode(t, i))) ||
ttisnumber(gkey(gnode(t, i)))) {
pushobject(L, gkey(gnode(t, i)));
ttisnil(&k) ||
ttisnumber(&k)) {
pushobject(L, &k);
}
else
lua_pushliteral(L, "<undef>");
@ -863,6 +1004,7 @@ static int loadlib (lua_State *L) {
{"math", luaopen_math},
{"string", luaopen_string},
{"table", luaopen_table},
{"T", luaB_opentests},
{NULL, NULL}
};
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 */
luaL_checkstack(L1, sz, msg);
}
else if EQ("rawcheckstack") {
int sz = getnum;
lua_pushboolean(L1, lua_checkstack(L1, sz));
}
else if EQ("compare") {
const char *opt = getstring; /* EQ, LT, or LE */
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") {
lua_pop(L1, getnum);
}
else if EQ("print") {
else if EQ("printstack") {
int n = getnum;
if (n != 0) {
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 if EQ("print") {
const char *msg = getstring;
printf("%s\n", msg);
}
else if EQ("pushbool") {
lua_pushboolean(L1, getnum);
}
@ -1295,8 +1445,17 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
int n = getnum;
if (L1 != L) {
int i;
for (i = 0; i < n; i++)
lua_pushstring(L, lua_tostring(L1, -(n - i)));
for (i = 0; i < 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;
}
@ -1520,13 +1679,16 @@ static const struct luaL_Reg tests_funcs[] = {
{"doonnewstack", doonnewstack},
{"doremote", doremote},
{"gccolor", gc_color},
{"gcage", gc_age},
{"gcstate", gc_state},
{"pobj", gc_printobj},
{"getref", getref},
{"hash", hash_query},
{"int2fb", int2fb_aux},
{"log2", log2_aux},
{"limits", get_limits},
{"listcode", listcode},
{"printcode", printcode},
{"listk", listk},
{"listlocals", listlocals},
{"loadlib", loadlib},
@ -1545,6 +1707,7 @@ static const struct luaL_Reg tests_funcs[] = {
{"testC", testC},
{"makeCfunc", makeCfunc},
{"totalmem", mem_query},
{"alloccount", alloc_count},
{"trick", settrick},
{"udataval", udataval},
{"unref", unref},

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

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

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

@ -404,7 +404,7 @@ llvm::Value *RaviCodeGenerator::emit_table_get_nodearray(RaviFunctionDef *def,
llvm::Value *RaviCodeGenerator::emit_table_get_keytype(RaviFunctionDef *def,
llvm::Value *node,
llvm::Value *index) {
llvm::Value *ktype_ptr = emit_gep(def, "keytype", node, index, 1, 1);
llvm::Value *ktype_ptr = emit_gep(def, "keytype", node, index, 2);
llvm::Instruction *ktype = def->builder->CreateLoad(ktype_ptr);
ktype->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_ttT);
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 *node,
llvm::Value *index) {
llvm::Value *value_ptr = emit_gep(def, "keyvalue", node, index, 1, 0);
llvm::Value *value_ptr = emit_gep(def, "keyvalue", node, index, 4);
llvm::Value *sptr =
def->builder->CreateBitCast(value_ptr, def->types->ppTStringT);
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 *node,
llvm::Value *index) {
return emit_gep(def, "nodeval", node, index, 0);
llvm::Value *value = emit_gep(def, "nodeval", node, index, 0);
// We need to cast it to TValue *
llvm::Value *ptr = def->builder->CreateBitCast(value, def->types->pTValueT);
return ptr;
}
// Gets the size of the table's array part
@ -712,6 +715,61 @@ llvm::Value *RaviCodeGenerator::emit_ci_is_Lua(RaviFunctionDef *def,
}
#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 *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->types->luaV_objlenT, reinterpret_cast<void *>(&luaV_objlen),
"luaV_objlen");
def->luaC_upvalbarrierF = def->raviF->addExternFunction(
def->types->luaC_upvalbarrierT,
reinterpret_cast<void *>(&luaC_upvalbarrier_), "luaC_upvalbarrier_");
def->luaC_barrierF = def->raviF->addExternFunction(
def->types->luaC_barrierT, reinterpret_cast<void *>(&luaC_barrier_),
"luaC_barrier_");
def->raviV_op_concatF = def->raviF->addExternFunction(
def->types->raviV_op_concatT, reinterpret_cast<void *>(&raviV_op_concat),
"raviV_op_concat");
@ -1293,13 +1351,7 @@ llvm::Instruction *RaviCodeGenerator::emit_load_upval_v(
// Get &upval->v
llvm::Value *RaviCodeGenerator::emit_gep_upval_v(RaviFunctionDef *def,
llvm::Instruction *pupval) {
return emit_gep(def, "v", pupval, 0, 0);
}
// Get &upval->value -> result is TValue *
llvm::Value *RaviCodeGenerator::emit_gep_upval_value(
RaviFunctionDef *def, llvm::Instruction *pupval) {
return emit_gep(def, "value", pupval, 0, 2);
return emit_gep(def, "v", pupval, 0, 3);
}
bool RaviCodeGenerator::compile(lua_State *L, Proto *p,

@ -764,30 +764,7 @@ void RaviCodeGenerator::emit_SETUPVAL(RaviFunctionDef *def, int A, int B,
llvm::Value *v = emit_load_upval_v(def, upval);
emit_assign(def, v, ra);
llvm::Value *type = emit_load_type(def, v);
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);
emit_GC_barrier(def, upval, ra);
}
// R(A) := UpValue[B][RK(C)]

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

Loading…
Cancel
Save