19b77c36 |
(in-package :cl-wasm)
|
f393694d |
(declaim (inline signed invsigned))
(eval-when (:compile-toplevel :load-toplevel :execute)
(defun signed (n i)
(if (and (<= 0 i)
(< i (expt 2 (1- n))))
i
(- i (expt 2 n))))
(defun invsigned (n i)
(if (< i 0)
(+ i (expt 2 n))
i)))
|
19b77c36 |
(defgeneric run-inst (client stack locals instruction argument)
(:method (client (stack list) (locals vector) (instruction (eql :get-local)) (argument number))
(cons (aref locals argument)
stack)))
(defmacro define-numeric-instruction (suffix (&optional (arg '(argument null))) &body body)
(let ((i32-name (alexandria:make-keyword (format nil "~a.~a" :i32 suffix)))
(i64-name (alexandria:make-keyword (format nil "~a.~a" :i64 suffix)))
(f32-name (alexandria:make-keyword (format nil "~a.~a" :f32 suffix)))
(f64-name (alexandria:make-keyword (format nil "~a.~a" :f64 suffix))))
(flet ((get-argument (type)
(case type
(:i32 (list (car arg)
(case (cadr arg)
(:type 'integer)
(t (cadr arg)))))
(:i64 (list (car arg)
(case (cadr arg)
(:type 'integer)
(t (cadr arg)))))
(:f32 (list (car arg)
(case (cadr arg)
(:type 'single-float)
(t (cadr arg)))))
(:f64 (list (car arg)
(case (cadr arg)
(:type 'double-float)
(t (cadr arg))))))))
`(macrolet ((numeric-dispatch (&body forms)
(cons 'or forms)))
(defmethod run-inst (client (stack list) (locals vector) (inst (eql ,i32-name)) ,(get-argument :i32))
|
f393694d |
(declare (optimize (speed 1) (safety 1)))
|
19b77c36 |
(macrolet ((numeric-case (type &body body)
(when (eql type :i32)
(cons 'progn body))))
(let ((numeric-type '(integer 0 #.(1- (expt 2 32))))
(size 32))
(declare (ignorable numeric-type size))
,@body)))
(defmethod run-inst (client (stack list) (locals vector) (inst (eql ,i64-name)) ,(get-argument :i64))
|
f393694d |
(declare (optimize (speed 1) (safety 1)))
|
19b77c36 |
(macrolet ((numeric-case (type &body body)
(when (eql type :i64)
(cons 'progn body))))
|
f393694d |
(let ((numeric-type '(integer 0 #.(1- (expt 2 64))))
|
19b77c36 |
(size 64))
(declare (ignorable numeric-type size))
,@body)))
(defmethod run-inst (client (stack list) (locals vector) (inst (eql ,f32-name)) ,(get-argument :f32))
|
f393694d |
(declare (optimize (speed 1) (safety 1)))
|
19b77c36 |
(macrolet ((numeric-case (type &body body)
(when (eql type :f32)
(cons 'progn body))))
(let ((numeric-type 'single-float)
(size 32))
(declare (ignorable numeric-type size))
,@body)))
(defmethod run-inst (client (stack list) (locals vector) (inst (eql ,f64-name)) ,(get-argument :f64))
|
f393694d |
(declare (optimize (speed 1) (safety 1)))
|
19b77c36 |
(macrolet ((numeric-case (type &body body)
(when (eql type :f64)
(cons 'progn body))))
(let ((numeric-type 'double-float)
(size 64))
(declare (ignorable numeric-type size))
,@body)))))))
(define-numeric-instruction add ()
(let ((result (+ (coerce (pop stack) numeric-type)
(coerce (pop stack) numeric-type))))
(cons (numeric-dispatch
(numeric-case :i32 (mod result #.(expt 2 32)))
(numeric-case :i64 (mod result #.(expt 2 64)))
(numeric-case :f32 result)
(numeric-case :f64 result))
stack)))
(define-numeric-instruction mul ()
(let ((result (* (coerce (pop stack) numeric-type)
(coerce (pop stack) numeric-type))))
(cons (numeric-dispatch
(numeric-case :i32 (mod result #.(expt 2 32)))
(numeric-case :i64 (mod result #.(expt 2 64)))
(numeric-case :f32 result)
(numeric-case :f64 result))
stack)))
(define-numeric-instruction const ((arg :type))
(cons (coerce arg numeric-type)
stack))
(define-numeric-instruction sub ()
(let ((i2 (pop stack))
(i1 (pop stack)))
(declare (ignorable i1 i2))
(cons (numeric-dispatch
(numeric-case :i32 (mod (+ (- (coerce i1 numeric-type)
(coerce i2 numeric-type))
#.(expt 2 32))
#.(expt 2 32)))
(numeric-case :i64 (mod (+ (- (coerce i1 numeric-type)
(coerce i2 numeric-type))
#.(expt 2 64))
#.(expt 2 64)))
(numeric-case :f32 (- (coerce i1 numeric-type)
(coerce i2 numeric-type)))
(numeric-case :f64 (- (coerce i1 numeric-type)
(coerce i2 numeric-type))))
stack)))
(define-numeric-instruction div_u ()
(let ((i2 (pop stack))
(i1 (pop stack)))
(declare (ignorable i1 i2))
(cons (numeric-dispatch
(numeric-case :i32 (mod (truncate (coerce i1 numeric-type)
(coerce i2 numeric-type))
#.(expt 2 32)))
(numeric-case :i64 (mod (truncate (coerce i1 numeric-type)
(coerce i2 numeric-type))
#.(expt 2 64)))
(numeric-case :f32 (error "floating div not implemented"))
(numeric-case :f64 (error "floating div not implemented")))
stack)))
(define-numeric-instruction div_s ()
(let* ((i2 (coerce (pop stack) numeric-type))
|
f393694d |
(j2 (signed size i2))
|
19b77c36 |
(i1 (coerce (pop stack) numeric-type))
|
f393694d |
(j1 (signed size i1)))
|
19b77c36 |
(declare (ignorable i1 i2 j1 j2))
(cons (numeric-dispatch
|
f393694d |
(numeric-case :i32 (if (/= (truncate i1 i2) #.(expt 2 31))
(invsigned 32 (truncate j1 j2))
|
19b77c36 |
(error "undefined result")))
(numeric-case :i64 (if (/= (truncate (coerce i1 numeric-type)
(coerce i2 numeric-type))
#.(expt 2 63))
|
f393694d |
(invsigned 64 (truncate j1 j2))
|
19b77c36 |
(error "undefined result")))
(numeric-case :f32 (error "floating div not implemented"))
(numeric-case :f64 (error "floating div not implemented")))
stack)))
(define-numeric-instruction rem_u ()
(let ((i2 (pop stack))
(i1 (pop stack)))
(declare (ignorable i1 i2))
(cons (numeric-dispatch
(numeric-case :i32 (mod (- (coerce i1 numeric-type)
(* (coerce i2 numeric-type)
(truncate i1 i2)))
#.(expt 2 32)))
(numeric-case :i64 (mod (- (coerce i1 numeric-type)
(* (coerce i2 numeric-type)
(truncate i1 i2)))
#.(expt 2 64)))
(numeric-case :f32 (error "floating rem not implemented"))
(numeric-case :f64 (error "floating rem not implemented")))
stack)))
(define-numeric-instruction rem_s ()
(let* ((i2 (pop stack))
(j2 (signed size i2))
(i1 (pop stack))
(j1 (signed size i1)))
(declare (ignorable i1 i2 j1 j2))
(cons (numeric-dispatch
|
f393694d |
(numeric-case :i32 (mod (- j1 (* j2
(truncate j1 j2)))
|
19b77c36 |
#.(expt 2 32)))
|
f393694d |
(numeric-case :i64 (mod (- j1 (* j2
(truncate j1 j2)))
|
19b77c36 |
#.(expt 2 64)))
(numeric-case :f32 (error "floating rem not implemented"))
(numeric-case :f64 (error "floating rem not implemented")))
stack)))
(define-numeric-instruction rem_s ()
(let* ((i2 (pop stack))
(j2 (signed size i2))
(i1 (pop stack))
(j1 (signed size i1)))
(declare (ignorable i1 i2 j1 j2))
(cons (numeric-dispatch
(numeric-case :i32 (mod (- (coerce j1 numeric-type)
(* (coerce j2 numeric-type)
(truncate j1 j2)))
#.(expt 2 32)))
(numeric-case :i64 (mod (- (coerce j1 numeric-type)
(* (coerce j2 numeric-type)
(truncate j1 j2)))
#.(expt 2 64)))
(numeric-case :f32 (error "floating rem not implemented"))
(numeric-case :f64 (error "floating rem not implemented")))
stack)))
(define-numeric-instruction and ()
(let* ((i2 (coerce (pop stack)
numeric-type))
(i1 (coerce (pop stack)
numeric-type)))
(declare (ignorable i1 i2))
(cons (numeric-dispatch
(numeric-case :i32 (logand #.(1- (expt 2 32))
(logand i1 i2)))
(numeric-case :i64 (logand #.(1- (expt 2 64))
(logand i1 i2)))
(numeric-case :f32 (error "floating rem not implemented"))
(numeric-case :f64 (error "floating rem not implemented")))
stack)))
(define-numeric-instruction or ()
(let* ((i2 (coerce (pop stack)
numeric-type))
(i1 (coerce (pop stack)
numeric-type)))
(declare (ignorable i1 i2))
(cons (numeric-dispatch
(numeric-case :i32 (logand #.(1- (expt 2 32))
(logior i1 i2)))
(numeric-case :i64 (logand #.(1- (expt 2 64))
(logior i1 i2)))
(numeric-case :f32 (error "floating rem not implemented"))
(numeric-case :f64 (error "floating rem not implemented")))
stack)))
(define-numeric-instruction xor ()
(let* ((i2 (coerce (pop stack)
numeric-type))
(i1 (coerce (pop stack)
numeric-type)))
(declare (ignorable i1 i2))
(cons (numeric-dispatch
(numeric-case :i32 (logand #.(1- (expt 2 32))
(logxor i1 i2)))
(numeric-case :i64 (logand #.(1- (expt 2 64))
(logxor i1 i2)))
(numeric-case :f32 (error "floating rem not implemented"))
(numeric-case :f64 (error "floating rem not implemented")))
stack)))
|
f393694d |
(define-numeric-instruction shl ()
(let* ((i2 (coerce (pop stack)
numeric-type))
(i1 (coerce (pop stack)
numeric-type)))
(declare (ignorable i1 i2))
(cons (numeric-dispatch
(numeric-case :i32 (mod (ash i1 i2)
#.(expt 2 32)))
(numeric-case :i64 (mod (ash i1 i2)
#.(expt 2 64)))
(numeric-case :f32 (error "floating rem not implemented"))
(numeric-case :f64 (error "floating rem not implemented")))
stack)))
(define-numeric-instruction shr_u ()
(let* ((i2 (coerce (pop stack)
numeric-type))
(i1 (coerce (pop stack)
numeric-type)))
(declare (ignorable i1 i2))
(cons (numeric-dispatch
(numeric-case :i32 (mod (ash i1 (- i2))
#.(expt 2 32)))
(numeric-case :i64 (mod (ash i1 (- i2))
#.(expt 2 64)))
(numeric-case :f32 (error "floating rem not implemented"))
(numeric-case :f64 (error "floating rem not implemented")))
stack)))
(define-numeric-instruction shr_s ()
(let* ((i2 (coerce (pop stack)
numeric-type))
(i1 (coerce (pop stack)
numeric-type)))
(declare (ignorable i1 i2))
(cons (numeric-dispatch
(numeric-case :i32 (mod (ash (logand -1 i1)
(- i2))
#.(expt 2 32)))
(numeric-case :i64 (mod (ash (logand -1 i1)
(- i2))
#.(expt 2 64)))
(numeric-case :f32 (error "floating rem not implemented"))
(numeric-case :f64 (error "floating rem not implemented")))
stack)))
|
19b77c36 |
(fw.lu:defclass+ tracer ()
((%level :initarg :level :accessor level)))
(fw.lu:defclass+ wat-emitter ()
((%level :initarg :level :accessor level)))
(defvar *client*
(tracer 0))
(defmethod run-inst :around ((client tracer) stack locals instruction argument)
(format t "~&~vt> ~s ~s ~s~%~vt~8t|~{~s~^ ~}|"
(level client) locals instruction argument
(level client) (reverse stack))
(incf (level client))
(unwind-protect
(let ((out (call-next-method)))
(prog1 out
(format t "~&~vt<~8t|~{~s~^ ~}|~%"
(level client) (reverse out))))
(decf (level client))))
(defmethod run-inst :around ((client wat-emitter) stack locals instruction argument)
(incf (level client))
(unwind-protect
(let ((out (call-next-method)))
(let ((*print-case* :downcase))
(format t "~&~4t~a~:[~; ~:*~a~]" instruction argument))
out)
(decf (level client))))
(defgeneric pre-interpret (client)
(:method (client)))
(defgeneric post-interpret (client)
(:method (client)))
(defmethod pre-interpret ((client wat-emitter))
(format t "~&(module (func $it (result i32)"))
(defmethod post-interpret ((client wat-emitter))
(format t ")
(export \"it\" (func $it)))~%"))
(defun interpret (instructions locals)
(pre-interpret *client*)
(let ((stack ()))
(loop for (instruction argument) in instructions
do (setf stack
(run-inst *client* stack locals instruction argument)))
(post-interpret *client*)
stack))
(defun test-responder ()
(spinneret:with-html-string
(:html
(:body
(:script :src "https://localhost/~elangley/libwabt.js")
|
f393694d |
(:script
(ps:ps
(let* ((ws (ps:new (-web-socket "ws://localhost:5001/ws")))
(compile-wat (lambda (m)
(lambda (wabt)
(ps:chain ws
(send
(+ "result "
(ps:chain
(setf (ps:@ window module)
(ps:new
((ps:@ -web-assembly -instance)
(ps:new
((ps:@ -web-assembly -module)
(ps:chain wabt
(parse-wat "foo.wast"
(ps:@ m data))
(to-binary
(ps:create log ps:t
write_debug_names ps:t))
buffer))))))
exports
(it))))))))
(message-handler (lambda (m)
(ps:chain console (log (ps:@ m data)))
(ps:chain (ps:new (-wabt-module))
(then (compile-wat m))))))
(ps:chain ws
(add-event-listener "message" message-handler))
(ps:chain ws
(add-event-listener "close"
(lambda (_)
(setf ws (ps:new (-web-socket "ws://localhost:5001/ws")))
(ps:chain ws
(add-event-listener "message" message-handler))))))))))))
(defclass wasm-session (hunchensocket:websocket-resource)
((name :initarg :name :reader name)))
(defvar *wasm-sessions*
(make-array 10 :fill-pointer 0 :adjustable t))
(defmethod hunchensocket:text-message-received ((resource wasm-session) client message)
(format t "~&in: ~a~%" message))
(defun find-wasm-session (request)
(or (find (hunchentoot:script-name request)
*wasm-sessions*
:test #'string=
:key 'name)
(fw.lu:prog1-bind (session (make-instance 'wasm-session
:name (hunchentoot:script-name request)))
(vector-push-extend session
*wasm-sessions*))))
(pushnew 'find-wasm-session
hunchensocket:*websocket-dispatch-table*)
(defun broadcast (session message)
(loop for peer in (hunchensocket:clients session)
do (hunchensocket:send-text-message peer message)))
(defclass my-acceptor (hunchensocket:websocket-acceptor)
())
(defmethod hunchentoot:acceptor-dispatch-request ((acceptor my-acceptor) request)
(if (string= "/" (hunchentoot:script-name request))
(test-responder)
(call-next-method)))
|
19b77c36 |
(defvar *app*)
(defvar *handler*)
|
f393694d |
|
19b77c36 |
(defun demo ()
|
f393694d |
(let ((app (make-instance 'my-acceptor :port 5001)))
(values (hunchentoot:start app)
|
19b77c36 |
app)))
(defun go* ()
(setf (values *handler* *app*)
(demo)))
|
f393694d |
#|
i32.clz
i32.ctz
i32.popcnt
i32.shl
i32.shr_s
i32.shr_u
i32.rotl
i32.rotr
i64.clz
i64.ctz
i64.popcnt
i64.shl
i64.shr_s
i64.shr_u
i64.rotl
i64.rotr
f32.abs
f32.neg
f32.ceil
f32.floor
f32.trunc
f32.nearest
f32.sqrt
f32.div
f32.min
f32.max
f32.copysign
f64.abs
f64.neg
f64.ceil
f64.floor
f64.trunc
f64.nearest
f64.sqrt
f64.div
f64.min
f64.max
f64.copysign
i32.eqz
i32.eq
i32.ne
i32.lt_s
i32.lt_u
i32.gt_s
i32.gt_u
i32.le_s
i32.le_u
i32.ge_s
i32.ge_u
i64.eqz
i64.eq
i64.ne
i64.lt_s
i64.lt_u
i64.gt_s
i64.gt_u
i64.le_s
i64.le_u
i64.ge_s
i64.ge_u
f32.eq
f32.ne
f32.lt
f32.gt
f32.le
f32.ge
f64.eq
f64.ne
f64.lt
f64.gt
f64.le
f64.ge
i32.wrap_i64
i32.trunc_f32_s
i32.trunc_f32_u
i32.trunc_f64_s
i32.trunc_f64_u
i64.extend_i32_s
i64.extend_i32_u
i64.trunc_f32_s
i64.trunc_f32_u
i64.trunc_f64_s
i64.trunc_f64_u
f32.convert_i32_s
f32.convert_i32_u
f32.convert_i64_s
f32.convert_i64_u
f32.demote_f64
f64.convert_i32_s
f64.convert_i32_u
f64.convert_i64_s
f64.convert_i64_u
f64.promote_f32
i32.reinterpret_f32
i64.reinterpret_f64
f32.reinterpret_i32
f64.reinterpret_i64
|#
|