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, ¬Int);
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(¬Int);
65 BRANCH(TaggedIsString(glue, key), &isString, ¬String);
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, ¬InternString);
80 Bind(¬InternString);
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(¬String);
96 BRANCH(TaggedIsDouble(key), &isDouble, ¬Double);
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, ¬InternString);
127 Bind(¬InternString);
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(¬Double);
137 BRANCH(IsSymbol(glue, key), &isSymbol, ¬Symbol);
138
139 Bind(&isSymbol);
140 {
141 *propKey = key;
142 Jump(isProperty);
143 }
144
145 Bind(¬Symbol);
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, ¬EcmaObject);
196
197 Bind(¬EcmaObject);
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, ¬JsGlobalObject);
246 }
247
248 Bind(¬JsGlobalObject);
249 {
250 Label notDicMod(env);
251 GateRef hclass = LoadHClass(glue, obj);
252 BRANCH(IsDictionaryModeByHClass(hclass), &isDicMode, ¬DicMod);
253 Bind(¬DicMod);
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, ¬StringObject);
322 Bind(&isPrimitiveRef);
323 {
324 GateRef value = Load(VariableType::JS_ANY(), glue, obj, IntPtr(JSPrimitiveRef::VALUE_OFFSET));
325 BRANCH(TaggedIsString(glue, value), &isStringObject, ¬StringObject);
326 Bind(&isStringObject);
327 {
328 Label elementFound(env);
329 GateRef strLength = GetLengthFromString(value);
330 BRANCH(Int32LessThan(elementIdx, strLength), &elementFound, ¬StringObject);
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(¬StringObject);
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, ¬DicMode);
396 Bind(¬DicMode);
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, ¬JSProxy);
584 }
585 }
586
587 Bind(¬JSProxy);
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