Example #1
0
        /// <summary>
        /// https://tc39.es/ecma262/#sec-ordinarycallbindthis
        /// </summary>
        internal void OrdinaryCallBindThis(ExecutionContext calleeContext, JsValue thisArgument)
        {
            var thisMode = _thisMode;

            if (thisMode == FunctionThisMode.Lexical)
            {
                return;
            }

            var calleeRealm = _realm;

            var localEnv = (FunctionEnvironmentRecord)calleeContext.LexicalEnvironment;

            JsValue thisValue;

            if (_thisMode == FunctionThisMode.Strict)
            {
                thisValue = thisArgument;
            }
            else
            {
                if (thisArgument is null || thisArgument.IsNullOrUndefined())
                {
                    var globalEnv = calleeRealm.GlobalEnv;
                    thisValue = globalEnv.GlobalThisValue;
                }
Example #2
0
        public static string ConvertToString(this JsValue self)
        {
            if (self.IsNullOrUndefined())
            {
                return(null);
            }

            return(TypeConverter.ToString(self));
        }
Example #3
0
        public static double?ConvertToDouble(this JsValue self)
        {
            if (self.IsNullOrUndefined())
            {
                return(null);
            }

            return(TypeConverter.ToNumber(self));
        }
Example #4
0
        public static long?ConvertToInt64(this JsValue self)
        {
            if (self.IsNullOrUndefined())
            {
                return(null);
            }

            return((long)TypeConverter.ToInteger(self));
        }
Example #5
0
        public static int?ConvertToInt32(this JsValue self)
        {
            if (self.IsNullOrUndefined())
            {
                return(null);
            }

            return(TypeConverter.ToInt32(self));
        }
Example #6
0
        public static bool?ConvertToBoolean(this JsValue self)
        {
            if (self.IsNullOrUndefined())
            {
                return(null);
            }

            return(TypeConverter.ToBoolean(self));
        }
        private JsValue Fill(JsValue thisObj, JsValue[] arguments)
        {
            if (thisObj.IsNullOrUndefined())
            {
                ExceptionHelper.ThrowTypeError(_engine, "Cannot convert undefined or null to object");
            }

            var operations = ArrayOperations.For(thisObj as ObjectInstance);
            var length     = operations.GetLength();

            var value = arguments.At(0);

            var start = ConvertAndCheckForInfinity(arguments.At(1), 0);

            var  relativeStart = TypeConverter.ToInteger(start);
            uint actualStart;

            if (relativeStart < 0)
            {
                actualStart = (uint)System.Math.Max(length + relativeStart, 0);
            }
            else
            {
                actualStart = (uint)System.Math.Min(relativeStart, length);
            }

            var  end         = ConvertAndCheckForInfinity(arguments.At(2), length);
            var  relativeEnd = TypeConverter.ToInteger(end);
            uint actualEnd;

            if (relativeEnd < 0)
            {
                actualEnd = (uint)System.Math.Max(length + relativeEnd, 0);
            }
            else
            {
                actualEnd = (uint)System.Math.Min(relativeEnd, length);
            }

            for (var i = actualStart; i < actualEnd; ++i)
            {
                operations.Set(i, value, updateLength: false, throwOnError: false);
            }

            return(thisObj);
        }
        private JsValue CopyWithin(JsValue thisObj, JsValue[] arguments)
        {
            // Steps 1-2.
            if (thisObj.IsNullOrUndefined())
            {
                return(ExceptionHelper.ThrowTypeError <JsValue>(_engine, "this is null or not defined"));
            }

            JsValue target = arguments.At(0);
            JsValue start  = arguments.At(1);
            JsValue end    = arguments.At(2);

            var operations    = ArrayOperations.For(thisObj as ObjectInstance);
            var initialLength = operations.GetLength();
            var len           = ConvertAndCheckForInfinity(initialLength, 0);

            var relativeTarget = ConvertAndCheckForInfinity(target, 0);

            var to = relativeTarget < 0 ?
                     System.Math.Max(len + relativeTarget, 0) :
                     System.Math.Min(relativeTarget, len);

            var relativeStart = ConvertAndCheckForInfinity(start, 0);

            var from = relativeStart < 0 ?
                       System.Math.Max(len + relativeStart, 0) :
                       System.Math.Min(relativeStart, len);

            var relativeEnd = ConvertAndCheckForInfinity(end, len);

            var final = relativeEnd < 0 ?
                        System.Math.Max(len + relativeEnd, 0) :
                        System.Math.Min(relativeEnd, len);

            var count = System.Math.Min(final - from, len - to);

            var direction = 1;

            if (from < to && to < from + count)
            {
                direction = -1;
                from     += (uint)count - 1;
                to       += (uint)count - 1;
            }

            while (count > 0)
            {
                var fromPresent = operations.HasProperty((ulong)from);
                if (fromPresent)
                {
                    var fromValue = operations.Get((ulong)from);
                    operations.Set((ulong)to, fromValue, updateLength: true, throwOnError: true);
                }
                else
                {
                    operations.DeletePropertyOrThrow((ulong)to);
                }
                from = (uint)(from + direction);
                to   = (uint)(to + direction);
                count--;
            }

            return(thisObj);
        }
Example #9
0
        protected override ExpressionResult EvaluateInternal(EvaluationContext context)
        {
            JsValue actualThis        = null;
            string  baseReferenceName = null;
            JsValue baseValue         = null;
            var     isStrictModeCode  = StrictModeScope.IsStrictModeCode;

            var engine = context.Engine;

            if (_objectExpression is JintIdentifierExpression identifierExpression)
            {
                baseReferenceName = identifierExpression._expressionName.Key.Name;
                var strict = isStrictModeCode;
                var env    = engine.ExecutionContext.LexicalEnvironment;
                JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
                    env,
                    identifierExpression._expressionName,
                    strict,
                    out _,
                    out baseValue);
            }
            else if (_objectExpression is JintThisExpression thisExpression)
            {
                baseValue = thisExpression.GetValue(context).Value;
            }
            else if (_objectExpression is JintSuperExpression)
            {
                var env = (FunctionEnvironmentRecord)engine.ExecutionContext.GetThisEnvironment();
                actualThis = env.GetThisBinding();
                baseValue  = env.GetSuperBase();
            }

            if (baseValue is null)
            {
                // fast checks failed
                var baseReference = _objectExpression.Evaluate(context).Value;
                if (ReferenceEquals(Undefined.Instance, baseReference))
                {
                    return(NormalCompletion(Undefined.Instance));
                }
                if (baseReference is Reference reference)
                {
                    baseReferenceName = reference.GetReferencedName().ToString();
                    baseValue         = engine.GetValue(reference, false);
                    engine._referencePool.Return(reference);
                }
                else
                {
                    baseValue = engine.GetValue(baseReference, false);
                }
            }

            if (baseValue.IsNullOrUndefined() && (_memberExpression.Optional || _objectExpression._expression.IsOptional()))
            {
                return(NormalCompletion(Undefined.Instance));
            }

            var property = _determinedProperty ?? _propertyExpression.GetValue(context).Value;

            if (baseValue.IsNullOrUndefined())
            {
                // we can use base data types securely, object evaluation can mess things up
                var referenceName = property.IsPrimitive()
                    ? TypeConverter.ToString(property)
                    : _determinedProperty?.ToString() ?? baseReferenceName;

                TypeConverter.CheckObjectCoercible(engine, baseValue, _memberExpression.Property, referenceName);
            }

            // only convert if necessary
            var propertyKey = property.IsInteger() && baseValue.IsIntegerIndexedArray
                ? property
                : TypeConverter.ToPropertyKey(property);

            var rent = context.Engine._referencePool.Rent(baseValue, propertyKey, isStrictModeCode, thisValue: actualThis);

            return(new ExpressionResult(
                       ExpressionCompletionType.Reference,
                       rent,
                       _expression.Location));
        }
        /// <summary>
        /// https://tc39.es/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist
        /// </summary>
        public override JsValue Call(JsValue thisArgument, JsValue[] arguments)
        {
            // ** PrepareForOrdinaryCall **
            // var callerContext = _engine.ExecutionContext;
            // Let calleeRealm be F.[[Realm]].
            // Set the Realm of calleeContext to calleeRealm.
            // Set the ScriptOrModule of calleeContext to F.[[ScriptOrModule]].
            var localEnv = LexicalEnvironment.NewFunctionEnvironment(_engine, this, Undefined);

            // If callerContext is not already suspended, suspend callerContext.
            // Push calleeContext onto the execution context stack; calleeContext is now the running execution context.
            // NOTE: Any exception objects produced after this point are associated with calleeRealm.
            // Return calleeContext.

            _engine.EnterExecutionContext(localEnv, localEnv);

            // ** OrdinaryCallBindThis **

            JsValue thisValue;

            if (_thisMode == FunctionThisMode.Strict)
            {
                thisValue = thisArgument;
            }
            else
            {
                if (thisArgument.IsNullOrUndefined())
                {
                    var globalEnv    = _engine.GlobalEnvironment;
                    var globalEnvRec = (GlobalEnvironmentRecord)globalEnv._record;
                    thisValue = globalEnvRec.GlobalThisValue;
                }
                else
                {
                    thisValue = TypeConverter.ToObject(_engine, thisArgument);
                }
            }

            var envRec = (FunctionEnvironmentRecord)localEnv._record;

            envRec.BindThisValue(thisValue);

            // actual call

            var strict = _thisMode == FunctionThisMode.Strict || _engine._isStrict;

            using (new StrictModeScope(strict, true))
            {
                try
                {
                    var argumentsInstance = _engine.FunctionDeclarationInstantiation(
                        functionInstance: this,
                        arguments,
                        localEnv);

                    var result = _function.Execute();
                    var value  = result.GetValueOrDefault().Clone();
                    argumentsInstance?.FunctionWasCalled();

                    if (result.Type == CompletionType.Throw)
                    {
                        ExceptionHelper.ThrowJavaScriptException(_engine, value, result);
                    }

                    if (result.Type == CompletionType.Return)
                    {
                        return(value);
                    }
                }
                finally
                {
                    _engine.LeaveExecutionContext();
                }

                return(Undefined);
            }
        }