diff options
Diffstat (limited to 'lfunc.c')
-rw-r--r-- | lfunc.c | 126 |
1 files changed, 94 insertions, 32 deletions
@@ -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 | **/ | ||
64 | static 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 | */ | ||
59 | UpVal *luaF_findupval (lua_State *L, StkId level) { | 86 | UpVal *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 | ||
92 | static 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)); | 110 | static 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 | */ | ||
133 | static 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 | */ | ||
157 | static 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 | */ | ||
169 | void 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 | |||
121 | void luaF_unlinkupval (UpVal *uv) { | 183 | void 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 | } |