diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 import Distribution.Simple
 import Distribution.Simple.Setup
 import Distribution.Simple.LocalBuildInfo
@@ -8,26 +9,42 @@
 
 main = defaultMainWithHooks $ simpleUserHooks {
     postBuild = \args buildflags pkgdesc buildinfo -> do
-       when (buildinfo `has` "portable" || buildinfo `has` "portable-compiler") $ do
+       when (buildinfo `has` "portable" ||
+             buildinfo `has` "portable-compiler") $ do
          -- Figure out paths
          let dirname = "haste-compiler"
-             exes = map fst $ executableConfigs buildinfo
+             exes = [ exeName exe
+                    | exe <- executables pkgdesc]
              builddir = buildDir buildinfo
-             outdir = builddir </> dirname
+             outdir = dirname
              datadir = dataDir $ localPkgDescr buildinfo
              jsfiles = dataFiles $ localPkgDescr buildinfo
+             hastedirfile = ".hastedir" -- does Haste "own" this directory?
          
          dirExists <- doesDirectoryExist outdir
-         when dirExists $ removeDirectoryRecursive outdir
+         isHasteDir <- doesFileExist (outdir </> hastedirfile)
+         when (dirExists && not isHasteDir) $
+           error $ "The output directory " ++ outdir ++ " already exists, "
+                 ++ "and doesn't seem to be a Haste installation."
+         when (dirExists && isHasteDir) $
+           removeDirectoryRecursive outdir
+             
          createDirectoryIfMissing True (outdir </> "js")
          
          -- Copy executables
          forM_ exes $ \exe -> do
-           copyFile (builddir </> exe </> exe) (outdir </> exe)
+           exists <- doesFileExist $ builddir </> exe </> exe
+           if exists
+             then copyFile (builddir </> exe </> exe) (outdir </> exe)
+             else copyFile (builddir </> exe </> exe <.> "exe")
+                           (outdir </> exe <.> "exe")
          
          -- Copy libs
          forM_ jsfiles $ \js -> do
            copyFile (datadir </> js) (outdir </> "js" </> js)
+         
+         -- Mark the directory as ours
+         writeFile (outdir </> ".hastedir") ""
   }
 
 has :: LocalBuildInfo -> String -> Bool
diff --git a/haste-compiler.cabal b/haste-compiler.cabal
--- a/haste-compiler.cabal
+++ b/haste-compiler.cabal
@@ -1,5 +1,5 @@
 Name:           haste-compiler
-Version:        0.2.4
+Version:        0.2.5
 License:        BSD3
 License-File:   LICENSE
 Synopsis:       Haskell To ECMAScript compiler
@@ -33,6 +33,7 @@
     cheap-unicode.js
     debug.js
     Canvas.js
+    Handle.js
 
 Flag portable
     Description:
@@ -45,6 +46,10 @@
         Install Haste into a self-contained directory. Package databases are
         still local to each user. Primarily useful for global installs.
     Default: False
+
+source-repository head
+    type:       git
+    location:   https://github.com/valderman/haste-compiler.git
 
 Executable haste-boot
     Main-Is: haste-boot.hs
diff --git a/lib/Canvas.js b/lib/Canvas.js
--- a/lib/Canvas.js
+++ b/lib/Canvas.js
@@ -18,4 +18,7 @@
 }
 function jsDrawText(ctx, str, x, y) {ctx.fillText(str, x, y);}
 function jsClip(ctx) {ctx.clip();}
+function jsArc(ctx, x, y, radius, fromAngle, toAngle) {
+    ctx.arc(x, y, radius, fromAngle, toAngle);
+}
 function jsCanvasToDataURL(el) {return el.toDataURL('image/png');}
