/// <summary> /// Инициировать вызов функции (управляемой/неуправляемой) /// </summary> /// <param name="function">Функция</param> /// <param name="context">Контекст</param> /// <param name="args">Параметры</param> /// <param name="copyResult">Копировать результат работы функции в стек вычислений вызывающей функции</param> /// <param name="onCompleteCallback">Вызывается по завершении работы функции</param> internal void CallFunction( JSFunction function, JSObject context, JSValue[] args, bool copyResult, Action onCompleteCallback = null) { if (function.IsNative) { var result = function.Invoke(this, context, CurrentFrame.LocalScope, args); if (copyResult) { CurrentFrame.Push(result); } } else { var managedFunction = (JSManagedFunction)function; CurrentFrame = new CallStackFrame( CurrentFrame, VM, managedFunction, context, new LocalVariableScope(managedFunction.OuterScope), args, copyResult, onCompleteCallback); } }
internal ExecutionThread(VirtualMachine vm, CompiledFunction globalFunction, JSValue[] globalArguments) { Contract.Requires(vm != null); Contract.Requires(globalFunction != null); VM = vm; GlobalScope = new GlobalVariableScope(vm.GlobalObject); GlobalFunction = new JSManagedFunction(VM, GlobalScope, globalFunction, VM.Function); CurrentFrame = new CallStackFrame( null, VM, GlobalFunction, vm.GlobalObject, GlobalScope, globalArguments ?? JSFunction.EmptyArgumentList); }
private void NewObject(JSFunction constructor, JSValue[] args) { if (constructor.IsNative) { CurrentFrame.Push(constructor.Construct(this, CurrentFrame.LocalScope, args)); } else { var managedConstructor = (JSManagedFunction)constructor; var newObject = new JSObject(VM, managedConstructor.GetPrototype()); CurrentFrame = new CallStackFrame( CurrentFrame, VM, managedConstructor, newObject, new LocalVariableScope(managedConstructor.OuterScope), args, true); CurrentFrame.Push(newObject); } }
internal CallStackFrame( CallStackFrame caller, VirtualMachine vm, JSManagedFunction function, JSObject context, VariableScope localScope, JSValue[] parameterValues, bool copyResult = false, Action onCompleteCallback = null) { Contract.Requires(vm != null); Contract.Requires(function != null); Contract.Requires(context != null); Contract.Requires(localScope != null); Contract.Requires(parameterValues != null); Caller = caller; CopyResult = copyResult; Function = function; Context = context; LocalScope = localScope; _evalStack = new Stack <JSValue>(4); CodeReader = new ByteCodeReader(Function.CompiledFunction.CompiledCode); OnCompleteCallback = onCompleteCallback; // Создать привязки для параметров var parameterNames = function.CompiledFunction.ParameterNames; var n = Math.Min(parameterNames.Length, parameterValues.Length); for (var i = 0; i < n; i++) { LocalScope.DeclareVariable(parameterNames[i], parameterValues[i]); } for (var i = n; i < parameterNames.Length; i++) { LocalScope.DeclareVariable(parameterNames[i], JSValue.Undefined); } // Создать привязку для arguments LocalScope.DeclareVariable("arguments", vm.NewArguments(parameterValues)); // Создать привязки для объявленных функций for (var i = 0; i < Function.CompiledFunction.DeclaredFunctionCount; i++) { var declaredFunction = Function.CompiledFunction.NestedFunctions[i]; if (!LocalScope.ContainsVariable(declaredFunction.Name)) { LocalScope.DeclareVariable( declaredFunction.Name, vm.NewFunction(LocalScope, declaredFunction)); } } // Создать привязки для объявленных переменных foreach (var variableName in Function.CompiledFunction.DeclaredVariables) { LocalScope.DeclareVariableIfNotExists(variableName, JSValue.Undefined); } }
private void ExecuteStep(CallStackFrame currentFrame) { try { switch (currentFrame.CodeReader.ReadOpCode()) { case OpCode.Nop: break; case OpCode.Break: // currentFrame.Dump(); break; #region Загрузка значений case OpCode.LdUndefined: currentFrame.Push(JSValue.Undefined); break; case OpCode.LdNull: currentFrame.Push(JSValue.Null); break; case OpCode.LdBoolean: currentFrame.Push(currentFrame.CodeReader.ReadBoolean()); break; case OpCode.LdInteger: currentFrame.Push(currentFrame.CodeReader.ReadInteger()); break; case OpCode.LdFloat: currentFrame.Push(currentFrame.CodeReader.ReadFloat()); break; case OpCode.LdString: currentFrame.Push(currentFrame.CodeReader.ReadString()); break; case OpCode.LdThis: currentFrame.Push(CurrentFrame.Context); break; #endregion #region Локальные переменные и функции case OpCode.LdLocalFunc: currentFrame.Push(currentFrame.GetFunction(VM, currentFrame.CodeReader.ReadInteger())); break; case OpCode.LdLocal: currentFrame.Push(currentFrame.LocalScope.GetVariable(currentFrame.CodeReader.ReadString())); break; case OpCode.StLocal: currentFrame.LocalScope.SetVariable(currentFrame.CodeReader.ReadString(), currentFrame.Pop()); break; #endregion #region Свойства объектов case OpCode.IsMember: { var obj = currentFrame.Pop().ToObject(VM); var member = currentFrame.Pop(); currentFrame.Push(obj.ContainsMember(member)); break; } case OpCode.MakeRef: { var member = currentFrame.Pop(); var obj = currentFrame.Pop().ToObject(VM); currentFrame.Push(new JSReference(obj, member)); break; } case OpCode.LdMember: { var member = currentFrame.Pop(); var obj = currentFrame.Pop().ToObject(VM); currentFrame.Push(obj.GetMember(member)); break; } case OpCode.StMember: { var value = currentFrame.Pop(); var member = currentFrame.Pop(); var obj = currentFrame.Pop().RequireObject(); obj.SetMember(member, value); break; } case OpCode.StMemberDup: { var value = currentFrame.Pop(); var member = currentFrame.Pop(); var obj = currentFrame.Pop().RequireObject(); obj.SetMember(member, value); currentFrame.Push(value); break; } case OpCode.LdMemberByRef: { var reference = currentFrame.Pop().RequireReference(); currentFrame.Push(reference.Value); break; } case OpCode.StMemberByRef: { var value = currentFrame.Pop(); var reference = currentFrame.Pop().RequireReference(); reference.Value = value; break; } case OpCode.StMemberByRefDup: { var value = currentFrame.Pop(); var reference = currentFrame.Pop().RequireReference(); reference.Value = value; currentFrame.Push(value); break; } case OpCode.DelMember: { var member = currentFrame.Pop(); var obj = currentFrame.Pop().RequireObject(); currentFrame.Push(obj.DeleteMember(member)); break; } #endregion #region Управляющие case OpCode.Dup: currentFrame.Push(currentFrame.Peek()); break; case OpCode.Dup2: { var top = currentFrame.Pop(); var top1 = currentFrame.Peek(); currentFrame.Push(top); currentFrame.Push(top1); currentFrame.Push(top); break; } case OpCode.Pop: currentFrame.Pop(); break; case OpCode.Pop2: currentFrame.Pop(); currentFrame.Pop(); break; case OpCode.Swap: { var top = currentFrame.Pop(); var top1 = currentFrame.Pop(); currentFrame.Push(top); currentFrame.Push(top1); break; } case OpCode.SwapDup: { var top = currentFrame.Pop(); var top1 = currentFrame.Pop(); currentFrame.Push(top); currentFrame.Push(top1); currentFrame.Push(top); break; } case OpCode.Goto: currentFrame.CodeReader.Seek(currentFrame.CodeReader.ReadInteger()); break; case OpCode.GotoIfTrue: { var offset = currentFrame.CodeReader.ReadInteger(); if (currentFrame.Pop().CastToBoolean()) { currentFrame.CodeReader.Seek(offset); } break; } case OpCode.GotoIfFalse: { var offset = currentFrame.CodeReader.ReadInteger(); if (!currentFrame.Pop().CastToBoolean()) { currentFrame.CodeReader.Seek(offset); } break; } case OpCode.Switch: Switch(currentFrame.CodeReader.ReadInteger(), currentFrame.Pop()); break; case OpCode.BeginScope: currentFrame.BeginScope(); break; case OpCode.EndScope: currentFrame.EndScope(); break; case OpCode.EnterTry: currentFrame.EnterTry(); break; case OpCode.LeaveTry: currentFrame.LeaveTry(); break; case OpCode.EnterCatch: EnterCatch(); break; case OpCode.LeaveCatch: LeaveCatch(); break; case OpCode.Throw: Throw(currentFrame.Pop()); break; case OpCode.Rethrow: Rethrow(); break; #endregion #region Вызовы функций case OpCode.NewObj: { var arguments = currentFrame.PopArguments(); var constructor = currentFrame.Pop().RequireFunction(); NewObject(constructor, arguments); break; } case OpCode.MakeEmptyObject: currentFrame.Push(VM.NewObject()); break; case OpCode.MakeObject: MakeObject(currentFrame.Pop().RequireInteger()); break; case OpCode.MakeEmptyArray: currentFrame.Push(VM.NewArray(new List <JSValue>())); break; case OpCode.MakeArray: MakeArray(currentFrame.Pop().RequireInteger()); break; case OpCode.Call: { var arguments = currentFrame.PopArguments(); var function = currentFrame.Pop().RequireFunction(); CallFunction(function, VM.GlobalObject, arguments, currentFrame.CodeReader.ReadBoolean()); break; } case OpCode.CallMember: { var arguments = currentFrame.PopArguments(); var function = currentFrame.Pop().RequireFunction(); var context = currentFrame.Pop().ToObject(VM); CallFunction(function, context, arguments, currentFrame.CodeReader.ReadBoolean()); break; } case OpCode.Return: if (currentFrame.CopyResult) { Contract.Assume(currentFrame.Caller != null); CurrentFrame.Caller.Push(currentFrame.Pop()); } CurrentFrame = currentFrame.Caller; currentFrame.OnCompleteCallback?.Invoke(); break; #endregion #region Перечислители case OpCode.GetEnumerator: currentFrame.Push(currentFrame.Pop().GetJSEnumerator()); break; case OpCode.MoveNext: { var enumerator = currentFrame.Peek().RequireEnumerator(); var hasMoreValue = enumerator.MoveNext(); currentFrame.LocalScope.SetVariable( currentFrame.CodeReader.ReadString(), hasMoreValue ? enumerator.Current : JSValue.Undefined); currentFrame.Push(hasMoreValue); break; } #endregion #region Преобразования case OpCode.CastToPrimitive: { var top = currentFrame.Peek(); if (top.Type == JSValueType.Object) { currentFrame.Pop(); top.CastToPrimitiveValue(this, currentFrame.Push); } break; } #endregion #region Числовые case OpCode.Inc: currentFrame.Push(currentFrame.Pop().ToNumber().Inc()); break; case OpCode.Dec: currentFrame.Push(currentFrame.Pop().ToNumber().Dec()); break; case OpCode.Pos: currentFrame.Push(currentFrame.Pop().ToNumber()); break; case OpCode.Neg: currentFrame.Push(currentFrame.Pop().ToNumber().Neg()); break; case OpCode.Plus: { var op2 = currentFrame.Pop(); var op1 = currentFrame.Pop(); currentFrame.Push(op1.Plus(op2)); break; } case OpCode.Minus: { var op2 = currentFrame.Pop().ToNumber(); var op1 = currentFrame.Pop().ToNumber(); currentFrame.Push(op1.Minus(op2)); break; } case OpCode.Mul: { var op2 = currentFrame.Pop().ToNumber(); var op1 = currentFrame.Pop().ToNumber(); currentFrame.Push(op1.Mul(op2)); break; } case OpCode.IntDiv: { var op2 = currentFrame.Pop().ToNumber(); var op1 = currentFrame.Pop().ToNumber(); currentFrame.Push(op1.IntDiv(op2)); break; } case OpCode.FltDiv: { var op2 = currentFrame.Pop().ToNumber(); var op1 = currentFrame.Pop().ToNumber(); currentFrame.Push(op1.FltDiv(op2)); break; } case OpCode.Mod: { var op2 = currentFrame.Pop().ToNumber(); var op1 = currentFrame.Pop().ToNumber(); currentFrame.Push(op1.Mod(op2)); break; } case OpCode.BitNot: currentFrame.Push(currentFrame.Pop().ToNumber().BitNot()); break; case OpCode.BitAnd: { var op2 = currentFrame.Pop().ToNumber(); var op1 = currentFrame.Pop().ToNumber(); currentFrame.Push(op1.BitAnd(op2)); break; } case OpCode.BitOr: { var op2 = currentFrame.Pop().ToNumber(); var op1 = currentFrame.Pop().ToNumber(); currentFrame.Push(op1.BitOr(op2)); break; } case OpCode.BitXor: { var op2 = currentFrame.Pop().ToNumber(); var op1 = currentFrame.Pop().ToNumber(); currentFrame.Push(op1.BitXor(op2)); break; } case OpCode.Shl: { var op2 = currentFrame.Pop().ToNumber(); var op1 = currentFrame.Pop().ToNumber(); currentFrame.Push(op1.BitShl(op2)); break; } case OpCode.ShrS: { var op2 = currentFrame.Pop().ToNumber(); var op1 = currentFrame.Pop().ToNumber(); currentFrame.Push(op1.BitShrS(op2)); break; } case OpCode.ShrU: { var op2 = currentFrame.Pop().ToNumber(); var op1 = currentFrame.Pop().ToNumber(); currentFrame.Push(op1.BitShrU(op2)); break; } #endregion #region Логические case OpCode.Not: currentFrame.Push(currentFrame.Pop().Not()); break; case OpCode.And: { var op2 = currentFrame.Pop(); var op1 = currentFrame.Pop(); currentFrame.Push(op1.And(op2)); break; } case OpCode.Or: { var op2 = currentFrame.Pop(); var op1 = currentFrame.Pop(); currentFrame.Push(op1.Or(op2)); break; } #endregion #region авенства case OpCode.ConvEq: { var op2 = currentFrame.Pop(); var op1 = currentFrame.Pop(); currentFrame.Push(op1.ConvEqualsTo(op2)); break; } case OpCode.StrictEq: { var op2 = currentFrame.Pop(); var op1 = currentFrame.Pop(); currentFrame.Push(op1.StrictEqualsTo(op2)); break; } case OpCode.ConvNeq: { var op2 = currentFrame.Pop(); var op1 = currentFrame.Pop(); currentFrame.Push(!op1.ConvEqualsTo(op2)); break; } case OpCode.StrictNeq: { var op2 = currentFrame.Pop(); var op1 = currentFrame.Pop(); currentFrame.Push(!op1.StrictEqualsTo(op2)); break; } #endregion #region Отношения case OpCode.Lt: { var op2 = currentFrame.Pop(); var op1 = currentFrame.Pop(); currentFrame.Push(op1.Lt(op2)); break; } case OpCode.Lte: { var op2 = currentFrame.Pop(); var op1 = currentFrame.Pop(); currentFrame.Push(op1.Lte(op2)); break; } case OpCode.Gt: { var op2 = currentFrame.Pop(); var op1 = currentFrame.Pop(); currentFrame.Push(op2.Lt(op1)); break; } case OpCode.Gte: { var op2 = currentFrame.Pop(); var op1 = currentFrame.Pop(); currentFrame.Push(op2.Lte(op1)); break; } case OpCode.InstanceOf: { var op2 = currentFrame.Pop().RequireFunction(); var op1 = currentFrame.Pop(); currentFrame.Push(op1.IsInstanceOf(op2)); break; } case OpCode.TypeOf: currentFrame.Push(currentFrame.Pop().TypeOf()); break; #endregion default: throw new UnknownOpCodeException(); } IsTerminated = CurrentFrame == null; if (IsTerminated) { Result = currentFrame.Pop(); } } catch (ReferenceErrorException ex) { Throw(VM.NewReferenceError(ex.Message)); } catch (SyntaxErrorException ex) { Throw(VM.NewSyntaxError(ex.Message)); } catch (TypeErrorException ex) { Throw(VM.NewTypeError(ex.Message)); } catch (RangeErrorException ex) { Throw(VM.NewRangeError(ex.Message)); } catch (RuntimeErrorException ex) { Throw(VM.NewInternalError(ex.Message, ex.StackTrace)); } }
public CallStackFrameView(CallStackFrame stackFrame) { Contract.Requires(stackFrame != null); FunctionName = stackFrame.Function.CompiledFunction.Name; CodeOffset = stackFrame.CodeReader.Offset; }