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