diff --git a/lib/Handle.js b/lib/Handle.js
new file mode 100644
--- /dev/null
+++ b/lib/Handle.js
@@ -0,0 +1,64 @@
+// Simulate handles.
+// When implementing new handles, remember that passed strings may be thunks,
+// and so need to be evaluated before use.
+
+function jsNewHandle(init, read, write, flush, close, seek, tell) {
+    var h = {
+        read: read || function() {},
+        write: write || function() {},
+        seek: seek || function() {},
+        tell: tell || function() {},
+        close: close || function() {},
+        flush: flush || function() {}
+    };
+    init.call(h);
+    return h;
+}
+
+function jsReadHandle(h, len) {return h.read(len);}
+function jsWriteHandle(h, str) {return h.write(str);}
+function jsFlushHandle(h) {return h.flush();}
+function jsCloseHandle(h) {return h.close();}
+
+function jsMkConWriter(op) {
+    return function(str) {
+        str = E(str);
+        var lines = (this.buf + str).split('\n');
+        for(var i = 0; i < lines.length-1; ++i) {
+            op.call(console, lines[i]);
+        }
+        this.buf = lines[lines.length-1];
+    }
+}
+
+function jsMkStdout() {
+    return jsNewHandle(
+        function() {this.buf = '';},
+        function(_) {return '';},
+        jsMkConWriter(console.log),
+        function() {console.log(this.buf); this.buf = '';}
+    );
+}
+
+function jsMkStderr() {
+    return jsNewHandle(
+        function() {this.buf = '';},
+        function(_) {return '';},
+        jsMkConWriter(console.warn),
+        function() {console.warn(this.buf); this.buf = '';}
+    );
+}
+
+function jsMkStdin() {
+    return jsNewHandle(
+        function() {this.buf = '';},
+        function(len) {
+            while(this.buf.length < len) {
+                this.buf += prompt('[stdin]') + '\n';
+            }
+            var ret = this.buf.substr(0, len);
+            this.buf = this.buf.substr(len);
+            return ret;
+        }
+    );
+}
diff --git a/lib/rts.js b/lib/rts.js
--- a/lib/rts.js
+++ b/lib/rts.js
@@ -177,7 +177,7 @@
 function charCodeAt(str, i) {return str.charCodeAt(i);}
 
 function fromJSStr(str) {
-    return unCStr(E(str)[1]);
+    return unCStr(E(str));
 }
 
 function toJSStr(hsstr) {
@@ -185,7 +185,7 @@
     for(var str = E(hsstr); str[0] == 1; str = E(str[2])) {
         s += String.fromCharCode(E(str[1])[1]);
     }
-    return [0,s];
+    return s;
 }
 
 // newMutVar
@@ -201,6 +201,13 @@
 // writeMutVar
 function wMV(mv, val) {
     mv.x = val;
+}
+
+// atomicModifyMutVar
+function mMV(mv, f) {
+    var x = A(f, [mv.x]);
+    mv.x = x[1];
+    return x[2];
 }
 
 function localeEncoding() {
diff --git a/lib/stdlib.js b/lib/stdlib.js
--- a/lib/stdlib.js
+++ b/lib/stdlib.js
@@ -154,6 +154,10 @@
     return document.createElement(tag);
 }
 
+function jsCreateTextNode(str) {
+    return document.createTextNode(str);
+}
+
 function jsGetChildBefore(elem) {
     elem = elem.previousSibling;
     while(elem) {
diff --git a/src/Haste/Builtins.hs b/src/Haste/Builtins.hs
--- a/src/Haste/Builtins.hs
+++ b/src/Haste/Builtins.hs
@@ -26,10 +26,6 @@
       Just $ foreignVar "unFoldrCStr"
 
     -- Primitive needs of the Haste standard library
-    (Just "Haste.Prim", "toJSStr") ->
-      Just $ foreignVar "toJSStr"
-    (Just "Haste.Prim", "fromJSStr") ->
-      Just $ foreignVar "fromJSStr"
     (Just "Haste.Prim", "jsRound") ->
       Just $ foreignVar "Math.round"
     (Just "Haste.Prim", "jsCeiling") ->
diff --git a/src/Haste/Config.hs b/src/Haste/Config.hs
--- a/src/Haste/Config.hs
+++ b/src/Haste/Config.hs
@@ -14,7 +14,7 @@
 stdJSLibs :: [FilePath]
 stdJSLibs = map (jsDir </>)  [
     "rts.js", "stdlib.js", "MVar.js", "StableName.js", "Integer.js", "md5.js",
-    "array.js", "pointers.js", "cheap-unicode.js", "Canvas.js"
+    "array.js", "pointers.js", "cheap-unicode.js", "Canvas.js", "Handle.js"
   ]
 
 debugLib :: FilePath
diff --git a/src/Haste/PrimOps.hs b/src/Haste/PrimOps.hs
--- a/src/Haste/PrimOps.hs
+++ b/src/Haste/PrimOps.hs
@@ -211,7 +211,7 @@
     ReadMutVarOp -> callF "rMV"
     WriteMutVarOp -> callF "wMV"
     SameMutVarOp -> bOp Eq
-    AtomicModifyMutVarOp -> Right $ callSaturated (xs !! 1) [(xs !! 0)]
+    AtomicModifyMutVarOp -> callF "mMV"
     
     -- TVars - since there's no parallelism and no preemption, TVars behave
     -- just like normal IORefs.
@@ -262,6 +262,10 @@
     AddrGeOp               ->
         Right $ binOp Sub (litN 0) $ callForeign "addrLT" [a, b]
       where (a:b:_) = xs
+    Addr2IntOp             ->
+        Right $ index x (lit "off")
+      where
+        (x:_) = xs
 
     -- MVars
     NewMVarOp     -> callF "newMVar"
diff --git a/src/Haste/Version.hs b/src/Haste/Version.hs
--- a/src/Haste/Version.hs
+++ b/src/Haste/Version.hs
@@ -10,7 +10,7 @@
 import Haste.Environment (hasteDir)
 
 hasteVersion :: Version
-hasteVersion = Version [0, 2, 4] []
+hasteVersion = Version [0, 2, 5] []
 
 ghcVersion :: String
 ghcVersion = cProjectVersion
