• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37624

18 Sep 2023 02:15AM UTC coverage: 85.879% (-0.3%) from 86.162%
#37624

push

local

web-flow
testdefs: make sure that if a test set changes the active project, they change it back when they're done (#51029)

We already check the following for mutation by a test set:
1. DEPOT_PATH
2. LOAD_PATH
3. ENV

So this PR just adds the active project to the list of things we check.

Changing the active project during a test set can definitely have
negative effects on subsequent test sets that are run on the same
worker, so we want to make sure if a test set changes the active
project, that they change it back when they're done.

72351 of 84248 relevant lines covered (85.88%)

11376443.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.68
/stdlib/InteractiveUtils/src/codeview.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
# highlighting settings
4
const highlighting = Dict{Symbol, Bool}(
5
    :warntype => true,
6
    :llvm => true,
7
    :native => true,
8
)
9

10
const llstyle = Dict{Symbol, Tuple{Bool, Union{Symbol, Int}}}(
11
    :default     => (false, :normal), # e.g. comma, equal sign, unknown token
12
    :comment     => (false, :light_black),
13
    :label       => (false, :light_red),
14
    :instruction => ( true, :light_cyan),
15
    :type        => (false, :cyan),
16
    :number      => (false, :yellow),
17
    :bracket     => (false, :yellow),
18
    :variable    => (false, :normal), # e.g. variable, register
19
    :keyword     => (false, :light_magenta),
20
    :funcname    => (false, :light_yellow),
21
)
22

23
function printstyled_ll(io::IO, x, s::Symbol, trailing_spaces="")
1,563✔
24
    printstyled(io, x, bold=llstyle[s][1], color=llstyle[s][2])
1,563✔
25
    print(io, trailing_spaces)
1,042✔
26
end
27

28
# displaying type warnings
29

30
function warntype_type_printer(io::IO; @nospecialize(type), used::Bool, show_type::Bool=true, _...)
580✔
31
    (show_type && used) || return nothing
383✔
32
    str = "::$type"
197✔
33
    if !highlighting[:warntype]
197✔
34
        print(io, str)
4✔
35
    elseif type isa Union && is_expected_union(type)
193✔
36
        Base.emphasize(io, str, Base.warn_color()) # more mild user notification
6✔
37
    elseif type isa Type && (!Base.isdispatchelem(type) || type == Core.Box)
325✔
38
        Base.emphasize(io, str)
7✔
39
    else
40
        Base.printstyled(io, str, color=:cyan) # show the "good" type
180✔
41
    end
42
    return nothing
197✔
43
end
44

45
# True if one can be pretty certain that the compiler handles this union well,
46
# i.e. must be small with concrete types.
47
function is_expected_union(u::Union)
14✔
48
    Base.unionlen(u) < 4 || return false
14✔
49
    for x in Base.uniontypes(u)
14✔
50
        if !Base.isdispatchelem(x) || x == Core.Box
57✔
51
            return false
3✔
52
        end
53
    end
38✔
54
    return true
11✔
55
end
56

57
"""
58
    code_warntype([io::IO], f, types; debuginfo=:default)
59

60
Prints lowered and type-inferred ASTs for the methods matching the given generic function
61
and type signature to `io` which defaults to `stdout`. The ASTs are annotated in such a way
62
as to cause "non-leaf" types which may be problematic for performance to be emphasized
63
(if color is available, displayed in red). This serves as a warning of potential type instability.
64

65
Not all non-leaf types are particularly problematic for performance, and the performance
66
characteristics of a particular type is an implementation detail of the compiler.
67
`code_warntype` will err on the side of coloring types red if they might be a performance
68
concern, so some types may be colored red even if they do not impact performance.
69
Small unions of concrete types are usually not a concern, so these are highlighted in yellow.
70

71
Keyword argument `debuginfo` may be one of `:source` or `:none` (default), to specify the verbosity of code comments.
72

73
See [`@code_warntype`](@ref man-code-warntype) for more information.
74

75
See also: [`@code_warntype`](@ref), [`code_typed`](@ref), [`code_lowered`](@ref), [`code_llvm`](@ref), [`code_native`](@ref).
76
"""
77
function code_warntype(io::IO, @nospecialize(f), @nospecialize(t=Base.default_tt(f));
54✔
78
                       debuginfo::Symbol=:default, optimize::Bool=false, kwargs...)
