Jump to content

Search the Community

Showing results for tags 'compiler'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Delphi Questions and Answers
    • Algorithms, Data Structures and Class Design
    • VCL
    • FMX
    • RTL and Delphi Object Pascal
    • Databases
    • Network, Cloud and Web
    • Windows API
    • Cross-platform
    • Delphi IDE and APIs
    • General Help
  • Delphi General Discussions
    • Tips / Blogs / Tutorials / Videos
    • Delphi Third-Party
    • Job Opportunities / Coder for Hire
    • I made this
  • Software Development
    • Project Planning and -Management
    • Software Testing and Quality Assurance
  • Community
    • Community Management

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Delphi-Version

Found 3 results

  1. Discussion started with: This is valid point, I must concede. We need to have an option to reference count just for explicitly designated object types and variables. And a first-class one, without need to build an interface wrapper. Which means not some crappy wrappers like shared_ptr, no, lets introduce compiler magic and (non-breaking) language changes. like FObject: auto TObject; // compiler, just manage the lifetime automacally type TMyRefObject = class auto (TObject) // all instances are automatic var manualRef := unsafe(RefCountedObject); // Compiler, I understand the risk, just give me raw pointer var autoInline := auto TObject.Create;// compiler, manage it automatically
  2. Primož Gabrijelčič

    Object destroyed too soon?

    Dear all, I'm being stupid and I can't figure why in the following code the `TTestObj` is destroyed before its owner. Can you please help? Full code is available here and is also posted at the end of this post. Basically, I have an interface `IWorkItem` which owns record `TOmniValue` which owns interface `IAutoDestroyObject`. The code creates an instance of `IWorkItem` and then calls: procedure Test(const workItem: IWorkItem); begin workItem.Result.AsOwnedObject := TTestObj.Create; end; This sets the `IAutoDestroyObject` field of the nested `TOmniValue` record. When the `Test` function exits (during the procedure finalization code) this `TTestObj` gets destroyed, and I can't figure out why. program ObjectDestroyedTooSoon; {$APPTYPE CONSOLE} {$R *.res} uses Winapi.Windows, System.SysUtils; type TTestObj = class public destructor Destroy; override; end; IAutoDestroyObject = interface ['{30CF4CCF-9383-41C0-BBA3-E24F7C4EFF71}'] function GetObj: TObject; property Obj: TObject read GetObj; end; TAutoDestroyObject = class(TInterfacedObject, IAutoDestroyObject) strict private FObject: TObject; protected function GetObj: TObject; public constructor Create(obj: TObject); destructor Destroy; override; property Obj: TObject read GetObj; end; TOmniValue = record private FOwnedObject: IAutoDestroyObject; function GetAsOwnedObject: TObject; procedure SetAsOwnedObject(const Value: TObject); public property AsOwnedObject: TObject read GetAsOwnedObject write SetAsOwnedObject; end; IWorkItem = interface ['{7C583FC8-90DD-46A5-81B9-81B911AA1CBE}'] function GetResult: TOmniValue; procedure SetResult(const Value: TOmniValue); property Result: TOmniValue read GetResult write SetResult; end; TWorkItem = class(TInterfacedObject, IWorkItem) strict private FResult: TOmniValue; strict protected function GetResult: TOmniValue; procedure SetResult(const Value: TOmniValue); public destructor Destroy; override; property Result: TOmniValue read GetResult write SetResult; end; { TTestObj } destructor TTestObj.Destroy; begin Writeln('TTestObj destroyed'); inherited; end; { TWorkItem } destructor TWorkItem.Destroy; begin Writeln('TWorkItem destroyed'); inherited; end; function TWorkItem.GetResult: TOmniValue; begin Result := FResult; end; procedure TWorkItem.SetResult(const Value: TOmniValue); begin FResult := Value; end; { TOmniValue } function TOmniValue.GetAsOwnedObject: TObject; begin Result := FOwnedObject.Obj; end; procedure TOmniValue.SetAsOwnedObject(const Value: TObject); begin FOwnedObject := TAutoDestroyObject.Create(Value); end; { TAutoDestroyObject } constructor TAutoDestroyObject.Create(obj: TObject); begin inherited Create; FObject := obj; end; destructor TAutoDestroyObject.Destroy; begin FreeAndNil(FObject); inherited; end; function TAutoDestroyObject.GetObj: TObject; begin Result := FObject; end; { main } procedure Test(const workItem: IWorkItem); begin workItem.Result.AsOwnedObject := TTestObj.Create; end; var workItem: IWorkItem; begin try workItem := TWorkItem.Create; Test(workItem); Writeln('After Test'); workItem := nil; Writeln('workItem destroyed'); Readln; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end.
  3. I have the following code (Delphi Berlin): interface type TSliver = record public private case integer of 8: (Data8: int64); end; TSlice = record private FData: array [0..63] of byte; end; TSliverHelper = record helper for TSliver class function NS(const North, South: TSlice; out Changed: TSliverChanges): TSliver; static; inline; end; {$L 'C:\mydir\AVXGenerate.o'} //imported assembly generated by lazarus. procedure AVXGENERATE_TSLIVERHELPER_NS; external name 'AVXGENERATE_$$_TSLIVERHELPER_NS'; //no parameters for simplicity. implementation class function TSliverHelper.NS(const North, South: TSlice; out Changed: TSliverChanges): TSliver; {inline;} //RCX =North: PSlice //RDX =South: PSlice //R8 = Changed: PSliverChanges ((scUnchanged=0, scChanged=1, scInvalid=3)); //RAX = Result: TSliver (as Int64) begin AVXGENERATE_TSLIVERHELPER_NS; end; //asm // jmp AVXGENERATE_TSLIVERHELPER_NS; //end; The asm method works correctly, the inlined method does not. If we look at the generated code it's easy to see why this happens. a:= TSliver.NSTest(N,S,statusA); //a = -1 UnitTests.pas.877: b:= TSliver.NS(N,S, statusB); 00000000009A77CE 488D8C2480000000 lea rcx,[rsp+$0080] 00000000009A77D6 488D542440 lea rdx,[rsp+$40] 00000000009A77DB 4C8D44242E lea r8,[rsp+$2e] 00000000009A77E0 E82B5E0100 call TSliverHelper.NS 00000000009A77E5 4889442430 mov [rsp+$30],rax //b = 7 why? //Let's see what's happening in the inlined method. class function TSliverHelper.NS(const [ref] N,S: TBigRec; out status: TEnumRec): UInt64_Rec; Unit2.pas.4360: begin 00000000009BD610 55 push rbp 00000000009BD611 4883EC30 sub rsp,$30 00000000009BD615 488BEC mov rbp,rsp Unit2.pas.4361: AVXGENERATE_TSLIVERHELPER_NS; 00000000009BD618 E833350000 call AVXGENERATE_TSLIVERHELPER_NS //external asm procedure with no declared params. Unit2.pas.4362: end; //At this point RAX = result = -1, all OK 00000000009BD61D 488B4528 mov rax,[rbp+$28] //Oops, RAX gets overwritten, why? <<<<??????????????????????? 00000000009BD621 488D6530 lea rsp,[rbp+$30] 00000000009BD625 5D pop rbp 00000000009BD626 C3 ret Why does the compiler insert an assignment to RAX? I have not instructed it to do anything of the sort. Compiling this code also does not issue a warning that Result might be unassigned. Why does the compiler do this? (I know I can fix this by declaring the external proc as a function, but that's beside the point). EDIT When we redefine the external proc as a function and change the inline method as shown below, correct code gets generated. It also gives some insight what is going on: Unit2.pas.4360: begin 00000000009BD610 55 push rbp 00000000009BD611 4883EC30 sub rsp,$30 00000000009BD615 488BEC mov rbp,rsp Unit2.pas.4361: Result:= AVXGENERATE_TSLIVERHELPER_NS; 00000000009BD618 E833350000 call AVXGENERATE_TSLIVERHELPER_NS 00000000009BD61D 48894528 mov [rbp+$28],rax //pointless stack trashing Unit2.pas.4362: end; 00000000009BD621 488B4528 mov rax,[rbp+$28] //the exit code expects Result to be in the stackframe. 00000000009BD625 488D6530 lea rsp,[rbp+$30] 00000000009BD629 5D pop rbp 00000000009BD62A C3 ret The compiler is just copy pasting its exit code, regardless of the actual code in the body. Note that I've compiled the code with no stackframes
×