diff --git a/basis/io/ports/ports.factor b/basis/io/ports/ports.factor
index 3acb9bff64..ea20622cb7 100644
--- a/basis/io/ports/ports.factor
+++ b/basis/io/ports/ports.factor
@@ -1,12 +1,13 @@
 ! Copyright (C) 2005, 2010 Slava Pestov, Doug Coleman
 ! See http://factorcode.org/license.txt for BSD license.
-USING: math kernel io sequences io.buffers io.timeouts generic
-byte-vectors system io.encodings math.order io.backend
-continuations classes byte-arrays namespaces splitting grouping
-dlists alien alien.c-types alien.data assocs io.encodings.binary
-summary accessors destructors combinators fry specialized-arrays
-locals ;
-SPECIALIZED-ARRAY: uchar
+USING: accessors alien alien.c-types alien.data assocs
+byte-arrays byte-vectors classes combinators continuations
+destructors dlists fry generic grouping hints io io.backend
+io.buffers io.encodings io.encodings.ascii io.encodings.binary
+io.encodings.private io.encodings.utf8 io.timeouts kernel libc
+locals math math.order namespaces sequences specialized-arrays
+specialized-arrays.instances.alien.c-types.uchar splitting
+strings summary system ;
 IN: io.ports
 
 SYMBOL: default-buffer-size
@@ -28,6 +29,7 @@ TUPLE: buffered-port < port { buffer buffer } ;
         default-buffer-size get <buffer> >>buffer ; inline
 
 TUPLE: input-port < buffered-port ;
+INSTANCE: input-port noncopying-reader
 
 M: input-port stream-element-type drop +byte+ ; inline
 
@@ -45,40 +47,44 @@ M: input-port stream-read1
     dup check-disposed
     dup wait-to-read [ drop f ] [ buffer>> buffer-pop ] if ; inline
 
-: read-step ( count port -- byte-array/f )
+: read-step ( count port -- count/f ptr/f )
     {
-        { [ over 0 = ] [ 2drop f ] }
-        { [ dup wait-to-read ] [ 2drop f ] }
-        [ buffer>> buffer-read ]
+        { [ over 0 = ] [ 2drop f f ] }
+        { [ dup wait-to-read ] [ 2drop f f ] }
+        [ buffer>> buffer-read-unsafe ]
     } cond ;
 
 : prepare-read ( count stream -- count stream )
     dup check-disposed [ 0 max >fixnum ] dip ; inline
 
-M: input-port stream-read-partial ( max stream -- byte-array/f )
-    prepare-read read-step ;
+M: input-port stream-read-partial-unsafe ( n dst port -- count )
+    [ swap ] dip prepare-read read-step
+    [ swap [ memcpy ] keep ] [ 2drop 0 ] if* ;
 
-: read-loop ( count port accum -- )
-    pick over length - dup 0 > [
-        pick read-step dup [
-            append! read-loop
+:: read-loop ( n-remaining n-read port dst -- n-total )
+    n-remaining 0 > [
+        n-remaining port read-step :> ( n-buffered ptr )
+        ptr [
+            dst ptr n-buffered memcpy
+            n-remaining n-buffered - :> n-remaining'
+            n-read n-buffered + :> n-read'
+            n-buffered dst <displaced-alien> :> dst'
+            n-remaining' n-read' port dst' read-loop
+        ] [ n-read ] if
+    ] [ n-read ] if ; inline recursive
+
+M:: input-port stream-read-unsafe ( n dst port -- count )
+    n port prepare-read :> ( n' port' )
+    n' port' read-step :> ( n-buffered ptr )
+    ptr [
+        dst ptr n-buffered memcpy
+        n-buffered n' < [
+            n-buffered dst <displaced-alien> :> dst'
+            n' n-buffered - n-buffered port dst' read-loop
         ] [
-            2drop 2drop
+            n-buffered
         ] if
-    ] [
-        2drop 2drop
-    ] if ;
-
-M: input-port stream-read
-    prepare-read
-    2dup read-step dup [
-        pick over length > [
-            pick <byte-vector>
-            [ push-all ] keep
-            [ read-loop ] keep
-            B{ } like
-        ] [ 2nip ] if
-    ] [ 2nip ] if ;
+    ] [ 0 ] if ;
 
 : read-until-step ( separators port -- string/f separator/f )
     dup wait-to-read [ 2drop f f ] [ buffer>> buffer-until ] if ;
@@ -211,8 +217,6 @@ GENERIC: underlying-handle ( stream -- handle )
 M: object underlying-handle underlying-port handle>> ;
 
 ! Fast-path optimization
-USING: hints strings io.encodings.utf8 io.encodings.ascii
-io.encodings.private ;
 
 HINTS: decoder-read-until { string input-port utf8 } { string input-port ascii } ;