79
    debuginfo = Base.IRShow.debuginfo(debuginfo)
26✔
80
    lineprinter = Base.IRShow.__debuginfo[debuginfo]
26✔
81
    for (src, rettype) in code_typed(f, t; optimize, kwargs...)
26✔
82
        if !(src isa Core.CodeInfo)
26✔
83
            println(io, src)
×
84
            println(io, "  failed to infer")
×
85
            continue
×
86
        end
87
        lambda_io::IOContext = io
26✔
88
        p = src.parent
26✔
89
        nargs::Int = 0
26✔
90
        if p isa Core.MethodInstance
26✔
91
            println(io, p)
26✔
92
            print(io, "  from ")
26✔
93
            println(io, p.def)
26✔
94
            p.def isa Method && (nargs = p.def.nargs)
52✔
95
            if !isempty(p.sparam_vals)
26✔
96
                println(io, "Static Parameters")
4✔
97
                sig = p.def.sig
4✔
98
                warn_color = Base.warn_color() # more mild user notification
4✔
99
                for i = 1:length(p.sparam_vals)
8✔
100
                    sig = sig::UnionAll
8✔
101
                    name = sig.var.name
8✔
102
                    val = p.sparam_vals[i]
8✔
103
                    print_highlighted(io::IO, v::String, color::Symbol) =
17✔
104
                        if highlighting[:warntype]
105
                            Base.printstyled(io, v; color)
9✔
106
                        else
107
                            Base.print(io, v)
×
108
                        end
109
                    if val isa TypeVar
8✔
110
                        if val.lb === Union{}
3✔
111
                            print(io, "  ", name, " <: ")
1✔
112
                            print_highlighted(io, "$(val.ub)", warn_color)
1✔
113
                        elseif val.ub === Any
2✔
114
                            print(io, "  ", sig.var.name, " >: ")
1✔
115
                            print_highlighted(io, "$(val.lb)", warn_color)
1✔
116
                        else
117
                            print(io, "  ")
1✔
118
                            print_highlighted(io, "$(val.lb)", warn_color)
1✔
119
                            print(io, " <: ", sig.var.name, " <: ")
1✔
120
                            print_highlighted(io, "$(val.ub)", warn_color)
4✔
121
                        end
122
                    elseif val isa typeof(Vararg)
5✔
123
                        print(io, "  ", name, "::")
1✔
124
                        print_highlighted(io, "Int", warn_color)
1✔
125
                    else
126
                        print(io, "  ", sig.var.name, " = ")
4✔
127
                        print_highlighted(io, "$(val)", :cyan) # show the "good" type
4✔
128
                    end
129
                    println(io)
8✔
130
                    sig = sig.body
8✔
131
                end
12✔
132
            end
133
        end
134
        if src.slotnames !== nothing
26✔
135
            slotnames = Base.sourceinfo_slotnames(src)
26✔
136
            lambda_io = IOContext(lambda_io, :SOURCE_SLOTNAMES => slotnames)
26✔
137
            slottypes = src.slottypes
26✔
138
            nargs > 0 && println(io, "Arguments")
26✔
139
            for i = 1:length(slotnames)
52✔
140
                if i == nargs + 1
75✔
141
                    println(io, "Locals")
6✔
142
                end
143
                print(io, "  ", slotnames[i])
75✔
144
                if isa(slottypes, Vector{Any})
75✔
145
                    warntype_type_printer(io; type=slottypes[i], used=true)
75✔
146
                end
147
                println(io)
75✔
148
            end
124✔
149
        end
150
        print(io, "Body")
26✔
151
        warntype_type_printer(io; type=rettype, used=true)
26✔
152
        println(io)
26✔
153
        irshow_config = Base.IRShow.IRShowConfig(lineprinter(src), warntype_type_printer)
26✔
154
        Base.IRShow.show_ir(lambda_io, src, irshow_config)
26✔
155
        println(io)
26✔
156
    end
