Example #1
0
        public override IEnumerable <KeyValuePair <string, PropertyDescriptor> > GetOwnProperties()
        {
            if (_length != null)
            {
                yield return(new KeyValuePair <string, PropertyDescriptor>(PropertyNameLength, _length));
            }

            if (_dense != null)
            {
                var length = System.Math.Min(_dense.Length, GetLength());
                for (var i = 0; i < length; i++)
                {
                    if (_dense[i] != null)
                    {
                        yield return(new KeyValuePair <string, PropertyDescriptor>(TypeConverter.ToString(i), _dense[i]));
                    }
                }
            }
            else
            {
                foreach (var entry in _sparse)
                {
                    yield return(new KeyValuePair <string, PropertyDescriptor>(TypeConverter.ToString(entry.Key), entry.Value));
                }
            }

            foreach (var entry in base.GetOwnProperties())
            {
                yield return(entry);
            }
        }
Example #2
0
        public bool TryGetValue(uint index, out JsValue value)
        {
            value = Undefined;

            PropertyDescriptor desc;

            TryGetDescriptor(index, out desc);
            desc = desc ?? GetProperty(TypeConverter.ToString(index)) ?? PropertyDescriptor.Undefined;
            return(desc.TryGetValue(this, out value));
        }
Example #3
0
        internal uint Push(JsValue[] arguments)
        {
            var initialLength = GetLength();
            var newLength     = initialLength + arguments.Length;

            // if we see that we are bringing more than normal growth algorithm handles, ensure capacity eagerly
            if (_dense != null &&
                initialLength != 0 &&
                arguments.Length > initialLength * 2 &&
                newLength <= MaxDenseArrayLength)
            {
                EnsureCapacity((uint)newLength);
            }

            double n = initialLength;

            for (var i = 0; i < arguments.Length; i++)
            {
                var desc = new PropertyDescriptor(arguments[i], PropertyFlag.ConfigurableEnumerableWritable);
                if (_dense != null && n < _dense.Length)
                {
                    _dense[(int)n] = desc;
                }
                else if (n < uint.MaxValue)
                {
                    WriteArrayValue((uint)n, desc);
                }
                else
                {
                    DefineOwnProperty(TypeConverter.ToString((uint)n), desc, true);
                }
                n++;
            }

            // check if we can set length fast without breaking ECMA specification
            if (n < uint.MaxValue && CanPut(PropertyNameLength))
            {
                _length.Value = (uint)n;
            }
            else
            {
                Put(PropertyNameLength, newLength, true);
            }

            return((uint)n);
        }
Example #4
0
        /// <inheritdoc />
        internal override bool FindWithCallback(
            JsValue[] arguments,
            out uint index,
            out JsValue value)
        {
            var len = GetLength();

            if (len == 0)
            {
                index = 0;
                value = Undefined;
                return(false);
            }

            var callbackfn = arguments.At(0);
            var thisArg    = arguments.At(1);
            var callable   = GetCallable(callbackfn);

            var args = _engine._jsValueArrayPool.RentArray(3);

            args[2] = this;
            for (uint k = 0; k < len; k++)
            {
                var kvalue = args[0];
                if (TryGetValue(k, out kvalue))
                {
                    args[0] = kvalue;
                    args[1] = k;
                    var testResult = callable.Call(thisArg, args);
                    if (TypeConverter.ToBoolean(testResult))
                    {
                        index = k;
                        value = kvalue;
                        return(true);
                    }
                }
            }

            _engine._jsValueArrayPool.ReturnArray(args);

            index = 0;
            value = Undefined;
            return(false);
        }
