1#!/usr/bin/env ruby 2 3# Copyright (c) 2021-2024 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16include_relative 'common.irt' 17 18module Constants 19 SB_VALUE_OFFSET = 8 20 SB_COUNT_OFFSET = 12 21 NULLSTR = "0x006c006c0075006e" 22 NULLSTR_LEN = "4" 23 TRUESTR = "0x0065007500720074" 24 FALSESTR = "0x0073006c00610066" 25 FALSESTR2 = "0x0065" 26 BOOLSTRLEN = "5" 27end 28 29function(:StringBuilderBool, 30 params: {sb: 'ref', tv: 'u8'}, 31 regmap: $full_regmap, 32 regalloc_set: $panda_mask, 33 mode: [:FastPath]) { 34 # Arm32 is not supported 35 if Options.arch == :arm32 36 Intrinsic(:UNREACHABLE).void.Terminator 37 next 38 end 39 40 value := LoadI(sb).Imm(Constants::SB_VALUE_OFFSET).ref 41 value := Cast(value).SrcType(Constants::COMPILER_REFERENCE).ptr 42 count := LoadI(sb).Imm(Constants::SB_COUNT_OFFSET).u32 43 size := LoadI(value).Imm(Constants::ARRAY_LENGTH_OFFSET).u32 44 length := Cast(Constants::BOOLSTRLEN).u32 45 # len("false") == 5, len("true") == len("false") - (int)true 46 length := Sub(length, Cast(tv).u32).u32 47 48 new_count := Add(count, length).u32 49 If(size, new_count).LT.Unlikely.b { 50 ep_offset = get_entrypoint_offset("STRING_BUILDER_BOOL_SLOW_PATH"); 51 Intrinsic(:SLOW_PATH_ENTRY, sb, tv).AddImm(ep_offset).MethodAsImm("StringBuilderBoolUsualBridge").Terminator.ref 52 Intrinsic(:UNREACHABLE).Terminator.void 53 } 54 55 buf := AddI(value).Imm(Constants::ARRAY_DATA_OFFSET).ptr 56 buf := Add(buf, ShlI(count).Imm(1).u32).ptr 57 58 compare := Compare(tv, 1).EQ.b 59 IfImm(compare).Imm(0).NE.b { 60 v := Constants::TRUESTR 61 StoreI(buf, v).Imm(0).u64 62 } Else { 63 v := Constants::FALSESTR 64 v2 := Constants::FALSESTR2 65 StoreI(buf, v).Imm(0).u64 66 StoreI(buf, v2).Imm(8).u16 67 } 68 69 StoreI(sb, new_count.u32).Imm(Constants::SB_COUNT_OFFSET).u32 70 Return(sb).ref 71} 72 73function(:StringBuilderChar, 74 params: {sb: 'ref', ch: 'u16'}, 75 regmap: $full_regmap, 76 regalloc_set: $panda_mask, 77 mode: [:FastPath]) { 78 # Arm32 is not supported 79 if Options.arch == :arm32 80 Intrinsic(:UNREACHABLE).void.Terminator 81 next 82 end 83 84 value := LoadI(sb).Imm(Constants::SB_VALUE_OFFSET).ref 85 value := Cast(value).SrcType(Constants::COMPILER_REFERENCE).ptr 86 count := LoadI(sb).Imm(Constants::SB_COUNT_OFFSET).u32 87 size := LoadI(value).Imm(Constants::ARRAY_LENGTH_OFFSET).u32 88 If(size, count).LE.Unlikely.b { 89 ep_offset = get_entrypoint_offset("STRING_BUILDER_CHAR_SLOW_PATH"); 90 Intrinsic(:SLOW_PATH_ENTRY, sb, ch).AddImm(ep_offset).MethodAsImm("StringBuilderCharUsualBridge").Terminator.ref 91 Intrinsic(:UNREACHABLE).Terminator.void 92 } 93 94 buf := AddI(value).Imm(Constants::ARRAY_DATA_OFFSET).ptr 95 Store(buf, ShlI(count).Imm(1).u32, ch).u16 96 StoreI(sb, AddI(count).Imm(1).u32).Imm(Constants::SB_COUNT_OFFSET).u32 97 98 Return(sb).ref 99} 100 101def GenerateStringBuilderString(compression) 102 suffix = compression ? "Compressed" : "" 103 function("StringBuilderString#{suffix}".to_sym, 104 params: {sb: 'ref', str: 'ref'}, 105 regmap: $full_regmap, 106 regalloc_set: $panda_mask, 107 mode: [:FastPath]) { 108 109 # Arm32 is not supported 110 if Options.arch == :arm32 111 Intrinsic(:UNREACHABLE).void.Terminator 112 next 113 end 114 115 value := LoadI(sb).Imm(Constants::SB_VALUE_OFFSET).ref 116 value := Cast(value).SrcType(Constants::COMPILER_REFERENCE).ptr 117 count := LoadI(sb).Imm(Constants::SB_COUNT_OFFSET).u32 118 size := LoadI(value).Imm(Constants::ARRAY_LENGTH_OFFSET).u32 119 dst := AddI(value).Imm(Constants::ARRAY_DATA_OFFSET).ptr 120 121 # str is nullptr, store the "null" string with the length of 4 122 compare := Compare(str, 0).SrcType(Constants::COMPILER_REFERENCE).EQ.b 123 IfImm(compare).Imm(0).SrcType(Constants::COMPILER_BOOL).NE.Unlikely.b { 124 new_count := AddI(count).Imm(Constants::NULLSTR_LEN).u32 125 If(new_count, size).GT.Unlikely.b { 126 Goto(:CallCppIntrinsic) 127 } 128 nullstr := Constants::NULLSTR 129 130 Store(dst, ShlI(count).Imm(1).u32, nullstr).u64 131 StoreI(sb, new_count).Imm(Constants::SB_COUNT_OFFSET).Volatile.u32 132 } Else { 133 length := LoadI(str).Imm(Constants::STRING_LENGTH_OFFSET).u32 134 compare := Compare(length, 0).EQ.b 135 IfImm(compare).Imm(0).NE.Unlikely.b { 136 Goto(:Exit) 137 } 138 139 utf16 := Cast(1).u32 140 141 if compression 142 utf16 := AndI(length).Imm(1).u32 143 length := ShrI(length).Imm(1).u32 144 end 145 146 # do not do compressed string unpacking 147 If(utf16, 0).EQ.Unlikely.b { 148 Goto(:CallCppIntrinsic) 149 } 150 151 new_count := Add(count, length).u32 152 If(new_count, size).GT.Unlikely.b { 153 Goto(:CallCppIntrinsic) 154 } 155 156 compare := Compare(length, 8).GT.b 157 IfImm(compare).Imm(0).NE.Unlikely.b { 158 Goto(:CallCppIntrinsic) 159 } 160 161 count := ShlI(count).Imm(1).u32 162 src := Cast(str).SrcType(Constants::COMPILER_REFERENCE).ptr 163 src := AddI(src).Imm(Constants::STRING_DATA_OFFSET).ptr 164 dst := Add(dst, count).ptr 165 166 compare := Compare(length, 4).GT.b 167 IfImm(compare).Imm(0).NE.b { 168 Goto(:SizeGT4) 169 } 170 171 compare := Compare(length, 4).EQ.b 172 IfImm(compare).Imm(0).NE.b { 173 b := LoadI(src).Imm(0).u64 174 StoreI(dst, b).Imm(0).u64 175 Goto(:StoreCount) 176 } 177 178 compare := Compare(length, 1).EQ.b 179 IfImm(compare).Imm(0).NE.b { 180 b := LoadI(src).Imm(0).u16 181 StoreI(dst, b).Imm(0).u16 182 Goto(:StoreCount) 183 } 184 185 b := LoadI(src).Imm(0).u32 186 compare := Compare(length, 2).EQ.b 187 IfImm(compare).Imm(0).NE.b { 188 StoreI(dst, b).Imm(0).u32 189 Goto(:StoreCount) 190 } 191 192 b1 := LoadI(src).Imm(4).u16 193 StoreI(dst, b).Imm(0).u32 194 StoreI(dst, b1).Imm(4).u16 195 Goto(:StoreCount) 196 197Label(:SizeGT4) 198 sz := ShlI(length).Imm(1).u32 199 b1 := LoadI(src).Imm(0).u64 200 b2 := Load(src, SubI(sz).Imm(8).u32).u64 201 StoreI(dst, b1).Imm(0).u64 202 Store(dst, SubI(sz).Imm(8).u32, b2).u64 203 204Label(:StoreCount) 205 StoreI(sb, new_count).Imm(Constants::SB_COUNT_OFFSET).Volatile.u32 206 } 207 208Label(:Exit) 209 Return(sb).ref 210 211Label(:CallCppIntrinsic) 212 ep_offset = get_entrypoint_offset("STRING_BUILDER_STRING_SLOW_PATH"); 213 Intrinsic(:SLOW_PATH_ENTRY, sb, str).AddImm(ep_offset).MethodAsImm("StringBuilderStringUsualBridge").Terminator.ref 214 Intrinsic(:UNREACHABLE).Terminator.void 215 216} 217end 218 219include_plugin 'ets_string_builder' 220 221GenerateStringBuilderString(true) 222GenerateStringBuilderString(false) 223