ce8ba63bbf4cfe9936d26d0003a6be46a98ee590
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSGenericTypedArrayViewConstructorInlines.h
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef JSGenericTypedArrayViewConstructorInlines_h
27 #define JSGenericTypedArrayViewConstructorInlines_h
28
29 #include "Error.h"
30 #include "JSArrayBuffer.h"
31 #include "JSGenericTypedArrayViewConstructor.h"
32 #include "JSGlobalObject.h"
33
34 namespace JSC {
35
36 template<typename ViewClass>
37 JSGenericTypedArrayViewConstructor<ViewClass>::JSGenericTypedArrayViewConstructor(JSGlobalObject* globalObject, Structure* structure)
38     : Base(globalObject, structure)
39 {
40 }
41
42 template<typename ViewClass>
43 void JSGenericTypedArrayViewConstructor<ViewClass>::finishCreation(VM& vm, JSObject* prototype, const String& name)
44 {
45     Base::finishCreation(vm, name);
46     putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly);
47     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(3), DontEnum | DontDelete | ReadOnly);
48     putDirectWithoutTransition(vm, vm.propertyNames->BYTES_PER_ELEMENT, jsNumber(ViewClass::elementSize), DontEnum | ReadOnly | DontDelete);
49 }
50
51 template<typename ViewClass>
52 JSGenericTypedArrayViewConstructor<ViewClass>*
53 JSGenericTypedArrayViewConstructor<ViewClass>::create(
54     JSGlobalObject* globalObject, Structure* structure, JSObject* prototype,
55     const String& name)
56 {
57     VM& vm = globalObject->vm();
58     JSGenericTypedArrayViewConstructor* result =
59         new (NotNull, allocateCell<JSGenericTypedArrayViewConstructor>(vm.heap))
60         JSGenericTypedArrayViewConstructor(globalObject, structure);
61     result->finishCreation(vm, prototype, name);
62     return result;
63 }
64
65 template<typename ViewClass>
66 Structure* JSGenericTypedArrayViewConstructor<ViewClass>::createStructure(
67     VM& vm, JSGlobalObject* globalObject, JSValue prototype)
68 {
69     return Structure::create(
70         vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
71 }
72
73 template<typename ViewClass>
74 static EncodedJSValue JSC_HOST_CALL constructGenericTypedArrayView(ExecState* exec)
75 {
76     Structure* structure =
77         asInternalFunction(exec->callee())->globalObject()->typedArrayStructure(
78             ViewClass::TypedArrayStorageType);
79     
80     if (!exec->argumentCount()) {
81         if (ViewClass::TypedArrayStorageType == TypeDataView)
82             return throwVMError(exec, createTypeError(exec, "DataView constructor requires at least one argument."));
83         
84         // Even though the documentation doesn't say so, it's correct to say
85         // "new Int8Array()". This is the same as allocating an array of zero
86         // length.
87         return JSValue::encode(ViewClass::create(exec, structure, 0));
88     }
89     
90     if (JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(exec->argument(0))) {
91         RefPtr<ArrayBuffer> buffer = jsBuffer->impl();
92         
93         unsigned offset = (exec->argumentCount() > 1) ? exec->uncheckedArgument(1).toUInt32(exec) : 0;
94         if (exec->hadException())
95             return JSValue::encode(jsUndefined());
96         unsigned length = 0;
97         if (exec->argumentCount() > 2) {
98             length = exec->uncheckedArgument(2).toUInt32(exec);
99             if (exec->hadException())
100                 return JSValue::encode(jsUndefined());
101         } else {
102             if ((buffer->byteLength() - offset) % ViewClass::elementSize)
103                 return throwVMError(exec, createRangeError(exec, "ArrayBuffer length minus the byteOffset is not a multiple of the element size"));
104             length = (buffer->byteLength() - offset) / ViewClass::elementSize;
105         }
106         return JSValue::encode(ViewClass::create(exec, structure, buffer, offset, length));
107     }
108     
109     if (ViewClass::TypedArrayStorageType == TypeDataView)
110         return throwVMError(exec, createTypeError(exec, "Expected ArrayBuffer for the first argument."));
111     
112     // For everything but DataView, we allow construction with any of:
113     // - Another array. This creates a copy of the of that array.
114     // - An integer. This creates a new typed array of that length and zero-initializes it.
115     
116     if (JSObject* object = jsDynamicCast<JSObject*>(exec->uncheckedArgument(0))) {
117         unsigned length =
118             object->get(exec, exec->vm().propertyNames->length).toUInt32(exec);
119         if (exec->hadException())
120             return JSValue::encode(jsUndefined());
121         
122         ViewClass* result = ViewClass::createUninitialized(exec, structure, length);
123         if (!result) {
124             ASSERT(exec->hadException());
125             return JSValue::encode(jsUndefined());
126         }
127         
128         if (!result->set(exec, object, 0, length))
129             return JSValue::encode(jsUndefined());
130         
131         return JSValue::encode(result);
132     }
133     
134     int length;
135     if (exec->uncheckedArgument(0).isInt32())
136         length = exec->uncheckedArgument(0).asInt32();
137     else if (!exec->uncheckedArgument(0).isNumber())
138         return throwVMError(exec, createTypeError(exec, "Invalid array length argument"));
139     else {
140         length = static_cast<int>(exec->uncheckedArgument(0).asNumber());
141         if (length != exec->uncheckedArgument(0).asNumber())
142             return throwVMError(exec, createTypeError(exec, "Invalid array length argument (fractional lengths not allowed)"));
143     }
144
145     if (length < 0)
146         return throwVMError(exec, createRangeError(exec, "Requested length is negative"));
147     return JSValue::encode(ViewClass::create(exec, structure, length));
148 }
149
150 template<typename ViewClass>
151 ConstructType JSGenericTypedArrayViewConstructor<ViewClass>::getConstructData(JSCell*, ConstructData& constructData)
152 {
153     constructData.native.function = constructGenericTypedArrayView<ViewClass>;
154     return ConstructTypeHost;
155 }
156
157 template<typename ViewClass>
158 CallType JSGenericTypedArrayViewConstructor<ViewClass>::getCallData(JSCell*, CallData& callData)
159 {
160     callData.native.function = constructGenericTypedArrayView<ViewClass>;
161     return CallTypeHost;
162 }
163
164 } // namespace JSC
165
166 #endif // JSGenericTypedArrayViewConstructorInlines_h