Example #5
0
        public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
        {
            var oldLenDesc = _length;
            var oldLen     = (uint)TypeConverter.ToNumber(oldLenDesc.Value);

            uint index;

            if (propertyName.Length == 6 && propertyName == "length")
            {
                var value = desc.Value;
                if (ReferenceEquals(value, null))
                {
                    return(base.DefineOwnProperty("length", desc, throwOnError));
                }

                var  newLenDesc = new PropertyDescriptor(desc);
                uint newLen     = TypeConverter.ToUint32(value);
                if (newLen != TypeConverter.ToNumber(value))
                {
                    ExceptionHelper.ThrowRangeError(_engine);
                }

                newLenDesc.Value = newLen;
                if (newLen >= oldLen)
                {
                    return(base.DefineOwnProperty("length", newLenDesc, throwOnError));
                }

                if (!oldLenDesc.Writable)
                {
                    if (throwOnError)
                    {
                        ExceptionHelper.ThrowTypeError(_engine);
                    }

                    return(false);
                }

                bool newWritable;
                if (!newLenDesc.WritableSet || newLenDesc.Writable)
                {
                    newWritable = true;
                }
                else
                {
                    newWritable         = false;
                    newLenDesc.Writable = true;
                }

                var succeeded = base.DefineOwnProperty("length", newLenDesc, throwOnError);
                if (!succeeded)
                {
                    return(false);
                }

                var count = _dense?.Length ?? _sparse.Count;
                if (count < oldLen - newLen)
                {
                    if (_dense != null)
                    {
                        for (uint keyIndex = 0; keyIndex < _dense.Length; ++keyIndex)
                        {
                            if (_dense[keyIndex] == null)
                            {
                                continue;
                            }

                            // is it the index of the array
                            if (keyIndex >= newLen && keyIndex < oldLen)
                            {
                                var deleteSucceeded = DeleteAt(keyIndex);
                                if (!deleteSucceeded)
                                {
                                    newLenDesc.Value = keyIndex + 1;
                                    if (!newWritable)
                                    {
                                        newLenDesc.Writable = false;
                                    }

                                    base.DefineOwnProperty("length", newLenDesc, false);

                                    if (throwOnError)
                                    {
                                        ExceptionHelper.ThrowTypeError(_engine);
                                    }

                                    return(false);
                                }
                            }
                        }
                    }
                    else
                    {
                        // in the case of sparse arrays, treat each concrete element instead of
                        // iterating over all indexes
                        var keys      = new List <uint>(_sparse.Keys);
                        var keysCount = keys.Count;
                        for (var i = 0; i < keysCount; i++)
                        {
                            var keyIndex = keys[i];

                            // is it the index of the array
                            if (keyIndex >= newLen && keyIndex < oldLen)
                            {
                                var deleteSucceeded = Delete(TypeConverter.ToString(keyIndex), false);
                                if (!deleteSucceeded)
                                {
                                    newLenDesc.Value = JsNumber.Create(keyIndex + 1);
                                    if (!newWritable)
                                    {
                                        newLenDesc.Writable = false;
                                    }

                                    base.DefineOwnProperty("length", newLenDesc, false);

                                    if (throwOnError)
                                    {
                                        ExceptionHelper.ThrowTypeError(_engine);
                                    }

                                    return(false);
                                }
                            }
                        }
                    }
                }
                else
                {
                    while (newLen < oldLen)
                    {
                        // algorithm as per the spec
                        oldLen--;
                        var deleteSucceeded = Delete(TypeConverter.ToString(oldLen), false);
                        if (!deleteSucceeded)
                        {
                            newLenDesc.Value = oldLen + 1;
                            if (!newWritable)
                            {
                                newLenDesc.Writable = false;
                            }

                            base.DefineOwnProperty("length", newLenDesc, false);

                            if (throwOnError)
                            {
                                ExceptionHelper.ThrowTypeError(_engine);
                            }

                            return(false);
                        }
                    }
                }

                if (!newWritable)
                {
                    DefineOwnProperty("length", new PropertyDescriptor(value: null, flags: PropertyFlag.WritableSet), false);
                }

                return(true);
            }
            else if (IsArrayIndex(propertyName, out index))
            {
                if (index >= oldLen && !oldLenDesc.Writable)
                {
                    if (throwOnError)
                    {
                        ExceptionHelper.ThrowTypeError(_engine);
                    }

                    return(false);
                }

                var succeeded = base.DefineOwnProperty(propertyName, desc, false);
                if (!succeeded)
                {
                    if (throwOnError)
                    {
                        ExceptionHelper.ThrowTypeError(_engine);
                    }

                    return(false);
                }

                if (index >= oldLen)
                {
                    oldLenDesc.Value = index + 1;
                    base.DefineOwnProperty("length", oldLenDesc, false);
                }

                return(true);
            }

            return(base.DefineOwnProperty(propertyName, desc, throwOnError));
        }
Example #6
0
        /// <summary>
        /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.4
        /// </summary>
        /// <param name="forInStatement"></param>
        /// <returns></returns>
        public Completion ExecuteForInStatement(ForInStatement forInStatement)
        {
            Identifier identifier = forInStatement.Left.Type == SyntaxNodes.VariableDeclaration
                                        ? forInStatement.Left.As <VariableDeclaration>().Declarations.First().Id
                                        : forInStatement.Left.As <Identifier>();

            var varRef     = _engine.EvaluateExpression(identifier) as Reference;
            var exprRef    = _engine.EvaluateExpression(forInStatement.Right);
            var experValue = _engine.GetValue(exprRef);

            if (experValue == Undefined.Instance || experValue == Null.Instance)
            {
                return(new Completion(Completion.Normal, null, null));
            }


            var     obj = TypeConverter.ToObject(_engine, experValue);
            JsValue v   = Null.Instance;

            // keys are constructed using the prototype chain
            var cursor        = obj;
            var processedKeys = new HashSet <string>();

            while (cursor != null)
            {
                var keys = cursor.GetOwnProperties().Select(x => x.Key).ToArray();
                foreach (var p in keys)
                {
                    if (processedKeys.Contains(p))
                    {
                        continue;
                    }

                    processedKeys.Add(p);

                    // collection might be modified by inner statement
                    if (!cursor.HasOwnProperty(p))
                    {
                        continue;
                    }

                    var value = cursor.GetOwnProperty(p);
                    if (!value.Enumerable.HasValue || !value.Enumerable.Value)
                    {
                        continue;
                    }

                    _engine.PutValue(varRef, p);

                    var stmt = ExecuteStatement(forInStatement.Body);
                    if (stmt.Value.HasValue)
                    {
                        v = stmt.Value.Value;
                    }
                    if (stmt.Type == Completion.Break)
                    {
                        return(new Completion(Completion.Normal, v, null));
                    }
                    if (stmt.Type != Completion.Continue)
                    {
                        if (stmt.Type != Completion.Normal)
                        {
                            return(stmt);
                        }
                    }
                }

                cursor = cursor.Prototype;
            }

            return(new Completion(Completion.Normal, v, null));
        }