1 | /******************************************************************************* |
2 | * Copyright (c) 2009 Luaj.org. All rights reserved. |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | * of this software and associated documentation files (the "Software"), to deal |
6 | * in the Software without restriction, including without limitation the rights |
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
8 | * copies of the Software, and to permit persons to whom the Software is |
9 | * furnished to do so, subject to the following conditions: |
10 | * |
11 | * The above copyright notice and this permission notice shall be included in |
12 | * all copies or substantial portions of the Software. |
13 | * |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
20 | * THE SOFTWARE. |
21 | ******************************************************************************/ |
22 | package org.luaj.vm2; |
23 | |
24 | import net.luaos.tb.common.LuaUtil; |
25 | |
26 | /** |
27 | * Central interpreter loop |
28 | * |
29 | * Extension of {@link LuaFunction} which executes lua bytecode. |
30 | * <p> |
31 | * A {@link LuaClosure} is a combination of a {@link Prototype} |
32 | * and a {@link LuaValue} to use as an environment for execution. |
33 | * <p> |
34 | * There are three main ways {@link LuaClosure} instances are created: |
35 | * <ul> |
36 | * <li>Construct an instance using {@link #LuaClosure(Prototype, LuaValue)}</li> |
37 | * <li>Construct it indirectly by loading a chunk via {@link LuaCompiler#load(java.io.InputStream, String, LuaValue)} |
38 | * <li>Execute the lua bytecode {@link Lua#OP_CLOSURE} as part of bytecode processing |
39 | * </ul> |
40 | * <p> |
41 | * To construct it directly, the {@link Prototype} is typically created via a compiler such as {@link LuaC}: |
42 | * <pre> {@code |
43 | * InputStream is = new ByteArrayInputStream("print('hello,world').getBytes()); |
44 | * Prototype p = LuaC.instance.compile(is, "script"); |
45 | * LuaValue _G = JsePlatform.standardGlobals() |
46 | * LuaClosure f = new LuaClosure(p, _G); |
47 | * }</pre> |
48 | * <p> |
49 | * To construct it indirectly, the {@link LuaC} compiler may be used, |
50 | * which implements the {@link LuaCompiler} interface: |
51 | * <pre> {@code |
52 | * LuaFunction f = LuaC.instance.load(is, "script", _G); |
53 | * }</pre> |
54 | * <p> |
55 | * Typically, a closure that has just been loaded needs to be initialized by executing it, |
56 | * and its return value can be saved if needed: |
57 | * <pre> {@code |
58 | * LuaValue r = f.call(); |
59 | * _G.set( "mypkg", r ) |
60 | * }</pre> |
61 | * <p> |
62 | * In the preceding, the loaded value is typed as {@link LuaFunction} |
63 | * to allow for the possibility of other compilers such as {@link LuaJC} |
64 | * producing {@link LuaFunction} directly without |
65 | * creating a {@link Prototype} or {@link LuaClosure}. |
66 | * <p> |
67 | * Since a {@link LuaClosure} is a {@link LuaFunction} which is a {@link LuaValue}, |
68 | * all the value operations can be used directly such as: |
69 | * <ul> |
70 | * <li>{@link LuaValue#call()}</li> |
71 | * <li>{@link LuaValue#call(LuaValue)}</li> |
72 | * <li>{@link LuaValue#invoke()}</li> |
73 | * <li>{@link LuaValue#invoke(Varargs)}</li> |
74 | * <li>{@link LuaValue#method(String)}</li> |
75 | * <li>{@link LuaValue#method(String,LuaValue)}</li> |
76 | * <li>{@link LuaValue#invokemethod(String)}</li> |
77 | * <li>{@link LuaValue#invokemethod(String,Varargs)}</li> |
78 | * <li> ...</li> |
79 | * </ul> |
80 | * @see LuaValue |
81 | * @see LuaFunction |
82 | * @see LuaValue#isclosure() |
83 | * @see LuaValue#checkclosure() |
84 | * @see LuaValue#optclosure(LuaClosure) |
85 | * @see LoadState |
86 | * @see LoadState#compiler |
87 | */ |
88 | public class LuaClosure extends LuaFunction { |
89 | private static final UpValue[] NOUPVALUES = new UpValue[0]; |
90 | |
91 | public final Prototype p; |
92 | |
93 | public UpValue[] upValues; |
94 | |
95 | Globals globals; |
96 | |
97 | /** Create a closure around a Prototype with a specific environment. |
98 | * If the prototype has upvalues, the environment will be written into the first upvalue. |
99 | * @param p the Prototype to construct this Closure for. |
100 | * @param env the environment to associate with the closure. |
101 | */ |
102 | public LuaClosure(Prototype p, LuaValue env) { |
103 | this(p, env, env instanceof Globals? (Globals) env: null); |
104 | } |
105 | |
106 | public LuaClosure(Prototype p, LuaValue env, Globals globals) { |
107 | this.p = p; |
108 | if (p.upvalues == null || p.upvalues.length == 0) |
109 | this.upValues = NOUPVALUES; |
110 | else { |
111 | this.upValues = new UpValue[p.upvalues.length]; |
112 | this.upValues[0] = new UpValue(new LuaValue[] {env}, 0); |
113 | } |
114 | this.globals = globals; |
115 | |
116 | // XXX Stefan |
117 | if (globals == null) |
118 | throw new RuntimeException("Fatal: Closure has no globals."); |
119 | } |
120 | |
121 | public boolean isclosure() { |
122 | return true; |
123 | } |
124 | |
125 | public LuaClosure optclosure(LuaClosure defval) { |
126 | return this; |
127 | } |
128 | |
129 | public LuaClosure checkclosure() { |
130 | return this; |
131 | } |
132 | |
133 | public LuaValue getmetatable() { |
134 | return s_metatable; |
135 | } |
136 | |
137 | public String tojstring() { |
138 | return "function: " + p.toString(); |
139 | } |
140 | |
141 | public final LuaValue call() { |
142 | LuaValue[] stack = new LuaValue[p.maxstacksize]; |
143 | for (int i = 0; i < p.numparams; ++i ) |
144 | stack[i] = NIL; |
145 | return execute(stack,NONE).arg1(); |
146 | } |
147 | |
148 | public final LuaValue call(LuaValue arg) { |
149 | LuaValue[] stack = new LuaValue[p.maxstacksize]; |
150 | System.arraycopy(NILS, 0, stack, 0, p.maxstacksize); |
151 | for (int i = 1; i < p.numparams; ++i ) |
152 | stack[i] = NIL; |
153 | switch ( p.numparams ) { |
154 | default: stack[0]=arg; return execute(stack,NONE).arg1(); |
155 | case 0: return execute(stack,arg).arg1(); |
156 | } |
157 | } |
158 | |
159 | public final LuaValue call(LuaValue arg1, LuaValue arg2) { |
160 | LuaValue[] stack = new LuaValue[p.maxstacksize]; |
161 | for (int i = 2; i < p.numparams; ++i ) |
162 | stack[i] = NIL; |
163 | switch ( p.numparams ) { |
164 | default: stack[0]=arg1; stack[1]=arg2; return execute(stack,NONE).arg1(); |
165 | case 1: stack[0]=arg1; return execute(stack,arg2).arg1(); |
166 | case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2): NONE).arg1(); |
167 | } |
168 | } |
169 | |
170 | public final LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) { |
171 | LuaValue[] stack = new LuaValue[p.maxstacksize]; |
172 | for (int i = 3; i < p.numparams; ++i ) |
173 | stack[i] = NIL; |
174 | switch ( p.numparams ) { |
175 | default: stack[0]=arg1; stack[1]=arg2; stack[2]=arg3; return execute(stack,NONE).arg1(); |
176 | case 2: stack[0]=arg1; stack[1]=arg2; return execute(stack,arg3).arg1(); |
177 | case 1: stack[0]=arg1; return execute(stack,p.is_vararg!=0? varargsOf(arg2,arg3): NONE).arg1(); |
178 | case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2,arg3): NONE).arg1(); |
179 | } |
180 | } |
181 | |
182 | public final Varargs invoke(Varargs varargs) { |
183 | return onInvoke(varargs).eval(); |
184 | } |
185 | |
186 | public final Varargs onInvoke(Varargs varargs) { |
187 | LuaValue[] stack = new LuaValue[p.maxstacksize]; |
188 | for ( int i=0; i<p.numparams; i++ ) |
189 | stack[i] = varargs.arg(i+1); |
190 | return execute(stack,p.is_vararg!=0? varargs.subargs(p.numparams+1): NONE); |
191 | } |
192 | |
193 | protected Varargs execute( LuaValue[] stack, Varargs varargs ) { |
194 | // loop through instructions |
195 | int i,a,b,c,pc=0,top=0; |
196 | LuaValue o; |
197 | Varargs v = NONE; |
198 | int[] code = p.code; |
199 | LuaValue[] k = p.k; |
200 | |
201 | if (LuaUtil.verbose) |
202 | System.out.println("LuaClosure.execute, globals.running=" + globals.running); |
203 | |
204 | // upvalues are only possible when closures create closures |
205 | // TODO: use linked list. |
206 | UpValue[] openups = p.p.length>0? new UpValue[stack.length]: null; |
207 | |
208 | // allow for debug hooks |
209 | if (globals != null && globals.debuglib != null) |
210 | globals.debuglib.onCall( this, varargs, stack ); |
211 | |
212 | // process instructions |
213 | try { |
214 | while ( true ) { |
215 | if (globals != null && globals.debuglib != null) |
216 | globals.debuglib.onInstruction( pc, v, top ); |
217 | |
218 | // pull out instruction |
219 | i = code[pc++]; |
220 | a = ((i>>6) & 0xff); |
221 | |
222 | // process the op code |
223 | switch ( i & 0x3f ) { |
224 | |
225 | case Lua.OP_MOVE:/* A B R(A):= R(B) */ |
226 | stack[a] = stack[i>>>23]; |
227 | continue; |
228 | |
229 | case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */ |
230 | stack[a] = k[i>>>14]; |
231 | continue; |
232 | |
233 | case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */ |
234 | stack[a] = (i>>>23!=0)? LuaValue.TRUE: LuaValue.FALSE; |
235 | if ((i&(0x1ff<<14)) != 0) |
236 | pc++; /* skip next instruction (if C) */ |
237 | continue; |
238 | |
239 | case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(A+B):= nil */ |
240 | for ( b=i>>>23; b-->=0; ) |
241 | stack[a++] = LuaValue.NIL; |
242 | continue; |
243 | |
244 | case Lua.OP_GETUPVAL: /* A B R(A):= UpValue[B] */ |
245 | stack[a] = upValues[i>>>23].getValue(); |
246 | continue; |
247 | |
248 | case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */ |
249 | stack[a] = upValues[i>>>23].getValue().get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); |
250 | continue; |
251 | |
252 | case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */ |
253 | stack[a] = stack[i>>>23].get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); |
254 | continue; |
255 | |
256 | case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */ |
257 | upValues[a].getValue().set(((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]), (c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); |
258 | continue; |
259 | |
260 | case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */ |
261 | upValues[i>>>23].setValue(stack[a]); |
262 | continue; |
263 | |
264 | case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */ |
265 | stack[a].set(((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]), (c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); |
266 | continue; |
267 | |
268 | case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */ |
269 | stack[a] = new LuaTable(i>>>23,(i>>14)&0x1ff); |
270 | continue; |
271 | |
272 | case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */ |
273 | stack[a+1] = (o = stack[i>>>23]); |
274 | stack[a] = o.get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); |
275 | continue; |
276 | |
277 | case Lua.OP_ADD: /* A B C R(A):= RK(B) + RK(C) */ |
278 | stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).add((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); |
279 | continue; |
280 | |
281 | case Lua.OP_SUB: /* A B C R(A):= RK(B) - RK(C) */ |
282 | stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).sub((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); |
283 | continue; |
284 | |
285 | case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */ |
286 | stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).mul((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); |
287 | continue; |
288 | |
289 | case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */ |
290 | stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).div((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); |
291 | continue; |
292 | |
293 | case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */ |
294 | stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).mod((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); |
295 | continue; |
296 | |
297 | case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */ |
298 | stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).pow((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); |
299 | continue; |
300 | |
301 | case Lua.OP_UNM: /* A B R(A):= -R(B) */ |
302 | stack[a] = stack[i>>>23].neg(); |
303 | continue; |
304 | |
305 | case Lua.OP_NOT: /* A B R(A):= not R(B) */ |
306 | stack[a] = stack[i>>>23].not(); |
307 | continue; |
308 | |
309 | case Lua.OP_LEN: /* A B R(A):= length of R(B) */ |
310 | stack[a] = stack[i>>>23].len(); |
311 | continue; |
312 | |
313 | case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */ |
314 | b = i>>>23; |
315 | c = (i>>14)&0x1ff; |
316 | { |
317 | if ( c > b+1 ) { |
318 | Buffer sb = stack[c].buffer(); |
319 | while ( --c>=b ) |
320 | sb = stack[c].concat(sb); |
321 | stack[a] = sb.value(); |
322 | } else { |
323 | stack[a] = stack[c-1].concat(stack[c]); |
324 | } |
325 | } |
326 | continue; |
327 | |
328 | case Lua.OP_JMP: /* sBx pc+=sBx */ |
329 | pc += (i>>>14)-0x1ffff; |
330 | if (a > 0) { |
331 | for (--a, b = openups.length; --b>=0; ) |
332 | if (openups[b] != null && openups[b].index >= a) { |
333 | openups[b].close(); |
334 | openups[b] = null; |
335 | } |
336 | } |
337 | continue; |
338 | |
339 | case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ |
340 | if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).eq_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) ) |
341 | ++pc; |
342 | continue; |
343 | |
344 | case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ |
345 | if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).lt_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) ) |
346 | ++pc; |
347 | continue; |
348 | |
349 | case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ |
350 | if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).lteq_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) ) |
351 | ++pc; |
352 | continue; |
353 | |
354 | case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */ |
355 | if ( stack[a].toboolean() != ((i&(0x1ff<<14))!=0) ) |
356 | ++pc; |
357 | continue; |
358 | |
359 | case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */ |
360 | /* note: doc appears to be reversed */ |
361 | if ( (o=stack[i>>>23]).toboolean() != ((i&(0x1ff<<14))!=0) ) |
362 | ++pc; |
363 | else |
364 | stack[a] = o; // TODO: should be sBx? |
365 | continue; |
366 | |
367 | case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */ |
368 | switch ( i & (Lua.MASK_B | Lua.MASK_C) ) { |
369 | case (1<<Lua.POS_B) | (0<<Lua.POS_C): v=stack[a].invoke(NONE); top=a+v.narg(); continue; |
370 | case (2<<Lua.POS_B) | (0<<Lua.POS_C): v=stack[a].invoke(stack[a+1]); top=a+v.narg(); continue; |
371 | case (1<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(); continue; |
372 | case (2<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1]); continue; |
373 | case (3<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2]); continue; |
374 | case (4<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2],stack[a+3]); continue; |
375 | case (1<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(); continue; |
376 | case (2<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1]); continue; |
377 | case (3<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1],stack[a+2]); continue; |
378 | case (4<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1],stack[a+2],stack[a+3]); continue; |
379 | default: |
380 | b = i>>>23; |
381 | c = (i>>14)&0x1ff; |
382 | v = b>0? |
383 | varargsOf(stack,a+1,b-1): // exact arg count |
384 | varargsOf(stack, a+1, top-v.narg()-(a+1), v); // from prev top |
385 | v = stack[a].invoke(v); |
386 | if ( c > 0 ) { |
387 | while ( --c > 0 ) |
388 | stack[a+c-1] = v.arg(c); |
389 | v = NONE; // TODO: necessary? |
390 | } else { |
391 | top = a + v.narg(); |
392 | } |
393 | continue; |
394 | } |
395 | |
396 | case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ |
397 | switch ( i & Lua.MASK_B ) { |
398 | case (1<<Lua.POS_B): return new TailcallVarargs(stack[a], NONE); |
399 | case (2<<Lua.POS_B): return new TailcallVarargs(stack[a], stack[a+1]); |
400 | case (3<<Lua.POS_B): return new TailcallVarargs(stack[a], varargsOf(stack[a+1],stack[a+2])); |
401 | case (4<<Lua.POS_B): return new TailcallVarargs(stack[a], varargsOf(stack[a+1],stack[a+2],stack[a+3])); |
402 | default: |
403 | b = i>>>23; |
404 | v = b>0? |
405 | varargsOf(stack,a+1,b-1): // exact arg count |
406 | varargsOf(stack, a+1, top-v.narg()-(a+1), v); // from prev top |
407 | return new TailcallVarargs( stack[a], v ); |
408 | } |
409 | |
410 | case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */ |
411 | b = i>>>23; |
412 | switch ( b ) { |
413 | case 0: return varargsOf(stack, a, top-v.narg()-a, v); |
414 | case 1: return NONE; |
415 | case 2: return stack[a]; |
416 | default: |
417 | return varargsOf(stack, a, b-1); |
418 | } |
419 | |
420 | case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2): if R(A) <?= R(A+1) then { pc+=sBx: R(A+3)=R(A) }*/ |
421 | { |
422 | LuaValue limit = stack[a + 1]; |
423 | LuaValue step = stack[a + 2]; |
424 | LuaValue idx = step.add(stack[a]); |
425 | if (step.gt_b(0)? idx.lteq_b(limit): idx.gteq_b(limit)) { |
426 | stack[a] = idx; |
427 | stack[a + 3] = idx; |
428 | pc += (i>>>14)-0x1ffff; |
429 | } |
430 | } |
431 | continue; |
432 | |
433 | case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */ |
434 | { |
435 | LuaValue init = stack[a].checknumber("'for' initial value must be a number"); |
436 | LuaValue limit = stack[a + 1].checknumber("'for' limit must be a number"); |
437 | LuaValue step = stack[a + 2].checknumber("'for' step must be a number"); |
438 | stack[a] = init.sub(step); |
439 | stack[a + 1] = limit; |
440 | stack[a + 2] = step; |
441 | pc += (i>>>14)-0x1ffff; |
442 | } |
443 | continue; |
444 | |
445 | case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */ |
446 | v = stack[a].invoke(varargsOf(stack[a+1],stack[a+2])); |
447 | c = (i>>14) & 0x1ff; |
448 | while (--c >= 0) |
449 | stack[a+3+c] = v.arg(c+1); |
450 | v = NONE; |
451 | continue; |
452 | |
453 | case Lua.OP_TFORLOOP: /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx */ |
454 | if (!stack[a+1].isnil()) { /* continue loop? */ |
455 | stack[a] = stack[a+1]; /* save control varible. */ |
456 | pc += (i>>>14)-0x1ffff; |
457 | } |
458 | continue; |
459 | |
460 | case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */ |
461 | { |
462 | if ( (c=(i>>14)&0x1ff) == 0 ) |
463 | c = code[pc++]; |
464 | int offset = (c-1) * Lua.LFIELDS_PER_FLUSH; |
465 | o = stack[a]; |
466 | if ( (b=i>>>23) == 0 ) { |
467 | b = top - a - 1; |
468 | int m = b - v.narg(); |
469 | int j=1; |
470 | for ( ;j<=m; j++ ) |
471 | o.set(offset+j, stack[a + j]); |
472 | for ( ;j<=b; j++ ) |
473 | o.set(offset+j, v.arg(j-m)); |
474 | } else { |
475 | o.presize( offset + b ); |
476 | for (int j=1; j<=b; j++) |
477 | o.set(offset+j, stack[a + j]); |
478 | } |
479 | } |
480 | continue; |
481 | |
482 | case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx]) */ |
483 | { |
484 | Prototype newp = p.p[i>>>14]; |
485 | LuaClosure ncl = new LuaClosure(newp, globals); |
486 | Upvaldesc[] uv = newp.upvalues; |
487 | for ( int j=0, nup=uv.length; j<nup; ++j ) { |
488 | if (uv[j].instack) /* upvalue refes to local variable? */ |
489 | ncl.upValues[j] = findupval(stack, uv[j].idx, openups); |
490 | else /* get upvalue from enclosing function */ |
491 | ncl.upValues[j] = upValues[uv[j].idx]; |
492 | } |
493 | stack[a] = ncl; |
494 | } |
495 | continue; |
496 | |
497 | case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ |
498 | b = i>>>23; |
499 | if ( b == 0 ) { |
500 | top = a + (b = varargs.narg()); |
501 | v = varargs; |
502 | } else { |
503 | for ( int j=1; j<b; ++j ) |
504 | stack[a+j-1] = varargs.arg(j); |
505 | } |
506 | continue; |
507 | |
508 | case Lua.OP_EXTRAARG: |
509 | throw new java.lang.IllegalArgumentException("Uexecutable opcode: OP_EXTRAARG"); |
510 | |
511 | default: |
512 | throw new java.lang.IllegalArgumentException("Illegal opcode: " + (i & 0x3f)); |
513 | } |
514 | } |
515 | } catch ( LuaError le ) { |
516 | if (le.traceback == null) |
517 | processErrorHooks(le, p, pc); |
518 | throw le; |
519 | } catch ( Exception e ) { |
520 | LuaError le = new LuaError(e); |
521 | processErrorHooks(le, p, pc); |
522 | throw le; |
523 | } finally { |
524 | if ( openups != null ) |
525 | for ( int u=openups.length; --u>=0; ) |
526 | if ( openups[u] != null ) |
527 | openups[u].close(); |
528 | if (globals != null && globals.debuglib != null) |
529 | globals.debuglib.onReturn(); |
530 | } |
531 | } |
532 | |
533 | /** |
534 | * Run the error hook if there is one |
535 | * @param msg the message to use in error hook processing. |
536 | * */ |
537 | String errorHook(String msg) { |
538 | if (globals == null || globals.errorfunc == null) |
539 | return msg; |
540 | LuaValue errfunc = globals.errorfunc; |
541 | globals.errorfunc = null; |
542 | try { |
543 | return errfunc.call( LuaValue.valueOf(msg) ).tojstring(); |
544 | } catch ( Throwable t ) { |
545 | return "error in error handling"; |
546 | } finally { |
547 | globals.errorfunc = errfunc; |
548 | } |
549 | } |
550 | |
551 | private void processErrorHooks(LuaError le, Prototype p, int pc) { |
552 | le.fileline = (p.source != null? p.source.tojstring(): "?") + ":" |
553 | + (p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length? String.valueOf(p.lineinfo[pc]): "?"); |
554 | le.traceback = errorHook(le.getMessage()); |
555 | if (globals != null && globals.debuglib != null) |
556 | le.traceback = le.traceback + "\n" + globals.debuglib.traceback(le.level); |
557 | } |
558 | |
559 | private UpValue findupval(LuaValue[] stack, short idx, UpValue[] openups) { |
560 | final int n = openups.length; |
561 | for (int i = 0; i < n; ++i) |
562 | if (openups[i] != null && openups[i].index == idx) |
563 | return openups[i]; |
564 | for (int i = 0; i < n; ++i) |
565 | if (openups[i] == null) |
566 | return openups[i] = new UpValue(stack, idx); |
567 | this.error("No space for upvalue"); |
568 | return null; |
569 | } |
570 | |
571 | protected LuaValue getUpvalue(int i) { |
572 | return upValues[i].getValue(); |
573 | } |
574 | |
575 | protected void setUpvalue(int i, LuaValue v) { |
576 | upValues[i].setValue(v); |
577 | } |
578 | |
579 | public String name() { |
580 | return "<"+p.shortsource()+":"+p.linedefined+">"; |
581 | } |
582 | |
583 | public void setGlobals(Globals globals) { |
584 | this.globals = globals; |
585 | } |
586 | |
587 | public Globals getGlobals() { |
588 | return globals; |
589 | } |
590 | } |
Current version from TinyBrain sources.
Travelled to 12 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1000249 |
Snippet name: | LuaClosure.java |
Eternal ID of this version: | #1000249/1 |
Text MD5: | 8a1f2b3b0bacc838ddd536e86e4df7c5 |
Author: | stefan |
Category: | |
Type: | Java source code |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2015-04-05 18:24:16 |
Source code size: | 21488 bytes / 590 lines |
Pitched / IR pitched: | No / Yes |
Views / Downloads: | 635 / 132 |
Referenced in: | [show references] |