diff --git a/NiL.JS/Core/Functions/ConstructorProxy.cs b/NiL.JS/Core/Functions/ConstructorProxy.cs index 7eac8509b..82de55edb 100644 --- a/NiL.JS/Core/Functions/ConstructorProxy.cs +++ b/NiL.JS/Core/Functions/ConstructorProxy.cs @@ -6,6 +6,7 @@ using NiL.JS.Backward; using NiL.JS.BaseLibrary; using NiL.JS.Core.Interop; +using NiL.JS.Expressions; namespace NiL.JS.Core.Functions { @@ -30,6 +31,8 @@ internal class ConstructorProxy : Function private const int passesCount = 3; private static readonly object[] _emptyObjectArray = new object[0]; + private static readonly Arguments _emptyArguments = new Arguments(); + internal readonly StaticProxy _staticProxy; private readonly MethodProxy[] _constructors; @@ -156,17 +159,36 @@ protected internal override bool DeleteProperty(JSValue name) return _staticProxy.DeleteProperty(name) && __proto__.DeleteProperty(name); } - protected internal override JSValue Invoke(bool construct, JSValue targetObject, Arguments arguments) + internal override JSValue InternalInvoke(JSValue targetObject, Expression[] arguments, Context initiator, bool withSpread, bool construct) { - var objc = targetObject as ObjectWrapper; - if (construct) // new + if (_functionDefinition._body == null) + return NotExists; + + var argumentsObject = arguments.Length == 0 ? _emptyArguments : Tools.CreateArguments(arguments, initiator); + + initiator._objectSource = null; + + if (construct) { + if (targetObject == null || targetObject._valueType < JSValueType.Object) + return Construct(argumentsObject); + return Construct(targetObject, argumentsObject); } else + return Call(targetObject, argumentsObject); + } + + public override JSValue Construct(Arguments arguments) + { + return Invoke(true, null, arguments); + } + + protected internal override JSValue Invoke(bool construct, JSValue targetObject, Arguments arguments) + { + if (!construct && _staticProxy._hostedType == typeof(Date)) { - if (_staticProxy._hostedType == typeof(Date)) - return new Date().ToString(); + return new Date().ToString(); } object obj; @@ -243,7 +265,6 @@ protected internal override JSValue Invoke(bool construct, JSValue targetObject, } JSValue res = obj as JSValue; - if (construct) { if (res != null) @@ -251,6 +272,7 @@ protected internal override JSValue Invoke(bool construct, JSValue targetObject, // Для Number, Boolean и String if (res._valueType < JSValueType.Object) { + var objc = (targetObject as ObjectWrapper ?? ConstructObject()) as ObjectWrapper; objc.instance = obj; if (objc._objectPrototype == null) objc._objectPrototype = res.__proto__; @@ -267,9 +289,8 @@ protected internal override JSValue Invoke(bool construct, JSValue targetObject, } else { - objc.instance = obj; + var objc = wrapObject(targetObject, obj); - objc._attributes |= _staticProxy._hostedType.GetTypeInfo().IsDefined(typeof(ImmutableAttribute), false) ? JSValueAttributesInternal.Immutable : JSValueAttributesInternal.None; if (obj.GetType() == typeof(Date)) objc._valueType = JSValueType.Date; else if (res != null) @@ -286,15 +307,23 @@ protected internal override JSValue Invoke(bool construct, JSValue targetObject, return res._oValue as JSValue; } - res = res ?? new ObjectWrapper(obj) + if (res == null) { - _attributes = JSValueAttributesInternal.SystemObject | (_staticProxy._hostedType.GetTypeInfo().IsDefined(typeof(ImmutableAttribute), false) ? JSValueAttributesInternal.Immutable : JSValueAttributesInternal.None) - }; + res = wrapObject(targetObject, obj); + } } return res; } + private ObjectWrapper wrapObject(JSValue targetObject, object obj) + { + var objc = (targetObject as ObjectWrapper ?? ConstructObject()) as ObjectWrapper; + objc.instance = obj; + objc._attributes |= _staticProxy._hostedType.GetTypeInfo().IsDefined(typeof(ImmutableAttribute), false) ? JSValueAttributesInternal.Immutable : JSValueAttributesInternal.None; + return objc; + } + protected internal override JSValue ConstructObject() { return new ObjectWrapper(null) @@ -328,7 +357,7 @@ private MethodProxy findConstructor(Arguments arguments, out object[] args) args = _constructors[i].ConvertArguments( arguments, (pass >= 1 ? 0 : ConvertArgsOptions.StrictConversion) - | (pass >= 2 ? ConvertArgsOptions.DummyValues : 0)); + | (pass >= 2 ? ConvertArgsOptions.AllowDefaultValues : 0)); if (args == null) continue; diff --git a/NiL.JS/Core/Functions/MethodGroup.cs b/NiL.JS/Core/Functions/MethodGroup.cs index 29da9d987..062c8c3df 100644 --- a/NiL.JS/Core/Functions/MethodGroup.cs +++ b/NiL.JS/Core/Functions/MethodGroup.cs @@ -88,7 +88,7 @@ protected internal override JSValue Invoke(bool construct, JSValue targetObject, args = _methods[i].ConvertArguments( arguments, (pass >= 1 ? ConvertArgsOptions.Default : ConvertArgsOptions.StrictConversion) - | (pass >= 2 ? ConvertArgsOptions.DummyValues : ConvertArgsOptions.Default)); + | (pass >= 2 ? ConvertArgsOptions.AllowDefaultValues : ConvertArgsOptions.Default)); if (args == null) continue; diff --git a/NiL.JS/Core/Functions/MethodProxy.cs b/NiL.JS/Core/Functions/MethodProxy.cs index 1a70cd183..39af91d39 100644 --- a/NiL.JS/Core/Functions/MethodProxy.cs +++ b/NiL.JS/Core/Functions/MethodProxy.cs @@ -18,7 +18,7 @@ internal enum ConvertArgsOptions Default = 0, ThrowOnError = 1, StrictConversion = 2, - DummyValues = 4 + AllowDefaultValues = 4 } internal delegate object WrapperDelegate(object target, Context initiator, Expressions.Expression[] arguments, Arguments argumentsObject); @@ -253,7 +253,7 @@ private WrapperDelegate makeFastWrapper(MethodInfo methodInfo) } else { - if ((_parameters.Length == 1 || (_parameters.Length == 2 && _forceInstance)) + if ((_parameters.Length == 1 || (_parameters.Length == 2 && _forceInstance)) && _parameters[_parameters.Length - 1].ParameterType == typeof(Arguments)) { var argumentsObject = Expression.Condition( @@ -477,6 +477,13 @@ internal override JSValue InternalInvoke(JSValue targetValue, Expressions.Expres } object value = invokeMethod(targetValue, argumentsSource, null, initiator); + + if (value is not null + && targetValue is not null + && (value is not JSValue jsval || jsval._valueType == targetValue._valueType) + && value == targetValue.Value) + return targetValue; + return Context.GlobalContext.ProxyValue(value); } @@ -573,7 +580,7 @@ private object processArgument(Expressions.Expression[] arguments, Context initi #endif private object convertArgument(int index, JSValue value) { - var cvtArgs = ConvertArgsOptions.ThrowOnError; + var cvtArgs = ConvertArgsOptions.ThrowOnError | ConvertArgsOptions.AllowDefaultValues; if (_strictConversion) cvtArgs |= ConvertArgsOptions.StrictConversion; @@ -603,10 +610,10 @@ private object convertArgument(int index, JSValue value, ConvertArgsOptions opti result = Tools.ConvertJStoObj(value, parameterType, !strictConversion); if (strictConversion && result == null) { - if (options.HasFlag(ConvertArgsOptions.ThrowOnError)) + if ((options & ConvertArgsOptions.ThrowOnError) != 0) ExceptionHelper.ThrowTypeError("Unable to convert " + value + " to type " + parameterType); - if (!options.HasFlag(ConvertArgsOptions.DummyValues)) + if ((options & ConvertArgsOptions.AllowDefaultValues) == 0) return null; } } @@ -616,7 +623,11 @@ private object convertArgument(int index, JSValue value, ConvertArgsOptions opti return value; } - if (result == null && _restPrmsArrayCreator == null && (options.HasFlag(ConvertArgsOptions.DummyValues) || parameterInfo.Attributes.HasFlag(ParameterAttributes.HasDefault))) + if (result == null + && _restPrmsArrayCreator == null + && (options & ConvertArgsOptions.AllowDefaultValues) != 0 + && ((parameterInfo.Attributes & ParameterAttributes.HasDefault) != 0 + || parameterInfo.ParameterType.IsValueType)) { result = parameterInfo.DefaultValue;