* pas2jni:

- Support for objects.
  - Support for pointers to records,objects,classes.
  - Fixed memory leaks when using records.
  - Added handy enum constructors.

git-svn-id: trunk@32560 -
This commit is contained in:
yury 2015-12-01 11:56:29 +00:00
parent 6fda08705b
commit cddbe1b83d
3 changed files with 289 additions and 114 deletions

View File

@ -29,8 +29,8 @@ uses
Classes, SysUtils, contnrs;
type
TDefType = (dtNone, dtUnit, dtClass, dtRecord, dtProc, dtField, dtProp, dtParam, dtVar,
dtType, dtConst, dtProcType, dtEnum, dtSet);
TDefType = (dtNone, dtUnit, dtClass, dtProc, dtField, dtProp, dtParam, dtVar,
dtType, dtConst, dtProcType, dtEnum, dtSet, dtPointer);
TDefClass = class of TDef;
{ TDef }
@ -77,6 +77,8 @@ type
property AliasName: string read GetAliasName write FAliasName;
end;
TClassType = (ctClass, ctInterface, ctObject, ctRecord);
{ TClassDef }
TClassDef = class(TDef)
@ -85,20 +87,17 @@ type
protected
procedure SetIsUsed(const AValue: boolean); override;
public
CType: TClassType;
AncestorClass: TClassDef;
HasAbstractMethods: boolean;
HasReplacedItems: boolean;
ImplementsReplacedItems: boolean;
Size: integer;
procedure ResolveDefs; override;
end;
TRecordDef = class(TDef)
public
Size: integer;
end;
TBasicType = (btVoid, btByte, btShortInt, btWord, btSmallInt, btLongWord, btLongInt, btInt64,
btSingle, btDouble, btString, btWideString, btBoolean, btChar, btWideChar, btEnum, btPointer,
btSingle, btDouble, btString, btWideString, btBoolean, btChar, btWideChar, btEnum,
btGuid);
{ TTypeDef }
@ -110,6 +109,19 @@ type
BasicType: TBasicType;
end;
{ TPointerDef }
TPointerDef = class(TDef)
private
FHasPtrRef: boolean;
protected
procedure SetIsUsed(const AValue: boolean); override;
public
PtrType: TDef;
procedure ResolveDefs; override;
function IsObjPtr: boolean;
end;
{ TReplDef }
TReplDef = class(TDef)
@ -210,6 +222,32 @@ begin
Result:=TTypeDef(t1).BasicType = TTypeDef(t2).BasicType;
end;
{ TPointerDef }
procedure TPointerDef.SetIsUsed(const AValue: boolean);
begin
if IsObjPtr then begin
inherited SetIsUsed(AValue);
SetExtUsed(PtrType, AValue, FHasPtrRef);
end
else
if AValue then
AddRef
else
DecRef;
end;
procedure TPointerDef.ResolveDefs;
begin
inherited ResolveDefs;
PtrType:=ResolveDef(PtrType);
end;
function TPointerDef.IsObjPtr: boolean;
begin
Result:=(PtrType <> nil) and (PtrType.DefType in [dtClass]);
end;
{ TReplDef }
procedure TReplDef.SetIsUsed(const AValue: boolean);
@ -456,14 +494,15 @@ end;
function TDef.ResolveDef(d: TDef; ExpectedClass: TDefClass): TDef;
begin
if (d = nil) or (d.DefType <> dtNone) then begin
Result:=d;
exit;
if (d = nil) or (d.DefType <> dtNone) then
Result:=d
else begin
Result:=d.Parent.FindDef(d.DefId);
if (ExpectedClass <> nil) and (Result <> nil) then
if not (Result is ExpectedClass) then
raise Exception.CreateFmt('Unexpected class. Expected: %s, got: %s', [ExpectedClass.ClassName, Result.ClassName]);
end;
Result:=d.Parent.FindDef(d.DefId);
if (ExpectedClass <> nil) and (Result <> nil) then
if not (Result is ExpectedClass) then
raise Exception.CreateFmt('Unexpected class. Expected: %s, got: %s', [ExpectedClass.ClassName, Result.ClassName]);
end;
procedure TDef.AddRef;

View File

