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/compiler/new_object_stub_builder.h"
17
18 #include "ecmascript/compiler/stub_builder-inl.h"
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/global_env_constants.h"
21 #include "ecmascript/js_arguments.h"
22 #include "ecmascript/js_object.h"
23 #include "ecmascript/js_thread.h"
24 #include "ecmascript/lexical_env.h"
25 #include "ecmascript/mem/mem.h"
26
27 namespace panda::ecmascript::kungfu {
NewLexicalEnv(Variable * result,Label * exit,GateRef numSlots,GateRef parent)28 void NewObjectStubBuilder::NewLexicalEnv(Variable *result, Label *exit, GateRef numSlots, GateRef parent)
29 {
30 auto env = GetEnvironment();
31
32 auto length = Int32Add(numSlots, Int32(LexicalEnv::RESERVED_ENV_LENGTH));
33 size_ = ComputeTaggedArraySize(ZExtInt32ToPtr(length));
34 Label afterAllocate(env);
35 // Be careful. NO GC is allowed when initization is not complete.
36 AllocateInYoung(result, &afterAllocate);
37 Bind(&afterAllocate);
38 Label hasPendingException(env);
39 Label noException(env);
40 Branch(TaggedIsException(result->ReadVariable()), &hasPendingException, &noException);
41 Bind(&noException);
42 {
43 auto hclass = GetGlobalConstantValue(
44 VariableType::JS_POINTER(), glue_, ConstantIndex::ENV_CLASS_INDEX);
45 StoreHClass(glue_, result->ReadVariable(), hclass);
46 Label afterInitialize(env);
47 InitializeTaggedArrayWithSpeicalValue(&afterInitialize,
48 result->ReadVariable(), Hole(), Int32(LexicalEnv::RESERVED_ENV_LENGTH), length);
49 Bind(&afterInitialize);
50 SetValueToTaggedArray(VariableType::INT64(),
51 glue_, result->ReadVariable(), Int32(LexicalEnv::SCOPE_INFO_INDEX), Hole());
52 SetValueToTaggedArray(VariableType::JS_POINTER(),
53 glue_, result->ReadVariable(), Int32(LexicalEnv::PARENT_ENV_INDEX), parent);
54 Jump(exit);
55 }
56 Bind(&hasPendingException);
57 {
58 Jump(exit);
59 }
60 }
61
NewJSObject(Variable * result,Label * exit,GateRef hclass)62 void NewObjectStubBuilder::NewJSObject(Variable *result, Label *exit, GateRef hclass)
63 {
64 auto env = GetEnvironment();
65
66 size_ = GetObjectSizeFromHClass(hclass);
67 Label afterAllocate(env);
68 // Be careful. NO GC is allowed when initization is not complete.
69 AllocateInYoung(result, &afterAllocate);
70 Bind(&afterAllocate);
71 Label hasPendingException(env);
72 Label noException(env);
73 Branch(TaggedIsException(result->ReadVariable()), &hasPendingException, &noException);
74 Bind(&noException);
75 {
76 StoreHClass(glue_, result->ReadVariable(), hclass);
77 DEFVARIABLE(initValue, VariableType::JS_ANY(), Undefined());
78 Label isTS(env);
79 Label initialize(env);
80 Branch(IsTSHClass(hclass), &isTS, &initialize);
81 Bind(&isTS);
82 {
83 // The object which created by AOT speculative hclass, should be initialized as hole, means does not exist,
84 // to follow ECMA spec.
85 initValue = Hole();
86 Jump(&initialize);
87 }
88 Bind(&initialize);
89 Label afterInitialize(env);
90 InitializeWithSpeicalValue(&afterInitialize,
91 result->ReadVariable(), *initValue, Int32(JSObject::SIZE), ChangeIntPtrToInt32(size_));
92 Bind(&afterInitialize);
93 auto emptyArray = GetGlobalConstantValue(
94 VariableType::JS_POINTER(), glue_, ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
95 SetHash(glue_, result->ReadVariable(), Int64(JSTaggedValue(0).GetRawData()));
96 SetPropertiesArray(VariableType::INT64(),
97 glue_, result->ReadVariable(), emptyArray);
98 SetElementsArray(VariableType::INT64(),
99 glue_, result->ReadVariable(), emptyArray);
100 Jump(exit);
101 }
102 Bind(&hasPendingException);
103 {
104 Jump(exit);
105 }
106 }
107
NewArgumentsList(Variable * result,Label * exit,GateRef sp,GateRef startIdx,GateRef numArgs)108 void NewObjectStubBuilder::NewArgumentsList(Variable *result, Label *exit,
109 GateRef sp, GateRef startIdx, GateRef numArgs)
110 {
111 auto env = GetEnvironment();
112 DEFVARIABLE(i, VariableType::INT32(), Int32(0));
113 Label setHClass(env);
114 size_ = ComputeTaggedArraySize(ZExtInt32ToPtr(numArgs));
115 Label afterAllocate(env);
116 AllocateInYoung(result, &afterAllocate);
117 Bind(&afterAllocate);
118 Branch(TaggedIsException(result->ReadVariable()), exit, &setHClass);
119 Bind(&setHClass);
120 GateRef arrayClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_,
121 ConstantIndex::ARRAY_CLASS_INDEX);
122 StoreHClass(glue_, result->ReadVariable(), arrayClass);
123 Store(VariableType::INT32(), glue_, result->ReadVariable(), IntPtr(TaggedArray::LENGTH_OFFSET), numArgs);
124 // skip InitializeTaggedArrayWithSpeicalValue due to immediate setting arguments
125 Label setArgumentsBegin(env);
126 Label setArgumentsAgain(env);
127 Label setArgumentsEnd(env);
128 Branch(Int32UnsignedLessThan(*i, numArgs), &setArgumentsBegin, &setArgumentsEnd);
129 LoopBegin(&setArgumentsBegin);
130 GateRef idx = ZExtInt32ToPtr(Int32Add(startIdx, *i));
131 GateRef argument = Load(VariableType::JS_ANY(), sp, PtrMul(IntPtr(sizeof(JSTaggedType)), idx));
132 SetValueToTaggedArray(VariableType::JS_ANY(), glue_, result->ReadVariable(), *i, argument);
133 i = Int32Add(*i, Int32(1));
134 Branch(Int32UnsignedLessThan(*i, numArgs), &setArgumentsAgain, &setArgumentsEnd);
135 Bind(&setArgumentsAgain);
136 LoopEnd(&setArgumentsBegin);
137 Bind(&setArgumentsEnd);
138 Jump(exit);
139 }
140
NewArgumentsObj(Variable * result,Label * exit,GateRef argumentsList,GateRef numArgs)141 void NewObjectStubBuilder::NewArgumentsObj(Variable *result, Label *exit,
142 GateRef argumentsList, GateRef numArgs)
143 {
144 auto env = GetEnvironment();
145
146 GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
147 GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue_, glueGlobalEnvOffset);
148 GateRef argumentsClass = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
149 GlobalEnv::ARGUMENTS_CLASS);
150 Label afterNewObject(env);
151 NewJSObject(result, &afterNewObject, argumentsClass);
152 Bind(&afterNewObject);
153 Label setArgumentsObjProperties(env);
154 Branch(TaggedIsException(result->ReadVariable()), exit, &setArgumentsObjProperties);
155 Bind(&setArgumentsObjProperties);
156 SetPropertyInlinedProps(glue_, result->ReadVariable(), argumentsClass, IntToTaggedInt(numArgs),
157 Int32(JSArguments::LENGTH_INLINE_PROPERTY_INDEX));
158 SetElementsArray(VariableType::JS_ANY(), glue_, result->ReadVariable(), argumentsList);
159 GateRef arrayProtoValuesFunction = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
160 GlobalEnv::ARRAY_PROTO_VALUES_FUNCTION_INDEX);
161 SetPropertyInlinedProps(glue_, result->ReadVariable(), argumentsClass, arrayProtoValuesFunction,
162 Int32(JSArguments::ITERATOR_INLINE_PROPERTY_INDEX));
163 GateRef accessorCaller = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
164 GlobalEnv::ARGUMENTS_CALLER_ACCESSOR);
165 SetPropertyInlinedProps(glue_, result->ReadVariable(), argumentsClass, accessorCaller,
166 Int32(JSArguments::CALLER_INLINE_PROPERTY_INDEX));
167 GateRef accessorCallee = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
168 GlobalEnv::ARGUMENTS_CALLEE_ACCESSOR);
169 SetPropertyInlinedProps(glue_, result->ReadVariable(), argumentsClass, accessorCallee,
170 Int32(JSArguments::CALLEE_INLINE_PROPERTY_INDEX));
171 Jump(exit);
172 }
173
NewJSArrayLiteral(Variable * result,Label * exit,RegionSpaceFlag spaceType,GateRef obj,GateRef hclass,bool isEmptyArray)174 void NewObjectStubBuilder::NewJSArrayLiteral(Variable *result, Label *exit, RegionSpaceFlag spaceType, GateRef obj,
175 GateRef hclass, bool isEmptyArray)
176 {
177 auto env = GetEnvironment();
178 Label initializeArray(env);
179 Label afterInitialize(env);
180 HeapAlloc(result, &initializeArray, spaceType);
181 Bind(&initializeArray);
182 Store(VariableType::JS_POINTER(), glue_, result->ReadVariable(), IntPtr(0), hclass);
183 InitializeWithSpeicalValue(&afterInitialize, result->ReadVariable(), Undefined(), Int32(JSArray::SIZE),
184 TruncInt64ToInt32(size_));
185 Bind(&afterInitialize);
186 GateRef hashOffset = IntPtr(ECMAObject::HASH_OFFSET);
187 Store(VariableType::INT64(), glue_, result->ReadVariable(), hashOffset, Int64(JSTaggedValue(0).GetRawData()));
188
189 GateRef propertiesOffset = IntPtr(JSObject::PROPERTIES_OFFSET);
190 GateRef elementsOffset = IntPtr(JSObject::ELEMENTS_OFFSET);
191 GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
192 if (isEmptyArray) {
193 Store(VariableType::JS_POINTER(), glue_, result->ReadVariable(), propertiesOffset, obj);
194 Store(VariableType::JS_POINTER(), glue_, result->ReadVariable(), elementsOffset, obj);
195 Store(VariableType::JS_ANY(), glue_, result->ReadVariable(), lengthOffset, IntToTaggedInt(Int32(0)));
196 } else {
197 auto newProperties = Load(VariableType::JS_POINTER(), obj, propertiesOffset);
198 Store(VariableType::JS_POINTER(), glue_, result->ReadVariable(), propertiesOffset, newProperties);
199
200 auto newElements = Load(VariableType::JS_POINTER(), obj, elementsOffset);
201 Store(VariableType::JS_POINTER(), glue_, result->ReadVariable(), elementsOffset, newElements);
202
203 GateRef arrayLength = Load(VariableType::JS_ANY(), obj, lengthOffset);
204 Store(VariableType::JS_ANY(), glue_, result->ReadVariable(), lengthOffset, arrayLength);
205 }
206
207 auto accessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::ARRAY_LENGTH_ACCESSOR);
208 SetPropertyInlinedProps(glue_, result->ReadVariable(), hclass, accessor,
209 Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX), VariableType::JS_POINTER());
210 Jump(exit);
211 }
212
HeapAlloc(Variable * result,Label * exit,RegionSpaceFlag spaceType)213 void NewObjectStubBuilder::HeapAlloc(Variable *result, Label *exit, RegionSpaceFlag spaceType)
214 {
215 switch (spaceType) {
216 case RegionSpaceFlag::IN_YOUNG_SPACE:
217 AllocateInYoung(result, exit);
218 break;
219 default:
220 break;
221 }
222 }
223
AllocateInYoung(Variable * result,Label * exit)224 void NewObjectStubBuilder::AllocateInYoung(Variable *result, Label *exit)
225 {
226 auto env = GetEnvironment();
227 Label success(env);
228 Label callRuntime(env);
229
230 #ifdef ARK_ASAN_ON
231 DEFVARIABLE(ret, VariableType::JS_ANY(), Undefined());
232 Jump(&callRuntime);
233 #else
234 auto topOffset = JSThread::GlueData::GetNewSpaceAllocationTopAddressOffset(env->Is32Bit());
235 auto endOffset = JSThread::GlueData::GetNewSpaceAllocationEndAddressOffset(env->Is32Bit());
236 auto topAddress = Load(VariableType::NATIVE_POINTER(), glue_, IntPtr(topOffset));
237 auto endAddress = Load(VariableType::NATIVE_POINTER(), glue_, IntPtr(endOffset));
238 auto top = Load(VariableType::JS_POINTER(), topAddress, IntPtr(0));
239 auto end = Load(VariableType::JS_POINTER(), endAddress, IntPtr(0));
240 DEFVARIABLE(ret, VariableType::JS_ANY(), Undefined());
241 auto newTop = PtrAdd(top, size_);
242 Branch(IntPtrGreaterThan(newTop, end), &callRuntime, &success);
243 Bind(&success);
244 {
245 Store(VariableType::NATIVE_POINTER(), glue_, topAddress, IntPtr(0), newTop);
246 if (env->Is32Bit()) {
247 top = ZExtInt32ToInt64(top);
248 }
249 ret = top;
250 result->WriteVariable(*ret);
251 Jump(exit);
252 }
253 #endif
254 Bind(&callRuntime);
255 {
256 ret = CallRuntime(glue_, RTSTUB_ID(AllocateInYoung), {
257 IntToTaggedInt(size_) });
258 result->WriteVariable(*ret);
259 Jump(exit);
260 }
261 }
262
InitializeWithSpeicalValue(Label * exit,GateRef object,GateRef value,GateRef start,GateRef end)263 void NewObjectStubBuilder::InitializeWithSpeicalValue(Label *exit, GateRef object, GateRef value, GateRef start,
264 GateRef end)
265 {
266 auto env = GetEnvironment();
267 Label begin(env);
268 Label storeValue(env);
269 Label endLoop(env);
270
271 DEFVARIABLE(startOffset, VariableType::INT32(), start);
272 Jump(&begin);
273 LoopBegin(&begin);
274 {
275 Branch(Int32UnsignedLessThan(*startOffset, end), &storeValue, exit);
276 Bind(&storeValue);
277 {
278 Store(VariableType::INT64(), glue_, object, ZExtInt32ToPtr(*startOffset), value);
279 startOffset = Int32Add(*startOffset, Int32(JSTaggedValue::TaggedTypeSize()));
280 Jump(&endLoop);
281 }
282 Bind(&endLoop);
283 LoopEnd(&begin);
284 }
285 }
286
InitializeTaggedArrayWithSpeicalValue(Label * exit,GateRef array,GateRef value,GateRef start,GateRef length)287 void NewObjectStubBuilder::InitializeTaggedArrayWithSpeicalValue(Label *exit,
288 GateRef array, GateRef value, GateRef start, GateRef length)
289 {
290 Store(VariableType::INT32(), glue_, array, IntPtr(TaggedArray::LENGTH_OFFSET), length);
291 auto offset = Int32Mul(start, Int32(JSTaggedValue::TaggedTypeSize()));
292 auto dataOffset = Int32Add(offset, Int32(TaggedArray::DATA_OFFSET));
293 offset = Int32Mul(length, Int32(JSTaggedValue::TaggedTypeSize()));
294 auto endOffset = Int32Add(offset, Int32(TaggedArray::DATA_OFFSET));
295 InitializeWithSpeicalValue(exit, array, value, dataOffset, endOffset);
296 }
297
AllocStringObject(Variable * result,Label * exit,GateRef length,bool compressed)298 void NewObjectStubBuilder::AllocStringObject(Variable *result, Label *exit, GateRef length, bool compressed)
299 {
300 auto env = GetEnvironment();
301 if (compressed) {
302 size_ = AlignUp(ComputeSizeUtf8(ZExtInt32ToPtr(length)),
303 IntPtr(static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)));
304 } else {
305 size_ = AlignUp(ComputeSizeUtf16(ZExtInt32ToPtr(length)),
306 IntPtr(static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)));
307 }
308 Label afterAllocate(env);
309 AllocateInYoung(result, &afterAllocate);
310
311 Bind(&afterAllocate);
312 GateRef arrayClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_,
313 ConstantIndex::STRING_CLASS_INDEX);
314 StoreHClass(glue_, result->ReadVariable(), arrayClass);
315 SetLength(glue_, result->ReadVariable(), length, compressed);
316 SetRawHashcode(glue_, result->ReadVariable(), Int32(0));
317 Jump(exit);
318 }
319
320
FastNewThisObject(GateRef glue,GateRef ctor)321 GateRef NewObjectStubBuilder::FastNewThisObject(GateRef glue, GateRef ctor)
322 {
323 auto env = GetEnvironment();
324 Label entry(env);
325 env->SubCfgEntry(&entry);
326 Label exit(env);
327 Label isHeapObject(env);
328 Label callRuntime(env);
329 Label checkJSObject(env);
330 Label newObject(env);
331
332 DEFVARIABLE(thisObj, VariableType::JS_ANY(), Undefined());
333 auto protoOrHclass = Load(VariableType::JS_ANY(), ctor,
334 IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
335 Branch(TaggedIsHeapObject(protoOrHclass), &isHeapObject, &callRuntime);
336 Bind(&isHeapObject);
337 Branch(IsJSHClass(protoOrHclass), &checkJSObject, &callRuntime);
338 Bind(&checkJSObject);
339 auto objectType = GetObjectType(protoOrHclass);
340 Branch(Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_OBJECT))),
341 &newObject, &callRuntime);
342 Bind(&newObject);
343 {
344 SetParameters(glue, 0);
345 NewJSObject(&thisObj, &exit, protoOrHclass);
346 }
347 Bind(&callRuntime);
348 {
349 thisObj = CallRuntime(glue, RTSTUB_ID(NewThisObject), {ctor});
350 Jump(&exit);
351 }
352 Bind(&exit);
353 auto ret = *thisObj;
354 env->SubCfgExit();
355 return ret;
356 }
357
NewThisObjectChecked(GateRef glue,GateRef ctor)358 GateRef NewObjectStubBuilder::NewThisObjectChecked(GateRef glue, GateRef ctor)
359 {
360 auto env = GetEnvironment();
361 Label entry(env);
362 env->SubCfgEntry(&entry);
363 Label exit(env);
364
365 Label ctorIsHeapObject(env);
366 Label ctorIsJSFunction(env);
367 Label fastPath(env);
368 Label slowPath(env);
369 Label ctorIsBase(env);
370
371 DEFVARIABLE(thisObj, VariableType::JS_ANY(), Undefined());
372
373 Branch(TaggedIsHeapObject(ctor), &ctorIsHeapObject, &slowPath);
374 Bind(&ctorIsHeapObject);
375 Branch(IsJSFunction(ctor), &ctorIsJSFunction, &slowPath);
376 Bind(&ctorIsJSFunction);
377 Branch(IsConstructor(ctor), &fastPath, &slowPath);
378 Bind(&fastPath);
379 {
380 Branch(IsBase(ctor), &ctorIsBase, &exit);
381 Bind(&ctorIsBase);
382 {
383 thisObj = FastNewThisObject(glue, ctor);
384 Jump(&exit);
385 }
386 }
387 Bind(&slowPath);
388 {
389 thisObj = Hole();
390 Jump(&exit);
391 }
392 Bind(&exit);
393 auto ret = *thisObj;
394 env->SubCfgExit();
395 return ret;
396 }
397 } // namespace panda::ecmascript::kungfu
398