• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/builtins/builtins_sharedarraybuffer.h"
17 
18 #include "ecmascript/ecma_macros.h"
19 #include "ecmascript/ecma_vm.h"
20 #include "ecmascript/global_env.h"
21 #include "ecmascript/interpreter/interpreter.h"
22 #include "ecmascript/js_arraybuffer.h"
23 #include "ecmascript/js_object-inl.h"
24 #include "ecmascript/js_tagged_number.h"
25 #include "ecmascript/js_tagged_value-inl.h"
26 #include "ecmascript/js_tagged_value.h"
27 #include "ecmascript/object_factory.h"
28 
29 #include "securec.h"
30 
31 namespace panda::ecmascript::builtins {
32 // 25.2.2.1 SharedArrayBuffer ( [ length ] )
SharedArrayBufferConstructor(EcmaRuntimeCallInfo * argv)33 JSTaggedValue BuiltinsSharedArrayBuffer::SharedArrayBufferConstructor(EcmaRuntimeCallInfo *argv)
34 {
35     ASSERT(argv);
36     BUILTINS_API_TRACE(argv->GetThread(), SharedArrayBuffer, Constructor);
37     JSThread *thread = argv->GetThread();
38     [[maybe_unused]] EcmaHandleScope handleScope(thread);
39     JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
40     // 1. If NewTarget is undefined, throw a TypeError exception.
41     if (newTarget->IsUndefined()) {
42         THROW_TYPE_ERROR_AND_RETURN(thread, "newtarget is undefined", JSTaggedValue::Exception());
43     }
44     JSHandle<JSTaggedValue> lengthHandle = GetCallArg(argv, 0);
45     // 2. Let byteLength be ? ToIndex(length).
46     JSTaggedNumber lenNum = JSTaggedValue::ToIndex(thread, lengthHandle);
47     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
48     uint64_t byteLength = lenNum.GetNumber();
49     // 3. Return ? AllocateSharedArrayBuffer(NewTarget, byteLength).
50     return AllocateSharedArrayBuffer(thread, newTarget, byteLength);
51 }
52 
53 // 25.2.1.2 IsSharedArrayBuffer ( obj )
IsSharedArrayBuffer(EcmaRuntimeCallInfo * argv)54 JSTaggedValue BuiltinsSharedArrayBuffer::IsSharedArrayBuffer(EcmaRuntimeCallInfo *argv)
55 {
56     ASSERT(argv);
57     BUILTINS_API_TRACE(argv->GetThread(), SharedArrayBuffer, IsSharedArrayBuffer);
58     [[maybe_unused]] EcmaHandleScope handleScope(argv->GetThread());
59     JSHandle<JSTaggedValue> arg = GetCallArg(argv, 0);
60     // 1. If Type(arg) is not Object,and it not has an [[ArrayBufferData]] internal slot return false.
61     if (!arg->IsECMAObject()) {
62         return BuiltinsSharedArrayBuffer::GetTaggedBoolean(false);
63     }
64     if (!arg->IsSharedArrayBuffer()) {
65         return BuiltinsSharedArrayBuffer::GetTaggedBoolean(false);
66     }
67     // 2. Let bufferData be obj.[[ArrayBufferData]].
68     JSHandle<JSArrayBuffer> buffer(arg);
69     JSTaggedValue bufferdata = buffer->GetArrayBufferData();
70     // 3. If bufferData is null, return false.
71     if (bufferdata.IsNull()) {
72         return BuiltinsSharedArrayBuffer::GetTaggedBoolean(false);
73     }
74     // 4. If this ArrayBuffer is not shared, return false.
75     if (buffer->GetShared() == false) {
76         return BuiltinsSharedArrayBuffer::GetTaggedBoolean(false);
77     }
78     return BuiltinsSharedArrayBuffer::GetTaggedBoolean(true);
79 }
80 
IsShared(JSTaggedValue arrayBuffer)81 bool BuiltinsSharedArrayBuffer::IsShared(JSTaggedValue arrayBuffer)
82 {
83     if (!arrayBuffer.IsSharedArrayBuffer()) {
84         return false;
85     }
86     JSArrayBuffer *buffer = JSArrayBuffer::Cast(arrayBuffer.GetTaggedObject());
87     JSTaggedValue dataSlot = buffer->GetArrayBufferData();
88     // 2. If arrayBuffer’s [[ArrayBufferData]] internal slot is null, return false.
89     if (dataSlot.IsNull()) {
90         return false;
91     }
92     // 3. If this ArrayBuffer is not shared, return false.
93     return buffer->GetShared();
94 }
95 
96 // 25.2.1.1 AllocateSharedArrayBuffer ( constructor, byteLength )
AllocateSharedArrayBuffer(JSThread * thread,const JSHandle<JSTaggedValue> & newTarget,uint64_t byteLength)97 JSTaggedValue BuiltinsSharedArrayBuffer::AllocateSharedArrayBuffer(
98     JSThread *thread, const JSHandle<JSTaggedValue> &newTarget, uint64_t byteLength)
99 {
100     BUILTINS_API_TRACE(thread, SharedArrayBuffer, AllocateSharedArrayBuffer);
101     /**
102      * 1. Let obj be ? OrdinaryCreateFromConstructor(constructor, "%SharedArrayBuffer.prototype%",
103      * «[[ArrayBufferData]], [[ArrayBufferByteLength]] »).
104      * */
105     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
106     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
107     JSHandle<JSTaggedValue> shaArrBufFunc = env->GetSharedArrayBufferFunction();
108     JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(shaArrBufFunc), newTarget);
109     // 2. ReturnIfAbrupt
110     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
111     // 4. Let block be CreateSharedByteDataBlock(byteLength).
112     if (byteLength > INT_MAX) {
113         THROW_RANGE_ERROR_AND_RETURN(thread, "Out of range", JSTaggedValue::Exception());
114     }
115     JSHandle<JSArrayBuffer> sharedArrayBuffer(obj);
116     // 6. Set obj’s [[ArrayBufferData]] internal slot to block.
117     factory->NewJSSharedArrayBufferData(sharedArrayBuffer, byteLength);
118     // 7. Set obj’s [[ArrayBufferByteLength]] internal slot to byteLength.
119     sharedArrayBuffer->SetArrayBufferByteLength(static_cast<uint32_t>(byteLength));
120     // 8. Return obj.
121     return sharedArrayBuffer.GetTaggedValue();
122 }
123 
124 // 25.2.3.2 get SharedArrayBuffer [ @@species ]
Species(EcmaRuntimeCallInfo * argv)125 JSTaggedValue BuiltinsSharedArrayBuffer::Species(EcmaRuntimeCallInfo *argv)
126 {
127     ASSERT(argv);
128     BUILTINS_API_TRACE(argv->GetThread(), SharedArrayBuffer, Species);
129     // 1. Return the this value.
130     return GetThis(argv).GetTaggedValue();
131 }
132 
133 // 25.2.4.1 get SharedArrayBuffer.prototype.byteLength
GetByteLength(EcmaRuntimeCallInfo * argv)134 JSTaggedValue BuiltinsSharedArrayBuffer::GetByteLength(EcmaRuntimeCallInfo *argv)
135 {
136     ASSERT(argv);
137     BUILTINS_API_TRACE(argv->GetThread(), SharedArrayBuffer, GetByteLength);
138     JSThread *thread = argv->GetThread();
139     [[maybe_unused]] EcmaHandleScope handleScope(thread);
140     // 1. Let O be the this value.
141     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
142     // 2. If Type(O) is not Object, throw a TypeError exception.
143     if (!thisHandle->IsECMAObject()) {
144         THROW_TYPE_ERROR_AND_RETURN(thread, "this value is not an object", JSTaggedValue::Exception());
145     }
146     // 3. If O does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception.
147     if (!thisHandle->IsSharedArrayBuffer()) {
148         THROW_TYPE_ERROR_AND_RETURN(thread, "don't have internal slot", JSTaggedValue::Exception());
149     }
150     JSHandle<JSArrayBuffer> shaArrBuf(thisHandle);
151     // 5. Let length be the value of O’s [[SharedArrayBufferByteLength]] internal slot.
152     uint32_t length = shaArrBuf->GetArrayBufferByteLength();
153     // 6. Return length.
154     return JSTaggedValue(length);
155 }
156 
157 // 25.2.4.3 SharedArrayBuffer.prototype.slice ( start, end )
Slice(EcmaRuntimeCallInfo * argv)158 JSTaggedValue BuiltinsSharedArrayBuffer::Slice(EcmaRuntimeCallInfo *argv)
159 {
160     ASSERT(argv);
161     BUILTINS_API_TRACE(argv->GetThread(), SharedArrayBuffer, Slice);
162     JSThread *thread = argv->GetThread();
163     [[maybe_unused]] EcmaHandleScope handleScope(thread);
164     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
165     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
166     // 1. Let O be the this value.
167     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
168     // 2. If Type(O) is not Object, throw a TypeError exception.
169     if (!thisHandle->IsECMAObject()) {
170         THROW_TYPE_ERROR_AND_RETURN(thread, "this value is not an object", JSTaggedValue::Exception());
171     }
172     JSHandle<JSArrayBuffer> shaArrBuf(thisHandle);
173     // 3. If O does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception.
174     if (!thisHandle->IsSharedArrayBuffer()) {
175         THROW_TYPE_ERROR_AND_RETURN(thread, "don't have internal slot", JSTaggedValue::Exception());
176     }
177     // 4. If IsSharedArrayBuffer(O) is false, throw a TypeError exception.
178     if (!IsShared(thisHandle.GetTaggedValue())) {
179         THROW_TYPE_ERROR_AND_RETURN(thread, "this value not IsSharedArrayBuffer", JSTaggedValue::Exception());
180     }
181     // 5. Let len be the value of O’s [[ArrayBufferByteLength]] internal slot.
182     int32_t len = static_cast<int32_t>(shaArrBuf->GetArrayBufferByteLength());
183     JSHandle<JSTaggedValue> startHandle = GetCallArg(argv, 0);
184     // 6. Let relativeStart be ToInteger(start).
185     JSTaggedNumber relativeStart = JSTaggedValue::ToInteger(thread, startHandle);
186     // 7. ReturnIfAbrupt(relativeStart).
187     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
188     int32_t start = base::NumberHelper::DoubleInRangeInt32(relativeStart.GetNumber());
189     int32_t end = 0;
190     int32_t first = 0;
191     int32_t last = 0;
192     // 8. If relativeStart < 0, let first be max((len + relativeStart),0); else let first be min(relativeStart, len).
193     if (start < 0) {
194         first = std::max((len + start), 0);
195     } else {
196         first = std::min(start, len);
197     }
198     // 9. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end).
199     JSHandle<JSTaggedValue> endHandle = GetCallArg(argv, 1);
200     if (endHandle->IsUndefined()) {
201         end = len;
202     } else {
203         JSTaggedNumber relativeEnd = JSTaggedValue::ToInteger(thread, endHandle);
204         // 10. ReturnIfAbrupt(relativeEnd).
205         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
206         end = base::NumberHelper::DoubleInRangeInt32(relativeEnd.GetNumber());
207     }
208     // 11. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len).
209     last = end < 0 ? std::max((len + end), 0) : std::min(end, len);
210     // 12. Let newLen be max(final-first,0).
211     uint32_t newLen = std::max((last - first), 0);
212     // 13. Let ctor be SpeciesConstructor(O, %SharedArrayBuffer%).
213     JSHandle<JSTaggedValue> defaultConstructor = env->GetSharedArrayBufferFunction();
214     JSHandle<JSObject> objHandle(thisHandle);
215     JSHandle<JSTaggedValue> constructor = JSObject::SpeciesConstructor(thread, objHandle, defaultConstructor);
216     // 14. ReturnIfAbrupt(ctor).
217     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
218     // 15. Let new be Construct(ctor, «newLen»).
219     JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
220     EcmaRuntimeCallInfo *info =
221         EcmaInterpreter::NewRuntimeCallInfo(thread, constructor, undefined, undefined, 1);
222     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
223     info->SetCallArg(JSTaggedValue(newLen));
224     JSTaggedValue taggedNewArrBuf = JSFunction::Construct(info);
225     JSHandle<JSTaggedValue> newArrBuf(thread, taggedNewArrBuf);
226     // 16. ReturnIfAbrupt(new).
227     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
228     // 17. If new does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception.
229     if (!newArrBuf->IsSharedArrayBuffer()) {
230         THROW_TYPE_ERROR_AND_RETURN(thread, "don't have bufferdata internal slot", JSTaggedValue::Exception());
231     }
232     // 18. If IsSharedArrayBuffer(new) is false, throw a TypeError exception.
233     if (!IsShared(newArrBuf.GetTaggedValue())) {
234         THROW_TYPE_ERROR_AND_RETURN(thread, "new arrayBuffer not IsSharedArrayBuffer", JSTaggedValue::Exception());
235     }
236     // 19. If SameValue(new, O) is true, throw a TypeError exception.
237     if (JSTaggedValue::SameValue(newArrBuf.GetTaggedValue(), thisHandle.GetTaggedValue())) {
238         THROW_TYPE_ERROR_AND_RETURN(thread, "value of new arraybuffer and this is same", JSTaggedValue::Exception());
239     }
240     JSHandle<JSArrayBuffer> newJsShaArrBuf(newArrBuf);
241     // 20. If the value of new’s [[ArrayBufferByteLength]] internal slot < newLen, throw a TypeError exception.
242     uint32_t newArrBufLen = newJsShaArrBuf->GetArrayBufferByteLength();
243     if (newArrBufLen < newLen) {
244         THROW_TYPE_ERROR_AND_RETURN(thread, "new array buffer length smaller than newlen", JSTaggedValue::Exception());
245     }
246     if (newLen > 0) {
247         // 23. Let fromBuf be the value of O’s [[ArrayBufferData]] internal slot.
248         JSTaggedValue from = shaArrBuf->GetArrayBufferData();
249         // 24. Let toBuf be the value of new’s [[ArrayBufferData]] internal slot.
250         JSTaggedValue to = newJsShaArrBuf->GetArrayBufferData();
251         // 25. Perform CopyDataBlockBytes(toBuf, fromBuf, first, newLen).
252         JSArrayBuffer::CopyDataBlockBytes(to, from, first, newLen);
253     }
254     // Return new.
255     return newArrBuf.GetTaggedValue();
256 }
257 }  // namespace panda::ecmascript::builtins