@ -245,6 +245,7 @@ var
d: TDef;
it: TJSONObject;
jarr, arr: TJSONArray;
ct: TClassType;
begin
jarr:=jobj.Get(ItemsName, TJSONArray(nil));
if jarr = nil then
@ -255,9 +256,19 @@ var
CurObjName:=it.Get('Name', '');
jt:=it.Strings['Type'];
if jt = 'obj' then begin
if it.Strings['ObjType'] <> 'class' then
s:=it.Strings['ObjType'];
if s = 'class' then
ct:=ctClass
else
// if s = 'interface' then
// ct:=ctInterface
// else
if s = 'object' then
ct:=ctObject
else
continue;
d:=TClassDef.Create(CurDef, dtClass);
TClassDef(d).CType:=ct;
end
else
if jt = 'rec' then begin
@ -265,8 +276,10 @@ var
d:=TTypeDef.Create(CurDef, dtType);
TTypeDef(d).BasicType:=btGuid;
end
else
d:=TRecordDef.Create(CurDef, dtRecord);
else begin
d:=TClassDef.Create(CurDef, dtClass);
TClassDef(d).CType:=ctRecord;
end;
end
else
if jt = 'proc' then
@ -364,8 +377,7 @@ var
d:=TSetDef.Create(CurDef, dtSet)
else
if jt = 'ptr' then begin
d:=TTypeDef.Create(CurDef, dtType);
TTypeDef(d).BasicType:=btPointer;
d:=TPointerDef.Create(CurDef, dtPointer);
end
else
if jt = 'const' then
@ -391,12 +403,10 @@ var
case d.DefType of
dtClass:
with TClassDef(d) do begin
AncestorClass:=TClassDef(_GetRef(it.Get('Ancestor', TJSONObject(nil)), TClassDef));
_ReadDefs(d, it, 'Fields');
end;
dtRecord:
with TRecordDef(d) do begin
Size:=it.Integers['Size'];
if CType <> ctRecord then
AncestorClass:=TClassDef(_GetRef(it.Get('Ancestor', TJSONObject(nil)), TClassDef));
if CType in [ctObject, ctRecord] then
Size:=it.Integers['Size'];
_ReadDefs(d, it, 'Fields');
end;
dtProc, dtProcType:
@ -506,6 +516,10 @@ var
else
FreeAndNil(d);
end;
dtPointer:
with TPointerDef(d) do begin
PtrType:=_GetRef(it.Get('Ptr', TJSONObject(nil)));;
end;
end;
end;
end;

View File

