1 /*
2 * Copyright (c) 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/compiler/builtins/builtins_proxy_stub_builder.h"
17 #include "ecmascript/compiler/call_stub_builder.h"
18 #include "ecmascript/compiler/new_object_stub_builder.h"
19
20 namespace panda::ecmascript::kungfu {
GenProxyConstructor(GateRef nativeCode,GateRef func,GateRef newTarget)21 void BuiltinsProxyStubBuilder::GenProxyConstructor(GateRef nativeCode, GateRef func, GateRef newTarget)
22 {
23 auto env = GetEnvironment();
24 DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
25 Label thisCollectionObj(env);
26 Label slowPath(env);
27 Label slowPath1(env);
28 Label exit(env);
29
30 Label handleIsEcma(env);
31 Label targetIsEcma(env);
32 Label newTargetNotUndefined(env);
33 BRANCH(TaggedIsUndefined(newTarget), &slowPath, &newTargetNotUndefined);
34 Bind(&newTargetNotUndefined);
35
36 GateRef target = GetArgFromArgv(glue_, IntPtr(0), numArgs_, true);
37 GateRef handler = GetArgFromArgv(glue_, IntPtr(1), numArgs_, true);
38
39 BRANCH(IsEcmaObject(glue_, target), &targetIsEcma, &slowPath);
40 Bind(&targetIsEcma);
41 BRANCH(IsEcmaObject(glue_, handler), &handleIsEcma, &slowPath);
42 Bind(&handleIsEcma);
43 {
44 NewObjectStubBuilder newBuilder(this, GetCurrentGlobalEnv());
45 newBuilder.SetParameters(glue_, IntPtr(0));
46 res = newBuilder.NewJSProxy(glue_, target, handler);
47 Jump(&exit);
48 }
49 Bind(&slowPath);
50 {
51 GateRef argv = GetArgv();
52 res = CallBuiltinRuntime(glue_, { glue_, nativeCode, func, thisValue_, numArgs_, argv }, true);
53 Jump(&exit);
54 }
55 Bind(&exit);
56 Return(*res);
57 }
58
CheckGetTrapResult(GateRef target,GateRef key,Variable * result,Label * exit)59 void BuiltinsProxyStubBuilder::CheckGetTrapResult(GateRef target, GateRef key, Variable *result, Label *exit)
60 {
61 auto env = GetEnvironment();
62 Label callRuntime(env);
63 Label isFoundData(env);
64 Label isFoundAccessor(env);
65 DEFVARIABLE(value, VariableType::JS_ANY(), Hole());
66 DEFVARIABLE(attr, VariableType::INT64(), Int64(0));
67 TryGetOwnProperty(glue_, target, key, Circuit::NullGate(), &value, &attr,
68 &isFoundData, &isFoundAccessor, exit, &callRuntime);
69 Bind(&isFoundData);
70 {
71 Label trapResultTypeError(env);
72 GateRef rAttr = attr.ReadVariable();
73 GateRef rValue = value.ReadVariable();
74 GateRef rResult = result->ReadVariable();
75 GateRef trapResultCheck = LogicOrBuilder(env).Or(IsConfigable(rAttr))
76 .Or(IsWritable(rAttr))
77 .Or(SameValue(glue_, rResult, rValue))
78 .Done();
79 BRANCH(BoolNot(trapResultCheck), &trapResultTypeError, exit);
80 Bind(&trapResultTypeError);
81 {
82 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(ProxyGetPropertyResultTypeError));
83 CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(),
84 RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
85 result->WriteVariable(Exception());
86 Jump(exit);
87 }
88 }
89 Bind(&isFoundAccessor);
90 {
91 Label trapResultIsUndefined(env);
92 Label trapResultIsNotUndefined(env);
93 GateRef rAttr = attr.ReadVariable();
94 GateRef rValue = value.ReadVariable();
95 GateRef rResult = result->ReadVariable();
96 GateRef getter = Load(VariableType::JS_ANY(), glue_, rValue, IntPtr(AccessorData::GETTER_OFFSET));
97 GateRef trapResultCheck = LogicAndBuilder(env).And(BoolNot(IsConfigable(rAttr)))
98 .And(TaggedIsUndefined(getter))
99 .And(BoolNot(TaggedIsUndefined(rResult)))
100 .Done();
101 BRANCH(trapResultCheck, &trapResultIsNotUndefined, exit);
102 Bind(&trapResultIsNotUndefined);
103 {
104 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(ProxyGetPropertyResultNotUndefined));
105 CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(),
106 RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
107 result->WriteVariable(Exception());
108 Jump(exit);
109 }
110 }
111 Bind(&callRuntime);
112 {
113 result->WriteVariable(CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(),
114 RTSTUB_ID(CheckGetTrapResult), { target, key, result->ReadVariable() }));
115 Jump(exit);
116 }
117 }
118
CheckSetTrapResult(GateRef target,GateRef key,GateRef value,Variable * result,Label * exit)119 void BuiltinsProxyStubBuilder::CheckSetTrapResult(GateRef target, GateRef key, GateRef value,
120 Variable *result, Label *exit)
121 {
122 auto env = GetEnvironment();
123 Label callRuntime(env);
124 Label isFoundData(env);
125 Label isFoundAccessor(env);
126 DEFVARIABLE(tValue, VariableType::JS_ANY(), Hole());
127 DEFVARIABLE(attr, VariableType::INT64(), Int64(0));
128 TryGetOwnProperty(glue_, target, key, Circuit::NullGate(), &tValue, &attr,
129 &isFoundData, &isFoundAccessor, exit, &callRuntime);
130 Bind(&isFoundData);
131 {
132 Label trapResultTypeError(env);
133 GateRef rAttr = attr.ReadVariable();
134 GateRef rValue = tValue.ReadVariable();
135 GateRef trapResultCheck = LogicOrBuilder(env).Or(IsConfigable(rAttr))
136 .Or(IsWritable(rAttr))
137 .Or(SameValue(glue_, value, rValue))
138 .Done();
139 BRANCH(BoolNot(trapResultCheck), &trapResultTypeError, exit);
140 Bind(&trapResultTypeError);
141 {
142 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(ProxySetPropertyResultTypeError));
143 CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(),
144 RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
145 result->WriteVariable(TaggedFalse());
146 Jump(exit);
147 }
148 }
149 Bind(&isFoundAccessor);
150 {
151 Label trapResultIsUndefined(env);
152 Label trapResultIsNotUndefined(env);
153 GateRef rAttr = attr.ReadVariable();
154 GateRef rValue = tValue.ReadVariable();
155 GateRef setter = Load(VariableType::JS_ANY(), glue_, rValue, IntPtr(AccessorData::SETTER_OFFSET));
156 GateRef trapResultCheck = LogicAndBuilder(env).And(BoolNot(IsConfigable(rAttr)))
157 .And(TaggedIsUndefined(setter))
158 .Done();
159 BRANCH(trapResultCheck, &trapResultIsNotUndefined, exit);
160 Bind(&trapResultIsNotUndefined);
161 {
162 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(ProxySetPropertyResultNotAccessor));
163 CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(),
164 RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
165 result->WriteVariable(TaggedFalse());
166 Jump(exit);
167 }
168 }
169 Bind(&callRuntime);
170 {
171 result->WriteVariable(CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(),
172 RTSTUB_ID(CheckSetTrapResult), { target, key, value }));
173 Jump(exit);
174 }
175 }
176
GetProperty(GateRef proxy,GateRef key,GateRef receiver)177 GateRef BuiltinsProxyStubBuilder::GetProperty(GateRef proxy, GateRef key, GateRef receiver)
178 {
179 auto env = GetEnvironment();
180 DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
181 Label stackOverflow(env);
182 Label dispatch(env);
183 Label checkGetTrapResult(env);
184 Label exit(env);
185 Label handlerIsNull(env);
186 Label handlerIsNotNull(env);
187 Label slowPath(env);
188 Label trapIsCallable(env);
189 Label trapFastPath(env);
190 BRANCH_UNLIKELY(CheckStackOverflow(glue_), &stackOverflow, &dispatch);
191 Bind(&stackOverflow);
192 {
193 CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(), RTSTUB_ID(ThrowStackOverflowException), {});
194 result = Exception();
195 Jump(&exit);
196 }
197 Bind(&dispatch);
198 GateRef handler = GetHandler(glue_, proxy);
199 BRANCH(TaggedIsNull(handler), &handlerIsNull, &handlerIsNotNull);
200 Bind(&handlerIsNull);
201 {
202 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(ProxyGetPropertyHandlerIsNull));
203 CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(), RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
204 result = Exception();
205 Jump(&exit);
206 }
207 Bind(&handlerIsNotNull);
208 {
209 GateRef target = GetTarget(glue_, proxy);
210 GateRef name = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_,
211 ConstantIndex::GET_STRING_INDEX);
212 GateRef trap = GetPropertyByName(glue_, handler, name);
213 Label isPendingException(env);
214 Label noPendingException(env);
215 BRANCH_UNLIKELY(HasPendingException(glue_), &isPendingException, &noPendingException);
216 Bind(&isPendingException);
217 {
218 result = Exception();
219 Jump(&exit);
220 }
221 Bind(&noPendingException);
222 BRANCH(TaggedIsHeapObject(trap), &trapFastPath, &slowPath);
223 Bind(&trapFastPath);
224 {
225 BRANCH(IsCallable(glue_, trap), &trapIsCallable, &slowPath);
226 Bind(&trapIsCallable);
227 {
228 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
229 callArgs.callThisArg3WithReturnArgs = { handler, target, key, receiver };
230 CallStubBuilder callBuilder(this, glue_, trap,
231 Int32(3), 0, nullptr, Circuit::NullGate(), callArgs); // 3 : three arg
232 result = callBuilder.JSCallDispatch();
233 Jump(&checkGetTrapResult);
234 }
235 }
236 Bind(&checkGetTrapResult);
237 {
238 CheckGetTrapResult(target, key, &result, &exit);
239 }
240 Bind(&slowPath);
241 {
242 result = CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(),
243 RTSTUB_ID(JSProxyGetProperty), { proxy, key, receiver });
244 Jump(&exit);
245 }
246 }
247 Bind(&exit);
248 auto ret = *result;
249 return ret;
250 }
251
SetProperty(GateRef proxy,GateRef key,GateRef value,GateRef receiver,bool mayThrow)252 GateRef BuiltinsProxyStubBuilder::SetProperty(GateRef proxy, GateRef key, GateRef value, GateRef receiver,
253 bool mayThrow)
254 {
255 auto env = GetEnvironment();
256 DEFVARIABLE(result, VariableType::JS_ANY(), TaggedTrue());
257 Label stackOverflow(env);
258 Label dispatch(env);
259 Label trapResultIsFalse(env);
260 Label checkSetTrapResult(env);
261 Label exit(env);
262 Label handlerIsNull(env);
263 Label handlerIsNotNull(env);
264 Label slowPath(env);
265 Label trapIsCallable(env);
266 Label trapFastPath(env);
267 BRANCH_UNLIKELY(CheckStackOverflow(glue_), &stackOverflow, &dispatch);
268 Bind(&stackOverflow);
269 {
270 CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(), RTSTUB_ID(ThrowStackOverflowException), {});
271 result = TaggedFalse();
272 Jump(&exit);
273 }
274 Bind(&dispatch);
275 GateRef handler = GetHandler(glue_, proxy);
276 BRANCH(TaggedIsNull(handler), &handlerIsNull, &handlerIsNotNull);
277 Bind(&handlerIsNull);
278 {
279 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(ProxySetPropertyHandlerIsNull));
280 CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(), RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
281 result = TaggedFalse();
282 Jump(&exit);
283 }
284 Bind(&handlerIsNotNull);
285 {
286 GateRef target = GetTarget(glue_, proxy);
287 GateRef name = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_,
288 ConstantIndex::SET_STRING_INDEX);
289 GateRef trap = GetPropertyByName(glue_, handler, name);
290 Label isPendingException(env);
291 Label noPendingException(env);
292 BRANCH_UNLIKELY(HasPendingException(glue_), &isPendingException, &noPendingException);
293 Bind(&isPendingException);
294 {
295 result = TaggedFalse();
296 Jump(&exit);
297 }
298 Bind(&noPendingException);
299 BRANCH(TaggedIsHeapObject(trap), &trapFastPath, &slowPath);
300 Bind(&trapFastPath);
301 {
302 BRANCH(IsCallable(glue_, trap), &trapIsCallable, &slowPath);
303 Bind(&trapIsCallable);
304 {
305 GateRef argsLength = Int32(4);
306 NewObjectStubBuilder newBuilder(this);
307 GateRef argList = newBuilder.NewTaggedArray(glue_, argsLength);
308 // param 0: target
309 SetValueToTaggedArray(VariableType::JS_ANY(), glue_, argList, Int32(0), target);
310 // param 1: key
311 SetValueToTaggedArray(VariableType::JS_ANY(), glue_, argList, Int32(1), key);
312 // param 2: value
313 SetValueToTaggedArray(VariableType::JS_ANY(), glue_, argList, Int32(2), value);
314 // param 3: receiver
315 SetValueToTaggedArray(VariableType::JS_ANY(), glue_, argList, Int32(3), receiver);
316 GateRef argv = PtrAdd(argList, IntPtr(TaggedArray::DATA_OFFSET));
317 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARGV_WITH_RETURN);
318 callArgs.callThisArgvWithReturnArgs = { argsLength, argv, handler };
319 CallStubBuilder callBuilder(this, glue_, trap, argsLength, 0, nullptr,
320 Circuit::NullGate(), callArgs);
321 GateRef trapResult = callBuilder.JSCallDispatch();
322 BRANCH(TaggedIsFalse(FastToBoolean(glue_, trapResult)), &trapResultIsFalse, &checkSetTrapResult);
323 Bind(&trapResultIsFalse);
324 {
325 if (mayThrow) {
326 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(ProxySetPropertyReturnFalse));
327 CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(),
328 RTSTUB_ID(ThrowTypeError), {IntToTaggedInt(taggedId)});
329 }
330 result = TaggedFalse();
331 Jump(&exit);
332 }
333 }
334 }
335 Bind(&checkSetTrapResult);
336 {
337 CheckSetTrapResult(target, key, value, &result, &exit);
338 }
339 Bind(&slowPath);
340 {
341 result = CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(), RTSTUB_ID(JSProxySetProperty),
342 {proxy, key, value, receiver, mayThrow ? TaggedTrue() : TaggedFalse()});
343 Jump(&exit);
344 }
345 }
346 Bind(&exit);
347 auto ret = *result;
348 return ret;
349 }
350 } // namespace panda::ecmascript::kungfu
351