Skip to content
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

Add gc use intrinisic #23562

Merged
merged 1 commit into from
Sep 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -438,4 +438,6 @@ show(@nospecialize a) = show(STDOUT, a)
print(@nospecialize a...) = print(STDOUT, a...)
println(@nospecialize a...) = println(STDOUT, a...)

gcuse(@nospecialize a) = ccall(:jl_gc_use, Void, (Any,), a)

ccall(:jl_set_istopmod, Void, (Any, Bool), Core, true)
33 changes: 18 additions & 15 deletions base/strings/string.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ String(s::Symbol) = unsafe_string(Cstring(s))
pointer(s::String) = unsafe_convert(Ptr{UInt8}, s)
pointer(s::String, i::Integer) = pointer(s)+(i-1)

function unsafe_load(s::String, i::Integer=1)
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem like the right name for this function, as we've been deprecating names of this form. It seems like it should be spelled @inbounds codeunit(...) instead, following the example of the array code.

ptr = pointer(s, i)
r = unsafe_load(ptr)
Core.gcuse(s)
r
end

sizeof(s::String) = Core.sizeof(s)

"""
Expand All @@ -73,7 +80,7 @@ codeunit(s::AbstractString, i::Integer)
@boundscheck if (i < 1) | (i > sizeof(s))
throw(BoundsError(s,i))
end
unsafe_load(pointer(s),i)
unsafe_load(s, i)
end

write(io::IO, s::String) = unsafe_write(io, pointer(s), reinterpret(UInt, sizeof(s)))
Expand Down Expand Up @@ -160,26 +167,24 @@ const utf8_trailing = [
## required core functionality ##

function endof(s::String)
p = pointer(s)
i = sizeof(s)
while i > 0 && is_valid_continuation(unsafe_load(p,i))
while i > 0 && is_valid_continuation(unsafe_load(s, i))
i -= 1
end
i
end

function length(s::String)
p = pointer(s)
cnum = 0
for i = 1:sizeof(s)
cnum += !is_valid_continuation(unsafe_load(p,i))
cnum += !is_valid_continuation(unsafe_load(s, i))
end
cnum
end

@noinline function slow_utf8_next(p::Ptr{UInt8}, b::UInt8, i::Int, l::Int)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The noinline can probably be removed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that was there for performance reasons to keep the slow path out of the icache?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, sure. (Not that the current heuristic inlines the big function anyway....)

@noinline function slow_utf8_next(s::String, b::UInt8, i::Int, l::Int)
if is_valid_continuation(b)
throw(UnicodeError(UTF_ERR_INVALID_INDEX, i, unsafe_load(p,i)))
throw(UnicodeError(UTF_ERR_INVALID_INDEX, i, unsafe_load(s, i)))
end
trailing = utf8_trailing[b + 1]
if l < i + trailing
Expand All @@ -188,7 +193,7 @@ end
c::UInt32 = 0
for j = 1:(trailing + 1)
c <<= 6
c += unsafe_load(p,i)
c += unsafe_load(s, i)
i += 1
end
c -= utf8_offset[trailing + 1]
Expand All @@ -206,12 +211,11 @@ done(s::String, state) = state > sizeof(s)
@boundscheck if (i < 1) | (i > sizeof(s))
throw(BoundsError(s,i))
end
p = pointer(s)
b = unsafe_load(p, i)
b = unsafe_load(s, i)
if b < 0x80
return Char(b), i + 1
end
return slow_utf8_next(p, b, i, sizeof(s))
return slow_utf8_next(s, b, i, sizeof(s))
end

function first_utf8_byte(ch::Char)
Expand All @@ -225,8 +229,7 @@ end

function reverseind(s::String, i::Integer)
j = sizeof(s) + 1 - i
p = pointer(s)
while is_valid_continuation(unsafe_load(p,j))
while is_valid_continuation(unsafe_load(s, j))
j -= 1
end
return j
Expand All @@ -235,7 +238,7 @@ end
## overload methods for efficiency ##

isvalid(s::String, i::Integer) =
(1 <= i <= sizeof(s)) && !is_valid_continuation(unsafe_load(pointer(s),i))
(1 <= i <= sizeof(s)) && !is_valid_continuation(unsafe_load(s, i))

function getindex(s::String, r::UnitRange{Int})
isempty(r) && return ""
Expand Down Expand Up @@ -438,7 +441,7 @@ function repeat(s::String, r::Integer)
n = sizeof(s)
out = _string_n(n*r)
if n == 1 # common case: repeating a single ASCII char
ccall(:memset, Ptr{Void}, (Ptr{UInt8}, Cint, Csize_t), out, unsafe_load(pointer(s)), r)
ccall(:memset, Ptr{Void}, (Ptr{UInt8}, Cint, Csize_t), out, unsafe_load(s), r)
else
for i=1:r
unsafe_copy!(pointer(out, 1+(i-1)*n), pointer(s), n)
Expand Down
7 changes: 7 additions & 0 deletions src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1687,6 +1687,13 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs)
emit_signal_fence(ctx);
return ghostValue(jl_void_type);
}
else if (is_libjulia_func(jl_gc_use)) {
assert(lrt == T_void);
assert(!isVa && !llvmcall && nargt == 1);
ctx.builder.CreateCall(prepare_call(gc_use_func), {decay_derived(boxed(ctx, argv[0]))});
JL_GC_POP();
return ghostValue(jl_void_type);
}
else if (_is_libjulia_func((uintptr_t)ptls_getter, "jl_get_ptls_states")) {
assert(lrt == T_pint8);
assert(!isVa && !llvmcall && nargt == 0);
Expand Down
7 changes: 7 additions & 0 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ static GlobalVariable *jlgetworld_global;

// placeholder functions
static Function *gcroot_flush_func;
static Function *gc_use_func;
static Function *except_enter_func;
static Function *pointer_from_objref_func;

Expand Down Expand Up @@ -6489,6 +6490,12 @@ static void init_julia_llvm_env(Module *m)
"julia.gcroot_flush");
add_named_global(gcroot_flush_func, (void*)NULL, /*dllimport*/false);

gc_use_func = Function::Create(FunctionType::get(T_void,
ArrayRef<Type*>(PointerType::get(T_jlvalue, AddressSpace::Derived)), false),
Function::ExternalLinkage,
"julia.gc_use");
add_named_global(gc_use_func, (void*)NULL, /*dllimport*/false);

pointer_from_objref_func = Function::Create(FunctionType::get(T_pjlvalue,
ArrayRef<Type*>(PointerType::get(T_jlvalue, AddressSpace::Derived)), false),
Function::ExternalLinkage,
Expand Down
1 change: 1 addition & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,7 @@ JL_DLLEXPORT jl_value_t *jl_gc_alloc_1w(void);
JL_DLLEXPORT jl_value_t *jl_gc_alloc_2w(void);
JL_DLLEXPORT jl_value_t *jl_gc_alloc_3w(void);
JL_DLLEXPORT jl_value_t *jl_gc_allocobj(size_t sz);
JL_DLLEXPORT void jl_gc_use(jl_value_t *a);

JL_DLLEXPORT void jl_clear_malloc_data(void);

Expand Down
8 changes: 6 additions & 2 deletions src/llvm-late-gc-lowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ struct LateLowerGCFrame: public FunctionPass {
MDNode *tbaa_tag;
Function *ptls_getter;
Function *gc_flush_func;
Function *gc_use_func;
Function *pointer_from_objref_func;
Function *alloc_obj_func;
Function *pool_alloc_func;
Expand Down Expand Up @@ -745,7 +746,8 @@ State LateLowerGCFrame::LocalScan(Function &F) {
}
if (auto callee = CI->getCalledFunction()) {
// Known functions emitted in codegen that are not safepoints
if (callee == pointer_from_objref_func || callee->getName() == "memcmp") {
if (callee == pointer_from_objref_func || callee == gc_use_func ||
callee->getName() == "memcmp") {
continue;
}
}
Expand Down Expand Up @@ -1137,7 +1139,8 @@ bool LateLowerGCFrame::CleanupIR(Function &F) {
}
CallingConv::ID CC = CI->getCallingConv();
auto callee = CI->getCalledValue();
if (gc_flush_func != nullptr && callee == gc_flush_func) {
if ((gc_flush_func != nullptr && callee == gc_flush_func) ||
(gc_use_func != nullptr && callee == gc_use_func)) {
/* No replacement */
} else if (pointer_from_objref_func != nullptr && callee == pointer_from_objref_func) {
auto *ASCI = new AddrSpaceCastInst(CI->getOperand(0),
Expand Down Expand Up @@ -1405,6 +1408,7 @@ static void addRetNoAlias(Function *F)
bool LateLowerGCFrame::doInitialization(Module &M) {
ptls_getter = M.getFunction("jl_get_ptls_states");
gc_flush_func = M.getFunction("julia.gcroot_flush");
gc_use_func = M.getFunction("julia.gc_use");
pointer_from_objref_func = M.getFunction("julia.pointer_from_objref");
auto &ctx = M.getContext();
T_size = M.getDataLayout().getIntPtrType(ctx);
Expand Down
4 changes: 4 additions & 0 deletions src/rtutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,10 @@ JL_DLLEXPORT jl_value_t *jl_value_ptr(jl_value_t *a)
{
return a;
}
JL_DLLEXPORT void jl_gc_use(jl_value_t *a)
{
(void)a;
}

// parsing --------------------------------------------------------------------

Expand Down