Документация Engee

Анализ и интроспекция

Страница в процессе перевода.

Julia предоставляет различные возможности анализа во время выполнения.

Привязки модулей

Общедоступные имена для Module доступны посредством функции names(m::Module), которая возвращает массив элементов Symbol, представляющих общедоступные привязки. Функция names(m::Module, all = true) возвращает символы для всех привязок в m независимо от состояния общедоступности.

Поля DataType

Имена полей DataType можно запросить с помощью функции fieldnames. Например, для следующего типа fieldnames(Point) возвращает массив объектов Symbol, представляющих имена полей:

julia> struct Point
           x::Int
           y
       end

julia> fieldnames(Point)
(:x, :y)

Тип каждого поля в объекте Point хранится в поле types самой переменной Point:

julia> Point.types
svec(Int64, Any)

Хотя переменная x помечена как Int, с y в определении типа аннотация снята, поэтому y по умолчанию имеет тип Any.

Сами типы представлены в виде структуры DataType:

julia> typeof(Point)
DataType

Обратите внимание, что функция fieldnames(DataType) возвращает имена каждого поля самой структуры DataType, и одним из этих полей является поле types, показанное в примере выше.

Подтипы

Список непосредственных подтипов любого типа DataType можно получить с помощью функции subtypes. Например, у абстрактного типа DataType AbstractFloat четыре (конкретных) подтипа:

julia> InteractiveUtils.subtypes(AbstractFloat)
5-element Vector{Any}:
 BigFloat
 Core.BFloat16
 Float16
 Float32
 Float64

В этот список также включается любой абстрактный подтип, но не дальнейшие подтипы; для изучения всего дерева типов можно использовать subtypes рекурсивно.

Обратите внимание, что subtypes находится внутри InteractiveUtils, но автоматически экспортируется при использовании REPL.

Структура DataType

Внутреннее представление DataType крайне важно при взаимодействии с кодом на C. Для его анализа доступно несколько функций. isbitstype(T::DataType) возвращает true, если тип T хранится с выравниванием, совместимым с C. fieldoffset(T::DataType, i::Integer) возвращает смещение (в байтах) для поля i относительно начала типа.

Методы функции

Список методов любой универсальной функции можно получить с помощью функции methods. Поиск методов, принимающих определенный тип, в таблице диспетчеризации методов можно выполнить с помощью функции methodswith.

Расширение и понижение

Как говорилось в главе Метапрограммирование, функция macroexpand возвращает интерполированную форму выражения (Expr) без кавычек для данного макроса. Чтобы использовать macroexpand, заключите в кавычки (quote) сам блок выражения (иначе будет вычислен сам макрос и будет передан его результат). Например:

julia> InteractiveUtils.macroexpand(@__MODULE__, :(@edit println("")) )
:(InteractiveUtils.edit(println, (Base.typesof)("")))

Функции Base.Meta.show_sexpr и dump служат для представления выражений в символьной форме и отображения информации о глубоко вложенном содержимом любого выражения.

Наконец, функция Meta.lower возвращает пониженную (lowered) форму любого выражения и особенно полезна для понимания того, как конструкции языка сопоставляются с примитивными операциями, такими как присваивание, ветвление и вызовы:

julia> Meta.lower(@__MODULE__, :( [1+2, sin(0.5)] ))
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope`
1 ─ %1 = 1 + 2
│   %2 = sin(0.5)
│   %3 = Base.vect(%1, %2)
└──      return %3
))))

Промежуточные и скомпилированные представления

Анализ пониженной формы функций требует выбора конкретных методов для отображения, поскольку универсальные функции могут иметь множество методов с различными сигнатурами типов. С этой целью доступно понижение кода для конкретного метода посредством code_lowered, а также вариант с выводом типов посредством code_typed. code_warntype добавляет выделение к выходным данным code_typed.

На уровне, более близком к машинному, промежуточное представление LLVM функции можно вывести с помощью code_llvm, а скомпилированный машинный код доступен посредством code_native (при этом инициируется JIT-компиляция или формирование кода для любых функций, которые не вызывались ранее).

Для удобства существуют версии приведенных выше функций в виде макросов, которые принимают стандартные вызовы функций и автоматически расширяют типы аргументов:

julia> @code_llvm +(1,1)
;  @ int.jl:87 within `+`
; Function Attrs: sspstrong uwtable
define i64 @"julia_+_476"(i64 signext %0, i64 signext %1) #0 {
top:
  %2 = add i64 %1, %0
  ret i64 %2
}

Дополнительные сведения см. в описании @code_lowered, @code_typed, @code_warntype, @code_llvm и @code_native.

Вывод отладочной информации

Упомянутые выше функции и макросы принимают именованный аргумент debuginfo, определяющий уровень выводимой отладочной информации.

julia> InteractiveUtils.@code_typed debuginfo=:source +(1,1)
CodeInfo(
    @ int.jl:87 within `+`
1 ─ %1 = Base.add_int(x, y)::Int64
└──      return %1
) => Int64

Возможные значения debuginfo: :none, :source и :default. По умолчанию отладочная информация не выводится. Чтобы изменить это поведение, задайте Base.IRShow.default_debuginfo[] = :source.