Example #1
0
        public static EcmaValue ConstructTypedArray(TypedArrayKind kind, EcmaValue thisValue, EcmaValue[] args)
        {
            TypedArray array = thisValue.GetUnderlyingObject <TypedArray>();

            if (args.Length == 0)
            {
                array.Init(0);
                return(thisValue);
            }
            if (args[0].Type != EcmaValueType.Object)
            {
                array.Init(args[0].ToIndex());
                return(thisValue);
            }
            RuntimeObject obj             = args[0].ToObject();
            long          bytesPerElement = array.ElementSize;

            if (obj is TypedArray srcArray)
            {
                Guard.BufferNotDetached(srcArray);
                RuntimeObject bufferConstructor;
                if (srcArray.Buffer.IsShared)
                {
                    bufferConstructor = srcArray.Realm.GetRuntimeObject(WellKnownObject.ArrayBuffer);
                }
                else
                {
                    bufferConstructor = RuntimeObject.GetSpeciesConstructor(srcArray.Buffer, WellKnownObject.ArrayBuffer);
                }
                if (srcArray.ArrayKind == kind)
                {
                    ArrayBuffer buffer = srcArray.Buffer.Clone(srcArray.ByteOffset, bytesPerElement * srcArray.Length, bufferConstructor);
                    array.Init(buffer);
                }
                else
                {
                    ArrayBuffer buffer = ArrayBuffer.AllocateArrayBuffer(bufferConstructor, bytesPerElement * srcArray.Length);
                    Guard.BufferNotDetached(srcArray);
                    array.Init(buffer);
                    for (int i = 0, j = 0, count = srcArray.Length; i < count; i++, j++)
                    {
                        array.SetValueInBuffer(j, srcArray.GetValueFromBuffer(i));
                    }
                }
                return(thisValue);
            }
            if (obj is ArrayBuffer srcBuffer)
            {
                long offset = args.Length > 1 ? args[1].ToIndex() : 0;
                if ((offset % bytesPerElement) != 0)
                {
                    throw new EcmaRangeErrorException(InternalString.Error.TypedArrayInvalidOffset, TypedArrayInfo.GetTypedArrayName(array.ArrayKind), bytesPerElement);
                }
                long length;
                if (args.Length <= 2 || args[2] == default)
                {
                    Guard.BufferNotDetached(srcBuffer);
                    if ((srcBuffer.ByteLength % bytesPerElement) != 0)
                    {
                        throw new EcmaRangeErrorException(InternalString.Error.TypedArrayInvalidByteLength, TypedArrayInfo.GetTypedArrayName(array.ArrayKind), bytesPerElement);
                    }
                    if (srcBuffer.ByteLength < offset)
                    {
                        throw new EcmaRangeErrorException(InternalString.Error.BufferOffsetOutOfBound, offset);
                    }
                    length = srcBuffer.ByteLength - offset;
                }
                else
                {
                    length = args[2].ToIndex() * bytesPerElement;
                    Guard.BufferNotDetached(srcBuffer);
                    if (offset + length > srcBuffer.ByteLength)
                    {
                        throw new EcmaRangeErrorException(InternalString.Error.TypedArrayInvalidLength, length);
                    }
                }
                array.Init(srcBuffer, offset, length);
                return(thisValue);
            }
            RuntimeObject iterator = obj.GetMethod(WellKnownSymbol.Iterator);

            if (iterator != null)
            {
                List <EcmaValue> values = new List <EcmaValue>(obj.GetIterator());
                array.Init(values.Count);
                int i = 0;
                foreach (EcmaValue v in values)
                {
                    array.Set(i++, v);
                }
            }
            else
            {
                long length = obj[WellKnownProperty.Length].ToLength();
                array.Init((int)length);
                for (int i = 0; i < length; i++)
                {
                    array.Set(i, obj[i]);
                }
            }
            return(thisValue);
        }