52✔
157
    nothing
26✔
158
end
159
code_warntype(args...; kwargs...) = (@nospecialize; code_warntype(stdout, args...; kwargs...))
×
160

161
using Base: CodegenParams
162

163
const GENERIC_SIG_WARNING = "; WARNING: This code may not match what actually runs.\n"
164
const OC_MISMATCH_WARNING =
165
"""
166
; WARNING: The pre-inferred opaque closure is not callable with the given arguments
167
;          and will error on dispatch with this signature.
168
"""
169

170
# Printing code representations in IR and assembly
171

172
function _dump_function(@nospecialize(f), @nospecialize(t), native::Bool, wrapper::Bool,
125✔
173
                        raw::Bool, dump_module::Bool, syntax::Symbol,
174
                        optimize::Bool, debuginfo::Symbol, binary::Bool,
175
                        params::CodegenParams=CodegenParams(debug_info_kind=Cint(0), safepoint_on_entry=raw, gcstack_arg=raw))
176
    ccall(:jl_is_in_pure_context, Bool, ()) && error("code reflection cannot be used from generated functions")
125✔
177
    if isa(f, Core.Builtin)
120✔
178
        throw(ArgumentError("argument is not a generic function"))
2✔
179
    end
180
    warning = ""
118✔
181
    # get the MethodInstance for the method match
182
    if !isa(f, Core.OpaqueClosure)
118✔
183
        world = Base.get_world_counter()
114✔
184
        match = Base._which(signature_type(f, t); world)
114✔
185
        mi = Core.Compiler.specialize_method(match)
111✔
186
        # TODO: use jl_is_cacheable_sig instead of isdispatchtuple
187
        isdispatchtuple(mi.specTypes) || (warning = GENERIC_SIG_WARNING)
111✔
188
    else
189
        world = UInt64(f.world)
4✔
190
        tt = Base.to_tuple_type(t)
4✔
191
        if Core.Compiler.is_source_inferred(f.source.source)
4✔
192
            # OC was constructed from inferred source. There's only one
193
            # specialization and we can't infer anything more precise either.
194
            world = f.source.primary_world
4✔
195
            mi = f.source.specializations::Core.MethodInstance
4✔
196
            Core.Compiler.hasintersect(typeof(f).parameters[1], tt) || (warning = OC_MISMATCH_WARNING)
4✔
197
        else
198
            mi = Core.Compiler.specialize_method(f.source, Tuple{typeof(f.captures), tt.parameters...}, Core.svec())
×
199
            actual = isdispatchtuple(mi.specTypes)
×
200
            isdispatchtuple(mi.specTypes) || (warning = GENERIC_SIG_WARNING)
×
201
        end
202
    end
203
    # get the code for it
204
    if debuginfo === :default
115✔
205
        debuginfo = :source
74✔
206
    elseif debuginfo !== :source && debuginfo !== :none
41✔
207
        throw(ArgumentError("'debuginfo' must be either :source or :none"))
×
208
    end
209
    if native
115✔
210
        if syntax !== :att && syntax !== :intel
28✔
211
            throw(ArgumentError("'syntax' must be either :intel or :att"))
×
212
        end
213
        if dump_module
28✔
214
            # we want module metadata, so use LLVM to generate assembly output
215
            str = _dump_function_native_assembly(mi, world, wrapper, syntax, debuginfo, binary, raw, params)
25✔
216
        else
217
            # if we don't want the module metadata, just disassemble what our JIT has
218
            str = _dump_function_native_disassembly(mi, world, wrapper, syntax, debuginfo, binary)
31✔
219
        end
220
    else
221
        str = _dump_function_llvm(mi, world, wrapper, !raw, dump_module, optimize, debuginfo, params)
87✔
222
    end
223
    str = warning * str
115✔
224
    return str
115✔
225
end
226

227
function _dump_function_native_disassembly(mi::Core.MethodInstance, world::UInt,
3✔
228
                                           wrapper::Bool, syntax::Symbol,
229
                                           debuginfo::Symbol, binary::Bool)
