aboutsummaryrefslogtreecommitdiff
path: root/lfunc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lfunc.c')
-rw-r--r--lfunc.c126
1 files changed, 94 insertions, 32 deletions
diff --git a/lfunc.c b/lfunc.c
index fde72b8c..4f9362f3 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -40,6 +40,7 @@ LClosure *luaF_newLclosure (lua_State *L, int n) {
40 return c; 40 return c;
41} 41}
42 42
43
43/* 44/*
44** fill a closure with new closed upvalues 45** fill a closure with new closed upvalues
45*/ 46*/
@@ -56,31 +57,43 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
56} 57}
57 58
58 59
60/*
61** Create a new upvalue with the given tag at the given level,
62** and link it to the list of open upvalues of 'L' after entry 'prev'.
63**/
64static UpVal *newupval (lua_State *L, int tag, StkId level, UpVal **prev) {
65 GCObject *o = luaC_newobj(L, tag, sizeof(UpVal));
66 UpVal *uv = gco2upv(o);
67 UpVal *next = *prev;
68 uv->v = s2v(level); /* current value lives in the stack */
69 uv->u.open.next = next; /* link it to list of open upvalues */
70 uv->u.open.previous = prev;
71 if (next)
72 next->u.open.previous = &uv->u.open.next;
73 *prev = uv;
74 if (!isintwups(L)) { /* thread not in list of threads with upvalues? */
75 L->twups = G(L)->twups; /* link it to the list */
76 G(L)->twups = L;
77 }
78 return uv;
79}
80
81
82/*
83** Find and reuse, or create if it does not exist, a regular upvalue
84** at the given level.
85*/
59UpVal *luaF_findupval (lua_State *L, StkId level) { 86UpVal *luaF_findupval (lua_State *L, StkId level) {
60 UpVal **pp = &L->openupval; 87 UpVal **pp = &L->openupval;
61 GCObject *o;
62 UpVal *p; 88 UpVal *p;
63 UpVal *uv;
64 lua_assert(isintwups(L) || L->openupval == NULL); 89 lua_assert(isintwups(L) || L->openupval == NULL);
65 while ((p = *pp) != NULL && uplevel(p) >= level) { 90 while ((p = *pp) != NULL && uplevel(p) >= level) { /* search for it */
66 if (uplevel(p) == level && !isdead(G(L), p)) /* corresponding upvalue? */ 91 if (uplevel(p) == level && !isdead(G(L), p)) /* corresponding upvalue? */
67 return p; /* return it */ 92 return p; /* return it */
68 pp = &p->u.open.next; 93 pp = &p->u.open.next;
69 } 94 }
70 /* not found: create a new upvalue between 'pp' and 'p' */ 95 /* not found: create a new upvalue after 'pp' */
71 o = luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal)); 96 return newupval(L, LUA_TUPVAL, level, pp);
72 uv = gco2upv(o);
73 uv->u.open.next = p; /* link it to list of open upvalues */
74 uv->u.open.previous = pp;
75 if (p)
76 p->u.open.previous = &uv->u.open.next;
77 *pp = uv;
78 uv->v = s2v(level); /* current value lives in the stack */
79 if (!isintwups(L)) { /* thread not in list of threads with upvalues? */
80 L->twups = G(L)->twups; /* link it to the list */
81 G(L)->twups = L;
82 }
83 return uv;
84} 97}
85 98
86 99
@@ -89,25 +102,44 @@ static void callclose (lua_State *L, void *ud) {
89} 102}
90 103
91 104
92static int closeupval (lua_State *L, UpVal *uv, StkId level, int status) { 105/*
93 StkId func = level + 1; /* save slot for old error message */ 106** Prepare closing method with its argument for object at
94 if (status != LUA_OK) /* was there an error? */ 107** index 'func' in the stack. Assume there is an error message
95 luaD_seterrorobj(L, status, level); /* save error message */ 108** (or nil) just below the object.
96 else 109*/
97 setnilvalue(s2v(level)); 110static int prepclosingmethod (lua_State *L, StkId func) {
98 if (ttisfunction(uv->v)) { /* object to-be-closed is a function? */ 111 if (ttisfunction(s2v(func))) { /* object to-be-closed is a function? */
99 setobj2s(L, func, uv->v); /* will call it */ 112 setobjs2s(L, func + 1, func - 1); /* push error msg. as argument */
100 setobjs2s(L, func + 1, level); /* error msg. as argument */
101 } 113 }
102 else { /* try '__close' metamethod */ 114 else { /* try '__close' metamethod */
103 const TValue *tm = luaT_gettmbyobj(L, uv->v, TM_CLOSE); 115 const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CLOSE);
104 if (ttisnil(tm)) 116 if (ttisnil(tm)) /* no metamethod? */
105 return status; /* no metamethod */ 117 return 0; /* nothing to call */
118 setobjs2s(L, func + 1, func); /* 'self' is the argument */
106 setobj2s(L, func, tm); /* will call metamethod */ 119 setobj2s(L, func, tm); /* will call metamethod */
107 setobj2s(L, func + 1, uv->v); /* with 'self' as argument */
108 } 120 }
109 L->top = func + 2; /* add function and argument */ 121 L->top = func + 2; /* add function and argument */
110 if (status == LUA_OK) /* not in "error mode"? */ 122 return 1;
123}
124
125
126/*
127** Prepare and call a closing method. If status is OK, code is
128** still inside the original protected call, and so any error
129** will be handled there. Otherwise, a previous error already
130** activated original protected call, and so the call to the
131** closing method must be protected here.
132*/
133static int closeupval (lua_State *L, TValue *uv, StkId level, int status) {
134 StkId func = level + 1; /* save slot for old error message */
135 if (unlikely(status != LUA_OK)) /* was there an error? */
136 luaD_seterrorobj(L, status, level); /* save error message */
137 else
138 setnilvalue(s2v(level)); /* no error message */
139 setobj2s(L, func, uv); /* put object on top of error message */
140 if (!prepclosingmethod(L, func))
141 return status; /* nothing to call */
142 if (likely(status == LUA_OK)) /* not in "error mode"? */
111 callclose(L, func); /* call closing method */ 143 callclose(L, func); /* call closing method */
112 else { /* already inside error handler; cannot raise another error */ 144 else { /* already inside error handler; cannot raise another error */
113 int newstatus = luaD_pcall(L, callclose, func, savestack(L, level), 0); 145 int newstatus = luaD_pcall(L, callclose, func, savestack(L, level), 0);
@@ -118,6 +150,36 @@ static int closeupval (lua_State *L, UpVal *uv, StkId level, int status) {
118} 150}
119 151
120 152
153/*
154** Try to create a to-be-closed upvalue
155** (can raise a memory-allocation error)
156*/
157static void trynewtbcupval (lua_State *L, void *ud) {
158 StkId level = cast(StkId, ud);
159 lua_assert(L->openupval == NULL || uplevel(L->openupval) < level);
160 newupval(L, LUA_TUPVALTBC, level, &L->openupval);
161}
162
163
164/*
165** Create a to-be-closed upvalue. If there is a memory error
166** when creating the upvalue, the closing method must be called here,
167** as there is no upvalue to call it later.
168*/
169void luaF_newtbcupval (lua_State *L, StkId level) {
170 int status = luaD_rawrunprotected(L, trynewtbcupval, level);
171 if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */
172 StkId func = level + 1;
173 lua_assert(status == LUA_ERRMEM);
174 setobjs2s(L, func, level); /* open space for error message */
175 luaD_seterrorobj(L, status, level); /* save error message */
176 if (prepclosingmethod(L, func))
177 callclose(L, func); /* call closing method */
178 luaD_throw(L, LUA_ERRMEM); /* throw memory error */
179 }
180}
181
182
121void luaF_unlinkupval (UpVal *uv) { 183void luaF_unlinkupval (UpVal *uv) {
122 lua_assert(upisopen(uv)); 184 lua_assert(upisopen(uv));
123 *uv->u.open.previous = uv->u.open.next; 185 *uv->u.open.previous = uv->u.open.next;
@@ -139,7 +201,7 @@ int luaF_close (lua_State *L, StkId level, int status) {
139 luaC_barrier(L, uv, slot); 201 luaC_barrier(L, uv, slot);
140 if (status >= 0 && uv->tt == LUA_TUPVALTBC) { /* must be closed? */ 202 if (status >= 0 && uv->tt == LUA_TUPVALTBC) { /* must be closed? */
141 ptrdiff_t levelrel = savestack(L, level); 203 ptrdiff_t levelrel = savestack(L, level);
142 status = closeupval(L, uv, upl, status); /* may reallocate the stack */ 204 status = closeupval(L, uv->v, upl, status); /* may reallocate the stack */
143 level = restorestack(L, levelrel); 205 level = restorestack(L, levelrel);
144 } 206 }
145 } 207 }