Bläddra i källkod

Added closure support in jtalkc, added Benchib class category in ide.html.

Göran Krampe 13 år sedan
förälder
incheckning
cd06eb8e87
6 ändrade filer med 212 tillägg och 24 borttagningar
  1. 1 0
      ide.html
  2. 81 0
      js/Benchfib.js
  3. 2 6
      nodejs/README
  4. 2 2
      nodejs/benchfib/Makefile
  5. 56 16
      nodejs/jtalkc
  6. 70 0
      st/Benchfib.st

+ 1 - 0
ide.html

@@ -18,6 +18,7 @@
     <script type="text/javascript" src="./js/IDE.js"></script>
     <script type="text/javascript" src="./js/SUnit.js"></script>
     <script type="text/javascript" src="./js/Examples.js"></script>
+    <script type="text/javascript" src="./js/Benchfib.js"></script>
     <script type="text/javascript" src="./js/init.js"></script>
     <link rel="stylesheet" type="text/css" href="./css/jtalk.css">
     <link rel="stylesheet" type="text/css" href="./css/sunit.css">

+ 81 - 0
js/Benchfib.js

@@ -0,0 +1,81 @@
+smalltalk.addClass('Benchfib', smalltalk.Object, [], 'Benchfib');
+
+smalltalk.addMethod(
+'_main',
+smalltalk.method({
+selector: 'main',
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var result=nil;
+result=smalltalk.send((0), "_tinyBenchmarks", []);
+console.log('0 tinyBenchmarks => ' + result);;
+return self;},
+source: unescape('main%0A%0A%09%7C%20result%20%7C%0A%09result%20%3A%3D%200%20tinyBenchmarks.%0A%09%7B%27console.log%28%27%270%20tinyBenchmarks%20%3D%3E%20%27%27%20+%20result%29%3B%27%7D'),
+messageSends: ["tinyBenchmarks"],
+referencedClasses: []
+}),
+smalltalk.Benchfib.klass);
+
+
+smalltalk.addMethod(
+'_benchFib',
+smalltalk.method({
+selector: 'benchFib',
+category: '*Benchfib',
+fn: function (){
+var self=this;
+return smalltalk.send(smalltalk.send(self, "__lt", [(2)]), "_ifTrue_ifFalse_", [(function(){return (1);}), (function(){return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(self, "__minus", [(1)]), "_benchFib", []), "__plus", [smalltalk.send(smalltalk.send(self, "__minus", [(2)]), "_benchFib", [])]), "__plus", [(1)]);})]);
+return self;},
+source: unescape('benchFib%0A%09%22Handy%20send-heavy%20benchmark%22%0A%09%22%28result%20//%20seconds%20to%20run%29%20%3D%20approx%20calls%20per%20second%22%0A%09%22%20%7C%20r%20t%20%7C%0A%09%20%20t%20%3A%3D%20Time%20millisecondsToRun%3A%20%5Br%20%3A%3D%2026%20benchFib%5D.%0A%09%20%20%28r%20*%201000%29%20//%20t%22%0A%09%22138000%20on%20a%20Mac%208100/100%22%0A%09%5E%20self%20%3C%202%0A%09%09ifTrue%3A%20%5B1%5D%20%0A%09%09ifFalse%3A%20%5B%28self-1%29%20benchFib%20+%20%28self-2%29%20benchFib%20+%201%5D'),
+messageSends: ["ifTrue:ifFalse:", unescape("%3C"), unescape("+"), "benchFib", unescape("-")],
+referencedClasses: []
+}),
+smalltalk.Number);
+
+smalltalk.addMethod(
+'_benchmark',
+smalltalk.method({
+selector: 'benchmark',
+category: '*Benchfib',
+fn: function (){
+var self=this;
+var size=nil;
+var flags=nil;
+var prime=nil;
+var k=nil;
+var count=nil;
+size=(8190);
+smalltalk.send((1), "_to_do_", [self, (function(iter){count=(0);flags=smalltalk.send(smalltalk.Array, "_new", []);smalltalk.send(size, "_timesRepeat_", [(function(){return smalltalk.send(flags, "_add_", [true]);})]);return smalltalk.send((1), "_to_do_", [size, (function(i){return smalltalk.send(smalltalk.send(flags, "_at_", [i]), "_ifTrue_", [(function(){prime=smalltalk.send(i, "__plus", [(1)]);k=smalltalk.send(i, "__plus", [prime]);smalltalk.send((function(){return smalltalk.send(k, "__lt_eq", [size]);}), "_whileTrue_", [(function(){smalltalk.send(flags, "_at_put_", [k, false]);return k=smalltalk.send(k, "__plus", [prime]);})]);return count=smalltalk.send(count, "__plus", [(1)]);})]);})]);})]);
+return count;
+return self;},
+source: unescape('benchmark%20%20%22Handy%20bytecode-heavy%20benchmark%22%0A%09%22%28500000%20//%20time%20to%20run%29%20%3D%20approx%20bytecodes%20per%20second%22%0A%09%225000000%20//%20%28Time%20millisecondsToRun%3A%20%5B10%20benchmark%5D%29%20*%201000%22%0A%09%223059000%20on%20a%20Mac%208100/100%22%0A%20%20%20%20%7C%20size%20flags%20prime%20k%20count%20%7C%0A%20%20%20%20size%20%3A%3D%208190.%0A%20%20%20%201%20to%3A%20self%20do%3A%0A%20%20%20%20%20%20%20%20%5B%3Aiter%20%7C%0A%20%20%20%20%20%20%20%20count%20%3A%3D%200.%0A%20%20%20%20%20%20%20%20flags%20%3A%3D%20Array%20new.%0A%20%20%20%20%20%20%20%20size%20timesRepeat%3A%20%5B%20flags%20add%3A%20true%5D.%0A%20%20%20%20%20%20%20%201%20to%3A%20size%20do%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B%3Ai%20%7C%20%28flags%20at%3A%20i%29%20ifTrue%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5Bprime%20%3A%3D%20i+1.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20k%20%3A%3D%20i%20+%20prime.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5Bk%20%3C%3D%20size%5D%20whileTrue%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5Bflags%20at%3A%20k%20put%3A%20false.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20k%20%3A%3D%20k%20+%20prime%5D.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20count%20%3A%3D%20count%20+%201%5D%5D%5D.%0A%20%20%20%20%5E%20count'),
+messageSends: ["to:do:", "new", "timesRepeat:", "add:", "ifTrue:", "at:", unescape("+"), "whileTrue:", unescape("%3C%3D"), "at:put:"],
+referencedClasses: [smalltalk.Array]
+}),
+smalltalk.Number);
+
+smalltalk.addMethod(
+'_tinyBenchmarks',
+smalltalk.method({
+selector: 'tinyBenchmarks',
+category: '*Benchfib',
+fn: function (){
+var self=this;
+var t1=nil;
+var t2=nil;
+var r=nil;
+var n1=nil;
+var n2=nil;
+n1=(1);
+smalltalk.send((function(){t1=smalltalk.send(smalltalk.Date, "_millisecondsToRun_", [(function(){return smalltalk.send(n1, "_benchmark", []);})]);return smalltalk.send(t1, "__lt", [(1000)]);}), "_whileTrue_", [(function(){return n1=smalltalk.send(n1, "__star", [(2)]);})]);
+n2=(28);
+smalltalk.send((function(){t2=smalltalk.send(smalltalk.Date, "_millisecondsToRun_", [(function(){return r=smalltalk.send(n2, "_benchFib", []);})]);return smalltalk.send(t2, "__lt", [(1000)]);}), "_whileTrue_", [(function(){return n2=smalltalk.send(n2, "__plus", [(1)]);})]);
+return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(n1, "__star", [(500000)]), "__star", [(1000)]), "__slash", [t1]), "_printString", []), "__comma", [unescape("%20bytecodes/sec%3B%20")]), "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(r, "__star", [(1000)]), "__slash", [t2]), "_printString", [])]), "__comma", [unescape("%20sends/sec")]);
+return self;},
+source: unescape('tinyBenchmarks%0A%09%22Report%20the%20results%20of%20running%20the%20two%20tiny%20Squeak%20benchmarks.%0A%09ar%209/10/1999%3A%20Adjusted%20to%20run%20at%20least%201%20sec%20to%20get%20more%20stable%20results%22%0A%09%220%20tinyBenchmarks%22%0A%09%22On%20a%20292%20MHz%20G3%20Mac%3A%2022727272%20bytecodes/sec%3B%20984169%20sends/sec%22%0A%09%22On%20a%20400%20MHz%20PII/Win98%3A%20%2018028169%20bytecodes/sec%3B%201081272%20sends/sec%22%0A%09%7C%20t1%20t2%20r%20n1%20n2%20%7C%0A%09n1%20%3A%3D%201.%0A%09%5Bt1%20%3A%3D%20Date%20millisecondsToRun%3A%20%5Bn1%20benchmark%5D.%0A%09t1%20%3C%201000%5D%20whileTrue%3A%5Bn1%20%3A%3D%20n1%20*%202%5D.%20%22Note%3A%20%23benchmark%27s%20runtime%20is%20about%20O%28n%29%22%0A%0A%09n2%20%3A%3D%2028.%0A%09%5Bt2%20%3A%3D%20Date%20millisecondsToRun%3A%20%5Br%20%3A%3D%20n2%20benchFib%5D.%0A%09t2%20%3C%201000%5D%20whileTrue%3A%5Bn2%20%3A%3D%20n2%20+%201%5D.%20%0A%09%22Note%3A%20%23benchFib%27s%20runtime%20is%20about%20O%28k%5En%29%2C%0A%09%09where%20k%20is%20the%20golden%20number%20%3D%20%281%20+%205%20sqrt%29%20/%202%20%3D%201.618....%22%0A%0A%09%5E%20%28%28n1%20*%20500000%20*%201000%29%20/%20t1%29%20printString%2C%20%27%20bytecodes/sec%3B%20%27%2C%0A%09%20%20%28%28r%20*%201000%29%20/%20t2%29%20printString%2C%20%27%20sends/sec%27'),
+messageSends: ["whileTrue:", "millisecondsToRun:", "benchmark", unescape("%3C"), unescape("*"), "benchFib", unescape("+"), unescape("%2C"), "printString", unescape("/")],
+referencedClasses: [smalltalk.Date]
+}),
+smalltalk.Number);
+