230
    str = @ccall jl_dump_method_asm(mi::Any, world::UInt, false::Bool, wrapper::Bool,
3✔
231
                                    syntax::Ptr{UInt8}, debuginfo::Ptr{UInt8},
232
                                    binary::Bool)::Ref{String}
233
    return str
3✔
234
end
235

236
struct LLVMFDump
237
    tsm::Ptr{Cvoid} # opaque
238
    f::Ptr{Cvoid} # opaque
239
end
240

241
function _dump_function_native_assembly(mi::Core.MethodInstance, world::UInt,
25✔
242
                                        wrapper::Bool, syntax::Symbol, debuginfo::Symbol,
243
                                        binary::Bool, raw::Bool, params::CodegenParams)
244
    llvmf_dump = Ref{LLVMFDump}()
25✔
245
    @ccall jl_get_llvmf_defn(llvmf_dump::Ptr{LLVMFDump},mi::Any, world::UInt, wrapper::Bool,
25✔
246
                             true::Bool, params::CodegenParams)::Cvoid
247
    llvmf_dump[].f == C_NULL && error("could not compile the specified method")
25✔
248
    str = @ccall jl_dump_function_asm(llvmf_dump::Ptr{LLVMFDump}, false::Bool,
25✔
249
                                      syntax::Ptr{UInt8}, debuginfo::Ptr{UInt8},
250
                                      binary::Bool, raw::Bool)::Ref{String}
251
    return str
25✔
252
end
253

254
function _dump_function_llvm(
87✔
255
        mi::Core.MethodInstance, world::UInt, wrapper::Bool,
256
        strip_ir_metadata::Bool, dump_module::Bool,
257
        optimize::Bool, debuginfo::Symbol,
258
        params::CodegenParams)
259
    llvmf_dump = Ref{LLVMFDump}()
87✔
260
    @ccall jl_get_llvmf_defn(llvmf_dump::Ptr{LLVMFDump}, mi::Any, world::UInt,
87✔
261
                             wrapper::Bool, optimize::Bool, params::CodegenParams)::Cvoid
262
    llvmf_dump[].f == C_NULL && error("could not compile the specified method")
87✔
263
    str = @ccall jl_dump_function_ir(llvmf_dump::Ptr{LLVMFDump}, strip_ir_metadata::Bool,
87✔
264
                                     dump_module::Bool, debuginfo::Ptr{UInt8})::Ref{String}
265
    return str
87✔
266
end
267

268
"""
269
    code_llvm([io=stdout,], f, types; raw=false, dump_module=false, optimize=true, debuginfo=:default)
270

271
Prints the LLVM bitcodes generated for running the method matching the given generic
272
function and type signature to `io`.
273

274
If the `optimize` keyword is unset, the code will be shown before LLVM optimizations.
275
All metadata and dbg.* calls are removed from the printed bitcode. For the full IR, set the `raw` keyword to true.
276
To dump the entire module that encapsulates the function (with declarations), set the `dump_module` keyword to true.
277
Keyword argument `debuginfo` may be one of source (default) or none, to specify the verbosity of code comments.
278

279
See also: [`@code_llvm`](@ref), [`code_warntype`](@ref), [`code_typed`](@ref), [`code_lowered`](@ref), [`code_native`](@ref).
280
"""
281
function code_llvm(io::IO, @nospecialize(f), @nospecialize(types=Base.default_tt(f));
108✔
282
                   raw::Bool=false, dump_module::Bool=false, optimize::Bool=true, debuginfo::Symbol=:default,
283
                   params::CodegenParams=CodegenParams(debug_info_kind=Cint(0), safepoint_on_entry=raw, gcstack_arg=raw))
284
    d = _dump_function(f, types, false, false, raw, dump_module, :intel, optimize, debuginfo, false, params)
53✔
285
    if highlighting[:llvm] && get(io, :color, false)::Bool
49✔
286
        print_llvm(io, d)
1✔
287
    else
288
        print(io, d)
48✔
289
    end
290
end
291
code_llvm(args...; kwargs...) = (@nospecialize; code_llvm(stdout, args...; kwargs...))
12✔
292

