@@ -59,7 +59,9 @@ data JS = JSRaw String
59 | JSApp JS [JS]
59 | JSApp JS [JS]
60 | JSNew String [JS]
60 | JSNew String [JS]
61 | JSError String
61 | JSError String
62+ | JSBinOp String JS JS
62− | JSOp String JS JS
63+ | JSPreOp String JS
63 | JSProj JS String
65 | JSProj JS String
64 | JSVar LVar
66 | JSVar LVar
@@ -76,6 +78,7 @@ data JS = JSRaw String
76 | JSCond [(JS, JS)]
78 | JSCond [(JS, JS)]
77 | JSTernary JS JS JS
79 | JSTernary JS JS JS
78 | JSParens JS
80 | JSParens JS
79 deriving Eq
82 deriving Eq
@@ -122,7 +125,7 @@ compileJS (JSNew name args) =
122compileJS (JSError exc) =
125compileJS (JSError exc) =
123 "throw new Error(\"" ++ exc ++ "\")"
126 "throw new Error(\"" ++ exc ++ "\")"
125−compileJS (JSOp op lhs rhs) =
128+compileJS (JSBinOp op lhs rhs) =
126 compileJS lhs ++ " " ++ op ++ " " ++ compileJS rhs
129 compileJS lhs ++ " " ++ op ++ " " ++ compileJS rhs
128compileJS (JSProj obj field)
131compileJS (JSProj obj field)
@@ -194,6 +197,10 @@ compileJS (JSTernary cond true false) =
194compileJS (JSParens js) =
197compileJS (JSParens js) =
195 "(" ++ compileJS js ++ ")"
198 "(" ++ compileJS js ++ ")"
200+compileJS (JSWhile cond body) =
201+ "while (" ++ compileJS cond ++ ") {\n"
198jsTailcall :: JS -> JS
205jsTailcall :: JS -> JS
199jsTailcall call =
206jsTailcall call =
@@ -212,15 +219,15 @@ jsMeth obj meth =
214jsInstanceOf :: JS -> JS -> JS
221jsInstanceOf :: JS -> JS -> JS
215−jsInstanceOf = JSOp "instanceof"
222+jsInstanceOf = JSBinOp "instanceof"
218jsEq :: JS -> JS -> JS
225jsEq :: JS -> JS -> JS
219−jsEq = JSOp "=="
226+jsEq = JSBinOp "=="
222jsAnd :: JS -> JS -> JS
229jsAnd :: JS -> JS -> JS
223−jsAnd = JSOp "&&"
230+jsAnd = JSBinOp "&&"
226jsType :: JS
233jsType :: JS
@@ -277,8 +284,12 @@ foldJS tr add acc js =
277 add (tr js) $ add (fold lhs) (foldl' add acc $ map fold rhs)
284 add (tr js) $ add (fold lhs) (foldl' add acc $ map fold rhs)
278 | JSNew _ args <- js =
285 | JSNew _ args <- js =
279 add (tr js) $ foldl' add acc $ map fold args
286 add (tr js) $ foldl' add acc $ map fold args
280− | JSOp _ lhs rhs <- js =
287+ | JSBinOp _ lhs rhs <- js =
281 add (tr js) $ add (fold lhs) (fold rhs)
288 add (tr js) $ add (fold lhs) (fold rhs)
289+ | JSPreOp _ val <- js =
290+ add (tr js) $ fold val
291+ | JSPostOp _ val <- js =
292+ add (tr js) $ fold val
282 | JSProj obj _ <- js =
293 | JSProj obj _ <- js =
283 add (tr js) (fold obj)
294 add (tr js) (fold obj)
284 | JSArray vals <- js =
295 | JSArray vals <- js =
@@ -295,6 +306,8 @@ foldJS tr add acc js =
295 add (tr js) $ fold val
306 add (tr js) $ fold val
296 | JSCond conds <- js =
307 | JSCond conds <- js =
297 add (tr js) $ foldl' add acc $ map (uncurry add . (fold *** fold)) conds
308 add (tr js) $ foldl' add acc $ map (uncurry add . (fold *** fold)) conds
309+ | JSWhile cond body <- js =
310+ add (tr js) $ add (fold cond) (fold body)
298 | otherwise =
311 | otherwise =
@@ -310,7 +323,9 @@ transformJS tr js =
310 | JSReturn ret <- js = JSReturn $ tr ret
323 | JSReturn ret <- js = JSReturn $ tr ret
311 | JSApp lhs rhs <- js = JSApp (tr lhs) $ map tr rhs
324 | JSApp lhs rhs <- js = JSApp (tr lhs) $ map tr rhs
312 | JSNew con args <- js = JSNew con $ map tr args
325 | JSNew con args <- js = JSNew con $ map tr args
313− | JSOp op lhs rhs <- js = JSOp op (tr lhs) (tr rhs)
326+ | JSBinOp op lhs rhs <- js = JSBinOp op (tr lhs) (tr rhs)
327+ | JSPreOp op val <- js = JSPreOp op (tr val)
328+ | JSPostOp op val <- js = JSPostOp op (tr val)
314 | JSProj obj field <- js = JSProj (tr obj) field
329 | JSProj obj field <- js = JSProj (tr obj) field
315 | JSArray vals <- js = JSArray $ map tr vals
330 | JSArray vals <- js = JSArray $ map tr vals
316 | JSAssign lhs rhs <- js = JSAssign (tr lhs) (tr rhs)
331 | JSAssign lhs rhs <- js = JSAssign (tr lhs) (tr rhs)
@@ -319,9 +334,21 @@ transformJS tr js =
319 | JSCond conds <- js = JSCond $ map (tr *** tr) conds
334 | JSCond conds <- js = JSCond $ map (tr *** tr) conds
320 | JSTernary c t f <- js = JSTernary (tr c) (tr t) (tr f)
335 | JSTernary c t f <- js = JSTernary (tr c) (tr t) (tr f)
321 | JSParens val <- js = JSParens $ tr val
336 | JSParens val <- js = JSParens $ tr val
337+ | JSWhile cond body <- js = JSWhile(tr cond) (tr body)
322 | otherwise = js
338 | otherwise = js
341+moveJSDeclToTop :: String -> [JS] -> [JS]
342+moveJSDeclToTop decl js = move ([], js)
344+ move :: ([JS], [JS]) -> [JS]
345+ move (front, js@(JSAlloc name _):back)
346+ | name == decl = js : front ++ back
348+ move (front, js:back) =
349+ move (front ++ [js], back)
325jsSubst :: JS -> JS -> JS -> JS
352jsSubst :: JS -> JS -> JS -> JS
326jsSubst var new old
353jsSubst var new old
327 | var == old = new
354 | var == old = new
@@ -454,9 +481,9 @@ inlineJS (JSApp (JSFunction [arg] (JSReturn ret)) [val])
455 ) (inlineJS $ jsSubst (JSIdent arg) opt idx)
482 ) (inlineJS $ jsSubst (JSIdent arg) opt idx)
457− | JSOp op lhs rhs <- ret
484+ | JSBinOp op lhs rhs <- ret
458 , opt <- inlineJS val =
485 , opt <- inlineJS val =
459− inlineJS $ JSOp op (inlineJS $ jsSubst (JSIdent arg) opt lhs) $
486+ inlineJS $ JSBinOp op (inlineJS $ jsSubst (JSIdent arg) opt lhs) $
460 (inlineJS $ jsSubst (JSIdent arg) opt rhs)
487 (inlineJS $ jsSubst (JSIdent arg) opt rhs)
462 | JSApp (JSIdent fun) args <- ret
489 | JSApp (JSIdent fun) args <- ret
@@ -518,8 +545,12 @@ deadEvalApplyCases js =
518initConstructors :: [JS] -> [JS]
545initConstructors :: [JS] -> [JS]
519initConstructors js =
546initConstructors js =
520 let tags = nub $ sort $ concat (map getTags js) in
547 let tags = nub $ sort $ concat (map getTags js) in
521− map createConstant tags ++ replaceConstructors tags js
548+ rearrangePrelude $ map createConstant tags ++ replaceConstructors tags js
550+ rearrangePrelude :: [JS] -> [JS]
551+ rearrangePrelude = moveJSDeclToTop $ idrRTNamespace ++ "Con"
523 getTags :: JS -> [Int]
554 getTags :: JS -> [Int]
524 getTags = foldJS match (++) []
555 getTags = foldJS match (++) []
@@ -670,6 +701,8 @@ inlineFunctions js =
671 | JSApp (JSIdent ident) _ <- js
702 | JSApp (JSIdent ident) _ <- js
672 , name == ident = 1
703 , name == ident = 1
673 | otherwise = 0
706 | otherwise = 0
@@ -689,9 +722,9 @@ reduceConstant
689 (JSApp (JSIdent "__IDRRT__tailcall") [JSFunction [] (
722 (JSApp (JSIdent "__IDRRT__tailcall") [JSFunction [] (
690 JSReturn (JSApp (JSIdent "__IDR__mEVAL0") [val])
723 JSReturn (JSApp (JSIdent "__IDR__mEVAL0") [val])
692− | JSNum num <- val = val
725+ | JSNum num <- val = val
693− | JSOp op lhs rhs <- val =
726+ | JSBinOp op lhs rhs <- val =
694− JSParens $ JSOp op (reduceConstant lhs) (reduceConstant rhs)
727+ JSParens $ JSBinOp op (reduceConstant lhs) (reduceConstant rhs)
696 | JSApp (JSProj lhs op) [rhs] <- val
729 | JSApp (JSProj lhs op) [rhs] <- val
697 , op `elem` [ "subtract"
730 , op `elem` [ "subtract"
@@ -733,9 +766,9 @@ elimDuplicateEvals (JSAlloc fun (Just (JSFunction args (JSSeq seq)))) =
733elimDuplicateEvals js = js
766elimDuplicateEvals js = js
736−optimizeEvalTailcalls :: (String, String) -> JS -> JS
769+optimizeRuntimeCalls :: String -> String -> [JS] -> [JS]
737−optimizeEvalTailcalls (fun, tc) js =
770+optimizeRuntimeCalls fun tc js =
738− optHelper js
771+ optTC tc : map optHelper js
740 optHelper :: JS -> JS
773 optHelper :: JS -> JS
741 optHelper (JSApp (JSIdent "__IDRRT__tailcall") [
774 optHelper (JSApp (JSIdent "__IDRRT__tailcall") [
@@ -746,6 +779,165 @@ optimizeEvalTailcalls (fun, tc) js =
746 optHelper js = transformJS optHelper js
779 optHelper js = transformJS optHelper js
782+ optTC :: String -> JS
783+ optTC tc@"__IDRRT__EVALTC" =
784+ JSAlloc tc (Just $ JSFunction ["arg0"] (
785+ JSSeq [ JSAlloc "ret" $ Just (
787+ (JSIdent "arg0" `jsInstanceOf` jsCon) `jsAnd`
788+ (hasProp "__IDRLT__mEVAL0" "arg0")
791+ (JSIdent "__IDRLT__mEVAL0")
792+ (JSProj (JSIdent "arg0") "tag")
797+ , JSWhile (JSIdent "ret" `jsInstanceOf` (JSIdent "__IDRRT__Cont")) (
798+ JSAssign (JSIdent "ret") (
799+ JSApp (JSProj (JSIdent "ret") "k") []
802+ , JSReturn $ JSIdent "ret"
806+ optTC tc@"__IDRRT__APPLYTC" =
807+ JSAlloc tc (Just $ JSFunction ["fn0", "arg0"] (
808+ JSSeq [ JSAlloc "ev" $ Just (JSApp
809+ (JSIdent "__IDRRT__EVALTC") [JSIdent "fn0"]
811+ , JSAlloc "ret" $ Just (
813+ (JSIdent "ev" `jsInstanceOf` jsCon) `jsAnd`
814+ (hasProp "__IDRLT__mAPPLY0" "ev")
817+ (JSIdent "__IDRLT__mAPPLY0")
818+ (JSProj (JSIdent "ev") "tag")
820+ [JSIdent "fn0", JSIdent "arg0", JSIdent "ev"]
823+ , JSWhile (JSIdent "ret" `jsInstanceOf` (JSIdent "__IDRRT__Cont")) (
824+ JSAssign (JSIdent "ret") (
825+ JSApp (JSProj (JSIdent "ret") "k") []
828+ , JSReturn $ JSIdent "ret"
833+ hasProp :: String -> String -> JS
835+ JSIndex (JSIdent table) (JSProj (JSIdent var) "tag")
838+unfoldLookupTable :: [JS] -> [JS]
839+unfoldLookupTable input =
840+ let (evals, evalunfold) = unfoldLT "__IDRLT__mEVAL0" input
841+ (applys, applyunfold) = unfoldLT "__IDRLT__mAPPLY0" evalunfold
843+ adaptRuntime $ expandCons evals applys js
845+ adaptRuntime :: [JS] -> [JS]
847+ adaptCon . adaptApply "__var_2" . adaptApply "ev" . adaptEval
850+ adaptApply var = map (jsSubst (
851+ JSIndex (JSIdent "__IDRLT__mAPPLY0") (JSProj (JSIdent var) "tag")
852+ ) (JSProj (JSIdent var) "app"))
855+ adaptEval = map (jsSubst (
856+ JSIndex (JSIdent "__IDRLT__mEVAL0") (JSProj (JSIdent "arg0") "tag")
857+ ) (JSProj (JSIdent "arg0") "eval"))
863+ adaptCon' front ((JSAlloc "__IDRRT__Con" (Just body)):back) =
866+ adaptCon' front (next:back) =
867+ adaptCon' (front ++ [next]) back
869+ adaptCon' front [] = front
873+ JSAlloc "__IDRRT__Con" (Just $
874+ JSFunction newArgs (
875+ JSSeq (map newVar newArgs)
879+ newVar var = JSAssign (JSProj JSThis var) (JSIdent var)
880+ newArgs = ["tag", "eval", "app", "vars"]
883+ unfoldLT :: String -> [JS] -> ([Int], [JS])
885+ let (table, code) = extractLT lt js
886+ expanded = expandLT lt table in
887+ (map fst expanded, map snd expanded ++ code)
890+ expandCons :: [Int] -> [Int] -> [JS] -> [JS]
891+ expandCons evals applys js =
894+ expandCons' :: JS -> JS
895+ expandCons' (JSNew "__IDRRT__Con" [JSNum (JSInt tag), JSArray args])
896+ | evalid <- getId "__IDRLT__mEVAL0" tag evals
897+ , applyid <- getId "__IDRLT__mAPPLY0" tag applys =
898+ JSNew "__IDRRT__Con" [ JSNum (JSInt tag)
899+ , maybe JSNull JSIdent evalid
900+ , maybe JSNull JSIdent applyid
901+ , JSArray (map expandCons' args)
904+ expandCons' js = transformJS expandCons' js
907+ getId :: String -> Int -> [Int] -> Maybe String
908+ getId lt tag entries
909+ | tag `elem` entries = Just $ ltIdentifier lt tag
910+ | otherwise = Nothing
913+ ltIdentifier :: String -> Int -> String
914+ ltIdentifier "__IDRLT__mEVAL0" id = idrLTNamespace ++ "EVAL" ++ show id
915+ ltIdentifier "__IDRLT__mAPPLY0" id = idrLTNamespace ++ "APPLY" ++ show id
918+ extractLT :: String -> [JS] -> (JS, [JS])
922+ extractLT' :: ([JS], [JS]) -> (JS, [JS])
923+ extractLT' (front, js@(JSAlloc fun _):back)
924+ | fun == lt = (js, front ++ back)
926+ extractLT' (front, js:back) = extractLT' (front ++ [js], back)
929+ expandLT :: String -> JS -> [(Int, JS)]
931+ JSAlloc _ (Just (JSApp (JSFunction [] (JSSeq seq)) []))
932+ ) = catMaybes (map expandEntry seq)
934+ expandEntry :: JS -> Maybe (Int, JS)
935+ expandEntry (JSAssign (JSIndex _ (JSNum (JSInt id))) body) =
936+ Just $ (id, JSAlloc (ltIdentifier lt id) (Just body))
938+ expandEntry js = Nothing
749removeInstanceChecks :: JS -> JS
941removeInstanceChecks :: JS -> JS
750removeInstanceChecks (JSCond conds) =
942removeInstanceChecks (JSCond conds) =
751 JSCond $ eliminateDeadBranches $ map (
943 JSCond $ eliminateDeadBranches $ map (
@@ -753,7 +945,7 @@ removeInstanceChecks (JSCond conds) =
755 removeHelper (
947 removeHelper (
756− JSOp "&&" (JSOp "instanceof" _ (JSIdent "__IDRRT__Con")) check
948+ JSBinOp "&&" (JSBinOp "instanceof" _ (JSIdent "__IDRRT__Con")) check
757 ) = removeHelper check
949 ) = removeHelper check
758 removeHelper js = js
950 removeHelper js = js
@@ -854,9 +1046,12 @@ codegenJavaScript target definitions filename outputType = do
854 functions :: [String]
1046 functions :: [String]
855 functions = translate >>> optimize >>> compile $ def
1047 functions = translate >>> optimize >>> compile $ def
857− translate p = concatMap translateDeclaration p ++ [mainLoop, invokeLoop]
1050+ prelude ++ concatMap translateDeclaration p ++ [mainLoop, invokeLoop]
858− optimize p = foldl' (flip ($)) p opt
1052+ foldl' (flip ($)) p opt
859− compile = map compileJS
1054+ map compileJS
862 [ map optimizeJS
1057 [ map optimizeJS
@@ -867,13 +1062,25 @@ codegenJavaScript target definitions filename outputType = do
867 , map removeAllocations
1062 , map removeAllocations
868 , elimDeadLoop
1063 , elimDeadLoop
869 , map elimDuplicateEvals
1064 , map elimDuplicateEvals
870− , map (optimizeEvalTailcalls ("__IDR__mEVAL0", "__IDRRT__EVALTC"))
1065+ , optimizeRuntimeCalls "__IDR__mEVAL0" "__IDRRT__EVALTC"
871− , map (optimizeEvalTailcalls ("__IDR__mAPPLY0", "__IDRRT__APPLYTC"))
1066+ , optimizeRuntimeCalls "__IDR__mAPPLY0" "__IDRRT__APPLYTC"
872 , map removeInstanceChecks
1067 , map removeInstanceChecks
873 , inlineFunctions
1068 , inlineFunctions
874 , map reduceContinuations
1069 , map reduceContinuations
1070+ , unfoldLookupTable
1075+ [ JSAlloc (idrRTNamespace ++ "Cont") (Just $ JSFunction ["k"] (
1076+ JSAssign (JSProj JSThis "k") (JSIdent "k")
1078+ , JSAlloc (idrRTNamespace ++ "Con") (Just $ JSFunction ["tag", "vars"] (
1079+ JSSeq [ JSAssign (JSProj JSThis "tag") (JSIdent "tag")
1080+ , JSAssign (JSProj JSThis "vars") (JSIdent "vars")
878 mainLoop :: JS
1085 mainLoop :: JS
879 mainLoop =
1086 mainLoop =
@@ -1016,8 +1223,10 @@ translateDeclaration (path, SFun name params stackSize body)
1016 , (SLet var val next) <- body
1223 , (SLet var val next) <- body
1017 , (SChkCase cvar cases) <- next
1224 , (SChkCase cvar cases) <- next
1018 , ap == txt "APPLY" =
1225 , ap == txt "APPLY" =
1019− let lvar = translateVariableName var
1226+ let lvar = translateVariableName var
1228+ (JSIndex (JSIdent t) (JSProj (JSIdent lvar) "tag"))
1020− lookup = "[" ++ lvar ++ ".tag](fn0,arg0," ++ lvar ++ ")" in
1229+ [JSIdent "fn0", JSIdent "arg0", JSIdent lvar]) in
1021 [ lookupTable [(var, "chk")] var cases
1230 [ lookupTable [(var, "chk")] var cases
1022 , jsDecl $ JSFunction ["fn0", "arg0"] (
1231 , jsDecl $ JSFunction ["fn0", "arg0"] (
1023 JSSeq [ JSAlloc "__var_0" (Just $ JSIdent "fn0")
1232 JSSeq [ JSAlloc "__var_0" (Just $ JSIdent "fn0")
@@ -1027,10 +1236,7 @@ translateDeclaration (path, SFun name params stackSize body)
1027 , JSReturn $ (JSTernary (
1236 , JSReturn $ (JSTernary (
1028 (JSVar var `jsInstanceOf` jsCon) `jsAnd`
1237 (JSVar var `jsInstanceOf` jsCon) `jsAnd`
1029 (hasProp lookupTableName (translateVariableName var))
1238 (hasProp lookupTableName (translateVariableName var))
1031− lookupTableName ++ lookup
1239+ ) (lookup lookupTableName) JSNull)
@@ -1306,7 +1512,7 @@ translateExpression (SOp op vars)
1308 translateBinaryOp :: String -> LVar -> LVar -> JS
1514 translateBinaryOp :: String -> LVar -> LVar -> JS
1309− translateBinaryOp f lhs rhs = JSOp f (JSVar lhs) (JSVar rhs)
1515+ translateBinaryOp f lhs rhs = JSBinOp f (JSVar lhs) (JSVar rhs)
1312 invokeMeth :: LVar -> String -> [LVar] -> JS
1518 invokeMeth :: LVar -> String -> [LVar] -> JS