Processor_InstructionLoop.cs 36 KB

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