293
"""
294
    code_native([io=stdout,], f, types; syntax=:intel, debuginfo=:default, binary=false, dump_module=true)
295

296
Prints the native assembly instructions generated for running the method matching the given
297
generic function and type signature to `io`.
298

299
* Set assembly syntax by setting `syntax` to `:intel` (default) for intel syntax or `:att` for AT&T syntax.
300
* Specify verbosity of code comments by setting `debuginfo` to `:source` (default) or `:none`.
301
* If `binary` is `true`, also print the binary machine code for each instruction precedented by an abbreviated address.
302
* If `dump_module` is `false`, do not print metadata such as rodata or directives.
303
* If `raw` is `false`, uninteresting instructions (like the safepoint function prologue) are elided.
304

305
See also: [`@code_native`](@ref), [`code_warntype`](@ref), [`code_typed`](@ref), [`code_lowered`](@ref), [`code_llvm`](@ref).
306
"""
307
function code_native(io::IO, @nospecialize(f), @nospecialize(types=Base.default_tt(f));
68✔
308
                     dump_module::Bool=true, syntax::Symbol=:intel, raw::Bool=false,
309
                     debuginfo::Symbol=:default, binary::Bool=false,
310
                     params::CodegenParams=CodegenParams(debug_info_kind=Cint(0), safepoint_on_entry=raw, gcstack_arg=raw))
311
    d = _dump_function(f, types, true, false, raw, dump_module, syntax, true, debuginfo, binary, params)
33✔
312
    if highlighting[:native] && get(io, :color, false)::Bool
28✔
313
        print_native(io, d)
1✔
314
    else
315
        print(io, d)
27✔
316
    end
317
end
318
code_native(args...; kwargs...) = (@nospecialize; code_native(stdout, args...; kwargs...))
14✔
319

320
## colorized IR and assembly printing
321

322
const num_regex = r"^(?:\$?-?\d+|0x[0-9A-Fa-f]+|-?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?)$"
323

324
function print_llvm(io::IO, code::String)
34✔
325
    buf = IOBuffer(code)
34✔
326
    for line in eachline(buf)
68✔
327
        m = match(r"^(\s*)((?:[^;]|;\")*)(.*)$", line)
43✔
328
        m === nothing && continue
43✔
329
        indent, tokens, comment = m.captures
43✔
330
        print(io, indent)
86✔
331
        print_llvm_tokens(io, tokens)
86✔
332
        printstyled_ll(io, comment, :comment)
86✔
333
        println(io)
43✔
334
    end
43✔
335
end
336

337
const llvm_types =
338
    r"^(?:void|half|float|double|x86_\w+|ppc_\w+|label|metadata|type|opaque|token|i\d+)$"
339
const llvm_cond = r"^(?:[ou]?eq|[ou]?ne|[uso][gl][te]|ord|uno)$" # true|false
340

341
function print_llvm_tokens(io, tokens)
43✔
342
    m = match(r"^((?:[^\s:]+:)?)(\s*)(.*)", tokens)
43✔
343
    if m !== nothing
43✔
344
        label, spaces, tokens = m.captures
43✔
345
        printstyled_ll(io, label, :label, spaces)
86✔
346
    end
347
    m = match(r"^(%[^\s=]+)(\s*)=(\s*)(.*)", tokens)
43✔
348
    if m !== nothing
43✔
349
        result, spaces, spaces2, tokens = m.captures
21✔
350
        printstyled_ll(io, result, :variable, spaces)
42✔
351
        printstyled_ll(io, '=', :default, spaces2)
42✔
352
    end
353
    m = match(r"^([a-z]\w*)(\s*)(.*)", tokens)
43✔
354
    if m !== nothing
43✔
355
        inst, spaces, tokens = m.captures
34✔
356
        iskeyword = occursin(r"^(?:define|declare|type)$", inst) || occursin("=", tokens)
64✔
357
        printstyled_ll(io, inst, iskeyword ? :keyword : :instruction, spaces)
68✔
358
    end
359

360
    print_llvm_operands(io, tokens)
43✔
361
end
362

363
function print_llvm_operands(io, tokens)
67✔
364
    while !isempty(tokens)
240✔
365
        tokens = print_llvm_operand(io, tokens)
106✔
366
    end
106✔
367
    return tokens
