A bold guess for the Object Pascal compiler to assign a stack memory detail (on)

zhaozj2021-02-11  170

A bold guess for the Object Pascal compiler to assign a stack of memory details (below)

9CBS roast chicken wings

I have read the netizens of my previous article, I know that I am a guy who likes "the root of the roots", "dead drill angle". Recently, since the work needs to be transferred to Delphi, after exposure to Object Pascal, it really appreciates its neat and beautiful, and the author of "programming language: design and realization" is also praised by Pascal is "a very beautiful language". However, there have been many problems in the learning process, especially those who learn from C to OP [Object Pascal, because I have different languages, and the question mark will be more. Among them, a big difference in the OP and C languages ​​is: the memory allocation mechanism of the class object [or known as the class instance] is different. Two of them have to say:

First, when is it allocated?

In C , the object is defined, then the memory is allocated, then the constructor is called, this memory may be in the stack, or may be in the full data area. But OP is very different, defines an object, such as: Obj: TOBJECT; just assigns 4 bytes of a pointer space, and the real object space has not been assigned, how is it used? Of course, it is necessary to assign space to the object before use, or it will cause access to memory errors, and it is also simple to assign space to objects:

Obj: = TOBJECT.CREATE;

OK, this object space is allocated in the heap, you know that in the stack is automatically recycled after the use period, but the pluck memory needs the programmer to manage itself, so after using the class object, don't forget obj.free [True implementation is Obj.Destroy, but Obj.Free is a safer way].

"When to assign" this problem is indeed different on the answer on OP and C , but it is not "doubts". I know that the OP class object is to get such a statement (constructor): obj: = TOBJECT.CREATE; how to get a stack of memory, how is the compiler to allocate a stack memory inside?

Please see the next question:

Second, how does the OP compiler allocated?

First of all, I would like to thank Lippman's "Inside C Ojbect Model". This is a non-much good book. She told you some of you most confused for C compiler, but also the details of the most, but I don't know the Delphi industry. Is there such a book, you can make me clearly understand how the OP compiler is specific [specific to each detail] how to assign a stack memory for a class object [If there is such a book, you must notify me: CODER @ Vip.sina.com]?

I boldly guess!

Some small actions are already defined in advance within the TOBJECT class! Let's pay attention to these Tobject class methods (TOBJECT is defined in system.pas):

TOBJECT = Class

......

Constructor crete;

PROCEDURE FREE

Class Function InitInstance (Instance: Pointer): TOBJECT;

Procedure Cleanupinstance;

Class Function InstanceSize: longint;

Class function newinstance: TOBJECT; Virtual

DESTRUCTOR DESTROY; Virtual;

END;

From the name of the method, we can faint feelings: NewInstance and FreeInstance are sure and descriptions of the structure and destructors of the class!

First analyze newinstance:

Class Function TOBJECT.NEWINSTANCE: TOBJECT

Begin

Result: = INITINSTANCE (_getMem (instancesize));

END;

There is only one code, but three other methods are called:

1,

Class Function TOBJECT.INSTANCESIZE: Longint

Begin

Result: = Pinteger (Integer VmtinstanceSize) ^

END;

This method is an important way to implement RTTI, which can return to the size of the stack memory. Note that it is not the size of the class object, because the class object is a pointer, then in the 32-bit environment, The pointer is always 4 bytes!

Everyone may be confused about this code: = Pinteger (Integer (Self) VmtinstanceSize) ^; I define a OP class:

TBASE = Class (TOBJECT)

x: integer;

Y: Double;

Constructor crete;

END;

Then allocate memory:

B: TBASE;

B: = TBASE.CREATE;

I envisage the distributed memory layout should be such a [Memory to consider the memory of the C object]:

Look at this sentence: Result: = Pinteger (Integer (Self) VmtinstanceSize) ^; its purpose is to take the content in the VMT index = -40 [Note: Constant VMTINSTANCESIZE = -40]. Everyone sees here

What is the value of the SELF variable? Is B's value is also VPTR's address? Absolutely not! Because the program is executing how many stacks are required to be divided by calling it, it is not officially assigned a stack memory, that is, VPTR, X, Y does not exist [but VMT is established together with the class. It contains some information related to the class. If the class instance needs to request the size of the memory, the size of the memory, etc.], of course, this self cannot be b value, I guess its content is INDEX = 0 Terries' address, only this, the code here, the code you want can be explained normally, but how is SELF being assigned to this value, I want to be the process made by the compiler.

In this way, Result: = Pinteger (Integer (Self) VMTINSTANCESIZE) ^ Nature Get information on the number of memory size!

In order to prove that my guess is correct, everyone can experiment with the following code:

VAR

B: TBASE;

SIZE_B: Integer;

Begin

B: = TBASE.CREATE;

ShowMessage (Format ('INITANCESIZE OF TBASE:% D', [B.InstanceSize]);

SIZE_B: = Pinteger (pinteger (b) ^ - 40) ^;

ShowMessage (Format ('INITANCESIZE OF TBASE:% D', [SIZE_B])); ......

END;

Everyone can see that the two methods get the same value!

Ok, now we go back to explain the second function to be called in Tobject.newInstance.

2, function _getmem (size: integer): Pointer;

It is defined in System.PAS as follows:

Function _getmem (size: integer): Pointer;

{$ If defined (debug) and defined (linux)}

VAR

Signature: Plongint;

{$ Ifend}

Begin

IF size> 0 THEN

Begin

{$ If defined (debug) and defined (linux)}

Signature: = Plongint (MemoryManager.getMem (Size 4));

if Signature = NIL THEN

Error (ReutofMemory);

SIGNATURE ^: = 0;

Result: = POINTER (Longint (Signature) 4);

{$ Else}

Result: = MemoryManager.getMem (size);

if Result = nil dam

Error (ReutofMemory);

{$ Ifend}

end

Else

Result: = NIL;

END;

The specific code is not analyzed, but we finally saw the specific function of allocating the memory in the OP, which is OP is the heap memory space acquired by a memory manager MemoryManager!

The third call in TOBJECT.NEWINSTANCE:

3,

Class Function TOBJECT.INITINSTANCE (Instance: Pointer): TOBJECT

{IFDEF PurePascal}

VAR

INTFTABLE: PINTERFACETABLE;

Classptr: TCLASS;

I: integer;

Begin

Fillchar (Instance ^, InstanceSize, 0);

Pinteger (Instance) ^: = Integer (Self);

Classptr: = Self;

While Classptruth <> NIL DO

Begin

INTFTABLE: = Classptr.getInterfaceTable;

IF INTFTABLE <> NIL THEN

For i: = 0 to intftable.Entrycount-1 DO

With intftable.entries [i] do

Begin

IF vTable <> nil dam

Pinteger (@pchar (instance) [ioffset]) ^: = integer (vTable);

END;

Classptr: = Classptr.classParent;

END;

RESULT: = Instance;

END;

{$ Else}

ASM

Push EBX

PUSH ESI

Push EDI

MOV EBX, EAX

MOV EDI, EDX

Stosd

MOV ECX, [EBX] .VmtinstanceSize

XOR EAX, EAX

Push ECX

SHR ECX, 2

Dec ECX

Rep StosDPOP ECX

And ECX, 3

Rep Stosb

MOV EAX, EDX

MOV EDX, ESP

@@ 0: MOV ECX, [EBX] .VmtintFTable

Test ECX, ECX

JE @@ 1

Push ECX

@@ 1: MOV EBX, [EBX] .vmtparent

Test EBX, EBX

JE @@ 2

MOV EBX, [EBX]

JMP @@ 0

@@ 2: CMP ESP, EDX

JE @@ 5

@@ 3: POP EBX

MOV ECX, [EBX] .tinterfaceTable.Entrycount

Add ebx, 4

@@ 4: MOV ESI, [EBX] .tinterfaceentry.vtable

Test ESI, ESI

JE @@ 4a

Mov Edi, [EBX] .tinterfaceentry.ioffset

MOV [EAX EDI], ESI

@@ 4a: Add Ebx, Type TinterfaceEntry

Dec ECX

JNE @@ 4

CMP ESP, EDX

JNE @@ 3

@@ 5: POP EDI

POP ESI

POP EBX

END;

{$ ENDIF}

Just known that _getmem has got a stack memory space, and this method we have to discuss now is to initialize some must. Other codes regardless of this:

Fillchar (Instance ^, InstanceSize, 0);

Pinteger (Instance) ^: = Integer (Self);

The first is to give the class object clear, now we know why the field of the OP class instance will automatically initialize zero [String is empty, the pointer is nil]!

The second statement is to let the VTPR pointer point to the VMT table 0: Reader Please refer to the structure of the structural map, which also proves the correctness of the speculation of the SELF value].

(Endlessly)

转载请注明原文地址:https://www.9cbs.com/read-5747.html

New Post(0)