Skip to content
Draft
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
15 changes: 4 additions & 11 deletions base/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ stackframe_lineinfo_color() = repl_color("JULIA_STACKFRAME_LINEINFO_COLOR", :bol
stackframe_function_color() = repl_color("JULIA_STACKFRAME_FUNCTION_COLOR", :bold)

function repl_cmd(cmd, out)
shell = shell_split(get(ENV, "JULIA_SHELL", get(ENV, "SHELL", "/bin/sh")))
shell_name = Base.basename(shell[1])

# Immediately expand all arguments, so that typing e.g. ~/bin/foo works.
cmd.exec .= expanduser.(cmd.exec)

Expand Down Expand Up @@ -64,19 +61,15 @@ function repl_cmd(cmd, out)
cd(dir)
println(out, pwd())
else
@static if !Sys.iswindows()
if shell_name == "fish"
shell_escape_cmd = "begin; $(shell_escape_posixly(cmd)); and true; end"
else
shell_escape_cmd = "($(shell_escape_posixly(cmd))) && true"
end
if !Sys.iswindows()
shell = shell_split(get(ENV, "JULIA_SHELL", get(ENV, "SHELL", "/bin/sh")))
shell_escape_cmd = shell_escape_posixly(cmd)
cmd = `$shell -c $shell_escape_cmd`
end
try
run(ignorestatus(cmd))
catch
# Windows doesn't shell out right now (complex issue), so Julia tries to run the program itself
# Julia throws an exception if it can't find the program, but the stack trace isn't useful
# Julia throws an exception if it can't find the cmd (which may be the shell itself), but the stack trace isn't useful
lasterr = current_exceptions()
lasterr = ExceptionStack([(exception = e[1], backtrace = [] ) for e in lasterr])
invokelatest(display_error, lasterr)
Expand Down
7 changes: 5 additions & 2 deletions base/sort.jl
Original file line number Diff line number Diff line change
Expand Up @@ -556,12 +556,15 @@ function _sort!(v::UnwrappableSubArray, a::SubArrayOptimization, o::Ordering, kw
@getkw lo hi
# @assert v.stride1 == 1
parent = v.parent
if parent isa Array && !(parent isa Vector) && hi - lo < 100
if parent isa Array && !(parent isa Vector) && hi - lo < 100 || !iszero(v.offset1)
# vec(::Array{T, ≠1}) allocates and is therefore somewhat expensive.
# We don't want that for small inputs.

# Additionally, if offset1 is non-zero, then this optimization is incompatible with
# algorithms that track absolute first and last indices (e.g. ScratchQuickSort)
_sort!(v, a.next, o, kw)
else
_sort!(vec(parent), a.next, o, (;kw..., lo = lo + v.offset1, hi = hi + v.offset1))
_sort!(vec(parent), a.next, o, kw)
end
end

Expand Down
4 changes: 2 additions & 2 deletions base/strings/string.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ An error occurred when trying to access `str` at index `i` that is not valid.
"""
struct StringIndexError <: Exception
string::AbstractString
index::Integer
index::Int
end
@noinline string_index_err(s::AbstractString, i::Integer) =
@noinline string_index_err((@nospecialize s::AbstractString), i::Integer) =
throw(StringIndexError(s, Int(i)))
function Base.showerror(io::IO, exc::StringIndexError)
s = exc.string
Expand Down
24 changes: 5 additions & 19 deletions doc/src/devdocs/eval.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,25 +62,11 @@ The 10,000 foot view of the whole process is as follows:

## [Parsing](@id dev-parsing)

The Julia parser is a small lisp program written in femtolisp, the source-code for which is distributed
inside Julia in [src/flisp](https://github.com/JuliaLang/julia/tree/master/src/flisp).

The interface functions for this are primarily defined in [`jlfrontend.scm`](https://github.com/JuliaLang/julia/blob/master/src/jlfrontend.scm).
The code in [`ast.c`](https://github.com/JuliaLang/julia/blob/master/src/ast.c) handles this handoff
on the Julia side.

The other relevant files at this stage are [`julia-parser.scm`](https://github.com/JuliaLang/julia/blob/master/src/julia-parser.scm),
which handles tokenizing Julia code and turning it into an AST, and [`julia-syntax.scm`](https://github.com/JuliaLang/julia/blob/master/src/julia-syntax.scm),
which handles transforming complex AST representations into simpler, "lowered" AST representations
which are more suitable for analysis and execution.

If you want to test the parser without re-building Julia in its entirety, you can run the frontend
on its own as follows:

$ cd src
$ flisp/flisp
> (load "jlfrontend.scm")
> (jl-parse-file "<filename>")
By default, Julia uses [JuliaSyntax.jl](https://github.com/JuliaLang/JuliaSyntax.jl) to produce the
AST. Historically, it used a small lisp program written in femtolisp, the source-code for which is
distributed inside Julia in [src/flisp](https://github.com/JuliaLang/julia/tree/master/src/flisp).
If the `JULIA_USE_FLISP_PARSER` environment variable is set to `1`, the old parser will be used
instead.

## [Macro Expansion](@id dev-macro-expansion)

Expand Down
8 changes: 5 additions & 3 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ SRCS := \
simplevector runtime_intrinsics precompile jloptions mtarraylist \
threading scheduler stackwalk gc gc-debug gc-pages gc-stacks gc-alloc-profiler gc-page-profiler method \
jlapi signal-handling safepoint timing subtype rtutils gc-heap-snapshot \
crc32c APInt-C processor ircode opaque_closure codegen-stubs coverage runtime_ccall
crc32c APInt-C processor ircode opaque_closure codegen-stubs coverage runtime_ccall \
null_sysimage

RT_LLVMLINK :=
CG_LLVMLINK :=
Expand All @@ -56,7 +57,8 @@ CODEGEN_SRCS := codegen jitlayers aotcompile debuginfo disasm llvm-simdloop llvm
llvm-final-gc-lowering llvm-pass-helpers llvm-late-gc-lowering llvm-ptls \
llvm-lower-handlers llvm-gc-invariant-verifier llvm-propagate-addrspaces \
llvm-multiversioning llvm-alloc-opt llvm-alloc-helpers cgmemmgr llvm-remove-addrspaces \
llvm-remove-ni llvm-julia-licm llvm-demote-float16 llvm-cpufeatures pipeline llvm_api
llvm-remove-ni llvm-julia-licm llvm-demote-float16 llvm-cpufeatures pipeline llvm_api \
null_sysimage
FLAGS += -I$(shell $(LLVM_CONFIG_HOST) --includedir)
CG_LLVM_LIBS := all
ifeq ($(USE_POLLY),1)
Expand Down Expand Up @@ -160,7 +162,7 @@ endif
CLANG_LDFLAGS := $(LLVM_LDFLAGS)
ifeq ($(OS), Darwin)
CLANG_LDFLAGS += -Wl,-undefined,dynamic_lookup
OSLIBS += -Wl,-U,__dyld_atfork_parent -Wl,-U,__dyld_atfork_prepare -Wl,-U,__dyld_dlopen_atfork_parent -Wl,-U,__dyld_dlopen_atfork_prepare -Wl,-U,_jl_image_pointers -Wl,-U,_jl_system_image_data -Wl,-U,_jl_system_image_size
OSLIBS += -Wl,-U,__dyld_atfork_parent -Wl,-U,__dyld_atfork_prepare -Wl,-U,__dyld_dlopen_atfork_parent -Wl,-U,__dyld_dlopen_atfork_prepare
LIBJULIA_PATH_REL := @rpath/libjulia
else
LIBJULIA_PATH_REL := libjulia
Expand Down
11 changes: 8 additions & 3 deletions src/aotcompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1788,9 +1788,14 @@ void jl_dump_native_impl(void *native_code,
auto lock = TSCtx.getLock();
auto dataM = data->M.getModuleUnlocked();

// Delete data when add_output thinks it's done with it
// Saves memory for use when multithreading
data_outputs = compile(*dataM, "text", threads, [data](Module &) { delete data; });
data_outputs = compile(*dataM, "text", threads, [data, &lock, &TSCtx](Module &) {
// Delete data when add_output thinks it's done with it
// Saves memory for use when multithreading
auto lock2 = std::move(lock);
delete data;
// Drop last reference to shared LLVM::Context
auto TSCtx2 = std::move(TSCtx);
});
}

if (params->emit_metadata)
Expand Down
38 changes: 33 additions & 5 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -622,13 +622,13 @@ static Value *emit_struct_gep(jl_codectx_t &ctx, Type *lty, Value *base, unsigne

static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, LLVMContext &ctxt, jl_value_t *jt, bool *isboxed, bool llvmcall=false);

static Type *_julia_type_to_llvm(jl_codegen_params_t *ctx, LLVMContext &ctxt, jl_value_t *jt, bool *isboxed)
static Type *_julia_type_to_llvm(jl_codegen_params_t *ctx, LLVMContext &ctxt, jl_value_t *jt, bool *isboxed, bool no_boxing)
{
// this function converts a Julia Type into the equivalent LLVM type
if (isboxed) *isboxed = false;
if (jt == (jl_value_t*)jl_bottom_type)
return getVoidTy(ctxt);
if (jl_is_concrete_immutable(jt)) {
if (jl_is_concrete_immutable(jt) || no_boxing) {
if (jl_datatype_nbits(jt) == 0)
return getVoidTy(ctxt);
Type *t = _julia_struct_to_llvm(ctx, ctxt, jt, isboxed);
Expand All @@ -641,13 +641,20 @@ static Type *_julia_type_to_llvm(jl_codegen_params_t *ctx, LLVMContext &ctxt, jl

static Type *julia_type_to_llvm(jl_codectx_t &ctx, jl_value_t *jt, bool *isboxed)
{
return _julia_type_to_llvm(&ctx.emission_context, ctx.builder.getContext(), jt, isboxed);
return _julia_type_to_llvm(&ctx.emission_context, ctx.builder.getContext(), jt, isboxed, false);
}

extern "C" JL_DLLEXPORT_CODEGEN
Type *jl_type_to_llvm_impl(jl_value_t *jt, LLVMContextRef ctxt, bool *isboxed)
{
return _julia_type_to_llvm(NULL, *unwrap(ctxt), jt, isboxed);
return _julia_type_to_llvm(NULL, *unwrap(ctxt), jt, isboxed, false);
}


extern "C" JL_DLLEXPORT_CODEGEN
Type *jl_struct_to_llvm_impl(jl_value_t *jt, LLVMContextRef ctxt, bool *isboxed)
{
return _julia_type_to_llvm(NULL, *unwrap(ctxt), jt, isboxed, true);
}


Expand Down Expand Up @@ -1395,10 +1402,30 @@ static void undef_var_error_ifnot(jl_codectx_t &ctx, Value *ok, jl_sym_t *name,
ctx.builder.SetInsertPoint(ifok);
}


static bool has_known_null_nullptr(Type *T)
{
if (auto PT = dyn_cast<PointerType>(T)) {
auto addrspace = PT->getAddressSpace();
if (addrspace == AddressSpace::Generic || (AddressSpace::FirstSpecial <= addrspace && addrspace <= AddressSpace::LastSpecial)) {
return true;
}
}
return false;
}

// ctx.builder.CreateIsNotNull(v) lowers incorrectly in non-standard
// address spaces where null is not zero
// TODO: adapt to https://github.com/llvm/llvm-project/pull/131557 once merged
static Value *null_pointer_cmp(jl_codectx_t &ctx, Value *v)
{
++EmittedNullchecks;
return ctx.builder.CreateIsNotNull(v);
Type *T = v->getType();
if (has_known_null_nullptr(T) || !isa<PointerType>(T)) // i64/i32 are considered pointer like here
return ctx.builder.CreateIsNotNull(v);
else
return ctx.builder.CreateICmpNE(v, ctx.builder.CreateAddrSpaceCast(
Constant::getNullValue(ctx.builder.getPtrTy(0)), T));
}


Expand Down Expand Up @@ -2995,6 +3022,7 @@ static void init_bits_value(jl_codectx_t &ctx, Value *newv, Value *v, MDNode *tb
static void init_bits_cgval(jl_codectx_t &ctx, Value *newv, const jl_cgval_t& v, MDNode *tbaa)
{
// newv should already be tagged
newv = maybe_decay_tracked(ctx, newv);
if (v.ispointer()) {
unsigned align = std::max(julia_alignment(v.typ), (unsigned)sizeof(void*));
emit_memcpy(ctx, newv, jl_aliasinfo_t::fromTBAA(ctx, tbaa), v, jl_datatype_size(v.typ), Align(align), Align(julia_alignment(v.typ)));
Expand Down
2 changes: 2 additions & 0 deletions src/codegen-stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ JL_DLLEXPORT LLVMOrcThreadSafeModuleRef jl_get_llvm_module_fallback(void *native

JL_DLLEXPORT void *jl_type_to_llvm_fallback(jl_value_t *jt, LLVMContextRef llvmctxt, bool_t *isboxed) UNAVAILABLE

JL_DLLEXPORT void *jl_struct_to_llvm_fallback(jl_value_t *jt, LLVMContextRef llvmctxt, bool_t *isboxed) UNAVAILABLE

JL_DLLEXPORT jl_value_t *jl_get_libllvm_fallback(void) JL_NOTSAFEPOINT
{
return jl_nothing;
Expand Down
4 changes: 2 additions & 2 deletions src/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -4170,7 +4170,7 @@ JL_DLLEXPORT void *jl_gc_counted_realloc_with_old_size(void *p, size_t old, size
// but with several fixes to improve the correctness of the computation and remove unnecessary parameters
#define SAVED_PTR(x) ((void *)((DWORD_PTR)((char *)x - sizeof(void *)) & \
~(sizeof(void *) - 1)))
static size_t _aligned_msize(void *p)
static size_t _aligned_msizejl(void *p)
{
void *alloc_ptr = *(void**)SAVED_PTR(p);
return _msize(alloc_ptr) - ((char*)p - (char*)alloc_ptr);
Expand All @@ -4182,7 +4182,7 @@ size_t memory_block_usable_size(void *p, int isaligned) JL_NOTSAFEPOINT
{
#if defined(_OS_WINDOWS_)
if (isaligned)
return _aligned_msize(p);
return _aligned_msizejl(p);
else
return _msize(p);
#elif defined(_OS_DARWIN_)
Expand Down
3 changes: 2 additions & 1 deletion src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -2925,7 +2925,8 @@ STATIC_INLINE jl_value_t *_jl_invoke(jl_value_t *F, jl_value_t **args, uint32_t
// manually inlined copy of jl_method_compiled
jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mfunc->cache);
while (codeinst) {
if (jl_atomic_load_relaxed(&codeinst->min_world) <= world && world <= jl_atomic_load_relaxed(&codeinst->max_world)) {
if (jl_atomic_load_relaxed(&codeinst->min_world) <= world && world <= jl_atomic_load_relaxed(&codeinst->max_world)
&& codeinst->owner == jl_nothing) {
jl_callptr_t invoke = jl_atomic_load_acquire(&codeinst->invoke);
if (invoke != NULL) {
jl_value_t *res = invoke(F, args, nargs, codeinst);
Expand Down
1 change: 1 addition & 0 deletions src/jl_exported_funcs.inc
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,7 @@
YY(jl_dump_llvm_opt) \
YY(jl_dump_fptr_asm) \
YY(jl_get_function_id) \
YY(jl_struct_to_llvm) \
YY(jl_type_to_llvm) \
YY(jl_getUnwindInfo) \
YY(jl_get_libllvm) \
Expand Down
18 changes: 0 additions & 18 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1710,24 +1710,6 @@ jl_sym_t *_jl_symbol(const char *str, size_t len) JL_NOTSAFEPOINT;
#define JL_GC_ASSERT_LIVE(x) (void)(x)
#endif

#ifdef _OS_WINDOWS_
// On Windows, weak symbols do not default to 0 due to a GCC bug
// (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90826), use symbol
// aliases with a known value instead.
#define JL_WEAK_SYMBOL_OR_ALIAS_DEFAULT(sym) __attribute__((weak,alias(#sym)))
#define JL_WEAK_SYMBOL_DEFAULT(sym) &sym
#else
#define JL_WEAK_SYMBOL_OR_ALIAS_DEFAULT(sym) __attribute__((weak))
#define JL_WEAK_SYMBOL_DEFAULT(sym) NULL
#endif

//JL_DLLEXPORT float julia__gnu_h2f_ieee(half param) JL_NOTSAFEPOINT;
//JL_DLLEXPORT half julia__gnu_f2h_ieee(float param) JL_NOTSAFEPOINT;
//JL_DLLEXPORT half julia__truncdfhf2(double param) JL_NOTSAFEPOINT;
//JL_DLLEXPORT float julia__truncsfbf2(float param) JL_NOTSAFEPOINT;
//JL_DLLEXPORT float julia__truncdfbf2(double param) JL_NOTSAFEPOINT;
//JL_DLLEXPORT double julia__extendhfdf2(half n) JL_NOTSAFEPOINT;

JL_DLLEXPORT uint32_t jl_crc32c(uint32_t crc, const char *buf, size_t len);

// -- exports from codegen -- //
Expand Down
3 changes: 3 additions & 0 deletions src/llvm-late-gc-lowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2253,6 +2253,9 @@ Value *LateLowerGCFrame::EmitLoadTag(IRBuilder<> &builder, Type *T_size, Value *
auto &M = *builder.GetInsertBlock()->getModule();
LoadInst *load = builder.CreateAlignedLoad(T_size, addr, M.getDataLayout().getPointerABIAlignment(0), V->getName() + ".tag");
load->setOrdering(AtomicOrdering::Unordered);
// Mark as volatile to prevent optimizers from treating GC tag loads as constants
// since GC mark bits can change during runtime (issue #59547)
load->setVolatile(true);
load->setMetadata(LLVMContext::MD_tbaa, tbaa_tag);
MDBuilder MDB(load->getContext());
auto *NullInt = ConstantInt::get(T_size, 0);
Expand Down
15 changes: 15 additions & 0 deletions src/null_sysimage.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// This file is a part of Julia. License is MIT: https://julialang.org/license

#include <stddef.h>
#include "processor.h"

/**
* These symbols support statically linking the sysimage with libjulia-internal.
*
* Here we provide dummy definitions that are used when these are not linked
* together (the default build configuration). The 0 value of jl_system_image_size
* is used as a sentinel to indicate that the sysimage should be loaded externally.
**/
char jl_system_image_data = 0;
size_t jl_system_image_size = 0;
jl_image_pointers_t jl_image_pointers = { 0 };
11 changes: 3 additions & 8 deletions src/processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -619,11 +619,6 @@ static inline llvm::SmallVector<TargetData<n>, 0> &get_cmdline_targets(F &&featu
return targets;
}

extern "C" {
void *image_pointers_unavailable;
extern void * JL_WEAK_SYMBOL_OR_ALIAS_DEFAULT(image_pointers_unavailable) jl_image_pointers;
}

// Load sysimg, use the `callback` for dispatch and perform all relocations
// for the selected target.
template<typename F>
Expand All @@ -633,10 +628,10 @@ static inline jl_image_t parse_sysimg(void *hdl, F &&callback)
jl_image_t res{};

const jl_image_pointers_t *pointers;
if (hdl == jl_exe_handle && &jl_image_pointers != JL_WEAK_SYMBOL_DEFAULT(image_pointers_unavailable))
pointers = (const jl_image_pointers_t *)&jl_image_pointers;
else
if (jl_system_image_size == 0)
jl_dlsym(hdl, "jl_image_pointers", (void**)&pointers, 1);
else
pointers = &jl_image_pointers; // libjulia-internal and sysimage statically linked

const void *ids = pointers->target_data;
jl_value_t* rejection_reason = nullptr;
Expand Down
12 changes: 12 additions & 0 deletions src/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,18 @@ JL_DLLEXPORT int32_t jl_set_zero_subnormals(int8_t isZero);
JL_DLLEXPORT int32_t jl_get_zero_subnormals(void);
JL_DLLEXPORT int32_t jl_set_default_nans(int8_t isDefault);
JL_DLLEXPORT int32_t jl_get_default_nans(void);

/**
* System image contents.
*
* These symbols are typically dummy values, unless statically linking
* libjulia-* and the sysimage together (see null_sysimage.c), in which
* case they allow accessing the local copy of the sysimage.
**/
extern char jl_system_image_data;
extern size_t jl_system_image_size;
extern jl_image_pointers_t jl_image_pointers;

#ifdef __cplusplus
}

Expand Down
Loading