mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-31 10:31:44 +01:00 
			
		
		
		
	* 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:
		
							parent
							
								
									6fda08705b
								
							
						
					
					
						commit
						cddbe1b83d
					
				| @ -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; | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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.'); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 yury
						yury