• 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/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