Processor_InstructionLoop.cs 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using MoonSharp.Interpreter.DataStructs;
  6. using MoonSharp.Interpreter.Debugging;
  7. using MoonSharp.Interpreter.Interop;
  8. namespace MoonSharp.Interpreter.Execution.VM
  9. {
  10. sealed partial class Processor
  11. {
  12. const int YIELD_SPECIAL_TRAP = -99;
  13. private DynValue Processing_Loop(int instructionPtr)
  14. {
  15. // This is the main loop of the processor, has a weird control flow and needs to be as fast as possible.
  16. // This sentence is just a convoluted way to say "don't complain about gotos".
  17. repeat_execution:
  18. try
  19. {
  20. while (true)
  21. {
  22. Instruction i = m_RootChunk.Code[instructionPtr];
  23. if (m_Debug.DebuggerAttached != null)
  24. {
  25. ListenDebugger(i, instructionPtr);
  26. }
  27. ++instructionPtr;
  28. switch (i.OpCode)
  29. {
  30. case OpCode.Nop:
  31. case OpCode.Debug:
  32. break;
  33. case OpCode.Pop:
  34. m_ValueStack.RemoveLast(i.NumVal);
  35. break;
  36. case OpCode.Copy:
  37. m_ValueStack.Push(m_ValueStack.Peek(i.NumVal));
  38. break;
  39. case OpCode.Swap:
  40. ExecSwap(i);
  41. break;
  42. case OpCode.Literal:
  43. m_ValueStack.Push(i.Value);
  44. break;
  45. case OpCode.Add:
  46. instructionPtr = ExecAdd(i, instructionPtr);
  47. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  48. break;
  49. case OpCode.Concat:
  50. instructionPtr = ExecConcat(i, instructionPtr);
  51. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  52. break;
  53. case OpCode.Neg:
  54. instructionPtr = ExecNeg(i, instructionPtr);
  55. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  56. break;
  57. case OpCode.Sub:
  58. instructionPtr = ExecSub(i, instructionPtr);
  59. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  60. break;
  61. case OpCode.Mul:
  62. instructionPtr = ExecMul(i, instructionPtr);
  63. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  64. break;
  65. case OpCode.Div:
  66. instructionPtr = ExecDiv(i, instructionPtr);
  67. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  68. break;
  69. case OpCode.Mod:
  70. instructionPtr = ExecMod(i, instructionPtr);
  71. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  72. break;
  73. case OpCode.Power:
  74. instructionPtr = ExecPower(i, instructionPtr);
  75. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  76. break;
  77. case OpCode.Eq:
  78. instructionPtr = ExecEq(i, instructionPtr);
  79. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  80. break;
  81. case OpCode.LessEq:
  82. instructionPtr = ExecLessEq(i, instructionPtr);
  83. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  84. break;
  85. case OpCode.Less:
  86. instructionPtr = ExecLess(i, instructionPtr);
  87. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  88. break;
  89. case OpCode.Len:
  90. instructionPtr = ExecLen(i, instructionPtr);
  91. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  92. break;
  93. case OpCode.Call:
  94. case OpCode.ThisCall:
  95. instructionPtr = Internal_ExecCall(i.NumVal, instructionPtr, null, null, i.OpCode == OpCode.ThisCall, i.Name);
  96. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  97. break;
  98. case OpCode.Scalar:
  99. m_ValueStack.Push(m_ValueStack.Pop().ToScalar());
  100. break;
  101. case OpCode.Not:
  102. ExecNot(i);
  103. break;
  104. case OpCode.CNot:
  105. ExecCNot(i);
  106. break;
  107. case OpCode.JfOrPop:
  108. case OpCode.JtOrPop:
  109. instructionPtr = ExecShortCircuitingOperator(i, instructionPtr);
  110. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  111. break;
  112. case OpCode.JNil:
  113. {
  114. DynValue v = m_ValueStack.Pop();
  115. if (v.Type == DataType.Nil)
  116. instructionPtr = i.NumVal;
  117. }
  118. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  119. break;
  120. case OpCode.Jf:
  121. instructionPtr = JumpBool(i, false, instructionPtr);
  122. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  123. break;
  124. case OpCode.Jump:
  125. instructionPtr = i.NumVal;
  126. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  127. break;
  128. case OpCode.MkTuple:
  129. ExecMkTuple(i);
  130. break;
  131. case OpCode.Enter:
  132. NilifyBlockData(i);
  133. break;
  134. case OpCode.Leave:
  135. case OpCode.Exit:
  136. ClearBlockData(i);
  137. break;
  138. case OpCode.Closure:
  139. ExecClosure(i);
  140. break;
  141. case OpCode.BeginFn:
  142. ExecBeginFn(i);
  143. break;
  144. case OpCode.ToBool:
  145. m_ValueStack.Push(DynValue.NewBoolean(m_ValueStack.Pop().CastToBool()));
  146. break;
  147. case OpCode.Args:
  148. ExecArgs(i);
  149. break;
  150. case OpCode.Ret:
  151. instructionPtr = ExecRet(i);
  152. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  153. if (instructionPtr < 0)
  154. goto return_to_native_code;
  155. break;
  156. case OpCode.Incr:
  157. ExecIncr(i);
  158. break;
  159. case OpCode.ToNum:
  160. ExecToNum(i);
  161. break;
  162. case OpCode.JFor:
  163. instructionPtr = ExecJFor(i, instructionPtr);
  164. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  165. break;
  166. case OpCode.NewTable:
  167. m_ValueStack.Push(DynValue.NewTable(this.m_Script));
  168. break;
  169. case OpCode.IterPrep:
  170. ExecIterPrep(i);
  171. break;
  172. case OpCode.IterUpd:
  173. ExecIterUpd(i);
  174. break;
  175. case OpCode.ExpTuple:
  176. ExecExpTuple(i);
  177. break;
  178. case OpCode.Local:
  179. m_ValueStack.Push(m_ExecutionStack.Peek().LocalScope[i.Symbol.i_Index].AsReadOnly());
  180. break;
  181. case OpCode.Upvalue:
  182. m_ValueStack.Push(m_ExecutionStack.Peek().ClosureScope[i.Symbol.i_Index].AsReadOnly());
  183. break;
  184. case OpCode.StoreUpv:
  185. ExecStoreUpv(i);
  186. break;
  187. case OpCode.StoreLcl:
  188. ExecStoreLcl(i);
  189. break;
  190. case OpCode.TblInitN:
  191. ExecTblInitN(i);
  192. break;
  193. case OpCode.TblInitI:
  194. ExecTblInitI(i);
  195. break;
  196. case OpCode.Index:
  197. instructionPtr = ExecIndex(i, instructionPtr);
  198. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  199. break;
  200. case OpCode.IndexSet:
  201. instructionPtr = ExecIndexSet(i, instructionPtr);
  202. if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
  203. break;
  204. case OpCode.Invalid:
  205. throw new NotImplementedException(string.Format("Invalid opcode : {0}", i.Name));
  206. default:
  207. throw new NotImplementedException(string.Format("Execution for {0} not implented yet!", i.OpCode));
  208. }
  209. }
  210. yield_to_calling_coroutine:
  211. DynValue yieldRequest = m_ValueStack.Pop();
  212. if (m_CanYield)
  213. return yieldRequest;
  214. else if (this.State == CoroutineState.Main)
  215. throw ScriptRuntimeException.CannotYieldMain();
  216. else
  217. throw ScriptRuntimeException.CannotYield();
  218. }
  219. catch (InterpreterException ex)
  220. {
  221. FillDebugData(ex, instructionPtr);
  222. if (!(ex is ScriptRuntimeException)) throw;
  223. while (m_ExecutionStack.Count > 0)
  224. {
  225. CallStackItem csi = PopToBasePointer();
  226. if (csi.ErrorHandler != null)
  227. {
  228. instructionPtr = csi.ReturnAddress;
  229. var argscnt = (int)(m_ValueStack.Pop().Number);
  230. m_ValueStack.RemoveLast(argscnt + 1);
  231. var cbargs = new DynValue[] { DynValue.NewString(ex.DecoratedMessage) };
  232. DynValue handled = csi.ErrorHandler.Invoke(new ScriptExecutionContext(this, csi.ErrorHandler), cbargs);
  233. m_ValueStack.Push(handled);
  234. goto repeat_execution;
  235. }
  236. }
  237. if (m_ExecutionStack.Count == 0)
  238. {
  239. throw;
  240. }
  241. }
  242. return_to_native_code:
  243. return m_ValueStack.Pop();
  244. }
  245. private void AssignLocal(SymbolRef symref, DynValue value)
  246. {
  247. var stackframe = m_ExecutionStack.Peek();
  248. DynValue v = stackframe.LocalScope[symref.i_Index];
  249. if (v == null)
  250. stackframe.LocalScope[symref.i_Index] = v = DynValue.NewNil();
  251. v.Assign(value);
  252. }
  253. private void ExecStoreLcl(Instruction i)
  254. {
  255. DynValue value = GetStoreValue(i);
  256. SymbolRef symref = i.Symbol;
  257. AssignLocal(symref, value);
  258. }
  259. private void ExecStoreUpv(Instruction i)
  260. {
  261. DynValue value = GetStoreValue(i);
  262. SymbolRef symref = i.Symbol;
  263. var stackframe = m_ExecutionStack.Peek();
  264. DynValue v = stackframe.ClosureScope[symref.i_Index];
  265. if (v == null)
  266. stackframe.ClosureScope[symref.i_Index] = v = DynValue.NewNil();
  267. v.Assign(value);
  268. }
  269. private void ExecSwap(Instruction i)
  270. {
  271. DynValue v1 = m_ValueStack.Peek(i.NumVal);
  272. DynValue v2 = m_ValueStack.Peek(i.NumVal2);
  273. m_ValueStack.Set(i.NumVal, v2);
  274. m_ValueStack.Set(i.NumVal2, v1);
  275. }
  276. private DynValue GetStoreValue(Instruction i)
  277. {
  278. int stackofs = i.NumVal;
  279. int tupleidx = i.NumVal2;
  280. DynValue v = m_ValueStack.Peek(stackofs);
  281. if (v.Type == DataType.Tuple)
  282. {
  283. return (tupleidx < v.Tuple.Length) ? v.Tuple[tupleidx] : DynValue.NewNil();
  284. }
  285. else
  286. {
  287. return (tupleidx == 0) ? v : DynValue.NewNil();
  288. }
  289. }
  290. private void ExecClosure(Instruction i)
  291. {
  292. Closure c = new Closure(this.m_Script, i.NumVal, i.SymbolList,
  293. i.SymbolList.Select(s => this.GetUpvalueSymbol(s)).ToList());
  294. m_ValueStack.Push(DynValue.NewClosure(c));
  295. }
  296. private DynValue GetUpvalueSymbol(SymbolRef s)
  297. {
  298. if (s.Type == SymbolRefType.Local)
  299. return m_ExecutionStack.Peek().LocalScope[s.i_Index];
  300. else if (s.Type == SymbolRefType.Upvalue)
  301. return m_ExecutionStack.Peek().ClosureScope[s.i_Index];
  302. else
  303. throw new Exception("unsupported symbol type");
  304. }
  305. private void ExecMkTuple(Instruction i)
  306. {
  307. Slice<DynValue> slice = new Slice<DynValue>(m_ValueStack, m_ValueStack.Count - i.NumVal, i.NumVal, false);
  308. var v = Internal_AdjustTuple(slice);
  309. m_ValueStack.RemoveLast(i.NumVal);
  310. m_ValueStack.Push(DynValue.NewTuple(v));
  311. }
  312. private void ExecToNum(Instruction i)
  313. {
  314. double? v = m_ValueStack.Pop().CastToNumber();
  315. if (v.HasValue)
  316. m_ValueStack.Push(DynValue.NewNumber(v.Value));
  317. else
  318. throw ScriptRuntimeException.ConvertToNumberFailed(i.NumVal);
  319. }
  320. private void ExecIterUpd(Instruction i)
  321. {
  322. DynValue v = m_ValueStack.Peek(0);
  323. DynValue t = m_ValueStack.Peek(1);
  324. t.Tuple[2] = v;
  325. }
  326. private void ExecExpTuple(Instruction i)
  327. {
  328. DynValue t = m_ValueStack.Peek(i.NumVal);
  329. if (t.Type == DataType.Tuple)
  330. {
  331. for (int idx = 0; idx < t.Tuple.Length; idx++)
  332. m_ValueStack.Push(t.Tuple[idx]);
  333. }
  334. else
  335. {
  336. m_ValueStack.Push(t);
  337. }
  338. }
  339. private void ExecIterPrep(Instruction i)
  340. {
  341. DynValue v = m_ValueStack.Pop();
  342. if (v.Type != DataType.Tuple)
  343. {
  344. v = DynValue.NewTuple(v, DynValue.Nil, DynValue.Nil);
  345. }
  346. DynValue f = v.Tuple.Length >= 1 ? v.Tuple[0] : DynValue.Nil;
  347. DynValue s = v.Tuple.Length >= 2 ? v.Tuple[1] : DynValue.Nil;
  348. DynValue var = v.Tuple.Length >= 3 ? v.Tuple[2] : DynValue.Nil;
  349. // Moon# additions - given f, s, var
  350. // 1) if f is not a function and has a __iterator metamethod, call __iterator to get the triplet
  351. // 2) if f is a table with no __call metamethod, use a default table iterator
  352. if (f.Type != DataType.Function && f.Type != DataType.ClrFunction)
  353. {
  354. DynValue meta = this.GetMetamethod(f, "__iterator");
  355. if (meta != null && !meta.IsNil())
  356. {
  357. v = this.GetScript().Call(meta, f, s, var);
  358. f = v.Tuple.Length >= 1 ? v.Tuple[0] : DynValue.Nil;
  359. s = v.Tuple.Length >= 2 ? v.Tuple[1] : DynValue.Nil;
  360. var = v.Tuple.Length >= 3 ? v.Tuple[2] : DynValue.Nil;
  361. m_ValueStack.Push(DynValue.NewTuple(f, s, var));
  362. }
  363. else if (f.Type == DataType.Table)
  364. {
  365. DynValue callmeta = this.GetMetamethod(f, "__call");
  366. if (callmeta == null || callmeta.IsNil())
  367. {
  368. m_ValueStack.Push(EnumerableWrapper.ConvertTable(f.Table));
  369. }
  370. }
  371. }
  372. m_ValueStack.Push(DynValue.NewTuple(f, s, var));
  373. }
  374. private int ExecJFor(Instruction i, int instructionPtr)
  375. {
  376. double val = m_ValueStack.Peek(0).Number;
  377. double step = m_ValueStack.Peek(1).Number;
  378. double stop = m_ValueStack.Peek(2).Number;
  379. bool whileCond = (step > 0) ? val <= stop : val >= stop;
  380. if (!whileCond)
  381. return i.NumVal;
  382. else
  383. return instructionPtr;
  384. }
  385. private void ExecIncr(Instruction i)
  386. {
  387. DynValue top = m_ValueStack.Peek(0);
  388. DynValue btm = m_ValueStack.Peek(i.NumVal);
  389. if (top.ReadOnly)
  390. {
  391. m_ValueStack.Pop();
  392. if (top.ReadOnly)
  393. top = top.CloneAsWritable();
  394. m_ValueStack.Push(top);
  395. }
  396. top.AssignNumber(top.Number + btm.Number);
  397. }
  398. private void ExecCNot(Instruction i)
  399. {
  400. DynValue v = m_ValueStack.Pop();
  401. DynValue not = m_ValueStack.Pop();
  402. if (not.Type != DataType.Boolean)
  403. throw new InternalErrorException("CNOT had non-bool arg");
  404. if (not.CastToBool())
  405. m_ValueStack.Push(DynValue.NewBoolean(!(v.CastToBool())));
  406. else
  407. m_ValueStack.Push(DynValue.NewBoolean(v.CastToBool()));
  408. }
  409. private void ExecNot(Instruction i)
  410. {
  411. DynValue v = m_ValueStack.Pop();
  412. m_ValueStack.Push(DynValue.NewBoolean(!(v.CastToBool())));
  413. }
  414. private void ExecBeginFn(Instruction i)
  415. {
  416. CallStackItem c = m_ExecutionStack.Peek();
  417. c.Debug_Symbols = i.SymbolList;
  418. c.LocalScope = new DynValue[i.NumVal];
  419. if (i.NumVal2 >= 0 && i.NumVal > 0)
  420. {
  421. for (int idx = 0; idx < i.NumVal2; idx++)
  422. {
  423. c.LocalScope[idx] = DynValue.NewNil();
  424. }
  425. }
  426. }
  427. private CallStackItem PopToBasePointer()
  428. {
  429. var csi = m_ExecutionStack.Pop();
  430. m_ValueStack.CropAtCount(csi.BasePointer);
  431. return csi;
  432. }
  433. private int PopExecStackAndCheckVStack(int vstackguard)
  434. {
  435. var xs = m_ExecutionStack.Pop();
  436. if (vstackguard != xs.BasePointer)
  437. throw new InternalErrorException("StackGuard violation");
  438. return xs.ReturnAddress;
  439. }
  440. private void ExecArgs(Instruction I)
  441. {
  442. int numargs = (int)m_ValueStack.Peek(0).Number;
  443. for (int i = 0; i < I.SymbolList.Length; i++)
  444. {
  445. if (i >= numargs)
  446. {
  447. this.AssignLocal(I.SymbolList[i], DynValue.NewNil());
  448. }
  449. else if ((i == I.SymbolList.Length - 1) && (I.SymbolList[i].i_Name == WellKnownSymbols.VARARGS))
  450. {
  451. int len = numargs - i;
  452. DynValue[] varargs = new DynValue[len];
  453. for (int ii = 0; ii < len; ii++)
  454. {
  455. varargs[ii] = m_ValueStack.Peek(numargs - i - ii).CloneAsWritable();
  456. }
  457. this.AssignLocal(I.SymbolList[i], DynValue.NewTuple(varargs));
  458. }
  459. else
  460. {
  461. this.AssignLocal(I.SymbolList[i], m_ValueStack.Peek(numargs - i).CloneAsWritable());
  462. }
  463. }
  464. }
  465. private int Internal_ExecCall(int argsCount, int instructionPtr, CallbackFunction handler = null, CallbackFunction continuation = null, bool thisCall = false, string debugText = null)
  466. {
  467. DynValue fn = m_ValueStack.Peek(argsCount);
  468. if (fn.Type == DataType.ClrFunction)
  469. {
  470. IList<DynValue> args = new Slice<DynValue>(m_ValueStack, m_ValueStack.Count - argsCount, argsCount, false);
  471. // we expand tuples before callbacks
  472. if (args.Any(v => v.Type == DataType.Tuple))
  473. {
  474. args = DynValue.ExpandArgumentsToList(args);
  475. }
  476. var ret = fn.Callback.Invoke(new ScriptExecutionContext(this, fn.Callback), args, isMethodCall:thisCall);
  477. m_ValueStack.RemoveLast(argsCount + 1);
  478. m_ValueStack.Push(ret);
  479. return Internal_CheckForTailRequests(null, instructionPtr);
  480. }
  481. else if (fn.Type == DataType.Function)
  482. {
  483. m_ValueStack.Push(DynValue.NewNumber(argsCount));
  484. m_ExecutionStack.Push(new CallStackItem()
  485. {
  486. BasePointer = m_ValueStack.Count,
  487. ReturnAddress = instructionPtr,
  488. Debug_EntryPoint = fn.Function.EntryPointByteCodeLocation,
  489. ClosureScope = fn.Function.ClosureContext,
  490. ErrorHandler = handler,
  491. Continuation = continuation
  492. });
  493. return fn.Function.EntryPointByteCodeLocation;
  494. }
  495. else
  496. {
  497. var metatable = GetMetatable(fn);
  498. if (metatable != null)
  499. {
  500. var m = metatable.RawGet("__call");
  501. if (m != null && m.Type != DataType.Nil)
  502. {
  503. DynValue[] tmp = new DynValue[argsCount + 1];
  504. for (int i = 0; i < argsCount + 1; i++)
  505. tmp[i] = m_ValueStack.Pop();
  506. m_ValueStack.Push(m);
  507. for (int i = argsCount; i >= 0; i--)
  508. m_ValueStack.Push(tmp[i]);
  509. return Internal_ExecCall(argsCount + 1, instructionPtr, handler, continuation);
  510. }
  511. }
  512. if (debugText != null)
  513. throw new ScriptRuntimeException("attempt to call a {0} value near '{1}'", fn.ToString(), debugText);
  514. else
  515. throw new ScriptRuntimeException("attempt to call a {0} value", fn.ToString());
  516. }
  517. }
  518. private int ExecRet(Instruction i)
  519. {
  520. CallStackItem csi;
  521. int retpoint = 0;
  522. if (i.NumVal == 0)
  523. {
  524. csi = PopToBasePointer();
  525. retpoint = csi.ReturnAddress;
  526. var argscnt = (int)(m_ValueStack.Pop().Number);
  527. m_ValueStack.RemoveLast(argscnt + 1);
  528. m_ValueStack.Push(DynValue.Nil);
  529. }
  530. else if (i.NumVal == 1)
  531. {
  532. var retval = m_ValueStack.Pop();
  533. csi = PopToBasePointer();
  534. retpoint = csi.ReturnAddress;
  535. var argscnt = (int)(m_ValueStack.Pop().Number);
  536. m_ValueStack.RemoveLast(argscnt + 1);
  537. m_ValueStack.Push(retval);
  538. retpoint = Internal_CheckForTailRequests(i, retpoint);
  539. }
  540. else
  541. {
  542. throw new InternalErrorException("RET supports only 0 and 1 ret val scenarios");
  543. }
  544. if (csi.Continuation != null)
  545. m_ValueStack.Push(csi.Continuation.Invoke(new ScriptExecutionContext(this, csi.Continuation),
  546. new DynValue[1] { m_ValueStack.Pop() }));
  547. return retpoint;
  548. }
  549. private int Internal_CheckForTailRequests(Instruction i, int instructionPtr)
  550. {
  551. DynValue tail = m_ValueStack.Peek(0);
  552. if (tail.Type == DataType.TailCallRequest)
  553. {
  554. m_ValueStack.Pop(); // discard tail call request
  555. TailCallData tcd = tail.TailCallData;
  556. m_ValueStack.Push(tcd.Function);
  557. for (int ii = 0; ii < tcd.Args.Length; ii++)
  558. m_ValueStack.Push(tcd.Args[ii]);
  559. return Internal_ExecCall(tcd.Args.Length, instructionPtr, tcd.ErrorHandler, tcd.Continuation);
  560. }
  561. else if (tail.Type == DataType.YieldRequest)
  562. {
  563. m_SavedInstructionPtr = instructionPtr;
  564. return YIELD_SPECIAL_TRAP;
  565. }
  566. return instructionPtr;
  567. }
  568. private int JumpBool(Instruction i, bool expectedValueForJump, int instructionPtr)
  569. {
  570. DynValue op = m_ValueStack.Pop();
  571. if (op.CastToBool() == expectedValueForJump)
  572. return i.NumVal;
  573. return instructionPtr;
  574. }
  575. private int ExecShortCircuitingOperator(Instruction i, int instructionPtr)
  576. {
  577. bool expectedValToShortCircuit = i.OpCode == OpCode.JtOrPop;
  578. DynValue op = m_ValueStack.Peek();
  579. if (op.CastToBool() == expectedValToShortCircuit)
  580. {
  581. return i.NumVal;
  582. }
  583. else
  584. {
  585. m_ValueStack.Pop();
  586. return instructionPtr;
  587. }
  588. }
  589. private int ExecAdd(Instruction i, int instructionPtr)
  590. {
  591. DynValue r = m_ValueStack.Pop();
  592. DynValue l = m_ValueStack.Pop();
  593. double? rn = r.CastToNumber();
  594. double? ln = l.CastToNumber();
  595. if (ln.HasValue && rn.HasValue)
  596. {
  597. m_ValueStack.Push(DynValue.NewNumber(ln.Value + rn.Value));
  598. return instructionPtr;
  599. }
  600. else
  601. {
  602. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__add", instructionPtr);
  603. if (ip >= 0) return ip;
  604. else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
  605. }
  606. }
  607. private int ExecSub(Instruction i, int instructionPtr)
  608. {
  609. DynValue r = m_ValueStack.Pop();
  610. DynValue l = m_ValueStack.Pop();
  611. double? rn = r.CastToNumber();
  612. double? ln = l.CastToNumber();
  613. if (ln.HasValue && rn.HasValue)
  614. {
  615. m_ValueStack.Push(DynValue.NewNumber(ln.Value - rn.Value));
  616. return instructionPtr;
  617. }
  618. else
  619. {
  620. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__sub", instructionPtr);
  621. if (ip >= 0) return ip;
  622. else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
  623. }
  624. }
  625. private int ExecMul(Instruction i, int instructionPtr)
  626. {
  627. DynValue r = m_ValueStack.Pop();
  628. DynValue l = m_ValueStack.Pop();
  629. double? rn = r.CastToNumber();
  630. double? ln = l.CastToNumber();
  631. if (ln.HasValue && rn.HasValue)
  632. {
  633. m_ValueStack.Push(DynValue.NewNumber(ln.Value * rn.Value));
  634. return instructionPtr;
  635. }
  636. else
  637. {
  638. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__mul", instructionPtr);
  639. if (ip >= 0) return ip;
  640. else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
  641. }
  642. }
  643. private int ExecMod(Instruction i, int instructionPtr)
  644. {
  645. DynValue r = m_ValueStack.Pop();
  646. DynValue l = m_ValueStack.Pop();
  647. double? rn = r.CastToNumber();
  648. double? ln = l.CastToNumber();
  649. if (ln.HasValue && rn.HasValue)
  650. {
  651. double mod = Math.IEEERemainder(ln.Value, rn.Value);
  652. if (mod < 0) mod += rn.Value;
  653. m_ValueStack.Push(DynValue.NewNumber(mod));
  654. return instructionPtr;
  655. }
  656. else
  657. {
  658. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__div", instructionPtr);
  659. if (ip >= 0) return ip;
  660. else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
  661. }
  662. }
  663. private int ExecDiv(Instruction i, int instructionPtr)
  664. {
  665. DynValue r = m_ValueStack.Pop();
  666. DynValue l = m_ValueStack.Pop();
  667. double? rn = r.CastToNumber();
  668. double? ln = l.CastToNumber();
  669. if (ln.HasValue && rn.HasValue)
  670. {
  671. m_ValueStack.Push(DynValue.NewNumber(ln.Value / rn.Value));
  672. return instructionPtr;
  673. }
  674. else
  675. {
  676. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__div", instructionPtr);
  677. if (ip >= 0) return ip;
  678. else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
  679. }
  680. }
  681. private int ExecPower(Instruction i, int instructionPtr)
  682. {
  683. DynValue r = m_ValueStack.Pop();
  684. DynValue l = m_ValueStack.Pop();
  685. double? rn = r.CastToNumber();
  686. double? ln = l.CastToNumber();
  687. if (ln.HasValue && rn.HasValue)
  688. {
  689. m_ValueStack.Push(DynValue.NewNumber(Math.Pow(ln.Value, rn.Value)));
  690. return instructionPtr;
  691. }
  692. else
  693. {
  694. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__pow", instructionPtr);
  695. if (ip >= 0) return ip;
  696. else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
  697. }
  698. }
  699. private int ExecNeg(Instruction i, int instructionPtr)
  700. {
  701. DynValue r = m_ValueStack.Pop();
  702. double? rn = r.CastToNumber();
  703. if (rn.HasValue)
  704. {
  705. m_ValueStack.Push(DynValue.NewNumber(-rn.Value));
  706. return instructionPtr;
  707. }
  708. else
  709. {
  710. int ip = Internal_InvokeUnaryMetaMethod(r, "__unm", instructionPtr);
  711. if (ip >= 0) return ip;
  712. else throw ScriptRuntimeException.ArithmeticOnNonNumber(r);
  713. }
  714. }
  715. private int ExecEq(Instruction i, int instructionPtr)
  716. {
  717. DynValue r = m_ValueStack.Pop();
  718. DynValue l = m_ValueStack.Pop();
  719. if (object.ReferenceEquals(r, l))
  720. {
  721. m_ValueStack.Push(DynValue.True);
  722. }
  723. else if (r.Type != l.Type)
  724. {
  725. m_ValueStack.Push(DynValue.False);
  726. }
  727. else if ((l.Type == DataType.Table || l.Type == DataType.UserData) && (GetMetatable(l) != null) && (GetMetatable(l) == GetMetatable(r)))
  728. {
  729. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__eq", instructionPtr);
  730. if (ip < 0)
  731. m_ValueStack.Push(DynValue.NewBoolean(r.Equals(l)));
  732. else
  733. return ip;
  734. }
  735. else
  736. {
  737. m_ValueStack.Push(DynValue.NewBoolean(r.Equals(l)));
  738. }
  739. return instructionPtr;
  740. }
  741. private int ExecLess(Instruction i, int instructionPtr)
  742. {
  743. DynValue r = m_ValueStack.Pop();
  744. DynValue l = m_ValueStack.Pop();
  745. if (l.Type == DataType.Number && r.Type == DataType.Number)
  746. {
  747. m_ValueStack.Push(DynValue.NewBoolean(l.Number < r.Number));
  748. }
  749. else if (l.Type == DataType.String && r.Type == DataType.String)
  750. {
  751. m_ValueStack.Push(DynValue.NewBoolean(l.String.CompareTo(r.String) < 0));
  752. }
  753. else
  754. {
  755. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__lt", instructionPtr);
  756. if (ip < 0)
  757. throw ScriptRuntimeException.CompareInvalidType(l, r);
  758. else
  759. return ip;
  760. }
  761. return instructionPtr;
  762. }
  763. private int ExecLessEq(Instruction i, int instructionPtr)
  764. {
  765. DynValue r = m_ValueStack.Pop();
  766. DynValue l = m_ValueStack.Pop();
  767. if (l.Type == DataType.Number && r.Type == DataType.Number)
  768. {
  769. m_ValueStack.Push(DynValue.False);
  770. m_ValueStack.Push(DynValue.NewBoolean(l.Number <= r.Number));
  771. }
  772. else if (l.Type == DataType.String && r.Type == DataType.String)
  773. {
  774. m_ValueStack.Push(DynValue.False);
  775. m_ValueStack.Push(DynValue.NewBoolean(l.String.CompareTo(r.String) <= 0));
  776. }
  777. else
  778. {
  779. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__le", instructionPtr, DynValue.False);
  780. if (ip < 0)
  781. {
  782. ip = Internal_InvokeBinaryMetaMethod(r, l, "__lt", instructionPtr, DynValue.True);
  783. if (ip < 0)
  784. throw ScriptRuntimeException.CompareInvalidType(l, r);
  785. else
  786. return ip;
  787. }
  788. else
  789. return ip;
  790. }
  791. return instructionPtr;
  792. }
  793. private int ExecLen(Instruction i, int instructionPtr)
  794. {
  795. DynValue r = m_ValueStack.Pop();
  796. if (r.Type == DataType.String)
  797. m_ValueStack.Push(DynValue.NewNumber(r.String.Length));
  798. else
  799. {
  800. int ip = Internal_InvokeUnaryMetaMethod(r, "__len", instructionPtr);
  801. if (ip >= 0)
  802. return ip;
  803. else if (r.Type == DataType.Table)
  804. m_ValueStack.Push(DynValue.NewNumber(r.Table.Length));
  805. else throw ScriptRuntimeException.LenOnInvalidType(r);
  806. }
  807. return instructionPtr;
  808. }
  809. private int ExecConcat(Instruction i, int instructionPtr)
  810. {
  811. DynValue r = m_ValueStack.Pop();
  812. DynValue l = m_ValueStack.Pop();
  813. string rs = r.CastToString();
  814. string ls = l.CastToString();
  815. if (rs != null && ls != null)
  816. {
  817. m_ValueStack.Push(DynValue.NewString(ls + rs));
  818. return instructionPtr;
  819. }
  820. else
  821. {
  822. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__concat", instructionPtr);
  823. if (ip >= 0) return ip;
  824. else throw ScriptRuntimeException.ConcatOnNonString(l, r);
  825. }
  826. }
  827. private void ExecTblInitI(Instruction i)
  828. {
  829. // stack: tbl - val
  830. DynValue val = m_ValueStack.Pop();
  831. DynValue tbl = m_ValueStack.Peek();
  832. if (tbl.Type != DataType.Table)
  833. throw new InternalErrorException("Unexpected type in table ctor : {0}", tbl);
  834. tbl.Table.InitNextArrayKeys(val, i.NumVal != 0);
  835. }
  836. private void ExecTblInitN(Instruction i)
  837. {
  838. // stack: tbl - key - val
  839. DynValue val = m_ValueStack.Pop();
  840. DynValue key = m_ValueStack.Pop();
  841. DynValue tbl = m_ValueStack.Peek();
  842. if (tbl.Type != DataType.Table)
  843. throw new InternalErrorException("Unexpected type in table ctor : {0}", tbl);
  844. tbl.Table.Set(key, val.ToScalar());
  845. }
  846. private int ExecIndexSet(Instruction i, int instructionPtr)
  847. {
  848. int nestedMetaOps = 100; // sanity check, to avoid potential infinite loop here
  849. // stack: vals.. - base - index
  850. DynValue idx = i.Value ?? m_ValueStack.Pop();
  851. DynValue obj = m_ValueStack.Pop();
  852. var value = GetStoreValue(i);
  853. DynValue h = null;
  854. while (nestedMetaOps > 0)
  855. {
  856. --nestedMetaOps;
  857. if (obj.Type == DataType.Table)
  858. {
  859. if (!obj.Table.Get(idx).IsNil())
  860. {
  861. obj.Table.Set(idx, value);
  862. return instructionPtr;
  863. }
  864. h = GetMetamethod(obj, "__newindex");
  865. if (h == null || h.IsNil())
  866. {
  867. obj.Table.Set(idx, value);
  868. return instructionPtr;
  869. }
  870. }
  871. else if (obj.Type == DataType.UserData)
  872. {
  873. UserData ud = obj.UserData;
  874. if (idx.Type != DataType.String)
  875. throw ScriptRuntimeException.BadArgument(1, string.Format("userdata<{0}>.__newindex", ud.Descriptor.Name), "string", idx.Type.ToLuaTypeString(), false);
  876. ud.Descriptor.SetIndex(this.GetScript(), ud.Object, idx.String, value);
  877. return instructionPtr;
  878. }
  879. else
  880. {
  881. h = GetMetamethod(obj, "__newindex");
  882. if (h == null || h.IsNil())
  883. throw ScriptRuntimeException.IndexType(obj);
  884. }
  885. if (h.Type == DataType.Function || h.Type == DataType.ClrFunction)
  886. {
  887. m_ValueStack.Push(h);
  888. m_ValueStack.Push(obj);
  889. m_ValueStack.Push(idx);
  890. m_ValueStack.Push(value);
  891. return Internal_ExecCall(3, instructionPtr);
  892. }
  893. else
  894. {
  895. obj = h;
  896. h = null;
  897. }
  898. }
  899. throw ScriptRuntimeException.LoopInNewIndex();
  900. }
  901. private int ExecIndex(Instruction i, int instructionPtr)
  902. {
  903. int nestedMetaOps = 100; // sanity check, to avoid potential infinite loop here
  904. // stack: base - index
  905. DynValue idx = i.Value ?? m_ValueStack.Pop();
  906. DynValue obj = m_ValueStack.Pop();
  907. DynValue h = null;
  908. while (nestedMetaOps > 0)
  909. {
  910. --nestedMetaOps;
  911. if (obj.Type == DataType.Table)
  912. {
  913. var v = obj.Table.Get(idx);
  914. if (!v.IsNil())
  915. {
  916. m_ValueStack.Push(v.AsReadOnly());
  917. return instructionPtr;
  918. }
  919. h = GetMetamethod(obj, "__index");
  920. if (h == null || h.IsNil())
  921. {
  922. m_ValueStack.Push(DynValue.Nil);
  923. return instructionPtr;
  924. }
  925. }
  926. else if (obj.Type == DataType.UserData)
  927. {
  928. UserData ud = obj.UserData;
  929. if (idx.Type != DataType.String)
  930. throw ScriptRuntimeException.BadArgument(1, string.Format("userdata<{0}>.__index", ud.Descriptor.Name), "string", idx.Type.ToLuaTypeString(), false);
  931. var v = ud.Descriptor.Index(this.GetScript(), ud.Object, idx.String);
  932. m_ValueStack.Push(v.AsReadOnly());
  933. return instructionPtr;
  934. }
  935. else
  936. {
  937. h = GetMetamethod(obj, "__index");
  938. if (h == null || h.IsNil())
  939. throw ScriptRuntimeException.IndexType(obj);
  940. }
  941. if (h.Type == DataType.Function || h.Type == DataType.ClrFunction)
  942. {
  943. m_ValueStack.Push(h);
  944. m_ValueStack.Push(obj);
  945. m_ValueStack.Push(idx);
  946. return Internal_ExecCall(2, instructionPtr);
  947. }
  948. else
  949. {
  950. obj = h;
  951. h = null;
  952. }
  953. }
  954. throw ScriptRuntimeException.LoopInIndex();
  955. }
  956. }
  957. }