diff --git a/.travis.yml b/.travis.yml index 49360963f6239..428bd6bc38e87 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ notifications: - http://criid.ee.washington.edu:8000/travis-hook - http://julia.mit.edu:8000/travis-hook before_install: - - BUILDOPTS="LLVM_CONFIG=llvm-config-3.3 VERBOSE=1 USE_BLAS64=0"; for lib in LLVM ZLIB SUITESPARSE ARPACK BLAS FFTW LAPACK GMP MPFR PCRE LIBUNWIND READLINE GRISU OPENLIBM RMATH; do export BUILDOPTS="$BUILDOPTS USE_SYSTEM_$lib=1"; done + - BUILDOPTS="LLVM_CONFIG=llvm-config-3.3 LLVM_LLC=llc-3.3 VERBOSE=1 USE_BLAS64=0"; for lib in LLVM ZLIB SUITESPARSE ARPACK BLAS FFTW LAPACK GMP MPFR PCRE LIBUNWIND READLINE GRISU OPENLIBM RMATH; do export BUILDOPTS="$BUILDOPTS USE_SYSTEM_$lib=1"; done - sudo apt-get update -qq -y - sudo apt-get install zlib1g-dev - sudo add-apt-repository ppa:staticfloat/julia-deps -y diff --git a/Make.inc b/Make.inc index 1fae58b4c5a1f..423429f0d594f 100644 --- a/Make.inc +++ b/Make.inc @@ -248,6 +248,9 @@ ifneq ($(ARCH), ppc64) endif endif +ifeq ($(OS),WINNT) +LIBUNWIND= +else ifeq ($(USE_SYSTEM_LIBUNWIND), 1) ifneq ($(OS),Darwin) LIBUNWIND=-lunwind-generic -lunwind @@ -260,11 +263,14 @@ else LIBUNWIND=$(BUILD)/$(JL_LIBDIR)/libunwind-generic.a $(BUILD)/$(JL_LIBDIR)/libunwind.a endif endif +endif ifeq ($(USE_SYSTEM_LLVM), 1) LLVM_CONFIG ?= llvm-config$(EXE) +LLVM_LLC ?= llc$(EXE) else LLVM_CONFIG=$(LLVMROOT)/bin/llvm-config$(EXE) +LLVM_LLC=$(LLVMROOT)/bin/llc$(EXE) endif ifeq ($(USE_SYSTEM_READLINE), 1) diff --git a/Makefile b/Makefile index 7f185aa8b681c..9dd4cfeb1179e 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ $(foreach link,base test doc examples,$(eval $(call symlink_target,$(link),$(BUI debug release: | $(DIRS) $(BUILD)/share/julia/base $(BUILD)/share/julia/test $(BUILD)/share/julia/doc $(BUILD)/share/julia/examples $(BUILD)/etc/julia/juliarc.jl @$(MAKE) $(QUIET_MAKE) julia-$@ @export JL_PRIVATE_LIBDIR=$(JL_PRIVATE_LIBDIR) && \ - $(MAKE) $(QUIET_MAKE) LD_LIBRARY_PATH=$(BUILD)/lib:$(LD_LIBRARY_PATH) JULIA_EXECUTABLE="$(JULIA_EXECUTABLE_$@)" $(BUILD)/$(JL_PRIVATE_LIBDIR)/sys.ji + $(MAKE) $(QUIET_MAKE) LD_LIBRARY_PATH=$(BUILD)/lib:$(LD_LIBRARY_PATH) JULIA_EXECUTABLE="$(JULIA_EXECUTABLE_$@)" $(BUILD)/$(JL_PRIVATE_LIBDIR)/sys.$(SHLIB_EXT) julia-debug-symlink: @ln -sf $(BUILD)/bin/julia-debug-$(DEFAULT_REPL) julia @@ -65,15 +65,24 @@ $(BUILD)/etc/julia/juliarc.jl: etc/juliarc.jl | $(BUILD)/etc/julia @cp $< $@ # use sys.ji if it exists, otherwise run two stages -$(BUILD)/$(JL_PRIVATE_LIBDIR)/sys0.ji: +$(BUILD)/$(JL_PRIVATE_LIBDIR)/sys%ji: $(BUILD)/$(JL_PRIVATE_LIBDIR)/sys%bc + +$(BUILD)/$(JL_PRIVATE_LIBDIR)/sys%o: $(BUILD)/$(JL_PRIVATE_LIBDIR)/sys%bc + $(call spawn,$(LLVM_LLC)) -filetype=obj -relocation-model=pic -o $@ $< + +$(BUILD)/$(JL_PRIVATE_LIBDIR)/sys%$(SHLIB_EXT): $(BUILD)/$(JL_PRIVATE_LIBDIR)/sys%o + $(CXX) -shared -fPIC -L$(BUILD)/$(JL_PRIVATE_LIBDIR) -L$(BUILD)/$(JL_LIBDIR) -o $@ $< \ + $$([ $(OS) = Darwin ] && echo -Wl,-undefined,dynamic_lookup || echo -Wl,--unresolved-symbols,ignore-all ) \ + $$([ $(OS) = WINNT ] && echo -ljulia -lssp) + +$(BUILD)/$(JL_PRIVATE_LIBDIR)/sys0.bc: @$(QUIET_JULIA) cd base && \ - $(call spawn,$(JULIA_EXECUTABLE)) -bf sysimg.jl - mv $(BUILD)/$(JL_PRIVATE_LIBDIR)/sys.ji $(BUILD)/$(JL_PRIVATE_LIBDIR)/sys0.ji + $(call spawn,$(JULIA_EXECUTABLE)) --build $(BUILD)/$(JL_PRIVATE_LIBDIR)/sys0 sysimg.jl -$(BUILD)/$(JL_PRIVATE_LIBDIR)/sys.ji: VERSION base/*.jl base/pkg/*.jl base/linalg/*.jl base/sparse/*.jl $(BUILD)/share/julia/helpdb.jl $(BUILD)/share/man/man1/julia.1 $(BUILD)/$(JL_PRIVATE_LIBDIR)/sys0.ji +$(BUILD)/$(JL_PRIVATE_LIBDIR)/sys.bc: VERSION base/*.jl base/pkg/*.jl base/linalg/*.jl base/sparse/*.jl $(BUILD)/share/julia/helpdb.jl $(BUILD)/share/man/man1/julia.1 $(BUILD)/$(JL_PRIVATE_LIBDIR)/sys0.$(SHLIB_EXT) @$(QUIET_JULIA) cd base && \ - $(call spawn,$(JULIA_EXECUTABLE)) -f \ - `[ -e $(BUILD)/$(JL_PRIVATE_LIBDIR)/sys.ji ] || echo -J"$(BUILD)/$(JL_PRIVATE_LIBDIR)/sys0.ji"` sysimg.jl \ + $(call spawn,$(JULIA_EXECUTABLE)) --build $(BUILD)/$(JL_PRIVATE_LIBDIR)/sys \ + -J$(BUILD)/$(JL_PRIVATE_LIBDIR)/$$([ -e $(BUILD)/$(JL_PRIVATE_LIBDIR)/sys.ji ] && echo sys.ji || echo sys0.ji) -f sysimg.jl \ || (echo "*** This error is usually fixed by running 'make clean'. If the error persists, try 'make cleanall'. ***" && false) run-julia-debug run-julia-release: run-julia-%: @@ -157,16 +166,18 @@ endif PREFIX ?= julia-$(JULIA_COMMIT) install: - @$(MAKE) $(QUIET_MAKE) debug @$(MAKE) $(QUIET_MAKE) release + @$(MAKE) $(QUIET_MAKE) debug @for subdir in "bin" "libexec" $(JL_LIBDIR) $(JL_PRIVATE_LIBDIR) "share/julia" "share/man/man1" "include/julia" "share/julia/site/"$(VERSDIR) "etc/julia" ; do \ mkdir -p $(PREFIX)/$$subdir ; \ done cp -a $(BUILD)/bin/julia* $(PREFIX)/bin/ - -cp -a $(BUILD)/bin/*.dll $(BUILD)/bin/*.bat $(PREFIX)/bin/ - cp -a $(BUILD)/libexec $(PREFIX) + #-cp -a $(BUILD)/bin/llc$(EXE) $(PREFIX)/libexec # this needs libLLVM-3.3.$(SHLIB_EXT) ifneq ($(OS),WINNT) + cp -a $(BUILD)/libexec $(PREFIX) cd $(PREFIX)/bin && ln -sf julia-$(DEFAULT_REPL) julia +else + cp -a $(BUILD)/bin/*.dll $(BUILD)/bin/*.bat $(PREFIX)/bin/ endif for suffix in $(JL_LIBS) ; do \ cp -a $(BUILD)/$(JL_LIBDIR)/lib$${suffix}*.$(SHLIB_EXT)* $(PREFIX)/$(JL_PRIVATE_LIBDIR) ; \ @@ -186,6 +197,7 @@ endif cp -a src/julia.h src/support/*.h $(PREFIX)/include/julia # Copy system image cp $(BUILD)/$(JL_PRIVATE_LIBDIR)/sys.ji $(PREFIX)/$(JL_PRIVATE_LIBDIR) + cp $(BUILD)/$(JL_PRIVATE_LIBDIR)/sys.$(SHLIB_EXT) $(PREFIX)/$(JL_PRIVATE_LIBDIR) # Copy in all .jl sources as well cp -R -L $(BUILD)/share/julia $(PREFIX)/share/ ifeq ($(OS), WINNT) @@ -232,7 +244,6 @@ ifeq ($(OS), WINNT) cp 7z.exe 7z.dll libexpat-1.dll zlib1.dll ../$(PREFIX)/bin && \ mkdir ../$(PREFIX)/Git && \ 7z x PortableGit.7z -o"../$(PREFIX)/Git" ) - cd $(PREFIX)/bin && rm -f llvm* llc.exe lli.exe opt.exe LTO.dll bugpoint.exe macho-dump.exe ./dist-extras/7z a -mx9 -sfx7z.sfx julia-$(JULIA_COMMIT)-$(OS)-$(ARCH).exe julia-$(JULIA_COMMIT) else tar zcvf julia-$(JULIA_COMMIT)-$(OS)-$(ARCH).tar.gz julia-$(JULIA_COMMIT) diff --git a/base/precompile.jl b/base/precompile.jl new file mode 100644 index 0000000000000..69e35f161f0cd --- /dev/null +++ b/base/precompile.jl @@ -0,0 +1,162 @@ +include = include_from_node1 + +# prime method cache with some things we know we'll need right after startup +precompile(pwd, ()) +precompile(fdio, (Int32,)) +precompile(ProcessGroup, (Int, Array{Any,1}, Array{Any,1})) +precompile(next, (Dict{Any,Any}, Int)) +precompile(start, (Dict{Any,Any},)) +precompile(perform_work, ()) +precompile(isempty, (Array{Any,1},)) +precompile(getindex, (Dict{Any,Any}, Int32)) +precompile(event_loop, (Bool,)) +precompile(_start, ()) +precompile(process_options, (Array{Any,1},)) +precompile(run_repl, ()) +precompile(any, (Function, Array{Any,1})) +precompile(Dict{Any,Any}, (Int,)) +precompile(Set, ()) +precompile(setindex!, (Dict{Any,Any}, Bool, Cmd)) +precompile(rehash, (Dict{Any,Any}, Int)) +precompile(wait, (Int32,)) +precompile(systemerror, (Symbol, Bool)) +precompile(SystemError, (ASCIIString,)) +precompile(has, (EnvHash, ASCIIString)) +precompile(parse_input_line, (ASCIIString,)) +precompile(cmp, (Int32, Int32)) +precompile(min, (Int32, Int32)) +precompile(==, (ASCIIString, ASCIIString)) +precompile(arg_gen, (ASCIIString,)) +precompile(Random.librandom_init, ()) +precompile(Random.srand, (ASCIIString, Int)) +precompile(Random.srand, (Uint64,)) +precompile(open, (ASCIIString, Bool, Bool, Bool, Bool)) +precompile(done, (IntSet, Int64)) +precompile(next, (IntSet, Int64)) +precompile(ht_keyindex, (Dict{Any,Any}, Int32)) +precompile(perform_work, (Task,)) +precompile(notify_full, (RemoteValue,)) +precompile(notify_empty, (RemoteValue,)) +precompile(work_result, (RemoteValue,)) +precompile(take, (RemoteValue,)) +precompile(wait_full, (RemoteValue,)) +precompile(enq_work, (Task,)) +precompile(string, (Int,)) +precompile(parseint, (Type{Int}, ASCIIString, Int)) +precompile(repeat, (ASCIIString, Int)) +precompile(KeyError, (Int,)) +precompile(show, (Float64,)) +precompile(match, (Regex, ASCIIString)) +precompile(length, (ASCIIString,)) +precompile(alignment, (Float64,)) +precompile(repl_callback, (Expr, Int)) +precompile(istaskdone, (Task,)) +precompile(int, (Uint64,)) +precompile(copy, (Bool,)) +precompile(bool, (Bool,)) +precompile(bool, (RemoteRef,)) +precompile(wait, (RemoteRef,)) +precompile(hash, (RemoteRef,)) +precompile(take, (RemoteRef,)) +precompile(bitmix, (Int, Int)) +precompile(bitmix, (Uint, Int)) +precompile(bitmix, (Uint64, Int64)) +precompile(hash, (Int,)) +precompile(isequal, (Symbol, Symbol)) +precompile(isequal, (Bool, Bool)) +precompile(get, (EnvHash, ASCIIString, ASCIIString)) +precompile(rr2id, (RemoteRef,)) +precompile(isequal, (RemoteRef, WeakRef)) +precompile(isequal, (RemoteRef, RemoteRef)) +precompile(_ieval, (Symbol,)) +precompile(static_convert, (Nothing, Nothing)) +precompile(setindex!, (Array{Any,1}, WeakRef, Int)) +precompile(isequal, ((Int,Int),(Int,Int))) +precompile(isequal, (Int,Int)) +precompile(RemoteRef, (Int, Int, Int)) +precompile(eval_user_input, (Expr, Bool)) +precompile(print, (Float64,)) +precompile(a2t, (Array{Any,1},)) +precompile(flush, (IOStream,)) +precompile(getindex, (Type{ByteString}, ASCIIString, ASCIIString)) +precompile(bytestring, (ASCIIString,)) +precompile(int, (Int,)) +precompile(uint, (Uint,)) +precompile(_atexit, ()) +precompile(read, (IOStream, Array{Uint32,1})) +precompile(hex, (Char, Int)) +precompile(abs, (Char,)) +precompile(abstract_eval, (LambdaStaticData, ObjectIdDict, StaticVarInfo)) +precompile(length, (Range1{Int},)) +precompile(start, (Range1{Int},)) +precompile(done, (Range1{Int},Int)) +precompile(next, (Range1{Int},Int)) +precompile(IOStream, (ASCIIString, Array{Uint8,1})) +precompile(mk_tupleref, (SymbolNode, Int)) +precompile(abstract_interpret, (Bool, ObjectIdDict, StaticVarInfo)) +precompile(eval_annotate, (LambdaStaticData, ObjectIdDict, StaticVarInfo, ObjectIdDict, Array{Any,1})) +precompile(occurs_more, (Bool, Function, Int)) +precompile(isconstantfunc, (SymbolNode, StaticVarInfo)) +precompile(CallStack, (Expr, Module, (Nothing,), EmptyCallStack)) +precompile(convert, (Type{Module}, Module)) +precompile(effect_free, (Expr,)) +precompile(effect_free, (TopNode,)) +precompile(abspath, (ASCIIString,)) +precompile(isabspath, (ASCIIString,)) +precompile(split, (ASCIIString,)) +precompile(split, (ASCIIString, ASCIIString, Int, Bool)) +precompile(split, (ASCIIString, Regex, Int, Bool)) +precompile(print_joined, (IOBuffer, Array{String,1}, ASCIIString)) +precompile(beginswith, (ASCIIString, ASCIIString)) +precompile(resolve_globals, (Symbol, Module, Module, Vector{Any}, Vector{Any})) +precompile(resolve_globals, (SymbolNode, Module, Module, Vector{Any}, Vector{Any})) +precompile(BitArray, (Int,)) +precompile(getindex, (BitArray{1}, Int,)) +precompile(setindex!, (BitArray{1}, Bool, Int,)) +precompile(fill!, (BitArray{1}, Bool)) +precompile(pop!, (Array{Any,1},)) +precompile(unshift!, (Array{Any,1}, Task)) +precompile(nnz, (BitArray{1},)) +precompile(get_chunks_id, (Int,)) +precompile(occurs_more, (Uint8, Function, Int)) +precompile(abstract_eval_arg, (Uint8, ObjectIdDict, StaticVarInfo)) +precompile(occurs_outside_tupleref, (Function, Symbol, StaticVarInfo, Int)) +precompile(search, (ASCIIString, Regex, Int)) +precompile(setindex!, (Vector{Any}, Uint8, Int)) +precompile(setindex!, (Vector{Any}, Vector{Any}, Int)) +precompile(first, (Range1{Int},)) +precompile(last, (Range1{Int},)) +precompile(isempty, (ASCIIString,)) +precompile(normpath, (ASCIIString,)) +precompile(print, (ASCIIString,)) +precompile(println, (TTY,)) +precompile(print, (TTY,Char)) +precompile(==, (Bool,Bool)) +precompile(try_include, (ASCIIString,)) +precompile(isfile, (ASCIIString,)) +precompile(include_from_node1, (ASCIIString,)) +precompile(source_path, (Nothing,)) +precompile(task_local_storage, ()) +precompile(atexit, (Function,)) +precompile(print, (TTY, ASCIIString)) +precompile(close, (TTY,)) +precompile(read_buffer, (TTY,Int)) +precompile(put, (RemoteRef, Any)) +precompile(getpid, ()) +precompile(print, (IOStream, Int32)) +precompile(show, (IOStream, Int32)) +precompile(open, (ASCIIString, ASCIIString)) +precompile(readline, (ASCIIString,)) +precompile(endof, (Array{Any,1},)) +precompile(sym_replace, (Uint8, Array{Any,1}, Array{Any,1}, Array{Any,1}, Array{Any,1})) +precompile(isslotempty, (Dict{Any,Any}, Int)) +precompile(setindex!, (Array{Uint8,1}, Uint8, Int)) +precompile(get, (Dict{Any,Any}, Symbol, ASCIIString)) +precompile(*, (ASCIIString, ASCIIString, ASCIIString)) +precompile(chop, (ASCIIString,)) +precompile(ismatch, (Regex, ASCIIString)) +precompile(!=, (Bool, Bool)) +precompile(nextind, (ASCIIString, Int)) +precompile(delete_var!, (Expr, Symbol)) +precompile(close, (IOStream,)) +precompile(haskey, (ObjectIdDict, Symbol)) diff --git a/base/stream.jl b/base/stream.jl index d1844d79c273a..03f2432068548 100644 --- a/base/stream.jl +++ b/base/stream.jl @@ -219,6 +219,8 @@ function init_stdio(handle) ret = TcpSocket(handle) elseif t == UV_NAMED_PIPE ret = Pipe(handle) + else + error("FATAL: stdio type invalid") end ret.status = StatusOpen ret.line_buffered = false diff --git a/base/sysimg.jl b/base/sysimg.jl index 825a4da39f181..439ee78136660 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -218,168 +218,7 @@ include("graphics.jl") include("profile.jl") importall .Profile -include = include_from_node1 - -# prime method cache with some things we know we'll need right after startup -precompile(pwd, ()) -precompile(fdio, (Int32,)) -precompile(ProcessGroup, (Int, Array{Any,1}, Array{Any,1})) -precompile(next, (Dict{Any,Any}, Int)) -precompile(start, (Dict{Any,Any},)) -precompile(perform_work, ()) -precompile(isempty, (Array{Any,1},)) -precompile(getindex, (Dict{Any,Any}, Int32)) -precompile(event_loop, (Bool,)) -precompile(_start, ()) -precompile(process_options, (Array{Any,1},)) -precompile(run_repl, ()) -precompile(any, (Function, Array{Any,1})) -precompile(Dict{Any,Any}, (Int,)) -precompile(Set, ()) -precompile(setindex!, (Dict{Any,Any}, Bool, Cmd)) -precompile(rehash, (Dict{Any,Any}, Int)) -precompile(wait, (Int32,)) -precompile(systemerror, (Symbol, Bool)) -precompile(SystemError, (ASCIIString,)) -precompile(has, (EnvHash, ASCIIString)) -precompile(parse_input_line, (ASCIIString,)) -precompile(cmp, (Int32, Int32)) -precompile(min, (Int32, Int32)) -precompile(==, (ASCIIString, ASCIIString)) -precompile(arg_gen, (ASCIIString,)) -precompile(Random.librandom_init, ()) -precompile(Random.srand, (ASCIIString, Int)) -precompile(Random.srand, (Uint64,)) -precompile(open, (ASCIIString, Bool, Bool, Bool, Bool)) -precompile(done, (IntSet, Int64)) -precompile(next, (IntSet, Int64)) -precompile(ht_keyindex, (Dict{Any,Any}, Int32)) -precompile(perform_work, (Task,)) -precompile(notify_full, (RemoteValue,)) -precompile(notify_empty, (RemoteValue,)) -precompile(work_result, (RemoteValue,)) -precompile(take, (RemoteValue,)) -precompile(wait_full, (RemoteValue,)) -precompile(enq_work, (Task,)) -precompile(string, (Int,)) -precompile(parseint, (Type{Int}, ASCIIString, Int)) -precompile(repeat, (ASCIIString, Int)) -precompile(KeyError, (Int,)) -precompile(show, (Float64,)) -precompile(match, (Regex, ASCIIString)) -precompile(length, (ASCIIString,)) -precompile(alignment, (Float64,)) -precompile(repl_callback, (Expr, Int)) -precompile(istaskdone, (Task,)) -precompile(int, (Uint64,)) -precompile(copy, (Bool,)) -precompile(bool, (Bool,)) -precompile(bool, (RemoteRef,)) -precompile(wait, (RemoteRef,)) -precompile(hash, (RemoteRef,)) -precompile(take, (RemoteRef,)) -precompile(bitmix, (Int, Int)) -precompile(bitmix, (Uint, Int)) -precompile(bitmix, (Uint64, Int64)) -precompile(hash, (Int,)) -precompile(isequal, (Symbol, Symbol)) -precompile(isequal, (Bool, Bool)) -precompile(get, (EnvHash, ASCIIString, ASCIIString)) -precompile(rr2id, (RemoteRef,)) -precompile(isequal, (RemoteRef, WeakRef)) -precompile(isequal, (RemoteRef, RemoteRef)) -precompile(_ieval, (Symbol,)) -precompile(static_convert, (Nothing, Nothing)) -precompile(setindex!, (Array{Any,1}, WeakRef, Int)) -precompile(isequal, ((Int,Int),(Int,Int))) -precompile(isequal, (Int,Int)) -precompile(RemoteRef, (Int, Int, Int)) -precompile(eval_user_input, (Expr, Bool)) -precompile(print, (Float64,)) -precompile(a2t, (Array{Any,1},)) -precompile(flush, (IOStream,)) -precompile(getindex, (Type{ByteString}, ASCIIString, ASCIIString)) -precompile(bytestring, (ASCIIString,)) -precompile(int, (Int,)) -precompile(uint, (Uint,)) -precompile(_atexit, ()) -precompile(read, (IOStream, Array{Uint32,1})) -precompile(hex, (Char, Int)) -precompile(abs, (Char,)) -precompile(abstract_eval, (LambdaStaticData, ObjectIdDict, StaticVarInfo)) -precompile(length, (Range1{Int},)) -precompile(start, (Range1{Int},)) -precompile(done, (Range1{Int},Int)) -precompile(next, (Range1{Int},Int)) -precompile(IOStream, (ASCIIString, Array{Uint8,1})) -precompile(mk_tupleref, (SymbolNode, Int)) -precompile(abstract_interpret, (Bool, ObjectIdDict, StaticVarInfo)) -precompile(eval_annotate, (LambdaStaticData, ObjectIdDict, StaticVarInfo, ObjectIdDict, Array{Any,1})) -precompile(occurs_more, (Bool, Function, Int)) -precompile(isconstantfunc, (SymbolNode, StaticVarInfo)) -precompile(CallStack, (Expr, Module, (Nothing,), EmptyCallStack)) -precompile(convert, (Type{Module}, Module)) -precompile(effect_free, (Expr,)) -precompile(effect_free, (TopNode,)) -precompile(abspath, (ASCIIString,)) -precompile(isabspath, (ASCIIString,)) -precompile(split, (ASCIIString,)) -precompile(split, (ASCIIString, ASCIIString, Int, Bool)) -precompile(split, (ASCIIString, Regex, Int, Bool)) -precompile(print_joined, (IOBuffer, Array{String,1}, ASCIIString)) -precompile(beginswith, (ASCIIString, ASCIIString)) -precompile(resolve_globals, (Symbol, Module, Module, Vector{Any}, Vector{Any})) -precompile(resolve_globals, (SymbolNode, Module, Module, Vector{Any}, Vector{Any})) -precompile(BitArray, (Int,)) -precompile(getindex, (BitArray{1}, Int,)) -precompile(setindex!, (BitArray{1}, Bool, Int,)) -precompile(fill!, (BitArray{1}, Bool)) -precompile(pop!, (Array{Any,1},)) -precompile(unshift!, (Array{Any,1}, Task)) -precompile(nnz, (BitArray{1},)) -precompile(get_chunks_id, (Int,)) -precompile(occurs_more, (Uint8, Function, Int)) -precompile(abstract_eval_arg, (Uint8, ObjectIdDict, StaticVarInfo)) -precompile(occurs_outside_tupleref, (Function, Symbol, StaticVarInfo, Int)) -precompile(search, (ASCIIString, Regex, Int)) -precompile(setindex!, (Vector{Any}, Uint8, Int)) -precompile(setindex!, (Vector{Any}, Vector{Any}, Int)) -precompile(first, (Range1{Int},)) -precompile(last, (Range1{Int},)) -precompile(isempty, (ASCIIString,)) -precompile(normpath, (ASCIIString,)) -precompile(print, (ASCIIString,)) -precompile(println, (TTY,)) -precompile(print, (TTY,Char)) -precompile(==, (Bool,Bool)) -precompile(try_include, (ASCIIString,)) -precompile(isfile, (ASCIIString,)) -precompile(include_from_node1, (ASCIIString,)) -precompile(source_path, (Nothing,)) -precompile(task_local_storage, ()) -precompile(atexit, (Function,)) -precompile(print, (TTY, ASCIIString)) -precompile(close, (TTY,)) -precompile(read_buffer, (TTY,Int)) -precompile(put, (RemoteRef, Any)) -precompile(getpid, ()) -precompile(print, (IOStream, Int32)) -precompile(show, (IOStream, Int32)) -precompile(open, (ASCIIString, ASCIIString)) -precompile(readline, (ASCIIString,)) -precompile(endof, (Array{Any,1},)) -precompile(sym_replace, (Uint8, Array{Any,1}, Array{Any,1}, Array{Any,1}, Array{Any,1})) -precompile(isslotempty, (Dict{Any,Any}, Int)) -precompile(setindex!, (Array{Uint8,1}, Uint8, Int)) -precompile(get, (Dict{Any,Any}, Symbol, ASCIIString)) -precompile(*, (ASCIIString, ASCIIString, ASCIIString)) -precompile(chop, (ASCIIString,)) -precompile(ismatch, (Regex, ASCIIString)) -precompile(!=, (Bool, Bool)) -precompile(nextind, (ASCIIString, Int)) -precompile(delete_var!, (Expr, Symbol)) -precompile(close, (IOStream,)) -precompile(haskey, (ObjectIdDict, Symbol)) +include("precompile.jl") # invoke type inference, running the existing inference code on the new # inference code to cache an optimized version of it. @@ -390,11 +229,3 @@ begin end end # baremodule Base - -using Base.get, Base.ENV - -let JL_PRIVATE_LIBDIR = get(ENV, "JL_PRIVATE_LIBDIR", "lib/julia") -# create system image file -ccall(:jl_save_system_image, Void, (Ptr{Uint8},), - "$JULIA_HOME/../$JL_PRIVATE_LIBDIR/sys.ji") -end diff --git a/deps/.gitignore b/deps/.gitignore index 59b4f07235b1e..bd4dca2fbdc1a 100644 --- a/deps/.gitignore +++ b/deps/.gitignore @@ -16,6 +16,7 @@ /libunwind-* /libosxunwind-* /lighttpd-* +/libcxx-* /llvm-* /mpfr-* /openblas-* diff --git a/src/alloc.c b/src/alloc.c index e54c46595cc46..eccfa2dff6239 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -219,7 +219,7 @@ DLLEXPORT jl_value_t *jl_new_struct_uninit(jl_datatype_t *type) return jv; } -jl_tuple_t *jl_tuple(size_t n, ...) +DLLEXPORT jl_tuple_t *jl_tuple(size_t n, ...) { va_list args; if (n == 0) return jl_null; @@ -345,6 +345,8 @@ jl_lambda_info_t *jl_new_lambda_info(jl_value_t *ast, jl_tuple_t *sparams) li->roots = NULL; li->functionObject = NULL; li->cFunctionObject = NULL; + li->functionID = 0; + li->cFunctionID = 0; li->specTypes = NULL; li->inferred = 0; li->inInference = 0; diff --git a/src/builtins.c b/src/builtins.c index a254cfb80e6e3..b816160f7d2f9 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -29,7 +29,7 @@ // exceptions ----------------------------------------------------------------- -void jl_error(const char *str) +DLLEXPORT void jl_error(const char *str) { if (jl_errorexception_type == NULL) { JL_PRINTF(JL_STDERR, "%s", str); diff --git a/src/ccall.cpp b/src/ccall.cpp index 154bc21bd3599..d019401dacf21 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -73,53 +73,111 @@ extern "C" const char *jl_lookup_soname(char *pfx, size_t n) #endif // map from user-specified lib names to handles -static std::map libMap; +static std::map libMap; -extern "C" int add_library_mapping(char *lib, void *hnd) +static uv_lib_t *get_library(char *lib) { - JL_PUTS(const_cast("WARNING: add_library_mapping is deprecated, use push!(DL_LOAD_PATH,\"/path/to/search\") instead.\n"), JL_STDERR); - if (libMap[lib] == NULL && hnd != NULL) { + uv_lib_t *hnd; +#ifdef _OS_WINDOWS_ + if ((intptr_t)lib == 1) + return jl_exe_handle; + if ((intptr_t)lib == 2) + return jl_dl_handle; +#endif + if (lib == NULL) + return jl_RTLD_DEFAULT_handle; + hnd = libMap[lib]; + if (hnd != NULL) + return hnd; + hnd = jl_load_dynamic_library(lib, JL_RTLD_DEFAULT); + if (hnd != NULL) libMap[lib] = hnd; - return 0; - } - else { - return -1; - } + return hnd; } -static void *add_library_sym(char *name, char *lib) +extern "C" DLLEXPORT +void *jl_load_and_lookup(char *f_lib, char *f_name, uv_lib_t **hnd) { - void *hnd; - if (lib == NULL) { - hnd = jl_dl_handle; - } - else { - hnd = libMap[lib]; - if (hnd == NULL) { - hnd = jl_load_dynamic_library(lib, JL_RTLD_DEFAULT); - if (hnd != NULL) - libMap[lib] = hnd; - else - return NULL; - } - } - // add a symbol->address mapping for the JIT - void *sval = jl_dlsym_e((uv_lib_t*)hnd, name); - if (lib != NULL && hnd != jl_dl_handle) { - void *exist = sys::DynamicLibrary::SearchForAddressOfSymbol(name); - if (exist != NULL && exist != sval && - // openlibm conflicts with libm, and lots of our libraries - // (including LLVM) link to libm. fortunately AddSymbol() is - // able to resolve these in favor of openlibm, but this could - // be an issue in the future (TODO). - strcmp(lib,"libopenlibm")) { - ios_printf(ios_stderr, "Warning: Possible conflict in library symbol %s\n", name); - } - sys::DynamicLibrary::AddSymbol(name, sval); - } - return sval; + uv_lib_t *handle = *hnd; + if (!handle) + *hnd = handle = get_library(f_lib); + void *ptr = jl_dlsym_e(handle, f_name); + if (!ptr) + jl_errorf("symbol could not be found %s: %s\n", f_name, uv_dlerror(handle)); + return ptr; } +static std::map libMapGV; +static std::map symMapGV; +static Value *runtime_sym_lookup(PointerType *funcptype, char *f_lib, char *f_name, jl_codectx_t *ctx) +{ + // in pseudo-code, this function emits the following: + // global uv_lib_t **libptrgv + // global void **llvmgv + // if (*llvmgv == NULL) { + // *llvmgv = jl_load_and_lookup(f_lib, f_name, libptrgv); + // } + // return (*llvmgv) + Constant *initnul = ConstantPointerNull::get((PointerType*)T_pint8); + + uv_lib_t *libsym = NULL; + bool runtime_lib = false; + GlobalVariable *libptrgv; +#ifdef _OS_WINDOWS_ + if ((intptr_t)f_lib == 1) + libptrgv = jlexe_var; + else if ((intptr_t)f_lib == 2) + libptrgv = jldll_var; + else +#endif + if (f_lib == NULL) + libptrgv = jlRTLD_DEFAULT_var; + else { + runtime_lib = true; + libptrgv = libMapGV[f_lib]; + if (libptrgv == NULL) { + libptrgv = new GlobalVariable(*jl_Module, T_pint8, + false, GlobalVariable::PrivateLinkage, + initnul, f_lib); + libMapGV[f_lib] = libptrgv; + libsym = get_library(f_lib); + *((uv_lib_t**)jl_ExecutionEngine->getPointerToGlobal(libptrgv)) = libsym; + } + } + if (libsym == NULL) { + libsym = *((uv_lib_t**)jl_ExecutionEngine->getPointerToGlobal(libptrgv)); + } + + GlobalVariable *llvmgv = symMapGV[f_name]; + if (llvmgv == NULL) { + llvmgv = new GlobalVariable(*jl_Module, T_pint8, + false, GlobalVariable::PrivateLinkage, + initnul, f_name); + symMapGV[f_name] = llvmgv; + *((void**)jl_ExecutionEngine->getPointerToGlobal(llvmgv)) = jl_dlsym_e(libsym, f_name); + } + + BasicBlock *dlsym_lookup = BasicBlock::Create(getGlobalContext(), "dlsym"), + *ccall_bb = BasicBlock::Create(getGlobalContext(), "ccall"); + builder.CreateCondBr(builder.CreateICmpNE(builder.CreateLoad(llvmgv), initnul), ccall_bb, dlsym_lookup); + + ctx->f->getBasicBlockList().push_back(dlsym_lookup); + builder.SetInsertPoint(dlsym_lookup); + Value *libname; + if (runtime_lib) { + libname = builder.CreateGlobalStringPtr(f_lib); + } else { + libname = literal_static_pointer_val(f_lib, T_pint8); + } + Value *llvmf = builder.CreateCall3(jldlsym_func, libname, builder.CreateGlobalStringPtr(f_name), libptrgv); + builder.CreateStore(llvmf, llvmgv); + builder.CreateBr(ccall_bb); + + ctx->f->getBasicBlockList().push_back(ccall_bb); + builder.SetInsertPoint(ccall_bb); + llvmf = builder.CreateLoad(llvmgv); + return builder.CreatePointerCast(llvmf,funcptype); +} // --- argument passing and scratch space utilities --- static Function *value_to_pointer_func; @@ -134,12 +192,12 @@ static uint32_t arg_block_n = 0; static Function *save_arg_area_loc_func; static Function *restore_arg_area_loc_func; -static uint64_t save_arg_area_loc() +extern "C" DLLEXPORT uint64_t save_arg_area_loc() { return (((uint64_t)arg_block_n)<<32) | ((uint64_t)arg_area_loc); } -static void restore_arg_area_loc(uint64_t l) +extern "C" DLLEXPORT void restore_arg_area_loc(uint64_t l) { arg_area_loc = l&0xffffffff; uint32_t ab = l>>32; @@ -178,7 +236,7 @@ static void *alloc_temp_arg_copy(void *obj, uint32_t sz) // this is a run-time function // warning: cannot allocate memory except using alloc_temp_arg_space -extern "C" void *jl_value_to_pointer(jl_value_t *jt, jl_value_t *v, int argn, +extern "C" DLLEXPORT void *jl_value_to_pointer(jl_value_t *jt, jl_value_t *v, int argn, int addressof) { jl_value_t *jvt = (jl_value_t*)jl_typeof(v); @@ -374,11 +432,9 @@ static native_sym_arg_t interpret_symbol_arg(jl_value_t *arg, jl_codectx_t *ctx, f_name = jl_string_data(ptr); if (f_name != NULL) { // just symbol, default to JuliaDLHandle -#ifdef _OS_WINDOWS_ - //TODO: store the f_lib name instead of fptr - fptr = jl_dlsym_win32(f_name); -#else // will look in process symbol table +#ifdef _OS_WINDOWS_ + f_lib = jl_dlfind_win32(f_name); #endif } else if (jl_is_cpointer_type(jl_typeof(ptr))) { @@ -453,43 +509,32 @@ static Value *emit_cglobal(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) res = builder.CreateIntToPtr(sym.jl_ptr, lrt); } else if (sym.fptr != NULL) { - res = literal_pointer_val(sym.fptr, lrt); + res = literal_static_pointer_val(sym.fptr, lrt); + JL_PRINTF(JL_STDERR,"warning: literal address used in cglobal for %s; code cannot be statically compiled\n", sym.f_name); } else { - void *symaddr; - if (sym.f_lib != NULL) - symaddr = add_library_sym(sym.f_name, sym.f_lib); - else - symaddr = sys::DynamicLibrary::SearchForAddressOfSymbol(sym.f_name); - if (symaddr == NULL) { - std::stringstream msg; - msg << "cglobal: could not find symbol "; - msg << sym.f_name; - if (sym.f_lib != NULL) { - msg << " in library "; - msg << sym.f_lib; - } - emit_error(msg.str(), ctx); - res = literal_pointer_val(NULL, lrt); + if (imaging_mode) { + res = runtime_sym_lookup((PointerType*)lrt, sym.f_lib, sym.f_name, ctx); } else { - Value *nv = jl_Module->getNamedValue(sym.f_name); - if (nv != NULL) { - // if the symbol already exists, it might be a function or - // something else other than a GlobalVariable, so return - // whatever it is. - res = nv; - if (res->getType() != lrt) { - // if you attempt to access a cglobal multiple times with - // different types, the type of the cached global might be - // wrong. - res = builder.CreateBitCast(res, lrt); + void *symaddr = jl_dlsym_e(get_library(sym.f_lib), sym.f_name); + if (symaddr == NULL) { + std::stringstream msg; + msg << "cglobal: could not find symbol "; + msg << sym.f_name; + if (sym.f_lib != NULL) { +#ifdef _OS_WINDOWS_ + assert((intptr_t)sym.f_lib != 1 && (intptr_t)sym.f_lib != 2); +#endif + msg << " in library "; + msg << sym.f_lib; } + emit_error(msg.str(), ctx); + res = literal_static_pointer_val(NULL, lrt); } - else { - res = jl_Module->getOrInsertGlobal(sym.f_name, - lrt->getContainedType(0)); - } + // since we aren't saving this code, there's no sense in + // putting anything complicated here: just JIT the address of the cglobal + res = literal_static_pointer_val(symaddr, lrt); } } @@ -683,41 +728,6 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) rt); } - // make LLVM function object for the target - Value *llvmf; - FunctionType *functype = FunctionType::get(lrt, fargt_sig, isVa); - - if (jl_ptr != NULL) { - null_pointer_check(jl_ptr,ctx); - Type *funcptype = PointerType::get(functype,0); - llvmf = builder.CreateIntToPtr(jl_ptr, funcptype); - } - else if (fptr != NULL) { - Type *funcptype = PointerType::get(functype,0); - llvmf = literal_pointer_val(fptr, funcptype); - } - else { - void *symaddr; - if (f_lib != NULL) - symaddr = add_library_sym(f_name, f_lib); - else - symaddr = sys::DynamicLibrary::SearchForAddressOfSymbol(f_name); - if (symaddr == NULL) { - JL_GC_POP(); - std::stringstream msg; - msg << "ccall: could not find function "; - msg << f_name; - if (f_lib != NULL) { - msg << " in library "; - msg << f_lib; - } - emit_error(msg.str(), ctx); - return literal_pointer_val(jl_nothing); - } - llvmf = jl_Module->getOrInsertFunction(f_name, functype); - } - - // save place before arguments, for possible insertion of temp arg // area saving code. Value *saveloc=NULL; @@ -733,7 +743,7 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) savespot = &_savespot; } - if (0 && f_name != NULL && f_lib != NULL) { + if (0 && f_name != NULL) { // print the f_name before each ccall Value *zeros[2] = { ConstantInt::get(T_int32, 0), ConstantInt::get(T_int32, 0) }; @@ -741,7 +751,7 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) msg << "ccall: "; msg << f_name; msg << "(...)"; - if (f_lib != NULL) { + if (f_lib != NULL && (intptr_t)f_lib != 1 && (intptr_t)f_lib != 2) { msg << " in library "; msg << f_lib; } @@ -749,7 +759,7 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) builder.CreateCall2(jlputs_func, builder.CreateGEP(stringConst(msg.str()), ArrayRef(zeros)), - literal_pointer_val(JL_STDERR)); + jlstderr_var); } // emit arguments @@ -830,6 +840,54 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) needTempSpace |= mightNeed; needStackRestore |= nSR; } + + + // make LLVM function object for the target + // keep this close to the function call, so that the compiler can + // optimize the global pointer load in the common case + Value *llvmf; + FunctionType *functype = FunctionType::get(lrt, fargt_sig, isVa); + + if (jl_ptr != NULL) { + null_pointer_check(jl_ptr,ctx); + Type *funcptype = PointerType::get(functype,0); + llvmf = builder.CreateIntToPtr(jl_ptr, funcptype); + } + else if (fptr != NULL) { + Type *funcptype = PointerType::get(functype,0); + llvmf = literal_static_pointer_val(fptr, funcptype); + JL_PRINTF(JL_STDERR,"warning: literal address used in ccall for %s; code cannot be statically compiled\n", f_name); + } + else { + assert(f_name != NULL); + + PointerType *funcptype = PointerType::get(functype,0); + if (imaging_mode) { + llvmf = runtime_sym_lookup(funcptype, f_lib, f_name, ctx); + } + else { + void *symaddr = jl_dlsym_e(get_library(f_lib), f_name); + if (symaddr == NULL) { + JL_GC_POP(); + std::stringstream msg; + msg << "ccall: could not find function "; + msg << f_name; + if (f_lib != NULL) { +#ifdef _OS_WINDOWS_ + assert((intptr_t)f_lib != 1 && (intptr_t)f_lib != 2); +#endif + msg << " in library "; + msg << f_lib; + } + emit_error(msg.str(), ctx); + return literal_pointer_val(jl_nothing); + } + // since we aren't saving this code, there's no sense in + // putting anything complicated here: just JIT the function address + llvmf = literal_static_pointer_val(symaddr, funcptype); + } + } + if (needTempSpace) { // save temp argument area stack pointer // TODO: inline this @@ -848,6 +906,7 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) else instList.push_front((Instruction*)stacksave); } + // the actual call Value *ret = builder.CreateCall( llvmf, diff --git a/src/cgutils.cpp b/src/cgutils.cpp index d6d64d7c4dd17..1464b7ccb799d 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -1,7 +1,6 @@ // utility procedures used in code generation // --- string constants --- - static std::map stringConstants; static GlobalVariable *stringConst(const std::string &txt) @@ -17,7 +16,7 @@ static GlobalVariable *stringConst(const std::string &txt) gv = new GlobalVariable(*jl_Module, ArrayType::get(T_int8, txt.length()+1), true, - GlobalVariable::ExternalLinkage, + GlobalVariable::PrivateLinkage, #ifndef LLVM_VERSION_MAJOR ConstantArray::get(getGlobalContext(), txt.c_str()), @@ -37,25 +36,158 @@ static GlobalVariable *stringConst(const std::string &txt) // --- emitting pointers directly into code --- -static Value *literal_pointer_val(void *p, Type *t) +static Value *literal_static_pointer_val(void *p, Type *t) { + // this function will emit a static pointer into the generated code + // the generated code will only be valid during the current session, + // and thus, this should typically be avoided in new API's #if defined(_P64) - return ConstantExpr::getIntToPtr(ConstantInt::get(T_int64, (uint64_t)p), - t); + return ConstantExpr::getIntToPtr(ConstantInt::get(T_int64, (uint64_t)p), t); #else - return ConstantExpr::getIntToPtr(ConstantInt::get(T_int32, (uint32_t)p), - t); + return ConstantExpr::getIntToPtr(ConstantInt::get(T_int32, (uint32_t)p), t); #endif } +typedef struct {Value* gv; int32_t index;} jl_value_llvm; // uses 1-based indexing +static std::map jl_value_to_llvm; +static std::vector jl_sysimg_gvars; + +extern "C" int32_t jl_get_llvm_gv(jl_value_t *p) +{ + // map a jl_value_t memory location to a GlobalVariable + std::map::iterator it; + it = jl_value_to_llvm.find(p); + if (it == jl_value_to_llvm.end()) + return 0; + return it->second.index; +} +static void jl_gen_llvm_gv_array() +{ + // emit the variable table into the code image (can only call this once) + // used just before dumping bitcode + ArrayType *atype = ArrayType::get(T_psize,jl_sysimg_gvars.size()); + new GlobalVariable( + *jl_Module, + atype, + true, + GlobalVariable::ExternalLinkage, + ConstantArray::get(atype, ArrayRef(jl_sysimg_gvars)), + "jl_sysimg_gvars"); +} + +static int32_t jl_assign_functionID(Function *functionObject) { + // give the function an index in the constant lookup table + if (!imaging_mode) + return 0; + jl_sysimg_gvars.push_back(ConstantExpr::getBitCast(functionObject,T_psize)); + return jl_sysimg_gvars.size(); +} + +static Value *julia_gv(const char *cname, void *addr) +{ + // emit a GlobalVariable for a jl_value_t named "cname" + std::map::iterator it; + // first see if there already is a GlobalVariable for this address + it = jl_value_to_llvm.find(addr); + if (it != jl_value_to_llvm.end()) + return builder.CreateLoad(it->second.gv); + // no existing GlobalVariable, create one and store it + GlobalValue *gv = new GlobalVariable(*jl_Module, jl_pvalue_llvmt, + false, GlobalVariable::InternalLinkage, + ConstantPointerNull::get((PointerType*)jl_pvalue_llvmt), cname); + // make the pointer valid for this session + void **p = (void**)jl_ExecutionEngine->getPointerToGlobal(gv); + *p = addr; + // make the pointer valid for future sessions + jl_sysimg_gvars.push_back(ConstantExpr::getBitCast(gv, T_psize)); + jl_value_llvm gv_struct; + gv_struct.gv = gv; + gv_struct.index = jl_sysimg_gvars.size(); + jl_value_to_llvm[addr] = gv_struct; + return builder.CreateLoad(gv); +} + +static Value *julia_gv(const char *prefix, jl_sym_t *name, jl_module_t *mod, void *addr) { + // emit a GlobalVariable for a jl_value_t, using the prefix, name, and module to + // to create a readable name of the form prefixModA.ModB.name + size_t len = strlen(name->name)+strlen(prefix)+1; + jl_module_t *parent = mod, *prev = NULL; + while (parent != NULL && parent != prev) { + len += strlen(parent->name->name)+1; + prev = parent; + parent = parent->parent; + } + char *fullname = (char*)alloca(len); + strcpy(fullname, prefix); + len -= strlen(name->name)+1; + strcpy(fullname+len,name->name); + parent = mod; + prev = NULL; + while (parent != NULL && parent != prev) { + size_t part = strlen(parent->name->name)+1; + strcpy(fullname+len-part,parent->name->name); + fullname[len-1] = '.'; + len -= part; + prev = parent; + parent = parent->parent; + } + return julia_gv(fullname, addr); +} + static Value *literal_pointer_val(jl_value_t *p) { - return literal_pointer_val(p, jl_pvalue_llvmt); + // emit a pointer to any jl_value_t which will be valid across reloading code + // also, try to give it a nice name for gdb, for easy identification + if (p == NULL) + return ConstantPointerNull::get((PointerType*)jl_pvalue_llvmt); + if (!imaging_mode) + return literal_static_pointer_val(p, jl_pvalue_llvmt); + if (jl_is_datatype(p)) { + jl_datatype_t* addr = (jl_datatype_t*)p; + // DataTypes are prefixed with a + + return julia_gv("+", addr->name->name, addr->name->module, p); + } + if (jl_is_func(p)) { + jl_lambda_info_t* linfo = ((jl_function_t*)p)->linfo; + // Functions are prefixed with a - + if (linfo != NULL) + return julia_gv("-", linfo->name, linfo->module, p); + // Anonymous lambdas are prefixed with jl_method# + return julia_gv("jl_method#", p); + } + if (jl_is_lambda_info(p)) { + jl_lambda_info_t* linfo = (jl_lambda_info_t*)p; + // Type-inferred functions are prefixed with a - + return julia_gv("-", linfo->name, linfo->module, p); + } + if (jl_is_symbol(p)) { + jl_sym_t* addr = (jl_sym_t*)p; + // Symbols are prefixed with jl_sym# + return julia_gv("jl_sym#", addr, NULL, p); + } + // something else gets just a generic name + return julia_gv("jl_global#", p); } -static Value *literal_pointer_val(void *p) +static Value *literal_pointer_val(jl_binding_t *p) { - return literal_pointer_val(p, T_pint8); + // emit a pointer to any jl_value_t which will be valid across reloading code + if (p == NULL) + return ConstantPointerNull::get((PointerType*)jl_pvalue_llvmt); + if (!imaging_mode) + return literal_static_pointer_val(p, jl_pvalue_llvmt); + // bindings are prefixed with jl_bnd# + return julia_gv("jl_bnd#", p->name, p->owner, p); +} + +static Value *julia_binding_gv(jl_binding_t *b) { + // emit a literal_pointer_val to the value field of a jl_binding_t + // binding->value are prefixed with * + Value *bv = imaging_mode ? + builder.CreateBitCast(julia_gv("*", b->name, b->owner, b), jl_ppvalue_llvmt) : + literal_static_pointer_val(b,jl_ppvalue_llvmt); + return builder.CreateGEP(bv,ConstantInt::get(T_size, + offsetof(jl_binding_t,value)/sizeof(size_t))); } // --- mapping between julia and llvm types --- diff --git a/src/codegen.cpp b/src/codegen.cpp index 450da700eb0cd..ac18b3fd8dff8 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -26,6 +26,7 @@ #include "llvm/PassManager.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Analysis/Passes.h" +#include "llvm/Bitcode/ReaderWriter.h" #if defined(LLVM_VERSION_MAJOR) && LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 4 #define LLVM34 1 #endif @@ -122,6 +123,9 @@ static DataLayout *jl_data_layout; static TargetData *jl_data_layout; #endif +// for image reloading +static bool imaging_mode = false; + // types static Type *jl_value_llvmt; static Type *jl_pvalue_llvmt; @@ -168,6 +172,12 @@ static GlobalVariable *jldomerr_var; static GlobalVariable *jlovferr_var; static GlobalVariable *jlinexacterr_var; static GlobalVariable *jlboundserr_var; +static GlobalVariable *jlstderr_var; +static GlobalVariable *jlRTLD_DEFAULT_var; +#ifdef _OS_WINDOWS_ +static GlobalVariable *jlexe_var; +static GlobalVariable *jldll_var; +#endif // important functions static Function *jlnew_func; @@ -210,6 +220,7 @@ static Function *box16_func; static Function *box32_func; static Function *box64_func; static Function *jlputs_func; +static Function *jldlsym_func; #ifdef _OS_WINDOWS_ static Function *resetstkoflw_func; #endif @@ -296,9 +307,11 @@ extern "C" void jl_generate_fptr(jl_function_t *f) if (li->cFunctionObject != NULL) (void)jl_ExecutionEngine->getPointerToFunction((Function*)li->cFunctionObject); JL_SIGATOMIC_END(); + if (!imaging_mode) { llvmf->deleteBody(); if (li->cFunctionObject != NULL) ((Function*)li->cFunctionObject)->deleteBody(); + } } f->fptr = li->fptr; } @@ -454,6 +467,24 @@ struct jl_varinfo_t { } }; +// --- helpers for reloading IR image +extern "C" +void jl_set_imaging_mode(int stat) +{ + imaging_mode = !!stat; +} + +static void jl_gen_llvm_gv_array(); + +extern "C" +void jl_dump_bitcode(char* fname) +{ + std::string err; + raw_fd_ostream OS(fname, err); + jl_gen_llvm_gv_array(); + WriteBitcodeToFile(jl_Module, OS); +} + // aggregate of array metadata typedef struct { Value *dataptr; @@ -1464,8 +1495,8 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, #else builder.CreateStore(literal_pointer_val((jl_value_t*)jl_tuple_type), emit_nthptr_addr(tup, (size_t)0)); - builder.CreateStore(literal_pointer_val((jl_value_t*)nargs), - emit_nthptr_addr(tup, (size_t)1)); + builder.CreateStore(ConstantInt::get(T_size, nargs), + builder.CreateBitCast(emit_nthptr_addr(tup, (size_t)1), T_psize)); #endif #ifdef OVERLAP_TUPLE_LEN size_t offs = 1; @@ -1839,7 +1870,7 @@ static Value *global_binding_pointer(jl_module_t *m, jl_sym_t *s, if (assign || b==NULL) b = jl_get_binding_wr(m, s); if (pbnd) *pbnd = b; - return literal_pointer_val(&b->value, jl_ppvalue_llvmt); + return julia_binding_gv(b); } // yields a jl_value_t** giving the binding location of a variable @@ -1978,7 +2009,7 @@ static void emit_assignment(jl_value_t *l, jl_value_t *r, jl_codectx_t *ctx) if (bnd) { rval = boxed(emit_expr(r, ctx, true),ctx); builder.CreateCall2(jlcheckassign_func, - literal_pointer_val((void*)bnd), + literal_pointer_val(bnd), rval); } else { @@ -2111,7 +2142,7 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, jl_binding_t *b = jl_get_binding(mod, var); if (b == NULL) b = jl_get_binding_wr(mod, var); - Value *bp = literal_pointer_val(&b->value, jl_ppvalue_llvmt); + Value *bp = julia_binding_gv(b); if ((b->constp && b->value!=NULL) || (etype!=(jl_value_t*)jl_any_type && !jl_subtype((jl_value_t*)jl_undef_type, etype, 0))) { @@ -2217,7 +2248,7 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, else { if (is_global((jl_sym_t*)mn, ctx)) { bnd = jl_get_binding_for_method_def(ctx->module, (jl_sym_t*)mn); - bp = literal_pointer_val(&bnd->value, jl_ppvalue_llvmt); + bp = julia_binding_gv(bnd); } else { bp = var_binding_pointer((jl_sym_t*)mn, &bnd, false, ctx); @@ -2227,7 +2258,7 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, make_gcroot(a1, ctx); Value *a2 = boxed(emit_expr(args[2], ctx),ctx); make_gcroot(a2, ctx); - Value *mdargs[5] = { name, bp, literal_pointer_val((void*)bnd), a1, a2 }; + Value *mdargs[5] = { name, bp, literal_pointer_val(bnd), a1, a2 }; ctx->argDepth = last_depth; return builder.CreateCall(jlmethod_func, ArrayRef(&mdargs[0], 5)); } @@ -2238,7 +2269,7 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, (void)var_binding_pointer(sym, &bnd, true, ctx); if (bnd) { builder.CreateCall(jldeclareconst_func, - literal_pointer_val((void*)bnd)); + literal_pointer_val(bnd)); } } @@ -2341,8 +2372,7 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, } else { // 0 fields, singleton - return literal_pointer_val - (jl_new_struct_uninit((jl_datatype_t*)ty)); + return literal_pointer_val(jl_new_struct_uninit((jl_datatype_t*)ty)); } } Value *typ = emit_expr(args[0], ctx); @@ -2619,7 +2649,7 @@ static void finalize_gc_frame(jl_codectx_t *ctx) // generate a julia-callable function that calls f (AKA lam) static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, jl_expr_t *ast, Function *f) { - Function *w = Function::Create(jl_func_sig, Function::ExternalLinkage, + Function *w = Function::Create(jl_func_sig, Function::InternalLinkage, f->getName(), jl_Module); Function::arg_iterator AI = w->arg_begin(); AI++; //const Argument &fArg = *AI++; @@ -2843,25 +2873,33 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) } Type *rt = (jlrettype == (jl_value_t*)jl_nothing->type ? T_void : julia_type_to_llvm(jlrettype)); f = Function::Create(FunctionType::get(rt, fsig, false), - Function::ExternalLinkage, funcName, jl_Module); + Function::InternalLinkage, funcName, jl_Module); if (lam->cFunctionObject == NULL) { lam->cFunctionObject = (void*)f; + lam->cFunctionID = jl_assign_functionID(f); } if (lam->functionObject == NULL) { - lam->functionObject = (void*)gen_jlcall_wrapper(lam, ast, f); + Function *fwrap = gen_jlcall_wrapper(lam, ast, f); + lam->functionObject = (void*)fwrap; + lam->functionID = jl_assign_functionID(fwrap); } } else { - f = Function::Create(jl_func_sig, Function::ExternalLinkage, + f = Function::Create(jl_func_sig, Function::InternalLinkage, funcName, jl_Module); if (lam->functionObject == NULL) { lam->functionObject = (void*)f; + lam->functionID = jl_assign_functionID(f); } } //TODO: this seems to cause problems, but should be made to work eventually //if (jlrettype == (jl_value_t*)jl_bottom_type) // f->setDoesNotReturn(); #if defined(_OS_WINDOWS_) && !defined(_CPU_X86_64_) + // tell Win32 to realign the stack to the next 8-byte boundary + // upon entry to any function. This achieves compatibility + // with both MinGW-GCC (which assumes an 8-byte-aligned stack) and + // Windows (which uses a 2-byte-aligned stack) AttrBuilder *attr = new AttrBuilder(); attr->addStackAlignmentAttr(8); #if LLVM32 && !LLVM33 @@ -2950,9 +2988,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) } Value *fArg=NULL, *argArray=NULL, *argCount=NULL; - if (specsig) { - } - else { + if (!specsig) { Function::arg_iterator AI = f->arg_begin(); fArg = AI++; argArray = AI++; @@ -3322,7 +3358,37 @@ static Function *jlfunc_to_llvm(const std::string &cname, void *addr) return f; } -extern "C" jl_value_t *jl_new_box(jl_value_t *v) +extern "C" void jlfptr_to_llvm(void *fptr, jl_lambda_info_t *lam, int specsig) { + // this assigns a function pointer (from loading the system image), to the function object + if (specsig) { + jl_value_t *jlrettype = jl_ast_rettype(lam, (jl_value_t*)lam->ast); + std::vector fsig(0); + for(size_t i=0; i < jl_tuple_len(lam->specTypes); i++) { + Type *ty = julia_type_to_llvm(jl_tupleref(lam->specTypes,i)); + if (ty != T_void) + fsig.push_back(ty); + } + Type *rt = (jlrettype == (jl_value_t*)jl_nothing->type ? T_void : julia_type_to_llvm(jlrettype)); + Function *f = + Function::Create(FunctionType::get(rt, fsig, false), Function::ExternalLinkage, + "jl_julia_fptr", jl_Module); + if (lam->cFunctionObject == NULL) { + lam->cFunctionObject = (void*)f; + lam->cFunctionID = jl_assign_functionID(f); + } + jl_ExecutionEngine->addGlobalMapping(f, (void*)fptr); + } else { + Function *f = jlfunc_to_llvm("jl_julia_fptr", fptr); + if (lam->functionObject == NULL) { + lam->functionObject = (void*)f; + lam->functionID = jl_assign_functionID(f); + assert(lam->fptr == &jl_trampoline); + lam->fptr = (jl_fptr_t)fptr; + } + } +} + +extern "C" DLLEXPORT jl_value_t *jl_new_box(jl_value_t *v) { jl_value_t *box = (jl_value_t*)alloc_2w(); #ifdef OVERLAP_TUPLE_LEN @@ -3336,6 +3402,8 @@ extern "C" jl_value_t *jl_new_box(jl_value_t *v) static void init_julia_llvm_env(Module *m) { + // every variable or function mapped in this function must be + // exported from libjulia, to support static compilation T_int1 = Type::getInt1Ty(getGlobalContext()); T_int8 = Type::getInt8Ty(getGlobalContext()); T_pint8 = PointerType::get(T_int8, 0); @@ -3414,7 +3482,30 @@ static void init_julia_llvm_env(Module *m) (void*)&jl_inexact_exception); jlboundserr_var = global_to_llvm("jl_bounds_exception", (void*)&jl_bounds_exception); + jlstderr_var = + new GlobalVariable(*jl_Module, T_int8, + true, GlobalVariable::ExternalLinkage, + NULL, "jl_uv_stderr"); + jl_ExecutionEngine->addGlobalMapping(jlstderr_var, (void*)&jl_uv_stderr); + jlRTLD_DEFAULT_var = + new GlobalVariable(*jl_Module, T_pint8, + true, GlobalVariable::ExternalLinkage, + NULL, "jl_RTLD_DEFAULT_handle"); + jl_ExecutionEngine->addGlobalMapping(jlRTLD_DEFAULT_var, (void*)&jl_RTLD_DEFAULT_handle); +#ifdef _OS_WINDOWS_ + jlexe_var = + new GlobalVariable(*jl_Module, T_pint8, + true, GlobalVariable::ExternalLinkage, + NULL, "jl_exe_handle"); + jl_ExecutionEngine->addGlobalMapping(jlexe_var, (void*)&jl_exe_handle); + jldll_var = + new GlobalVariable(*jl_Module, T_pint8, + true, GlobalVariable::ExternalLinkage, + NULL, "jl_dl_handle"); + jl_ExecutionEngine->addGlobalMapping(jldll_var, (void*)&jl_dl_handle); +#endif + // Has to be big enough for the biggest LLVM-supported float type jlfloattemp_var = new GlobalVariable(*jl_Module, IntegerType::get(jl_LLVMContext,128), @@ -3461,8 +3552,7 @@ static void init_julia_llvm_env(Module *m) #endif setjmp_func = Function::Create(FunctionType::get(T_int32, args2, false), - Function::ExternalLinkage, "sigsetjmp", jl_Module); - //Intrinsic::getDeclaration(jl_Module, Intrinsic::eh_sjlj_setjmp); + Function::ExternalLinkage, jl_setjmp_name, jl_Module); #if LLVM32 && !LLVM33 setjmp_func->addFnAttr(Attributes::ReturnsTwice); #else @@ -3484,7 +3574,7 @@ static void init_julia_llvm_env(Module *m) (void*)&jl_type_error_rt); std::vector args_2ptrs(0); - args_2ptrs.push_back(T_pint8); + args_2ptrs.push_back(jl_pvalue_llvmt); args_2ptrs.push_back(jl_pvalue_llvmt); jlcheckassign_func = Function::Create(FunctionType::get(T_void, args_2ptrs, false), @@ -3494,7 +3584,7 @@ static void init_julia_llvm_env(Module *m) (void*)&jl_checked_assignment); std::vector args_1ptr(0); - args_1ptr.push_back(T_pint8); + args_1ptr.push_back(jl_pvalue_llvmt); jldeclareconst_func = Function::Create(FunctionType::get(T_void, args_1ptr, false), Function::ExternalLinkage, @@ -3549,7 +3639,7 @@ static void init_julia_llvm_env(Module *m) std::vector mdargs(0); mdargs.push_back(jl_pvalue_llvmt); mdargs.push_back(jl_ppvalue_llvmt); - mdargs.push_back(T_pint8); + mdargs.push_back(jl_pvalue_llvmt); mdargs.push_back(jl_pvalue_llvmt); mdargs.push_back(jl_pvalue_llvmt); jlmethod_func = @@ -3627,6 +3717,16 @@ static void init_julia_llvm_env(Module *m) "jl_puts", jl_Module); jl_ExecutionEngine->addGlobalMapping(jlputs_func, (void*)&jl_puts); + std::vector dlsym_args(0); + dlsym_args.push_back(T_pint8); + dlsym_args.push_back(T_pint8); + dlsym_args.push_back(PointerType::get(T_pint8,0)); + jldlsym_func = + Function::Create(FunctionType::get(T_pint8, dlsym_args, false), + Function::ExternalLinkage, + "jl_load_and_lookup", jl_Module); + jl_ExecutionEngine->addGlobalMapping(jldlsym_func, (void*)&jl_load_and_lookup); + // set up optimization passes FPM = new FunctionPassManager(jl_Module); @@ -3714,9 +3814,13 @@ extern "C" void jl_init_codegen(void) options.NoFramePointerElimNonLeaf = true; #endif #if defined(_OS_WINDOWS_) && !defined(_CPU_X86_64_) + // tell Win32 to assume the stack is always 8-byte aligned, + // and to ensure that it is 8-byte aligned for out-going calls, + // to ensure compatibility with GCC codes options.StackAlignmentOverride = 8; #endif #ifdef __APPLE__ + // turn on JIT support for libunwind to walk the stack options.JITExceptionHandling = 1; #endif // Temporarily disable Haswell BMI2 features due to LLVM bug. @@ -3728,6 +3832,7 @@ extern "C" void jl_init_codegen(void) .setMAttrs(attrvec) .create(); #endif // LLVM VERSION + jl_ExecutionEngine->DisableLazyCompilation(); dbuilder = new DIBuilder(*jl_Module); diff --git a/src/dlload.c b/src/dlload.c index 8ea4c28d9e6a4..08bd8f91b4bce 100644 --- a/src/dlload.c +++ b/src/dlload.c @@ -102,7 +102,7 @@ static uv_lib_t *jl_load_dynamic_library_(char *modname, unsigned flags, int thr error = jl_uv_dlopen(modname,handle,flags); if (!error) goto done; } - else { + else if (jl_base_module != NULL) { jl_array_t* DL_LOAD_PATH = (jl_array_t*)jl_get_global(jl_base_module, jl_symbol("DL_LOAD_PATH")); if (DL_LOAD_PATH != NULL) { size_t j; @@ -161,7 +161,7 @@ uv_lib_t *jl_load_dynamic_library(char *modname, unsigned flags) return jl_load_dynamic_library_(modname, flags, 1); } -DLLEXPORT void *jl_dlsym_e(uv_lib_t *handle, char *symbol) +void *jl_dlsym_e(uv_lib_t *handle, char *symbol) { void *ptr; int error=uv_dlsym(handle, symbol, &ptr); @@ -169,7 +169,7 @@ DLLEXPORT void *jl_dlsym_e(uv_lib_t *handle, char *symbol) return ptr; } -DLLEXPORT void *jl_dlsym(uv_lib_t *handle, char *symbol) +void *jl_dlsym(uv_lib_t *handle, char *symbol) { void *ptr; int error = uv_dlsym(handle, symbol, &ptr); @@ -181,25 +181,29 @@ DLLEXPORT void *jl_dlsym(uv_lib_t *handle, char *symbol) #ifdef _OS_WINDOWS_ //Look for symbols in win32 libraries -void *jl_dlsym_win32(char *f_name) +char *jl_dlfind_win32(char *f_name) { - void *fptr = jl_dlsym_e(jl_exe_handle, f_name); - if (!fptr) { - fptr = jl_dlsym_e(jl_dl_handle, f_name); - if (!fptr) { - fptr = jl_dlsym_e(jl_kernel32_handle, f_name); - if (!fptr) { - fptr = jl_dlsym_e(jl_ntdll_handle, f_name); - if (!fptr) { - fptr = jl_dlsym_e(jl_crtdll_handle, f_name); - if (!fptr) { - fptr = jl_dlsym(jl_winsock_handle, f_name); - } - } - } - } - } - return fptr; + if (jl_dlsym_e(jl_exe_handle, f_name)) + return (char*)1; + if (jl_dlsym_e(jl_dl_handle, f_name)) + return (char*)2; + if (jl_dlsym_e(jl_kernel32_handle, f_name)) + return "kernel32"; + if (jl_dlsym_e(jl_ntdll_handle, f_name)) + return "ntdll"; + if (jl_dlsym_e(jl_crtdll_handle, f_name)) + return "msvcrt"; + if (jl_dlsym(jl_winsock_handle, f_name)) + return "ws2_32"; + // additional common libraries (libc?) could be added here, but in general, + // it is better to specify the library explicitly in the code. This exists + // mainly to ease compatibility with linux, and for libraries that don't + // have a name (julia.exe and libjulia.dll) + // We could also loop over all libraries that have been used so far, but, again, + // explicit is preferred over implicit + return NULL; + // oops, we didn't find it. NULL defaults to searching jl_RTLD_DEFAULT_handle, + // which defaults to jl_dl_handle, where we won't find it, and will throw the + // appropriate error. } - #endif diff --git a/src/dump.c b/src/dump.c index 586de50eff1f6..34ed36157f687 100644 --- a/src/dump.c +++ b/src/dump.c @@ -87,11 +87,161 @@ static void write_as_tag(ios_t *s, uint8_t tag) write_uint8(s, tag); } -// --- serialize --- +// --- Static Compile --- #define jl_serialize_value(s, v) jl_serialize_value_(s,(jl_value_t*)(v)) - static void jl_serialize_value_(ios_t *s, jl_value_t *v); +static jl_value_t *jl_deserialize_value(ios_t *s); + + +static jl_value_t ***sysimg_gvars = NULL; +static void jl_load_sysimg_so(char *fname) +{ + // attempt to load the pre-compiled sysimg at fname + // if this succeeds, sysimg_gvars will be a valid array + // otherwise, it will be NULL + uv_lib_t *sysimg_handle = jl_load_dynamic_library_e(fname, JL_RTLD_DEFAULT); + if (sysimg_handle != 0) { + sysimg_gvars = (jl_value_t***)jl_dlsym(sysimg_handle, "jl_sysimg_gvars"); + } else { + sysimg_gvars = 0; + } +} + +static jl_value_t *jl_deserialize_gv(ios_t *s, jl_value_t *v) +{ + // Restore the GlobalVariable reference to this jl_value_t via the sysimg_gvars table + int32_t gvname_index = read_int32(s)-1; + if (sysimg_gvars != NULL && gvname_index >= 0) { + *sysimg_gvars[gvname_index] = v; + } + return v; +} + +static void jl_serialize_gv(ios_t *s, jl_value_t *v) +{ + // write the index of the literal_pointer_val into the system image + write_int32(s, jl_get_llvm_gv(v)); +} + +static void jl_serialize_globalvals(ios_t *s) +{ + size_t i, len = backref_table.size; + void **p = backref_table.table; + for(i=0; i < len; i+=2) { + void *v = p[i]; + if (v != HT_NOTFOUND) { + void *key = p[i+1]; + if (key != HT_NOTFOUND) { + int32_t gv = jl_get_llvm_gv(v); + if (gv != 0) { + write_int32(s, (int)(intptr_t)key); +#ifdef _P64 + write_int32(s, (int)((intptr_t)key>>32)); +#endif + write_int32(s, gv); + } + } + } + } + write_int32(s, 0); +#ifdef _P64 + write_int32(s, 0); +#endif +} + +static void jl_deserialize_globalvals(ios_t *s) +{ + while (1) { + intptr_t key = read_int32(s); +#ifdef _P64 + key |= ((intptr_t)read_int32(s))<<32; +#endif + if (key == 0) break; + jl_deserialize_gv(s, ptrhash_get(&backref_table, (void*)key)); + } +} + +static void jl_serialize_gv_syms(ios_t *s, jl_sym_t *v) +{ + // ensures all symbols referenced in the code have + // references in the system image to their global variable + // since symbols are static, they might not have had a + // reference anywhere in the code image other than here + void *bp = ptrhash_get(&backref_table, v); + if (bp == HT_NOTFOUND) { + int32_t gv = jl_get_llvm_gv((jl_value_t*)v); + if (gv != 0) { + jl_serialize_value(s, v); + write_int32(s, gv); + } + } + if (v->left) jl_serialize_gv_syms(s, v->left); + if (v->right) jl_serialize_gv_syms(s, v->right); +} + +static void jl_deserialize_gv_syms(ios_t *s) +{ + while (1) { + jl_value_t *v = jl_deserialize_value(s); + if (!v) break; + jl_deserialize_gv(s, v); + } +} + +struct { + jl_lambda_info_t *li; + int32_t func; + int32_t cfunc; +} *delayed_fptrs = NULL; +static size_t delayed_fptrs_n = 0; +static size_t delayed_fptrs_max = 0; + +static void jl_delayed_fptrs(jl_lambda_info_t *li, int32_t func, int32_t cfunc) +{ + // can't restore the fptrs until after the system image is fully restored, + // since it will try to decompress the function AST to determine the argument types + if (cfunc || func) { + if (delayed_fptrs_max < delayed_fptrs_n + 1) { + if (delayed_fptrs_max == 0) + // current measurements put the number of functions at 1130 + delayed_fptrs_max = 2048; + else + delayed_fptrs_max *= 2; + delayed_fptrs = realloc(delayed_fptrs, delayed_fptrs_max*sizeof(delayed_fptrs[0])); //assumes sizeof==alignof + } + delayed_fptrs[delayed_fptrs_n++] = (typeof(delayed_fptrs[0])){.li=li, .func=func, .cfunc=cfunc}; + } +} + +static void jl_update_all_fptrs() +{ + //printf("delayed_fptrs_n: %d\n", delayed_fptrs_n); + jl_value_t ***gvars = sysimg_gvars; + if (gvars == 0) return; + // jlfptr_to_llvm needs to decompress some ast's, therefore this needs to be NULL + // to skip trying to restore GlobalVariable pointers in jl_deserialize_gv + sysimg_gvars = NULL; + size_t i; + for (i = 0; i < delayed_fptrs_n; i++) { + jl_lambda_info_t *li = delayed_fptrs[i].li; + int32_t func = delayed_fptrs[i].func-1; + if (func >= 0) { + jlfptr_to_llvm((jl_fptr_t)gvars[func], li, 0); + } + int32_t cfunc = delayed_fptrs[i].cfunc-1; + if (cfunc >= 0) { + jlfptr_to_llvm((jl_fptr_t)gvars[cfunc], li, 1); + } + } + delayed_fptrs_n = 0; + delayed_fptrs_max = 0; + free(delayed_fptrs); + delayed_fptrs = NULL; +} + + +// --- serialize --- static void jl_serialize_fptr(ios_t *s, void *fptr) { @@ -137,7 +287,7 @@ static void jl_serialize_datatype(ios_t *s, jl_datatype_t *dt) static void jl_serialize_module(ios_t *s, jl_module_t *m) { - // set on every startup; don't save + // set on every startup; don't save value jl_sym_t *jhsym = jl_symbol("JULIA_HOME"); writetag(s, jl_module_type); jl_serialize_value(s, m->name); @@ -145,15 +295,19 @@ static void jl_serialize_module(ios_t *s, jl_module_t *m) size_t i; void **table = m->bindings.table; for(i=1; i < m->bindings.size; i+=2) { - if (table[i] != HT_NOTFOUND && - !(table[i-1] == jhsym && m == jl_core_module)) { + if (table[i] != HT_NOTFOUND) { jl_binding_t *b = (jl_binding_t*)table[i]; - if (!(b->owner != m && m == jl_main_module)) { + if (b->owner == m || m != jl_main_module) { jl_serialize_value(s, b->name); - jl_serialize_value(s, b->value); + if (table[i-1] == jhsym && m == jl_core_module) { + jl_serialize_value(s, NULL); + } else { + jl_serialize_value(s, b->value); + } jl_serialize_value(s, b->type); jl_serialize_value(s, b->owner); write_int8(s, (b->constp<<2) | (b->exportp<<1) | (b->imported)); + jl_serialize_gv(s, (jl_value_t*)b); } } } @@ -345,6 +499,9 @@ static void jl_serialize_value_(ios_t *s, jl_value_t *v) jl_serialize_value(s, (jl_value_t*)li->roots); jl_serialize_value(s, (jl_value_t*)li->def); jl_serialize_value(s, (jl_value_t*)li->capt); + // save functionObject pointers + write_int32(s, li->functionID); + write_int32(s, li->cFunctionID); } else if (jl_typeis(v, jl_module_type)) { jl_serialize_module(s, (jl_module_t*)v); @@ -359,45 +516,45 @@ static void jl_serialize_value_(ios_t *s, jl_value_t *v) *(int64_t*)data >= S32_MIN && *(int64_t*)data <= S32_MAX) { writetag(s, (jl_value_t*)SmallInt64_tag); write_int32(s, (int32_t)*(int64_t*)data); - return; } - if (t == jl_int32_type) { + else if (t == jl_int32_type) { writetag(s, (jl_value_t*)Int32_tag); write_int32(s, (int32_t)*(int32_t*)data); - return; } - if ((jl_value_t*)t == jl_idtable_type) - writetag(s, (jl_value_t*)IdTable_tag); - else - writetag(s, (jl_value_t*)jl_datatype_type); - jl_serialize_value(s, t); - size_t nf = jl_tuple_len(t->names); - if (nf == 0 && jl_datatype_size(t)>0) { - if (t->name == jl_pointer_type->name) { - write_int32(s, 0); + else { + if ((jl_value_t*)t == jl_idtable_type) + writetag(s, (jl_value_t*)IdTable_tag); + else + writetag(s, (jl_value_t*)jl_datatype_type); + jl_serialize_value(s, t); + size_t nf = jl_tuple_len(t->names); + if (nf == 0 && jl_datatype_size(t)>0) { + if (t->name == jl_pointer_type->name) { + write_int32(s, 0); #ifdef _P64 - write_int32(s, 0); + write_int32(s, 0); #endif + } + else { + ios_write(s, data, jl_datatype_size(t)); + } } else { - ios_write(s, data, jl_datatype_size(t)); - } - } - else { - if ((jl_value_t*)t == jl_idtable_type) { - jl_array_t *data = (jl_array_t*)jl_get_nth_field(v, 0); - jl_value_t **d = (jl_value_t**)data->data; - for(size_t i=0; i < jl_array_len(data); i+=2) { - if (d[i+1] != NULL) { - jl_serialize_value(s, d[i+1]); - jl_serialize_value(s, d[i]); + if ((jl_value_t*)t == jl_idtable_type) { + jl_array_t *data = (jl_array_t*)jl_get_nth_field(v, 0); + jl_value_t **d = (jl_value_t**)data->data; + for(size_t i=0; i < jl_array_len(data); i+=2) { + if (d[i+1] != NULL) { + jl_serialize_value(s, d[i+1]); + jl_serialize_value(s, d[i]); + } } + jl_serialize_value(s, NULL); } - jl_serialize_value(s, NULL); - } - else { - for(size_t i=0; i < nf; i++) { - jl_serialize_value(s, jl_get_nth_field(v, i)); + else { + for(size_t i=0; i < nf; i++) { + jl_serialize_value(s, jl_get_nth_field(v, i)); + } } } } @@ -406,8 +563,6 @@ static void jl_serialize_value_(ios_t *s, jl_value_t *v) // --- deserialize --- -static jl_value_t *jl_deserialize_value(ios_t *s); - static jl_fptr_t jl_deserialize_fptr(ios_t *s) { int fptr = read_uint16(s); @@ -475,11 +630,14 @@ static jl_value_t *jl_deserialize_datatype(ios_t *s, int pos) // parametric types here. jl_cell_1d_push(datatype_list, (jl_value_t*)dt); } + return (jl_value_t*)dt; } jl_array_t *jl_eqtable_put(jl_array_t *h, void *key, void *val); +static jl_value_t *jl_deserialize_value_(ios_t *s, int pos, jl_value_t *vtag); + static jl_value_t *jl_deserialize_value(ios_t *s) { int pos = ios_pos(s); @@ -504,7 +662,12 @@ static jl_value_t *jl_deserialize_value(ios_t *s) if (tag >= VALUE_TAGS) { return vtag; } - + else if (vtag == (jl_value_t*)LiteralVal_tag) { + return jl_cellref(tree_literal_values, read_uint16(s)); + } + return jl_deserialize_value_(s, pos, vtag); +} +static jl_value_t *jl_deserialize_value_(ios_t *s, int pos, jl_value_t *vtag) { int usetable = (tree_literal_values == NULL); size_t i; @@ -532,10 +695,10 @@ static jl_value_t *jl_deserialize_value(ios_t *s) char *name = alloca(len+1); ios_read(s, name, len); name[len] = '\0'; - jl_value_t *s = (jl_value_t*)jl_symbol(name); + jl_value_t *sym = (jl_value_t*)jl_symbol(name); if (usetable) - ptrhash_put(&backref_table, (void*)(ptrint_t)pos, s); - return s; + ptrhash_put(&backref_table, (void*)(ptrint_t)pos, sym); + return sym; } else if (vtag == (jl_value_t*)jl_array_type || vtag == (jl_value_t*)Array1d_tag) { @@ -587,9 +750,6 @@ static jl_value_t *jl_deserialize_value(ios_t *s) } return (jl_value_t*)e; } - else if (vtag == (jl_value_t*)LiteralVal_tag) { - return jl_cellref(tree_literal_values, read_uint16(s)); - } else if (vtag == (jl_value_t*)jl_tvar_type) { jl_tvar_t *tv = (jl_tvar_t*)newobj((jl_value_t*)jl_tvar_type, 4); if (usetable) @@ -629,13 +789,18 @@ static jl_value_t *jl_deserialize_value(ios_t *s) li->roots = (jl_array_t*)jl_deserialize_value(s); li->def = (jl_lambda_info_t*)jl_deserialize_value(s); li->capt = jl_deserialize_value(s); - li->fptr = &jl_trampoline; li->functionObject = NULL; li->cFunctionObject = NULL; li->inInference = 0; li->inCompile = 0; li->unspecialized = NULL; + li->functionID = 0; + li->cFunctionID = 0; + int32_t cfunc_llvm, func_llvm; + func_llvm = read_int32(s); + cfunc_llvm = read_int32(s); + jl_delayed_fptrs(li, func_llvm, cfunc_llvm); return (jl_value_t*)li; } else if (vtag == (jl_value_t*)jl_module_type) { @@ -645,10 +810,10 @@ static jl_value_t *jl_deserialize_value(ios_t *s) ptrhash_put(&backref_table, (void*)(ptrint_t)pos, m); m->parent = (jl_module_t*)jl_deserialize_value(s); while (1) { - jl_value_t *name = jl_deserialize_value(s); + jl_sym_t *name = (jl_sym_t*)jl_deserialize_value(s); if (name == NULL) break; - jl_binding_t *b = jl_get_binding_wr(m, (jl_sym_t*)name); + jl_binding_t *b = jl_get_binding_wr(m, name); b->value = jl_deserialize_value(s); b->type = (jl_value_t*)jl_deserialize_value(s); b->owner = (jl_module_t*)jl_deserialize_value(s); @@ -656,6 +821,7 @@ static jl_value_t *jl_deserialize_value(ios_t *s) b->constp = (flags>>2) & 1; b->exportp = (flags>>1) & 1; b->imported = (flags) & 1; + jl_deserialize_gv(s, (jl_value_t*)b); } size_t ni = read_int32(s); for(size_t i=0; i < ni; i++) { @@ -772,6 +938,19 @@ void jl_save_system_image(char *fname) jl_serialize_value(&f, jl_main_module); + // deser_tag is an array indexed from 2 until HT_NOTFOUND + // ensure everything in there can be reassociated with it's GlobalValue + ptrint_t i=2; + void *v = ptrhash_get(&deser_tag, (void*)i); + while (v != HT_NOTFOUND) { + jl_serialize_gv(&f, (jl_value_t*)v); + v = ptrhash_get(&deser_tag, (void*)i); + i += 1; + } + jl_serialize_globalvals(&f); + jl_serialize_gv_syms(&f, jl_get_root_symbol()); // serialize symbols with GlobalValue references + jl_serialize_value(&f, NULL); // signal the end of the symbols list + write_int32(&f, jl_get_t_uid_ctr()); write_int32(&f, jl_get_gs_ctr()); htable_reset(&backref_table, 0); @@ -787,7 +966,7 @@ extern void jl_get_system_hooks(void); extern void jl_get_uv_hooks(void); DLLEXPORT -void jl_restore_system_image(char *fname) +void jl_restore_system_image(char *fname, int build_mode) { ios_t f; char *fpath = fname; @@ -795,6 +974,18 @@ void jl_restore_system_image(char *fname) JL_PRINTF(JL_STDERR, "System image file \"%s\" not found\n", fname); exit(1); } +#ifdef _OS_WINDOWS_ + //XXX: the windows linker forces our system image to be + // linked against only one dll, I picked libjulia-release + if (jl_is_debugbuild()) build_mode = 1; +#endif + if (!build_mode) { + char *fname_shlib = alloca(strlen(fname)); + strcpy(fname_shlib, fname); + char *fname_shlib_dot = strrchr(fname_shlib, '.'); + if (fname_shlib_dot != NULL) *fname_shlib_dot = 0; + jl_load_sysimg_so(fname_shlib); + } #ifdef JL_GC_MARKSWEEP int en = jl_gc_is_enabled(); jl_gc_disable(); @@ -811,6 +1002,18 @@ void jl_restore_system_image(char *fname) jl_symbol("Base")); jl_current_module = jl_base_module; // run start_image in Base + // deser_tag is an array indexed from 2 until HT_NOTFOUND + // ensure everything in there is reassociated with it's GlobalValue + ptrint_t i=2; + void *v = ptrhash_get(&deser_tag, (void*)i); + while (v != HT_NOTFOUND) { + jl_deserialize_gv(&f, (jl_value_t*)v); + v = ptrhash_get(&deser_tag, (void*)i); + i += 1; + } + jl_deserialize_globalvals(&f); + jl_deserialize_gv_syms(&f); + // cache builtin parametric types for(int i=0; i < jl_array_len(datatype_list); i++) { jl_value_t *v = jl_cellref(datatype_list, i); @@ -837,6 +1040,10 @@ void jl_restore_system_image(char *fname) #ifdef JL_GC_MARKSWEEP if (en) jl_gc_enable(); #endif + // restore the value of our "magic" JULIA_HOME variable/constant + jl_get_binding_wr(jl_core_module, jl_symbol("JULIA_HOME"))->value = + jl_cstr_to_string(julia_home); + jl_update_all_fptrs(); } DLLEXPORT diff --git a/src/gc.c b/src/gc.c index 33c9f3123d344..39b093fee0ee0 100644 --- a/src/gc.c +++ b/src/gc.c @@ -988,7 +988,7 @@ void *allocb(size_t sz) return (void*)((void**)b + 1); } -void *allocobj(size_t sz) +DLLEXPORT void *allocobj(size_t sz) { #ifdef MEMDEBUG return alloc_big(sz); @@ -998,7 +998,7 @@ void *allocobj(size_t sz) return pool_alloc(&pools[szclass(sz)]); } -void *alloc_2w(void) +DLLEXPORT void *alloc_2w(void) { #ifdef MEMDEBUG return alloc_big(2*sizeof(void*)); @@ -1010,7 +1010,7 @@ void *alloc_2w(void) #endif } -void *alloc_3w(void) +DLLEXPORT void *alloc_3w(void) { #ifdef MEMDEBUG return alloc_big(3*sizeof(void*)); @@ -1022,7 +1022,7 @@ void *alloc_3w(void) #endif } -void *alloc_4w(void) +DLLEXPORT void *alloc_4w(void) { #ifdef MEMDEBUG return alloc_big(4*sizeof(void*)); diff --git a/src/init.c b/src/init.c index 1c2bde29e83e3..d315f64d82f4f 100644 --- a/src/init.c +++ b/src/init.c @@ -344,6 +344,8 @@ DLLEXPORT void uv_atexit_hook() // able to show stuff (incl. printf's) jl_uv_exitcleanup_add((uv_handle_t*)jl_uv_stdout, &queue); jl_uv_exitcleanup_add((uv_handle_t*)jl_uv_stderr, &queue); + //uv_unref((uv_handle_t*)jl_uv_stdout); + //uv_unref((uv_handle_t*)jl_uv_stderr); struct uv_shutdown_queue_item *item = queue.first; while (item) { JL_TRY { @@ -398,6 +400,8 @@ DLLEXPORT void uv_atexit_hook() void jl_get_builtin_hooks(void); uv_lib_t *jl_dl_handle; +uv_lib_t _jl_RTLD_DEFAULT_handle; +uv_lib_t *jl_RTLD_DEFAULT_handle=&_jl_RTLD_DEFAULT_handle; #ifdef _OS_WINDOWS_ uv_lib_t _jl_ntdll_handle; uv_lib_t _jl_exe_handle; @@ -598,11 +602,18 @@ DLLEXPORT kern_return_t catch_exception_raise #endif -void julia_init(char *imageFile) +void julia_init(char *imageFile, int build_mode) { + if (build_mode) + jl_set_imaging_mode(1); jl_page_size = jl_getpagesize(); jl_find_stack_bottom(); jl_dl_handle = jl_load_dynamic_library(NULL, JL_RTLD_DEFAULT); +#ifdef RTLD_DEFAULT + jl_RTLD_DEFAULT_handle->handle = RTLD_DEFAULT; +#else + jl_RTLD_DEFAULT_handle->handle = jl_dl_handle->handle; +#endif #ifdef _OS_WINDOWS_ uv_dlopen("ntdll.dll",jl_ntdll_handle); //bypass julia's pathchecking for system dlls uv_dlopen("kernel32.dll",jl_kernel32_handle); @@ -643,7 +654,7 @@ void julia_init(char *imageFile) jl_init_frontend(); jl_init_types(); jl_init_tasks(jl_stack_lo, jl_stack_hi-jl_stack_lo); - jl_init_codegen(); + jl_init_codegen(imageFile); jl_an_empty_cell = (jl_value_t*)jl_alloc_cell_1d(0); jl_init_serializer(); @@ -663,11 +674,16 @@ void julia_init(char *imageFile) jl_get_builtin_hooks(); jl_boot_file_loaded = 1; jl_init_box_caches(); + // Core.JULIA_HOME is a "magic" constant, we set it at runtime here + // since it's value gets excluded from the system image + jl_set_const(jl_core_module, jl_symbol("JULIA_HOME"), + jl_cstr_to_string(julia_home)); + jl_module_export(jl_core_module, jl_symbol("JULIA_HOME")); } if (imageFile) { JL_TRY { - jl_restore_system_image(imageFile); + jl_restore_system_image(imageFile, build_mode); } JL_CATCH { JL_PRINTF(JL_STDERR, "error during init:\n"); @@ -790,10 +806,10 @@ DLLEXPORT void jl_install_sigint_handler() //printf("sigint installed\n"); } - +extern int asprintf(char **str, const char *fmt, ...); extern void * __stack_chk_guard; -DLLEXPORT int julia_trampoline(int argc, char **argv, int (*pmain)(int ac,char *av[])) +DLLEXPORT int julia_trampoline(int argc, char **argv, int (*pmain)(int ac,char *av[]), char *build_path) { #if defined(_OS_WINDOWS_) //&& !defined(_WIN64) SetUnhandledExceptionFilter(exception_handler); @@ -814,6 +830,22 @@ DLLEXPORT int julia_trampoline(int argc, char **argv, int (*pmain)(int ac,char * } #endif int ret = pmain(argc, argv); + if (build_path) { + char *build_ji; + if (asprintf(&build_ji, "%s.ji",build_path) > 0) { + jl_save_system_image(build_ji); + free(build_ji); + char *build_bc; + if (asprintf(&build_bc, "%s.bc",build_path) > 0) { + jl_dump_bitcode(build_bc); + free(build_bc); + } else { + ios_printf(ios_stderr,"FATAL: failed to create string for .bc build path"); + } + } else { + ios_printf(ios_stderr,"FATAL: failed to create string for .ji build path"); + } + } p[sizeof(__stack_chk_guard)-1] = a; p[sizeof(__stack_chk_guard)-2] = b; p[0] = c; diff --git a/src/jl_uv.c b/src/jl_uv.c index 995ebb9e9ed22..6f0358f0db867 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -467,6 +467,7 @@ DLLEXPORT int jl_fs_close(int handle) //units are in ms DLLEXPORT int jl_puts(char *str, uv_stream_t *stream) { + if (!stream) return 0; return jl_write(stream,str,strlen(str)); } diff --git a/src/jlapi.c b/src/jlapi.c index f5925e76328ce..66ee594942f46 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -16,9 +16,8 @@ char * __cdecl basename(char *); #include #endif #include "julia.h" -extern char *julia_home; -DLLEXPORT char *jl_locate_sysimg(char *jlhome) +DLLEXPORT char *jl_locate_sysimg(char *jlhome, char* imgpath) { if (jlhome == NULL) { char *julia_path = (char*)malloc(512); @@ -32,7 +31,7 @@ DLLEXPORT char *jl_locate_sysimg(char *jlhome) } char path[512]; snprintf(path, sizeof(path), "%s%s%s", - julia_home, PATHSEPSTRING, JL_SYSTEM_IMAGE_PATH); + julia_home, PATHSEPSTRING, imgpath); return strdup(path); } @@ -44,8 +43,8 @@ DLLEXPORT void *jl_eval_string(char *str); DLLEXPORT void jl_init(char *julia_home_dir) { libsupport_init(); - char *image_file = jl_locate_sysimg(julia_home_dir); - julia_init(image_file); + char *image_file = jl_locate_sysimg(julia_home_dir, JL_SYSTEM_IMAGE_PATH); + julia_init(image_file, 0); jl_set_const(jl_core_module, jl_symbol("JULIA_HOME"), jl_cstr_to_string(julia_home)); jl_module_export(jl_core_module, jl_symbol("JULIA_HOME")); diff --git a/src/julia.expmap b/src/julia.expmap index 208f821899e8e..9724203ca2c9c 100644 --- a/src/julia.expmap +++ b/src/julia.expmap @@ -1,5 +1,7 @@ { global: + alloc_*w; + allocobj; asprintf; bitvector_any1; bitvector_count; @@ -54,6 +56,7 @@ jl_alloc_tuple; jl_cell_1d_push; jl_cell_1d_push2; + jl_checked_assignment; jl_apply_generic; jl_array_del_beg; jl_array_del_end; @@ -71,14 +74,10 @@ jl_base_module; jl_boundp; jl_breakpoint; + jl_declare_constant; jl_defines_or_exports_p; - jl_box_int32; - jl_box_int64; - jl_unbox_int32; - jl_unbox_int64; - jl_unbox_float32; - jl_unbox_float64; - jl_unbox_voidpointer; + jl_box_*; + jl_unbox_*; jl_callback; jl_clear_input; jl_close_uv; @@ -100,7 +99,9 @@ jl_dlsym; jl_dlsym_e; jl_dump_function; + jl_f_*; jl_function_ptr; + jl_egal; jl_enable_color; jl_enable_inference; jl_enq_send_req; @@ -111,6 +112,7 @@ jl_eqtable_put; jl_eqtable_pop; jl_errno; + jl_error; jl_errorexception_type; jl_exception_in_transit; jl_exit; @@ -120,6 +122,8 @@ jl_eval_string; jl_exception_occurred; jl_exception_clear; + jl_tuple; + jl_type_error_rt; jl_typeof_str; jl_typename_str; jl_array_eltype; @@ -167,6 +171,9 @@ jl_getutf8; jl_global_event_loop; jl_hrtime; + jl_idle_init; + jl_idle_start; + jl_idle_stop; jl_init_frontend; jl_init_pipe; jl_install_sigint_handler; @@ -184,6 +191,7 @@ jl_listen; jl_load_; jl_load; + jl_load_and_lookup; jl_load_dynamic_library; jl_load_dynamic_library_e; jl_load_file_string; @@ -197,8 +205,10 @@ jl_make_async; jl_make_pipe; jl_make_tcp; + jl_make_timer; jl_matching_methods; jl_match_method; + jl_method_def; jl_mmap; jl_module_export; jl_module_names; @@ -208,6 +218,7 @@ jl_module_usings; jl_native_alignment; jl_next_from_addrinfo; + jl_new_box; jl_is_char_signed; jl_nb_available; jl_new_array; @@ -228,6 +239,7 @@ jl_pchar_to_string; jl_pgcstack; jl_prepare_ast; + jl_ast_rettype; jl_print_int64; jl_print_symbol; jl_printf; @@ -250,6 +262,7 @@ jl_read_buffer; jl_readdir; jl_readuntil; + jl_RTLD_DEFAULT_handle; jl_throw; jl_rethrow; jl_rethrow_other; @@ -294,6 +307,8 @@ jl_tcp6_connect; jl_spawn; jl_stackovf_exception; + jl_start_io_thread; + jl_start_reading; jl_stat; jl_stat_blksize; jl_stat_blocks; @@ -332,6 +347,7 @@ jl_tcp_init; jl_test; jl_poll_start; + jl_pop_handler; jl_fs_poll_start; jl_fs_event_init; jl_fs_unlink; @@ -354,6 +370,7 @@ jl_write; jl_write_no_copy; jl_value_ptr; + jl_value_to_pointer; jl_zero_subnormals; julia_free; julia_home; @@ -369,8 +386,10 @@ open_any_tcp_port; repl_callback_enable; jl_init_repl; + restore_arg_area_loc; restore_signals; rl_clear_input; + save_arg_area_loc; jl_SC_CLK_TCK; jl_getpagesize; u8_isvalid; @@ -381,6 +400,16 @@ uv_*; add_library_mapping; + jl_stackovf_exception; + jl_memory_exception; + jl_diverror_exception; + jl_domain_exception; + jl_overflow_exception; + jl_inexact_exception; + jl_undefref_exception; + jl_interrupt_exception; + jl_bounds_exception; + /* freebsd */ environ; __progname; diff --git a/src/julia.h b/src/julia.h index 565be928a93cc..8d8c0e6aad016 100644 --- a/src/julia.h +++ b/src/julia.h @@ -183,6 +183,8 @@ typedef struct _jl_lambda_info_t { jl_fptr_t fptr; // jlcall entry point void *functionObject; // jlcall llvm Function void *cFunctionObject; // c callable llvm Function + int32_t functionID; // index that this function will have in the codegen table + int32_t cFunctionID; // index that this cFunction will have in the codegen table } jl_lambda_info_t; #define LAMBDA_INFO_NW (NWORDS(sizeof(jl_lambda_info_t))-1) @@ -369,17 +371,17 @@ extern DLLEXPORT jl_datatype_t *jl_ascii_string_type; extern DLLEXPORT jl_datatype_t *jl_utf8_string_type; extern DLLEXPORT jl_datatype_t *jl_errorexception_type; extern DLLEXPORT jl_datatype_t *jl_loaderror_type; -extern jl_datatype_t *jl_typeerror_type; -extern jl_datatype_t *jl_methoderror_type; -extern jl_value_t *jl_stackovf_exception; -extern jl_value_t *jl_memory_exception; -extern jl_value_t *jl_diverror_exception; -extern jl_value_t *jl_domain_exception; -extern jl_value_t *jl_overflow_exception; -extern jl_value_t *jl_inexact_exception; -extern jl_value_t *jl_undefref_exception; -extern jl_value_t *jl_interrupt_exception; -extern jl_value_t *jl_bounds_exception; +extern DLLEXPORT jl_datatype_t *jl_typeerror_type; +extern DLLEXPORT jl_datatype_t *jl_methoderror_type; +extern DLLEXPORT jl_value_t *jl_stackovf_exception; +extern DLLEXPORT jl_value_t *jl_memory_exception; +extern DLLEXPORT jl_value_t *jl_diverror_exception; +extern DLLEXPORT jl_value_t *jl_domain_exception; +extern DLLEXPORT jl_value_t *jl_overflow_exception; +extern DLLEXPORT jl_value_t *jl_inexact_exception; +extern DLLEXPORT jl_value_t *jl_undefref_exception; +extern DLLEXPORT jl_value_t *jl_interrupt_exception; +extern DLLEXPORT jl_value_t *jl_bounds_exception; extern jl_value_t *jl_an_empty_cell; extern jl_datatype_t *jl_box_type; @@ -429,10 +431,12 @@ extern jl_function_t *jl_unprotect_stack_func; extern jl_function_t *jl_bottom_func; extern uv_lib_t *jl_dl_handle; +DLLEXPORT extern uv_lib_t *jl_RTLD_DEFAULT_handle; #if defined(_OS_WINDOWS_) +DLLEXPORT extern uv_lib_t *jl_dl_handle; +DLLEXPORT extern uv_lib_t *jl_exe_handle; extern uv_lib_t *jl_ntdll_handle; -extern uv_lib_t *jl_exe_handle; extern uv_lib_t *jl_kernel32_handle; extern uv_lib_t *jl_crtdll_handle; extern uv_lib_t *jl_winsock_handle; @@ -704,7 +708,7 @@ DLLEXPORT jl_value_t *jl_new_struct_uninit(jl_datatype_t *type); DLLEXPORT jl_function_t *jl_new_closure(jl_fptr_t proc, jl_value_t *env, jl_lambda_info_t *li); DLLEXPORT jl_lambda_info_t *jl_new_lambda_info(jl_value_t *ast, jl_tuple_t *sparams); -jl_tuple_t *jl_tuple(size_t n, ...); +DLLEXPORT jl_tuple_t *jl_tuple(size_t n, ...); jl_tuple_t *jl_tuple1(void *a); jl_tuple_t *jl_tuple2(void *a, void *b); DLLEXPORT jl_tuple_t *jl_alloc_tuple(size_t n); @@ -724,23 +728,23 @@ void jl_add_method(jl_function_t *gf, jl_tuple_t *types, jl_function_t *meth, jl_tuple_t *tvars); jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_t *bnd, jl_tuple_t *argtypes, jl_function_t *f); -jl_value_t *jl_box_bool(int8_t x); -jl_value_t *jl_box_int8(int32_t x); -jl_value_t *jl_box_uint8(uint32_t x); -jl_value_t *jl_box_int16(int16_t x); -jl_value_t *jl_box_uint16(uint16_t x); +DLLEXPORT jl_value_t *jl_box_bool(int8_t x); +DLLEXPORT jl_value_t *jl_box_int8(int32_t x); +DLLEXPORT jl_value_t *jl_box_uint8(uint32_t x); +DLLEXPORT jl_value_t *jl_box_int16(int16_t x); +DLLEXPORT jl_value_t *jl_box_uint16(uint16_t x); DLLEXPORT jl_value_t *jl_box_int32(int32_t x); -jl_value_t *jl_box_uint32(uint32_t x); -jl_value_t *jl_box_char(uint32_t x); +DLLEXPORT jl_value_t *jl_box_uint32(uint32_t x); +DLLEXPORT jl_value_t *jl_box_char(uint32_t x); DLLEXPORT jl_value_t *jl_box_int64(int64_t x); -jl_value_t *jl_box_uint64(uint64_t x); -jl_value_t *jl_box_float32(float x); -jl_value_t *jl_box_float64(double x); -jl_value_t *jl_box_voidpointer(void *x); -jl_value_t *jl_box8 (jl_datatype_t *t, int8_t x); -jl_value_t *jl_box16(jl_datatype_t *t, int16_t x); -jl_value_t *jl_box32(jl_datatype_t *t, int32_t x); -jl_value_t *jl_box64(jl_datatype_t *t, int64_t x); +DLLEXPORT jl_value_t *jl_box_uint64(uint64_t x); +DLLEXPORT jl_value_t *jl_box_float32(float x); +DLLEXPORT jl_value_t *jl_box_float64(double x); +DLLEXPORT jl_value_t *jl_box_voidpointer(void *x); +DLLEXPORT jl_value_t *jl_box8 (jl_datatype_t *t, int8_t x); +DLLEXPORT jl_value_t *jl_box16(jl_datatype_t *t, int16_t x); +DLLEXPORT jl_value_t *jl_box32(jl_datatype_t *t, int32_t x); +DLLEXPORT jl_value_t *jl_box64(jl_datatype_t *t, int64_t x); DLLEXPORT int8_t jl_unbox_bool(jl_value_t *v); DLLEXPORT int8_t jl_unbox_int8(jl_value_t *v); DLLEXPORT uint8_t jl_unbox_uint8(jl_value_t *v); @@ -866,30 +870,33 @@ DLLEXPORT struct tm* localtime_r(const time_t *t, struct tm *tm); #endif // exceptions -void NORETURN jl_error(const char *str); +DLLEXPORT void NORETURN jl_error(const char *str); void NORETURN jl_errorf(const char *fmt, ...); void jl_too_few_args(const char *fname, int min); void jl_too_many_args(const char *fname, int max); void jl_type_error(const char *fname, jl_value_t *expected, jl_value_t *got); -void jl_type_error_rt(const char *fname, const char *context, +DLLEXPORT void jl_type_error_rt(const char *fname, const char *context, jl_value_t *ty, jl_value_t *got); jl_value_t *jl_no_method_error(jl_function_t *f, jl_value_t **args, size_t na); void jl_check_type_tuple(jl_tuple_t *t, jl_sym_t *name, const char *ctx); // initialization functions -DLLEXPORT void julia_init(char *imageFile); -DLLEXPORT int julia_trampoline(int argc, char *argv[], int (*pmain)(int ac,char *av[])); +DLLEXPORT void julia_init(char *imageFile, int build_mode); +DLLEXPORT int julia_trampoline(int argc, char *argv[], int (*pmain)(int ac,char *av[]), char* build_mode); void jl_init_types(void); void jl_init_box_caches(void); DLLEXPORT void jl_init_frontend(void); void jl_init_primitives(void); -void jl_init_codegen(void); +void jl_init_codegen(); void jl_init_intrinsic_functions(void); void jl_init_tasks(void *stack, size_t ssize); void jl_init_serializer(void); -DLLEXPORT void jl_save_system_image(char *fname); -DLLEXPORT void jl_restore_system_image(char *fname); +void jl_save_system_image(char *fname); +void jl_restore_system_image(char *fname, int build_mode); +void jl_dump_bitcode(char *fname); +void jl_set_imaging_mode(int stat); +int32_t jl_get_llvm_gv(jl_value_t *p); // front end interface DLLEXPORT jl_value_t *jl_parse_input_line(const char *str); @@ -929,8 +936,8 @@ DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var); DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m, jl_sym_t *var); DLLEXPORT void jl_set_global(jl_module_t *m, jl_sym_t *var, jl_value_t *val); DLLEXPORT void jl_set_const(jl_module_t *m, jl_sym_t *var, jl_value_t *val); -void jl_checked_assignment(jl_binding_t *b, jl_value_t *rhs); -void jl_declare_constant(jl_binding_t *b); +DLLEXPORT void jl_checked_assignment(jl_binding_t *b, jl_value_t *rhs); +DLLEXPORT void jl_declare_constant(jl_binding_t *b); void jl_module_using(jl_module_t *to, jl_module_t *from); void jl_module_use(jl_module_t *to, jl_module_t *from, jl_sym_t *s); void jl_module_import(jl_module_t *to, jl_module_t *from, jl_sym_t *s); @@ -957,7 +964,7 @@ DLLEXPORT void *jl_dlsym_e(uv_lib_t *handle, char *symbol); DLLEXPORT void *jl_dlsym(uv_lib_t *handle, char *symbol); DLLEXPORT uv_lib_t *jl_wrap_raw_dl_handle(void *handle); void *jl_dlsym_e(uv_lib_t *handle, char *symbol); //supress errors -void *jl_dlsym_win32(char *name); +char *jl_dlfind_win32(char *name); DLLEXPORT int add_library_mapping(char *lib, void *hnd); // event loop @@ -991,6 +998,7 @@ jl_function_t *jl_method_lookup_by_type(jl_methtable_t *mt, jl_tuple_t *types, jl_function_t *jl_method_lookup(jl_methtable_t *mt, jl_value_t **args, size_t nargs, int cache); jl_value_t *jl_gf_invoke(jl_function_t *gf, jl_tuple_t *types, jl_value_t **args, size_t nargs); +void jlfptr_to_llvm(void *fptr, jl_lambda_info_t *lam, int specsig); // AST access jl_array_t *jl_lam_args(jl_expr_t *l); @@ -1032,7 +1040,7 @@ STATIC_INLINE int jl_vinfo_sa(jl_array_t *vi) // for writing julia functions in C #define JL_CALLABLE(name) \ - jl_value_t *name(jl_value_t *F, jl_value_t **args, uint32_t nargs) + DLLEXPORT jl_value_t *name(jl_value_t *F, jl_value_t **args, uint32_t nargs) STATIC_INLINE jl_value_t *jl_apply(jl_function_t *f, jl_value_t **args, uint32_t nargs) @@ -1231,6 +1239,7 @@ DLLEXPORT void jl_free2(void *p, void *hint); DLLEXPORT int jl_cpu_cores(void); DLLEXPORT long jl_getpagesize(void); +DLLEXPORT int jl_is_debugbuild(void); typedef struct { uv_loop_t *loop; @@ -1270,6 +1279,8 @@ DLLEXPORT JL_STREAM *jl_stdout_stream(); DLLEXPORT JL_STREAM *jl_stdin_stream(); DLLEXPORT JL_STREAM *jl_stderr_stream(); +extern char *julia_home; + STATIC_INLINE void jl_eh_restore_state(jl_handler_t *eh) { JL_SIGATOMIC_BEGIN(); @@ -1287,20 +1298,22 @@ DLLEXPORT void jl_pop_handler(int n); #if defined(_COMPILER_MINGW_) int __attribute__ ((__nothrow__,__returns_twice__)) jl_setjmp(jmp_buf _Buf); __declspec(noreturn) __attribute__ ((__nothrow__)) void jl_longjmp(jmp_buf _Buf,int _Value); +#else +int jl_setjmp(jmp_buf _Buf); +void jl_longjmp(jmp_buf _Buf,int _Value); +#endif #define jl_setjmp_f jl_setjmp +#define jl_setjmp_name "jl_setjmp" #define jl_setjmp(a,b) jl_setjmp(a) #define jl_longjmp(a,b) jl_longjmp(a,b) #else -#define jl_setjmp_f setjmp -#define jl_setjmp(a,b) setjmp(a) -#define jl_longjmp(a,b) longjmp(a,b) -#endif -#else // determine actual entry point name #if defined(sigsetjmp) #define jl_setjmp_f __sigsetjmp +#define jl_setjmp_name "__sigsetjmp" #else #define jl_setjmp_f sigsetjmp +#define jl_setjmp_name "sigsetjmp" #endif #define jl_setjmp(a,b) sigsetjmp(a,b) #define jl_longjmp(a,b) siglongjmp(a,b) diff --git a/src/module.c b/src/module.c index e6622d7fcde10..720bb1740b1a9 100644 --- a/src/module.c +++ b/src/module.c @@ -347,7 +347,7 @@ DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var) return b && b->constp; } -void jl_checked_assignment(jl_binding_t *b, jl_value_t *rhs) +DLLEXPORT void jl_checked_assignment(jl_binding_t *b, jl_value_t *rhs) { if (b->constp && b->value != NULL) { if (!jl_egal(rhs, b->value) && @@ -360,7 +360,7 @@ void jl_checked_assignment(jl_binding_t *b, jl_value_t *rhs) b->value = rhs; } -void jl_declare_constant(jl_binding_t *b) +DLLEXPORT void jl_declare_constant(jl_binding_t *b) { if (b->value != NULL && !b->constp) { jl_errorf("cannot declare %s constant; it already has a value", diff --git a/src/toplevel.c b/src/toplevel.c index e81d59b9ea1f4..4b80c0f75043e 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -476,8 +476,6 @@ jl_value_t *jl_parse_eval_all(char *fname) return result; } -int asprintf(char **strp, const char *fmt, ...); - jl_value_t *jl_load(const char *fname) { if (jl_current_module == jl_base_module) { @@ -560,7 +558,7 @@ static int type_contains(jl_value_t *ty, jl_value_t *x) void print_func_loc(JL_STREAM *s, jl_lambda_info_t *li); -jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_t *bnd, +DLLEXPORT jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_t *bnd, jl_tuple_t *argtypes, jl_function_t *f) { // argtypes is a tuple ((types...), (typevars...)) diff --git a/ui/repl.c b/ui/repl.c index cfae3cb2e1910..1e4d9d5a2f7a2 100644 --- a/ui/repl.c +++ b/ui/repl.c @@ -8,10 +8,15 @@ #define WHOLE_ARCHIVE #include "../src/julia.h" +#ifndef JL_SYSTEM_IMAGE_PATH +#define JL_SYSTEM_IMAGE_PATH ".." PATHSEPSTRING "lib" PATHSEPSTRING "julia" PATHSEPSTRING "sys.ji" +#endif + static int lisp_prompt = 0; static char *program = NULL; -char *image_file = "sys.ji"; +char *image_file = NULL; int tab_width = 2; +char *build_mode = NULL; static const char *usage = "julia [options] [program] [args...]\n"; static const char *opts = @@ -37,11 +42,11 @@ static const char *opts = " -h --help Print this message\n"; void parse_opts(int *argcp, char ***argvp) { - static char* shortopts = "+H:T:bhJ:"; + static char* shortopts = "+H:T:hJ:"; static struct option longopts[] = { { "home", required_argument, 0, 'H' }, { "tab", required_argument, 0, 'T' }, - { "bare", no_argument, 0, 'b' }, + { "build", required_argument, 0, 'b' }, { "lisp", no_argument, &lisp_prompt, 1 }, { "help", no_argument, 0, 'h' }, { "sysimage", required_argument, 0, 'J' }, @@ -49,35 +54,33 @@ void parse_opts(int *argcp, char ***argvp) { }; int c; opterr = 0; - int ind = 1; -#ifdef JL_SYSTEM_IMAGE_PATH int imagepathspecified=0; -#endif + image_file = JL_SYSTEM_IMAGE_PATH; + int skip = 0; + int lastind = optind; while ((c = getopt_long(*argcp,*argvp,shortopts,longopts,0)) != -1) { switch (c) { case 0: break; case '?': + if (optind != lastind) skip++; + lastind = optind; break; case 'H': julia_home = strdup(optarg); - ind+=2; break; case 'T': // TODO: more robust error checking. tab_width = atoi(optarg); - ind+=2; break; case 'b': - image_file = NULL; - ind+=1; + build_mode = strdup(optarg); + if (!imagepathspecified) + image_file = NULL; break; case 'J': - image_file = optarg; -#ifdef JL_SYSTEM_IMAGE_PATH + image_file = strdup(optarg); imagepathspecified = 1; -#endif - ind+=2; break; case 'h': printf("%s%s", usage, opts); @@ -100,35 +103,30 @@ void parse_opts(int *argcp, char ***argvp) { free(julia_path); } } - *argvp += ind; - *argcp -= ind; + optind -= skip; + *argvp += optind; + *argcp -= optind; if (image_file==NULL && *argcp > 0) { if (strcmp((*argvp)[0], "-")) { program = (*argvp)[0]; } } if (image_file) { - int build_time_path = 0; -#ifdef JL_SYSTEM_IMAGE_PATH - if (!imagepathspecified) { - image_file = JL_SYSTEM_IMAGE_PATH; - build_time_path = 1; - } -#endif if (image_file[0] != PATHSEP) { struct stat stbuf; char path[512]; - if (build_time_path) { + if (!imagepathspecified) { // build time path relative to JULIA_HOME - snprintf(path, sizeof(path), "%s%s%s", - julia_home, PATHSEPSTRING, JL_SYSTEM_IMAGE_PATH); + snprintf(path, sizeof(path), "%s%s", + julia_home, PATHSEPSTRING JL_SYSTEM_IMAGE_PATH); image_file = strdup(path); } else if (jl_stat(image_file, (char*)&stbuf) != 0) { // otherwise try julia_home/../lib/julia/%s - snprintf(path, sizeof(path), "%s%s..%slib%sjulia%s%s", - julia_home, PATHSEPSTRING, PATHSEPSTRING, - PATHSEPSTRING, PATHSEPSTRING, image_file); + snprintf(path, sizeof(path), "%s%s%s", + julia_home, + PATHSEPSTRING ".." PATHSEPSTRING "lib" PATHSEPSTRING "julia" PATHSEPSTRING, + image_file); image_file = strdup(path); } } @@ -185,8 +183,12 @@ void handle_input(jl_value_t *ast, int end, int show_value) } jl_value_t *f = jl_get_global(jl_base_module,jl_symbol("repl_callback")); assert(f); - jl_value_t *fargs[] = { ast, jl_box_long(show_value) }; + jl_value_t **fargs; + JL_GC_PUSHARGS(fargs, 2); + fargs[0] = ast; + fargs[1] = jl_box_long(show_value); jl_apply((jl_function_t*)f, fargs, 2); + JL_GC_POP(); } void jl_lisp_prompt(); @@ -230,10 +232,7 @@ int true_main(int argc, char *argv[]) jl_arrayset(args, (jl_value_t*)jl_cstr_to_string(argv[i]), i); } } - jl_set_const(jl_core_module, jl_symbol("JULIA_HOME"), - jl_cstr_to_string(julia_home)); - jl_module_export(jl_core_module, jl_symbol("JULIA_HOME")); - + // run program if specified, otherwise enter REPL if (program) { int ret = exec_program(); @@ -286,6 +285,6 @@ int main(int argc, char *argv[]) jl_lisp_prompt(); return 0; } - julia_init(lisp_prompt ? NULL : image_file); - return julia_trampoline(argc, argv, true_main); + julia_init(lisp_prompt ? NULL : image_file, build_mode!=NULL); + return julia_trampoline(argc, argv, true_main, build_mode); }