-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
juliac: log entrypoints and nonstandard typedefs #59108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
ebb3ded
1099753
e90786b
ce0f007
334f613
612350a
c2dffaf
ff8931c
52878f3
106868a
cb068c2
c0e1c3e
a1b8349
0a744d6
e1d3052
d51511a
76057d4
f5ffa0c
0c38e91
6fd68ec
77b1916
c8a0c0b
af8e042
6161dab
cb503ee
93a0557
d9ea0eb
be561b7
7adc37b
53b84e6
4dfc45b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ | |
/test/results_*.json | ||
/test/results_*.dat | ||
/test/deps | ||
/test/trimming/Manifest.toml | ||
|
||
*.expmap | ||
*.exe | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
const C_friendly_types = Base.IdSet{Any}([ # a few of these are redundant to make it easier to maintain | ||
Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64, Float32, Float64, Bool, | ||
Cvoid, Cint, Cshort, Clong, Cuint, Cushort, Culong, Cssize_t, Csize_t, | ||
Cchar, Cwchar_t, Cstring, Cwstring, | ||
RawFD, | ||
]) | ||
|
||
function recursively_add_types!(types::Base.IdSet{DataType}, @nospecialize(T::DataType)) | ||
T in types && return types | ||
while T.name === Ptr.body.name | ||
push!(types, T) | ||
timholy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
T = T.parameters[1] # unwrap Ptr{...} | ||
T in types && return types | ||
end | ||
if T.name.module === Core && T ∉ C_friendly_types | ||
error("invalid type for juliac: ", T) # exclude internals (they may change) | ||
end | ||
push!(types, T) | ||
for list in (T.parameters, fieldtypes(T)) | ||
for S in list | ||
recursively_add_types!(types, S) | ||
end | ||
end | ||
return types | ||
end | ||
|
||
struct TypeEmitter | ||
io::IO | ||
type_ids::IdDict{Any,Int} | ||
end | ||
|
||
function escape_string_json(s::AbstractString) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIUC there isn't a "meaningful" test of this escaping. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like we have a number of copies of this now running around (test_print_str_escape_json, json_repr). Can we potentially combine them, or at least put them all in a single file to include as needed, so that we can make sure they all use the same logic? |
||
iob = IOBuffer() | ||
print(iob, '"') | ||
for c in s | ||
if c == '"' | ||
print(iob, "\\\"") | ||
elseif c == '\\' | ||
print(iob, "\\\\") | ||
elseif c == '\b' | ||
print(iob, "\\b") | ||
elseif c == '\f' | ||
print(iob, "\\f") | ||
elseif c == '\n' | ||
print(iob, "\\n") | ||
elseif c == '\r' | ||
print(iob, "\\r") | ||
elseif c == '\t' | ||
print(iob, "\\t") | ||
elseif '\x00' <= c <= '\x1f' | ||
print(iob, "\\u", lpad(string(UInt16(c), base=16), 4, '0')) | ||
else | ||
@assert isvalid(c) "invalid unicode character" | ||
print(iob, c) | ||
end | ||
end | ||
print(iob, '"') | ||
return String(take!(iob)) | ||
end | ||
|
||
dequalify(str::AbstractString) = last(split(str, '.')) | ||
|
||
function type_name_json(@nospecialize(dt::DataType)) | ||
return escape_string_json(dequalify(repr(dt))) | ||
end | ||
|
||
function field_name_json(@nospecialize(dt::DataType), field::Int) | ||
name = String(fieldname(dt, field)) | ||
return escape_string_json(name) | ||
end | ||
|
||
function emit_pointer_info!(ctx::TypeEmitter, @nospecialize(dt::DataType); indent::Int = 0) | ||
pointee_type_id = ctx.type_ids[dt.parameters[1]] | ||
let indented_println(args...) = println(ctx.io, " " ^ indent, args...) | ||
indented_println("{") | ||
indented_println(" \"id\": ", ctx.type_ids[dt], ",") | ||
indented_println(" \"kind\": \"pointer\",") | ||
indented_println(" \"name\": ", type_name_json(dt), ",") | ||
indented_println(" \"pointee_type_id\": ", pointee_type_id) | ||
print(ctx.io, " " ^ indent, "}") | ||
end | ||
end | ||
|
||
function emit_field_info!(ctx::TypeEmitter, @nospecialize(dt::DataType), field::Int; indent::Int = 0) | ||
desc = Base.DataTypeFieldDesc(dt)[field] | ||
type_id = ctx.type_ids[fieldtype(dt, field)] | ||
print(ctx.io, " " ^ indent) | ||
print(ctx.io, "{") | ||
print(ctx.io, " \"name\": ", field_name_json(dt, field), ",") | ||
print(ctx.io, " \"type_id\": ", type_id, ",") | ||
print(ctx.io, " \"offset\": ", desc.offset, ",") | ||
print(ctx.io, " \"isptr\": ", desc.isptr, ",") | ||
print(ctx.io, " \"isfieldatomic\": ", Base.isfieldatomic(dt, field)) | ||
print(ctx.io, " }") | ||
timholy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
end | ||
|
||
function emit_struct_info!(ctx::TypeEmitter, @nospecialize(dt::DataType); indent::Int = 0) | ||
type_id = ctx.type_ids[dt] | ||
let indented_println(args...) = println(ctx.io, " " ^ indent, args...) | ||
indented_println("{") | ||
indented_println(" \"id\": ", type_id, ",") | ||
indented_println(ismutabletype(dt) ? " \"kind\": \"mutable struct\"," : " \"kind\": \"struct\",") | ||
indented_println(" \"name\": ", type_name_json(dt), ",") | ||
indented_println(" \"size\": ", Core.sizeof(dt), ",") | ||
indented_println(" \"alignment\": ", Base.datatype_alignment(dt), ",") | ||
indented_println(" \"fields\": [") | ||
for i = 1:Base.datatype_nfields(dt) | ||
emit_field_info!(ctx, dt, i; indent = indent + 4) | ||
println(ctx.io, i == Base.datatype_nfields(dt) ? "" : ",") | ||
end | ||
indented_println(" ]") | ||
print(ctx.io, " " ^ indent, "}") | ||
end | ||
end | ||
|
||
function emit_primitive_type!(ctx::TypeEmitter, @nospecialize(dt::DataType); indent::Int = 0) | ||
type_id = ctx.type_ids[dt] | ||
let indented_println(args...) = println(ctx.io, " " ^ indent, args...) | ||
indented_println("{") | ||
indented_println(" \"id\": ", type_id, ",") | ||
indented_println(" \"kind\": \"primitive\",") | ||
indented_println(" \"name\": ", type_name_json(dt), ",") | ||
indented_println(" \"signed\": ", (dt <: Signed), ",") | ||
indented_println(" \"bits\": ", 8 * Base.packedsize(dt), ",") # size for reinterpret / in-register | ||
indented_println(" \"size\": ", Base.aligned_sizeof(dt), ",") # size with padding / in-memory | ||
indented_println(" \"alignment\": ", Base.datatype_alignment(dt)) | ||
print(ctx.io, " " ^ indent, "}") | ||
end | ||
end | ||
|
||
function emit_type_info!(ctx::TypeEmitter, @nospecialize(dt::DataType); indent::Int = 0) | ||
if dt.name === Ptr.body.name | ||
emit_pointer_info!(ctx, dt; indent) | ||
elseif Base.isprimitivetype(dt) | ||
emit_primitive_type!(ctx, dt; indent) | ||
else | ||
emit_struct_info!(ctx, dt; indent) | ||
end | ||
end | ||
|
||
function emit_method_info!(ctx::TypeEmitter, method::Core.Method; indent::Int = 0) | ||
(rt, sig) = method.ccallable | ||
(name, symbol) = let | ||
symbol = length(method.ccallable) > 2 ? Symbol(method.ccallable[3]) : method.name | ||
iob = IOBuffer() | ||
print(IOContext(iob, :print_method_signature_only => true), method) | ||
str = String(take!(iob)) | ||
if symbol !== method.name && startswith(str, String(method.name)) | ||
# Make a best-effort attempt to use the exported name | ||
# | ||
# Note: the `startswith` check is to make sure we support 'functor's in arg0, | ||
# which Base.@ccallable supports as long as they are singletons. | ||
str = replace(str, String(method.name) => String(symbol); count = 1) | ||
end | ||
(str, String(symbol)) | ||
end | ||
|
||
argnames = String.(Base.method_argnames(method)) | ||
let indented_println(args...) = println(ctx.io, " " ^ indent, args...) | ||
indented_println("{") | ||
indented_println(" \"symbol\": ", escape_string_json(symbol), ",") | ||
indented_println(" \"name\": ", escape_string_json(name), ",") | ||
timholy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
indented_println(" \"arguments\": [") | ||
for i in 2:length(sig.parameters) | ||
print(ctx.io, " " ^ (indent + 4)) | ||
print(ctx.io, "{") | ||
print(ctx.io, " \"name\": ", escape_string_json(argnames[i]), ",") | ||
print(ctx.io, " \"type_id\": ", ctx.type_ids[sig.parameters[i]]) | ||
println(ctx.io, i == length(sig.parameters) ? " }" : " },") | ||
end | ||
indented_println(" ],") | ||
indented_println(" \"returns\": { \"type_id\": ", ctx.type_ids[rt], " }") | ||
print(ctx.io, " " ^ indent, "}") | ||
end | ||
end | ||
|
||
function emit_abi_info!(ctx::TypeEmitter, exported::Vector{Core.Method}, types::IdSet{DataType}) | ||
println(ctx.io, "{") | ||
|
||
# assign an ID to each type, so that we can refer to them | ||
for (i, T) in enumerate(types) | ||
ctx.type_ids[T] = i | ||
end | ||
|
||
# print exported functions | ||
println(ctx.io, " \"functions\": [") | ||
for (i, method) in enumerate(exported) | ||
emit_method_info!(ctx, method; indent = 4) | ||
println(ctx.io, i == length(exported) ? "" : ",") | ||
end | ||
println(ctx.io, " ],") | ||
|
||
# print type / structure information | ||
println(ctx.io, " \"types\": [") | ||
for (i, T) in enumerate(types) | ||
emit_type_info!(ctx, T; indent = 4) | ||
println(ctx.io, i == length(types) ? "" : ",") | ||
end | ||
println(ctx.io, " ]") | ||
|
||
println(ctx.io, "}") | ||
end | ||
|
||
function write_abi_metadata(io::IO) | ||
types = Base.IdSet{DataType}() | ||
|
||
# discover all exported methods + any types they reference | ||
exported = Core.Method[] | ||
Base.visit(Core.methodtable) do method | ||
if isdefined(method, :ccallable) | ||
push!(exported, method) | ||
(rt, sig) = method.ccallable | ||
for T in sig.parameters[2:end] | ||
recursively_add_types!(types, T) | ||
end | ||
recursively_add_types!(types, rt) | ||
end | ||
end | ||
|
||
# print the discovered ABI info | ||
ctx = TypeEmitter(io, IdDict{Any,Int}()) | ||
emit_abi_info!(ctx, exported, types) | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#include <stdio.h> | ||
#include "libsimple.h" | ||
|
||
int main() { | ||
// Example usage of the functions defined in libsimple.h | ||
CVectorPair_Float32 vecPair; | ||
vecPair.from.length = 3; | ||
vecPair.from.data = (float[]){1.0f, 2.0f, 3.0f}; | ||
vecPair.to.length = 3; | ||
vecPair.to.data = (float[]){4.0f, 5.0f, 6.0f}; | ||
|
||
float sum = copyto_and_sum(vecPair); | ||
printf("Sum of copied values: %f\n", sum); | ||
|
||
MyTwoVec list[] = {{1, 2}, {5, 5}, {3, 4}}; | ||
int32_t count = countsame(list, 3); | ||
printf("Count of same vectors: %d\n", count); | ||
|
||
return 0; | ||
} |
Uh oh!
There was an error while loading. Please reload this page.