unit RuntimeBuilder.Fasm; interface //{$INLINE auto} uses System.Classes,System.TypInfo,System.IOUtils,System.Rtti,System.Generics.Collections,Winapi.Windows, RuntimeBuilder,FasmOnDelphi; type TRTBFasmCompiler=class(TRTBCompiler) protected type TRTBFasmSource=class(TRTBSource) protected type TRTBFasmModule=class(TRTBModule) protected type TRTBFasmFunc=class(TRTBFunc) protected p:Pointer; public constructor Create(p:Pointer); function Call(OutType:PTypeInfo;args:TArray;CallType:TRTBCallType=CRTBCallTypeDefault):TValue;override; destructor Destroy;override; end; TRTBFasmVar=class(TRTBVar) protected p:pointer; &Type:TRTBType; procedure SetVal(Val:TValue);override; function GetVal:TValue;override; public constructor Create(p:pointer;&Type:TRTBType); destructor Destroy;override; end; protected p:Pointer; sb:NativeUInt; funcs:TDictionary; regvars:TDictionary>; function GetFuntion(Name:string):TRTBFunc;override; function GetVar(Name:string):TRTBVar;override; public constructor Create(p:Pointer;sb:NativeUInt;funcs:TDictionary;regvars:TDictionary>); destructor Destroy;override; end; protected libs:TStringList; funcs:TStringList; regvars:TList>; consts:TList>; callbacks:TList>; FText:string; function GetIncLibs():string; function GetText:string;override; procedure SetText(const S:string);override; public constructor Create(Compiler:TRTBFasmCompiler); procedure LoadLib(const Name:string);override; procedure UnLoadLib(const Name:string);override; procedure AddNameSpace(const Name:string);override; procedure DelNameSpace(const Name:string);override; procedure AddType(const NameSpace,Name:string;&Type:TRTBType);override;//- procedure DelType(const NameSpace,Name:string);override;//- procedure AddConst(const NameSpace,Name:string;Val:TValue);override; procedure DelConst(const NameSpace,Name:string);override; procedure AddVariable(const NameSpace,Name:string;var Data);override; procedure ExportVariable(const NameSpace,Name:string;var Data);override; procedure DelVariable(const NameSpace,Name:string);override; procedure AddCallBack(const NameSpace,Name:string;CallBack:TRTBCallBack);override; procedure DelCallBack(const NameSpace,Name:string);override; procedure &Register(const NameSpace,Name:string;&Type:TRTBType);override; procedure UnRegister(const NameSpace,Name:string);override; procedure RegisterFunction(const NameSpace,Name:string);override; procedure UnRegisterFunction(const NameSpace,Name:string);override; function Compilate:TRTBModule;override; destructor Destroy;override; end; public CompilerMem:NativeUInt; MaxSteps:word; constructor Create(FasmPath:String=FasmPath;AsDll:boolean=false); function GenNewSrc():TRTBSource;override; end; implementation uses System.SysUtils; function CallBackCall(callbacks:TList>;n:NativeUInt;p:pointer):pointer;stdcall; begin with callbacks[n].Value([p])do begin Result:=GetMemory(DataSize); ExtractRawData(Result); end; end; constructor TRTBFasmCompiler.TRTBFasmSource.TRTBFasmModule.TRTBFasmFunc.Create(p:Pointer); begin inherited Create(); Self.p:=p; end; function TRTBFasmCompiler.TRTBFasmSource.TRTBFasmModule.TRTBFasmFunc.Call(OutType:PTypeInfo;args:TArray;CallType:TRTBCallType=CRTBCallTypeDefault):TValue; begin {$IFDEF CPUX64} Result:=Invoke(p,args,ccReg,OutType); {$ELSE} case CallType of CRTBCallTypeRegister:Result:=Invoke(p,args,ccReg,OutType); CRTBCallTypeStdCall:Result:=Invoke(p,args,ccStdCall,OutType); CRTBCallTypeCdecl:Result:=Invoke(p,args,ccCdecl,OutType); CRTBCallTypePascal:Result:=Invoke(p,args,ccPascal,OutType); CRTBCallTypeSafeCall:Result:=Invoke(p,args,ccSafeCall,OutType); end; {$ENDIF} end; destructor TRTBFasmCompiler.TRTBFasmSource.TRTBFasmModule.TRTBFasmFunc.Destroy; begin p:=nil; end; procedure TRTBFasmCompiler.TRTBFasmSource.TRTBFasmModule.TRTBFasmVar.SetVal(Val:TValue); begin if Val.TypeInfo=&Type then Val.ExtractRawData(p); end; function TRTBFasmCompiler.TRTBFasmSource.TRTBFasmModule.TRTBFasmVar.GetVal:TValue; begin TValue.Make(p,&Type,Result); end; constructor TRTBFasmCompiler.TRTBFasmSource.TRTBFasmModule.TRTBFasmVar.Create(p:pointer;&Type:TRTBType); begin Self.p:=p; Self.&Type:=&Type; end; destructor TRTBFasmCompiler.TRTBFasmSource.TRTBFasmModule.TRTBFasmVar.Destroy; begin p:=nil; &Type:=nil; end; function TRTBFasmCompiler.TRTBFasmSource.TRTBFasmModule.GetFuntion(Name:string):TRTBFunc; begin Result:=TRTBFasmFunc.Create(PPointer(NativeUInt(funcs.Items[Name])+NativeUInt(p))^); end; function TRTBFasmCompiler.TRTBFasmSource.TRTBFasmModule.GetVar(Name:string):TRTBVar; begin Result:=TRTBFasmVar.Create(PPointer(NativeUInt(regvars.Items[Name].Key)+NativeUInt(p))^,regvars.Items[Name].Value) end; constructor TRTBFasmCompiler.TRTBFasmSource.TRTBFasmModule.Create(p:Pointer;sb:NativeUInt;funcs:TDictionary;regvars:TDictionary>); begin Self.p:=p; Self.sb:=sb; Self.funcs:=funcs; Self.regvars:=regvars; end; destructor TRTBFasmCompiler.TRTBFasmSource.TRTBFasmModule.Destroy; begin VirtualFree(p,sb,MEM_RELEASE); end; function TRTBFasmCompiler.TRTBFasmSource.GetIncLibs():string; var i:integer; begin Result:=''; for i:=0 to libs.count-1 do Result:=Result+sLineBreak+'include '+#39+libs.Strings[i]+#39; end; function TRTBFasmCompiler.TRTBFasmSource.GetText:string; begin Result:=FText; end; procedure TRTBFasmCompiler.TRTBFasmSource.SetText(const S:string); begin FText:=S; end; constructor TRTBFasmCompiler.TRTBFasmSource.Create(Compiler:TRTBFasmCompiler); begin inherited Create(Compiler); FText:=''; libs:=TStringList.Create; funcs:=TStringList.Create; regvars:=TList>.Create; consts:=TList>.Create; callbacks:=TList>.Create; end; procedure TRTBFasmCompiler.TRTBFasmSource.LoadLib(const Name:string); begin libs.Add(Name); end; procedure TRTBFasmCompiler.TRTBFasmSource.UnLoadLib(const Name:string); begin with libs do Delete(IndexOf(Name)); end; procedure TRTBFasmCompiler.TRTBFasmSource.AddNameSpace(const Name:string); begin end; procedure TRTBFasmCompiler.TRTBFasmSource.DelNameSpace(const Name:string); label funcscontinue,regvarscontinue,constscontinue; var i,i0:NativeUInt; tName:string; begin tName:=Name+'.'; i:=0; while i'' then consts.Add(TPair.Create(NameSpace+'.'+Name,Val)) else consts.Add(TPair.Create(Name,Val)); end; procedure TRTBFasmCompiler.TRTBFasmSource.DelConst(const NameSpace,Name:string); var i:NativeUInt; begin if consts.Count<>0 then for i:=0 to consts.Count-1 do if(consts.Items[i].Key=NameSpace+'.'+Name)or(consts.Items[i].Key=Name)then begin consts.Delete(i); Break; end; end; procedure TRTBFasmCompiler.TRTBFasmSource.AddVariable(const NameSpace,Name:string;var Data); begin if NameSpace<>'' then consts.Add(TPair.Create(NameSpace+'.'+Name,addr(Data))) else consts.Add(TPair.Create(Name,addr(Data))); end; procedure TRTBFasmCompiler.TRTBFasmSource.ExportVariable(const NameSpace,Name:string;var Data); begin if NameSpace<>'' then consts.Add(TPair.Create(NameSpace+'.'+Name,Addr(Data))) else consts.Add(TPair.Create(Name,Addr(Data))); end; procedure TRTBFasmCompiler.TRTBFasmSource.DelVariable(const NameSpace,Name:string); begin DelConst(NameSpace,Name); end; procedure TRTBFasmCompiler.TRTBFasmSource.AddCallBack(const NameSpace,Name:string;CallBack:TRTBCallBack); begin if NameSpace<>'' then callbacks.Add(TPair.Create(NameSpace+'.'+Name,CallBack)) else callbacks.Add(TPair.Create(Name,CallBack)); end; procedure TRTBFasmCompiler.TRTBFasmSource.DelCallBack(const NameSpace,Name:string); var i:NativeUInt; begin if callbacks.Count<>0 then for i:=0 to callbacks.Count-1 do if(callbacks.Items[i].Key=NameSpace+'.'+Name)or(callbacks.Items[i].Key=Name)then begin callbacks.Delete(i); Break; end; end; procedure TRTBFasmCompiler.TRTBFasmSource.&Register(const NameSpace,Name:string;&Type:TRTBType); begin if NameSpace<>'' then regvars.Add(TPair.Create(NameSpace+'.'+Name,&Type)) else regvars.Add(TPair.Create(Name,&Type)); end; procedure TRTBFasmCompiler.TRTBFasmSource.UnRegister(const NameSpace,Name:string); var i:NativeUInt; begin if regvars.Count<>0 then for i:=0 to regvars.Count-1 do if(regvars.Items[i].Key=Name)or(regvars.Items[i].Key=NameSpace+'.'+Name) then begin regvars.Delete(i); Break; end; end; procedure TRTBFasmCompiler.TRTBFasmSource.RegisterFunction(const NameSpace,Name:string); begin if NameSpace<>'' then funcs.Add(NameSpace+'.'+Name) else funcs.Add(Name); end; procedure TRTBFasmCompiler.TRTBFasmSource.UnRegisterFunction(const NameSpace,Name:string); begin with funcs do begin Delete(IndexOf(NameSpace+'.'+Name)); Delete(IndexOf(Name)); end; end; function TRTBFasmCompiler.TRTBFasmSource.Compilate:TRTBModule; procedure VarParse(key:string;Value:TValue;var PreDecl:string;var base:NativeUInt); var i:NativeUInt; p0:PByte; rfield:TRttiField; rmetod:TRttiMethod; begin if Value.IsType or Value.IsType or Value.IsType then begin PreDecl:=PreDecl+Key+' db '+#39+Value.AsType+#39+',0'+sLineBreak; inc(base,length(Value.AsType)); end else if Value.IsType then begin PreDecl:=PreDecl+Key+' db '+#39+Value.AsType+#39+',0'+sLineBreak; inc(base,length(Value.AsType)); end else if Value.IsType then begin PreDecl:=PreDecl+Key+' db '; p0:=Pointer(PWideChar(Value.AsType)); for i:={$IFDEF NEXTGEN}0{$ELSE}1{$ENDIF} to length(Value.AsType){$IFDEF NEXTGEN}-1{$ENDIF} do begin PreDecl:=PreDecl+inttostr(p0^)+','; inc(p0); PreDecl:=PreDecl+inttostr(p0^)+','; inc(p0); end; PreDecl:=PreDecl+'0,0'+sLineBreak; inc(base,length(Value.AsType)*2); end else if Value.IsType then begin PreDecl:=PreDecl+Key+' db '; p0:=Pointer(PWideChar(Value.AsType)); for i:={$IFDEF NEXTGEN}0{$ELSE}1{$ENDIF} to length(Value.AsType){$IFDEF NEXTGEN}-1{$ENDIF} do begin PreDecl:=PreDecl+inttostr(p0^)+','; inc(p0); PreDecl:=PreDecl+inttostr(p0^)+','; inc(p0); PreDecl:=PreDecl+inttostr(p0^)+','; inc(p0); PreDecl:=PreDecl+inttostr(p0^)+','; inc(p0); end; PreDecl:=PreDecl+'0,0,0,0'+sLineBreak; inc(base,length(Value.AsType)*4); end else if Value.IsOrdinal then begin case Value.DataSize of 1:PreDecl:=PreDecl+Key+' db '+Value.AsOrdinal.ToString+sLineBreak; 2:PreDecl:=PreDecl+Key+' dw '+Value.AsOrdinal.ToString+sLineBreak; 4:PreDecl:=PreDecl+Key+' dd '+Value.AsOrdinal.ToString+sLineBreak; 8:PreDecl:=PreDecl+Key+' dq '+Value.AsOrdinal.ToString+sLineBreak; end; inc(base,Value.DataSize); end else if Value.Kind=tkFloat then begin if Value.IsType then PreDecl:=PreDecl+Key+' dd '+FloatToStrF(Value.AsType,ffFixed,1000,1000)+sLineBreak else if Value.IsType then PreDecl:=PreDecl+Key+' dq '+FloatToStrF(Value.AsType,ffFixed,1000,1000)+sLineBreak else if Value.IsType then PreDecl:=PreDecl+Key+{$IF 8=SizeOf(Extended)}' dq '{$ELSEIF 10=SizeOf(Extended)}' dt '{$ELSE}' ddq '{$IFEND}+FloatToStrF(Value.AsType,ffFixed,1000,1000)+sLineBreak else if Value.IsType then PreDecl:=PreDecl+Key+' dq '+FloatToStrF(Value.AsType,ffFixed,1000,1000)+sLineBreak else if Value.IsType then PreDecl:=PreDecl+Key+' df '+FloatToStrF(Value.AsType,ffFixed,1000,1000)+sLineBreak else if Value.IsType then PreDecl:=PreDecl+Key+' dq '+FloatToStrF(Value.AsType,ffFixed,1000,1000)+sLineBreak else if Value.IsType then PreDecl:=PreDecl+Key+' dq '+FloatToStrF(Value.AsType,ffFixed,1000,1000)+sLineBreak else PreDecl:=PreDecl+Key+' dd 0.0'+sLineBreak; end else if Value.Kind=tkPointer then begin case SizeOf(pointer) of 2:PreDecl:=PreDecl+Key+' dw '+NativeUInt(Value.AsType).ToString+sLineBreak; 4:PreDecl:=PreDecl+Key+' dd '+NativeUInt(Value.AsType).ToString+sLineBreak; 8:PreDecl:=PreDecl+Key+' dq '+NativeUInt(Value.AsType).ToString+sLineBreak; end; inc(base,SizeOf(pointer)); end else if Value.IsArray then begin if Value.GetArrayLength=0 then begin PreDecl:=PreDecl+Key+' equ 0'+sLineBreak; end else begin PreDecl:=PreDecl+Key+':'+sLineBreak; for i:=0 to Value.GetArrayLength-1 do VarParse(key+'.i'+i.ToString,Value.GetArrayElement(i),PreDecl,Base); end; end else if Value.Kind=tkRecord or Value.IsClass then begin PreDecl:=PreDecl+Key+':'+sLineBreak; for rfield in TRTTIContext.Create.GetType(Value.TypeInfo).GetFields do VarParse(key+'.'+rfield.Name,rfield.GetValue(@Value),PreDecl,base); for rmetod in TRTTIContext.Create.GetType(Value.TypeInfo).GetMethods do begin PreDecl:=PreDecl+key+'.'+rmetod.Name+' dd '+NativeUInt(rmetod.CodeAddress).ToString; case SizeOf(pointer) of 2:PreDecl:=PreDecl+Key+' dw '+NativeUInt(Value.AsType).ToString+sLineBreak; 4:PreDecl:=PreDecl+Key+' dd '+NativeUInt(Value.AsType).ToString+sLineBreak; 8:PreDecl:=PreDecl+Key+' dq '+NativeUInt(Value.AsType).ToString+sLineBreak; end; inc(base,SizeOf(pointer)); end; end else //if Value.Kind=tkUnknown then PreDecl:=PreDecl+Key+': times '+ Value.DataSize.ToString+' db 0'+sLineBreak; end; procedure ConstParse(key:string;value:TValue;var PreDecl:string;var base:NativeUInt); var i:NativeUInt; p0:PByte; begin if Value.IsType or Value.IsType or Value.IsType then begin PreDecl:=PreDecl+Key+' db '+#39+Value.AsType+#39+',0'+sLineBreak; inc(base,length(Value.AsType)); end else if Value.IsType then begin PreDecl:=PreDecl+Key+' db '+#39+Value.AsType+#39+',0'+sLineBreak; inc(base,length(Value.AsType)); end else if Value.IsType then begin PreDecl:=PreDecl+Key+' db '; p0:=Pointer(PWideChar(Value.AsType)); for i:={$IFDEF NEXTGEN}0{$ELSE}1{$ENDIF} to length(Value.AsType){$IFDEF NEXTGEN}-1{$ENDIF} do begin PreDecl:=PreDecl+inttostr(p0^)+','; inc(p0); PreDecl:=PreDecl+inttostr(p0^)+','; inc(p0); end; PreDecl:=PreDecl+'0,0'+sLineBreak; inc(base,length(Value.AsType)*2); end else if Value.IsType then begin PreDecl:=PreDecl+Key+' db '; p0:=Pointer(PWideChar(Value.AsType)); for i:={$IFDEF NEXTGEN}0{$ELSE}1{$ENDIF} to length(Value.AsType){$IFDEF NEXTGEN}-1{$ENDIF} do begin PreDecl:=PreDecl+inttostr(p0^)+','; inc(p0); PreDecl:=PreDecl+inttostr(p0^)+','; inc(p0); PreDecl:=PreDecl+inttostr(p0^)+','; inc(p0); PreDecl:=PreDecl+inttostr(p0^)+','; inc(p0); end; PreDecl:=PreDecl+'0,0,0,0'+sLineBreak; inc(base,length(Value.AsType)*4); end else if Value.IsOrdinal then PreDecl:=PreDecl+Key+' equ '+Value.AsOrdinal.ToString+sLineBreak else if Value.Kind=tkFloat then begin if Value.IsType then PreDecl:=PreDecl+Key+' equ '+FloatToStrF(Value.AsType,ffFixed,1000,1000)+sLineBreak else if Value.IsType then PreDecl:=PreDecl+Key+' equ '+FloatToStrF(Value.AsType,ffFixed,1000,1000)+sLineBreak else if Value.IsType then PreDecl:=PreDecl+Key+' equ '+FloatToStrF(Value.AsType,ffFixed,1000,1000)+sLineBreak else if Value.IsType then PreDecl:=PreDecl+Key+' equ '+FloatToStrF(Value.AsType,ffFixed,1000,1000)+sLineBreak else if Value.IsType then PreDecl:=PreDecl+Key+' equ '+FloatToStrF(Value.AsType,ffFixed,1000,1000)+sLineBreak else if Value.IsType then PreDecl:=PreDecl+Key+' equ '+FloatToStrF(Value.AsType,ffFixed,1000,1000)+sLineBreak else if Value.IsType then PreDecl:=PreDecl+Key+' equ '+FloatToStrF(Value.AsType,ffFixed,1000,1000)+sLineBreak else PreDecl:=PreDecl+Key+' equ 0.0'+sLineBreak; end else if Value.Kind=tkPointer then PreDecl:=PreDecl+Key+' equ '+NativeUInt(Value.AsType).ToString+sLineBreak else if Value.IsArray then begin if Value.GetArrayLength=0 then begin PreDecl:=PreDecl+Key+' equ 0'+sLineBreak; end else begin PreDecl:=PreDecl+Key+':'+sLineBreak; for i:=0 to Value.GetArrayLength-1 do VarParse(key+'.i'+i.ToString,Value.GetArrayElement(i),PreDecl,Base); end; end else VarParse(key,Value,PreDecl,Base); end; var pointerDecl,PreDecl:string; Res:TFasmResult; i,base,sb:NativeUInt; FuncDict:TDictionary; RegVarDict:TDictionary>; p:pointer; begin sb:=(Compiler as TRTBFasmCompiler).CompilerMem; p:=VirtualAlloc(nil,sb,MEM_COMMIT,PAGE_EXECUTE_READWRITE); case SizeOf(pointer)of 2:pointerDecl:='dw '; 4:pointerDecl:='dd '; 8:pointerDecl:='dq '; end; PreDecl:='use32'+sLineBreak; FuncDict:=TDictionary.Create(); base:=0; with funcs do if Count<>0 then for i:=0 to Count-1 do begin PreDecl:=PreDecl+pointerDecl+Strings[i]+sLineBreak; FuncDict.Add(Strings[i],base); inc(base,SizeOf(pointer)); end; RegVarDict:=TDictionary>.Create(); with regvars do if Count<>0 then for i:=0 to Count-1 do begin PreDecl:=PreDecl+pointerDecl+Items[i].Key+sLineBreak; RegVarDict.Add(Items[i].Key,TPair.Create(base,Items[i].Value)); inc(base,SizeOf(pointer)); end; with consts do if Count<>0 then for i:=0 to Count-1 do with Items[i] do ConstParse(Key,Value,PreDecl,base); if callbacks.Count<>0 then for i:=0 to callbacks.Count-1 do PreDecl:=PreDecl+callbacks[i].Key+':'+sLineBreak+ {$IFDEF CPU32BITS}'pop eax'{$ELSE}'pop rax'{$ENDIF}+sLineBreak+ {$IFDEF CPU32BITS}'push dword '{$ELSE}'push qword '{$ENDIF}+i.ToString+sLineBreak+ {$IFDEF CPU32BITS}'push dword '{$ELSE}'push qword '{$ENDIF}+NativeUint(pointer(callbacks)).ToString+sLineBreak+ {$IFDEF CPU32BITS}'push eax'{$ELSE}'push rax'{$ENDIF}+sLineBreak+ {$IFDEF CPU32BITS}'jmp dword '{$ELSE}'jmp qword '{$ENDIF}+NativeUint(@CallBackCall).ToString+sLineBreak; Res:=FasmAssemble('org '+NativeUInt(p).ToString+sLineBreak+PreDecl+Text+GetIncLibs,sb,(Compiler as TRTBFasmCompiler).MaxSteps); if Res.Error<>FASM_OK then begin VirtualFree(p,sb,MEM_RELEASE); raise Exception.Create(Res.OutStr); end; VirtualAlloc(p,Res.sb,MEM_COMMIT,PAGE_EXECUTE_READWRITE); CopyMemory(p,Res.OutData,Res.sb); FreeMem(Res.OutData); Result:=TRTBFasmModule.Create(p,Res.sb,FuncDict,RegVarDict); p:=nil; end; destructor TRTBFasmCompiler.TRTBFasmSource.Destroy; begin FreeAndNil(libs); FreeAndNil(funcs); FreeAndNil(regvars); FreeAndNil(consts); end; constructor TRTBFasmCompiler.Create(FasmPath:String=FasmPath;AsDll:boolean=false); begin inherited Create(); CompilerMem:=1024*1024*16; MaxSteps:=65535; OpenFASM(FasmPath,AsDll); end; function TRTBFasmCompiler.GenNewSrc():TRTBSource; begin Result:=TRTBFasmSource.Create(Self); end; end.