11cb0ef41Sopenharmony_ci// Copyright 2021 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include 'src/objects/swiss-name-dictionary.h' 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci@doNotGenerateCppClass 81cb0ef41Sopenharmony_ciextern class SwissNameDictionary extends HeapObject { 91cb0ef41Sopenharmony_ci hash: uint32; 101cb0ef41Sopenharmony_ci const capacity: int32; 111cb0ef41Sopenharmony_ci meta_table: ByteArray; 121cb0ef41Sopenharmony_ci data_table[Convert<intptr>(capacity) * 2]: JSAny|TheHole; 131cb0ef41Sopenharmony_ci ctrl_table[Convert<intptr>(capacity) + swiss_table::kGroupWidth]: uint8; 141cb0ef41Sopenharmony_ci property_details_table[Convert<intptr>(capacity)]: uint8; 151cb0ef41Sopenharmony_ci} 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_cinamespace swiss_table { 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ciconst kDataTableEntryCount: constexpr intptr 201cb0ef41Sopenharmony_ci generates 'SwissNameDictionary::kDataTableEntryCount'; 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ciconst kMax1ByteMetaTableCapacity: constexpr int32 231cb0ef41Sopenharmony_ci generates 'SwissNameDictionary::kMax1ByteMetaTableCapacity'; 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ciconst kMax2ByteMetaTableCapacity: constexpr int32 261cb0ef41Sopenharmony_ci generates 'SwissNameDictionary::kMax2ByteMetaTableCapacity'; 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ciconst kNotFoundSentinel: 291cb0ef41Sopenharmony_ci constexpr int32 generates 'SwissNameDictionary::kNotFoundSentinel'; 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ciextern macro LoadSwissNameDictionaryKey(SwissNameDictionary, intptr): Name; 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ciextern macro StoreSwissNameDictionaryKeyAndValue( 341cb0ef41Sopenharmony_ci SwissNameDictionary, intptr, Object, Object): void; 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_ciextern macro SwissNameDictionarySetCtrl( 371cb0ef41Sopenharmony_ci SwissNameDictionary, intptr, intptr, uint8): void; 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ciextern macro StoreSwissNameDictionaryPropertyDetails( 401cb0ef41Sopenharmony_ci SwissNameDictionary, intptr, intptr, uint8): void; 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ciextern macro 431cb0ef41Sopenharmony_ciSwissNameDictionaryIncreaseElementCountOrBailout( 441cb0ef41Sopenharmony_ci ByteArray, intptr, uint32): uint32 labels Bailout; 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ciextern macro 471cb0ef41Sopenharmony_ciStoreSwissNameDictionaryEnumToEntryMapping( 481cb0ef41Sopenharmony_ci SwissNameDictionary, intptr, intptr, int32): void; 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ciextern macro 511cb0ef41Sopenharmony_ciSwissNameDictionaryUpdateCountsForDeletion(ByteArray, intptr): uint32; 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_cinamespace runtime { 541cb0ef41Sopenharmony_ciextern runtime SwissTableFindEntry(NoContext, SwissNameDictionary, Name): Smi; 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ciextern runtime SwissTableAdd( 571cb0ef41Sopenharmony_ci NoContext, SwissNameDictionary, Name, Object, Smi): SwissNameDictionary; 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ciextern runtime ShrinkSwissNameDictionary( 601cb0ef41Sopenharmony_ci NoContext, SwissNameDictionary): SwissNameDictionary; 611cb0ef41Sopenharmony_ci} 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci// Counterpart for SwissNameDictionary::CapacityFor in C++. 641cb0ef41Sopenharmony_ci@export 651cb0ef41Sopenharmony_cimacro SwissNameDictionaryCapacityFor(atLeastSpaceFor: intptr): intptr { 661cb0ef41Sopenharmony_ci if (atLeastSpaceFor <= 4) { 671cb0ef41Sopenharmony_ci if (atLeastSpaceFor == 0) { 681cb0ef41Sopenharmony_ci return 0; 691cb0ef41Sopenharmony_ci } else if (atLeastSpaceFor < kSwissNameDictionaryInitialCapacity) { 701cb0ef41Sopenharmony_ci return 4; 711cb0ef41Sopenharmony_ci } else if (FromConstexpr<bool>(kGroupWidth == 16)) { 721cb0ef41Sopenharmony_ci dcheck(atLeastSpaceFor == 4); 731cb0ef41Sopenharmony_ci return 4; 741cb0ef41Sopenharmony_ci } else if (FromConstexpr<bool>(kGroupWidth == 8)) { 751cb0ef41Sopenharmony_ci dcheck(atLeastSpaceFor == 4); 761cb0ef41Sopenharmony_ci return 8; 771cb0ef41Sopenharmony_ci } 781cb0ef41Sopenharmony_ci } 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_ci const nonNormalized = atLeastSpaceFor + atLeastSpaceFor / 7; 811cb0ef41Sopenharmony_ci return IntPtrRoundUpToPowerOfTwo32(nonNormalized); 821cb0ef41Sopenharmony_ci} 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci// Counterpart for SwissNameDictionary::MaxUsableCapacity in C++. 851cb0ef41Sopenharmony_ci@export 861cb0ef41Sopenharmony_cimacro SwissNameDictionaryMaxUsableCapacity(capacity: intptr): intptr { 871cb0ef41Sopenharmony_ci dcheck(capacity == 0 || capacity >= kSwissNameDictionaryInitialCapacity); 881cb0ef41Sopenharmony_ci if (FromConstexpr<bool>(kGroupWidth == 8) && capacity == 4) { 891cb0ef41Sopenharmony_ci // If the group size is 16 we can fully utilize capacity 4: There will be 901cb0ef41Sopenharmony_ci // enough kEmpty entries in the ctrl table. 911cb0ef41Sopenharmony_ci return 3; 921cb0ef41Sopenharmony_ci } 931cb0ef41Sopenharmony_ci return capacity - capacity / 8; 941cb0ef41Sopenharmony_ci} 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci// Counterpart for SwissNameDictionary::SizeFor in C++. 971cb0ef41Sopenharmony_ci@export 981cb0ef41Sopenharmony_cimacro SwissNameDictionarySizeFor(capacity: intptr): intptr { 991cb0ef41Sopenharmony_ci const constant: constexpr int32 = kHeapObjectHeaderSize + 8 + kTaggedSize; 1001cb0ef41Sopenharmony_ci const dynamic: intptr = 1011cb0ef41Sopenharmony_ci capacity * FromConstexpr<intptr>(2 * kTaggedSize + 2) + 1021cb0ef41Sopenharmony_ci FromConstexpr<intptr>(kGroupWidth); 1031cb0ef41Sopenharmony_ci return constant + dynamic; 1041cb0ef41Sopenharmony_ci} 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci// Counterpart for SwissNameDictionary::MetaTableSizePerEntryFor in C++. 1071cb0ef41Sopenharmony_ci@export 1081cb0ef41Sopenharmony_cimacro SwissNameDictionaryMetaTableSizePerEntryFor(capacity: intptr): intptr { 1091cb0ef41Sopenharmony_ci if (capacity <= kMax1ByteMetaTableCapacity) { 1101cb0ef41Sopenharmony_ci return 1; 1111cb0ef41Sopenharmony_ci } else if (capacity <= kMax2ByteMetaTableCapacity) { 1121cb0ef41Sopenharmony_ci return 2; 1131cb0ef41Sopenharmony_ci } else { 1141cb0ef41Sopenharmony_ci return 4; 1151cb0ef41Sopenharmony_ci } 1161cb0ef41Sopenharmony_ci} 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ci// Counterpart for SwissNameDictionary::MetaTableSizeFor in C++. 1191cb0ef41Sopenharmony_ci@export 1201cb0ef41Sopenharmony_cimacro SwissNameDictionaryMetaTableSizeFor(capacity: intptr): intptr { 1211cb0ef41Sopenharmony_ci const perEntry: intptr = 1221cb0ef41Sopenharmony_ci SwissNameDictionaryMetaTableSizePerEntryFor(capacity); 1231cb0ef41Sopenharmony_ci const maxUsable: intptr = 1241cb0ef41Sopenharmony_ci Convert<intptr>(SwissNameDictionaryMaxUsableCapacity(capacity)); 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci return (2 + maxUsable) * perEntry; 1271cb0ef41Sopenharmony_ci} 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci// 1301cb0ef41Sopenharmony_ci// Offsets. MT stands for "minus tag" 1311cb0ef41Sopenharmony_ci// 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ciconst kDataTableStartOffsetMT: constexpr intptr 1341cb0ef41Sopenharmony_ci generates 'SwissNameDictionary::DataTableStartOffset() - kHeapObjectTag'; 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_ci@export 1371cb0ef41Sopenharmony_cimacro SwissNameDictionaryDataTableStartOffsetMT(): intptr { 1381cb0ef41Sopenharmony_ci return kDataTableStartOffsetMT; 1391cb0ef41Sopenharmony_ci} 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci@export 1421cb0ef41Sopenharmony_cimacro SwissNameDictionaryCtrlTableStartOffsetMT(capacity: intptr): intptr { 1431cb0ef41Sopenharmony_ci return kDataTableStartOffsetMT + 1441cb0ef41Sopenharmony_ci kDataTableEntryCount * FromConstexpr<intptr>(kTaggedSize) * capacity; 1451cb0ef41Sopenharmony_ci} 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_cimacro Probe(hash: uint32, mask: uint32): ProbeSequence { 1481cb0ef41Sopenharmony_ci // Mask must be a power of 2 minus 1. 1491cb0ef41Sopenharmony_ci dcheck(((mask + 1) & mask) == 0); 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ci return ProbeSequence{mask: mask, offset: H1(hash) & mask, index: 0}; 1521cb0ef41Sopenharmony_ci} 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_cimacro FindEntry<GroupLoader: type>( 1551cb0ef41Sopenharmony_ci table: SwissNameDictionary, key: Name): never labels 1561cb0ef41Sopenharmony_ciFound(intptr), NotFound { 1571cb0ef41Sopenharmony_ci const hash: uint32 = LoadNameHash(key); 1581cb0ef41Sopenharmony_ci const capacity: int32 = table.capacity; 1591cb0ef41Sopenharmony_ci const nonZeroCapacity: int32 = capacity | Convert<int32>(capacity == 0); 1601cb0ef41Sopenharmony_ci const mask: uint32 = Unsigned(nonZeroCapacity - 1); 1611cb0ef41Sopenharmony_ci 1621cb0ef41Sopenharmony_ci const ctrlTableStart: intptr = 1631cb0ef41Sopenharmony_ci SwissNameDictionaryCtrlTableStartOffsetMT(Convert<intptr>(capacity)) + 1641cb0ef41Sopenharmony_ci BitcastTaggedToWord(table); 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ci let seq = Probe(hash, mask); 1671cb0ef41Sopenharmony_ci while (true) { 1681cb0ef41Sopenharmony_ci const group = 1691cb0ef41Sopenharmony_ci GroupLoader{}.LoadGroup(ctrlTableStart + Convert<intptr>(seq.offset)); 1701cb0ef41Sopenharmony_ci let match = group.Match(H2(hash)); 1711cb0ef41Sopenharmony_ci while (match.HasBitsSet()) { 1721cb0ef41Sopenharmony_ci const inGroupIndex = match.LowestBitSet(); 1731cb0ef41Sopenharmony_ci const candidateEntry = Convert<intptr>(seq.Offset(inGroupIndex)); 1741cb0ef41Sopenharmony_ci const candidateKey: Object = 1751cb0ef41Sopenharmony_ci LoadSwissNameDictionaryKey(table, candidateEntry); 1761cb0ef41Sopenharmony_ci if (TaggedEqual(key, candidateKey)) { 1771cb0ef41Sopenharmony_ci goto Found(candidateEntry); 1781cb0ef41Sopenharmony_ci } 1791cb0ef41Sopenharmony_ci match.ClearLowestSetBit(); 1801cb0ef41Sopenharmony_ci } 1811cb0ef41Sopenharmony_ci if (group.MatchEmpty().HasBitsSet()) { 1821cb0ef41Sopenharmony_ci goto NotFound; 1831cb0ef41Sopenharmony_ci } 1841cb0ef41Sopenharmony_ci seq.Next(); 1851cb0ef41Sopenharmony_ci } 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci unreachable; 1881cb0ef41Sopenharmony_ci} 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_cimacro FindFirstEmpty<GroupLoader: type>( 1911cb0ef41Sopenharmony_ci table: SwissNameDictionary, capacity: intptr, hash: uint32): int32 { 1921cb0ef41Sopenharmony_ci const nonZeroCapacity: int32 = 1931cb0ef41Sopenharmony_ci Convert<int32>(capacity) | Convert<int32>(capacity == 0); 1941cb0ef41Sopenharmony_ci const mask: uint32 = Unsigned(nonZeroCapacity - 1); 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ci const ctrlTableStart: intptr = 1971cb0ef41Sopenharmony_ci SwissNameDictionaryCtrlTableStartOffsetMT(capacity) + 1981cb0ef41Sopenharmony_ci BitcastTaggedToWord(table); 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ci let seq = Probe(hash, mask); 2011cb0ef41Sopenharmony_ci while (true) { 2021cb0ef41Sopenharmony_ci const group = 2031cb0ef41Sopenharmony_ci GroupLoader{}.LoadGroup(ctrlTableStart + Convert<intptr>(seq.offset)); 2041cb0ef41Sopenharmony_ci const match = group.MatchEmpty(); 2051cb0ef41Sopenharmony_ci if (match.HasBitsSet()) { 2061cb0ef41Sopenharmony_ci const inGroupIndex = match.LowestBitSet(); 2071cb0ef41Sopenharmony_ci return Signed(seq.Offset(inGroupIndex)); 2081cb0ef41Sopenharmony_ci } 2091cb0ef41Sopenharmony_ci seq.Next(); 2101cb0ef41Sopenharmony_ci } 2111cb0ef41Sopenharmony_ci 2121cb0ef41Sopenharmony_ci unreachable; 2131cb0ef41Sopenharmony_ci} 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_cimacro Add<GroupLoader: type>( 2161cb0ef41Sopenharmony_ci table: SwissNameDictionary, key: Name, value: Object, 2171cb0ef41Sopenharmony_ci propertyDetails: uint8): void labels Bailout { 2181cb0ef41Sopenharmony_ci const capacity: intptr = Convert<intptr>(table.capacity); 2191cb0ef41Sopenharmony_ci const maxUsable: uint32 = 2201cb0ef41Sopenharmony_ci Unsigned(Convert<int32>(SwissNameDictionaryMaxUsableCapacity(capacity))); 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ci try { 2231cb0ef41Sopenharmony_ci // We read the used capacity (present + deleted elements), compare it 2241cb0ef41Sopenharmony_ci // against the max usable capacity to determine if a bailout is necessary, 2251cb0ef41Sopenharmony_ci // and in case of no bailout increase the present element count all in one 2261cb0ef41Sopenharmony_ci // go using the following macro. This way we don't have to do the branching 2271cb0ef41Sopenharmony_ci // needed for meta table accesses multiple times. 2281cb0ef41Sopenharmony_ci const used: uint32 = SwissNameDictionaryIncreaseElementCountOrBailout( 2291cb0ef41Sopenharmony_ci table.meta_table, capacity, maxUsable) otherwise Bailout; 2301cb0ef41Sopenharmony_ci 2311cb0ef41Sopenharmony_ci const hash: uint32 = LoadNameHash(key); 2321cb0ef41Sopenharmony_ci const newEntry32 = FindFirstEmpty<GroupLoader>(table, capacity, hash); 2331cb0ef41Sopenharmony_ci const newEntry = Convert<intptr>(newEntry32); 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ci StoreSwissNameDictionaryKeyAndValue(table, newEntry, key, value); 2361cb0ef41Sopenharmony_ci 2371cb0ef41Sopenharmony_ci StoreSwissNameDictionaryEnumToEntryMapping( 2381cb0ef41Sopenharmony_ci table, capacity, Convert<intptr>(used), newEntry32); 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci const h2 = Convert<uint8>(Convert<intptr>(H2(hash))); 2411cb0ef41Sopenharmony_ci SwissNameDictionarySetCtrl(table, capacity, newEntry, h2); 2421cb0ef41Sopenharmony_ci 2431cb0ef41Sopenharmony_ci StoreSwissNameDictionaryPropertyDetails( 2441cb0ef41Sopenharmony_ci table, capacity, newEntry, propertyDetails); 2451cb0ef41Sopenharmony_ci } label Bailout { 2461cb0ef41Sopenharmony_ci goto Bailout; 2471cb0ef41Sopenharmony_ci } 2481cb0ef41Sopenharmony_ci} 2491cb0ef41Sopenharmony_ci 2501cb0ef41Sopenharmony_ci@export 2511cb0ef41Sopenharmony_cimacro SwissNameDictionaryDelete(table: SwissNameDictionary, entry: intptr): 2521cb0ef41Sopenharmony_ci void labels Shrunk(SwissNameDictionary) { 2531cb0ef41Sopenharmony_ci const capacity = Convert<intptr>(table.capacity); 2541cb0ef41Sopenharmony_ci 2551cb0ef41Sopenharmony_ci // Update present and deleted element counts at once, without needing to do 2561cb0ef41Sopenharmony_ci // the meta table access related branching more than once. 2571cb0ef41Sopenharmony_ci const newElementCount = 2581cb0ef41Sopenharmony_ci SwissNameDictionaryUpdateCountsForDeletion(table.meta_table, capacity); 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_ci StoreSwissNameDictionaryKeyAndValue(table, entry, TheHole, TheHole); 2611cb0ef41Sopenharmony_ci 2621cb0ef41Sopenharmony_ci const kDeleted = FromConstexpr<uint8>(ctrl::kDeleted); 2631cb0ef41Sopenharmony_ci SwissNameDictionarySetCtrl(table, capacity, entry, kDeleted); 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci // Same logic for deciding when to shrink as in SwissNameDictionary::Delete. 2661cb0ef41Sopenharmony_ci if (Convert<intptr>(Signed(newElementCount)) < (capacity >> 2)) { 2671cb0ef41Sopenharmony_ci const shrunkTable = runtime::ShrinkSwissNameDictionary(kNoContext, table); 2681cb0ef41Sopenharmony_ci goto Shrunk(shrunkTable); 2691cb0ef41Sopenharmony_ci } 2701cb0ef41Sopenharmony_ci} 2711cb0ef41Sopenharmony_ci 2721cb0ef41Sopenharmony_ci// TODO(v8:11330) Ideally, we would like to implement 2731cb0ef41Sopenharmony_ci// CodeStubAssembler::SwissNameDictionaryFindEntry in Torque and do the 2741cb0ef41Sopenharmony_ci// necessary switching between the two implementations with if(kUseSimd) {...} 2751cb0ef41Sopenharmony_ci// else {...}. However, Torque currently generates a call to 2761cb0ef41Sopenharmony_ci// CodeAssembler::Branch which cannot guarantee that code for the "bad" path is 2771cb0ef41Sopenharmony_ci// not generated, even if the branch can be resolved at compile time. This means 2781cb0ef41Sopenharmony_ci// that we end up trying to generate unused code using unsupported instructions. 2791cb0ef41Sopenharmony_ci@export 2801cb0ef41Sopenharmony_cimacro SwissNameDictionaryFindEntrySIMD(table: SwissNameDictionary, key: Name): 2811cb0ef41Sopenharmony_ci never labels Found(intptr), NotFound { 2821cb0ef41Sopenharmony_ci FindEntry<GroupSse2Loader>(table, key) 2831cb0ef41Sopenharmony_ci otherwise Found, NotFound; 2841cb0ef41Sopenharmony_ci} 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ci@export 2871cb0ef41Sopenharmony_cimacro SwissNameDictionaryFindEntryPortable( 2881cb0ef41Sopenharmony_ci table: SwissNameDictionary, key: Name): never labels 2891cb0ef41Sopenharmony_ciFound(intptr), 2901cb0ef41Sopenharmony_ci NotFound { 2911cb0ef41Sopenharmony_ci FindEntry<GroupPortableLoader>(table, key) 2921cb0ef41Sopenharmony_ci otherwise Found, NotFound; 2931cb0ef41Sopenharmony_ci} 2941cb0ef41Sopenharmony_ci 2951cb0ef41Sopenharmony_ci// TODO(v8:11330) Ideally, we would like to implement 2961cb0ef41Sopenharmony_ci// CodeStubAssembler::SwissNameDictionaryAdd in Torque and do the necessary 2971cb0ef41Sopenharmony_ci// switching between the two implementations with if(kUseSimd) {...} else {...}. 2981cb0ef41Sopenharmony_ci// However, Torque currently generates a call to CodeAssembler::Branch which 2991cb0ef41Sopenharmony_ci// cannot guarantee that code for the "bad" path is not generated, even if the 3001cb0ef41Sopenharmony_ci// branch can be resolved at compile time. This means that we end up trying to 3011cb0ef41Sopenharmony_ci// generate unused code using unsupported instructions. 3021cb0ef41Sopenharmony_ci@export 3031cb0ef41Sopenharmony_cimacro SwissNameDictionaryAddSIMD( 3041cb0ef41Sopenharmony_ci table: SwissNameDictionary, key: Name, value: Object, 3051cb0ef41Sopenharmony_ci propertyDetails: uint8): void labels Bailout { 3061cb0ef41Sopenharmony_ci Add<GroupSse2Loader>(table, key, value, propertyDetails) 3071cb0ef41Sopenharmony_ci otherwise Bailout; 3081cb0ef41Sopenharmony_ci} 3091cb0ef41Sopenharmony_ci 3101cb0ef41Sopenharmony_ci@export 3111cb0ef41Sopenharmony_cimacro SwissNameDictionaryAddPortable( 3121cb0ef41Sopenharmony_ci table: SwissNameDictionary, key: Name, value: Object, 3131cb0ef41Sopenharmony_ci propertyDetails: uint8): void labels Bailout { 3141cb0ef41Sopenharmony_ci Add<GroupPortableLoader>(table, key, value, propertyDetails) 3151cb0ef41Sopenharmony_ci otherwise Bailout; 3161cb0ef41Sopenharmony_ci} 3171cb0ef41Sopenharmony_ci} 318