+ 2 - 6
nodejs/README

@@ -2,13 +2,9 @@ JTalk + Node.js = Awesomeness
 =============================
 These are some experiments of using JTalk together with Node.js:
 
-jtalkc          - a bash script for compiling JTalk programs.
-nodecompile.js  - Node.js javascript code for compiling .st files, used by jtalkc.
-
 hello           - Hello world example with a simple Makefile.
+benchfib        - Port of tinybenchmarks from Squeak.
 trivialserver   - A slightly larger example.
 trivialserver2  - A variation on trivialserver that tries to do more in JTalk.
 
-You will need "node" in your path to try examples.
-
-
+You will need "node" in your path to try all the above.

+ 2 - 2
nodejs/benchfib/Makefile

@@ -1,8 +1,8 @@
 Program.js: Benchfib.st
-	../jtalkc -N -m Benchfib Benchfib.st Program
+	../jtalkc -N -O -m Benchfib Benchfib.st Program
 
 run: Program.js
 	./benchfib
 
 clean:
-	rm Program.js Benchfib.js
+	rm Program.js* Benchfib.js

+ 56 - 16
nodejs/jtalkc

@@ -7,22 +7,26 @@ JTALK=`dirname ${0}`/..
 
 function usage {
 	cat <<ENDOFHELP
-Usage: $0 [-N|D] [-K|C] [-m class] [-M file] [-i] [-I file] file1 [file2 ...] [Program]
+Usage: $0 [-N|D] [-K|C] [-o] [-O] [-m class] [-M file] [-i] [-I file] file1 [file2 ...] [Program]
 
-   Will compile Jtalk files in a variety of ways.
+   Will compile Jtalk files - either separately or into a runnable complete program.
    Files listed will be handled using these rules:
 
-     *.js files are concatenated as is. If not found we look in $JTALK/js
+   *.js
+     Files are concatenated in listed order. If not found we look in $JTALK/js
 
-     *.st files are compiled into .js files. If not found we look in $JTALK/st.
-     Each file is currently considered to be a fileout of a single class
-     category of the same name as the file.
+   *.st
+     Files are compiled into .js files before concatenated. If not found we look
+     in $JTALK/st.
 
-   If no Program is specified only each given .st file will be compiled into a .js file.
-   Otherwise a Program.js file is linked together based on the given options described below:
+     NOTE: Each file is currently considered to be a fileout of a single class
+     category of the same name as the file!
+
+   If no Program is specified each given .st file will be compiled into a .js file.
+   Otherwise a <Program>.js file is linked together based on the options:
 
   -N or -D
-     Compile for Node.js or D8 (V8 shell). Defaults to "-Kim Main" so boot.js and Kernel.js
+     Compile for Node.js or D8 (V8 shell). Implies "-K -i -m Main" so boot.js and Kernel.js
      are added first and init.js is added last with a call to Main class>>main.
 
   -K
@@ -31,6 +35,18 @@ Usage: $0 [-N|D] [-K|C] [-m class] [-M file] [-i] [-I file] file1 [file2 ...] [P
   -C
      Add libraries to get minimal JTalk Compiler running.
 
+  -o
+     Optimize each js file using the Google closure compiler. Using ~/compiler.jar    
+
+  -O
+     Optimize <Program>.js using the Google closure compiler. Using ~/compiler.jar
+
+  -l libray1,library2
+     Load listed libraries (no spaces) in Compiler before compiling.
+
+  -L
+     Loads all libraries in directory js in Compiler before compiling.
+
   -i
      Add library standard initializer $JTALK/js/init.js
 
@@ -75,6 +91,7 @@ fi
 BOOT="$JTALK/js/boot.js"
 KERNEL="$BOOT $JTALK/js/Kernel.js"
 COMPILER="$KERNEL $JTALK/js/Parser.js $JTALK/js/Compiler.js"
+CANVAS="$COMPILER $JTALK/js/Canvas.js"
 
 # Predefined initializer
 INITIALIZER="$JTALK/js/init.js"
@@ -85,10 +102,10 @@ INIT=
 MAIN=
 MAINFILE=
 BASE=$KERNEL
-OURCOMPILER="$COMPILER $JTALK/js/init.js $JTALK/nodejs/nodecompile.js"
+LOAD=
 
 # Read options and shift them away
-while getopts "NDKCiI:M:m:h?" o; do
+while getopts "NDKCoOl:LiI:M:m:h?" o; do
 case "$o" in
    N) ENV=NODE
       BASE=$KERNEL
@@ -100,6 +117,10 @@ case "$o" in
       MAIN=Main;;
    K) BASE=$KERNEL;;
    C) BASE=$COMPILER;;
