//[MethodImpl(MethodImplOptions.AggressiveInlining)] private void DoIterPrep(StackFrame frame, uint iterVar, bool hasStep) { // step, limit, init -> iter (iterVar = init to limit by step) var step = hasStep ? frame.Pop().As(this, LayeInt.TYPE) as LayeInt : null; var limit = frame.Pop().As(this, LayeInt.TYPE) as LayeInt; var init = frame.Pop().As(this, LayeInt.TYPE) as LayeInt; if (!hasStep) step = init.value < limit.value ? ICONST1 : ICONSTM1; // Now check what we popped, make sure they're valid if (init == null) { RaiseException("iter initial value must be an Int or convertible to an Int."); return; } if (limit == null) { RaiseException("iter limit must be an Int or convertible to an Int."); return; } if (step == null) { RaiseException("iter step must be an Int or convertible to an Int."); return; } if (step.value == 0) { RaiseException("iter step cannot be zero."); return; } if (init.value < limit.value ? step.value < 0 : step.value > 0) { RaiseException("Invalid iter step. The given step will lead the index away from the limit, dooming the loop to never complete."); return; } // Prep the init value init = LayeInt.ValueOf(init.value - step.value); // Store each value where it should go: // We double the first one because + 0 is the visible value, + 1 is the internal value for safety. // We don't want the user messing with our internal counter, we reset it each iteration. frame[iterVar] = init; frame[iterVar + 1] = init; frame[iterVar + 2] = limit; frame[iterVar + 3] = step; }
private void DoIterLoop(StackFrame frame, uint iterVar, uint jump) { // Get the values we need var index = (frame[iterVar + 1] as LayeInt).value; var limit = (frame[iterVar + 2] as LayeInt).value; var step = (frame[iterVar + 3] as LayeInt).value; // Do operations and check bounds index = index + step; if (step > 0 ? index < limit : index > limit) // Update the index frame[iterVar] = frame[iterVar + 1] = LayeInt.ValueOf(index); else frame.ip = jump - 1; }
private void DoThisInvoke(StackFrame frame, LayeObject ths, string methodName, uint insn) { var args = frame.PopCount((int)Insn.GET_A(insn)); frame.Push(ths.MethodInvoke(this, methodName, args)); }
private void DoRes(StackFrame frame) { var value = frame.Pop(); var gen = value as LayeGenerator; if (gen == null) { RaiseException("Expected a generator to resume, got a(n) {0}.", value.TypeName); return; } LayeObject result; var success = gen.Resume(this, out result); if (success) { if (result == null) frame.Push(NULL); else frame.Push(result); } }
internal StackFrame PushFrame(LayeClosure closure, LayeObject ths, LayeObject[] args) { FrameCount++; return Top = new StackFrame(Top, closure, ths, args); }
private void DoMethodInvoke(StackFrame frame, string methodName, uint insn) { var args = frame.PopCount((int)Insn.GET_A(insn)); frame.Push(frame.Pop().MethodInvoke(this, methodName, args)); }
private void DoLoad(StackFrame frame, LayeKit kit, string key) { if (kit.IsDefined(key)) frame.Push(kit[this, key]); else frame.Push(kit.GetGlobal(this, key)); }
private void DoIEachPrep(StackFrame frame, uint eachIndex) { LayeGenerator gen; var value = frame.Pop(); if (!(value is LayeGenerator)) { var genObj = value[this, "enumerator", false]; gen = genObj as LayeGenerator; if (gen == null) { RaiseException("Failed to get a generator from type {0} to enumerate. There should be an instance property called \"enumerator\" that returns a generator.", genObj.TypeName); return; } } else gen = value as LayeGenerator; frame[eachIndex + 1] = ICONST0; frame[eachIndex + 3] = gen; }
private void DoILoad(StackFrame frame, uint insn) { var args = frame.PopCount((int)Insn.GET_C(insn)); frame.Push(frame.Pop()[this, args]); }
private void DoIStore(StackFrame frame, uint insn) { var value = frame.Pop(); var args = frame.PopCount((int)Insn.GET_C(insn)); frame.Pop()[this, args] = value; frame.Push(value); }
private void EndCall(StackFrame frame, OuterValue[] openOuters) { // If we return early, make sure all things are gone plz // (this is me being lazy, we don't pop them automatically in the compiler) while (frame.activeExceptionHandlers > 0) { frame.activeExceptionHandlers--; exceptionHandlers.Pop(); } if (openOuters != null) CloseOuters(openOuters, 0); }
internal LayeObject Execute(StackFrame frame, LayeClosure closure, LayeObject ths = null, params LayeObject[] args) { if (frame == null) frame = stack.PushFrame(closure, ths, args); else stack.PushFrame(frame); reentry: var kit = closure.kit; var outers = closure.outers; var nested = closure.proto.nested; var strings = closure.proto.strings; var numericConsts = closure.proto.numericConsts; var code = closure.proto.code; var codeLen = (uint)code.Length; var paramc = closure.proto.numParams; var argc = args.Length; var vargs = closure.proto.hasVargs; var openOuters = frame.openOuters; uint insn; OpCode op; for (; frame.ip < codeLen && !frame.Aborted && !frame.yielded; frame.ip++) { op = (OpCode)((insn = code[frame.ip]) & Insn.MAX_OP); #if DEBUG_STACK Console.WriteLine(frame.ip + " " + op); frame.PrintLocals(this); frame.PrintStack(this); #endif switch (op) { default: RaiseException(string.Format("Unhandled op code {0}.", op)); return NULL; case OpCode.NOP: continue; case OpCode.POP: frame.Pop(); continue; case OpCode.DUP: frame.Dup(); continue; case OpCode.CLOSE: CloseOuters(openOuters, Insn.GET_C(insn)); continue; // These all do n - 1 because frame.ip++ happens anyway. I hate it, but oh well. case OpCode.JUMP: frame.ip = Insn.GET_C(insn) - 1; continue; case OpCode.JUMPEQ: if (frame.SwapPop().Equals(frame.Pop())) frame.ip = Insn.GET_C(insn) - 1; continue; case OpCode.JUMPNEQ: if (!frame.SwapPop().Equals(frame.Pop())) frame.ip = Insn.GET_C(insn) - 1; continue; case OpCode.JUMPT: if (frame.Pop().ToBool(this)) frame.ip = Insn.GET_C(insn) - 1; continue; case OpCode.JUMPF: if (!frame.Pop().ToBool(this)) frame.ip = Insn.GET_C(insn) - 1; continue; case OpCode.LLOAD: frame.Push(frame[Insn.GET_C(insn)]); continue; case OpCode.LSTORE: frame[Insn.GET_C(insn)] = frame.Top; continue; case OpCode.OLOAD: frame.Push(outers[Insn.GET_C(insn)].Value); continue; case OpCode.OSTORE: outers[Insn.GET_C(insn)].Set(this, frame.Top); continue; case OpCode.KLOAD: frame.Push(kit[this, strings[Insn.GET_C(insn)]]); continue; case OpCode.KSTORE: kit[this, strings[Insn.GET_C(insn)]] = frame.Top; continue; case OpCode.GLOAD: frame.Push(kit.GetGlobal(this, strings[Insn.GET_C(insn)])); continue; case OpCode.GSTORE: kit.SetGlobal(this, strings[Insn.GET_C(insn)], frame.Top); continue; case OpCode.ILOAD: DoILoad(frame, insn); continue; case OpCode.ISTORE: DoIStore(frame, insn); continue; case OpCode.OILOAD: frame.Push(frame.Pop().OperatorIndexGet(this, strings[Insn.GET_C(insn)])); continue; case OpCode.OISTORE: frame.SwapPop().OperatorIndexSet(this, strings[Insn.GET_C(insn)], frame.Top); continue; case OpCode.FLOAD: frame.Push(frame.Pop()[this, strings[Insn.GET_C(insn)]]); continue; case OpCode.FSTORE: frame.SwapPop()[this, strings[Insn.GET_C(insn)]] = frame.Top; continue; case OpCode.LOAD: DoLoad(frame, kit, strings[Insn.GET_C(insn)]); continue; case OpCode.STORE: DoStore(frame, kit, strings[Insn.GET_C(insn)]); continue; case OpCode.NULL: frame.Push(NULL); continue; case OpCode.TRUE: frame.Push(TRUE); continue; case OpCode.FALSE: frame.Push(FALSE); continue; case OpCode.ENDL: frame.Push(ENDL); continue; case OpCode.NCONST: frame.Push(numericConsts[Insn.GET_C(insn)]); continue; case OpCode.SCONST: frame.Push(Insn.GET_B(insn) == 0 ? new LayeString(strings[Insn.GET_A(insn)]) as LayeObject : LayeSymbol.getUnsafe(strings[Insn.GET_A(insn)])); continue; case OpCode.ICONSTM1: frame.Push(ICONSTM1); continue; case OpCode.ICONST0: frame.Push(ICONST0); continue; case OpCode.ICONST1: frame.Push(ICONST1); continue; case OpCode.ICONST2: frame.Push(ICONST2); continue; case OpCode.ICONST3: frame.Push(ICONST3); continue; case OpCode.ICONST4: frame.Push(ICONST4); continue; case OpCode.ICONST5: frame.Push(ICONST5); continue; case OpCode.FCONSTM1: frame.Push(FCONSTM1); continue; case OpCode.FCONST0: frame.Push(FCONST0); continue; case OpCode.FCONST1: frame.Push(FCONST1); continue; case OpCode.FCONST2: frame.Push(FCONST2); continue; case OpCode.LIST: frame.Push(new LayeList(frame.PopCount((int)Insn.GET_C(insn)))); continue; case OpCode.TUPLE: frame.Push(new LayeTuple(frame.PopCount((int)Insn.GET_C(insn)))); continue; case OpCode.CLOSURE: frame.Push(BuildClosure(nested[Insn.GET_A(insn)], openOuters, null, frame.PopCount((int)Insn.GET_B(insn)))); continue; case OpCode.GENERATOR: frame.Push(new LayeClosureGeneratorSpawner(frame.Pop() as LayeClosure)); continue; case OpCode.INVOKE: DoInvoke(frame, insn); continue; case OpCode.MINVOKE: DoMethodInvoke(frame, strings[Insn.GET_B(insn)], insn); continue; case OpCode.TINVOKE: DoThisInvoke(frame, ths, strings[Insn.GET_B(insn)], insn); continue; case OpCode.TAILINVOKE: var saveArgs = frame.PopCount((int)Insn.GET_C(insn)); EndCall(frame, openOuters); frame.Reset(); frame.SetArgs(saveArgs); goto reentry; case OpCode.YIELD: frame.yielded = true; continue; case OpCode.RES: DoRes(frame); continue; case OpCode.KIT: frame.Push(kit); continue; case OpCode.THIS: frame.Push(ths); continue; case OpCode.SELF: frame.Push(closure); continue; case OpCode.STATIC: frame.Push(closure.definedType); continue; case OpCode.PREFIX: frame.Push(frame.Pop().Prefix(this, strings[Insn.GET_C(insn)])); continue; case OpCode.INFIX: frame.Push(frame.SwapPop().Infix(this, strings[Insn.GET_C(insn)], frame.Pop())); continue; case OpCode.AS: frame.Push(frame.SwapPop().As(this, frame.Pop())); continue; case OpCode.NOT: frame.Push(frame.Pop().ToBool(this) ? FALSE : TRUE); continue; case OpCode.AND: if (frame.Top.ToBool(this)) frame.Pop(); else frame.ip = Insn.GET_C(insn) - 1; continue; case OpCode.OR: if (frame.Top.ToBool(this)) frame.ip = Insn.GET_C(insn) - 1; else frame.Pop(); continue; case OpCode.XOR: frame.Push((frame.Pop().ToBool(this) != frame.Pop().ToBool(this)) ? TRUE : FALSE); continue; case OpCode.COMPIS: frame.Push((LayeBool)ReferenceEquals(frame.Pop(), frame.Pop())); continue; case OpCode.COMPNOTIS: frame.Push((LayeBool)!ReferenceEquals(frame.Pop(), frame.Pop())); continue; case OpCode.COMPTYPEOF: frame.Push((LayeBool)frame.SwapPop().TypeOf(this, frame.Pop())); continue; case OpCode.COMPNOTTYPEOF: frame.Push((LayeBool)!frame.SwapPop().TypeOf(this, frame.Pop())); continue; case OpCode.TYPEOF: frame.Push(frame.Pop().TypeDef); continue; case OpCode.THROW: RaiseException(frame.Pop()); continue; case OpCode.STOREEX: frame[Insn.GET_C(insn)] = lastException; continue; case OpCode.BEGINEXH: var c = Insn.GET_C(insn); while (frame.stackPointer >= c) frame.Pop(); continue; case OpCode.PUSHEXH: frame.activeExceptionHandlers++; exceptionHandlers.Push(new ExceptionHandler(stack.FrameCount, Insn.GET_C(insn))); continue; case OpCode.POPEXH: frame.activeExceptionHandlers--; exceptionHandlers.Pop(); continue; case OpCode.ITERPREP: DoIterPrep(frame, Insn.GET_A(insn), Insn.GET_B(insn) != 0); continue; case OpCode.ITERLOOP: DoIterLoop(frame, Insn.GET_A(insn), Insn.GET_B(insn)); continue; case OpCode.EACHPREP: DoEachPrep(frame, Insn.GET_A(insn)); continue; case OpCode.EACHLOOP: DoEachLoop(frame, Insn.GET_A(insn), Insn.GET_B(insn)); continue; case OpCode.IEACHPREP: DoIEachPrep(frame, Insn.GET_A(insn)); continue; case OpCode.IEACHLOOP: DoIEachLoop(frame, Insn.GET_A(insn), Insn.GET_B(insn)); continue; } // end switch } // end for EndCall(frame, openOuters); #if DEBUG_STACK frame.PrintStack(this); #endif if (frame.Aborted) return NULL; stack.PopFrame(); return frame.HasValue() ? frame.Top : NULL; }
internal StackFrame PushFrame(StackFrame frame) { FrameCount++; frame.previous = Top; return Top = frame; }
private void DoEachPrep(StackFrame frame, uint eachVar) { LayeGenerator gen; var value = frame.Pop(); if (!(value is LayeGenerator)) { var genObj = value[this, "enumerator", false]; gen = genObj as LayeGenerator; if (gen == null) { RaiseException("Failed to get a generator from type {0} to enumerate. There should be an instance property called \"enumerator\" that returns a generator.", genObj.TypeName); return; } } else gen = value as LayeGenerator; // eachVar is the var the user has access to, eachVar + 1 is our temp store, and eachVar + 2 is the generator frame[eachVar + 1] = gen; }
private void DoStore(StackFrame frame, LayeKit kit, string key) { if (kit.IsDefined(key)) kit[this, key] = frame.Top; else kit.SetGlobal(this, key, frame.Top); }
private void DoEachLoop(StackFrame frame, uint eachVar, uint jump) { LayeObject result; var gen = frame[eachVar + 1] as LayeGenerator; var success = gen.Resume(this, out result); if (!success) return; // there was an error, control flow is not ours. if (result == null) // This is dead generator lol frame.ip = jump - 1; else frame[eachVar] = result; }
private void DoInvoke(StackFrame frame, uint insn) { var args = frame.PopCount((int)Insn.GET_C(insn)); frame.Push(frame.Pop().Invoke(this, args)); }
private void DoIEachLoop(StackFrame frame, uint eachIndex, uint jump) { LayeObject result; var gen = frame[eachIndex + 3] as LayeGenerator; var success = gen.Resume(this, out result); if (!success) return; // there was an error, control flow is not ours. if (result == null) // This is dead generator lol frame.ip = jump - 1; else { frame[eachIndex] = frame[eachIndex + 1] = LayeInt.ValueOf((frame[eachIndex + 1] as LayeInt).value + 1); frame[eachIndex + 2] = result; } }
internal StackFrame(StackFrame previous, LayeClosure closure, LayeObject ths, LayeObject[] args) { this.previous = previous; this.closure = closure; this.ths = ths; locals = new LayeObject[closure.proto.maxLocalCount]; stack = new LayeObject[closure.proto.maxStackCount]; openOuters = closure.proto.nested.Length != 0 ? new OuterValue[closure.proto.maxStackCount] : null; SetArgs(args); }