Skip to content

Commit

Permalink
Merge pull request #16917 from JuliaLang/jn/io-early
Browse files Browse the repository at this point in the history
IO fixes
  • Loading branch information
vtjnash authored Jun 15, 2016
2 parents 0bf3fbc + ca6b83e commit 74b3042
Show file tree
Hide file tree
Showing 19 changed files with 177 additions and 65 deletions.
1 change: 1 addition & 0 deletions base/REPL.jl
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ function run_repl(repl::AbstractREPL, consumer = x->nothing)
repl_channel = Channel(1)
response_channel = Channel(1)
backend = start_repl_backend(repl_channel, response_channel)
consumer(backend)
run_frontend(repl, REPLBackendRef(repl_channel,response_channel))
return backend
end
Expand Down
38 changes: 37 additions & 1 deletion base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export
Signed, Int, Int8, Int16, Int32, Int64, Int128,
Unsigned, UInt, UInt8, UInt16, UInt32, UInt64, UInt128,
# string types
Char, DirectIndexString, AbstractString, String,
Char, DirectIndexString, AbstractString, String, IO,
# errors
ErrorException, BoundsError, DivideError, DomainError, Exception, InexactError,
InterruptException, OutOfMemoryError, ReadOnlyMemoryError, OverflowError,
Expand Down Expand Up @@ -325,6 +325,7 @@ Array{T}(::Type{T}, m::Int) = Array{T,1}(m)
Array{T}(::Type{T}, m::Int,n::Int) = Array{T,2}(m,n)
Array{T}(::Type{T}, m::Int,n::Int,o::Int) = Array{T,3}(m,n,o)


# docsystem basics
macro doc(x...)
atdoc(x...)
Expand All @@ -338,6 +339,41 @@ end
atdoc = (str, expr) -> Expr(:escape, expr)
atdoc!(λ) = global atdoc = λ


# simple stand-alone print definitions for debugging
abstract IO
type CoreSTDOUT <: IO end
type CoreSTDERR <: IO end
const STDOUT = CoreSTDOUT()
const STDERR = CoreSTDERR()
io_pointer(::CoreSTDOUT) = Intrinsics.pointerref(Intrinsics.cglobal(:jl_uv_stdout, Ptr{Void}), 1)
io_pointer(::CoreSTDERR) = Intrinsics.pointerref(Intrinsics.cglobal(:jl_uv_stderr, Ptr{Void}), 1)

unsafe_write(io::IO, x::Ptr{UInt8}, nb::UInt) =
(ccall(:jl_uv_puts, Void, (Ptr{Void}, Ptr{UInt8}, UInt), io_pointer(io), x, nb); nb)
unsafe_write(io::IO, x::Ptr{UInt8}, nb::Int) =
(ccall(:jl_uv_puts, Void, (Ptr{Void}, Ptr{UInt8}, Int), io_pointer(io), x, nb); nb)
write(io::IO, x::UInt8) =
(ccall(:jl_uv_putb, Void, (Ptr{Void}, UInt8), io_pointer(io), x); 1)
function write(io::IO, x::String)
nb = sizeof(x.data)
unsafe_write(io, ccall(:jl_array_ptr, Ptr{UInt8}, (Any,), x.data), nb)
return nb
end

show(io::IO, x::ANY) = ccall(:jl_static_show, Void, (Ptr{Void}, Any), io_pointer(io), x)
print(io::IO, x::Char) = ccall(:jl_uv_putc, Void, (Ptr{Void}, Char), io_pointer(io), x)
print(io::IO, x::String) = write(io, x)
print(io::IO, x::ANY) = show(io, x)
print(io::IO, x::ANY, a::ANY...) = (print(io, x); print(io, a...))
println(io::IO) = write(io, 0x0a) # 0x0a = '\n'
println(io::IO, x::ANY...) = (print(io, x...); println(io))

show(a::ANY) = show(STDOUT, a)
print(a::ANY...) = print(STDOUT, a...)
println(a::ANY...) = println(STDOUT, a...)


module TopModule
# this defines the types that lowering expects to be defined in a (top) module
# that are usually inherited from Core, but could be defined custom for a module
Expand Down
18 changes: 11 additions & 7 deletions base/coreimg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@

