| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using MoonSharp.Interpreter.DataStructs;
- using MoonSharp.Interpreter.Debugging;
- using MoonSharp.Interpreter.Interop;
- namespace MoonSharp.Interpreter.Execution.VM
- {
- sealed partial class Processor
- {
- const int YIELD_SPECIAL_TRAP = -99;
- internal long AutoYieldCounter = 0;
- private DynValue Processing_Loop(int instructionPtr)
- {
- // This is the main loop of the processor, has a weird control flow and needs to be as fast as possible.
- // This sentence is just a convoluted way to say "don't complain about gotos".
- long executedInstructions = 0;
- bool canAutoYield = (AutoYieldCounter > 0) && m_CanYield && (this.State != CoroutineState.Main);
- repeat_execution:
- try
- {
- while (true)
- {
- Instruction i = m_RootChunk.Code[instructionPtr];
- if (m_Debug.DebuggerAttached != null)
- {
- ListenDebugger(i, instructionPtr);
- }
- ++executedInstructions;
- if (canAutoYield && executedInstructions > AutoYieldCounter)
- {
- m_SavedInstructionPtr = instructionPtr;
- return DynValue.NewForcedYieldReq();
- }
- ++instructionPtr;
- switch (i.OpCode)
- {
- case OpCode.Nop:
- case OpCode.Debug:
- case OpCode.Meta:
- break;
- case OpCode.Pop:
- m_ValueStack.RemoveLast(i.NumVal);
- break;
- case OpCode.Copy:
- m_ValueStack.Push(m_ValueStack.Peek(i.NumVal));
- break;
- case OpCode.Swap:
- ExecSwap(i);
- break;
- case OpCode.Literal:
- m_ValueStack.Push(i.Value);
- break;
- case OpCode.Add:
- instructionPtr = ExecAdd(i, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.Concat:
- instructionPtr = ExecConcat(i, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.Neg:
- instructionPtr = ExecNeg(i, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.Sub:
- instructionPtr = ExecSub(i, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.Mul:
- instructionPtr = ExecMul(i, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.Div:
- instructionPtr = ExecDiv(i, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.Mod:
- instructionPtr = ExecMod(i, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.Power:
- instructionPtr = ExecPower(i, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.Eq:
- instructionPtr = ExecEq(i, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.LessEq:
- instructionPtr = ExecLessEq(i, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.Less:
- instructionPtr = ExecLess(i, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.Len:
- instructionPtr = ExecLen(i, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.Call:
- case OpCode.ThisCall:
- instructionPtr = Internal_ExecCall(i.NumVal, instructionPtr, null, null, i.OpCode == OpCode.ThisCall, i.Name);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.Scalar:
- m_ValueStack.Push(m_ValueStack.Pop().ToScalar());
- break;
- case OpCode.Not:
- ExecNot(i);
- break;
- case OpCode.CNot:
- ExecCNot(i);
- break;
- case OpCode.JfOrPop:
- case OpCode.JtOrPop:
- instructionPtr = ExecShortCircuitingOperator(i, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.JNil:
- {
- DynValue v = m_ValueStack.Pop().ToScalar();
- if (v.Type == DataType.Nil || v.Type == DataType.Void)
- instructionPtr = i.NumVal;
- }
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.Jf:
- instructionPtr = JumpBool(i, false, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.Jump:
- instructionPtr = i.NumVal;
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.MkTuple:
- ExecMkTuple(i);
- break;
- case OpCode.Clean:
- ClearBlockData(i);
- break;
- case OpCode.Closure:
- ExecClosure(i);
- break;
- case OpCode.BeginFn:
- ExecBeginFn(i);
- break;
- case OpCode.ToBool:
- m_ValueStack.Push(DynValue.NewBoolean(m_ValueStack.Pop().ToScalar().CastToBool()));
- break;
- case OpCode.Args:
- ExecArgs(i);
- break;
- case OpCode.Ret:
- instructionPtr = ExecRet(i);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- if (instructionPtr < 0)
- goto return_to_native_code;
- break;
- case OpCode.Incr:
- ExecIncr(i);
- break;
- case OpCode.ToNum:
- ExecToNum(i);
- break;
- case OpCode.JFor:
- instructionPtr = ExecJFor(i, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.NewTable:
- if (i.NumVal == 0)
- m_ValueStack.Push(DynValue.NewTable(this.m_Script));
- else
- m_ValueStack.Push(DynValue.NewPrimeTable());
- break;
- case OpCode.IterPrep:
- ExecIterPrep(i);
- break;
- case OpCode.IterUpd:
- ExecIterUpd(i);
- break;
- case OpCode.ExpTuple:
- ExecExpTuple(i);
- break;
- case OpCode.Local:
- var scope = m_ExecutionStack.Peek().LocalScope;
- var index = i.Symbol.i_Index;
- m_ValueStack.Push(scope[index].AsReadOnly());
- break;
- case OpCode.Upvalue:
- m_ValueStack.Push(m_ExecutionStack.Peek().ClosureScope[i.Symbol.i_Index].AsReadOnly());
- break;
- case OpCode.StoreUpv:
- ExecStoreUpv(i);
- break;
- case OpCode.StoreLcl:
- ExecStoreLcl(i);
- break;
- case OpCode.TblInitN:
- ExecTblInitN(i);
- break;
- case OpCode.TblInitI:
- ExecTblInitI(i);
- break;
- case OpCode.Index:
- case OpCode.IndexN:
- case OpCode.IndexL:
- instructionPtr = ExecIndex(i, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.IndexSet:
- case OpCode.IndexSetN:
- case OpCode.IndexSetL:
- instructionPtr = ExecIndexSet(i, instructionPtr);
- if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
- break;
- case OpCode.Invalid:
- throw new NotImplementedException(string.Format("Invalid opcode : {0}", i.Name));
- default:
- throw new NotImplementedException(string.Format("Execution for {0} not implented yet!", i.OpCode));
- }
- }
- yield_to_calling_coroutine:
- DynValue yieldRequest = m_ValueStack.Pop().ToScalar();
- if (m_CanYield)
- return yieldRequest;
- else if (this.State == CoroutineState.Main)
- throw ScriptRuntimeException.CannotYieldMain();
- else
- throw ScriptRuntimeException.CannotYield();
- }
- catch (InterpreterException ex)
- {
- FillDebugData(ex, instructionPtr);
- if (!(ex is ScriptRuntimeException))
- {
- ex.Rethrow();
- throw;
- }
- if (m_Debug.DebuggerAttached != null)
- {
- if (m_Debug.DebuggerAttached.SignalRuntimeException((ScriptRuntimeException)ex))
- {
- if (instructionPtr >= 0 && instructionPtr < this.m_RootChunk.Code.Count)
- {
- ListenDebugger(m_RootChunk.Code[instructionPtr], instructionPtr);
- }
- }
- }
- for (int i = 0; i < m_ExecutionStack.Count; i++)
- {
- var c = m_ExecutionStack.Peek(i);
- if (c.ErrorHandlerBeforeUnwind != null)
- ex.DecoratedMessage = PerformMessageDecorationBeforeUnwind(c.ErrorHandlerBeforeUnwind, ex.DecoratedMessage, GetCurrentSourceRef(instructionPtr));
- }
- while (m_ExecutionStack.Count > 0)
- {
- CallStackItem csi = PopToBasePointer();
- if (csi.ErrorHandler != null)
- {
- instructionPtr = csi.ReturnAddress;
- if (csi.ClrFunction == null)
- {
- var argscnt = (int)(m_ValueStack.Pop().Number);
- m_ValueStack.RemoveLast(argscnt + 1);
- }
- var cbargs = new DynValue[] { DynValue.NewString(ex.DecoratedMessage) };
- DynValue handled = csi.ErrorHandler.Invoke(new ScriptExecutionContext(this, csi.ErrorHandler, GetCurrentSourceRef(instructionPtr)), cbargs);
- m_ValueStack.Push(handled);
- goto repeat_execution;
- }
- else if ((csi.Flags & CallStackItemFlags.EntryPoint) != 0)
- {
- ex.Rethrow();
- throw;
- }
- }
- ex.Rethrow();
- throw;
- }
- return_to_native_code:
- return m_ValueStack.Pop();
- }
- internal string PerformMessageDecorationBeforeUnwind(DynValue messageHandler, string decoratedMessage, SourceRef sourceRef)
- {
- try
- {
- DynValue[] args = new DynValue[] { DynValue.NewString(decoratedMessage) };
- DynValue ret = DynValue.Nil;
- if (messageHandler.Type == DataType.Function)
- {
- ret = this.Call(messageHandler, args);
- }
- else if (messageHandler.Type == DataType.ClrFunction)
- {
- ScriptExecutionContext ctx = new ScriptExecutionContext(this, messageHandler.Callback, sourceRef);
- ret = messageHandler.Callback.Invoke(ctx, args);
- }
- else
- {
- throw new ScriptRuntimeException("error handler not set to a function");
- }
- string newmsg = ret.ToPrintString();
- if (newmsg != null)
- return newmsg;
- }
- catch (ScriptRuntimeException innerEx)
- {
- return innerEx.Message + "\n" + decoratedMessage;
- }
- return decoratedMessage;
- }
- private void AssignLocal(SymbolRef symref, DynValue value)
- {
- var stackframe = m_ExecutionStack.Peek();
- DynValue v = stackframe.LocalScope[symref.i_Index];
- if (v == null)
- stackframe.LocalScope[symref.i_Index] = v = DynValue.NewNil();
- v.Assign(value);
- }
- private void ExecStoreLcl(Instruction i)
- {
- DynValue value = GetStoreValue(i);
- SymbolRef symref = i.Symbol;
- AssignLocal(symref, value);
- }
- private void ExecStoreUpv(Instruction i)
- {
- DynValue value = GetStoreValue(i);
- SymbolRef symref = i.Symbol;
- var stackframe = m_ExecutionStack.Peek();
- DynValue v = stackframe.ClosureScope[symref.i_Index];
- if (v == null)
- stackframe.ClosureScope[symref.i_Index] = v = DynValue.NewNil();
- v.Assign(value);
- }
- private void ExecSwap(Instruction i)
- {
- DynValue v1 = m_ValueStack.Peek(i.NumVal);
- DynValue v2 = m_ValueStack.Peek(i.NumVal2);
- m_ValueStack.Set(i.NumVal, v2);
- m_ValueStack.Set(i.NumVal2, v1);
- }
- private DynValue GetStoreValue(Instruction i)
- {
- int stackofs = i.NumVal;
- int tupleidx = i.NumVal2;
- DynValue v = m_ValueStack.Peek(stackofs);
- if (v.Type == DataType.Tuple)
- {
- return (tupleidx < v.Tuple.Length) ? v.Tuple[tupleidx] : DynValue.NewNil();
- }
- else
- {
- return (tupleidx == 0) ? v : DynValue.NewNil();
- }
- }
- private void ExecClosure(Instruction i)
- {
- Closure c = new Closure(this.m_Script, i.NumVal, i.SymbolList,
- i.SymbolList.Select(s => this.GetUpvalueSymbol(s)).ToList());
- m_ValueStack.Push(DynValue.NewClosure(c));
- }
- private DynValue GetUpvalueSymbol(SymbolRef s)
- {
- if (s.Type == SymbolRefType.Local)
- return m_ExecutionStack.Peek().LocalScope[s.i_Index];
- else if (s.Type == SymbolRefType.Upvalue)
- return m_ExecutionStack.Peek().ClosureScope[s.i_Index];
- else
- throw new Exception("unsupported symbol type");
- }
- private void ExecMkTuple(Instruction i)
- {
- Slice<DynValue> slice = new Slice<DynValue>(m_ValueStack, m_ValueStack.Count - i.NumVal, i.NumVal, false);
- var v = Internal_AdjustTuple(slice);
- m_ValueStack.RemoveLast(i.NumVal);
- m_ValueStack.Push(DynValue.NewTuple(v));
- }
- private void ExecToNum(Instruction i)
- {
- double? v = m_ValueStack.Pop().ToScalar().CastToNumber();
- if (v.HasValue)
- m_ValueStack.Push(DynValue.NewNumber(v.Value));
- else
- throw ScriptRuntimeException.ConvertToNumberFailed(i.NumVal);
- }
- private void ExecIterUpd(Instruction i)
- {
- DynValue v = m_ValueStack.Peek(0);
- DynValue t = m_ValueStack.Peek(1);
- t.Tuple[2] = v;
- }
- private void ExecExpTuple(Instruction i)
- {
- DynValue t = m_ValueStack.Peek(i.NumVal);
- if (t.Type == DataType.Tuple)
- {
- for (int idx = 0; idx < t.Tuple.Length; idx++)
- m_ValueStack.Push(t.Tuple[idx]);
- }
- else
- {
- m_ValueStack.Push(t);
- }
- }
- private void ExecIterPrep(Instruction i)
- {
- DynValue v = m_ValueStack.Pop();
- if (v.Type != DataType.Tuple)
- {
- v = DynValue.NewTuple(v, DynValue.Nil, DynValue.Nil);
- }
- DynValue f = v.Tuple.Length >= 1 ? v.Tuple[0] : DynValue.Nil;
- DynValue s = v.Tuple.Length >= 2 ? v.Tuple[1] : DynValue.Nil;
- DynValue var = v.Tuple.Length >= 3 ? v.Tuple[2] : DynValue.Nil;
- // MoonSharp additions - given f, s, var
- // 1) if f is not a function and has a __iterator metamethod, call __iterator to get the triplet
- // 2) if f is a table with no __call metamethod, use a default table iterator
- if (f.Type != DataType.Function && f.Type != DataType.ClrFunction)
- {
- DynValue meta = this.GetMetamethod(f, "__iterator");
- if (meta != null && !meta.IsNil())
- {
- if (meta.Type != DataType.Tuple)
- v = this.GetScript().Call(meta, f, s, var);
- else
- v = meta;
- f = v.Tuple.Length >= 1 ? v.Tuple[0] : DynValue.Nil;
- s = v.Tuple.Length >= 2 ? v.Tuple[1] : DynValue.Nil;
- var = v.Tuple.Length >= 3 ? v.Tuple[2] : DynValue.Nil;
- m_ValueStack.Push(DynValue.NewTuple(f, s, var));
- return;
- }
- else if (f.Type == DataType.Table)
- {
- DynValue callmeta = this.GetMetamethod(f, "__call");
- if (callmeta == null || callmeta.IsNil())
- {
- m_ValueStack.Push(EnumerableWrapper.ConvertTable(f.Table));
- return;
- }
- }
- }
- m_ValueStack.Push(DynValue.NewTuple(f, s, var));
- }
- private int ExecJFor(Instruction i, int instructionPtr)
- {
- double val = m_ValueStack.Peek(0).Number;
- double step = m_ValueStack.Peek(1).Number;
- double stop = m_ValueStack.Peek(2).Number;
- bool whileCond = (step > 0) ? val <= stop : val >= stop;
- if (!whileCond)
- return i.NumVal;
- else
- return instructionPtr;
- }
- private void ExecIncr(Instruction i)
- {
- DynValue top = m_ValueStack.Peek(0);
- DynValue btm = m_ValueStack.Peek(i.NumVal);
- if (top.ReadOnly)
- {
- m_ValueStack.Pop();
- if (top.ReadOnly)
- top = top.CloneAsWritable();
- m_ValueStack.Push(top);
- }
- top.AssignNumber(top.Number + btm.Number);
- }
- private void ExecCNot(Instruction i)
- {
- DynValue v = m_ValueStack.Pop().ToScalar();
- DynValue not = m_ValueStack.Pop().ToScalar();
- if (not.Type != DataType.Boolean)
- throw new InternalErrorException("CNOT had non-bool arg");
- if (not.CastToBool())
- m_ValueStack.Push(DynValue.NewBoolean(!(v.CastToBool())));
- else
- m_ValueStack.Push(DynValue.NewBoolean(v.CastToBool()));
- }
- private void ExecNot(Instruction i)
- {
- DynValue v = m_ValueStack.Pop().ToScalar();
- m_ValueStack.Push(DynValue.NewBoolean(!(v.CastToBool())));
- }
- private void ExecBeginFn(Instruction i)
- {
- CallStackItem cur = m_ExecutionStack.Peek();
- cur.Debug_Symbols = i.SymbolList;
- cur.LocalScope = new DynValue[i.NumVal];
- ClearBlockData(i);
- }
- private CallStackItem PopToBasePointer()
- {
- var csi = m_ExecutionStack.Pop();
- if (csi.BasePointer >= 0)
- m_ValueStack.CropAtCount(csi.BasePointer);
- return csi;
- }
- private int PopExecStackAndCheckVStack(int vstackguard)
- {
- var xs = m_ExecutionStack.Pop();
- if (vstackguard != xs.BasePointer)
- throw new InternalErrorException("StackGuard violation");
- return xs.ReturnAddress;
- }
- private IList<DynValue> CreateArgsListForFunctionCall(int numargs, int offsFromTop)
- {
- if (numargs == 0) return new DynValue[0];
- DynValue lastParam = m_ValueStack.Peek(offsFromTop);
- if (lastParam.Type == DataType.Tuple && lastParam.Tuple.Length > 1)
- {
- List<DynValue> values = new List<DynValue>();
- for (int idx = 0; idx < numargs - 1; idx++)
- values.Add(m_ValueStack.Peek(numargs - idx - 1 + offsFromTop));
- for (int idx = 0; idx < lastParam.Tuple.Length; idx++)
- values.Add(lastParam.Tuple[idx]);
- return values;
- }
- else
- {
- return new Slice<DynValue>(m_ValueStack, m_ValueStack.Count - numargs - offsFromTop, numargs, false);
- }
- }
- private void ExecArgs(Instruction I)
- {
- int numargs = (int)m_ValueStack.Peek(0).Number;
- // unpacks last tuple arguments to simplify a lot of code down under
- var argsList = CreateArgsListForFunctionCall(numargs, 1);
- for (int i = 0; i < I.SymbolList.Length; i++)
- {
- if (i >= argsList.Count)
- {
- this.AssignLocal(I.SymbolList[i], DynValue.NewNil());
- }
- else if ((i == I.SymbolList.Length - 1) && (I.SymbolList[i].i_Name == WellKnownSymbols.VARARGS))
- {
- int len = argsList.Count - i;
- DynValue[] varargs = new DynValue[len];
- for (int ii = 0; ii < len; ii++, i++)
- {
- varargs[ii] = argsList[i].ToScalar().CloneAsWritable();
- }
- this.AssignLocal(I.SymbolList[I.SymbolList.Length - 1], DynValue.NewTuple(Internal_AdjustTuple(varargs)));
- }
- else
- {
- this.AssignLocal(I.SymbolList[i], argsList[i].ToScalar().CloneAsWritable());
- }
- }
- }
- private int Internal_ExecCall(int argsCount, int instructionPtr, CallbackFunction handler = null,
- CallbackFunction continuation = null, bool thisCall = false, string debugText = null, DynValue unwindHandler = null)
- {
- DynValue fn = m_ValueStack.Peek(argsCount);
- CallStackItemFlags flags = (thisCall ? CallStackItemFlags.MethodCall : CallStackItemFlags.None);
- // if TCO threshold reached
- if ((m_ExecutionStack.Count > this.m_Script.Options.TailCallOptimizationThreshold && m_ExecutionStack.Count > 1)
- || (m_ValueStack.Count > this.m_Script.Options.TailCallOptimizationThreshold && m_ValueStack.Count > 1))
- {
- // and the "will-be" return address is valid (we don't want to crash here)
- if (instructionPtr >= 0 && instructionPtr < this.m_RootChunk.Code.Count)
- {
- Instruction I = this.m_RootChunk.Code[instructionPtr];
- // and we are followed *exactly* by a RET 1
- if (I.OpCode == OpCode.Ret && I.NumVal == 1)
- {
- CallStackItem csi = m_ExecutionStack.Peek();
- // if the current stack item has no "odd" things pending and neither has the new coming one..
- if (csi.ClrFunction == null && csi.Continuation == null && csi.ErrorHandler == null
- && csi.ErrorHandlerBeforeUnwind == null && continuation == null && unwindHandler == null && handler == null)
- {
- instructionPtr = PerformTCO(instructionPtr, argsCount);
- flags |= CallStackItemFlags.TailCall;
- }
- }
- }
- }
- if (fn.Type == DataType.ClrFunction)
- {
- //IList<DynValue> args = new Slice<DynValue>(m_ValueStack, m_ValueStack.Count - argsCount, argsCount, false);
- IList<DynValue> args = CreateArgsListForFunctionCall(argsCount, 0);
- // we expand tuples before callbacks
- // args = DynValue.ExpandArgumentsToList(args);
- // instructionPtr - 1: instructionPtr already points to the next instruction at this moment
- // but we need the current instruction here
- SourceRef sref = GetCurrentSourceRef(instructionPtr - 1);
- m_ExecutionStack.Push(new CallStackItem()
- {
- ClrFunction = fn.Callback,
- ReturnAddress = instructionPtr,
- CallingSourceRef = sref,
- BasePointer = -1,
- ErrorHandler = handler,
- Continuation = continuation,
- ErrorHandlerBeforeUnwind = unwindHandler,
- Flags = flags,
- });
- var ret = fn.Callback.Invoke(new ScriptExecutionContext(this, fn.Callback, sref), args, isMethodCall: thisCall);
- m_ValueStack.RemoveLast(argsCount + 1);
- m_ValueStack.Push(ret);
- m_ExecutionStack.Pop();
- return Internal_CheckForTailRequests(null, instructionPtr);
- }
- else if (fn.Type == DataType.Function)
- {
- m_ValueStack.Push(DynValue.NewNumber(argsCount));
- m_ExecutionStack.Push(new CallStackItem()
- {
- BasePointer = m_ValueStack.Count,
- ReturnAddress = instructionPtr,
- Debug_EntryPoint = fn.Function.EntryPointByteCodeLocation,
- CallingSourceRef = GetCurrentSourceRef(instructionPtr - 1), // See right above in GetCurrentSourceRef(instructionPtr - 1)
- ClosureScope = fn.Function.ClosureContext,
- ErrorHandler = handler,
- Continuation = continuation,
- ErrorHandlerBeforeUnwind = unwindHandler,
- Flags = flags,
- });
- return fn.Function.EntryPointByteCodeLocation;
- }
- // fallback to __call metamethod
- var m = GetMetamethod(fn, "__call");
- if (m != null && m.IsNotNil())
- {
- DynValue[] tmp = new DynValue[argsCount + 1];
- for (int i = 0; i < argsCount + 1; i++)
- tmp[i] = m_ValueStack.Pop();
- m_ValueStack.Push(m);
- for (int i = argsCount; i >= 0; i--)
- m_ValueStack.Push(tmp[i]);
- return Internal_ExecCall(argsCount + 1, instructionPtr, handler, continuation);
- }
- throw ScriptRuntimeException.AttemptToCallNonFunc(fn.Type, debugText);
- }
- private int PerformTCO(int instructionPtr, int argsCount)
- {
- DynValue[] args = new DynValue[argsCount + 1];
- // Remove all cur args and func ptr
- for (int i = 0; i <= argsCount; i++)
- args[i] = m_ValueStack.Pop();
- // perform a fake RET
- CallStackItem csi = PopToBasePointer();
- int retpoint = csi.ReturnAddress;
- var argscnt = (int)(m_ValueStack.Pop().Number);
- m_ValueStack.RemoveLast(argscnt + 1);
- // Re-push all cur args and func ptr
- for (int i = argsCount; i >= 0; i--)
- m_ValueStack.Push(args[i]);
- return retpoint;
- }
- private int ExecRet(Instruction i)
- {
- CallStackItem csi;
- int retpoint = 0;
- if (i.NumVal == 0)
- {
- csi = PopToBasePointer();
- retpoint = csi.ReturnAddress;
- var argscnt = (int)(m_ValueStack.Pop().Number);
- m_ValueStack.RemoveLast(argscnt + 1);
- m_ValueStack.Push(DynValue.Void);
- }
- else if (i.NumVal == 1)
- {
- var retval = m_ValueStack.Pop();
- csi = PopToBasePointer();
- retpoint = csi.ReturnAddress;
- var argscnt = (int)(m_ValueStack.Pop().Number);
- m_ValueStack.RemoveLast(argscnt + 1);
- m_ValueStack.Push(retval);
- retpoint = Internal_CheckForTailRequests(i, retpoint);
- }
- else
- {
- throw new InternalErrorException("RET supports only 0 and 1 ret val scenarios");
- }
- if (csi.Continuation != null)
- m_ValueStack.Push(csi.Continuation.Invoke(new ScriptExecutionContext(this, csi.Continuation, i.SourceCodeRef),
- new DynValue[1] { m_ValueStack.Pop() }));
- return retpoint;
- }
- private int Internal_CheckForTailRequests(Instruction i, int instructionPtr)
- {
- DynValue tail = m_ValueStack.Peek(0);
- if (tail.Type == DataType.TailCallRequest)
- {
- m_ValueStack.Pop(); // discard tail call request
- TailCallData tcd = tail.TailCallData;
- m_ValueStack.Push(tcd.Function);
- for (int ii = 0; ii < tcd.Args.Length; ii++)
- m_ValueStack.Push(tcd.Args[ii]);
- return Internal_ExecCall(tcd.Args.Length, instructionPtr, tcd.ErrorHandler, tcd.Continuation, false, null, tcd.ErrorHandlerBeforeUnwind);
- }
- else if (tail.Type == DataType.YieldRequest)
- {
- m_SavedInstructionPtr = instructionPtr;
- return YIELD_SPECIAL_TRAP;
- }
- return instructionPtr;
- }
- private int JumpBool(Instruction i, bool expectedValueForJump, int instructionPtr)
- {
- DynValue op = m_ValueStack.Pop().ToScalar();
- if (op.CastToBool() == expectedValueForJump)
- return i.NumVal;
- return instructionPtr;
- }
- private int ExecShortCircuitingOperator(Instruction i, int instructionPtr)
- {
- bool expectedValToShortCircuit = i.OpCode == OpCode.JtOrPop;
- DynValue op = m_ValueStack.Peek().ToScalar();
- if (op.CastToBool() == expectedValToShortCircuit)
- {
- return i.NumVal;
- }
- else
- {
- m_ValueStack.Pop();
- return instructionPtr;
- }
- }
- private int ExecAdd(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop().ToScalar();
- DynValue l = m_ValueStack.Pop().ToScalar();
- double? rn = r.CastToNumber();
- double? ln = l.CastToNumber();
- if (ln.HasValue && rn.HasValue)
- {
- m_ValueStack.Push(DynValue.NewNumber(ln.Value + rn.Value));
- return instructionPtr;
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__add", instructionPtr);
- if (ip >= 0) return ip;
- else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
- }
- }
- private int ExecSub(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop().ToScalar();
- DynValue l = m_ValueStack.Pop().ToScalar();
- double? rn = r.CastToNumber();
- double? ln = l.CastToNumber();
- if (ln.HasValue && rn.HasValue)
- {
- m_ValueStack.Push(DynValue.NewNumber(ln.Value - rn.Value));
- return instructionPtr;
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__sub", instructionPtr);
- if (ip >= 0) return ip;
- else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
- }
- }
- private int ExecMul(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop().ToScalar();
- DynValue l = m_ValueStack.Pop().ToScalar();
- double? rn = r.CastToNumber();
- double? ln = l.CastToNumber();
- if (ln.HasValue && rn.HasValue)
- {
- m_ValueStack.Push(DynValue.NewNumber(ln.Value * rn.Value));
- return instructionPtr;
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__mul", instructionPtr);
- if (ip >= 0) return ip;
- else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
- }
- }
- private int ExecMod(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop().ToScalar();
- DynValue l = m_ValueStack.Pop().ToScalar();
- double? rn = r.CastToNumber();
- double? ln = l.CastToNumber();
- if (ln.HasValue && rn.HasValue)
- {
- double mod = Math.IEEERemainder(ln.Value, rn.Value);
- if (mod < 0) mod += rn.Value;
- m_ValueStack.Push(DynValue.NewNumber(mod));
- return instructionPtr;
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__mod", instructionPtr);
- if (ip >= 0) return ip;
- else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
- }
- }
- private int ExecDiv(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop().ToScalar();
- DynValue l = m_ValueStack.Pop().ToScalar();
- double? rn = r.CastToNumber();
- double? ln = l.CastToNumber();
- if (ln.HasValue && rn.HasValue)
- {
- m_ValueStack.Push(DynValue.NewNumber(ln.Value / rn.Value));
- return instructionPtr;
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__div", instructionPtr);
- if (ip >= 0) return ip;
- else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
- }
- }
- private int ExecPower(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop().ToScalar();
- DynValue l = m_ValueStack.Pop().ToScalar();
- double? rn = r.CastToNumber();
- double? ln = l.CastToNumber();
- if (ln.HasValue && rn.HasValue)
- {
- m_ValueStack.Push(DynValue.NewNumber(Math.Pow(ln.Value, rn.Value)));
- return instructionPtr;
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__pow", instructionPtr);
- if (ip >= 0) return ip;
- else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
- }
- }
- private int ExecNeg(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop().ToScalar();
- double? rn = r.CastToNumber();
- if (rn.HasValue)
- {
- m_ValueStack.Push(DynValue.NewNumber(-rn.Value));
- return instructionPtr;
- }
- else
- {
- int ip = Internal_InvokeUnaryMetaMethod(r, "__unm", instructionPtr);
- if (ip >= 0) return ip;
- else throw ScriptRuntimeException.ArithmeticOnNonNumber(r);
- }
- }
- private int ExecEq(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop().ToScalar();
- DynValue l = m_ValueStack.Pop().ToScalar();
- // first we do a brute force equals over the references
- if (object.ReferenceEquals(r, l))
- {
- m_ValueStack.Push(DynValue.True);
- return instructionPtr;
- }
- // then if they are userdatas, attempt meta
- if (l.Type == DataType.UserData || r.Type == DataType.UserData)
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__eq", instructionPtr);
- if (ip >= 0) return ip;
- }
- // then if types are different, ret false
- if (r.Type != l.Type)
- {
- if ((l.Type == DataType.Nil && r.Type == DataType.Void) || (l.Type == DataType.Void && r.Type == DataType.Nil))
- m_ValueStack.Push(DynValue.True);
- else
- m_ValueStack.Push(DynValue.False);
- return instructionPtr;
- }
- // then attempt metatables for tables
- if ((l.Type == DataType.Table) && (GetMetatable(l) != null) && (GetMetatable(l) == GetMetatable(r)))
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__eq", instructionPtr);
- if (ip >= 0) return ip;
- }
- // else perform standard comparison
- m_ValueStack.Push(DynValue.NewBoolean(r.Equals(l)));
- return instructionPtr;
- }
- private int ExecLess(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop().ToScalar();
- DynValue l = m_ValueStack.Pop().ToScalar();
- if (l.Type == DataType.Number && r.Type == DataType.Number)
- {
- m_ValueStack.Push(DynValue.NewBoolean(l.Number < r.Number));
- }
- else if (l.Type == DataType.String && r.Type == DataType.String)
- {
- m_ValueStack.Push(DynValue.NewBoolean(l.String.CompareTo(r.String) < 0));
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__lt", instructionPtr);
- if (ip < 0)
- throw ScriptRuntimeException.CompareInvalidType(l, r);
- else
- return ip;
- }
- return instructionPtr;
- }
- private int ExecLessEq(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop().ToScalar();
- DynValue l = m_ValueStack.Pop().ToScalar();
- if (l.Type == DataType.Number && r.Type == DataType.Number)
- {
- m_ValueStack.Push(DynValue.False);
- m_ValueStack.Push(DynValue.NewBoolean(l.Number <= r.Number));
- }
- else if (l.Type == DataType.String && r.Type == DataType.String)
- {
- m_ValueStack.Push(DynValue.False);
- m_ValueStack.Push(DynValue.NewBoolean(l.String.CompareTo(r.String) <= 0));
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__le", instructionPtr, DynValue.False);
- if (ip < 0)
- {
- ip = Internal_InvokeBinaryMetaMethod(r, l, "__lt", instructionPtr, DynValue.True);
- if (ip < 0)
- throw ScriptRuntimeException.CompareInvalidType(l, r);
- else
- return ip;
- }
- else
- return ip;
- }
- return instructionPtr;
- }
- private int ExecLen(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop().ToScalar();
- if (r.Type == DataType.String)
- m_ValueStack.Push(DynValue.NewNumber(r.String.Length));
- else
- {
- int ip = Internal_InvokeUnaryMetaMethod(r, "__len", instructionPtr);
- if (ip >= 0)
- return ip;
- else if (r.Type == DataType.Table)
- m_ValueStack.Push(DynValue.NewNumber(r.Table.Length));
- else throw ScriptRuntimeException.LenOnInvalidType(r);
- }
- return instructionPtr;
- }
- private int ExecConcat(Instruction i, int instructionPtr)
- {
- DynValue r = m_ValueStack.Pop().ToScalar();
- DynValue l = m_ValueStack.Pop().ToScalar();
- string rs = r.CastToString();
- string ls = l.CastToString();
- if (rs != null && ls != null)
- {
- m_ValueStack.Push(DynValue.NewString(ls + rs));
- return instructionPtr;
- }
- else
- {
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__concat", instructionPtr);
- if (ip >= 0) return ip;
- else throw ScriptRuntimeException.ConcatOnNonString(l, r);
- }
- }
- private void ExecTblInitI(Instruction i)
- {
- // stack: tbl - val
- DynValue val = m_ValueStack.Pop();
- DynValue tbl = m_ValueStack.Peek();
- if (tbl.Type != DataType.Table)
- throw new InternalErrorException("Unexpected type in table ctor : {0}", tbl);
- tbl.Table.InitNextArrayKeys(val, i.NumVal != 0);
- }
- private void ExecTblInitN(Instruction i)
- {
- // stack: tbl - key - val
- DynValue val = m_ValueStack.Pop();
- DynValue key = m_ValueStack.Pop();
- DynValue tbl = m_ValueStack.Peek();
- if (tbl.Type != DataType.Table)
- throw new InternalErrorException("Unexpected type in table ctor : {0}", tbl);
- tbl.Table.Set(key, val.ToScalar());
- }
- private int ExecIndexSet(Instruction i, int instructionPtr)
- {
- int nestedMetaOps = 100; // sanity check, to avoid potential infinite loop here
- // stack: vals.. - base - index
- bool isNameIndex = i.OpCode == OpCode.IndexSetN;
- bool isMultiIndex = (i.OpCode == OpCode.IndexSetL);
- DynValue originalIdx = i.Value ?? m_ValueStack.Pop();
- DynValue idx = originalIdx.ToScalar();
- DynValue obj = m_ValueStack.Pop().ToScalar();
- var value = GetStoreValue(i);
- DynValue h = null;
- while (nestedMetaOps > 0)
- {
- --nestedMetaOps;
- if (obj.Type == DataType.Table)
- {
- if (!isMultiIndex)
- {
- if (!obj.Table.Get(idx).IsNil())
- {
- obj.Table.Set(idx, value);
- return instructionPtr;
- }
- }
- h = GetMetamethodRaw(obj, "__newindex");
- if (h == null || h.IsNil())
- {
- if (isMultiIndex) throw new ScriptRuntimeException("cannot multi-index a table. userdata expected");
- obj.Table.Set(idx, value);
- return instructionPtr;
- }
- }
- else if (obj.Type == DataType.UserData)
- {
- UserData ud = obj.UserData;
- if (!ud.Descriptor.SetIndex(this.GetScript(), ud.Object, originalIdx, value, isNameIndex))
- {
- throw ScriptRuntimeException.UserDataMissingField(ud.Descriptor.Name, idx.String);
- }
- return instructionPtr;
- }
- else
- {
- h = GetMetamethodRaw(obj, "__newindex");
- if (h == null || h.IsNil())
- throw ScriptRuntimeException.IndexType(obj);
- }
- if (h.Type == DataType.Function || h.Type == DataType.ClrFunction)
- {
- if (isMultiIndex) throw new ScriptRuntimeException("cannot multi-index through metamethods. userdata expected");
- m_ValueStack.Pop(); // burn extra value ?
- m_ValueStack.Push(h);
- m_ValueStack.Push(obj);
- m_ValueStack.Push(idx);
- m_ValueStack.Push(value);
- return Internal_ExecCall(3, instructionPtr);
- }
- else
- {
- obj = h;
- h = null;
- }
- }
- throw ScriptRuntimeException.LoopInNewIndex();
- }
- private int ExecIndex(Instruction i, int instructionPtr)
- {
- int nestedMetaOps = 100; // sanity check, to avoid potential infinite loop here
- // stack: base - index
- bool isNameIndex = i.OpCode == OpCode.IndexN;
- bool isMultiIndex = (i.OpCode == OpCode.IndexL);
- DynValue originalIdx = i.Value ?? m_ValueStack.Pop();
- DynValue idx = originalIdx.ToScalar();
- DynValue obj = m_ValueStack.Pop().ToScalar();
- DynValue h = null;
- while (nestedMetaOps > 0)
- {
- --nestedMetaOps;
- if (obj.Type == DataType.Table)
- {
- if (!isMultiIndex)
- {
- var v = obj.Table.Get(idx);
- if (!v.IsNil())
- {
- m_ValueStack.Push(v.AsReadOnly());
- return instructionPtr;
- }
- }
- h = GetMetamethodRaw(obj, "__index");
- if (h == null || h.IsNil())
- {
- if (isMultiIndex) throw new ScriptRuntimeException("cannot multi-index a table. userdata expected");
- m_ValueStack.Push(DynValue.Nil);
- return instructionPtr;
- }
- }
- else if (obj.Type == DataType.UserData)
- {
- UserData ud = obj.UserData;
- var v = ud.Descriptor.Index(this.GetScript(), ud.Object, originalIdx, isNameIndex);
- if (v == null)
- {
- throw ScriptRuntimeException.UserDataMissingField(ud.Descriptor.Name, idx.String);
- }
- m_ValueStack.Push(v.AsReadOnly());
- return instructionPtr;
- }
- else
- {
- h = GetMetamethodRaw(obj, "__index");
- if (h == null || h.IsNil())
- throw ScriptRuntimeException.IndexType(obj);
- }
- if (h.Type == DataType.Function || h.Type == DataType.ClrFunction)
- {
- if (isMultiIndex) throw new ScriptRuntimeException("cannot multi-index through metamethods. userdata expected");
- m_ValueStack.Push(h);
- m_ValueStack.Push(obj);
- m_ValueStack.Push(idx);
- return Internal_ExecCall(2, instructionPtr);
- }
- else
- {
- obj = h;
- h = null;
- }
- }
- throw ScriptRuntimeException.LoopInIndex();
- }
- }
- }
|