[Kde-java] Re: Should we ditch support for Sun's JDK in favour of Free Software?

Richard Dale Richard_Dale at tipitina.demon.co.uk
Sat Apr 17 11:32:38 CEST 2004


On Friday 16 April 2004 22:54, Tom Tromey wrote:
> >>>>> "Richard" == Richard Dale <Richard_Dale at tipitina.demon.co.uk> writes:
>
> Richard> I'm only really talking about the next version for KDE 3.3
> Richard> based on dynamic proxies. I think it just means I'll do a CNI
> Richard> version first, and then do a JNI/jdk oriented one if I've got
> Richard> time. There will only be about 20 CNI or JNI methods, so it
> Richard> will be easier to do both CNI/JNI.
>
> This sounds excellent.  Can these new native methods also be
> auto-generated?  That might make it even easier to support both.
No, they are the various support funtions needed to interface with the Smoke 
library - a 'Smoke Adaptor'. They have no dependencies on Qt/KDE classes 
apart from custom marshallers to convert from a C++ list type to ArrayLists 
for instance. That code doesn't need changing for each release, and is easy 
to maintain. Everything else is autogenerated as part of kdebindings 
configure - both the Smoke library, and all the .java classes with the 
interceptor proxies.

I did start on the interface with Proxy.invoke() to a native method a few 
months ago, but it seemed unnecessarily difficult to convert from a Object[] 
array to an array of jvalues, which are then pushed as C++ values onto the 
'Smoke::Stack'. A lot of the code is for converting Object[] <--> 
Smoke::Stack, you push things onto the Smoke::Stack to invoke a C++ method, 
or you take things off the Smoke::Stack for a callback for a virtual method 
override or slot invocation. I'm assuming the way CNI works will make it a 
lot simpler.

Below is the code to invoke a C++ method from ruby as an example of the sort 
of thing it looks like. In ruby the method_missing() method (the equivalent 
of Proxy.invoke() in java), is passed an array of ruby VALUEs that are then 
passed straight the MethodCall constructor, the '_sp' variable in the code 
below. But in java JNI it's quite involved.

'Smoke::Index' which identifies which method to call in the Smoke runtime, is 
actually as integer from 0..29000. In version 2 of the Smoke runtime it will 
be a URI which will be more flexible.

-- Richard

class MethodCall : public Marshall {
    int _cur;
    Smoke *_smoke;
    Smoke::Stack _stack;
    Smoke::Index _method;
    Smoke::Index *_args;
	VALUE _target;
	void *_current_object;
	Smoke::Index _current_object_class;
    VALUE *_sp;
    int _items;
    VALUE _retval;
    bool _called;
public:
    MethodCall(Smoke *smoke, Smoke::Index method, VALUE target, VALUE *sp, int 
items) :
	_cur(-1), _smoke(smoke), _method(method), _target(target), 
_current_object(0), _sp(sp), _items(items), _called(false)
    {
	if (_target != Qnil) {
	    smokeruby_object *o = value_obj_info(_target);
		if (o && o->ptr) {
		    _current_object = o->ptr;
		    _current_object_class = o->classId;
		}
	}
	
	_args = _smoke->argumentList + _smoke->methods[_method].args;
	_items = _smoke->methods[_method].numArgs;
	_stack = new Smoke::StackItem[items + 1];
	_retval = Qnil;
    }

    ~MethodCall() {
	delete[] _stack;
    }

    SmokeType type() {
    	return SmokeType(_smoke, _args[_cur]);
    }

    Marshall::Action action() {
    	return Marshall::FromVALUE;
    }
    Smoke::StackItem &item() {
    	return _stack[_cur + 1];
    }

    VALUE * var() {
	if(_cur < 0) return &_retval;
	return _sp + _cur;
    }

    inline const Smoke::Method &method() {
    	return _smoke->methods[_method];
    }

    void unsupported() {
    	if (strcmp(_smoke->className(method().classId), "QGlobalSpace") == 0) {
			rb_raise(rb_eArgError, "Cannot handle '%s' as argument to %s",
				type().name(),
				_smoke->methodNames[method().name]);
		} else {
			rb_raise(rb_eArgError, "Cannot handle '%s' as argument to %s::%s",
				type().name(),
				_smoke->className(method().classId),
				_smoke->methodNames[method().name]);
		}
    }

    Smoke *smoke() {
    	return _smoke;
    }

    inline void callMethod() {
	if(_called) return;
	_called = true;
	Smoke::ClassFn fn = _smoke->classes[method().classId].classFn;
	void *ptr = _smoke->cast(_current_object, _current_object_class, 
method().classId);
	_items = -1;
	(*fn)(method().method, ptr, _stack);
	MethodReturnValue r(_smoke, _method, _stack, &_retval);
    }

    void next() {
	int oldcur = _cur;
	_cur++;

	while(!_called && _cur < _items) {
	    Marshall::HandlerFn fn = getMarshallFn(type());
	    (*fn)(this);
	    _cur++;
	}
	callMethod();
	_cur = oldcur;
    }

    bool cleanup() {
    	return true;
    }
};


More information about the Kde-java mailing list