Processor_InstructionLoop.cs 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237
  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().ToScalar();
  115. if (v.Type == DataType.Nil || v.Type == DataType.Void)
  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().ToScalar().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().ToScalar();
  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. if (m_Debug.DebuggerAttached != null)
  224. {
  225. if (m_Debug.DebuggerAttached.SignalRuntimeException((ScriptRuntimeException)ex))
  226. {
  227. if (instructionPtr >= 0 && instructionPtr < this.m_RootChunk.Code.Count)
  228. {
  229. ListenDebugger(m_RootChunk.Code[instructionPtr], instructionPtr);
  230. }
  231. }
  232. }
  233. for (int i = 0; i < m_ExecutionStack.Count; i++)
  234. {
  235. var c = m_ExecutionStack.Peek(i);
  236. if (c.ErrorHandlerBeforeUnwind != null)
  237. ex.DecoratedMessage = PerformMessageDecorationBeforeUnwind(c.ErrorHandlerBeforeUnwind, ex.DecoratedMessage, GetCurrentSourceRef(instructionPtr));
  238. }
  239. while (m_ExecutionStack.Count > 0)
  240. {
  241. CallStackItem csi = PopToBasePointer();
  242. if (csi.ErrorHandler != null)
  243. {
  244. instructionPtr = csi.ReturnAddress;
  245. if (csi.ClrFunction == null)
  246. {
  247. var argscnt = (int)(m_ValueStack.Pop().Number);
  248. m_ValueStack.RemoveLast(argscnt + 1);
  249. }
  250. var cbargs = new DynValue[] { DynValue.NewString(ex.DecoratedMessage) };
  251. DynValue handled = csi.ErrorHandler.Invoke(new ScriptExecutionContext(this, csi.ErrorHandler, GetCurrentSourceRef(instructionPtr)), cbargs);
  252. m_ValueStack.Push(handled);
  253. goto repeat_execution;
  254. }
  255. }
  256. if (m_ExecutionStack.Count == 0)
  257. {
  258. throw;
  259. }
  260. }
  261. return_to_native_code:
  262. return m_ValueStack.Pop();
  263. }
  264. internal string PerformMessageDecorationBeforeUnwind(DynValue messageHandler, string decoratedMessage, SourceRef sourceRef)
  265. {
  266. try
  267. {
  268. DynValue[] args = new DynValue[] { DynValue.NewString(decoratedMessage) };
  269. DynValue ret = DynValue.Nil;
  270. if (messageHandler.Type == DataType.Function)
  271. {
  272. ret = this.Call(messageHandler, args);
  273. }
  274. else if (messageHandler.Type == DataType.ClrFunction)
  275. {
  276. ScriptExecutionContext ctx = new ScriptExecutionContext(this, messageHandler.Callback, sourceRef);
  277. ret = messageHandler.Callback.Invoke(ctx, args);
  278. }
  279. else
  280. {
  281. throw new ScriptRuntimeException("error handler not set to a function");
  282. }
  283. string newmsg = ret.ToPrintString();
  284. if (newmsg != null)
  285. return newmsg;
  286. }
  287. catch (ScriptRuntimeException innerEx)
  288. {
  289. return innerEx.Message + "\n" + decoratedMessage;
  290. }
  291. return decoratedMessage;
  292. }
  293. private void AssignLocal(SymbolRef symref, DynValue value)
  294. {
  295. var stackframe = m_ExecutionStack.Peek();
  296. DynValue v = stackframe.LocalScope[symref.i_Index];
  297. if (v == null)
  298. stackframe.LocalScope[symref.i_Index] = v = DynValue.NewNil();
  299. v.Assign(value);
  300. }
  301. private void ExecStoreLcl(Instruction i)
  302. {
  303. DynValue value = GetStoreValue(i);
  304. SymbolRef symref = i.Symbol;
  305. AssignLocal(symref, value);
  306. }
  307. private void ExecStoreUpv(Instruction i)
  308. {
  309. DynValue value = GetStoreValue(i);
  310. SymbolRef symref = i.Symbol;
  311. var stackframe = m_ExecutionStack.Peek();
  312. DynValue v = stackframe.ClosureScope[symref.i_Index];
  313. if (v == null)
  314. stackframe.ClosureScope[symref.i_Index] = v = DynValue.NewNil();
  315. v.Assign(value);
  316. }
  317. private void ExecSwap(Instruction i)
  318. {
  319. DynValue v1 = m_ValueStack.Peek(i.NumVal);
  320. DynValue v2 = m_ValueStack.Peek(i.NumVal2);
  321. m_ValueStack.Set(i.NumVal, v2);
  322. m_ValueStack.Set(i.NumVal2, v1);
  323. }
  324. private DynValue GetStoreValue(Instruction i)
  325. {
  326. int stackofs = i.NumVal;
  327. int tupleidx = i.NumVal2;
  328. DynValue v = m_ValueStack.Peek(stackofs);
  329. if (v.Type == DataType.Tuple)
  330. {
  331. return (tupleidx < v.Tuple.Length) ? v.Tuple[tupleidx] : DynValue.NewNil();
  332. }
  333. else
  334. {
  335. return (tupleidx == 0) ? v : DynValue.NewNil();
  336. }
  337. }
  338. private void ExecClosure(Instruction i)
  339. {
  340. Closure c = new Closure(this.m_Script, i.NumVal, i.SymbolList,
  341. i.SymbolList.Select(s => this.GetUpvalueSymbol(s)).ToList());
  342. m_ValueStack.Push(DynValue.NewClosure(c));
  343. }
  344. private DynValue GetUpvalueSymbol(SymbolRef s)
  345. {
  346. if (s.Type == SymbolRefType.Local)
  347. return m_ExecutionStack.Peek().LocalScope[s.i_Index];
  348. else if (s.Type == SymbolRefType.Upvalue)
  349. return m_ExecutionStack.Peek().ClosureScope[s.i_Index];
  350. else
  351. throw new Exception("unsupported symbol type");
  352. }
  353. private void ExecMkTuple(Instruction i)
  354. {
  355. Slice<DynValue> slice = new Slice<DynValue>(m_ValueStack, m_ValueStack.Count - i.NumVal, i.NumVal, false);
  356. var v = Internal_AdjustTuple(slice);
  357. m_ValueStack.RemoveLast(i.NumVal);
  358. m_ValueStack.Push(DynValue.NewTuple(v));
  359. }
  360. private void ExecToNum(Instruction i)
  361. {
  362. double? v = m_ValueStack.Pop().ToScalar().CastToNumber();
  363. if (v.HasValue)
  364. m_ValueStack.Push(DynValue.NewNumber(v.Value));
  365. else
  366. throw ScriptRuntimeException.ConvertToNumberFailed(i.NumVal);
  367. }
  368. private void ExecIterUpd(Instruction i)
  369. {
  370. DynValue v = m_ValueStack.Peek(0);
  371. DynValue t = m_ValueStack.Peek(1);
  372. t.Tuple[2] = v;
  373. }
  374. private void ExecExpTuple(Instruction i)
  375. {
  376. DynValue t = m_ValueStack.Peek(i.NumVal);
  377. if (t.Type == DataType.Tuple)
  378. {
  379. for (int idx = 0; idx < t.Tuple.Length; idx++)
  380. m_ValueStack.Push(t.Tuple[idx]);
  381. }
  382. else
  383. {
  384. m_ValueStack.Push(t);
  385. }
  386. }
  387. private void ExecIterPrep(Instruction i)
  388. {
  389. DynValue v = m_ValueStack.Pop();
  390. if (v.Type != DataType.Tuple)
  391. {
  392. v = DynValue.NewTuple(v, DynValue.Nil, DynValue.Nil);
  393. }
  394. DynValue f = v.Tuple.Length >= 1 ? v.Tuple[0] : DynValue.Nil;
  395. DynValue s = v.Tuple.Length >= 2 ? v.Tuple[1] : DynValue.Nil;
  396. DynValue var = v.Tuple.Length >= 3 ? v.Tuple[2] : DynValue.Nil;
  397. // MoonSharp additions - given f, s, var
  398. // 1) if f is not a function and has a __iterator metamethod, call __iterator to get the triplet
  399. // 2) if f is a table with no __call metamethod, use a default table iterator
  400. if (f.Type != DataType.Function && f.Type != DataType.ClrFunction)
  401. {
  402. DynValue meta = this.GetMetamethod(f, "__iterator");
  403. if (meta != null && !meta.IsNil())
  404. {
  405. v = this.GetScript().Call(meta, f, s, var);
  406. f = v.Tuple.Length >= 1 ? v.Tuple[0] : DynValue.Nil;
  407. s = v.Tuple.Length >= 2 ? v.Tuple[1] : DynValue.Nil;
  408. var = v.Tuple.Length >= 3 ? v.Tuple[2] : DynValue.Nil;
  409. m_ValueStack.Push(DynValue.NewTuple(f, s, var));
  410. }
  411. else if (f.Type == DataType.Table)
  412. {
  413. DynValue callmeta = this.GetMetamethod(f, "__call");
  414. if (callmeta == null || callmeta.IsNil())
  415. {
  416. m_ValueStack.Push(EnumerableWrapper.ConvertTable(f.Table));
  417. }
  418. }
  419. }
  420. m_ValueStack.Push(DynValue.NewTuple(f, s, var));
  421. }
  422. private int ExecJFor(Instruction i, int instructionPtr)
  423. {
  424. double val = m_ValueStack.Peek(0).Number;
  425. double step = m_ValueStack.Peek(1).Number;
  426. double stop = m_ValueStack.Peek(2).Number;
  427. bool whileCond = (step > 0) ? val <= stop : val >= stop;
  428. if (!whileCond)
  429. return i.NumVal;
  430. else
  431. return instructionPtr;
  432. }
  433. private void ExecIncr(Instruction i)
  434. {
  435. DynValue top = m_ValueStack.Peek(0);
  436. DynValue btm = m_ValueStack.Peek(i.NumVal);
  437. if (top.ReadOnly)
  438. {
  439. m_ValueStack.Pop();
  440. if (top.ReadOnly)
  441. top = top.CloneAsWritable();
  442. m_ValueStack.Push(top);
  443. }
  444. top.AssignNumber(top.Number + btm.Number);
  445. }
  446. private void ExecCNot(Instruction i)
  447. {
  448. DynValue v = m_ValueStack.Pop().ToScalar();
  449. DynValue not = m_ValueStack.Pop().ToScalar();
  450. if (not.Type != DataType.Boolean)
  451. throw new InternalErrorException("CNOT had non-bool arg");
  452. if (not.CastToBool())
  453. m_ValueStack.Push(DynValue.NewBoolean(!(v.CastToBool())));
  454. else
  455. m_ValueStack.Push(DynValue.NewBoolean(v.CastToBool()));
  456. }
  457. private void ExecNot(Instruction i)
  458. {
  459. DynValue v = m_ValueStack.Pop().ToScalar();
  460. m_ValueStack.Push(DynValue.NewBoolean(!(v.CastToBool())));
  461. }
  462. private void ExecBeginFn(Instruction i)
  463. {
  464. CallStackItem c = m_ExecutionStack.Peek();
  465. c.Debug_Symbols = i.SymbolList;
  466. c.LocalScope = new DynValue[i.NumVal];
  467. if (i.NumVal2 >= 0 && i.NumVal > 0)
  468. {
  469. for (int idx = 0; idx < i.NumVal2; idx++)
  470. {
  471. c.LocalScope[idx] = DynValue.NewNil();
  472. }
  473. }
  474. }
  475. private CallStackItem PopToBasePointer()
  476. {
  477. var csi = m_ExecutionStack.Pop();
  478. if (csi.BasePointer >= 0)
  479. m_ValueStack.CropAtCount(csi.BasePointer);
  480. return csi;
  481. }
  482. private int PopExecStackAndCheckVStack(int vstackguard)
  483. {
  484. var xs = m_ExecutionStack.Pop();
  485. if (vstackguard != xs.BasePointer)
  486. throw new InternalErrorException("StackGuard violation");
  487. return xs.ReturnAddress;
  488. }
  489. private void ExecArgs(Instruction I)
  490. {
  491. int numargs = (int)m_ValueStack.Peek(0).Number;
  492. for (int i = 0; i < I.SymbolList.Length; i++)
  493. {
  494. if (i >= numargs)
  495. {
  496. this.AssignLocal(I.SymbolList[i], DynValue.NewNil());
  497. }
  498. else if ((i == I.SymbolList.Length - 1) && (I.SymbolList[i].i_Name == WellKnownSymbols.VARARGS))
  499. {
  500. int len = numargs - i;
  501. DynValue[] varargs = new DynValue[len];
  502. for (int ii = 0; ii < len; ii++)
  503. {
  504. varargs[ii] = m_ValueStack.Peek(numargs - i - ii).CloneAsWritable();
  505. }
  506. this.AssignLocal(I.SymbolList[i], DynValue.NewTuple(varargs));
  507. }
  508. else
  509. {
  510. this.AssignLocal(I.SymbolList[i], m_ValueStack.Peek(numargs - i).CloneAsWritable());
  511. }
  512. }
  513. }
  514. private int Internal_ExecCall(int argsCount, int instructionPtr, CallbackFunction handler = null, CallbackFunction continuation = null, bool thisCall = false, string debugText = null, DynValue unwindHandler = null)
  515. {
  516. DynValue fn = m_ValueStack.Peek(argsCount);
  517. if (fn.Type == DataType.ClrFunction)
  518. {
  519. IList<DynValue> args = new Slice<DynValue>(m_ValueStack, m_ValueStack.Count - argsCount, argsCount, false);
  520. // we expand tuples before callbacks
  521. // args = DynValue.ExpandArgumentsToList(args);
  522. SourceRef sref = GetCurrentSourceRef(instructionPtr);
  523. m_ExecutionStack.Push(new CallStackItem()
  524. {
  525. ClrFunction = fn.Callback,
  526. ReturnAddress = instructionPtr,
  527. CallingSourceRef = sref,
  528. BasePointer = -1,
  529. ErrorHandler = handler,
  530. Continuation = continuation,
  531. ErrorHandlerBeforeUnwind = unwindHandler,
  532. });
  533. var ret = fn.Callback.Invoke(new ScriptExecutionContext(this, fn.Callback, sref), args, isMethodCall:thisCall);
  534. m_ValueStack.RemoveLast(argsCount + 1);
  535. m_ValueStack.Push(ret);
  536. m_ExecutionStack.Pop();
  537. return Internal_CheckForTailRequests(null, instructionPtr);
  538. }
  539. else if (fn.Type == DataType.Function)
  540. {
  541. m_ValueStack.Push(DynValue.NewNumber(argsCount));
  542. m_ExecutionStack.Push(new CallStackItem()
  543. {
  544. BasePointer = m_ValueStack.Count,
  545. ReturnAddress = instructionPtr,
  546. Debug_EntryPoint = fn.Function.EntryPointByteCodeLocation,
  547. CallingSourceRef = GetCurrentSourceRef(instructionPtr),
  548. ClosureScope = fn.Function.ClosureContext,
  549. ErrorHandler = handler,
  550. Continuation = continuation,
  551. ErrorHandlerBeforeUnwind = unwindHandler,
  552. });
  553. return fn.Function.EntryPointByteCodeLocation;
  554. }
  555. else
  556. {
  557. var metatable = GetMetatable(fn);
  558. if (metatable != null)
  559. {
  560. var m = metatable.RawGet("__call");
  561. if (m != null && m.IsNotNil())
  562. {
  563. DynValue[] tmp = new DynValue[argsCount + 1];
  564. for (int i = 0; i < argsCount + 1; i++)
  565. tmp[i] = m_ValueStack.Pop();
  566. m_ValueStack.Push(m);
  567. for (int i = argsCount; i >= 0; i--)
  568. m_ValueStack.Push(tmp[i]);
  569. return Internal_ExecCall(argsCount + 1, instructionPtr, handler, continuation);
  570. }
  571. }
  572. throw ScriptRuntimeException.AttemptToCallNonFunc(fn.Type, debugText);
  573. }
  574. }
  575. private int ExecRet(Instruction i)
  576. {
  577. CallStackItem csi;
  578. int retpoint = 0;
  579. if (i.NumVal == 0)
  580. {
  581. csi = PopToBasePointer();
  582. retpoint = csi.ReturnAddress;
  583. var argscnt = (int)(m_ValueStack.Pop().Number);
  584. m_ValueStack.RemoveLast(argscnt + 1);
  585. m_ValueStack.Push(DynValue.Void);
  586. }
  587. else if (i.NumVal == 1)
  588. {
  589. var retval = m_ValueStack.Pop();
  590. csi = PopToBasePointer();
  591. retpoint = csi.ReturnAddress;
  592. var argscnt = (int)(m_ValueStack.Pop().Number);
  593. m_ValueStack.RemoveLast(argscnt + 1);
  594. m_ValueStack.Push(retval);
  595. retpoint = Internal_CheckForTailRequests(i, retpoint);
  596. }
  597. else
  598. {
  599. throw new InternalErrorException("RET supports only 0 and 1 ret val scenarios");
  600. }
  601. if (csi.Continuation != null)
  602. m_ValueStack.Push(csi.Continuation.Invoke(new ScriptExecutionContext(this, csi.Continuation, i.SourceCodeRef),
  603. new DynValue[1] { m_ValueStack.Pop() }));
  604. return retpoint;
  605. }
  606. private int Internal_CheckForTailRequests(Instruction i, int instructionPtr)
  607. {
  608. DynValue tail = m_ValueStack.Peek(0);
  609. if (tail.Type == DataType.TailCallRequest)
  610. {
  611. m_ValueStack.Pop(); // discard tail call request
  612. TailCallData tcd = tail.TailCallData;
  613. m_ValueStack.Push(tcd.Function);
  614. for (int ii = 0; ii < tcd.Args.Length; ii++)
  615. m_ValueStack.Push(tcd.Args[ii]);
  616. return Internal_ExecCall(tcd.Args.Length, instructionPtr, tcd.ErrorHandler, tcd.Continuation, false, null, tcd.ErrorHandlerBeforeUnwind);
  617. }
  618. else if (tail.Type == DataType.YieldRequest)
  619. {
  620. m_SavedInstructionPtr = instructionPtr;
  621. return YIELD_SPECIAL_TRAP;
  622. }
  623. return instructionPtr;
  624. }
  625. private int JumpBool(Instruction i, bool expectedValueForJump, int instructionPtr)
  626. {
  627. DynValue op = m_ValueStack.Pop().ToScalar();
  628. if (op.CastToBool() == expectedValueForJump)
  629. return i.NumVal;
  630. return instructionPtr;
  631. }
  632. private int ExecShortCircuitingOperator(Instruction i, int instructionPtr)
  633. {
  634. bool expectedValToShortCircuit = i.OpCode == OpCode.JtOrPop;
  635. DynValue op = m_ValueStack.Peek().ToScalar();
  636. if (op.CastToBool() == expectedValToShortCircuit)
  637. {
  638. return i.NumVal;
  639. }
  640. else
  641. {
  642. m_ValueStack.Pop();
  643. return instructionPtr;
  644. }
  645. }
  646. private int ExecAdd(Instruction i, int instructionPtr)
  647. {
  648. DynValue r = m_ValueStack.Pop().ToScalar();
  649. DynValue l = m_ValueStack.Pop().ToScalar();
  650. double? rn = r.CastToNumber();
  651. double? ln = l.CastToNumber();
  652. if (ln.HasValue && rn.HasValue)
  653. {
  654. m_ValueStack.Push(DynValue.NewNumber(ln.Value + rn.Value));
  655. return instructionPtr;
  656. }
  657. else
  658. {
  659. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__add", instructionPtr);
  660. if (ip >= 0) return ip;
  661. else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
  662. }
  663. }
  664. private int ExecSub(Instruction i, int instructionPtr)
  665. {
  666. DynValue r = m_ValueStack.Pop().ToScalar();
  667. DynValue l = m_ValueStack.Pop().ToScalar();
  668. double? rn = r.CastToNumber();
  669. double? ln = l.CastToNumber();
  670. if (ln.HasValue && rn.HasValue)
  671. {
  672. m_ValueStack.Push(DynValue.NewNumber(ln.Value - rn.Value));
  673. return instructionPtr;
  674. }
  675. else
  676. {
  677. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__sub", instructionPtr);
  678. if (ip >= 0) return ip;
  679. else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
  680. }
  681. }
  682. private int ExecMul(Instruction i, int instructionPtr)
  683. {
  684. DynValue r = m_ValueStack.Pop().ToScalar();
  685. DynValue l = m_ValueStack.Pop().ToScalar();
  686. double? rn = r.CastToNumber();
  687. double? ln = l.CastToNumber();
  688. if (ln.HasValue && rn.HasValue)
  689. {
  690. m_ValueStack.Push(DynValue.NewNumber(ln.Value * rn.Value));
  691. return instructionPtr;
  692. }
  693. else
  694. {
  695. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__mul", instructionPtr);
  696. if (ip >= 0) return ip;
  697. else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
  698. }
  699. }
  700. private int ExecMod(Instruction i, int instructionPtr)
  701. {
  702. DynValue r = m_ValueStack.Pop().ToScalar();
  703. DynValue l = m_ValueStack.Pop().ToScalar();
  704. double? rn = r.CastToNumber();
  705. double? ln = l.CastToNumber();
  706. if (ln.HasValue && rn.HasValue)
  707. {
  708. double mod = Math.IEEERemainder(ln.Value, rn.Value);
  709. if (mod < 0) mod += rn.Value;
  710. m_ValueStack.Push(DynValue.NewNumber(mod));
  711. return instructionPtr;
  712. }
  713. else
  714. {
  715. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__div", instructionPtr);
  716. if (ip >= 0) return ip;
  717. else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
  718. }
  719. }
  720. private int ExecDiv(Instruction i, int instructionPtr)
  721. {
  722. DynValue r = m_ValueStack.Pop().ToScalar();
  723. DynValue l = m_ValueStack.Pop().ToScalar();
  724. double? rn = r.CastToNumber();
  725. double? ln = l.CastToNumber();
  726. if (ln.HasValue && rn.HasValue)
  727. {
  728. m_ValueStack.Push(DynValue.NewNumber(ln.Value / rn.Value));
  729. return instructionPtr;
  730. }
  731. else
  732. {
  733. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__div", instructionPtr);
  734. if (ip >= 0) return ip;
  735. else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
  736. }
  737. }
  738. private int ExecPower(Instruction i, int instructionPtr)
  739. {
  740. DynValue r = m_ValueStack.Pop().ToScalar();
  741. DynValue l = m_ValueStack.Pop().ToScalar();
  742. double? rn = r.CastToNumber();
  743. double? ln = l.CastToNumber();
  744. if (ln.HasValue && rn.HasValue)
  745. {
  746. m_ValueStack.Push(DynValue.NewNumber(Math.Pow(ln.Value, rn.Value)));
  747. return instructionPtr;
  748. }
  749. else
  750. {
  751. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__pow", instructionPtr);
  752. if (ip >= 0) return ip;
  753. else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
  754. }
  755. }
  756. private int ExecNeg(Instruction i, int instructionPtr)
  757. {
  758. DynValue r = m_ValueStack.Pop().ToScalar();
  759. double? rn = r.CastToNumber();
  760. if (rn.HasValue)
  761. {
  762. m_ValueStack.Push(DynValue.NewNumber(-rn.Value));
  763. return instructionPtr;
  764. }
  765. else
  766. {
  767. int ip = Internal_InvokeUnaryMetaMethod(r, "__unm", instructionPtr);
  768. if (ip >= 0) return ip;
  769. else throw ScriptRuntimeException.ArithmeticOnNonNumber(r);
  770. }
  771. }
  772. private int ExecEq(Instruction i, int instructionPtr)
  773. {
  774. DynValue r = m_ValueStack.Pop().ToScalar();
  775. DynValue l = m_ValueStack.Pop().ToScalar();
  776. if (object.ReferenceEquals(r, l))
  777. {
  778. m_ValueStack.Push(DynValue.True);
  779. }
  780. else if (r.Type != l.Type)
  781. {
  782. if ((l.Type == DataType.Nil && r.Type == DataType.Void)
  783. || (l.Type == DataType.Void && r.Type == DataType.Nil))
  784. m_ValueStack.Push(DynValue.True);
  785. else
  786. m_ValueStack.Push(DynValue.False);
  787. }
  788. else if ((l.Type == DataType.Table || l.Type == DataType.UserData) && (GetMetatable(l) != null) && (GetMetatable(l) == GetMetatable(r)))
  789. {
  790. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__eq", instructionPtr);
  791. if (ip < 0)
  792. m_ValueStack.Push(DynValue.NewBoolean(r.Equals(l)));
  793. else
  794. return ip;
  795. }
  796. else
  797. {
  798. m_ValueStack.Push(DynValue.NewBoolean(r.Equals(l)));
  799. }
  800. return instructionPtr;
  801. }
  802. private int ExecLess(Instruction i, int instructionPtr)
  803. {
  804. DynValue r = m_ValueStack.Pop().ToScalar();
  805. DynValue l = m_ValueStack.Pop().ToScalar();
  806. if (l.Type == DataType.Number && r.Type == DataType.Number)
  807. {
  808. m_ValueStack.Push(DynValue.NewBoolean(l.Number < r.Number));
  809. }
  810. else if (l.Type == DataType.String && r.Type == DataType.String)
  811. {
  812. m_ValueStack.Push(DynValue.NewBoolean(l.String.CompareTo(r.String) < 0));
  813. }
  814. else
  815. {
  816. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__lt", instructionPtr);
  817. if (ip < 0)
  818. throw ScriptRuntimeException.CompareInvalidType(l, r);
  819. else
  820. return ip;
  821. }
  822. return instructionPtr;
  823. }
  824. private int ExecLessEq(Instruction i, int instructionPtr)
  825. {
  826. DynValue r = m_ValueStack.Pop().ToScalar();
  827. DynValue l = m_ValueStack.Pop().ToScalar();
  828. if (l.Type == DataType.Number && r.Type == DataType.Number)
  829. {
  830. m_ValueStack.Push(DynValue.False);
  831. m_ValueStack.Push(DynValue.NewBoolean(l.Number <= r.Number));
  832. }
  833. else if (l.Type == DataType.String && r.Type == DataType.String)
  834. {
  835. m_ValueStack.Push(DynValue.False);
  836. m_ValueStack.Push(DynValue.NewBoolean(l.String.CompareTo(r.String) <= 0));
  837. }
  838. else
  839. {
  840. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__le", instructionPtr, DynValue.False);
  841. if (ip < 0)
  842. {
  843. ip = Internal_InvokeBinaryMetaMethod(r, l, "__lt", instructionPtr, DynValue.True);
  844. if (ip < 0)
  845. throw ScriptRuntimeException.CompareInvalidType(l, r);
  846. else
  847. return ip;
  848. }
  849. else
  850. return ip;
  851. }
  852. return instructionPtr;
  853. }
  854. private int ExecLen(Instruction i, int instructionPtr)
  855. {
  856. DynValue r = m_ValueStack.Pop().ToScalar();
  857. if (r.Type == DataType.String)
  858. m_ValueStack.Push(DynValue.NewNumber(r.String.Length));
  859. else
  860. {
  861. int ip = Internal_InvokeUnaryMetaMethod(r, "__len", instructionPtr);
  862. if (ip >= 0)
  863. return ip;
  864. else if (r.Type == DataType.Table)
  865. m_ValueStack.Push(DynValue.NewNumber(r.Table.Length));
  866. else throw ScriptRuntimeException.LenOnInvalidType(r);
  867. }
  868. return instructionPtr;
  869. }
  870. private int ExecConcat(Instruction i, int instructionPtr)
  871. {
  872. DynValue r = m_ValueStack.Pop().ToScalar();
  873. DynValue l = m_ValueStack.Pop().ToScalar();
  874. string rs = r.CastToString();
  875. string ls = l.CastToString();
  876. if (rs != null && ls != null)
  877. {
  878. m_ValueStack.Push(DynValue.NewString(ls + rs));
  879. return instructionPtr;
  880. }
  881. else
  882. {
  883. int ip = Internal_InvokeBinaryMetaMethod(l, r, "__concat", instructionPtr);
  884. if (ip >= 0) return ip;
  885. else throw ScriptRuntimeException.ConcatOnNonString(l, r);
  886. }
  887. }
  888. private void ExecTblInitI(Instruction i)
  889. {
  890. // stack: tbl - val
  891. DynValue val = m_ValueStack.Pop();
  892. DynValue tbl = m_ValueStack.Peek();
  893. if (tbl.Type != DataType.Table)
  894. throw new InternalErrorException("Unexpected type in table ctor : {0}", tbl);
  895. tbl.Table.InitNextArrayKeys(val, i.NumVal != 0);
  896. }
  897. private void ExecTblInitN(Instruction i)
  898. {
  899. // stack: tbl - key - val
  900. DynValue val = m_ValueStack.Pop();
  901. DynValue key = m_ValueStack.Pop();
  902. DynValue tbl = m_ValueStack.Peek();
  903. if (tbl.Type != DataType.Table)
  904. throw new InternalErrorException("Unexpected type in table ctor : {0}", tbl);
  905. tbl.Table.Set(key, val.ToScalar());
  906. }
  907. private int ExecIndexSet(Instruction i, int instructionPtr)
  908. {
  909. int nestedMetaOps = 100; // sanity check, to avoid potential infinite loop here
  910. // stack: vals.. - base - index
  911. DynValue idx = i.Value ?? m_ValueStack.Pop().ToScalar();
  912. DynValue obj = m_ValueStack.Pop().ToScalar();
  913. var value = GetStoreValue(i);
  914. DynValue h = null;
  915. while (nestedMetaOps > 0)
  916. {
  917. --nestedMetaOps;
  918. if (obj.Type == DataType.Table)
  919. {
  920. if (!obj.Table.Get(idx).IsNil())
  921. {
  922. obj.Table.Set(idx, value);
  923. return instructionPtr;
  924. }
  925. h = GetMetamethod(obj, "__newindex");
  926. if (h == null || h.IsNil())
  927. {
  928. obj.Table.Set(idx, value);
  929. return instructionPtr;
  930. }
  931. }
  932. else if (obj.Type == DataType.UserData)
  933. {
  934. UserData ud = obj.UserData;
  935. if (idx.Type != DataType.String)
  936. throw ScriptRuntimeException.BadArgument(1, string.Format("userdata<{0}>.__newindex", ud.Descriptor.Name), "string", idx.Type.ToLuaTypeString(), false);
  937. ud.Descriptor.SetIndex(this.GetScript(), ud.Object, idx.String, value);
  938. return instructionPtr;
  939. }
  940. else
  941. {
  942. h = GetMetamethod(obj, "__newindex");
  943. if (h == null || h.IsNil())
  944. throw ScriptRuntimeException.IndexType(obj);
  945. }
  946. if (h.Type == DataType.Function || h.Type == DataType.ClrFunction)
  947. {
  948. m_ValueStack.Push(h);
  949. m_ValueStack.Push(obj);
  950. m_ValueStack.Push(idx);
  951. m_ValueStack.Push(value);
  952. return Internal_ExecCall(3, instructionPtr);
  953. }
  954. else
  955. {
  956. obj = h;
  957. h = null;
  958. }
  959. }
  960. throw ScriptRuntimeException.LoopInNewIndex();
  961. }
  962. private int ExecIndex(Instruction i, int instructionPtr)
  963. {
  964. int nestedMetaOps = 100; // sanity check, to avoid potential infinite loop here
  965. // stack: base - index
  966. DynValue idx = i.Value ?? m_ValueStack.Pop().ToScalar();
  967. DynValue obj = m_ValueStack.Pop().ToScalar();
  968. DynValue h = null;
  969. while (nestedMetaOps > 0)
  970. {
  971. --nestedMetaOps;
  972. if (obj.Type == DataType.Table)
  973. {
  974. var v = obj.Table.Get(idx);
  975. if (!v.IsNil())
  976. {
  977. m_ValueStack.Push(v.AsReadOnly());
  978. return instructionPtr;
  979. }
  980. h = GetMetamethod(obj, "__index");
  981. if (h == null || h.IsNil())
  982. {
  983. m_ValueStack.Push(DynValue.Nil);
  984. return instructionPtr;
  985. }
  986. }
  987. else if (obj.Type == DataType.UserData)
  988. {
  989. UserData ud = obj.UserData;
  990. if (idx.Type != DataType.String)
  991. throw ScriptRuntimeException.BadArgument(1, string.Format("userdata<{0}>.__index", ud.Descriptor.Name), "string", idx.Type.ToLuaTypeString(), false);
  992. var v = ud.Descriptor.Index(this.GetScript(), ud.Object, idx.String);
  993. m_ValueStack.Push(v.AsReadOnly());
  994. return instructionPtr;
  995. }
  996. else
  997. {
  998. h = GetMetamethod(obj, "__index");
  999. if (h == null || h.IsNil())
  1000. throw ScriptRuntimeException.IndexType(obj);
  1001. }
  1002. if (h.Type == DataType.Function || h.Type == DataType.ClrFunction)
  1003. {
  1004. m_ValueStack.Push(h);
  1005. m_ValueStack.Push(obj);
  1006. m_ValueStack.Push(idx);
  1007. return Internal_ExecCall(2, instructionPtr);
  1008. }
  1009. else
  1010. {
  1011. obj = h;
  1012. h = null;
  1013. }
  1014. }
  1015. throw ScriptRuntimeException.LoopInIndex();
  1016. }
  1017. }
  1018. }