+   o) CLOSURE=true;;
+   O) CLOSUREFULL=true;;
+   l) LOAD=$OPTARG;;
+   L) LOAD="$JTALK/*.js";;
    I) INIT=$INITIALIZER;;
    i) INIT=$OPTARG;;
    M) MAINFILE=$OPTARG;;
@@ -110,6 +131,10 @@ case "$o" in
 done
 shift $(($OPTIND - 1))
 
+# Define our Compiler
+# We need to add extra listed libraries in $LOAD not already in $CANVAS
+OURCOMPILER="$CANVAS $JTALK/js/init.js $JTALK/nodejs/nodecompile.js"
+
 # Combine supplied libraries
 LIBS="$BASE $ADDONS"
 
@@ -182,6 +207,18 @@ do
   fi 
 done
 
+if [ ! -z $CLOSURE ]; then
+  echo "Compiling all js files using Google closure compiler."
+
+  ALLJSFILES="$COMPILED $LIBS"
+  for FILE in $ALLJSFILES
+  do
+    mv $FILE $FILE.original
+    java -jar ~/compiler.jar --js $FILE.original --js_output_file $FILE
+    rm $FILE.original
+  done
+fi
+
 
 if [ -z $PROGRAM ]; then
   echo "Done."
@@ -234,9 +271,12 @@ echo "Writing $PROGRAM.js ..."
 cat $LIBS $COMPILED $INIT $MAIN > $PROGRAM.js
 echo "Done."
 
