public static mdr.DArray CreateArgumentsObject(ref mdr.CallFrame callFrame, mdr.DObject context) { var metadata = (JSFunctionMetadata)callFrame.Function.Metadata; Debug.Assert(metadata.Scope.HasArgumentsSymbol, "Invalid situation, created arguments for the wrong scope!"); mdr.DArray arguments = null; if (metadata.Scope.IsEvalFunction) { //Read from context var tmp = new mdr.DValue(); context.GetField(JSFunctionArguments.Name, ref tmp); arguments = tmp.AsDArray(); } else { arguments = CreateArgumentsObject(ref callFrame); var parameters = metadata.FunctionIR.Parameters; Debug.Assert(arguments.Length >= parameters.Count, "arguments array is not large enough to hold all arguments."); for (var i = parameters.Count - 1; i >= 0; --i) { var symbol = parameters[i].Symbol; var paramIndex = symbol.ParameterIndex; Debug.Assert(paramIndex == i, "Invalid situation!, Parameter indexes don't match!"); if (symbol.SymbolType == JSSymbol.SymbolTypes.ClosedOnLocal) { var pd = context.AddOwnPropertyDescriptorByFieldId(symbol.FieldId, mdr.PropertyDescriptor.Attributes.Accessor | mdr.PropertyDescriptor.Attributes.NotConfigurable); context.Fields[pd.Index].Set(new ArgumentAccessor(arguments, paramIndex)); } } if (metadata.Scope.HasEval) context.SetField(JSFunctionArguments.Name, arguments); } return arguments; }
internal static void EvalString(string inputString, ref mdr.DValue result, mdr.DFunction callerFunction = null, mdr.DObject callerContext = null, mdr.DObject thisArg = null) { var funcMetadata = JSParser.ParseScript(inputString).Expression.Metadata; var func = new mdr.DFunction(funcMetadata, null); var tempCallFrame = new mdr.CallFrame(); bool isDirectEval = callerContext != null; if (isDirectEval) { //function will behave as if it was the caller Debug.Assert(thisArg != null && callerFunction != null && callerContext != null, "Invalid situation! Direct eval call must have thisArg, callerFunction, callerContext set"); funcMetadata.Scope.IsProgram = false; funcMetadata.Scope.IsEvalFunction = true; funcMetadata.ParentFunction = (JSFunctionMetadata)callerFunction.Metadata; tempCallFrame.CallerContext = callerContext; tempCallFrame.This = thisArg; } else { //This will behave just like a program code tempCallFrame.CallerContext = mdr.Runtime.Instance.GlobalContext; tempCallFrame.This = (mdr.Runtime.Instance.GlobalContext); } //TODO: find a way to assign a name to this //funcMetadata.Name += "_eval"; //After we know the ParentFunction tempCallFrame.Function = func; tempCallFrame.Signature = mdr.DFunctionSignature.EmptySignature; func.Call(ref tempCallFrame); result.Set(ref tempCallFrame.Return); }
//public static mdr.DValue IncDec(ref mdr.DValue i0, int i1) //{ // var result = new mdr.DValue(); // switch (i0.ValueType) // { // case mdr.ValueTypes.Int: // { // int oldValue = i0.IntValue; // int newValue = oldValue + i1; // result.Set(newValue); // break; // } // case mdr.ValueTypes.Boolean: // { // int oldValue = i0.BoolValue ? 1 : 0; // int newValue = oldValue + i1; // result.Set(newValue); // break; // } // default: // { // double oldValue = i0.ToDouble(); // double newValue = oldValue + i1; // result.Set(newValue); // break; // } // } // return result; //} /// <summary> /// The following is used for inc/dec that involves DValue. To handle arrays and properties well, we will have a separate object for /// reading the value, and another for setting. To make the inc/dec and assign, etc. uniform, we should consider that on the stack /// we have all the paramertes always for all kinds of values (symbols, arrays, properties, ...) /// /// followings: /// dest for writing /// DObject for setting (for array/property will be a member of the object itself) /// DObject for reading (for array/property may be a member of the object's prototype) /// </summary> /// <param name="result">for returing the value that is used in the next instruction.</param> /// <param name="dest">For updating the source itself</param> /// <param name="i0">the source for reading the value</param> /// <param name="i1">1 for inc and -1 for dec</param> /// <param name="isPostfix"></param> /// <returns></returns> public static void AddConst(ref mdr.DValue dest, /*const*/ ref mdr.DValue i0, int i1, bool isPostfix, ref mdr.DValue result) { switch (i0.ValueType) { case mdr.ValueTypes.Int32: { int oldValue = i0.IntValue; int newValue = oldValue + i1; dest.Set(newValue); result.Set(isPostfix ? oldValue : newValue); break; } case mdr.ValueTypes.Boolean: { int oldValue = i0.BooleanValue ? 1 : 0; int newValue = oldValue + i1; dest.Set(newValue); result.Set(isPostfix ? oldValue : newValue); break; } default: { double oldValue = i0.AsDouble(); double newValue = oldValue + i1; dest.Set(newValue); result.Set(isPostfix ? oldValue : newValue); break; } } }
/// <summary> /// Parse a number. Intended to be used at runtime for string-to-number conversions. /// </summary> public static void ParseNumber(string number, ref mdr.DValue dValue) { var parser = new JavaScriptParser.SequentialParser(number); var numericLiteral = parser.ParseNumber(); // Convert to a DValue and return via the ref parameter. Debug.Assert(numericLiteral is IR.PrimitiveLiteral, "ParseNumber() should yield a PrimitiveLiteral."); (numericLiteral as IR.PrimitiveLiteral).SetAsDValue(ref dValue); }
// i0 ? i1 : i2 public static void Run(ref mdr.DValue i0, ref mdr.DValue i1, ref mdr.DValue i2, ref mdr.DValue result) { if (Operations.Convert.ToBoolean.Run(ref i0)) { result.Set(ref i1); } else { result.Set(ref i2); } }
public static char Run(string i0) { if (i0.Length == 1) return i0[0]; else { var number = new mdr.DValue(); Convert.ToNumber.Run(i0, ref number); return Run(ref number); } }
public static char Run(string i0) { if (i0.Length == 1) { return(i0[0]); } else { var number = new mdr.DValue(); Convert.ToNumber.Run(i0, ref number); return(Run(ref number)); } }
public override void SetGlobalContext(mdr.DObject globalContext) { var timer = StartTimer(Configuration.ProfileInitTime, "JS/GlobalInit"); try { base.SetGlobalContext(globalContext); //This will set the GlobalContext if (JSRuntime.Instance.Configuration.EnableRecursiveInterpreter && false) { var result = new mdr.DValue(); Builtins.JSGlobalObject.EvalString(@" Object.defineProperty(Array.prototype, 'pop', { enumerable: false, value: function() { var n = (this.length); if (n == 0) { this.length = n; return; } n--; var value = this[n]; delete this[n]; this.length = n; return value; } }); Object.defineProperty(Array.prototype, 'push', { enumerable: false, value: function() { var n = this.length; var m = arguments.length; for (var i = 0; i < m; i++) { this[i+n] = arguments[i]; } this.length = n + m; return this.length; } }); ", ref result); } } finally { StopTimer(timer); } }
public static void Run(ref mdr.DValue i0, int i1) { switch (i0.ValueType) { case mdr.ValueTypes.Double: { double oldValue = i0.DoubleValue; double newValue = oldValue + i1; i0.DoubleValue = newValue; //i0.Set(newValue); break; } case mdr.ValueTypes.Int32: { int oldValue = i0.IntValue; int newValue = oldValue + i1; i0.IntValue = newValue; //i0.Set(newValue); break; } case mdr.ValueTypes.Boolean: { int oldValue = i0.BooleanValue ? 1 : 0; int newValue = oldValue + i1; i0.Set(newValue); break; } default: { double oldValue = i0.AsDouble(); double newValue = oldValue + i1; i0.Set(newValue); break; } } }
public static mdr.DArray CreateArgumentsObject(ref mdr.CallFrame callFrame, mdr.DObject context) { var metadata = (JSFunctionMetadata)callFrame.Function.Metadata; Debug.Assert(metadata.Scope.HasArgumentsSymbol, "Invalid situation, created arguments for the wrong scope!"); mdr.DArray arguments = null; if (metadata.Scope.IsEvalFunction) { //Read from context var tmp = new mdr.DValue(); context.GetField(JSFunctionArguments.Name, ref tmp); arguments = tmp.AsDArray(); } else { arguments = CreateArgumentsObject(ref callFrame); var parameters = metadata.FunctionIR.Parameters; Debug.Assert(arguments.Length >= parameters.Count, "arguments array is not large enough to hold all arguments."); for (var i = parameters.Count - 1; i >= 0; --i) { var symbol = parameters[i].Symbol; var paramIndex = symbol.ParameterIndex; Debug.Assert(paramIndex == i, "Invalid situation!, Parameter indexes don't match!"); if (symbol.SymbolType == JSSymbol.SymbolTypes.ClosedOnLocal) { var pd = context.AddOwnPropertyDescriptorByFieldId(symbol.FieldId, mdr.PropertyDescriptor.Attributes.Accessor | mdr.PropertyDescriptor.Attributes.NotConfigurable); context.Fields[pd.Index].Set(new ArgumentAccessor(arguments, paramIndex)); } } if (metadata.Scope.HasEval) { context.SetField(JSFunctionArguments.Name, arguments); } } return(arguments); }
public static string ToString(ref mdr.DValue arg) { //TODO: it seems eventually, this is the right implementation, but for now, we use the special implementation //mdr.DValue output; //if (Operations.Internals.CallToStringProperty(Operations.Convert.ToObject.Run(ref arg), out output)) // return output.AsString(); //else // return Operations.Convert.ToString.Run(ref arg); string s; if (!mdr.ValueTypesHelper.IsObject(arg.ValueType)) { s = Operations.Convert.ToString.Run(ref arg); } else { var argObj = arg.AsDObject(); //TODO: should we call ToObject(arg) here instead?! var toString = argObj.GetField("toString"); if (toString.ValueType == mdr.ValueTypes.Function) { var cf = new mdr.CallFrame(); cf.Function = toString.AsDFunction(); cf.Signature = mdr.DFunctionSignature.EmptySignature; cf.This = argObj; cf.Arguments = null; cf.Function.Call(ref cf); s = Operations.Convert.ToString.Run(ref cf.Return); } else { s = arg.AsString(); } } return(s); }
public abstract void SetAsDValue(ref mdr.DValue dValue);
public static void Run(mdr.DNull i0, ref mdr.DValue result) { result.Set(i0); }
public void Visit <T>(mdr.DValue <T> obj) { throw new NotImplementedException(); }
private void RunBody(ref mdr.CallFrame callFrame) { //as tempting it might be, we cannot use the callFrame.Return here since function may not have a return statement at all. var result = new mdr.DValue(); _currFuncMetadata.FunctionIR.Statement.Execute(ref result, ref callFrame, this); }
public override void Execute(ref mdr.DValue result, ref mdr.CallFrame callFrame, Interpreter interpreter) { interpreter.PushLocation(this); var tmpCallFrame = new mdr.CallFrame(); Function.Execute(ref result, ref callFrame, interpreter); if (ThisArg != null) { var thisValue = new mdr.DValue(); ThisArg.Execute(ref thisValue, ref callFrame, interpreter); tmpCallFrame.This = thisValue.AsDObject(); } else if (IsDirectEvalCall) { tmpCallFrame.CallerFunction = callFrame.Function; tmpCallFrame.CallerContext = interpreter.Context; tmpCallFrame.This = callFrame.This; } else { tmpCallFrame.This = mdr.Runtime.Instance.GlobalContext; } interpreter.LoadArguments(this.Arguments, ref tmpCallFrame, ref callFrame); tmpCallFrame.Function = result.AsDFunction(); JSRuntime.StopTimer(interpreter.Timer); tmpCallFrame.Function.Call(ref tmpCallFrame); JSRuntime.StartTimer(interpreter.Timer); result = tmpCallFrame.Return; interpreter.PopLocation(this, tmpCallFrame.Function); }
public override void Execute(ref mdr.DValue result, ref mdr.CallFrame callFrame, Interpreter interpreter) { interpreter.PushLocation(this); Container.Execute(ref result, ref callFrame, interpreter); var obj = result.AsDObject(); var index = new mdr.DValue(); Index.Execute(ref index, ref callFrame, interpreter); Value.Execute(ref result, ref callFrame, interpreter); obj.SetField(ref index, ref result); //interpreter.PopLocation(this, ref result, obj); interpreter.PopLocation(this, ref result); }
public static void WriteValueToContext(ref mdr.CallFrame callFrame, int valueIndex, int fieldId, ref mdr.DValue value) { var pd = GetPropertyDescriptor(ref callFrame, valueIndex, fieldId); if (pd.IsUndefined) { JSRuntime.Instance.GlobalContext.SetFieldByFieldId(fieldId, ref value); } else { var context = GetContext(ref callFrame); pd.Set(context, ref value); } }
/// <param name="input">Javascript value</param> /// <param name="output">Will have the primitive type of the input when the function returns</param> /// <param name="stringHint">Specifies whether the hint is string or number. Default is number.</param> //public static void Run(ref mdr.DValue input, out mdr.DValue output, bool stringHint = false) //{ // mdr.ValueTypes inputType = input.ValueType; // if (mdr.ValueTypesHelper.IsObject(inputType)) // Internals.DefaultValue(ref input, out output, stringHint); // else // type is a primitive type // output = input; //} public static void Run(mdr.DObject input, ref mdr.DValue output, bool stringHint = false) { Internals.DefaultValue(input, out output, stringHint); }
public static void Run(double i0, ref mdr.DValue result) { result.Set(i0); }
public static void LoadDValue(ref mdr.DValue value, ref Stack stack) { stack.Items[stack.Sp++].Set(ref value); }
public JSException(ref mdr.DValue e) : this() { Value.Set(ref e); }
public static void Throw(ref mdr.DValue e) { throw new JSException(ref e); }
public static void Run(mdr.DFunction i0, ref mdr.DValue result) { result.Set(i0); }
public static void Run(mdr.DObject i0, ref mdr.DValue result) { result.Set(i0); }
public static void Run(mdr.DUndefined i0, ref mdr.DValue result) { result.Set(i0); }
public JSArray() : base(mdr.Runtime.Instance.DArrayPrototype, "Array") { JittedCode = (ref mdr.CallFrame callFrame) => { mdr.DArray array; var argsCount = callFrame.PassedArgsCount; if (argsCount == 1) { var len = Operations.Convert.ToInt32.Run(ref callFrame.Arg0); array = new mdr.DArray(len); } else { array = new mdr.DArray(argsCount); switch (argsCount) { case 0: break; case 1: break; case 2: array.Elements[1] = callFrame.Arg1; array.Elements[0] = callFrame.Arg0; break; case 3: array.Elements[2] = callFrame.Arg2; goto case 2; case 4: array.Elements[3] = callFrame.Arg3; goto case 3; default: Debug.Assert(argsCount > mdr.CallFrame.InlineArgsCount, "Code gen must be updated to support new CallFrame"); Array.Copy(callFrame.Arguments, 0, array.Elements, mdr.CallFrame.InlineArgsCount, argsCount - mdr.CallFrame.InlineArgsCount); goto case 4; } } if (IsConstrutor) { callFrame.This = (array); } else { callFrame.Return.Set(array); } }; // ECMA-262 section 15.4.3.1 this.DefineOwnProperty("isArray", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.isArray"); if (callFrame.This.ValueType == mdr.ValueTypes.Array) { callFrame.Return.Set(true); } else { callFrame.Return.Set(false); } }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.2 TargetPrototype.DefineOwnProperty("toString", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.toString"); var join = callFrame.This.GetField("join"); if (join.ValueType == mdr.ValueTypes.Function)// it is callable { var joinFun = join.AsDFunction(); Debug.Assert(joinFun != null, "Invalid situation!"); callFrame.Function = joinFun; //callFrame.This is already set callFrame.Signature = mdr.DFunctionSignature.EmptySignature; callFrame.PassedArgsCount = 0; callFrame.Arguments = null; joinFun.Call(ref callFrame); callFrame.Return.Set(callFrame.Return.AsString()); } else { callFrame.Return.Set(callFrame.This.ToString()); } }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.3 TargetPrototype.DefineOwnProperty("toLocaleString", new mdr.DFunction((ref mdr.CallFrame callFrame) => { throw new NotImplementedException("Array.toLocaleString is not implemented"); // TODO: callFrame.This is not an accurate implementation /*mdr.DObject array = callFrame.This; * mdr.DFunction join = array.GetField("join").ToDObject() as mdr.DFunction; * if (join != null) // it is callable * { * callFrame.Function = join; * callFrame.Signature = mdr.DFunctionSignature.EmptySignature; * callFrame.Arguments = null; * join.Call(ref callFrame); * callFrame.Return.Set(callFrame.Return.ToString()); //TODO: is this the right implementation? * } * else * callFrame.Return.Set(array.ToString());*/ }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.4 TargetPrototype.DefineOwnProperty("concat", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.concat"); //The most common case is calling .concat on array object with normal set of arguments mdr.DArray newArray; var destStartIndex = 0; var thisArray = callFrame.This as mdr.DArray; if (thisArray != null) { newArray = new mdr.DArray(callFrame.PassedArgsCount + thisArray.Length); Array.Copy(thisArray.Elements, 0, newArray.Elements, 0, thisArray.Length); destStartIndex = thisArray.Length; } else { newArray = new mdr.DArray(callFrame.PassedArgsCount + 1); newArray.Elements[0].Set(callFrame.This); destStartIndex = 1; } for (int i = 0; i < callFrame.PassedArgsCount; ++i) { newArray.Elements[destStartIndex] = callFrame.Arg(i); //This is the common case if (newArray.Elements[destStartIndex].ValueType == mdr.ValueTypes.Array) { var array = newArray.Elements[destStartIndex].AsDArray(); //We had already accounted 1 cell for this item, so, we add the missing remaining elements newArray.Length += (array.Length - 1); //Extends newArray.Elements Array.Copy(array.Elements, 0, newArray.Elements, destStartIndex, array.Length); destStartIndex += array.Length; } else { ++destStartIndex; } } //concat(newArray, ref callFrame.Arguments[i]); callFrame.Return.Set(newArray); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.5 TargetPrototype.DefineOwnProperty("join", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.join"); string separator = (callFrame.PassedArgsCount == 0 || callFrame.Arg0.ValueType == mdr.ValueTypes.Undefined) ? "," : callFrame.Arg0.AsString(); callFrame.Return.Set(join(callFrame.This, separator).ToString()); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.6 TargetPrototype.DefineOwnProperty("pop", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.pop"); var This = callFrame.This; var lenField = This.GetField("length"); int len = Operations.Convert.ToInt32.Run(ref lenField); if (len == 0) { This.SetField("length", 0); callFrame.Return.Set(mdr.Runtime.Instance.DefaultDUndefined); } else if (len > 0) { var index = len - 1; mdr.DValue element = new mdr.DValue(); This.GetField(index, ref element); This.DeletePropertyDescriptor(index.ToString()); This.SetField("length", index); callFrame.Return.Set(ref element); } }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.7 TargetPrototype.DefineOwnProperty("push", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.push"); var This = callFrame.This; var lenField = This.GetField("length"); int len = Operations.Convert.ToInt32.Run(ref lenField); mdr.DValue arg = new mdr.DValue(); for (int i = 0; i < callFrame.PassedArgsCount; ++i) { arg = callFrame.Arg(i); This.SetField(len, ref arg); len++; } This.SetField("length", len); callFrame.Return.Set(len); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.8 TargetPrototype.DefineOwnProperty("reverse", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.reverse"); var This = callFrame.This; var lenField = This.GetField("length"); int len = Operations.Convert.ToInt32.Run(ref lenField); int middle = len / 2; mdr.DValue lowerValue = new mdr.DValue(); mdr.DValue upperValue = new mdr.DValue(); bool lowerExists, upperExists; for (int lower = 0; lower != middle; lower++) { int upper = len - lower - 1; lowerExists = This.HasProperty(lower); upperExists = This.HasProperty(upper); if (lowerExists && upperExists) { This.GetField(lower, ref lowerValue); This.GetField(upper, ref upperValue); This.SetField(lower, ref upperValue); This.SetField(upper, ref lowerValue); } else if (!lowerExists && upperExists) { This.GetField(upper, ref upperValue); This.SetField(lower, ref upperValue); This.DeletePropertyDescriptor(upper.ToString()); } else if (lowerExists && !upperExists) { This.GetField(lower, ref lowerValue); This.SetField(upper, ref lowerValue); This.DeletePropertyDescriptor(lower.ToString()); } } callFrame.Return.Set(This); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.9 TargetPrototype.DefineOwnProperty("shift", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.shift"); mdr.DArray array = callFrame.This.ToDArray(); int len = array.Length; if (array == null || array.Length == 0) { //callFrame.Return.ValueType = mdr.ValueTypes.Undefined; callFrame.Return.Set(mdr.Runtime.Instance.DefaultDUndefined); } else { callFrame.Return.Set(ref array.Elements[0]); for (int k = 1; k < len; k++) { array.Elements[k - 1].Set(ref array.Elements[k]); } array.Length--; } }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.10 TargetPrototype.DefineOwnProperty("slice", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.slice"); /* TODO: This is the implementation for a case that "this" is a DArray. Use this faster implementation after adding PackedArray optimization. * mdr.DArray array = callFrame.This.ToDArray(); * int len = array.Length; * int relativeStart = callFrame.Arg0.ToInt32(); * int k = (relativeStart < 0) ? Math.Max(len + relativeStart, 0) : Math.Min(relativeStart, len); * int relativeEnd = (callFrame.Arg1.ValueType == mdr.ValueTypes.Undefined) ? len : callFrame.Arg1.ToInt32(); * int final = (relativeEnd < 0) ? Math.Max(relativeEnd + len, 0) : Math.Min(relativeEnd, len); * mdr.DArray newArray = new mdr.DArray((final - k > 0) ? (final - k) : 0); * for (int n = 0; k < final; k++, n++) * newArray.Elements[n].Set(ref array.Elements[k]); * callFrame.Return.Set(newArray); */ var This = callFrame.This; var lenField = This.GetField("length"); int len = Operations.Convert.ToInt32.Run(ref lenField); int relativeStart = 0; if (callFrame.PassedArgsCount > 0) { relativeStart = Operations.Convert.ToInt32.Run(ref callFrame.Arg0); } int k = (relativeStart < 0) ? Math.Max(len + relativeStart, 0) : Math.Min(relativeStart, len); int relativeEnd = ((callFrame.Arg1.ValueType == mdr.ValueTypes.Undefined) || (callFrame.PassedArgsCount < 2)) ? len : Operations.Convert.ToInt32.Run(ref callFrame.Arg1); int final = (relativeEnd < 0) ? Math.Max(relativeEnd + len, 0) : Math.Min(relativeEnd, len); mdr.DArray newArray = new mdr.DArray((final - k > 0) ? (final - k) : 0); mdr.DValue item = new mdr.DValue(); for (int n = 0; k < final; k++, n++) { This.GetField(k, ref item); newArray.Elements[n].Set(ref item); } callFrame.Return.Set(newArray); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.12 //TODO: splice is generic and can be applied to other objects TargetPrototype.DefineOwnProperty("splice", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.splice"); if (callFrame.PassedArgsCount < 2) { callFrame.Return.Set(JSRuntime.Instance.DefaultDUndefined); return; } var A = new mdr.DArray(); var This = callFrame.This as mdr.DArray; if (This == null) { throw new Exception("Object is not an array, but splice must work with generic objects. Please fix it!"); } int len = This.Length; int relativeStart = Operations.Convert.ToInt32.Run(ref callFrame.Arg0); int actualStart = relativeStart < 0 ? Math.Max(len + relativeStart, 0) : Math.Min(relativeStart, len); int actualDeleteCount = Math.Min(Math.Max(Operations.Convert.ToInt32.Run(ref callFrame.Arg1), 0), len - actualStart); A.Length = actualDeleteCount; for (int k = 0; k < actualDeleteCount; k++) { int from = relativeStart + k; if (from < len) { A.Elements[k].Set(ref This.Elements[from]); } } int itemCount = callFrame.PassedArgsCount - 2; if (itemCount < actualDeleteCount) { for (int k = actualStart; k < len - actualDeleteCount; k++) { int from = k + actualDeleteCount; int to = k + itemCount; // if (from < len) // This condition will always hold This.Elements[to].Set(ref This.Elements[from]); // from will always be less than less and therefore the element exists in the array //TODO: can we assume any index less than Length exist? When an element is deleted from middle of the Elements, is Length adjusted? /* * else * { * This.RemoveElements(to, len - actualDeleteCount - k); * break; * }*/ } This.RemoveElements(len - actualDeleteCount + itemCount, actualDeleteCount - itemCount); This.Length = len - actualDeleteCount + itemCount; } else if (itemCount > actualDeleteCount) { This.Length = len - actualDeleteCount + itemCount; for (int k = len - actualDeleteCount; k > actualStart; k--) { int from = k + actualDeleteCount - 1; int to = k + itemCount - 1; //if (from < len) //This condition will always hold This.Elements[to].Set(ref This.Elements[from]); } } for (int k = 0; k < itemCount; k++) { This.Elements[k + actualStart] = callFrame.Arg(k + 2); } callFrame.Return.Set(A); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.11 TargetPrototype.DefineOwnProperty("sort", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.sort"); mdr.DArray array = callFrame.This.ToDArray(); int len = array.Length; if (len == 0) { callFrame.Return.Set(array); } int argsCount = callFrame.PassedArgsCount; mdr.DValue function = callFrame.Arg0; for (uint i = 0; i < len - 1; ++i) { mdr.DValue iObj = array.Elements[i]; uint themin = i; mdr.DValue minObj = iObj; for (uint j = i + 1; j < len; ++j) { mdr.DValue jObj = array.Elements[j]; double compareResult = 0; if (jObj.ValueType == mdr.ValueTypes.Undefined) { compareResult = 1; } else if (minObj.ValueType == mdr.ValueTypes.Undefined) { compareResult = -1; } else if (argsCount == 1 && function.ValueType == mdr.ValueTypes.Function) { callFrame.Function = function.AsDFunction(); callFrame.SetArg(0, ref minObj); callFrame.SetArg(1, ref jObj); callFrame.PassedArgsCount = 2; callFrame.Signature = new mdr.DFunctionSignature(ref callFrame, 2); callFrame.Function.Call(ref callFrame); compareResult = Operations.Convert.ToInt32.Run(ref callFrame.Return) <= 0 ? 1 : -1; } else { mdr.DValue v1 = mdr.DValue.Create(jObj.AsString()); mdr.DValue v2 = mdr.DValue.Create(minObj.AsString()); compareResult = Operations.Binary.LessThan.Run(ref v1, ref v2) ? -1 : 1; } if (compareResult < 0) { themin = j; minObj = jObj; } } if (themin > i) { array.Elements[i] = minObj; array.Elements[themin] = iObj; } } callFrame.Return.Set(array); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.13 TargetPrototype.DefineOwnProperty("unshift", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.unshift"); var thisObj = callFrame.This; mdr.DArray array = thisObj.ToDArray(); int len = array.Length; int argsCount = callFrame.PassedArgsCount; array.ResizeElements(len + argsCount); array.Length = len + argsCount; if (argsCount != 0 && len != 0) { mdr.DValue iObj; for (int i = len; i > 0; --i) { iObj = array.Elements[i - 1]; array.Elements[i - 1].Set(0); array.Elements[i + argsCount - 1] = iObj; } } for (int k = 0; k < argsCount; ++k) { array.Elements[k] = callFrame.Arg(k); } callFrame.Return.Set(array.Length); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.14 TargetPrototype.DefineOwnProperty("indexOf", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.indexOf"); mdr.DArray array = callFrame.This.ToDArray(); int len = array.Length; int index = 0; if (callFrame.PassedArgsCount > 1) { index = Operations.Convert.ToInt32.Run(ref callFrame.Arg1); } index = index < 0 ? Math.Max(len + index, 0) : Math.Min(index, len); mdr.DValue searchElem = callFrame.Arg0; for (; index < len; ++index) { mdr.DValue indexElem = array.Elements[index]; if (indexElem.ValueType != mdr.ValueTypes.Undefined && Operations.Binary.Equal.Run(ref indexElem, ref searchElem)) { callFrame.Return.Set(index); return; } } callFrame.Return.Set(-1); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.15 TargetPrototype.DefineOwnProperty("lastIndexOf", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.lastIndexOf"); mdr.DArray array = callFrame.This.ToDArray(); int len = array.Length; if (len == 0) { callFrame.Return.Set(-1); return; } int index = len - 1; if (callFrame.PassedArgsCount > 1) { index = Operations.Convert.ToInt32.Run(ref callFrame.Arg1); } index = index < 0 ? len + index : Math.Min(index, len - 1); if (index < 0) { callFrame.Return.Set(-1); return; } mdr.DValue searchElem = callFrame.Arg0; do { mdr.DValue indexElem = array.Elements[index]; if (indexElem.ValueType != mdr.ValueTypes.Undefined && Operations.Binary.Equal.Run(ref indexElem, ref searchElem)) { callFrame.Return.Set(index); return; } } while (index-- > 0); callFrame.Return.Set(-1); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.16 TargetPrototype.DefineOwnProperty("every", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.every"); var thisObj = callFrame.This; mdr.DArray array = thisObj.ToDArray(); int len = array.Length; if (len == 0) { callFrame.Return.Set(array); } // TODO: Commented because argsCount is unused. /*int argsCount = callFrame.ArgsCount;*/ mdr.DFunction function = callFrame.Arg0.AsDFunction(); bool result = true; for (int i = 0; i < len; ++i) { if (array.Elements[i].ValueType != mdr.ValueTypes.Undefined) { callFrame.Function = function; callFrame.SetArg(0, ref array.Elements[i]); callFrame.SetArg(1, i); callFrame.SetArg(2, thisObj); callFrame.Signature = new mdr.DFunctionSignature(ref callFrame, 3); callFrame.Function.Call(ref callFrame); if (Operations.Convert.ToBoolean.Run(ref callFrame.Return) == false) { result = false; break; } } } callFrame.Return.Set(result); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.17 TargetPrototype.DefineOwnProperty("some", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.some"); var thisObj = callFrame.This; mdr.DArray array = thisObj.ToDArray(); int len = array.Length; if (len == 0) { callFrame.Return.Set(array); } // TODO: Commented because argsCount is unused. /*int argsCount = callFrame.ArgsCount;*/ mdr.DFunction function = callFrame.Arg0.AsDFunction(); bool result = false; for (int i = 0; i < len; ++i) { if (array.Elements[i].ValueType != mdr.ValueTypes.Undefined) { callFrame.Function = function; callFrame.SetArg(0, ref array.Elements[i]); callFrame.SetArg(1, i); callFrame.SetArg(2, thisObj); callFrame.Signature = new mdr.DFunctionSignature(ref callFrame, 3); callFrame.Function.Call(ref callFrame); if (Operations.Convert.ToBoolean.Run(ref callFrame.Return) == true) { result = true; break; } } } callFrame.Return.Set(result); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.18 TargetPrototype.DefineOwnProperty("forEach", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.forEach"); mdr.DArray array = callFrame.This.ToDArray(); int len = array.Length; if (len == 0) { callFrame.Return.Set(array); } mdr.DFunction function = callFrame.Arg0.AsDFunction(); // TODO: Commented because thisArg is unused. /*mdr.DValue thisArg; * if (callFrame.ArgsCount > 1) * thisArg = callFrame.Arg1; * else * thisArg = new mdr.DValue();*/ for (int i = 0; i < len; ++i) { if (array.Elements[i].ValueType != mdr.ValueTypes.Undefined) { callFrame.Function = function; callFrame.PassedArgsCount = 3; callFrame.SetArg(0, ref array.Elements[i]); callFrame.SetArg(1, i); callFrame.SetArg(2, array); callFrame.Signature = new mdr.DFunctionSignature(ref callFrame, 3); callFrame.Function.Call(ref callFrame); } } callFrame.Return.Set(mdr.Runtime.Instance.DefaultDUndefined); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.19 TargetPrototype.DefineOwnProperty("map", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.map"); mdr.DArray array = callFrame.This.ToDArray(); int len = array.Length; if (len == 0) { callFrame.Return.Set(array); } mdr.DFunction function = callFrame.Arg0.AsDFunction(); mdr.DObject thisArg; if (callFrame.PassedArgsCount > 1) { thisArg = Operations.Convert.ToObject.Run(ref callFrame.Arg1); } else { thisArg = mdr.Runtime.Instance.GlobalContext; } mdr.DArray newarray = new mdr.DArray(len); for (int i = 0; i < len; ++i) { if (array.Elements[i].ValueType != mdr.ValueTypes.Undefined) { callFrame.Function = function; callFrame.This = thisArg; callFrame.PassedArgsCount = 3; callFrame.SetArg(0, ref array.Elements[i]); callFrame.SetArg(1, i); callFrame.SetArg(2, array); callFrame.Signature = new mdr.DFunctionSignature(ref callFrame, 3); callFrame.Function.Call(ref callFrame); newarray.Elements[i] = callFrame.Return; } } callFrame.Return.Set(newarray); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); TargetPrototype.DefineOwnProperty("filter", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Trace.Fail("Unimplemented"); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); TargetPrototype.DefineOwnProperty("reduce", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Trace.Fail("Unimplemented"); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); TargetPrototype.DefineOwnProperty("reduceRight", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Trace.Fail("Unimplemented"); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); }
public static void Run(/*const*/ ref mdr.DValue i0, ref mdr.DValue result) { result.Set(ref i0); }
public override void Execute(ref mdr.DValue result, ref mdr.CallFrame callFrame, Interpreter interpreter) { interpreter.PushLocation(this); var tmp = new mdr.DValue(); Left.Execute(ref result, ref callFrame, interpreter); Right.Execute(ref tmp, ref callFrame, interpreter); result.Set(Operations.Binary.BitwiseXor.Run(ref result, ref tmp)); interpreter.PopLocation(this, ref result); }
public override void SetAsDValue(ref mdr.DValue dValue) { dValue.Set(Value); }
public static void Run(ulong i0, ref mdr.DValue result) { result.Set(i0); }
public static void Run(/*const*/ ref mdr.DValue i0, bool i1, ref mdr.DValue result) { throw new NotImplementedException(); }
public static void Run(mdr.DObject i0, /*const*/ ref mdr.DValue i1, ref mdr.DValue result) { throw new NotImplementedException(); }
public JSArray() : base(mdr.Runtime.Instance.DArrayPrototype, "Array") { JittedCode = (ref mdr.CallFrame callFrame) => { mdr.DArray array; var argsCount = callFrame.PassedArgsCount; if (argsCount == 1) { var len = Operations.Convert.ToInt32.Run(ref callFrame.Arg0); array = new mdr.DArray(len); } else { array = new mdr.DArray(argsCount); switch (argsCount) { case 0: break; case 1: break; case 2: array.Elements[1] = callFrame.Arg1; array.Elements[0] = callFrame.Arg0; break; case 3: array.Elements[2] = callFrame.Arg2; goto case 2; case 4: array.Elements[3] = callFrame.Arg3; goto case 3; default: Debug.Assert(argsCount > mdr.CallFrame.InlineArgsCount, "Code gen must be updated to support new CallFrame"); Array.Copy(callFrame.Arguments, 0, array.Elements, mdr.CallFrame.InlineArgsCount, argsCount - mdr.CallFrame.InlineArgsCount); goto case 4; } } if (IsConstrutor) callFrame.This = (array); else callFrame.Return.Set(array); }; // ECMA-262 section 15.4.3.1 this.DefineOwnProperty("isArray", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.isArray"); if (callFrame.This.ValueType == mdr.ValueTypes.Array) callFrame.Return.Set(true); else callFrame.Return.Set(false); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.2 TargetPrototype.DefineOwnProperty("toString", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.toString"); var join = callFrame.This.GetField("join"); if (join.ValueType == mdr.ValueTypes.Function)// it is callable { var joinFun = join.AsDFunction(); Debug.Assert(joinFun != null, "Invalid situation!"); callFrame.Function = joinFun; //callFrame.This is already set callFrame.Signature = mdr.DFunctionSignature.EmptySignature; callFrame.PassedArgsCount = 0; callFrame.Arguments = null; joinFun.Call(ref callFrame); callFrame.Return.Set(callFrame.Return.AsString()); } else callFrame.Return.Set(callFrame.This.ToString()); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.3 TargetPrototype.DefineOwnProperty("toLocaleString", new mdr.DFunction((ref mdr.CallFrame callFrame) => { throw new NotImplementedException("Array.toLocaleString is not implemented"); // TODO: callFrame.This is not an accurate implementation /*mdr.DObject array = callFrame.This; mdr.DFunction join = array.GetField("join").ToDObject() as mdr.DFunction; if (join != null) // it is callable { callFrame.Function = join; callFrame.Signature = mdr.DFunctionSignature.EmptySignature; callFrame.Arguments = null; join.Call(ref callFrame); callFrame.Return.Set(callFrame.Return.ToString()); //TODO: is this the right implementation? } else callFrame.Return.Set(array.ToString());*/ }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.4 TargetPrototype.DefineOwnProperty("concat", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.concat"); //The most common case is calling .concat on array object with normal set of arguments mdr.DArray newArray; var destStartIndex = 0; var thisArray = callFrame.This as mdr.DArray; if(thisArray != null) { newArray = new mdr.DArray(callFrame.PassedArgsCount + thisArray.Length); Array.Copy(thisArray.Elements, 0, newArray.Elements, 0, thisArray.Length); destStartIndex = thisArray.Length; } else { newArray = new mdr.DArray(callFrame.PassedArgsCount + 1); newArray.Elements[0].Set(callFrame.This); destStartIndex = 1; } for (int i = 0; i < callFrame.PassedArgsCount; ++i) { newArray.Elements[destStartIndex] = callFrame.Arg(i); //This is the common case if (newArray.Elements[destStartIndex].ValueType == mdr.ValueTypes.Array) { var array = newArray.Elements[destStartIndex].AsDArray(); //We had already accounted 1 cell for this item, so, we add the missing remaining elements newArray.Length += (array.Length - 1); //Extends newArray.Elements Array.Copy(array.Elements, 0, newArray.Elements, destStartIndex, array.Length); destStartIndex += array.Length; } else ++destStartIndex; } //concat(newArray, ref callFrame.Arguments[i]); callFrame.Return.Set(newArray); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.5 TargetPrototype.DefineOwnProperty("join", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.join"); string separator = (callFrame.PassedArgsCount == 0 || callFrame.Arg0.ValueType == mdr.ValueTypes.Undefined) ? "," : callFrame.Arg0.AsString(); callFrame.Return.Set(join(callFrame.This, separator).ToString()); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.6 TargetPrototype.DefineOwnProperty("pop", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.pop"); var This = callFrame.This; var lenField = This.GetField("length"); int len = Operations.Convert.ToInt32.Run(ref lenField); if (len == 0) { This.SetField("length", 0); callFrame.Return.Set(mdr.Runtime.Instance.DefaultDUndefined); } else if (len > 0) { var index = len - 1; mdr.DValue element = new mdr.DValue(); This.GetField(index, ref element); This.DeletePropertyDescriptor(index.ToString()); This.SetField("length", index); callFrame.Return.Set(ref element); } }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.7 TargetPrototype.DefineOwnProperty("push", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.push"); var This = callFrame.This; var lenField = This.GetField("length"); int len = Operations.Convert.ToInt32.Run(ref lenField); mdr.DValue arg = new mdr.DValue(); for (int i = 0; i < callFrame.PassedArgsCount; ++i) { arg = callFrame.Arg(i); This.SetField(len, ref arg); len++; } This.SetField("length", len); callFrame.Return.Set(len); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.8 TargetPrototype.DefineOwnProperty("reverse", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.reverse"); var This = callFrame.This; var lenField = This.GetField("length"); int len = Operations.Convert.ToInt32.Run(ref lenField); int middle = len / 2; mdr.DValue lowerValue = new mdr.DValue(); mdr.DValue upperValue = new mdr.DValue(); bool lowerExists, upperExists; for (int lower = 0; lower != middle; lower++) { int upper = len - lower - 1; lowerExists = This.HasProperty(lower); upperExists = This.HasProperty(upper); if (lowerExists && upperExists) { This.GetField(lower, ref lowerValue); This.GetField(upper, ref upperValue); This.SetField(lower, ref upperValue); This.SetField(upper, ref lowerValue); } else if (!lowerExists && upperExists) { This.GetField(upper, ref upperValue); This.SetField(lower, ref upperValue); This.DeletePropertyDescriptor(upper.ToString()); } else if (lowerExists && !upperExists) { This.GetField(lower, ref lowerValue); This.SetField(upper, ref lowerValue); This.DeletePropertyDescriptor(lower.ToString()); } } callFrame.Return.Set(This); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.9 TargetPrototype.DefineOwnProperty("shift", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.shift"); mdr.DArray array = callFrame.This.ToDArray(); int len = array.Length; if (array == null || array.Length == 0) //callFrame.Return.ValueType = mdr.ValueTypes.Undefined; callFrame.Return.Set(mdr.Runtime.Instance.DefaultDUndefined); else { callFrame.Return.Set(ref array.Elements[0]); for (int k = 1; k < len; k++) array.Elements[k - 1].Set(ref array.Elements[k]); array.Length--; } }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.10 TargetPrototype.DefineOwnProperty("slice", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.slice"); /* TODO: This is the implementation for a case that "this" is a DArray. Use this faster implementation after adding PackedArray optimization. mdr.DArray array = callFrame.This.ToDArray(); int len = array.Length; int relativeStart = callFrame.Arg0.ToInt32(); int k = (relativeStart < 0) ? Math.Max(len + relativeStart, 0) : Math.Min(relativeStart, len); int relativeEnd = (callFrame.Arg1.ValueType == mdr.ValueTypes.Undefined) ? len : callFrame.Arg1.ToInt32(); int final = (relativeEnd < 0) ? Math.Max(relativeEnd + len, 0) : Math.Min(relativeEnd, len); mdr.DArray newArray = new mdr.DArray((final - k > 0) ? (final - k) : 0); for (int n = 0; k < final; k++, n++) newArray.Elements[n].Set(ref array.Elements[k]); callFrame.Return.Set(newArray); */ var This = callFrame.This; var lenField = This.GetField("length"); int len = Operations.Convert.ToInt32.Run(ref lenField); int relativeStart = 0; if (callFrame.PassedArgsCount > 0 ) relativeStart = Operations.Convert.ToInt32.Run(ref callFrame.Arg0); int k = (relativeStart < 0) ? Math.Max(len + relativeStart, 0) : Math.Min(relativeStart, len); int relativeEnd = ((callFrame.Arg1.ValueType == mdr.ValueTypes.Undefined) || (callFrame.PassedArgsCount < 2)) ? len : Operations.Convert.ToInt32.Run(ref callFrame.Arg1 ); int final = (relativeEnd < 0) ? Math.Max(relativeEnd + len, 0) : Math.Min(relativeEnd, len); mdr.DArray newArray = new mdr.DArray((final - k > 0) ? (final - k) : 0); mdr.DValue item = new mdr.DValue(); for (int n = 0; k < final; k++, n++) { This.GetField(k, ref item); newArray.Elements[n].Set(ref item); } callFrame.Return.Set(newArray); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.12 //TODO: splice is generic and can be applied to other objects TargetPrototype.DefineOwnProperty("splice", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.splice"); if (callFrame.PassedArgsCount < 2) { callFrame.Return.Set(JSRuntime.Instance.DefaultDUndefined); return; } var A = new mdr.DArray(); var This = callFrame.This as mdr.DArray; if (This == null) throw new Exception("Object is not an array, but splice must work with generic objects. Please fix it!"); int len = This.Length; int relativeStart = Operations.Convert.ToInt32.Run(ref callFrame.Arg0); int actualStart = relativeStart < 0 ? Math.Max(len + relativeStart, 0) : Math.Min(relativeStart, len); int actualDeleteCount = Math.Min(Math.Max(Operations.Convert.ToInt32.Run(ref callFrame.Arg1), 0), len - actualStart); A.Length = actualDeleteCount; for (int k = 0; k < actualDeleteCount; k++) { int from = relativeStart + k; if (from < len) A.Elements[k].Set(ref This.Elements[from]); } int itemCount = callFrame.PassedArgsCount - 2; if (itemCount < actualDeleteCount) { for (int k = actualStart; k < len - actualDeleteCount; k++) { int from = k + actualDeleteCount; int to = k + itemCount; // if (from < len) // This condition will always hold This.Elements[to].Set(ref This.Elements[from]); // from will always be less than less and therefore the element exists in the array //TODO: can we assume any index less than Length exist? When an element is deleted from middle of the Elements, is Length adjusted? /* else { This.RemoveElements(to, len - actualDeleteCount - k); break; }*/ } This.RemoveElements(len - actualDeleteCount + itemCount, actualDeleteCount - itemCount); This.Length = len - actualDeleteCount + itemCount; } else if (itemCount > actualDeleteCount) { This.Length = len - actualDeleteCount + itemCount; for (int k = len - actualDeleteCount; k > actualStart; k--) { int from = k + actualDeleteCount - 1; int to = k + itemCount - 1; //if (from < len) //This condition will always hold This.Elements[to].Set(ref This.Elements[from]); } } for (int k = 0; k < itemCount; k++) This.Elements[k + actualStart] = callFrame.Arg(k + 2); callFrame.Return.Set(A); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.11 TargetPrototype.DefineOwnProperty("sort", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.sort"); mdr.DArray array = callFrame.This.ToDArray(); int len = array.Length; if (len == 0) callFrame.Return.Set(array); int argsCount = callFrame.PassedArgsCount; mdr.DValue function = callFrame.Arg0; for (uint i = 0; i < len - 1; ++i) { mdr.DValue iObj = array.Elements[i]; uint themin = i; mdr.DValue minObj = iObj; for (uint j = i + 1; j < len; ++j) { mdr.DValue jObj = array.Elements[j]; double compareResult = 0; if (jObj.ValueType == mdr.ValueTypes.Undefined) compareResult = 1; else if (minObj.ValueType == mdr.ValueTypes.Undefined) compareResult = -1; else if (argsCount == 1 && function.ValueType == mdr.ValueTypes.Function) { callFrame.Function = function.AsDFunction(); callFrame.SetArg(0, ref minObj); callFrame.SetArg(1, ref jObj); callFrame.PassedArgsCount = 2; callFrame.Signature = new mdr.DFunctionSignature(ref callFrame, 2); callFrame.Function.Call(ref callFrame); compareResult = Operations.Convert.ToInt32.Run(ref callFrame.Return) <= 0 ? 1 : -1; } else { mdr.DValue v1 = mdr.DValue.Create(jObj.AsString()); mdr.DValue v2 = mdr.DValue.Create(minObj.AsString()); compareResult = Operations.Binary.LessThan.Run(ref v1, ref v2) ? -1 : 1; } if (compareResult < 0) { themin = j; minObj = jObj; } } if (themin > i) { array.Elements[i] = minObj; array.Elements[themin] = iObj; } } callFrame.Return.Set(array); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.13 TargetPrototype.DefineOwnProperty("unshift", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.unshift"); var thisObj = callFrame.This; mdr.DArray array = thisObj.ToDArray(); int len = array.Length; int argsCount = callFrame.PassedArgsCount; array.ResizeElements(len + argsCount); array.Length = len + argsCount; if (argsCount != 0 && len != 0) { mdr.DValue iObj; for (int i = len; i > 0; --i) { iObj = array.Elements[i - 1]; array.Elements[i - 1].Set(0); array.Elements[i + argsCount - 1] = iObj; } } for (int k = 0; k < argsCount; ++k) { array.Elements[k] = callFrame.Arg(k); } callFrame.Return.Set(array.Length); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.14 TargetPrototype.DefineOwnProperty("indexOf", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.indexOf"); mdr.DArray array = callFrame.This.ToDArray(); int len = array.Length; int index = 0; if (callFrame.PassedArgsCount > 1) index = Operations.Convert.ToInt32.Run(ref callFrame.Arg1); index = index < 0 ? Math.Max(len + index, 0) : Math.Min(index, len); mdr.DValue searchElem = callFrame.Arg0; for (; index < len; ++index) { mdr.DValue indexElem = array.Elements[index]; if (indexElem.ValueType != mdr.ValueTypes.Undefined && Operations.Binary.Equal.Run(ref indexElem, ref searchElem)) { callFrame.Return.Set(index); return; } } callFrame.Return.Set(-1); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.15 TargetPrototype.DefineOwnProperty("lastIndexOf", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.lastIndexOf"); mdr.DArray array = callFrame.This.ToDArray(); int len = array.Length; if (len == 0) { callFrame.Return.Set(-1); return; } int index = len - 1; if (callFrame.PassedArgsCount > 1) index = Operations.Convert.ToInt32.Run(ref callFrame.Arg1); index = index < 0 ? len + index : Math.Min(index, len - 1); if (index < 0) { callFrame.Return.Set(-1); return; } mdr.DValue searchElem = callFrame.Arg0; do { mdr.DValue indexElem = array.Elements[index]; if (indexElem.ValueType != mdr.ValueTypes.Undefined && Operations.Binary.Equal.Run(ref indexElem, ref searchElem)) { callFrame.Return.Set(index); return; } } while (index-- > 0); callFrame.Return.Set(-1); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.16 TargetPrototype.DefineOwnProperty("every", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.every"); var thisObj = callFrame.This; mdr.DArray array = thisObj.ToDArray(); int len = array.Length; if (len == 0) callFrame.Return.Set(array); // TODO: Commented because argsCount is unused. /*int argsCount = callFrame.ArgsCount;*/ mdr.DFunction function = callFrame.Arg0.AsDFunction(); bool result = true; for (int i = 0; i < len; ++i) { if (array.Elements[i].ValueType != mdr.ValueTypes.Undefined) { callFrame.Function = function; callFrame.SetArg(0, ref array.Elements[i]); callFrame.SetArg(1, i); callFrame.SetArg(2, thisObj); callFrame.Signature = new mdr.DFunctionSignature(ref callFrame, 3); callFrame.Function.Call(ref callFrame); if (Operations.Convert.ToBoolean.Run(ref callFrame.Return) == false) { result = false; break; } } } callFrame.Return.Set(result); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.17 TargetPrototype.DefineOwnProperty("some", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.some"); var thisObj = callFrame.This; mdr.DArray array = thisObj.ToDArray(); int len = array.Length; if (len == 0) callFrame.Return.Set(array); // TODO: Commented because argsCount is unused. /*int argsCount = callFrame.ArgsCount;*/ mdr.DFunction function = callFrame.Arg0.AsDFunction(); bool result = false; for (int i = 0; i < len; ++i) { if (array.Elements[i].ValueType != mdr.ValueTypes.Undefined) { callFrame.Function = function; callFrame.SetArg(0, ref array.Elements[i]); callFrame.SetArg(1, i); callFrame.SetArg(2, thisObj); callFrame.Signature = new mdr.DFunctionSignature(ref callFrame, 3); callFrame.Function.Call(ref callFrame); if (Operations.Convert.ToBoolean.Run(ref callFrame.Return) == true) { result = true; break; } } } callFrame.Return.Set(result); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.18 TargetPrototype.DefineOwnProperty("forEach", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.forEach"); mdr.DArray array = callFrame.This.ToDArray(); int len = array.Length; if (len == 0) callFrame.Return.Set(array); mdr.DFunction function = callFrame.Arg0.AsDFunction(); // TODO: Commented because thisArg is unused. /*mdr.DValue thisArg; if (callFrame.ArgsCount > 1) thisArg = callFrame.Arg1; else thisArg = new mdr.DValue();*/ for (int i = 0; i < len; ++i) { if (array.Elements[i].ValueType != mdr.ValueTypes.Undefined) { callFrame.Function = function; callFrame.PassedArgsCount = 3; callFrame.SetArg(0, ref array.Elements[i]); callFrame.SetArg(1, i); callFrame.SetArg(2, array); callFrame.Signature = new mdr.DFunctionSignature(ref callFrame, 3); callFrame.Function.Call(ref callFrame); } } callFrame.Return.Set(mdr.Runtime.Instance.DefaultDUndefined); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); // ECMA-262 section 15.4.4.19 TargetPrototype.DefineOwnProperty("map", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Debug.WriteLine("Calling JSArray.map"); mdr.DArray array = callFrame.This.ToDArray(); int len = array.Length; if (len == 0) callFrame.Return.Set(array); mdr.DFunction function = callFrame.Arg0.AsDFunction(); mdr.DObject thisArg; if (callFrame.PassedArgsCount > 1) thisArg = Operations.Convert.ToObject.Run(ref callFrame.Arg1); else thisArg = mdr.Runtime.Instance.GlobalContext; mdr.DArray newarray = new mdr.DArray(len); for (int i = 0; i < len; ++i) { if (array.Elements[i].ValueType != mdr.ValueTypes.Undefined) { callFrame.Function = function; callFrame.This = thisArg; callFrame.PassedArgsCount = 3; callFrame.SetArg(0, ref array.Elements[i]); callFrame.SetArg(1, i); callFrame.SetArg(2, array); callFrame.Signature = new mdr.DFunctionSignature(ref callFrame, 3); callFrame.Function.Call(ref callFrame); newarray.Elements[i] = callFrame.Return; } } callFrame.Return.Set(newarray); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); TargetPrototype.DefineOwnProperty("filter", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Trace.Fail("Unimplemented"); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); TargetPrototype.DefineOwnProperty("reduce", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Trace.Fail("Unimplemented"); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); TargetPrototype.DefineOwnProperty("reduceRight", new mdr.DFunction((ref mdr.CallFrame callFrame) => { Trace.Fail("Unimplemented"); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); }
public JSNumber() : base(mdr.Runtime.Instance.DNumberPrototype, "Number") { JittedCode = (ref mdr.CallFrame callFrame) => { mdr.DValue number = new mdr.DValue(); if (callFrame.PassedArgsCount > 0) { Operations.Convert.ToNumber.Run(ref callFrame.Arg0, ref number); //double arg = callFrame.Arg0.ToDouble(); ////if (Math.Floor(arg) == arg) //this is an int (FIXME: What if it is passed as 23.0? Should we still treat it as int?) //// number.Set((int)arg); ////else //number.Set(arg); } else { number.Set(0); } if (IsConstrutor) { mdr.DObject objNumber = new mdr.DObject(TargetPrototype); objNumber.PrimitiveValue = number; //objNumber.Class = "Number"; callFrame.This = (objNumber); } else { callFrame.Return.Set(ref number); } }; this.DefineOwnProperty("MAX_VALUE", 1.7976931348623157E308, mdr.PropertyDescriptor.Attributes.NotConfigurable | mdr.PropertyDescriptor.Attributes.NotWritable | mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); this.DefineOwnProperty("MIN_VALUE", 5E-324, mdr.PropertyDescriptor.Attributes.NotConfigurable | mdr.PropertyDescriptor.Attributes.NotWritable | mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); this.DefineOwnProperty("NaN", double.NaN, mdr.PropertyDescriptor.Attributes.NotConfigurable | mdr.PropertyDescriptor.Attributes.NotWritable | mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); this.DefineOwnProperty("NEGATIVE_INFINITY", double.NegativeInfinity, mdr.PropertyDescriptor.Attributes.NotConfigurable | mdr.PropertyDescriptor.Attributes.NotWritable | mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); this.DefineOwnProperty("POSITIVE_INFINITY", double.PositiveInfinity, mdr.PropertyDescriptor.Attributes.NotConfigurable | mdr.PropertyDescriptor.Attributes.NotWritable | mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); TargetPrototype.DefineOwnProperty("toString", new mdr.DFunction((ref mdr.CallFrame callFrame) => { int radix = 10; if (callFrame.PassedArgsCount > 0) { radix = callFrame.Arg0.AsInt32(); } var number = Operations.Convert.ToDouble.Run(callFrame.This); callFrame.Return.Set(ToStringImpl(number, radix)); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); TargetPrototype.DefineOwnProperty("toLocaleString", new mdr.DFunction((ref mdr.CallFrame callFrame) => { double number = callFrame.This.ToDouble(); callFrame.Return.Set(ToStringImpl(number, 10)); }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); TargetPrototype.DefineOwnProperty("valueOf", new mdr.DFunction((ref mdr.CallFrame callFrame) => { if (callFrame.This.ValueType == mdr.ValueTypes.Int32) { callFrame.Return.Set(callFrame.This.ToInt32()); } else { callFrame.Return.Set(callFrame.This.ToDouble()); } }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); TargetPrototype.DefineOwnProperty("toFixed", new mdr.DFunction((ref mdr.CallFrame callFrame) => { int numFractionDigits = 0; if (callFrame.PassedArgsCount > 0) { numFractionDigits = callFrame.Arg0.AsInt32(); if (numFractionDigits < 0 || numFractionDigits > 20) { throw new ArgumentOutOfRangeException(); } } double number = callFrame.This.ToDouble(); if (double.IsNaN(number)) { callFrame.Return.Set("NaN"); } else { callFrame.Return.Set(number.ToString("f" + numFractionDigits, CultureInfo.InvariantCulture)); } }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); TargetPrototype.DefineOwnProperty("toExponential", new mdr.DFunction((ref mdr.CallFrame callFrame) => { int numFractionDigits = 0; if (callFrame.PassedArgsCount > 0) { numFractionDigits = callFrame.Arg0.AsInt32(); if (numFractionDigits < 0 || numFractionDigits > 20) { throw new ArgumentOutOfRangeException(); } } double number = callFrame.This.ToDouble(); if (double.IsNaN(number)) { callFrame.Return.Set("NaN"); } else { string format = String.Concat("#.", new String('0', numFractionDigits), "e+0"); callFrame.Return.Set(number.ToString(format, CultureInfo.InvariantCulture)); } }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); TargetPrototype.DefineOwnProperty("toPrecision", new mdr.DFunction((ref mdr.CallFrame callFrame) => { if (callFrame.PassedArgsCount == 0) { callFrame.Return.Set(callFrame.This.ToDouble().ToString()); } else { double number = callFrame.This.ToDouble(); if (double.IsNaN(number)) { callFrame.Return.Set("NaN"); } else if (double.IsPositiveInfinity(number)) { callFrame.Return.Set("Infinity"); } else if (double.IsNegativeInfinity(number)) { callFrame.Return.Set("-Infinity"); } else { int precision = 0; precision = callFrame.Arg0.AsInt32(); if (precision < 1 || precision > 21) { throw new ArgumentOutOfRangeException(); } //TODO: make sure the following is correct implementation! // Get the number of decimals string str = number.ToString("e23", CultureInfo.InvariantCulture); int decimals = str.IndexOfAny(new char[] { '.', 'e' }); decimals = decimals == -1 ? str.Length : decimals; precision -= decimals; precision = precision < 1 ? 1 : precision; callFrame.Return.Set(number.ToString("f" + precision, CultureInfo.InvariantCulture)); } } }), mdr.PropertyDescriptor.Attributes.NotEnumerable | mdr.PropertyDescriptor.Attributes.Data); }