Reason for lack of Oracle driver

John M McIntosh johnmci at smalltalkconsulting.com
Wed Jul 2 07:24:41 UTC 2003


Well Tim was trying to say FFI is slower because you define to FFI what  
  the parms are and what the function/subroutine interface is. Then the  
FFI plugin code needs to assemble that data, then load everything into  
the C calling structure/methodology and check everything twice and then  
make the call, then assemble the return values based on the C  
calling/response pattern and return a value to you. There is plenty of  
overhead here because
the path follows the generic pattern for the platforms calling  
convention and it is very inefficient, but perhaps  you won't see it  
unless you are doing millions of calls.  Also screwing up parms and  
types between  what you specify in FFI, versus what is actually  
required results in instant, or slow death. Doing a buffer overflow  
many or many not core dump the VM right away, depends on where, and  
which GC activity takes place. In fact in my extended serial port  
testing I overwrote 4 bytes but didn't see it til 4 hours later when  
the first full GC ran. {All the extended serial port calls are now very  
paranoid about parm expectations.}

With a Slang solution, you build a minimal set of subroutines in mostly  
Smalltalk
with perhaps some C constructs. That gets translated to C and you  
compile that C code into a plugin,
An example would be the extended Serial Port class I put out back in  
May.  This way the call to
the OCI subroutine takes as few instructions as possible based on C  
compiler optimization.

An example
primitiveSerialPortUnixOpen: fileName attribute: anAttribute

	| fd |
	self primitive: 'primitiveSerialPortUnixOpen'
		parameters: #(String SmallInteger).
	self cCode: 'fd = open(fileName,anAttribute)' inSmalltalk: [fd _ 0].
	^ fd asSmallIntegerObj

Slang notes the primitive:parameters: and ensures I end up with a C  
string in fileName, and an integer within the SmallInteger bounds in  
anAttribute, it performs runtime checks so objects that don't match  
these classes cause a primitive failue.  The C construct fd =  
open(fileName,anAttribute) is of course the open(). Note that I return  
fd as a SmallInteger Object.

Higher up in the Smalltalk I issue
primitiveSerialPortUnixOpen: fileName attribute: anAttribute
	<primitive: 'primitiveSerialPortUnixOpen' module:  
'SerialExtendedUnixPlugin'>
	self primitiveFailed.

where somewhere I invoke
primitiveSerialPortUnixOpen: aFilePathString attribute: aMagicNumber

This all turns into this C code

EXPORT(int) primitiveSerialPortUnixOpen(void) {
	int fd;
	char *fileName;
	int anAttribute;
	int _return_value;

	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy- 
 >stackValue(1)));
	fileName = ((char *)  
(interpreterProxy->firstIndexableField(interpreterProxy- 
 >stackValue(1))));
	anAttribute = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	fd = open(fileName,anAttribute);
	_return_value = interpreterProxy->integerObjectOf(fd);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(3, _return_value);
	return null;
}



A more complicated example is

primitiveSerialPortUnixRead: fd into: array startingAt: startIndexPtr  
count: countPtr
	| bytesRead  startIndex count |
	self primitive: 'primitiveSerialPortUnixRead'
		parameters: #(SmallInteger ByteArray Oop Oop).

	startIndex _ interpreterProxy positive32BitValueOf: startIndexPtr.
	count _ interpreterProxy positive32BitValueOf: countPtr.
	((startIndex >= 1) and:
		[(startIndex + count - 1) <= (array size)])
			ifFalse:[^interpreterProxy primitiveFail].

	self cCode: 'bytesRead = read(fd, array+startIndex-1, (size_t)count)'  
inSmalltalk: [bytesRead _ 0].
	^ interpreterProxy positive32BitIntegerFor:  bytesRead


I get a bit more paranoid and check boundary conditions. Actually  
nothing prevents me from checking those conditions up in the Smalltalk,  
then assuming everything is correct by the time we call the plugin, but  
I've done it this way for historical reasons. Mmm actually checking up  
in the Smalltalk would be better because then I can throw an exception  
which is much more debuggable. Note the usage of positive32Bit to get  
the correct range of values 0-2GB range instead of the SmallInteger  
range for the integers.


On Tuesday, July 1, 2003, at 11:08  PM, Martin Drautzburg wrote:

> Tim Rowledge <tim at sumeru.stanford.edu> writes:
>
>> If you know what interfaces you need and can be bothered to write
>> the Slang code for a plugin it will almost always be faster since
>> you can very specifically handle the parameters.
>
> Slang = subset of Smalltalk that can be converted to C, right = I can
> imagine how to write "faster" code this way, i.e. code that CAN run in
> an interpreted way, but is faster when compiled via C.
>
> But how can I access the oracle client libs from Slang ? I mean, this
> code could not possibly run in an interpreted way.
>
>
>
--
======================================================================== 
===
John M. McIntosh <johnmci at smalltalkconsulting.com> 1-800-477-2659
Corporate Smalltalk Consulting Ltd.  http://www.smalltalkconsulting.com
======================================================================== 
===



More information about the Squeak-dev mailing list