1 /*
2 * Copyright (c) 2023 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/builtins/builtins_function_stub_builder.h"
17
18 #include "ecmascript/compiler/builtins/builtins_object_stub_builder.h"
19 #include "ecmascript/compiler/stub_builder-inl.h"
20 #include "ecmascript/js_arguments.h"
21
22 namespace panda::ecmascript::kungfu {
23
Apply(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)24 void BuiltinsFunctionStubBuilder::Apply(GateRef glue, GateRef thisValue,
25 GateRef numArgs, Variable* res, Label *exit, Label *slowPath)
26 {
27 auto env = GetEnvironment();
28 Label targetIsCallable(env);
29 Label targetIsUndefined(env);
30 Label targetNotUndefined(env);
31 Label isHeapObject(env);
32 //1. If IsCallable(func) is false, throw a TypeError exception
33 Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
34 Bind(&isHeapObject);
35 {
36 Branch(IsCallable(thisValue), &targetIsCallable, slowPath);
37 Bind(&targetIsCallable);
38 {
39 GateRef thisArg = GetCallArg0(numArgs);
40 GateRef arrayObj = GetCallArg1(numArgs);
41 // 2. If argArray is null or undefined, then
42 Branch(TaggedIsUndefined(arrayObj), &targetIsUndefined, &targetNotUndefined);
43 Bind(&targetIsUndefined);
44 {
45 // a. Return Call(func, thisArg).
46 res->WriteVariable(JSCallDispatch(glue, thisValue, Int32(0), 0, Circuit::NullGate(),
47 JSCallMode::CALL_GETTER, { thisArg }));
48 Jump(exit);
49 }
50 Bind(&targetNotUndefined);
51 {
52 // 3. Let argList be CreateListFromArrayLike(argArray).
53 GateRef elements = BuildArgumentsListFastElements(glue, arrayObj);
54 Label targetIsHole(env);
55 Label targetNotHole(env);
56 Branch(TaggedIsHole(elements), &targetIsHole, &targetNotHole);
57 Bind(&targetIsHole);
58 {
59 BuiltinsObjectStubBuilder objectStubBuilder(this);
60 GateRef argList = objectStubBuilder.CreateListFromArrayLike(glue, arrayObj);
61 // 4. ReturnIfAbrupt(argList).
62 Label isPendingException(env);
63 Label noPendingException(env);
64 Branch(HasPendingException(glue), &isPendingException, &noPendingException);
65 Bind(&isPendingException);
66 {
67 Jump(slowPath);
68 }
69 Bind(&noPendingException);
70 {
71 GateRef argsLength = GetLengthOfTaggedArray(argList);
72 GateRef argv = PtrAdd(argList, IntPtr(TaggedArray::DATA_OFFSET));
73 res->WriteVariable(JSCallDispatch(glue, thisValue, argsLength, 0, Circuit::NullGate(),
74 JSCallMode::CALL_THIS_ARGV_WITH_RETURN, { argsLength, argv, thisArg }));
75 Jump(exit);
76 }
77 }
78 Bind(&targetNotHole);
79 {
80 // 6. Return Call(func, thisArg, argList).
81 Label taggedIsStableJsArg(env);
82 Label taggedNotStableJsArg(env);
83 Branch(IsStableJSArguments(glue, arrayObj), &taggedIsStableJsArg, &taggedNotStableJsArg);
84 Bind(&taggedIsStableJsArg);
85 {
86 GateRef hClass = LoadHClass(arrayObj);
87 GateRef PropertyInlinedPropsOffset = IntPtr(JSArguments::LENGTH_INLINE_PROPERTY_INDEX);
88 GateRef result = GetPropertyInlinedProps(arrayObj, hClass, PropertyInlinedPropsOffset);
89 GateRef length = TaggedGetInt(result);
90 GateRef argsLength = MakeArgListWithHole(glue, elements, length);
91 GateRef elementArgv = PtrAdd(elements, IntPtr(TaggedArray::DATA_OFFSET));
92 res->WriteVariable(JSCallDispatch(glue, thisValue, argsLength, 0, Circuit::NullGate(),
93 JSCallMode::CALL_THIS_ARGV_WITH_RETURN, { argsLength, elementArgv, thisArg }));
94 Jump(exit);
95 }
96 Bind(&taggedNotStableJsArg);
97 {
98 GateRef length = GetArrayLength(arrayObj);
99 GateRef argsLength = MakeArgListWithHole(glue, elements, length);
100 GateRef elementArgv = PtrAdd(elements, IntPtr(TaggedArray::DATA_OFFSET));
101 res->WriteVariable(JSCallDispatch(glue, thisValue, argsLength, 0, Circuit::NullGate(),
102 JSCallMode::CALL_THIS_ARGV_WITH_RETURN, { argsLength, elementArgv, thisArg }));
103 Jump(exit);
104 }
105 }
106 }
107 }
108 }
109 }
110
111 // return elements
BuildArgumentsListFastElements(GateRef glue,GateRef arrayObj)112 GateRef BuiltinsFunctionStubBuilder::BuildArgumentsListFastElements(GateRef glue, GateRef arrayObj)
113 {
114 auto env = GetEnvironment();
115 Label subentry(env);
116 env->SubCfgEntry(&subentry);
117 DEFVARIABLE(res, VariableType::JS_ANY(), Hole());
118 Label exit(env);
119 Label hasStableElements(env);
120 Label targetIsStableJSArguments(env);
121 Label targetNotStableJSArguments(env);
122 Label targetIsInt(env);
123 Label hClassEqual(env);
124 Label targetIsStableJSArray(env);
125 Label targetNotStableJSArray(env);
126
127 Branch(HasStableElements(glue, arrayObj), &hasStableElements, &exit);
128 Bind(&hasStableElements);
129 {
130 Branch(IsStableJSArguments(glue, arrayObj), &targetIsStableJSArguments, &targetNotStableJSArguments);
131 Bind(&targetIsStableJSArguments);
132 {
133 GateRef hClass = LoadHClass(arrayObj);
134 GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
135 GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
136 GateRef argmentsClass = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
137 GlobalEnv::ARGUMENTS_CLASS);
138 Branch(Int64Equal(hClass, argmentsClass), &hClassEqual, &exit);
139 Bind(&hClassEqual);
140 {
141 GateRef PropertyInlinedPropsOffset = IntPtr(JSArguments::LENGTH_INLINE_PROPERTY_INDEX);
142 GateRef result = GetPropertyInlinedProps(arrayObj, hClass, PropertyInlinedPropsOffset);
143 Branch(TaggedIsInt(result), &targetIsInt, &exit);
144 Bind(&targetIsInt);
145 {
146 res = GetElementsArray(arrayObj);
147 Jump(&exit);
148 }
149 }
150 }
151 Bind(&targetNotStableJSArguments);
152 {
153 Branch(IsStableJSArray(glue, arrayObj), &targetIsStableJSArray, &targetNotStableJSArray);
154 Bind(&targetIsStableJSArray);
155 {
156 res = GetElementsArray(arrayObj);
157 Jump(&exit);
158 }
159 Bind(&targetNotStableJSArray);
160 {
161 FatalPrint(glue, { Int32(GET_MESSAGE_STRING_ID(ThisBranchIsUnreachable)) });
162 Jump(&exit);
163 }
164 }
165 }
166 Bind(&exit);
167 auto ret = *res;
168 env->SubCfgExit();
169 return ret;
170 }
171
MakeArgListWithHole(GateRef glue,GateRef argv,GateRef length)172 GateRef BuiltinsFunctionStubBuilder::MakeArgListWithHole(GateRef glue, GateRef argv, GateRef length)
173 {
174 auto env = GetEnvironment();
175 Label subentry(env);
176 env->SubCfgEntry(&subentry);
177 DEFVARIABLE(res, VariableType::INT32(), length);
178 DEFVARIABLE(i, VariableType::INT32(), Int32(0));
179 Label exit(env);
180
181 GateRef argsLength = GetLengthOfTaggedArray(argv);
182
183 Label lengthGreaterThanArgsLength(env);
184 Label lengthLessThanArgsLength(env);
185 Branch(Int32GreaterThan(length, argsLength), &lengthGreaterThanArgsLength, &lengthLessThanArgsLength);
186 Bind(&lengthGreaterThanArgsLength);
187 {
188 res = argsLength;
189 Jump(&lengthLessThanArgsLength);
190 }
191 Bind(&lengthLessThanArgsLength);
192 {
193 Label loopHead(env);
194 Label loopEnd(env);
195 Label targetIsHole(env);
196 Label targetNotHole(env);
197 Branch(Int32UnsignedLessThan(*i, *res), &loopHead, &exit);
198 LoopBegin(&loopHead);
199 {
200 GateRef value = GetValueFromTaggedArray(argv, *i);
201 Branch(TaggedIsHole(value), &targetIsHole, &targetNotHole);
202 Bind(&targetIsHole);
203 {
204 SetValueToTaggedArray(VariableType::JS_ANY(), glue, argv, *i, Undefined());
205 Jump(&targetNotHole);
206 }
207 Bind(&targetNotHole);
208 i = Int32Add(*i, Int32(1));
209 Branch(Int32UnsignedLessThan(*i, *res), &loopEnd, &exit);
210 }
211 Bind(&loopEnd);
212 LoopEnd(&loopHead);
213 }
214 Bind(&exit);
215 auto ret = *res;
216 env->SubCfgExit();
217 return ret;
218 }
219 } // namespace panda::ecmascript::kungfu
220