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 #ifndef ECMASCRIPT_ENUM_CACHE_H 17 #define ECMASCRIPT_ENUM_CACHE_H 18 19 #include "ecmascript/ecma_macros.h" 20 #include "ecmascript/mem/barriers.h" 21 22 // EnumCacheKind is only used in for-in. 23 enum class EnumCacheKind : uint8_t { 24 NONE, // No Cache, go slow path 25 SIMPLE, // Simple enum cache 26 PROTOCHAIN, // Prototype chain info enum cache 27 }; 28 29 // +---------------+-------------------------------------------+-------------------------------------------------+ 30 // | EnumCacheKind | Status Description | Valid Conditions | 31 // +---------------+-------------------------------------------+-------------------------------------------------+ 32 // | None | - Uninitialized or in SlowPath mode. | - None (No additional conditions required) | 33 // | | No active cache optimization. | | 34 // +---------------+-------------------------------------------+-------------------------------------------------+ 35 // | SIMPLE | - Fast path for simple enum cache check. | - Receiver's proto is NOT a HeapObject, | 36 // | | Indicates: | OR | 37 // | | • Properties exist ONLY on the object | - Receiver.proto.ProtoChainInfoEnumCache == | 38 // | | itself (no prototype chain properties) | Undefined. (Ensure no keys on prototype chain)| 39 // | | • NO elements (indexed properties) on | | 40 // | | self/proto | | 41 // +---------------+-------------------------------------------+-------------------------------------------------+ 42 // | PROTOCHAIN | - Fast path for protochain enum cache. | - Receiver's proto is a HeapObject, AND | 43 // | | Indicates: | - Receiver.ProtoChainInfoEnumCache == | 44 // | | • Properties exist on the object itself | receiver.proto.EnumCacheAll (Cache matches | 45 // | | or prototype chain | prototype's full enum cache), AND | 46 // | | • NO elements (indexed properties) on | - Receiver.ProtoChainInfoEnumCache != Null | 47 // | | self/proto | (Valid cache exists). | 48 // +---------------+-------------------------------------------+-------------------------------------------------+ 49 50 namespace panda { 51 namespace ecmascript { 52 class EnumCache : public TaggedObject { 53 public: 54 CAST_CHECK(EnumCache, IsEnumCache); 55 56 static constexpr size_t ENUM_CACHE_OWN_OFFSET = TaggedObjectSize(); 57 CheckSelfAndProtoEnumCache(const JSThread * thread,JSTaggedValue enumCacheOwn,JSTaggedValue enumCacheProto)58 static bool CheckSelfAndProtoEnumCache(const JSThread *thread, JSTaggedValue enumCacheOwn, 59 JSTaggedValue enumCacheProto) 60 { 61 if (!enumCacheOwn.IsEnumCache() || !enumCacheProto.IsEnumCache()) { 62 return false; 63 } 64 auto keyOwn = EnumCache::Cast(enumCacheOwn.GetTaggedObject())->GetProtoChainInfoEnumCache(thread); 65 auto keyProto = EnumCache::Cast(enumCacheProto.GetTaggedObject())->GetEnumCacheAll(thread); 66 if (keyOwn != keyProto || keyOwn == JSTaggedValue::Null()) { 67 return false; 68 } 69 return true; 70 } 71 IsEnumCacheAllValid(const JSThread * thread)72 inline bool IsEnumCacheAllValid(const JSThread *thread) const 73 { 74 return GetEnumCacheAll(thread) != JSTaggedValue::Null(); 75 } 76 IsEnumCacheOwnValid(const JSThread * thread)77 inline bool IsEnumCacheOwnValid(const JSThread *thread) const 78 { 79 return GetEnumCacheOwn(thread) != JSTaggedValue::Null(); 80 } 81 IsEnumCacheProtoInfoUndefined(const JSThread * thread)82 inline bool IsEnumCacheProtoInfoUndefined(const JSThread *thread) const 83 { 84 return GetProtoChainInfoEnumCache(thread) == JSTaggedValue::Undefined(); 85 } 86 SetInvalidState(const JSThread * thread)87 inline void SetInvalidState(const JSThread *thread) 88 { 89 SetEnumCacheAll(thread, JSTaggedValue::Null()); 90 SetProtoChainInfoEnumCache(thread, JSTaggedValue::Null()); 91 } 92 93 // EnumCacheOwn holds enum keys on itself. 94 ACCESSORS(EnumCacheOwn, ENUM_CACHE_OWN_OFFSET, ENUM_CACHE_ALL_OFFSET); 95 96 // EnumCacheAll holds all enum keys on the prototype chain, including its own keys. 97 ACCESSORS(EnumCacheAll, ENUM_CACHE_ALL_OFFSET, PROTO_CHAIN_INFO_ENUM_CACHE_OFFSET); 98 99 // ProtoChainInfoEnumCache holds all enum keys on the prototype chain, excluding its own keys. 100 ACCESSORS(ProtoChainInfoEnumCache, PROTO_CHAIN_INFO_ENUM_CACHE_OFFSET, ENUM_CACHE_KIND_OFFSET); 101 ACCESSORS_PRIMITIVE_FIELD(EnumCacheKind, uint32_t, ENUM_CACHE_KIND_OFFSET, LAST_OFFSET); 102 103 DEFINE_ALIGN_SIZE(LAST_OFFSET); 104 105 DECL_VISIT_OBJECT(ENUM_CACHE_OWN_OFFSET, ENUM_CACHE_KIND_OFFSET) 106 107 DECL_DUMP() 108 }; 109 } // namespace ecmascript 110 } // namespace panda 111 112 #endif // ECMASCRIPT_IC_ENUM_CACHE_H 113