• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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