@ -94,13 +94,14 @@ type
procedure WriteClassInfoVar(d: TDef);
procedure WriteComment(d: TDef; const AType: string);
procedure WriteClass(d: TDef; PreInfo: boolean);
procedure WriteClass(d: TClassDef; PreInfo: boolean);
procedure WriteProc(d: TProcDef; Variable: TVarDef = nil; AParent: TDef = nil);
procedure WriteVar(d: TVarDef; AParent: TDef = nil);
procedure WriteConst(d: TConstDef);
procedure WriteEnum(d: TDef);
procedure WriteProcType(d: TProcDef; PreInfo: boolean);
procedure WriteSet(d: TSetDef);
procedure WritePointer(d: TPointerDef);
procedure WriteUnit(u: TUnitDef);
procedure WriteOnLoad;
public
@ -123,13 +124,13 @@ implementation
const
JNIType: array[TBasicType] of string =
('', 'jshort', 'jbyte', 'jint', 'jshort', 'jlong', 'jint', 'jlong', 'jfloat', 'jdouble', 'jstring',
'jstring', 'jboolean', 'jchar', 'jchar', 'jint', 'jlong', 'jstring');
'jstring', 'jboolean', 'jchar', 'jchar', 'jint', 'jstring');
JNITypeSig: array[TBasicType] of string =
('V', 'S', 'B', 'I', 'S', 'J', 'I', 'J', 'F', 'D', 'Ljava/lang/String;', 'Ljava/lang/String;',
'Z', 'C', 'C', 'I', 'J', 'Ljava/lang/String;');
'Z', 'C', 'C', 'I', 'Ljava/lang/String;');
JavaType: array[TBasicType] of string =
('void', 'short', 'byte', 'int', 'short', 'long', 'int', 'long', 'float', 'double', 'String',
'String', 'boolean', 'char', 'char', 'int', 'long', 'String');
'String', 'boolean', 'char', 'char', 'int', 'String');
TextIndent = 2;
@ -254,7 +255,7 @@ begin
case d.DefType of
dtType:
Result:=JNIType[TTypeDef(d).BasicType];
dtClass, dtRecord, dtEnum:
dtClass, dtEnum:
Result:='jobject';
dtProcType:
if poMethodPtr in TProcDef(d).ProcOpt then
@ -270,6 +271,11 @@ begin
Result:=SUnsupportedType + ' ' + d.Name;
err:=True;
end;
dtPointer:
if TPointerDef(d).IsObjPtr then
Result:='jobject'
else
Result:='jlong';
else begin
Result:=SUnsupportedType + ' ' + d.Name;
err:=True;
@ -306,7 +312,7 @@ begin
if ExcludeList.IndexOf(s) >= 0 then begin
d.SetNotUsed;
end;
if not (d.DefType in [dtUnit, dtClass, dtRecord]) then
if not (d.DefType in [dtUnit, dtClass]) then
exit;
s:=s + '.';
for i:=0 to d.Count - 1 do
@ -327,8 +333,13 @@ begin
case d.DefType of
dtType:
Result:=JNITypeSig[TTypeDef(d).BasicType];
dtClass, dtRecord, dtProcType, dtSet, dtEnum:
dtClass, dtProcType, dtSet, dtEnum:
Result:='L' + GetJavaClassPath(d) + ';';
dtPointer:
if TPointerDef(d).IsObjPtr then
Result:='L' + GetJavaClassPath(d) + ';'
else
Result:='J';
else
Result:=SUnsupportedType;
end;
@ -342,8 +353,13 @@ begin
case d.DefType of
dtType:
Result:=JavaType[TTypeDef(d).BasicType];
dtClass, dtRecord, dtProcType, dtSet, dtEnum:
dtClass, dtProcType, dtSet, dtEnum:
Result:=d.Name;
dtPointer:
if TPointerDef(d).IsObjPtr then
Result:=d.Name
else
Result:='long';
else
Result:=SUnsupportedType;
end;
@ -366,7 +382,7 @@ begin
Result:=Result + d.Parent.AliasName + '$' + n;
end;
procedure TWriter.WriteClass(d: TDef; PreInfo: boolean);
procedure TWriter.WriteClass(d: TClassDef; PreInfo: boolean);
var
WrittenItems: TList;
@ -489,21 +505,15 @@ var
procedure WriteTypeCast(const AName: string; SecondPass: boolean);
var
s, ss: string;
s: string;
begin
if d.DefType <> dtClass then
exit;
with TClassDef(d) do begin
if (AncestorClass = nil) and not (SecondPass and HasReplacedItems) then
// TObject
s:='_pasobj=obj._pasobj'
else
s:='super(obj)';
if HasReplacedItems and not SecondPass then
ss:='protected'
s:='protected'
else
ss:='public';
Fjs.WriteLn(Format('%s %s(PascalObject obj) { %s; }', [ss, AName, s]))
s:='public';
Fjs.WriteLn(Format('%s %s(PascalObject obj) { super(obj); }', [s, AName]));
Fjs.WriteLn(Format('%s %s(long objptr) { super(objptr); }', [s, AName]));
end;
end;
@ -514,7 +524,7 @@ begin
if PreInfo then begin
WriteClassInfoVar(d);
if d.DefType = dtRecord then begin
if d.CType in [ctObject, ctRecord] then begin
s:=d.Parent.Name + '.' + d.Name;
Fps.WriteLn;
Fps.WriteLn(Format('function _%s_CreateObj(env: PJNIEnv; const r: %s): jobject;', [GetClassPrefix(d), s]));
@ -535,43 +545,46 @@ begin
Fps.WriteLn('Dispose(pr);', 1);
Fps.WriteLn('end;');
AddNativeMethod(d, ss, 'Release', '(J)V');
AddNativeMethod(d, ss, '__Destroy', '(J)V');
end;
exit;
end;
// Java
case d.DefType of
dtClass:
s:='class';
dtRecord:
case d.CType of
ctInterface:
s:='interface';
ctObject:
s:='interface';
ctRecord:
s:='record';
else
s:='';
s:='class';
end;
WriteComment(d, s);
n:=GetJavaClassName(d, nil);
s:='public static class ' + n + ' extends ';
if d.DefType = dtClass then
with TClassDef(d) do begin
if AncestorClass <> nil then begin
ss:=AncestorClass.Name;
if ImplementsReplacedItems then
ss:='__' + ss;
s:=s + ss;
end
else
s:=s + 'PascalObject';
with d do begin
if AncestorClass <> nil then begin
ss:=AncestorClass.Name;
if ImplementsReplacedItems then
ss:='__' + ss;
s:=s + ss;
end
else
s:=s + Format('%s.system.Record', [JavaPackage]);
if d.CType in [ctObject, ctRecord] then
s:=s + Format('%s.system.Record', [JavaPackage])
else
s:=s + 'PascalObject';
end;
Fjs.WriteLn(s + ' {');
Fjs.IncI;
if d.DefType = dtRecord then begin
Fjs.WriteLn('private native void Release(long pasobj);');
Fjs.WriteLn(Format('public %s() { }', [d.Name]));
Fjs.WriteLn(Format('public void Free() { Release(_pasobj); super.Free(); }', [d.Name]));
Fjs.WriteLn(Format('public int Size() { return %d; }', [TRecordDef(d).Size]));
if d.CType in [ctObject, ctRecord] then begin
Fjs.WriteLn('private native void __Destroy(long pasobj);');
Fjs.WriteLn(Format('protected %s(long objptr, boolean cleanup) { __Init(objptr, cleanup); }', [d.Name]));
Fjs.WriteLn(Format('public %s() { __Init(0, true); }', [d.Name]));
Fjs.WriteLn(Format('public void __Release() { __Destroy(_pasobj); super.__Release(); }', [d.Name]));
Fjs.WriteLn(Format('public int __Size() { return %d; }', [d.Size]));
end;
WriteTypeCast(n, False);
@ -616,14 +629,14 @@ end;
procedure TWriter.WriteProc(d: TProcDef; Variable: TVarDef; AParent: TDef);
var
i, j, ClassIdx: integer;
s, ss: string;
s, ss, TempRes: string;
err, tf: boolean;
pi: TProcInfo;
ci: TClassInfo;
IsTObject: boolean;
tempvars: TStringList;
vd: TVarDef;
UseTempObjVar: boolean;
UseTempObjVar, IsObj: boolean;
ItemDef: TDef;
begin
ASSERT(d.DefType = dtProc);
@ -675,6 +688,10 @@ begin
s:='procedure';
s:=s + ' ' + pi.JniName + '(_env: PJNIEnv; _jobj: jobject';
IsObj:=(d.Parent.DefType = dtClass) and (TClassDef(d.Parent).CType = ctObject);
if IsObj and (ProcType in [ptConstructor, ptDestructor]) then
TempRes:='__tempres';
UseTempObjVar:=(ProcType = ptProcedure) and (Variable <> nil) and (Variable.VarType <> nil) and (Variable.VarType.DefType = dtProcType) and (Variable.Parent.DefType <> dtUnit);
for j:=0 to Count - 1 do begin
@ -702,12 +719,13 @@ begin
if err then begin
d.SetNotUsed;
s:='// ' + s;
Fjs.WriteLn('// NOT SUPPORTED: ' + GetJavaProcDeclaration(d));
end;
Fps.WriteLn;
Fps.WriteLn(s);
if err then
exit;
if (tempvars <> nil) or UseTempObjVar then begin
if (tempvars <> nil) or UseTempObjVar or (TempRes <> '') then begin
s:='';
Fps.WriteLn('var');
Fps.IncI;
@ -726,6 +744,14 @@ begin
end;
if UseTempObjVar then
Fps.WriteLn('__objvar: ' + d.Parent.Name + ';');
if TempRes <> '' then begin
s:=TempRes + ': ';
if IsObj and (ProcType in [ptConstructor, ptDestructor]) then
s:=s + '^' + GetPasType(d.Parent, True)
else
s:=s + GetPasType(d.ReturnType, True);
Fps.WriteLn(s + ';');
end;
Fps.DecI;
end;
Fps.WriteLn('begin');
@ -757,13 +783,14 @@ begin
end;
s:='';
if Parent.DefType = dtUnit then
s:=Parent.Name + '.'
else
if ProcType = ptConstructor then
s:=Parent.Parent.Name + '.' + Parent.Name + '.'
if not (IsObj and (ProcType in [ptConstructor, ptDestructor])) then
if Parent.DefType = dtUnit then
s:=Parent.Name + '.'
else
s:=JniToPasType(d.Parent, '_jobj', True) + '.';
if ProcType = ptConstructor then
s:=Parent.Parent.Name + '.' + Parent.Name + '.'
else
s:=JniToPasType(d.Parent, '_jobj', True) + '.';
if Variable = nil then begin
// Regular proc
@ -816,10 +843,24 @@ begin
end;
end;
if ProcType in [ptFunction, ptConstructor] then
s:='Result:=' + PasToJniType(ReturnType, s);
s:=s + ';';
Fps.WriteLn(s);
if IsObj and (ProcType = ptConstructor) then begin
s:=Format('system.New(%s, %s);', [TempRes, s]);
Fps.WriteLn(s);
s:=Format('Result:=_CreateJavaObj(_env, %s, %s, False);', [TempRes, GetTypeInfoVar(ReturnType)]);
Fps.WriteLn(s);
end
else
if IsObj and (ProcType = ptDestructor) then begin
Fps.WriteLn(TempRes + ':=@' + JniToPasType(d.Parent, '_jobj', True) + ';');
s:=Format('system.Dispose(%s, %s);', [TempRes, s]);
Fps.WriteLn(s);
end
else begin
if ProcType in [ptFunction, ptConstructor] then
s:='Result:=' + PasToJniType(ReturnType, s);
s:=s + ';';
Fps.WriteLn(s);
end;
if (Variable <> nil) and UseTempObjVar then
Fps.WriteLn(ss);
@ -1049,6 +1090,11 @@ begin
Fjs.WriteLn(s);
end;
Fjs.WriteLn;
for i:=0 to d.Count - 1 do begin
s:=Format('public final static %s %s() { return new %0:s(%1:s); }', [d.Name, d[i].Name]);
Fjs.WriteLn(s);
end;
Fjs.WriteLn;
Fjs.WriteLn(Format('public %s(int v) { Value = v; }', [d.Name]));
Fjs.WriteLn(Format('@Override public boolean equals(Object o) { return ((o instanceof %0:s) && Value == ((%0:s)o).Value) || super.equals(o); }', [d.Name]));
Fjs.DecI;
@ -1202,6 +1248,7 @@ begin
Fjs.WriteLn(Format('public static class %s extends %s.system.MethodPtr {', [d.Name, JavaPackage]));
Fjs.IncI;
Fjs.WriteLn(Format('private String HandlerSig = "%s";', [GetProcSignature(d)]));
Fjs.WriteLn(Format('protected %s(long objptr, boolean cleanup) { }', [d.Name]));
Fjs.WriteLn(Format('public %s(Object Obj, String MethodName) { Init(Obj, MethodName, HandlerSig); }', [d.Name]));
Fjs.WriteLn(Format('public %s() { Init(this, "Execute", HandlerSig); }', [d.Name]));
Fjs.WriteLn(Format('protected %s throws NoSuchMethodException { throw new NoSuchMethodException(); }', [GetJavaProcDeclaration(d, 'Execute')]));
@ -1242,6 +1289,24 @@ begin
Fjs.WriteLn;
end;
procedure TWriter.WritePointer(d: TPointerDef);
begin
if not d.IsUsed or not d.IsObjPtr then
exit;
WriteComment(d, 'pointer');
RegisterPseudoClass(d);
WriteClassInfoVar(d);
Fjs.WriteLn(Format('public static class %s extends %s {', [d.Name, d.PtrType.Name]));
Fjs.IncI;
if TClassDef(d.PtrType).CType in [ctObject, ctRecord] then
Fjs.WriteLn(Format('protected %s(long objptr, boolean cleanup) { super(objptr, false); }', [d.Name]));
Fjs.WriteLn(Format('public %s(PascalObject obj) { super(obj); }', [d.Name]));
Fjs.WriteLn(Format('public %s(long objptr) { super(objptr); }', [d.Name]));
Fjs.DecI;
Fjs.WriteLn('}');
end;
procedure TWriter.WriteUnit(u: TUnitDef);
procedure _ExcludeClasses(AAncestorClass: TClassDef);
@ -1257,7 +1322,7 @@ procedure TWriter.WriteUnit(u: TUnitDef);
s:=u.Name + '.' + d.Name;
if AAncestorClass = nil then begin
excl:=DoCheckItem(s) = crExclude;
if not excl then
if not excl and (TClassDef(d).AncestorClass <> nil) then
with TClassDef(d).AncestorClass do
excl:=DoCheckItem(Parent.Name + '.' + Name) = crExclude;
end
@ -1332,6 +1397,9 @@ begin
Fjs.IncI;
Fjs.WriteLn(Format('static { %s.system.InitJni(); }', [JavaPackage]));
Fjs.WriteLn('protected long _pasobj = 0;');
Fjs.WriteLn('protected PascalObject() { }');
Fjs.WriteLn('protected PascalObject(PascalObject obj) { _pasobj=obj._pasobj; }');
Fjs.WriteLn('protected PascalObject(long objptr) { _pasobj=objptr; }');
Fjs.WriteLn('@Override public boolean equals(Object o) { return ((o instanceof PascalObject) && _pasobj == ((PascalObject)o)._pasobj); }');
Fjs.WriteLn('@Override public int hashCode() { return (int)_pasobj; }');
Fjs.DecI;
@ -1339,14 +1407,34 @@ begin
Fjs.WriteLn;
Fjs.WriteLn('public static long Pointer(PascalObject obj) { return (obj == null) ? 0 : obj._pasobj; }');
// Object with finalization
Fjs.WriteLn;
Fjs.WriteLn('public static class PascalObjectEx extends PascalObject {');
Fjs.IncI;
Fjs.WriteLn('protected boolean _cleanup = false;');
Fjs.WriteLn('protected void finalize() { ');
{$ifdef DEBUG}
Fjs.WriteLn('String s = "finalize(): " + getClass().getName(); if (_cleanup) s=s+". Need __Release()."; System.out.println(s);', 1);
{$endif DEBUG}
Fjs.WriteLn('if (_cleanup) __Release();', 1);
Fjs.WriteLn('}');
Fjs.WriteLn('protected PascalObjectEx() { }');
Fjs.WriteLn('protected PascalObjectEx(PascalObject obj) { super(obj); }');
Fjs.WriteLn('protected PascalObjectEx(long objptr) { super(objptr); }');
Fjs.WriteLn('public void __Release() { _pasobj = 0; }');
Fjs.DecI;
Fjs.WriteLn('}');
// Record
Fjs.WriteLn;
Fjs.WriteLn('public static class Record extends PascalObject {');
Fjs.WriteLn('public static class Record extends PascalObjectEx {');
Fjs.IncI;
Fjs.WriteLn('protected void finalize() { Free(); }');
Fjs.WriteLn('public Record() { _pasobj = AllocMemory(Size()); }');
Fjs.WriteLn('public void Free() { _pasobj = 0; }');
Fjs.WriteLn('public int Size() { return 0; }');
Fjs.WriteLn('protected PascalObject _objref;');
Fjs.WriteLn('protected void __Init(long objptr, boolean cleanup) { _pasobj=objptr; _cleanup=cleanup; if (_pasobj==0 && __Size() != 0) _pasobj=AllocMemory(__Size()); }');
Fjs.WriteLn('protected Record(PascalObject obj) { super(obj); _objref=obj; }');
Fjs.WriteLn('protected Record(long objptr) { super(objptr); }');
Fjs.WriteLn('public Record() { }');
Fjs.WriteLn('public int __Size() { return 0; }');
Fjs.DecI;
Fjs.WriteLn('}');
@ -1380,15 +1468,16 @@ begin
Fps.DecI;
Fps.WriteLn('end;');
AddNativeMethod(d, '_TMethodPtrInfo_Release', 'Release', '()V');
AddNativeMethod(d, '_TMethodPtrInfo_Release', '__Destroy', '()V');
Fjs.WriteLn;
Fjs.WriteLn('public static class MethodPtr extends PascalObject {');
Fjs.WriteLn('public static class MethodPtr extends PascalObjectEx {');
Fjs.IncI;
Fjs.WriteLn('private native void Release();');
Fjs.WriteLn('protected void finalize() { if (_pasobj != 0) Release(); }');
Fjs.WriteLn('private native void __Destroy();');
Fjs.WriteLn('protected native void Init(Object Obj, String MethodName, String MethodSignature);');
Fjs.WriteLn('protected MethodPtr() { _cleanup=true; }');
Fjs.WriteLn('public void __Release() { if (_pasobj != 0) __Destroy(); }');
Fjs.DecI;
Fjs.WriteLn('}');
Fjs.WriteLn;
@ -1446,8 +1535,8 @@ begin
case d.DefType of
dtSet, dtEnum:
WriteClassInfoVar(d);
dtClass, dtRecord:
WriteClass(d, True);
dtClass:
WriteClass(TClassDef(d), True);
dtProcType:
WriteProcType(TProcDef(d), True);
end;
@ -1459,8 +1548,8 @@ begin
if not d.IsUsed then
continue;
case d.DefType of
dtClass, dtRecord:
WriteClass(d, False);
dtClass:
WriteClass(TClassDef(d), False);
dtProc:
WriteProc(TProcDef(d));
dtVar, dtProp:
@ -1473,6 +1562,8 @@ begin
WriteSet(TSetDef(d));
dtConst:
WriteConst(TConstDef(d));
dtPointer:
WritePointer(TPointerDef(d));
end;
end;
@ -1529,6 +1620,10 @@ begin
Fps.IncI;
Fps.WriteLn('ci^.ClassRef:=env^^.NewGlobalRef(env, c);');
Fps.WriteLn('Result:=ci^.ClassRef <> nil;');
Fps.WriteLn('if Result and (env^^.ExceptionCheck(env) = 0) then begin');
Fps.WriteLn('ci^.ConstrId:=env^^.GetMethodID(env, ci^.ClassRef, ''<init>'', ''(JZ)V'');', 1);
Fps.WriteLn('env^^.ExceptionClear(env);', 1);
Fps.WriteLn('end;');
Fps.WriteLn('if Result and (FieldName <> '''') then begin');
Fps.WriteLn('ci^.ObjFieldId:=env^^.GetFieldID(env, ci^.ClassRef, PAnsiChar(FieldName), PAnsiChar(FieldSig));', 1);
Fps.WriteLn('Result:=ci^.ObjFieldId <> nil;', 1);
@ -1603,29 +1698,38 @@ begin
Result:=Format('char(widechar(%s))', [Result]);
btWideChar:
Result:=Format('widechar(%s)', [Result]);
btPointer:
Result:=Format('pointer(ptruint(%s))', [Result]);
btGuid:
Result:=Format('StringToGUID(ansistring(_StringFromJString(_env, %s)))', [Result]);
else
Result:=Format('%s(%s)', [d.Name, Result]);
Result:=Format('%s.%s(%s)', [d.Parent.Name, d.Name, Result]);
end;
dtClass:
begin
if CheckNil then
if TClassDef(d).CType = ctRecord then
n:='True'
else
n:='False';
Result:=Format('%s.%s(_GetPasObj(_env, %s, %s, %s))', [d.Parent.Name, d.Name, Result, GetTypeInfoVar(d), n]);
if CheckNil then
n:='True'
else
n:='False';
Result:=Format('_GetPasObj(_env, %s, %s, %s)', [Result, GetTypeInfoVar(d), n]);
if TClassDef(d).CType in [ctObject, ctRecord] then
Result:=Result + '^';
Result:=Format('%s.%s(%s)', [d.Parent.Name, d.Name, Result]);
end;
dtRecord:
Result:=Format('%s.%s(_GetPasObj(_env, %s, %s, True)^)', [d.Parent.Name, d.Name, Result, GetTypeInfoVar(d)]);
dtProcType:
Result:=Format('%sGetHandler(_env, %s, %s)', [GetClassPrefix(d), Result, GetTypeInfoVar(d)]);
dtEnum:
Result:=Format('%s.%s(_GetIntObjValue(_env, %s, %s))', [d.Parent.Name, d.Name, Result, GetTypeInfoVar(d)]);
dtSet:
Result:=Format('%s.%s(%s(_GetIntObjValue(_env, %s, %s)))', [d.Parent.Name, d.Name, GetPasIntType(TSetDef(d).Size), Result, GetTypeInfoVar(d)]);
dtPointer:
begin
if TPointerDef(d).IsObjPtr then
Result:=Format('%s.%s(_GetPasObj(_env, %s, %s, True))', [d.Parent.Name, d.Name, Result, GetTypeInfoVar(d)])
else
Result:=Format('pointer(ptruint(%s))', [Result]);
end;
end;
end;
@ -1648,21 +1752,25 @@ begin
Result:=Format('jchar(%s)', [Result]);
btEnum:
Result:=Format('jint(%s)', [Result]);
btPointer:
Result:=Format('ptruint(pointer(%s))', [Result]);
btGuid:
Result:=Format('_StringToJString(_env, _JNIString(GUIDToString(%s)))', [Result]);
end;
dtClass:
Result:=Format('_CreateJavaObj(_env, %s, %s)', [Result, GetTypeInfoVar(d)]);
dtRecord:
Result:=Format('_%s_CreateObj(_env, %s)', [GetClassPrefix(d), Result]);
if TClassDef(d).CType in [ctObject, ctRecord] then
Result:=Format('_%s_CreateObj(_env, %s)', [GetClassPrefix(d), Result])
else
Result:=Format('_CreateJavaObj(_env, %s, %s)', [Result, GetTypeInfoVar(d)]);
dtProcType:
Result:=Format('_CreateMethodPtrObject(_env, TMethod(%s), %s)', [Result, GetTypeInfoVar(d)]);
dtEnum:
Result:=Format('_CreateIntObj(_env, longint(%s), %s)', [Result, GetTypeInfoVar(d)]);
dtSet:
Result:=Format('_CreateIntObj(_env, %s(%s), %s)', [GetPasIntType(TSetDef(d).Size), Result, GetTypeInfoVar(d)]);
dtPointer:
if TPointerDef(d).IsObjPtr then
Result:=Format('_CreateJavaObj(_env, %s, %s)', [Result, GetTypeInfoVar(d)])
else
Result:=Format('ptruint(pointer(%s))', [Result]);
end;
end;
@ -1922,7 +2030,7 @@ begin
Fps.WriteLn;
Fps.WriteLn(Format('{ %s }', [d.Name]));
Fjs.WriteLn(Format('/* %s %s */', [AType, d.Name]));
Fjs.WriteLn(Format('/* %s */', [Trim(AType + ' ' + d.Name)]));
{$ifdef DEBUG}
Fjs.WriteLn(Format('/* Ref count: %d */', [d.RefCnt]));
{$endif}
@ -2058,6 +2166,7 @@ begin
Fps.WriteLn;
Fps.WriteLn('_TJavaClassInfo = record');
Fps.WriteLn('ClassRef: JClass;', 1);
Fps.WriteLn('ConstrId: JMethodId;', 1);
Fps.WriteLn('ObjFieldId: JFieldId;', 1);
Fps.WriteLn('end;');
Fps.WriteLn('_PJavaClassInfo = ^_TJavaClassInfo;');
@ -2092,14 +2201,21 @@ begin
Fps.WriteLn('end;');
Fps.WriteLn;
Fps.WriteLn('function _CreateJavaObj(env: PJNIEnv; PasObj: pointer; const ci: _TJavaClassInfo): jobject;');
Fps.WriteLn('function _CreateJavaObj(env: PJNIEnv; PasObj: pointer; const ci: _TJavaClassInfo; cleanup: boolean = True): jobject;');
Fps.WriteLn('var v: array [0..1] of jvalue;');
Fps.WriteLn('begin');
Fps.IncI;
Fps.WriteLn('Result:=nil;');
Fps.WriteLn('if PasObj = nil then exit;');
Fps.WriteLn('Result:=env^^.AllocObject(env, ci.ClassRef);');
Fps.WriteLn('if Result = nil then exit;');
Fps.WriteLn('env^^.SetLongField(env, Result, ci.ObjFieldId, Int64(ptruint(PasObj)));');
Fps.WriteLn('v[0].J:=Int64(ptruint(PasObj));');
Fps.WriteLn('if ci.ConstrId = nil then begin');
Fps.WriteLn('Result:=env^^.AllocObject(env, ci.ClassRef);', 1);
Fps.WriteLn('if Result = nil then exit;', 1);
Fps.WriteLn('env^^.SetLongField(env, Result, ci.ObjFieldId, v[0].J);', 1);
Fps.WriteLn('end else begin');
Fps.WriteLn('v[1].Z:=byte(cleanup) and 1;', 1);
Fps.WriteLn('Result:=env^^.NewObjectA(env, ci.ClassRef, ci.ConstrId, @v);', 1);
Fps.WriteLn('end;');
Fps.DecI;
Fps.WriteLn('end;');
@ -2290,7 +2406,13 @@ begin
WriteOnLoad;
Fps.WriteLn;
Fps.WriteLn('procedure ___doexit;');
Fps.WriteLn('begin');
Fps.WriteLn('_MethodPointersCS.Free;', 1);
Fps.WriteLn('end;');
Fps.WriteLn;
Fps.WriteLn('begin');
Fps.WriteLn('ExitProc:=@___doexit;', 1);
Fps.WriteLn('IsMultiThread:=True;', 1);
Fps.WriteLn('_MethodPointersCS:=TCriticalSection.Create;', 1);
Fps.WriteLn('end.');