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