\(10.6.\)Handling Objects: Construction

  • What we have here is two completely separate compilation units. We are facing the challenge of compiling the caller class and the callee class.

1.High level of object construction

  • When we do var Point p1, the compiler will end up generating code on some location in the stack which is going to be initialized to 0.
  • When we call the constructor, the compiled code will end up creating the object proper on the heap.
  • The two class running together will end up taking the base address of the newly created object and storing it in what we assign previously the p1 variable.

2.The callers's side

  • Whenever the compiler encounters a variable declaration, it generates no code whatsover. The only thing the compiler does is it update the relevant symbol table. Because we are now compiling code that resides in a certain subroutine, we will end up updating the symbol table of the subroutine.

  • Point.new(2, 3) is a call to some subroutine, so we handle it just like other subroutine. We push the two arguments and call Point.new

  • The calling code assumes that when the constructor will execute, it will end up allocating some space on the RAM for the newly constructed object. It will also take the base address of this space on the RAM and return it to the caller.

  • So we pop the topmost value of the stack into p1, because we want p1 to point at the base address of this object.

3.Resulting impact

  • Only when we call the constructors will we actually create the objects on RAM.
  • Object construction is a two-stage affair that happens both during compile time and run time.

4.The big picture of constructors

  A constructor is typically designed to do at least two things:

  1. Arrange some place on RAM for the new object.
  2. Assign certain values to the fields of the newly constructed object.

  To do this, the constructor must have access to the object's fields:

  • We can manipulate THIS segment to manipulate the object that the constructor juct created.
  • To access THIS segment, we first anchor it properly on the right address in the RAM using pointer segment.

5.Compiling constuctor

  1. The first thing we meet is the constructor signature. The compiler will generate no code whatsover. The only thing it will do is it will create the subroutine symbol table and record in it two variables ax and ay which are both arguments

  Then comes the question: how much space is needed?

  1. The compiler can consult the class level symbol table and realize that objects of the point class requires two words only, x and y.

  Then how do we find such a free memory block on RAM?

  1. The operating system supplies a function called alloc, if you provide alloc(x) with a certain argument, it will find a memory block on the RAM and return the base address of it. The memory block has two important properties:

    1. It's x words long.
    2. It's free, no one needs it now, so the constructor can safely use it.

  1. We push 2, because we need 2 words to store the arguments.
  2. We want to push THIS into the stack, we need 1 word, so we call Memory.alloc 1.
  3. As usual, we anchor THIS at the base address: pop pointer 0.

If we do pop pointer 0, we are going to align the virtual segment ot the object we currently constructed on the RAM. We do this because I know that with very high likelihood the next commands in the constructor will want to access the fields of the newly created object.

  1. Since THIS is anchored on the right endness, to return, we simply do push pointer 0. And when the caller of constructor do pop pointer 0, it can successfully get the address of the newly created object.