Thanks, you are right, much better to use the built-in key stuff
(defun (setf jfield) (newvalue class-ref-or-field field-or-instance &optional ( instance nil instance-supplied-p) unused-value) (declare (ignore unused-value)) (if instance-supplied-p (jfield class-ref-or-field field-or-instance instance newvalue) (jfield class-ref-or-field field-or-instance newvalue)))
----- Original Message ----- From: "Thomas Russ" tar@ISI.EDU To: dmiles@users.sourceforge.net Sent: Tuesday, November 24, 2009 9:24 AM Subject: Re: [armedbear-devel] SETF for JFEILDS
On Nov 23, 2009, at 6:47 AM, logicmoo@gmail.com wrote:
So actually
(defun (setf jfield) (newvalue class-ref-or-field field-or- instance &optional ( instance :noinst) unusedvalue) (if (eq instance :noinst) (jfield class-ref-or-field field-or-instance newvalue) (jfield class-ref-or-field field-or-instance instance newvalue)))
Would be a little better.. good eye.
For what it's worth, I am not a fan of using special values to determine whether optional (or keyword) arguments are actually passed or not. I prefer to use the predicate forms from the lambda list, so something more like
(defun (setf jfield) (newvalue class-ref-or-field field-or-instance &optional ( instance nil instance-supplied-p) unusedvalue) (declare (ignore unusedvalue)) (if instance-supplied-p (jfield class-ref-or-field field-or-instance newvalue) (jfield class-ref-or-field field-or-instance instance newvalue)))
----- Original Message ----- From: dmiles@users.sourceforge.net To: "Alessio Stalla" alessiostalla@gmail.com Cc: "Armed Bear" armedbear-devel@common-lisp.net Sent: Monday, November 23, 2009 6:27 AM Subject: Re: [armedbear-devel] SETF for JFEILDS
----- Original Message ----- From: "Alessio Stalla" alessiostalla@gmail.com To: dmiles@users.sourceforge.net Cc: "Armed Bear" armedbear-devel@common-lisp.net Sent: Monday, November 23, 2009 5:42 AM Subject: Re: [armedbear-devel] SETF for JFEILDS
On Mon, Nov 23, 2009 at 2:36 PM, logicmoo@gmail.com wrote:
Does anyone object to adding this to java.lisp? If not could it be done?
(defun (setf jfield) (newvalue class-ref-or-field field-or-instance &optional ( instance :noinst) (value :novalue)) (if (eq instance :noinst) (jfield class-ref-or-field field-or-instance newvalue) (jfield class-ref-or-field field-or-instance instance newvalue)))
It seems a nice idea to me, but there are a couple of things that I don't understand:
A>- why :noinst and not simply nil?
JFIELD is defined as: class-ref-or-field field-or-instance &optional instance value The valid argument patterns for this operation are: (class-ref field-name): to retrieve the value of a static field. (class-ref field-name instance-ref): to retrieve the value of a class field of the instance. (class-ref field-name primitive-value:) to store primitive-value in a static field. (class-ref field-name instance-ref value): to store value in a class field of the instance. (class-ref field-name nil value): to store value in a static field (when value may be confused with an instance-ref). (field-name instance): to retrieve the value of a field of the instance. The class is derived from the instance. (field-name instance value): to store value in a field of the instance. The class is derived from the instance.
JFIELD doesn't distingusih between static and non static fields
Also cases of "class-ref field-name instance-ref value" (accessing superclass field)
Depending on how the field is defined
(setf (jfield *MyClass* "someStaticBooleanField") NIL) it is distinguable from (setf (jfield *MySuperClass* "nonStaticBooleanField" *my- instance* ) NIL)
A>- value is not used, what's the point of it?
correct the "default :novalue" is not needed. (I was debugging and trying to find corner cases with all those bizzare legal jfield signatures )
but... "value" as an &optional was needed to match the signature of what is legal for jfield so things like this can work:
(define-symbol-macro %iscold (jfield "org.armedbear.lisp.Lisp" "cold")) %iscold ;; ==> NIL (setq %iscold T) ;; ==> T %iscold ;; ==> T (setq %iscold NIL) ;; ==> NIL
armedbear-devel mailing list armedbear-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
In case it is of some interest, the code below is what I use with jss. It's main element of interest is the "try-harder" flag, which uses setAccessible to allow setting some fields that would otherwise cause an exception.
(defun get-java-field (object field &optional try-harder) (if try-harder (let* ((class (if (symbolp object) (setq object (find-java-class object)) (if (equal "java.lang.Class" (jclass-name (jobject-class object)) ) object (jobject-class object)))) (jfield (if (java-object-p field) field (find field (#"getDeclaredFields" class) :key 'jfield-name :test 'equal)))) (#"setAccessible" jfield t) (values (#"get" jfield object) jfield)) (if (symbolp object) (let ((class (find-java-class object))) (#"peekStatic" 'invoke class field)) (#"peek" 'invoke object field))))
(defun set-java-field (object field value &optional try-harder) (if try-harder (let* ((class (if (symbolp object) (setq object (find-java-class object)) (if (equal "java.lang.Class" (jclass-name (jobject-class object)) ) object (jobject-class object)))) (jfield (if (java-object-p field) field (find field (#"getDeclaredFields" class) :key 'jfield-name :test 'equal)))) (#"setAccessible" jfield t) (values (#"set" jfield object value) jfield)) (if (symbolp object) (let ((class (find-java-class object))) (#"pokeStatic" 'invoke class field value)) (#"poke" 'invoke object field value))))
On Tue, Nov 24, 2009 at 4:27 PM, logicmoo@gmail.com wrote:
Thanks, you are right, much better to use the built-in key stuff
(defun (setf jfield) (newvalue class-ref-or-field field-or-instance &optional ( instance nil instance-supplied-p) unused-value) (declare (ignore unused-value)) (if instance-supplied-p (jfield class-ref-or-field field-or-instance instance newvalue) (jfield class-ref-or-field field-or-instance newvalue)))
----- Original Message ----- From: "Thomas Russ" tar@ISI.EDU To: dmiles@users.sourceforge.net Sent: Tuesday, November 24, 2009 9:24 AM Subject: Re: [armedbear-devel] SETF for JFEILDS
On Nov 23, 2009, at 6:47 AM, logicmoo@gmail.com wrote:
So actually
(defun (setf jfield) (newvalue class-ref-or-field field-or- instance &optional ( instance :noinst) unusedvalue) (if (eq instance :noinst) (jfield class-ref-or-field field-or-instance newvalue) (jfield class-ref-or-field field-or-instance instance newvalue)))
Would be a little better.. good eye.
For what it's worth, I am not a fan of using special values to determine whether optional (or keyword) arguments are actually passed or not. I prefer to use the predicate forms from the lambda list, so something more like
(defun (setf jfield) (newvalue class-ref-or-field field-or-instance &optional ( instance nil instance-supplied-p) unusedvalue) (declare (ignore unusedvalue)) (if instance-supplied-p (jfield class-ref-or-field field-or-instance newvalue) (jfield class-ref-or-field field-or-instance instance newvalue)))
----- Original Message ----- From: dmiles@users.sourceforge.net To: "Alessio Stalla" alessiostalla@gmail.com Cc: "Armed Bear" armedbear-devel@common-lisp.net Sent: Monday, November 23, 2009 6:27 AM Subject: Re: [armedbear-devel] SETF for JFEILDS
----- Original Message ----- From: "Alessio Stalla" alessiostalla@gmail.com To: dmiles@users.sourceforge.net Cc: "Armed Bear" armedbear-devel@common-lisp.net Sent: Monday, November 23, 2009 5:42 AM Subject: Re: [armedbear-devel] SETF for JFEILDS
On Mon, Nov 23, 2009 at 2:36 PM, logicmoo@gmail.com wrote:
Does anyone object to adding this to java.lisp? If not could it be done?
(defun (setf jfield) (newvalue class-ref-or-field field-or-instance &optional ( instance :noinst) (value :novalue)) (if (eq instance :noinst) (jfield class-ref-or-field field-or-instance newvalue) (jfield class-ref-or-field field-or-instance instance newvalue)))
It seems a nice idea to me, but there are a couple of things that I don't understand:
A>- why :noinst and not simply nil?
JFIELD is defined as: class-ref-or-field field-or-instance &optional instance value The valid argument patterns for this operation are: (class-ref field-name): to retrieve the value of a static field. (class-ref field-name instance-ref): to retrieve the value of a class field of the instance. (class-ref field-name primitive-value:) to store primitive-value in a static field. (class-ref field-name instance-ref value): to store value in a class field of the instance. (class-ref field-name nil value): to store value in a static field (when value may be confused with an instance-ref). (field-name instance): to retrieve the value of a field of the instance. The class is derived from the instance. (field-name instance value): to store value in a field of the instance. The class is derived from the instance.
JFIELD doesn't distingusih between static and non static fields
Also cases of "class-ref field-name instance-ref value" (accessing superclass field)
Depending on how the field is defined
(setf (jfield *MyClass* "someStaticBooleanField") NIL) it is distinguable from (setf (jfield *MySuperClass* "nonStaticBooleanField" *my- instance* ) NIL)
A>- value is not used, what's the point of it?
correct the "default :novalue" is not needed. (I was debugging and trying to find corner cases with all those bizzare legal jfield signatures )
but... "value" as an &optional was needed to match the signature of what is legal for jfield so things like this can work:
(define-symbol-macro %iscold (jfield "org.armedbear.lisp.Lisp" "cold")) %iscold ;; ==> NIL (setq %iscold T) ;; ==> T %iscold ;; ==> T (setq %iscold NIL) ;; ==> NIL
armedbear-devel mailing list armedbear-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
armedbear-devel mailing list armedbear-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
Alan, Thanks.. yeah that setAccessable is very useful. I helps resolve my temptation to make the jfield/jstatic and jcall secretly always setAccessable if !isAccessable! And the .getDeclared*s is equally important
Which reminds me - currently in ABCLs .java we are going to need to .patch #'jstatic to search the getDeclaredMethods() instead of getMethods() (And a couple other nits)
----- Original Message ----- From: "Alan Ruttenberg" alanruttenberg@gmail.com To: dmiles@users.sourceforge.net Cc: "Thomas Russ" tar@isi.edu; "Armed Bear" armedbear-devel@common-lisp.net Sent: Tuesday, November 24, 2009 1:33 PM Subject: Re: [armedbear-devel] SETF for JFEILDS
In case it is of some interest, the code below is what I use with jss. It's main element of interest is the "try-harder" flag, which uses setAccessible to allow setting some fields that would otherwise cause an exception.
(defun get-java-field (object field &optional try-harder) (if try-harder (let* ((class (if (symbolp object) (setq object (find-java-class object)) (if (equal "java.lang.Class" (jclass-name (jobject-class object)) ) object (jobject-class object)))) (jfield (if (java-object-p field) field (find field (#"getDeclaredFields" class) :key 'jfield-name :test 'equal)))) (#"setAccessible" jfield t) (values (#"get" jfield object) jfield)) (if (symbolp object) (let ((class (find-java-class object))) (#"peekStatic" 'invoke class field)) (#"peek" 'invoke object field))))
(defun set-java-field (object field value &optional try-harder) (if try-harder (let* ((class (if (symbolp object) (setq object (find-java-class object)) (if (equal "java.lang.Class" (jclass-name (jobject-class object)) ) object (jobject-class object)))) (jfield (if (java-object-p field) field (find field (#"getDeclaredFields" class) :key 'jfield-name :test 'equal)))) (#"setAccessible" jfield t) (values (#"set" jfield object value) jfield)) (if (symbolp object) (let ((class (find-java-class object))) (#"pokeStatic" 'invoke class field value)) (#"poke" 'invoke object field value))))
On Tue, Nov 24, 2009 at 4:27 PM, logicmoo@gmail.com wrote:
Thanks, you are right, much better to use the built-in key stuff
(defun (setf jfield) (newvalue class-ref-or-field field-or-instance &optional ( instance nil instance-supplied-p) unused-value) (declare (ignore unused-value)) (if instance-supplied-p (jfield class-ref-or-field field-or-instance instance newvalue) (jfield class-ref-or-field field-or-instance newvalue)))
----- Original Message ----- From: "Thomas Russ" tar@ISI.EDU To: dmiles@users.sourceforge.net Sent: Tuesday, November 24, 2009 9:24 AM Subject: Re: [armedbear-devel] SETF for JFEILDS
On Nov 23, 2009, at 6:47 AM, logicmoo@gmail.com wrote:
So actually
(defun (setf jfield) (newvalue class-ref-or-field field-or- instance &optional ( instance :noinst) unusedvalue) (if (eq instance :noinst) (jfield class-ref-or-field field-or-instance newvalue) (jfield class-ref-or-field field-or-instance instance newvalue)))
Would be a little better.. good eye.
For what it's worth, I am not a fan of using special values to determine whether optional (or keyword) arguments are actually passed or not. I prefer to use the predicate forms from the lambda list, so something more like
(defun (setf jfield) (newvalue class-ref-or-field field-or-instance &optional ( instance nil instance-supplied-p) unusedvalue) (declare (ignore unusedvalue)) (if instance-supplied-p (jfield class-ref-or-field field-or-instance newvalue) (jfield class-ref-or-field field-or-instance instance newvalue)))
----- Original Message ----- From: dmiles@users.sourceforge.net To: "Alessio Stalla" alessiostalla@gmail.com Cc: "Armed Bear" armedbear-devel@common-lisp.net Sent: Monday, November 23, 2009 6:27 AM Subject: Re: [armedbear-devel] SETF for JFEILDS
----- Original Message ----- From: "Alessio Stalla" alessiostalla@gmail.com To: dmiles@users.sourceforge.net Cc: "Armed Bear" armedbear-devel@common-lisp.net Sent: Monday, November 23, 2009 5:42 AM Subject: Re: [armedbear-devel] SETF for JFEILDS
On Mon, Nov 23, 2009 at 2:36 PM, logicmoo@gmail.com wrote:
Does anyone object to adding this to java.lisp? If not could it be done?
(defun (setf jfield) (newvalue class-ref-or-field field-or-instance &optional ( instance :noinst) (value :novalue)) (if (eq instance :noinst) (jfield class-ref-or-field field-or-instance newvalue) (jfield class-ref-or-field field-or-instance instance newvalue)))
It seems a nice idea to me, but there are a couple of things that I don't understand:
A>- why :noinst and not simply nil?
JFIELD is defined as: class-ref-or-field field-or-instance &optional instance value The valid argument patterns for this operation are: (class-ref field-name): to retrieve the value of a static field. (class-ref field-name instance-ref): to retrieve the value of a class field of the instance. (class-ref field-name primitive-value:) to store primitive-value in a static field. (class-ref field-name instance-ref value): to store value in a class field of the instance. (class-ref field-name nil value): to store value in a static field (when value may be confused with an instance-ref). (field-name instance): to retrieve the value of a field of the instance. The class is derived from the instance. (field-name instance value): to store value in a field of the instance. The class is derived from the instance.
JFIELD doesn't distingusih between static and non static fields
Also cases of "class-ref field-name instance-ref value" (accessing superclass field)
Depending on how the field is defined
(setf (jfield *MyClass* "someStaticBooleanField") NIL) it is distinguable from (setf (jfield *MySuperClass* "nonStaticBooleanField" *my- instance* ) NIL)
A>- value is not used, what's the point of it?
correct the "default :novalue" is not needed. (I was debugging and trying to find corner cases with all those bizzare legal jfield signatures )
but... "value" as an &optional was needed to match the signature of what is legal for jfield so things like this can work:
(define-symbol-macro %iscold (jfield "org.armedbear.lisp.Lisp" "cold")) %iscold ;; ==> NIL (setq %iscold T) ;; ==> T %iscold ;; ==> T (setq %iscold NIL) ;; ==> NIL
armedbear-devel mailing list armedbear-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
armedbear-devel mailing list armedbear-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
On Wed, Nov 25, 2009 at 1:19 AM, logicmoo@gmail.com wrote:
Alan, Thanks.. yeah that setAccessable is very useful. I helps resolve my temptation to make the jfield/jstatic and jcall secretly always setAccessable if !isAccessable! And the .getDeclared*s is equally important
Which reminds me - currently in ABCLs .java we are going to need to .patch #'jstatic to search the getDeclaredMethods() instead of getMethods() (And a couple other nits)
getDeclaredFields/Methods do not handle inherited members, so to do it correctly you need to recur over superclasses and interfaces. So it could go like this: if "try-harder" or some similar flag is false, look only for getFields/Methods - you'll get all the accessible members of that class, declared or inherited, but not private members. If the flag is true, use getDeclaredXXX on the full type hierarchy of your class. I have (Java) code written for this type of recursion available.
Bye, Alessio
----- Original Message ----- From: "Alan Ruttenberg" alanruttenberg@gmail.com To: dmiles@users.sourceforge.net Cc: "Thomas Russ" tar@isi.edu; "Armed Bear" armedbear-devel@common-lisp.net Sent: Tuesday, November 24, 2009 1:33 PM Subject: Re: [armedbear-devel] SETF for JFEILDS
In case it is of some interest, the code below is what I use with jss. It's main element of interest is the "try-harder" flag, which uses setAccessible to allow setting some fields that would otherwise cause an exception.
(defun get-java-field (object field &optional try-harder) (if try-harder (let* ((class (if (symbolp object) (setq object (find-java-class object)) (if (equal "java.lang.Class" (jclass-name (jobject-class object)) ) object (jobject-class object)))) (jfield (if (java-object-p field) field (find field (#"getDeclaredFields" class) :key 'jfield-name :test 'equal)))) (#"setAccessible" jfield t) (values (#"get" jfield object) jfield)) (if (symbolp object) (let ((class (find-java-class object))) (#"peekStatic" 'invoke class field)) (#"peek" 'invoke object field))))
(defun set-java-field (object field value &optional try-harder) (if try-harder (let* ((class (if (symbolp object) (setq object (find-java-class object)) (if (equal "java.lang.Class" (jclass-name (jobject-class object)) ) object (jobject-class object)))) (jfield (if (java-object-p field) field (find field (#"getDeclaredFields" class) :key 'jfield-name :test 'equal)))) (#"setAccessible" jfield t) (values (#"set" jfield object value) jfield)) (if (symbolp object) (let ((class (find-java-class object))) (#"pokeStatic" 'invoke class field value)) (#"poke" 'invoke object field value))))
On Tue, Nov 24, 2009 at 4:27 PM, logicmoo@gmail.com wrote:
Thanks, you are right, much better to use the built-in key stuff
(defun (setf jfield) (newvalue class-ref-or-field field-or-instance &optional ( instance nil instance-supplied-p) unused-value) (declare (ignore unused-value)) (if instance-supplied-p (jfield class-ref-or-field field-or-instance instance newvalue) (jfield class-ref-or-field field-or-instance newvalue)))
----- Original Message ----- From: "Thomas Russ" tar@ISI.EDU To: dmiles@users.sourceforge.net Sent: Tuesday, November 24, 2009 9:24 AM Subject: Re: [armedbear-devel] SETF for JFEILDS
On Nov 23, 2009, at 6:47 AM, logicmoo@gmail.com wrote:
So actually
(defun (setf jfield) (newvalue class-ref-or-field field-or- instance &optional ( instance :noinst) unusedvalue) (if (eq instance :noinst) (jfield class-ref-or-field field-or-instance newvalue) (jfield class-ref-or-field field-or-instance instance newvalue)))
Would be a little better.. good eye.
For what it's worth, I am not a fan of using special values to determine whether optional (or keyword) arguments are actually passed or not. I prefer to use the predicate forms from the lambda list, so something more like
(defun (setf jfield) (newvalue class-ref-or-field field-or-instance &optional ( instance nil instance-supplied-p) unusedvalue) (declare (ignore unusedvalue)) (if instance-supplied-p (jfield class-ref-or-field field-or-instance newvalue) (jfield class-ref-or-field field-or-instance instance newvalue)))
----- Original Message ----- From: dmiles@users.sourceforge.net To: "Alessio Stalla" alessiostalla@gmail.com Cc: "Armed Bear" armedbear-devel@common-lisp.net Sent: Monday, November 23, 2009 6:27 AM Subject: Re: [armedbear-devel] SETF for JFEILDS
----- Original Message ----- From: "Alessio Stalla" alessiostalla@gmail.com To: dmiles@users.sourceforge.net Cc: "Armed Bear" armedbear-devel@common-lisp.net Sent: Monday, November 23, 2009 5:42 AM Subject: Re: [armedbear-devel] SETF for JFEILDS
On Mon, Nov 23, 2009 at 2:36 PM, logicmoo@gmail.com wrote:
> Does anyone object to adding this to java.lisp? If not could it > be done? > > (defun (setf jfield) > (newvalue class-ref-or-field field-or-instance &optional > ( instance :noinst) (value :novalue)) > (if (eq instance :noinst) > (jfield class-ref-or-field field-or-instance newvalue) > (jfield class-ref-or-field field-or-instance instance newvalue)))
It seems a nice idea to me, but there are a couple of things that I don't understand:
A>- why :noinst and not simply nil?
JFIELD is defined as: class-ref-or-field field-or-instance &optional instance value The valid argument patterns for this operation are: (class-ref field-name): to retrieve the value of a static field. (class-ref field-name instance-ref): to retrieve the value of a class field of the instance. (class-ref field-name primitive-value:) to store primitive-value in a static field. (class-ref field-name instance-ref value): to store value in a class field of the instance. (class-ref field-name nil value): to store value in a static field (when value may be confused with an instance-ref). (field-name instance): to retrieve the value of a field of the instance. The class is derived from the instance. (field-name instance value): to store value in a field of the instance. The class is derived from the instance.
JFIELD doesn't distingusih between static and non static fields
Also cases of "class-ref field-name instance-ref value" (accessing superclass field)
Depending on how the field is defined
(setf (jfield *MyClass* "someStaticBooleanField") NIL) it is distinguable from (setf (jfield *MySuperClass* "nonStaticBooleanField" *my- instance* ) NIL)
A>- value is not used, what's the point of it?
correct the "default :novalue" is not needed. (I was debugging and trying to find corner cases with all those bizzare legal jfield signatures )
but... "value" as an &optional was needed to match the signature of what is legal for jfield so things like this can work:
(define-symbol-macro %iscold (jfield "org.armedbear.lisp.Lisp" "cold")) %iscold ;; ==> NIL (setq %iscold T) ;; ==> T %iscold ;; ==> T (setq %iscold NIL) ;; ==> NIL
armedbear-devel mailing list armedbear-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
armedbear-devel mailing list armedbear-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
armedbear-devel mailing list armedbear-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
On Wed, Nov 25, 2009 at 3:06 AM, Alessio Stalla alessiostalla@gmail.com wrote:
getDeclaredFields/Methods do not handle inherited members, so to do it correctly you need to recur over superclasses and interfaces. So it could go like this: if "try-harder" or some similar flag is false, look only for getFields/Methods - you'll get all the accessible members of that class, declared or inherited, but not private members. If the flag is true, use getDeclaredXXX on the full type hierarchy of your class. I have (Java) code written for this type of recursion available.
Nice. Please send :) -Alan
On Wed, Nov 25, 2009 at 2:42 PM, Alan Ruttenberg alanruttenberg@gmail.com wrote:
On Wed, Nov 25, 2009 at 3:06 AM, Alessio Stalla alessiostalla@gmail.com wrote:
getDeclaredFields/Methods do not handle inherited members, so to do it correctly you need to recur over superclasses and interfaces. So it could go like this: if "try-harder" or some similar flag is false, look only for getFields/Methods - you'll get all the accessible members of that class, declared or inherited, but not private members. If the flag is true, use getDeclaredXXX on the full type hierarchy of your class. I have (Java) code written for this type of recursion available.
Nice. Please send :)
It occurred to me that I had already used this code inside abcl, for the inspection of Java objects. It is in JavaObject.java - look for mapcarClassHierarchy and doClassHierarchy. It's not exposed as Lisp functions and may need to be polished if used somewhere else, but it's a start.
Ale
svn r12228 breaks the ABCL build pretty badly, with (at least) mention of the non-existent 'LispTrampolinesFile', although there are other errors that may/or may not be corrected by the addition of this missing file.
I am neutral with the intent of the patch to introduce static imports for Lisp.java, although as I understand it this is merely a cosmetic change as it doesn't change the generated bytecode. The use of the wildcard import bothers me a bit as the intent of the linkage is then implicit rather than explicit, but in truth this loses no more information that a call to "Lisp.foo()". I find I tend to get confused about where the symbol is coming from (is it inherited? is it from the import?), but maybe I am getting old and grumpy.
But as to the use of a trampoline, the last time I understand the proposal from David Miles, I was definitely against as requiring a lot of rather ugly looking boilerplate code to every Primitive without providing anything substantial in return. I admit that would need to re-study David's proposal a bit to come up with more concrete arguments, but at the level I understood it my negative assessment could be summarized by: maintaining the trampoline linkages would be a good candidate for an automatic tool with access to the Java AST. Without such a tool, we end up creating more work to maintain/undestand the source.
Therefore, I would advocate reverting svn r12228 for the time being, and at least separating the two issues of the static wildcard import of Lisp.java from the introduction of LispTrampolineFile.java.
2009/11/30 Mark Evenson evenson@panix.com:
svn r12228 breaks the ABCL build pretty badly, with (at least) mention of the non-existent 'LispTrampolinesFile', although there are other errors that may/or may not be corrected by the addition of this missing file.
Ouch. I have probably missed the need to add that file. I can fix that tonight, after I escape from work.
On Mon, Nov 30, 2009 at 10:25 AM, Mark Evenson evenson@panix.com wrote:
svn r12228 breaks the ABCL build pretty badly, with (at least) mention of the non-existent 'LispTrampolinesFile', although there are other errors that may/or may not be corrected by the addition of this missing file.
I am neutral with the intent of the patch to introduce static imports for Lisp.java, although as I understand it this is merely a cosmetic change as it doesn't change the generated bytecode. The use of the wildcard import bothers me a bit as the intent of the linkage is then implicit rather than explicit, but in truth this loses no more information that a call to "Lisp.foo()". I find I tend to get confused about where the symbol is coming from (is it inherited? is it from the import?), but maybe I am getting old and grumpy.
But as to the use of a trampoline, the last time I understand the proposal from David Miles, I was definitely against as requiring a lot of rather ugly looking boilerplate code to every Primitive without providing anything substantial in return. I admit that would need to re-study David's proposal a bit to come up with more concrete arguments, but at the level I understood it my negative assessment could be summarized by: maintaining the trampoline linkages would be a good candidate for an automatic tool with access to the Java AST. Without such a tool, we end up creating more work to maintain/undestand the source.
Therefore, I would advocate reverting svn r12228 for the time being, and at least separating the two issues of the static wildcard import of Lisp.java from the introduction of LispTrampolineFile.java.
I agree about separating the two issues. I too believe static imports should in general be used sparingly to avoid confusion. As for the static trampolines requiring manual maintenance, see my 11/11 mail w/ attached patch that uses Java reflection to hide much of the plumbing (and additionally reduces the number of classes from one per primitive to one plus a few possible special cases). I'm not advocating it as the perfect solution but I think it's good enough for general use, and can be introduced incrementally (i.e. we don't have to replace all the primitives at once). Also it's not significantly harder to read, provided that the static method(s) are defined textually close to the primitive and not in a single catch-all Trampolines class.
Alessio
I added the missing file, now the build should be ok. We can debate the merits of the trampoline separately.
2009/11/30 Ville Voutilainen ville.voutilainen@gmail.com:
I added the missing file, now the build should be ok. We can debate the merits of the trampoline separately.
Ok, r12290 gets rid of the LispTrampolinesFile completely. We don't need it, so I took it out.
On Mon, Nov 30, 2009 at 11:30 PM, Ville Voutilainen ville.voutilainen@gmail.com wrote:
2009/11/30 Ville Voutilainen ville.voutilainen@gmail.com:
I added the missing file, now the build should be ok. We can debate the merits of the trampoline separately.
Ok, r12290 gets rid of the LispTrampolinesFile completely. We don't need it, so I took it out.
Thanks.
The trampolines are a different issue. If they really are an issue to performance, we need to do something about it. However, if they're not we should not increase our startup costs: reflection seems to have a high lookup performance hit.
Bye,
Erik.
----- Original Message ----- From: "Erik Huelsmann" ehuels@gmail.com To: "Ville Voutilainen" ville.voutilainen@gmail.com Cc: armedbear-devel@common-lisp.net Sent: Monday, November 30, 2009 3:35 PM Subject: Re: [armedbear-devel] svn r12228 breaks build
On Mon, Nov 30, 2009 at 11:30 PM, Ville Voutilainen ville.voutilainen@gmail.com wrote:
2009/11/30 Ville Voutilainen ville.voutilainen@gmail.com:
I added the missing file, now the build should be ok. We can debate the merits of the trampoline separately.
Ok, r12290 gets rid of the LispTrampolinesFile completely. We don't need it, so I took it out.
Thanks.
The trampolines are a different issue. If they really are an issue to performance, we need to do something about it. However, if they're not we should not increase our startup costs: reflection seems to have a high lookup performance hit.
I believe for the "compiled library" in abcl.jar the use of calling only "static final" functions (AKA Trampolines) will be a tremendous speedup.
Here is some reasoning why:
All first order function calls, "(dosomething a b c)" would not use symbol primitives. and bypasses several java frames. (trace Allesso's COPY-TREE example so see how much overhead he removed)
But the worry that we have is:
Second order " (funcall #'dosomething a b c)" or "(sort foo #'mypred)" will hit reflection. This will penalize when done early (load time) or late (first call)). then durring runtime.
However even this is fixed in one of two ways:
There are 2 techiniques to get rid of reflection here:
First is at the source level with a AST printer that converts the execute(...) signature to calling the exact static methods that the compiler personally calls.
The second, is on on load time or first call to bytegenerate the primitive that makes each execute(..) that has an @SomeAnnotation(symbol="copy-tree",package="CL") public static final LispObnect copyTree(LispObject object) {..}
And this second get rid totally the primitive subclasses in .java!
Oh, There is also a even combination of the two....
At compile time the annotations are read.. and the .class(es) are generated. and packaged into the current archive.
Bye,
Erik.
armedbear-devel mailing list armedbear-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
On Tue, Dec 1, 2009 at 1:16 AM, dmiles@users.sourceforge.net wrote:
----- Original Message ----- From: "Erik Huelsmann" ehuels@gmail.com To: "Ville Voutilainen" ville.voutilainen@gmail.com Cc: armedbear-devel@common-lisp.net Sent: Monday, November 30, 2009 3:35 PM Subject: Re: [armedbear-devel] svn r12228 breaks build
On Mon, Nov 30, 2009 at 11:30 PM, Ville Voutilainen ville.voutilainen@gmail.com wrote:
2009/11/30 Ville Voutilainen ville.voutilainen@gmail.com:
I added the missing file, now the build should be ok. We can debate the merits of the trampoline separately.
Ok, r12290 gets rid of the LispTrampolinesFile completely. We don't need it, so I took it out.
Thanks.
The trampolines are a different issue. If they really are an issue to performance, we need to do something about it. However, if they're not we should not increase our startup costs: reflection seems to have a high lookup performance hit.
I believe for the "compiled library" in abcl.jar the use of calling only "static final" functions (AKA Trampolines) will be a tremendous speedup.
Here is some reasoning why:
All first order function calls, "(dosomething a b c)" would not use symbol primitives. and bypasses several java frames. (trace Allesso's COPY-TREE example so see how much overhead he removed)
But the worry that we have is:
Second order " (funcall #'dosomething a b c)" or "(sort foo #'mypred)" will hit reflection. This will penalize when done early (load time) or late (first call)). then durring runtime.
Let me add that, iirc, our compiler is smart enough to translate (funcall #'something a b c) to the same code it generates for (something a b c). It would only need to fall back to reflection if the parameter to funcall is not constant, as in (let ((fn #'something)) (funcall fn a b c)). Also what is especially costly about reflection is not the invocation per se but the lookup of the methods, and that is done only once, when the primitive is instantiated or when it makes the first reflective call (depending on the "lazy" flag). If all that is not enough, the techniques you suggested are interesting, though a bit too complicated for my personal tastes.
Cheers, Alessio
However even this is fixed in one of two ways:
There are 2 techiniques to get rid of reflection here:
First is at the source level with a AST printer that converts the execute(...) signature to calling the exact static methods that the compiler personally calls.
The second, is on on load time or first call to bytegenerate the primitive that makes each execute(..) that has an @SomeAnnotation(symbol="copy-tree",package="CL") public static final LispObnect copyTree(LispObject object) {..}
And this second get rid totally the primitive subclasses in .java!
Oh, There is also a even combination of the two....
At compile time the annotations are read.. and the .class(es) are generated. and packaged into the current archive.
Bye,
Erik.
armedbear-devel mailing list armedbear-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
armedbear-devel mailing list armedbear-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
2009/12/1 Alessio Stalla alessiostalla@gmail.com:
Let me add that, iirc, our compiler is smart enough to translate (funcall #'something a b c) to the same code it generates for (something a b c). It would only need to fall back to reflection if the parameter to funcall is not constant, as in (let ((fn #'something)) (funcall fn a b c)). Also what is especially costly about reflection is not the invocation per se but the lookup of the methods, and that is done only once, when the primitive is instantiated or when it makes the first reflective call (depending on the "lazy" flag).
I think the obvious route forward is to make a patch and measure. Then we'll know whether there are performance changes. Has anybody done measurements with the current partial patches, or have I missed a more comprehensive patch?
I have some progress towards the patch ;; INLINE REPORT total=653 cannot=1490 soon=0 inlined-calls=2280 <- thats in building ABCL library
First, I rewrote a Java PrettyPrinter to transform the AST to make primtive subclasses produce static funcions in the outer classes.. Instead of reflection, I produced synthetic methods to make the non-static execute(..)s to call the static ones. 653 of these are done this way.
Here is the transformed src: http://uabcl.googlecode.com/files/start-of-inlines.zip
Then I used Allesio's .patch on compiler-pass2.lisp to make bytecode call the static methods instead. 2280 call site were transformed this way
First here was a couple successes: (from decompiling the .cls files)
lispobject.aset(Primitives._ARRAY_ROW_MAJOR_INDEX_execute( lispobject, alispobject[2]).intValue(), lispobject1 = alispobject[0]);
That called #'ARRAY-ROW-MAJOR-INDEX
And
LispObject lispobject1 = HashTableFunctions.GETHASH_execute( lispobject, SYM223280_TRACE_INFO_HASHTABLE.symbolValue(lispthread));
Before that inline it would have been
lispthread.execute( Symbol.GETHASH, lispobject, SYM223280_TRACE_INFO_HASHTABLE.symbolValue(lispthread));
So that is good news!
However I could not do this to 1490 call sites. due to the fact that there was no static function avalible because the primtive was produced by the lisp compiler and had no method stub.
lispthread.execute(SYM223284_SET_FDEFINITION, lispobject, lispobject2);
That needed to say:
fdefination_22._SET_FDEFINITION_execute(lispobject, lispobject2);
that was %set-fdefinition which was defined in fdefination.lisp
So I still need to do some more work on getting the lisp part o the compiler to produce outer method stubs with inroads to being called via invoke-static.
I ran the ANSI-TESTS and CL-BENCH ..Tthe ansi-tests had too much variance in Time to say anything eigther way.. I proved to myself that the inlines was better.. a few times.. then I proved to myself a couple more time they weren't any faster. So didnt prove anything at all. (and I had some regressions that have to be fixed by removing some struct things from the inlinable registry (or something)) The CL-BENCH is also a bit too varied to say anything. But shouldnt expect too much yet since only 1/3 of the callsites that should be inlined are when I ran them.
PLEASE Anyone who wants, can download that .zip file and see of that can work on compiler-pass2.lisp To make the emitted primtives (and closures?) to produce statically invokable sites. (Also a clear way to find thm at later compile passes)
I am kinda sorta working on that.. but its easier for me to decompile the classes to .java.. (I use a patched JODE instead of JAD). Reprint them.. and recompile them (instead of doing it with .lisp)
However doing it with comnpiler-pass2.lisp would be much prefered and appriciated
----- Original Message ----- From: "Ville Voutilainen" ville.voutilainen@gmail.com To: "Alessio Stalla" alessiostalla@gmail.com Cc: dmiles@users.sourceforge.net; armedbear-devel@common-lisp.net Sent: Tuesday, December 01, 2009 1:55 AM Subject: Re: [armedbear-devel] svn r12228 breaks build
2009/12/1 Alessio Stalla alessiostalla@gmail.com:
Let me add that, iirc, our compiler is smart enough to translate (funcall #'something a b c) to the same code it generates for (something a b c). It would only need to fall back to reflection if the parameter to funcall is not constant, as in (let ((fn #'something)) (funcall fn a b c)). Also what is especially costly about reflection is not the invocation per se but the lookup of the methods, and that is done only once, when the primitive is instantiated or when it makes the first reflective call (depending on the "lazy" flag).
I think the obvious route forward is to make a patch and measure. Then we'll know whether there are performance changes. Has anybody done measurements with the current partial patches, or have I missed a more comprehensive patch?
On Wed, Dec 2, 2009 at 6:49 PM, logicmoo@gmail.com wrote:
I have some progress towards the patch ;; INLINE REPORT total=653 cannot=1490 soon=0 inlined-calls=2280 <- thats in building ABCL library
First, I rewrote a Java PrettyPrinter to transform the AST to make primtive subclasses produce static funcions in the outer classes.. Instead of reflection, I produced synthetic methods to make the non-static execute(..)s to call the static ones. 653 of these are done this way.
Here is the transformed src: http://uabcl.googlecode.com/files/start-of-inlines.zip
Then I used Allesio's .patch on compiler-pass2.lisp to make bytecode call the static methods instead. 2280 call site were transformed this way
First here was a couple successes: (from decompiling the .cls files)
lispobject.aset(Primitives._ARRAY_ROW_MAJOR_INDEX_execute( lispobject, alispobject[2]).intValue(), lispobject1 = alispobject[0]);
That called #'ARRAY-ROW-MAJOR-INDEX
And
LispObject lispobject1 = HashTableFunctions.GETHASH_execute( lispobject, SYM223280_TRACE_INFO_HASHTABLE.symbolValue(lispthread));
Before that inline it would have been
lispthread.execute( Symbol.GETHASH, lispobject, SYM223280_TRACE_INFO_HASHTABLE.symbolValue(lispthread));
So that is good news!
However I could not do this to 1490 call sites. due to the fact that there was no static function avalible because the primtive was produced by the lisp compiler and had no method stub.
lispthread.execute(SYM223284_SET_FDEFINITION, lispobject, lispobject2);
That needed to say:
fdefination_22._SET_FDEFINITION_execute(lispobject, lispobject2);
that was %set-fdefinition which was defined in fdefination.lisp
Yes, I think that's because iirc the compiler-written function classes extend Primitive, but those aren't really primitives. We can't have the compiler produce static methods and inline those all of the time, or function redefinition won't work anymore! In fact, I believe that inlining should not be done indiscriminatingly even for primitives written in Java, but it should be done selectively just for those that are heavily called and can be performance bottlenecks. Also the reason I chose COPY-TREE for my earlier example is not random: many of the primitives are already handled specially by the compiler (e.g. the arithmetic functions, apply/funcall, ...) so they don't get any benefit from trampolines, and should probably be left alone. COPY-TREE was the first that I found that was not special-cased and that could be handled easily with reflection. Furthermore, the compiler could and should inline local functions defined by flet and labels, but I'm afraid it's not that easy. (Actually if it can determine that the local function is only used locally and never returned or passed as argument to other functions it should not even create a class for it, just a private final static method).
Just my .02€
Alessio
So I still need to do some more work on getting the lisp part o the compiler to produce outer method stubs with inroads to being called via invoke-static.
I ran the ANSI-TESTS and CL-BENCH ..Tthe ansi-tests had too much variance in Time to say anything eigther way.. I proved to myself that the inlines was better.. a few times.. then I proved to myself a couple more time they weren't any faster. So didnt prove anything at all. (and I had some regressions that have to be fixed by removing some struct things from the inlinable registry (or something)) The CL-BENCH is also a bit too varied to say anything. But shouldnt expect too much yet since only 1/3 of the callsites that should be inlined are when I ran them.
PLEASE Anyone who wants, can download that .zip file and see of that can work on compiler-pass2.lisp To make the emitted primtives (and closures?) to produce statically invokable sites. (Also a clear way to find thm at later compile passes)
I am kinda sorta working on that.. but its easier for me to decompile the classes to .java.. (I use a patched JODE instead of JAD). Reprint them.. and recompile them (instead of doing it with .lisp)
However doing it with comnpiler-pass2.lisp would be much prefered and appriciated
----- Original Message ----- From: "Ville Voutilainen" ville.voutilainen@gmail.com To: "Alessio Stalla" alessiostalla@gmail.com Cc: dmiles@users.sourceforge.net; armedbear-devel@common-lisp.net Sent: Tuesday, December 01, 2009 1:55 AM Subject: Re: [armedbear-devel] svn r12228 breaks build
2009/12/1 Alessio Stalla alessiostalla@gmail.com:
Let me add that, iirc, our compiler is smart enough to translate (funcall #'something a b c) to the same code it generates for (something a b c). It would only need to fall back to reflection if the parameter to funcall is not constant, as in (let ((fn #'something)) (funcall fn a b c)). Also what is especially costly about reflection is not the invocation per se but the lookup of the methods, and that is done only once, when the primitive is instantiated or when it makes the first reflective call (depending on the "lazy" flag).
I think the obvious route forward is to make a patch and measure. Then we'll know whether there are performance changes. Has anybody done measurements with the current partial patches, or have I missed a more comprehensive patch?
armedbear-devel mailing list armedbear-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
----- Original Message ----- From: "Alessio Stalla" alessiostalla@gmail.com To: "Mark Evenson" evenson@panix.com Cc: armedbear-devel@common-lisp.net Sent: Monday, November 30, 2009 2:31 AM Subject: Re: [armedbear-devel] svn r12228 breaks build
On Mon, Nov 30, 2009 at 10:25 AM, Mark Evenson evenson@panix.com wrote:
svn r12228 breaks the ABCL build pretty badly, with (at least) mention of the non-existent 'LispTrampolinesFile', although there are other errors that may/or may not be corrected by the addition of this missing file.
I am neutral with the intent of the patch to introduce static imports for Lisp.java, although as I understand it this is merely a cosmetic change as it doesn't change the generated bytecode. The use of the wildcard import bothers me a bit as the intent of the linkage is then implicit rather than explicit, but in truth this loses no more information that a call to "Lisp.foo()". I find I tend to get confused about where the symbol is coming from (is it inherited? is it from the import?), but maybe I am getting old and grumpy.
The question was how did you tell where "foo" it was comming from before?
It seems that Lisp.foo() is best for way to denote the method came from Lisp. It maybe should have been that way all along.. I think the reason it wasnt was to keep the size of the source code down.
But as to the use of a trampoline, the last time I understand the proposal from David Miles, I was definitely against as requiring a lot of rather ugly looking boilerplate code to every Primitive without providing anything substantial in return. I admit that would need to re-study David's proposal a bit to come up with more concrete arguments, but at the level I understood it my negative assessment could be summarized by: maintaining the trampoline linkages would be a good candidate for an automatic tool with access to the Java AST. Without such a tool, we end up creating more work to maintain/undestand the source.
Therefore, I would advocate reverting svn r12228 for the time being, and at least separating the two issues of the static wildcard import of Lisp.java from the introduction of LispTrampolineFile.java.
LispTrampolineFile.java is just a stub that the current Trampolines extend.. It just was missed in the r12228 commit
The file simply contained =================================== package org.armedbear.lisp;
abstract public class LispTrampolinesFile { } =================================== As a historical placeholder for when the trampolines that have always been in ABCL extended Lisp that no longer do. Nothing would need to go into that file. It probably should have been an interface if anything at al.
I agree about separating the two issues. I too believe static imports should in general be used sparingly to avoid confusion.
Yes, in the patch being explicit about imports.. was considered but then decided to use wildcard to make it smaller. its a good idea to make them explicit.. just was trying to keep the size of the .patch down.
So one exmaple in CharacterFunctions.java hwere is says:
import static org.armedbear.lisp.Lisp.*;
would become
import static org.armedbear.lisp.Lisp.error; import static org.armedbear.lisp.Lisp.type_error; import static org.armedbear.lisp.Lisp.T; import static org.armedbear.lisp.Lisp.NIL;
etc
As for the static trampolines requiring manual maintenance, see my 11/11 mail w/ attached patch that uses Java reflection to hide much of the plumbing (and additionally reduces the number of classes from one per primitive to one plus a few possible special cases). I'm not advocating it as the perfect solution but I think it's good enough for general use, and can be introduced incrementally (i.e. we don't have to replace all the primitives at once). Also it's not significantly harder to read, provided that the static method(s) are defined textually close to the primitive and not in a single catch-all Trampolines class.
Yes, thanks for clearing that up.
Alessio
armedbear-devel mailing list armedbear-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
On Tue, Nov 24, 2009 at 10:27 PM, logicmoo@gmail.com wrote:
Thanks, you are right, much better to use the built-in key stuff
(defun (setf jfield) (newvalue class-ref-or-field field-or-instance &optional ( instance nil instance-supplied-p) unused-value) (declare (ignore unused-value)) (if instance-supplied-p (jfield class-ref-or-field field-or-instance instance newvalue) (jfield class-ref-or-field field-or-instance newvalue)))
I have tentatively included this code in java.lisp in my local copy of abcl, with the intention to commit it to trunk. It works like a charm, but I have a problem: how can I tell abcl to autoload java.lisp if it sees (setf (jfield ...)) for the first time?
Bye, Ale
On Tue, Dec 22, 2009 at 8:06 PM, Alessio Stalla alessiostalla@gmail.com wrote:
On Tue, Nov 24, 2009 at 10:27 PM, logicmoo@gmail.com wrote:
Thanks, you are right, much better to use the built-in key stuff
(defun (setf jfield) (newvalue class-ref-or-field field-or-instance &optional ( instance nil instance-supplied-p) unused-value) (declare (ignore unused-value)) (if instance-supplied-p (jfield class-ref-or-field field-or-instance instance newvalue) (jfield class-ref-or-field field-or-instance newvalue)))
I have tentatively included this code in java.lisp in my local copy of abcl, with the intention to commit it to trunk. It works like a charm, but I have a problem: how can I tell abcl to autoload java.lisp if it sees (setf (jfield ...)) for the first time?
You can't: the autoloader seems to work with symbols only; I've made the preloaded-function-proxy work with SETF functions too, so, you can lookup there how to do it. You'll just need to invent a syntax for the lisp side: multi-symbol lists are already taken for installing the autoloader on multiple symbols.
Bye,
Erik.
armedbear-devel@common-lisp.net