• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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/object_operator_stub_builder.h"
17 
18 #include "ecmascript/compiler/builtins/builtins_string_stub_builder.h"
19 #include "ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h"
20 #include "ecmascript/compiler/circuit_builder_helper.h"
21 #include "ecmascript/compiler/rt_call_signature.h"
22 #include "ecmascript/compiler/stub_builder-inl.h"
23 #include "ecmascript/ecma_string.h"
24 #include "ecmascript/js_primitive_ref.h"
25 #include "ecmascript/object_operator.h"
26 
27 namespace panda::ecmascript::kungfu {
28 
29 // ObjectOperator::HandleKey
HandleKey(GateRef glue,GateRef key,Variable * propKey,Variable * elemKey,Label * isProperty,Label * isElement,Label * hasException,GateRef hir)30 void ObjectOperatorStubBuilder::HandleKey(GateRef glue, GateRef key, Variable *propKey, Variable *elemKey,
31                                           Label *isProperty, Label *isElement, Label *hasException, GateRef hir)
32 {
33     auto env = GetEnvironment();
34     Label isInt(env);
35     Label notInt(env);
36     Label isString(env);
37     Label notString(env);
38     Label isDouble(env);
39     Label notDouble(env);
40     Label isSymbol(env);
41     Label notSymbol(env);
42 
43     BRANCH(TaggedIsInt(key), &isInt, &notInt);
44 
45     Bind(&isInt);
46     {
47         Label numberToString(env);
48         Label indexIsValid(env);
49         DEFVARIABLE(index, VariableType::INT32(), Int32(-1));
50         index = GetInt32OfTInt(key);
51         BRANCH(Int32GreaterThanOrEqual(*index, Int32(0)), &indexIsValid, &numberToString);
52         Bind(&indexIsValid);
53         {
54             *elemKey = *index;
55             Jump(isElement);
56         }
57         Bind(&numberToString);
58         {
59             *propKey = NumberToString(glue, key);
60             Jump(isProperty);
61         }
62     }
63 
64     Bind(&notInt);
65     BRANCH(TaggedIsString(glue, key), &isString, &notString);
66 
67     Bind(&isString);
68     {
69         Label toInternString(env);
70         Label index64To32(env);
71         Label notInternString(env);
72         DEFVARIABLE(index64, VariableType::INT64(), Int64(-1));
73         BuiltinsStringStubBuilder stringStub(this, GetCurrentGlobalEnv());
74         index64 = stringStub.StringToUint(glue, key, JSObject::MAX_ELEMENT_INDEX - 1);
75         BRANCH(Int64Equal(*index64, Int64(-1)), &toInternString, &index64To32);
76         Bind(&toInternString);
77         {
78             *propKey = key;
79             BRANCH(IsInternalString(propKey->ReadVariable()), isProperty, &notInternString);
80             Bind(&notInternString);
81             {
82                 // fixme(hewei): need the implementation of StringTable IR, callruntime now.
83                 *propKey = CallRuntime(glue, RTSTUB_ID(NewInternalString), {propKey->ReadVariable()});
84                 Jump(isProperty);
85             }
86         }
87 
88         Bind(&index64To32);
89         {
90             *elemKey = TruncInt64ToInt32(*index64);
91             Jump(isElement);
92         }
93     }
94 
95     Bind(&notString);
96     BRANCH(TaggedIsDouble(key), &isDouble, &notDouble);
97 
98     Bind(&isDouble);
99     {
100         GateRef number = GetDoubleOfTDouble(key);
101         GateRef integer = ChangeFloat64ToInt32(number);
102         Label inRange(env);
103         Label isEqual(env);
104         Label tryToString(env);
105 
106         BRANCH(LogicAndBuilder(env)
107                    .And(DoubleGreaterThanOrEqual(number, Double(0)))
108                    .And(DoubleLessThan(number, Double(JSObject::MAX_ELEMENT_INDEX)))
109                    .Done(),
110                &inRange,
111                &tryToString);
112 
113         Bind(&inRange);
114         BRANCH(DoubleEqual(number, ChangeInt32ToFloat64(integer)), &isEqual, &tryToString);
115 
116         Bind(&isEqual);
117         {
118             *elemKey = integer;
119             Jump(isElement);
120         }
121 
122         Bind(&tryToString);
123         {
124             Label notInternString(env);
125             *propKey = NumberToString(glue, key);
126             BRANCH(IsInternalString(propKey->ReadVariable()), isProperty, &notInternString);
127             Bind(&notInternString);
128             {
129                 // fixme(hewei): need the implementation of StringTable IR, callruntime now.
130                 *propKey = CallRuntime(glue, RTSTUB_ID(NewInternalString), {propKey->ReadVariable()});
131                 Jump(isProperty);
132             }
133         }
134     }
135 
136     Bind(&notDouble);
137     BRANCH(IsSymbol(glue, key), &isSymbol, &notSymbol);
138 
139     Bind(&isSymbol);
140     {
141         *propKey = key;
142         Jump(isProperty);
143     }
144 
145     Bind(&notSymbol);
146     {
147         Label noException(env);
148         *propKey = ToPrimitive(glue, key, PreferredPrimitiveType::PREFER_STRING, hir);
149         BRANCH(HasPendingException(glue), hasException, &noException);
150         Bind(&noException);
151         {
152             Label toString(env);
153             BRANCH(IsSymbol(glue, propKey->ReadVariable()), isProperty, &toString);
154             Bind(&toString);
155             {
156                 *propKey = JSTaggedValueToString(glue, propKey->ReadVariable(), hir);
157                 // fixme(hewei): need the implementation of StringTable IR, callruntime now.
158                 *propKey = CallRuntime(glue, RTSTUB_ID(NewInternalString), {propKey->ReadVariable()});
159                 Jump(isProperty);
160             }
161         }
162     }
163 }
164 
165 template <bool keyIsElement>
CheckValidIndexOrKeyIsLength(GateRef glue,GateRef holder,GateRef receiver,GateRef key,Label * checkSucc,Label * checkFail)166 void ObjectOperatorStubBuilder::CheckValidIndexOrKeyIsLength(GateRef glue, GateRef holder, GateRef receiver,
167                                                              GateRef key, Label *checkSucc, Label *checkFail)
168 {
169     auto env = GetEnvironment();
170     if constexpr (keyIsElement) {
171         /// For element, key is an int32 number.
172         BRANCH(Int32LessThan(key, GetLengthFromString(holder)), checkSucc, checkFail);
173     } else {
174         Label keyIsString(env);
175         BRANCH(BitAnd(TaggedIsString(glue, key), TaggedIsString(glue, receiver)), &keyIsString, checkFail);
176         Bind(&keyIsString);
177         {
178             GateRef lengthString =
179                 GetGlobalConstantValue(VariableType::JS_POINTER(), glue, ConstantIndex::LENGTH_STRING_INDEX);
180             BRANCH(FastStringEqual(glue, key, lengthString), checkSucc, checkFail);
181         }
182     }
183 }
184 
185 template <bool keyIsElement>
UpdateHolder(GateRef glue,ObjectOperatorResult & results,GateRef key,Label * holderUpdated)186 void ObjectOperatorStubBuilder::UpdateHolder(GateRef glue, ObjectOperatorResult &results,
187                                              GateRef key, Label *holderUpdated)
188 {
189     auto env = GetEnvironment();
190     Label notEcmaObject(env);
191     Label isString(env);
192     Label checkIsPrimitiveBoolOrNumber(env);
193     Label setOnProtoType(env);
194     Label toProtoType(env);
195     BRANCH(IsEcmaObject(glue, results.GetHolder()), holderUpdated, &notEcmaObject);
196 
197     Bind(&notEcmaObject);
198     {
199         BRANCH(TaggedIsString(glue, results.GetHolder()), &isString, &checkIsPrimitiveBoolOrNumber);
200     }
201     Bind(&isString);
202     {
203         Label checkSucess(env);
204         CheckValidIndexOrKeyIsLength<keyIsElement>(glue, results.GetHolder(), results.GetReceiver(),
205                                                    key, &checkSucess, &setOnProtoType);
206 
207         Bind(&checkSucess);
208         {
209             // fixme(hewei): need the implementation of JSTaggedValue::DefinePropertyOrThrow IR, callruntime now.
210             *results.holder = CallRuntime(glue, RTSTUB_ID(PrimitiveStringCreate), {results.GetHolder()});
211             Jump(holderUpdated);
212         }
213     }
214 
215     Bind(&checkIsPrimitiveBoolOrNumber);
216     {
217         BRANCH(BitOr(TaggedIsNumber(results.GetHolder()), TaggedIsBoolean(results.GetHolder())),
218                &setOnProtoType, &toProtoType);
219     }
220 
221     Bind(&setOnProtoType);
222     {
223         SetIsOnProtoType(results);
224         Jump(&toProtoType);
225     }
226 
227     Bind(&toProtoType);
228     *results.holder = ToPrototypeOrObj(glue, results.GetHolder());
229     Jump(holderUpdated);
230 }
231 
LookupPropertyInlinedProps(GateRef glue,GateRef obj,GateRef key,Label * exit,const ObjectOperatorOptions & options,ObjectOperatorResult & results,GateRef hir)232 void ObjectOperatorStubBuilder::LookupPropertyInlinedProps(GateRef glue, GateRef obj, GateRef key, Label *exit,
233                                                            const ObjectOperatorOptions &options,
234                                                            ObjectOperatorResult &results,
235                                                            GateRef hir)
236 {
237     auto env = GetEnvironment();
238     Label isJsObject(env);
239     Label notJsGlobalObject(env);
240     Label isDicMode(env);
241 
242     BRANCH(IsJSObject(glue, obj), &isJsObject, exit);
243     Bind(&isJsObject);
244     {
245         BRANCH(IsJSGlobalObject(glue, obj), &isDicMode, &notJsGlobalObject);
246     }
247 
248     Bind(&notJsGlobalObject);
249     {
250         Label notDicMod(env);
251         GateRef hclass = LoadHClass(glue, obj);
252         BRANCH(IsDictionaryModeByHClass(hclass), &isDicMode, &notDicMod);
253         Bind(&notDicMod);
254         {
255             Label hasEntry(env);
256             GateRef layOutInfo = GetLayoutFromHClass(glue, hclass);
257             GateRef propsNum = GetNumberOfPropsFromHClass(hclass);
258             // int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber)
259             GateRef entryA = FindElementWithCache(glue, layOutInfo, hclass, key, propsNum, hir);
260             // if branch condition : entry != -1
261             BRANCH(Int32NotEqual(entryA, Int32(-1)), &hasEntry, exit);
262             Bind(&hasEntry);
263             {
264                 if (options.lookupKind == LookupKind::KIND_HAS_PROPERTY) {
265                     SetFound(results);
266                     Jump(exit);
267                 } else {
268                     ASSERT(options.lookupKind == LookupKind::KIND_GET_PROPERTY ||
269                            options.lookupKind == LookupKind::KIND_SET_PROPERTY);
270                     GateRef attr = GetPropAttrFromLayoutInfo(glue, layOutInfo, entryA);
271                     GateRef result = JSObjectGetPropertyWithRep(glue, obj, hclass, attr);
272                     SetFound(results, result, entryA, attr);
273                     Jump(exit);
274                 }
275             }
276         }
277     }
278     Bind(&isDicMode);
279     {
280         Label findInDic(env);
281         Label hasEntry(env);
282         GateRef array = GetPropertiesArray(glue, obj);
283         GateRef len = GetLengthOfTaggedArray(array);
284         BRANCH(Int32Equal(len, Int32(0)), exit, &findInDic);
285 
286         Bind(&findInDic);
287         // int entry = dict->FindEntry(key)
288         GateRef entryB = FindEntryFromHashTable<NameDictionary>(glue, array, key, hir);
289         // if branch condition : entry != -1
290 
291         BRANCH(Int32NotEqual(entryB, Int32(-1)), &hasEntry, exit);
292         Bind(&hasEntry);
293         {
294             if (options.lookupKind == LookupKind::KIND_HAS_PROPERTY) {
295                 SetFound(results);
296                 Jump(exit);
297             } else {
298                 ASSERT(options.lookupKind == LookupKind::KIND_GET_PROPERTY ||
299                        options.lookupKind == LookupKind::KIND_SET_PROPERTY);
300                 GateRef attr = GetAttributesFromDictionary<NumberDictionary>(glue, array, entryB);
301                 GateRef value = GetValueFromDictionary<NumberDictionary>(glue, array, entryB);
302                 SetFound(results, value, entryB, attr);
303                 Jump(exit);
304             }
305         }
306     }
307 }
308 
LookupElementInlinedProps(GateRef glue,GateRef obj,GateRef elementIdx,Label * exit,const ObjectOperatorOptions & options,ObjectOperatorResult & results,GateRef hir)309 void ObjectOperatorStubBuilder::LookupElementInlinedProps(GateRef glue, GateRef obj, GateRef elementIdx, Label *exit,
310                                                           const ObjectOperatorOptions &options,
311                                                           ObjectOperatorResult &results,
312                                                           GateRef hir)
313 {
314     auto env = GetEnvironment();
315     Label isPrimitiveRef(env);
316     Label isStringObject(env);
317     Label notStringObject(env);
318     Label isTypedArray(env);
319     Label ordinaryObject(env);
320     // fastpath for string obj
321     BRANCH(IsJSPrimitiveRef(glue, obj), &isPrimitiveRef, &notStringObject);
322     Bind(&isPrimitiveRef);
323     {
324         GateRef value = Load(VariableType::JS_ANY(), glue, obj, IntPtr(JSPrimitiveRef::VALUE_OFFSET));
325         BRANCH(TaggedIsString(glue, value), &isStringObject, &notStringObject);
326         Bind(&isStringObject);
327         {
328             Label elementFound(env);
329             GateRef strLength = GetLengthFromString(value);
330             BRANCH(Int32LessThan(elementIdx, strLength), &elementFound, &notStringObject);
331             Bind(&elementFound);
332             {
333                 if (options.lookupKind == LookupKind::KIND_HAS_PROPERTY) {
334                     SetFound(results);
335                     Jump(exit);
336                 } else {
337                     ASSERT(options.lookupKind == LookupKind::KIND_GET_PROPERTY ||
338                            options.lookupKind == LookupKind::KIND_SET_PROPERTY);
339                     // flatten string so next time we use the string, it is a flat string.
340                     Label afterFlatten(env);
341                     BuiltinsStringStubBuilder stringBuilder(this, GetCurrentGlobalEnv());
342                     FlatStringStubBuilder thisFlat(this);
343                     thisFlat.FlattenString(glue, results.GetHolder(), &afterFlatten);
344                     Bind(&afterFlatten);
345                     {
346                         StringInfoGateRef stringInfoGate(&thisFlat);
347                         // get value
348                         auto strValue = stringBuilder.FastSubString(glue, results.GetHolder(),
349                                                                     elementIdx, Int32(1), stringInfoGate);
350                         // construct property attribute with EnumerableField
351                         GateRef attr = Int64(PropertyAttributes::GetDefaultAttributes());
352                         SetEnumerableFiledInPropAttr(attr, Int32(1));
353                         SetFound(results, strValue, elementIdx, attr);
354                         Jump(exit);
355                     }
356                 }
357             }
358         }
359     }
360 
361     Bind(&notStringObject);
362     BRANCH(IsTypedArray(glue, obj), &isTypedArray, &ordinaryObject);
363 
364     Bind(&isTypedArray);
365     {
366         Label elementFound(env);
367         BuiltinsTypedArrayStubBuilder typedArrayStubBuilder(this, GetCurrentGlobalEnv());
368         GateRef element =
369             typedArrayStubBuilder.FastGetPropertyByIndex(glue, obj, elementIdx, GetObjectType(LoadHClass(glue, obj)));
370 
371         BRANCH(TaggedIsHole(element), exit, &elementFound);
372         Bind(&elementFound);
373         if (options.lookupKind == LookupKind::KIND_HAS_PROPERTY) {
374             SetFound(results);
375             Jump(exit);
376         } else {
377             ASSERT(options.lookupKind == LookupKind::KIND_GET_PROPERTY ||
378                    options.lookupKind == LookupKind::KIND_SET_PROPERTY);
379             SetFound(results, element, elementIdx, Int64(PropertyAttributes::GetDefaultAttributes()));
380             Jump(exit);
381         }
382     }
383 
384     Bind(&ordinaryObject);
385     {
386         Label findByIndex(env);
387         GateRef elements = GetElementsArray(glue, obj);
388         GateRef len = GetLengthOfTaggedArray(elements);
389         BRANCH(Int32Equal(len, Int32(0)), exit, &findByIndex);
390 
391         Bind(&findByIndex);
392         {
393             Label isDicMode(env);
394             Label notDicMode(env);
395             BRANCH(IsDictionaryMode(glue, elements), &isDicMode, &notDicMode);
396             Bind(&notDicMode);
397             {
398                 Label lessThanLength(env);
399                 Label notLessThanLength(env);
400                 BRANCH(Int32UnsignedLessThanOrEqual(len, elementIdx), exit, &lessThanLength);
401                 Bind(&lessThanLength);
402                 {
403                     Label notHole(env);
404                     Label elementFound(env);
405                     GateRef value = GetTaggedValueWithElementsKind(glue, obj, elementIdx);
406                     BRANCH(TaggedIsHole(value), exit, &elementFound);
407                     Bind(&elementFound);
408                     {
409                         if (options.lookupKind == LookupKind::KIND_HAS_PROPERTY) {
410                             SetFound(results);
411                             Jump(exit);
412                         } else {
413                             ASSERT(options.lookupKind == LookupKind::KIND_GET_PROPERTY ||
414                                    options.lookupKind == LookupKind::KIND_SET_PROPERTY);
415                             SetFound(results, value, elementIdx, Int64(PropertyAttributes::GetDefaultAttributes()));
416                             Jump(exit);
417                         }
418                     }
419                 }
420             }
421             Bind(&isDicMode);
422             {
423                 Label elementFound(env);
424                 GateRef entryA = FindElementFromNumberDictionary(glue, elements, elementIdx);
425                 BRANCH(Int32NotEqual(entryA, Int32(-1)), &elementFound, exit);
426                 Bind(&elementFound);
427                 {
428                     if (options.lookupKind == LookupKind::KIND_HAS_PROPERTY) {
429                         SetFound(results);
430                         Jump(exit);
431                     } else {
432                         ASSERT(options.lookupKind == LookupKind::KIND_GET_PROPERTY ||
433                                options.lookupKind == LookupKind::KIND_SET_PROPERTY);
434                         GateRef attr = GetAttributesFromDictionary<NumberDictionary>(glue, elements, entryA);
435                         GateRef value = GetValueFromDictionary<NumberDictionary>(glue, elements, entryA);
436                         SetFound(results, value, elementIdx, attr);
437                         Jump(exit);
438                     }
439                 }
440             }
441         }
442     }
443 }
444 
445 // StartLookup is the entrypoint for IR ObjectOperator.
446 template <ObjectOperatorStubBuilder::StartLookupType startLookupType>
StartLookup(GateRef glue,GateRef key,Label * exit,const ObjectOperatorOptions & options,ObjectOperatorResult & results,GateRef hir)447 void ObjectOperatorStubBuilder::StartLookup(GateRef glue, GateRef key, Label *exit,
448                                             const ObjectOperatorOptions &options, ObjectOperatorResult &results,
449                                             GateRef hir)
450 {
451     auto env = GetEnvironment();
452     Label updateReceiver(env);
453     Label hasReceiver(env);
454     Label handleKey(env);
455     Label isProperty(env);
456     Label isElement(env);
457     Label lookupProperty(env);
458 
459     if (options.lookupKind == LookupKind::KIND_HAS_PROPERTY) {
460         // HasProperty not need to check receiver, for efficiency
461         Jump(&handleKey);
462     } else {
463         ASSERT(options.lookupKind == LookupKind::KIND_GET_PROPERTY ||
464                options.lookupKind == LookupKind::KIND_SET_PROPERTY);
465 
466         if constexpr (startLookupType == StartLookupType::HAS_RECEIVER) {
467             SetHasReceiver(results);
468         } else {
469             *results.receiver = results.GetHolder();
470         }
471 
472         Jump(&handleKey);
473     }
474 
475     // 1. handle property key
476     Bind(&handleKey);
477     HandleKey(glue, key, results.propKey, results.elemKey, &isProperty, &isElement, exit, hir);
478 
479     // 2(1). start lookup when key is property
480     Bind(&isProperty);
481     {
482         Label holderUpdated(env);
483         UpdateHolder<false>(glue, results, results.GetPropKey(), &holderUpdated);
484 
485         Bind(&holderUpdated);
486         {
487             if (options.type == OperatorType::OWN) {
488                 LookupPropertyInlinedProps(glue, results.GetHolder(), results.GetPropKey(),
489                                            exit, options, results, hir);
490             } else {
491                 ASSERT(options.type == OperatorType::PROTOTYPE_CHAIN);
492                 LookupProperty<false>(glue, results.GetPropKey(), exit, options, results, hir);
493             }
494         }
495     }
496 
497     // 2(2). start lookup when key is element
498     Bind(&isElement);
499     {
500         Label holderUpdated(env);
501         UpdateHolder<true>(glue, results, results.GetElemKey(), &holderUpdated);
502 
503         Bind(&holderUpdated);
504         {
505             if (options.type == OperatorType::OWN) {
506                 LookupElementInlinedProps(glue, results.GetHolder(), results.GetElemKey(), exit, options, results, hir);
507             } else {
508                 LookupProperty<true>(glue, results.GetElemKey(), exit, options, results, hir);
509             }
510         }
511     }
512 }
513 
514 template
515 void ObjectOperatorStubBuilder::StartLookup<ObjectOperatorStubBuilder::StartLookupType::HAS_RECEIVER>(
516     GateRef glue, GateRef key, Label *exit,
517     const ObjectOperatorOptions &options, ObjectOperatorResult &results,
518     GateRef hir);
519 template
520 void ObjectOperatorStubBuilder::StartLookup<ObjectOperatorStubBuilder::StartLookupType::NO_RECEIVER>(
521     GateRef glue, GateRef key, Label *exit,
522     const ObjectOperatorOptions &options, ObjectOperatorResult &results,
523     GateRef hir);
524 
525 template <bool keyIsElement>
LookupProperty(GateRef glue,GateRef key,Label * exit,const ObjectOperatorOptions & options,ObjectOperatorResult & results,GateRef hir)526 void ObjectOperatorStubBuilder::LookupProperty(GateRef glue, GateRef key,
527                                                Label *exit, const ObjectOperatorOptions &options,
528                                                ObjectOperatorResult &results, GateRef hir)
529 {
530     auto env = GetEnvironment();
531     Label continuelyLookup(env);
532     Label lookupInProtoChain(env);
533     BRANCH(TaggedIsJSProxy(glue, results.GetHolder()), exit, &continuelyLookup);
534 
535     Bind(&continuelyLookup);
536     {
537         Label checkResult(env);
538         if constexpr (keyIsElement) {
539             LookupElementInlinedProps(glue, results.GetHolder(), key, &checkResult, options, results, hir);
540         } else {
541             LookupPropertyInlinedProps(glue, results.GetHolder(), key, &checkResult, options, results, hir);
542         }
543         Bind(&checkResult);
544         BRANCH(IsFound(results.metaData), exit, &lookupInProtoChain);
545     }
546 
547     Bind(&lookupInProtoChain);
548     {
549         TryLookupInProtoChain<keyIsElement>(glue, key, exit, options, results, hir);
550     }
551 }
552 
553 template <bool keyIsElement>
TryLookupInProtoChain(GateRef glue,GateRef key,Label * exit,const ObjectOperatorOptions & options,ObjectOperatorResult & results,GateRef hir)554 void ObjectOperatorStubBuilder::TryLookupInProtoChain(GateRef glue, GateRef key, Label *exit,
555                                                       const ObjectOperatorOptions &options,
556                                                       ObjectOperatorResult &results, GateRef hir)
557 {
558     auto env = GetEnvironment();
559     Label loopHead(env);
560     Label loopEnd(env);
561     Label next(env);
562     Label loopExit(env);
563     Jump(&loopHead);
564     LoopBegin(&loopHead);
565     {
566         BRANCH(IsFound(results.metaData), &loopExit, &next);
567         Bind(&next);
568         {
569             Label noPendingException(env);
570             Label notJSProxy(env);
571             GateRef proto = GetPrototype(glue, results.GetHolder());
572             BRANCH_UNLIKELY(HasPendingException(glue), &loopExit, &noPendingException);
573 
574             Bind(&noPendingException);
575             {
576                 Label updateHolder(env);
577                 BRANCH(TaggedIsHeapObject(proto), &updateHolder, &loopExit);
578 
579                 Bind(&updateHolder);
580                 {
581                     *results.holder = proto;
582                     SetIsOnProtoType(results);
583                     BRANCH(TaggedIsJSProxy(glue, results.GetHolder()), exit, &notJSProxy);
584                 }
585             }
586 
587             Bind(&notJSProxy);
588             {
589                 if constexpr (keyIsElement) {
590                     LookupElementInlinedProps(glue, results.GetHolder(), key, &loopEnd, options, results, hir);
591                 } else {
592                     LookupPropertyInlinedProps(glue, results.GetHolder(), key, &loopEnd, options, results, hir);
593                 }
594             }
595         }
596     }
597     Bind(&loopEnd);
598     LoopEnd(&loopHead);
599     Bind(&loopExit);
600     Jump(exit);
601 }
602 
InitializeOperatorResults(ObjectOperatorResult & result)603 void ObjectOperatorStubBuilder::InitializeOperatorResults(ObjectOperatorResult &result)
604 {
605     auto env = GetEnvironment();
606     result.metaData = new Variable(env, VariableType::INT32(), NextVariableId(), Int32(0));
607     result.elemKey = new Variable(env, VariableType::INT32(), NextVariableId(), Int32(ObjectOperator::NOT_FOUND_INDEX));
608     result.propKey = new Variable(env, VariableType::JS_ANY(), NextVariableId(), Undefined());
609     result.index = new Variable(env, VariableType::INT32(), NextVariableId(), Int32(ObjectOperator::NOT_FOUND_INDEX));
610     result.value = new Variable(env, VariableType::JS_ANY(), NextVariableId(), Undefined());
611     result.holder = new Variable(env, VariableType::JS_ANY(), NextVariableId(), Undefined());
612     result.receiver = new Variable(env, VariableType::JS_ANY(), NextVariableId(), Hole());
613     result.attr = new Variable(env, VariableType::INT64(), NextVariableId(), Int64(-1));
614 }
615 
FinalizeOperatorResults(ObjectOperatorResult & result)616 void ObjectOperatorStubBuilder::FinalizeOperatorResults(ObjectOperatorResult &result)
617 {
618     delete result.metaData;
619     delete result.elemKey;
620     delete result.propKey;
621     delete result.index;
622     delete result.value;
623     delete result.holder;
624     delete result.receiver;
625     delete result.attr;
626 }
627 
IsFound(Variable * metaData)628 GateRef ObjectOperatorStubBuilder::IsFound(Variable *metaData)
629 {
630     return Int32NotEqual(Int32And(metaData->ReadVariable(), Int32(1 << IS_FOUND_BIT)), Int32(0));
631 }
632 
SetFound(ObjectOperatorResult & opResult)633 void ObjectOperatorStubBuilder::SetFound(ObjectOperatorResult &opResult)
634 {
635     *opResult.metaData = Int32Or(opResult.GetMetaData(), Int32(1 << IS_FOUND_BIT));
636 }
637 
SetFound(ObjectOperatorResult & opResult,GateRef value,GateRef index,GateRef attr)638 void ObjectOperatorStubBuilder::SetFound(ObjectOperatorResult &opResult, GateRef value, GateRef index, GateRef attr)
639 {
640     *opResult.metaData = Int32Or(opResult.GetMetaData(), Int32(1 << IS_FOUND_BIT));
641     *opResult.value = value;
642     *opResult.index = index;
643     *opResult.attr = attr;
644 }
645 
SetIsOnProtoType(ObjectOperatorResult & opResult)646 void ObjectOperatorStubBuilder::SetIsOnProtoType(ObjectOperatorResult &opResult)
647 {
648     *opResult.metaData = Int32Or(opResult.GetMetaData(), Int32(1 << IS_ON_PROTOTYPE_BIT));
649 }
650 
SetHasReceiver(ObjectOperatorResult & opResult)651 void ObjectOperatorStubBuilder::SetHasReceiver(ObjectOperatorResult &opResult)
652 {
653     *opResult.metaData = Int32Or(opResult.GetMetaData(), Int32(1 << HAS_RECEIVER_BIT));
654 }
655 
IsElement(ObjectOperatorResult & opResult)656 GateRef ObjectOperatorStubBuilder::IsElement(ObjectOperatorResult &opResult)
657 {
658     return Int32NotEqual(opResult.elemKey->ReadVariable(), Int32(ObjectOperator::NOT_FOUND_INDEX));
659 }
660 
IsAccessorDescriptor(ObjectOperatorResult & opResult)661 GateRef ObjectOperatorStubBuilder::IsAccessorDescriptor(ObjectOperatorResult &opResult)
662 {
663     return IsAccessor(opResult.GetAttr());
664 }
665 }  // namespace panda::ecmascript::kungfu
666