67✔
368
end
369

370
function print_llvm_operand(io, tokens)
106✔
371
    islabel = false
106✔
372
    while !isempty(tokens)
640✔
373
        m = match(r"^,(\s*)(.*)", tokens)
269✔
374
        if m !== nothing
269✔
375
            spaces, tokens = m.captures
31✔
376
            printstyled_ll(io, ',', :default, spaces)
62✔
377
            break
31✔
378
        end
379
        m = match(r"^(\*+|=)(\s*)(.*)", tokens)
238✔
380
        if m !== nothing
238✔
381
            sym, spaces, tokens = m.captures
20✔
382
            printstyled_ll(io, sym, :default, spaces)
40✔
383
            continue
20✔
384
        end
385
        m = match(r"^(\"[^\"]*\")(\s*)(.*)", tokens)
218✔
386
        if m !== nothing
218✔
387
            str, spaces, tokens = m.captures
3✔
388
            printstyled_ll(io, str, :variable, spaces)
6✔
389
            continue
3✔
390
        end
391
        m = match(r"^([({\[<])(\s*)(.*)", tokens)
215✔
392
        if m !== nothing
215✔
393
            bracket, spaces, tokens = m.captures
24✔
394
            printstyled_ll(io, bracket, :bracket, spaces)
48✔
395
            tokens = print_llvm_operands(io, tokens) # enter
48✔
396
            continue
24✔
397
        end
398
        m = match(r"^([)}\]>])(\s*)(.*)", tokens)
191✔
399
        if m !== nothing
191✔
400
            bracket, spaces, tokens = m.captures
24✔
401
            printstyled_ll(io, bracket, :bracket, spaces)
48✔
402
            break # leave
24✔
403
        end
404

405
        m = match(r"^([^\s,*=(){}\[\]<>]+)(\s*)(.*)", tokens)
167✔
406
        m === nothing && break
167✔
407
        token, spaces, tokens = m.captures
167✔
408
        if occursin(llvm_types, token)
167✔
409
            printstyled_ll(io, token, :type)
55✔
410
            islabel = token == "label"
106✔
411
        elseif occursin(llvm_cond, token) # condition code is instruction-level
112✔
412
            printstyled_ll(io, token, :instruction)
1✔
413
        elseif occursin(num_regex, token)
111✔
414
            printstyled_ll(io, token, :number)
29✔
415
        elseif occursin(r"^@.+$", token)
82✔
416
            printstyled_ll(io, token, :funcname)
5✔
417
        elseif occursin(r"^%.+$", token)
77✔
418
            islabel |= occursin(r"^%[^\d].*$", token) & occursin(r"^\]", tokens)
38✔
419
            printstyled_ll(io, token, islabel ? :label : :variable)
38✔
420
            islabel = false
38✔
421
        elseif occursin(r"^[a-z]\w+$", token)
39✔
422
            printstyled_ll(io, token, :keyword)
34✔
423
        else
424
            printstyled_ll(io, token, :default)
5✔
425
        end
426
        print(io, spaces)
167✔
427
    end
214✔
428
    return tokens
106✔
429
end
430

431
function print_native(io::IO, code::String, arch::Symbol=sys_arch_category())
59✔
432
    archv = Val(arch)
59✔
433
    buf = IOBuffer(code)
58✔
434
    for line in eachline(buf)
116✔
435
        m = match(r"^(\s*)((?:[^;#/]|#\S|;\"|/[^/])*)(.*)$", line)
96✔
436
        m === nothing && continue
96✔
437
        indent, tokens, comment = m.captures
96✔
438
        print(io, indent)
192✔
439
        print_native_tokens(io, tokens, archv)
96✔
440
        printstyled_ll(io, comment, :comment)
192✔
441
        println(io)
96✔
442
    end
96✔
443
end
444

445
function sys_arch_category()
1✔
446
    if Sys.ARCH === :x86_64 || Sys.ARCH === :i686
1✔
447
        :x86
1✔
448
    elseif Sys.ARCH === :aarch64 || startswith(string(Sys.ARCH), "arm")
×
449
        :arm
×
450
    else
451
        :unsupported
×
452
    end