Main.Core.eval(Main.Core, :(baremodule Inference
using Core.TopModule, Core.Intrinsics
import Core: print, println, show, write, unsafe_write, STDOUT, STDERR
if false # show that the IO system is already (relatively) operational
print("HELLO")
println(" WORLD")
show("αβγ :)"); println()
println(STDERR, "TEST")
println(STDERR, STDERR)
println(STDERR, 'a')
println(STDERR, 'α')
end

ccall(:jl_set_istopmod, Void, (Bool,), false)

eval(x) = Core.eval(Inference,x)
eval(m,x) = Core.eval(m,x)

include = Core.include

# simple print definitions for debugging.
show(x::ANY) = ccall(:jl_static_show, Void, (Ptr{Void}, Any),
pointerref(cglobal(:jl_uv_stdout,Ptr{Void}),1), x)
print(x::ANY) = show(x)
println(x::ANY) = ccall(:jl_, Void, (Any,), x) # includes a newline
print(a::ANY...) = for x=a; print(x); end

## Load essential files and libraries
include("essentials.jl")
include("generator.jl")
Expand Down
31 changes: 31 additions & 0 deletions base/coreio.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# This file is a part of Julia. License is MIT: http://julialang.org/license

show(x) = show(STDOUT::IO, x)
print(xs...) = print(STDOUT::IO, xs...)
println(xs...) = println(STDOUT::IO, xs...)
println(io::IO) = print(io, '\n')

immutable DevNullStream <: IO end
const DevNull = DevNullStream()
isreadable(::DevNullStream) = false
iswritable(::DevNullStream) = true
isopen(::DevNullStream) = true
read(::DevNullStream, ::Type{UInt8}) = throw(EOFError())
write(::DevNullStream, ::UInt8) = 1
close(::DevNullStream) = nothing
flush(::DevNullStream) = nothing
wait_connected(::DevNullStream) = nothing
wait_readnb(::DevNullStream) = wait()
wait_readbyte(::DevNullStream) = wait()
wait_close(::DevNullStream) = wait()
eof(::DevNullStream) = true

let CoreIO = Union{Core.CoreSTDOUT, Core.CoreSTDERR}
global write, unsafe_write
write(io::CoreIO, x::UInt8) = Core.write(io, x)
unsafe_write(io::CoreIO, x::Ptr{UInt8}, nb::UInt) = Core.unsafe_write(io, x, nb)
end

STDIN = DevNull
STDOUT = Core.STDOUT
STDERR = Core.STDERR
2 changes: 0 additions & 2 deletions base/essentials.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# This file is a part of Julia. License is MIT: http://julialang.org/license

abstract IO

typealias Callable Union{Function,DataType}

const Bottom = Union{}
Expand Down
1 change: 0 additions & 1 deletion base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ export
UniformScaling,
InsertionSort,
IntSet,
IO,
IOBuffer,
IOStream,
LinSpace,
Expand Down
6 changes: 3 additions & 3 deletions base/libuv.jl
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ function reinit_stdio()
global uv_jl_timercb = cfunction(uv_timercb, Void, (Ptr{Void},))

global uv_eventloop = ccall(:jl_global_event_loop, Ptr{Void}, ())
global STDIN = init_stdio(ccall(:jl_stdin_stream ,Ptr{Void},()))
global STDOUT = init_stdio(ccall(:jl_stdout_stream,Ptr{Void},()))
global STDERR = init_stdio(ccall(:jl_stderr_stream,Ptr{Void},()))
global STDIN = init_stdio(ccall(:jl_stdin_stream, Ptr{Void}, ()))
global STDOUT = init_stdio(ccall(:jl_stdout_stream, Ptr{Void}, ()))
global STDERR = init_stdio(ccall(:jl_stderr_stream, Ptr{Void}, ()))
end

"""
Expand Down
15 changes: 0 additions & 15 deletions base/process.jl
Original file line number Diff line number Diff line change
Expand Up @@ -147,21 +147,6 @@ immutable FileRedirect
end
end

immutable DevNullStream <: IO end
const DevNull = DevNullStream()
isreadable(::DevNullStream) = false
iswritable(::DevNullStream) = true
isopen(::DevNullStream) = true
read(::DevNullStream, ::Type{UInt8}) = throw(EOFError())
write(::DevNullStream, ::UInt8) = 1
close(::DevNullStream) = nothing
flush(::DevNullStream) = nothing
wait_connected(::DevNullStream) = nothing
wait_readnb(::DevNullStream) = wait()
wait_readbyte(::DevNullStream) = wait()
wait_close(::DevNullStream) = wait()
eof(::DevNullStream) = true

uvhandle(::DevNullStream) = C_NULL
uvtype(::DevNullStream) = UV_STREAM

Expand Down
1 change: 0 additions & 1 deletion base/show.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# This file is a part of Julia. License is MIT: http://julialang.org/license

show(x) = show(STDOUT::IO, x)
print(io::IO, s::Symbol) = (write(io,s); nothing)

immutable IOContext{IO_t <: IO} <: AbstractPipe
Expand Down
3 changes: 0 additions & 3 deletions base/strings/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ end

println(io::IO, xs...) = print(io, xs..., '\n')

print(xs...) = print(STDOUT, xs...)
println(xs...) = println(STDOUT, xs...)

## conversion of general objects to strings ##

function sprint(size::Integer, f::Function, args...; env=nothing)
Expand Down
22 changes: 16 additions & 6 deletions base/sysimg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ baremodule Base

using Core.TopModule, Core.Intrinsics
ccall(:jl_set_istopmod, Void, (Bool,), true)

include = Core.include
include("coreio.jl")

eval(x) = Core.eval(Base,x)
eval(m,x) = Core.eval(m,x)
Expand All @@ -19,11 +19,21 @@ include("exports.jl")
if false
# simple print definitions for debugging. enable these if something
# goes wrong during bootstrap before printing code is available.
show(x::ANY) = ccall(:jl_static_show, Void, (Ptr{Void}, Any),
pointerref(cglobal(:jl_uv_stdout,Ptr{Void}),1), x)
print(x::ANY) = show(x)
println(x::ANY) = ccall(:jl_, Void, (Any,), x)
print(a::ANY...) = for x=a; print(x); end
# otherwise, they just just eventually get (noisily) overwritten later
global show, print, println
show(io::IO, x::ANY) = Core.show(io, x)
print(io::IO, a::ANY...) = Core.print(io, a...)
println(io::IO, x::ANY...) = Core.println(io, x...)
if false # show that the IO system now (relatively) operational
print("HELLO")
println(" WORLD")
show("αβγ :)"); println()
println(STDERR, "TEST")
println(STDERR, STDERR)
println(STDERR, 'a')
println(STDERR, 'α')
show(STDOUT, 'α')
end
end

## Load essential files and libraries
Expand Down
4 changes: 2 additions & 2 deletions doc/devdocs/stdio.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ to be printed before this are routed to the standard C library

In ``sys.c``, the :code:`JL_STD*` stream pointers are statically initialised
to integer constants: ``STD*_FILENO (0, 1 and 2)``. In ``jl_uv.c`` the
:c:func:`jl_write` function checks its :code:`uv_stream_t* stream`
:c:func:`jl_uv_puts` function checks its :code:`uv_stream_t* stream`
argument and calls :c:func:`fwrite` if stream is set to :c:macro:`STDOUT_FILENO`
or :c:macro:`STDERR_FILENO`.

Expand Down Expand Up @@ -118,7 +118,7 @@ to point to :c:type:`ios_t` streams.

This is needed because :c:func:`jl_printf` caller :c:func:`jl_static_show`
is passed an :code:`ios_t` stream by femtolisp's :c:func:`fl_print` function.
Julia's :c:func:`jl_write` function has special handling for this::
Julia's :c:func:`jl_uv_puts` function has special handling for this::

if (stream->type > UV_HANDLE_TYPE_MAX) {
return ios_write((ios_t*)stream, str, n);
Expand Down
19 changes: 15 additions & 4 deletions src/flisp/print.c
Original file line number Diff line number Diff line change
Expand Up @@ -636,17 +636,28 @@ static void cvalue_printdata(fl_context_t *fl_ctx, ios_t *f, void *data,
numerictype_t nt = sym_to_numtype(fl_ctx, type);
if (nt == N_NUMTYPES) {
// These states should be context independent.
static size_t (*volatile jl_static_print)(ios_t*, void*) = 0;
static size_t (*volatile jl_static_print)(ios_t*, void*) = NULL;
static volatile int init = 0;
if (init == 0) {
#if defined(RTLD_SELF)
jl_static_print = (size_t (*)(ios_t *, void *)) dlsym(RTLD_SELF, "jl_static_show");
jl_static_print = (size_t (*)(ios_t*, void*))
dlsym(RTLD_SELF, "jl_static_show");
#elif defined(RTLD_DEFAULT)
jl_static_print = (size_t (*)(ios_t *, void *)) dlsym(RTLD_DEFAULT, "jl_static_show");
jl_static_print = (size_t (*)(ios_t*, void*))
dlsym(RTLD_DEFAULT, "jl_static_show");
#elif defined(_OS_WINDOWS_)
HMODULE handle;
if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCWSTR)(&cvalue_printdata),
&handle)) {
jl_static_print = (size_t (*)(ios_t*, void*))
GetProcAddress(handle, "jl_static_show");
}
#endif
init = 1;
}
if (jl_static_print != 0 && fl_ctx->jl_sym == type) {
if (jl_static_print != NULL && fl_ctx->jl_sym == type) {
fl_ctx->HPOS += ios_printf(f, "#<julia: ");
fl_ctx->HPOS += jl_static_print(f, *(void**)data);
fl_ctx->HPOS += ios_printf(f, ">");
Expand Down
2 changes: 1 addition & 1 deletion src/gc-debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ void objprofile_printall(void)
}
#endif

#if defined(GC_TIME) || defined(GC_FINAL_STATS)
STATIC_INLINE double jl_ns2ms(int64_t t)
{
return t / (double)1e6;
Expand All @@ -482,7 +483,6 @@ STATIC_INLINE double jl_ns2s(int64_t t)
return t / (double)1e9;
}

#if defined(GC_TIME) || defined(GC_FINAL_STATS)
static uint64_t gc_premark_end;
static uint64_t gc_postmark_end;
void gc_settime_premark_end(void)
Expand Down
2 changes: 1 addition & 1 deletion src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -958,7 +958,7 @@ void JL_NORETURN jl_method_error_bare(jl_function_t *f, jl_value_t *args)
jl_throw(jl_apply_generic(fargs, 3));
}
else {
jl_printf((JL_STREAM*)STDERR_FILENO, "A method error occurred before the base module was defined. Aborting...\n");
jl_printf((JL_STREAM*)STDERR_FILENO, "A method error occurred before the base MethodError type was defined. Aborting...\n");
jl_static_show((JL_STREAM*)STDERR_FILENO,(jl_value_t*)f); jl_printf((JL_STREAM*)STDERR_FILENO,"\n");
jl_static_show((JL_STREAM*)STDERR_FILENO,args); jl_printf((JL_STREAM*)STDERR_FILENO,"\n");
jl_bt_size = rec_backtrace(jl_bt_data, JL_MAX_BT_SIZE);
Expand Down
18 changes: 13 additions & 5 deletions src/jl_uv.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,10 +418,7 @@ JL_DLLEXPORT void jl_uv_writecb(uv_write_t *req, int status)
}
}

// Note: jl_write() is called only by jl_vprintf().
// See: doc/devdocs/stdio.rst

static void jl_write(uv_stream_t *stream, const char *str, size_t n)
JL_DLLEXPORT void jl_uv_puts(uv_stream_t *stream, const char *str, size_t n)
{
assert(stream);
static_assert(offsetof(uv_stream_t,type) == offsetof(ios_t,bm) &&
Expand Down Expand Up @@ -468,6 +465,17 @@ static void jl_write(uv_stream_t *stream, const char *str, size_t n)
}
}

JL_DLLEXPORT void jl_uv_putb(uv_stream_t *stream, uint8_t b)
{
jl_uv_puts(stream, (char*)&b, 1);
}

JL_DLLEXPORT void jl_uv_putc(uv_stream_t *stream, uint32_t wchar)
{
char s[4];
jl_uv_puts(stream, s, u8_wc_toutf8(s, wchar));
}

extern int vasprintf(char **str, const char *fmt, va_list ap);

JL_DLLEXPORT int jl_vprintf(uv_stream_t *s, const char *format, va_list args)
Expand All @@ -484,7 +492,7 @@ JL_DLLEXPORT int jl_vprintf(uv_stream_t *s, const char *format, va_list args)
c = vasprintf(&str, format, al);

if (c >= 0) {
jl_write(s, str, c);
jl_uv_puts(s, str, c);
free(str);
}
va_end(al);
Expand Down
8 changes: 5 additions & 3 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,16 @@ extern "C" {

typedef struct _jl_value_t jl_value_t;

struct _jl_taggedvalue_bits {
uintptr_t gc:2;
};

struct _jl_taggedvalue_t {
union {
uintptr_t header;
jl_taggedvalue_t *next;
jl_value_t *type; // 16-byte aligned
struct {
uintptr_t gc:2;
} bits;
struct _jl_taggedvalue_bits bits;
};
// jl_value_t value;
};
Expand Down
6 changes: 2 additions & 4 deletions test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1734,10 +1734,8 @@ let
end

# make sure front end can correctly print values to error messages
let
ex = expand(parse("\"a\"=1"))
@test ex == Expr(:error, "invalid assignment location \"\"a\"\"") ||
ex == Expr(:error, "invalid assignment location \"#<julia_value>\"")
let ex = expand(parse("\"a\"=1"))
@test ex == Expr(:error, "invalid assignment location \"\"a\"\"")
end

# make sure that incomplete tags are detected correctly
Expand Down
Loading

0 comments on commit 74b3042

Please sign in to comment.