-# Optionally run Program and give all args left to it
-if [ -n "$RUN" ]; then
-  echo "Running program"
-  echo "---------------"
-  node $PROGRAM.js $@
+
+if [ ! -z $CLOSUREFULL ]; then
+  echo "Compiling $PROGRAM.js file using Google closure compiler."
+  mv $PROGRAM.js $PROGRAM.js.original
+  java -jar ~/compiler.jar --js $PROGRAM.js.original --js_output_file $PROGRAM.js
+  rm $PROGRAM.js.original
+  echo "Done."
 fi
+

+ 70 - 0
st/Benchfib.st

@@ -0,0 +1,70 @@
+Object subclass: #Benchfib
+	instanceVariableNames: ''
+	category: 'Benchfib'!
+
+!Benchfib class methodsFor: 'not yet classified'!
+
+main
+
+	| result |
+	result := 0 tinyBenchmarks.
+	{'console.log(''0 tinyBenchmarks => '' + result);'}
+! !
+
+!Number methodsFor: '*Benchfib'!
+
+benchFib
+	"Handy send-heavy benchmark"
+	"(result // seconds to run) = approx calls per second"
+	" | r t |
+	  t := Time millisecondsToRun: [r := 26 benchFib].
+	  (r * 1000) // t"
+	"138000 on a Mac 8100/100"
+	^ self < 2
+		ifTrue: [1] 
+		ifFalse: [(self-1) benchFib + (self-2) benchFib + 1]
+!
+
+benchmark  "Handy bytecode-heavy benchmark"
+	"(500000 // time to run) = approx bytecodes per second"
+	"5000000 // (Time millisecondsToRun: [10 benchmark]) * 1000"
+	"3059000 on a Mac 8100/100"
+    | size flags prime k count |
+    size := 8190.
+    1 to: self do:
+        [:iter |
+        count := 0.
+        flags := Array new.
+        size timesRepeat: [ flags add: true].
+        1 to: size do:
+            [:i | (flags at: i) ifTrue:
+                [prime := i+1.
+                k := i + prime.
+                [k <= size] whileTrue:
+                    [flags at: k put: false.
+                    k := k + prime].
+                count := count + 1]]].
+    ^ count
+!
+
+tinyBenchmarks
+	"Report the results of running the two tiny Squeak benchmarks.
+	ar 9/10/1999: Adjusted to run at least 1 sec to get more stable results"
+	"0 tinyBenchmarks"
+	"On a 292 MHz G3 Mac: 22727272 bytecodes/sec; 984169 sends/sec"
+	"On a 400 MHz PII/Win98:  18028169 bytecodes/sec; 1081272 sends/sec"
+	| t1 t2 r n1 n2 |
+	n1 := 1.
+	[t1 := Date millisecondsToRun: [n1 benchmark].
+	t1 < 1000] whileTrue:[n1 := n1 * 2]. "Note: #benchmark's runtime is about O(n)"
+
+	n2 := 28.
+	[t2 := Date millisecondsToRun: [r := n2 benchFib].
+	t2 < 1000] whileTrue:[n2 := n2 + 1]. 
+	"Note: #benchFib's runtime is about O(k^n),
+		where k is the golden number = (1 + 5 sqrt) / 2 = 1.618...."
+
+	^ ((n1 * 500000 * 1000) / t1) printString, ' bytecodes/sec; ',
+	  ((r * 1000) / t2) printString, ' sends/sec'
+! !
+