• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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