453
end
454

455
print_native_tokens(io, line, ::Val) = print(io, line)
1✔
456

457
const x86_ptr = r"^(?:(?:[xyz]mm|[dq])?word|byte|ptr|offset)$"
458
const avx512flags = r"^(?:z|r[nduz]-sae|sae|1to1?\d)$"
459
const arm_cond = r"^(?:eq|ne|cs|ho|cc|lo|mi|pl|vs|vc|hi|ls|[lg][te]|al|nv)$"
460
const arm_keywords = r"^(?:lsl|lsr|asr|ror|rrx|!|/[zm])$"
461

462
function print_native_tokens(io, tokens, arch::Union{Val{:x86}, Val{:arm}})
95✔
463
    x86 = arch isa Val{:x86}
95✔
464
    m = match(r"^((?:[^\s:]+:|\"[^\"]+\":)?)(\s*)(.*)", tokens)
95✔
465
    if m !== nothing
95✔
466
        label, spaces, tokens = m.captures
95✔
467
        printstyled_ll(io, label, :label, spaces)
190✔
468
    end
469
    haslabel = false
95✔
470
    m = match(r"^([a-z][\w.]*)(\s*)(.*)", tokens)
95✔
471
    if m !== nothing
95✔
472
        instruction, spaces, tokens = m.captures
57✔
473
        printstyled_ll(io, instruction, :instruction, spaces)
114✔
474
        haslabel = occursin(r"^(?:bl?|bl?\.\w{2,5}|[ct]bn?z)?$", instruction)
57✔
475
    end
476

477
    isfuncname = false
95✔
478
    while !isempty(tokens)
896✔
479
        m = match(r"^([,:*])(\s*)(.*)", tokens)
353✔
480
        if m !== nothing
353✔
481
            sym, spaces, tokens = m.captures
86✔
482
            printstyled_ll(io, sym, :default, spaces)
172✔
483
            isfuncname = false
86✔
484
            continue
86✔
485
        end
486
        m = match(r"^([(){}\[\]])(\s*)(.*)", tokens)
267✔
487
        if m !== nothing
267✔
488
            bracket, spaces, tokens = m.captures
56✔
489
            printstyled_ll(io, bracket, :bracket, spaces)
112✔
490
            continue
56✔
491
        end
492
        m = match(r"^#([0-9a-fx.-]+)(\s*)(.*)", tokens)
211✔
493
        if !x86 && m !== nothing && occursin(num_regex, m.captures[1])
211✔
494
            num, spaces, tokens = m.captures
6✔
495
            printstyled_ll(io, "#" * num, :number, spaces)
12✔
496
            continue
6✔
497
        end
498

499
        m = match(r"^([^\s,:*(){}\[\]][^\s,:*/(){}\[\]]*)(\s*)(.*)", tokens)
205✔
500
        m === nothing && break
205✔
501
        token, spaces, tokens = m.captures
205✔
502
        if occursin(num_regex, token)
205✔
503
            printstyled_ll(io, token, :number)
20✔
504
        elseif x86 && occursin(x86_ptr, token) || occursin(avx512flags, token)
310✔
505
            printstyled_ll(io, token, :keyword)
22✔
506
            isfuncname = token == "offset"
22✔
507
        elseif !x86 && (occursin(arm_keywords, token) || occursin(arm_cond, token))
202✔
508
            printstyled_ll(io, token, :keyword)
7✔
509
        elseif occursin(r"^L.+$", token)
156✔
510
            printstyled_ll(io, token, :label)
5✔
511
        elseif occursin(r"^\$.+$", token)
151✔
512
            printstyled_ll(io, token, :funcname)
2✔
513
        elseif occursin(r"^%?(?:[a-z][\w.]+|\"[^\"]+\")$", token)
149✔
514
            islabel = haslabel & !occursin(',', tokens)
188✔
515
            printstyled_ll(io, token, islabel ? :label : isfuncname ? :funcname : :variable)
228✔
516
            isfuncname = false
114✔
517
        else
518
            printstyled_ll(io, token, :default)
35✔
519
        end
520
        print(io, spaces)
205✔
521
    end
448✔
522
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc