1#!/usr/bin/env ruby 2 3# Copyright (c) 2021-2022 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" 27 SB_STRING_SLOW_PATH = "cross_values::GetManagedThreadEntrypointOffset(GetArch(), EntrypointId::STRING_BUILDER_STRING_SLOW_PATH)" 28 SB_STRING_USUAL_BRIDGE = "cross_values::GetManagedThreadEntrypointOffset(GetArch(), EntrypointId::STRING_BUILDER_STRING_USUAL_BRIDGE)" 29 SB_CHAR_SLOW_PATH = "cross_values::GetManagedThreadEntrypointOffset(GetArch(), EntrypointId::STRING_BUILDER_CHAR_SLOW_PATH)" 30 SB_CHAR_USUAL_BRIDGE = "cross_values::GetManagedThreadEntrypointOffset(GetArch(), EntrypointId::STRING_BUILDER_CHAR_USUAL_BRIDGE)" 31 SB_BOOL_SLOW_PATH = "cross_values::GetManagedThreadEntrypointOffset(GetArch(), EntrypointId::STRING_BUILDER_BOOL_SLOW_PATH)" 32 SB_BOOL_USUAL_BRIDGE = "cross_values::GetManagedThreadEntrypointOffset(GetArch(), EntrypointId::STRING_BUILDER_BOOL_USUAL_BRIDGE)" 33end 34 35function(:StringBuilderBool, 36 params: {sb: 'ref', tv: 'u8'}, 37 regmap: $full_regmap, 38 regalloc_set: $panda_mask, 39 mode: [:FastPath]) { 40 # Arm32 is not supported 41 if Options.arch == :arm32 42 Intrinsic(:UNREACHABLE).void.Terminator 43 next 44 end 45 46 value := LoadI(sb).Imm(Constants::SB_VALUE_OFFSET).ref 47 value := Cast(value).SrcType(Constants::COMPILER_REFERENCE).ptr 48 count := LoadI(sb).Imm(Constants::SB_COUNT_OFFSET).u32 49 size := LoadI(value).Imm(Constants::ARRAY_LENGTH_OFFSET).u32 50 length := Cast(Constants::BOOLSTRLEN).u32 51 # len("false") == 5, len("true") == len("false") - (int)true 52 length := Sub(length, Cast(tv).u32).u32 53 54 new_count := Add(count, length).u32 55 If(size, new_count).LT.Unlikely.b { 56 Intrinsic(:SLOW_PATH_ENTRY, sb, tv).AddImm(Constants::SB_BOOL_SLOW_PATH).AddImm(Constants::SB_BOOL_USUAL_BRIDGE).Terminator.ref 57 Intrinsic(:UNREACHABLE).Terminator.void 58 } 59 60 buf := AddI(value).Imm(Constants::ARRAY_DATA_OFFSET).ptr 61 buf := Add(buf, ShlI(count).Imm(1).u32).ptr 62 63 compare := Compare(tv, 1).EQ.b 64 IfImm(compare).Imm(0).NE.b { 65 v := Constants::TRUESTR 66 StoreI(buf, v).Imm(0).u64 67 } Else { 68 v := Constants::FALSESTR 69 v2 := Constants::FALSESTR2 70 StoreI(buf, v).Imm(0).u64 71 StoreI(buf, v2).Imm(8).u16 72 } 73 74 StoreI(sb, new_count.u32).Imm(Constants::SB_COUNT_OFFSET).u32 75 Return(sb).ref 76} 77 78function(:StringBuilderChar, 79 params: {sb: 'ref', ch: 'u16'}, 80 regmap: $full_regmap, 81 regalloc_set: $panda_mask, 82 mode: [:FastPath]) { 83 # Arm32 is not supported 84 if Options.arch == :arm32 85 Intrinsic(:UNREACHABLE).void.Terminator 86 next 87 end 88 89 value := LoadI(sb).Imm(Constants::SB_VALUE_OFFSET).ref 90 value := Cast(value).SrcType(Constants::COMPILER_REFERENCE).ptr 91 count := LoadI(sb).Imm(Constants::SB_COUNT_OFFSET).u32 92 size := LoadI(value).Imm(Constants::ARRAY_LENGTH_OFFSET).u32 93 If(size, count).LE.Unlikely.b { 94 Intrinsic(:SLOW_PATH_ENTRY, sb, ch).AddImm(Constants::SB_CHAR_SLOW_PATH).AddImm(Constants::SB_CHAR_USUAL_BRIDGE).Terminator.ref 95 Intrinsic(:UNREACHABLE).Terminator.void 96 } 97 98 buf := AddI(value).Imm(Constants::ARRAY_DATA_OFFSET).ptr 99 Store(buf, ShlI(count).Imm(1).u32, ch).u16 100 StoreI(sb, AddI(count).Imm(1).u32).Imm(Constants::SB_COUNT_OFFSET).u32 101 102 Return(sb).ref 103} 104 105def GenerateStringBuilderString(compression) 106 suffix = compression ? "Compressed" : "" 107 function("StringBuilderString#{suffix}".to_sym, 108 params: {sb: 'ref', str: 'ref'}, 109 regmap: $full_regmap, 110 regalloc_set: $panda_mask, 111 mode: [:FastPath]) { 112 113 # Arm32 is not supported 114 if Options.arch == :arm32 115 Intrinsic(:UNREACHABLE).void.Terminator 116 next 117 end 118 119 value := LoadI(sb).Imm(Constants::SB_VALUE_OFFSET).ref 120 value := Cast(value).SrcType(Constants::COMPILER_REFERENCE).ptr 121 count := LoadI(sb).Imm(Constants::SB_COUNT_OFFSET).u32 122 size := LoadI(value).Imm(Constants::ARRAY_LENGTH_OFFSET).u32 123 dst := AddI(value).Imm(Constants::ARRAY_DATA_OFFSET).ptr 124 125 # str is nullptr, store the "null" string with the length of 4 126 compare := Compare(str, 0).SrcType(Constants::COMPILER_REFERENCE).EQ.b 127 IfImm(compare).Imm(0).SrcType(Constants::COMPILER_BOOL).NE.Unlikely.b { 128 new_count := AddI(count).Imm(Constants::NULLSTR_LEN).u32 129 If(new_count, size).GT.Unlikely.b { 130 Goto(:CallCppIntrinsic) 131 } 132 nullstr := Constants::NULLSTR 133 134 Store(dst, ShlI(count).Imm(1).u32, nullstr).u64 135 StoreI(sb, new_count).Imm(Constants::SB_COUNT_OFFSET).Volatile.u32 136 } Else { 137 length := LoadI(str).Imm(Constants::STRING_LENGTH_OFFSET).u32 138 compare := Compare(length, 0).EQ.b 139 IfImm(compare).Imm(0).NE.Unlikely.b { 140 Goto(:Exit) 141 } 142 143 utf16 := Cast(1).u32 144 145 if compression 146 utf16 := AndI(length).Imm(1).u32 147 length := ShrI(length).Imm(1).u32 148 end 149 150 # do not do compressed string unpacking 151 If(utf16, 0).EQ.Unlikely.b { 152 Goto(:CallCppIntrinsic) 153 } 154 155 new_count := Add(count, length).u32 156 If(new_count, size).GT.Unlikely.b { 157 Goto(:CallCppIntrinsic) 158 } 159 160 compare := Compare(length, 8).GT.b 161 IfImm(compare).Imm(0).NE.Unlikely.b { 162 Goto(:CallCppIntrinsic) 163 } 164 165 count := ShlI(count).Imm(1).u32 166 src := Cast(str).SrcType(Constants::COMPILER_REFERENCE).ptr 167 src := AddI(src).Imm(Constants::STRING_DATA_OFFSET).ptr 168 dst := Add(dst, count).ptr 169 170 compare := Compare(length, 4).GT.b 171 IfImm(compare).Imm(0).NE.b { 172 Goto(:SizeGT4) 173 } 174 175 compare := Compare(length, 4).EQ.b 176 IfImm(compare).Imm(0).NE.b { 177 b := LoadI(src).Imm(0).u64 178 StoreI(dst, b).Imm(0).u64 179 Goto(:StoreCount) 180 } 181 182 compare := Compare(length, 1).EQ.b 183 IfImm(compare).Imm(0).NE.b { 184 b := LoadI(src).Imm(0).u16 185 StoreI(dst, b).Imm(0).u16 186 Goto(:StoreCount) 187 } 188 189 b := LoadI(src).Imm(0).u32 190 compare := Compare(length, 2).EQ.b 191 IfImm(compare).Imm(0).NE.b { 192 StoreI(dst, b).Imm(0).u32 193 Goto(:StoreCount) 194 } 195 196 b1 := LoadI(src).Imm(4).u16 197 StoreI(dst, b).Imm(0).u32 198 StoreI(dst, b1).Imm(4).u16 199 Goto(:StoreCount) 200 201Label(:SizeGT4) 202 sz := ShlI(length).Imm(1).u32 203 b1 := LoadI(src).Imm(0).u64 204 b2 := Load(src, SubI(sz).Imm(8).u32).u64 205 StoreI(dst, b1).Imm(0).u64 206 Store(dst, SubI(sz).Imm(8).u32, b2).u64 207 208Label(:StoreCount) 209 StoreI(sb, new_count).Imm(Constants::SB_COUNT_OFFSET).Volatile.u32 210 } 211 212Label(:Exit) 213 Return(sb).ref 214 215Label(:CallCppIntrinsic) 216 Intrinsic(:SLOW_PATH_ENTRY, sb, str).AddImm(Constants::SB_STRING_SLOW_PATH).AddImm(Constants::SB_STRING_USUAL_BRIDGE).Terminator.ref 217 Intrinsic(:UNREACHABLE).Terminator.void 218 219} 220end 221GenerateStringBuilderString(true) 222GenerateStringBuilderString(false) 223