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