In this unit we are going to talk about a set of conventions that developers of Jack compilers are advised to follow. And taken together we call these set of conventions the Standard Mapping Over the Virtual Machine. Let's start with the big picture. To remind you we're developing a compiler and this compiler is two tiered. So it has two stages. First we compile from the Jack level to the VM code. Then we compile from the VM code all the way down to the target platform. The second part has been taken care of in modules one and two, and in this module and in the previous one we take care of closing the gap between Jack and the Virtual Machine. So for all practical purposes we can ignore everything that happens below the VM code and focus on the translation of Jack programs into the VM code. Now think about it, when you write a Jack program or a Java program or a C++ program, it doesn't matter. In any one of these programs, you create all sorts of, let's call them entities, things like classes, functions, constructors, methods and so on. And yet, when you have to translate these things into the VM level, you end up with something that looks completely differently, right? At the VM level, we don't know what is an object. We don't know what is a constructor. Now, all we have is stack and virtual segments. And we somehow have to map every one of these high level constructs, every one of these obstructions, on the reality of the virtual machine. And how to do it is something that we discussed throughout this module, but now I want to sort of recap and then put together all the rules that we have to follow when we create those mappings. From the high level to the VM level. And we do it using this document or set of standards that we call the standard mapping over the VM platform. By the way, if you want to create compilers for other languages like Java, C++ and so on, then for every one of these languages, for every one of these compilers, we're going to have a different document describing the standard mapping because every one of these languages have different constructs although many of them are quite similar. But in this course of course we focused on the Jack language. So that's what we're going to discuss here, how to map Jack on a virtual machine. All right, so let us start with files and subroutine mapping conventions. Well, a Jack program is a collection of one or more classes. Each class has a unique name and every one of these classes or every one of these class files is going to be translated onto a respective VM file that has the same prefix filename. And in the process, every subroutine in the source code is going to be translated on a function at the VM level. So each subroutine goes through a function, each file goes to a VM file. And notice that a Jack constructor or function that has k arguments is going to be compiled into a VM function that operates on k arguments, as well. And in this example, we see that .new, which is a constructor, it has one argument at the Jack level. It will also have one argument at the VM level. Likewise, the same is going to happen with the function .baz. What about methods? Well, with methods it's a little bit more tricky. A Jack method that has k arguments is going to be complied onto a VM function that operates on k+1 arguments. So in this example, the .bar method had only one argument, x at the jack level. And yet at the VM level, it is going to have two arguments. And we'll elaborate on this further and actually we also talked about it when we talked about object manipulation early on this module. So you see that, if you look at the diagram, something interesting is shown here. The kind of the subroutines, if you will, whether they are constructors, methods or functions, well all these is being lost in translation, right? Because when it reaches the VM level everything is going to be mapped onto functions. So we have somehow capture the constructor semantics, the function and the method semantics at the VM level. And we do it by certain conventions like the one that I just discussed now that methods take one additional argument compared to their source code manifestations. We'll have more to say about this later on. Okay, what about mapping variables? Well, in Jack we have four kinds of variables. We have locals, arguments, statics, and field variables. And each one of them is handled in a certain way. So the local variables of some Jack subroutine are mapped on the virtual segment label. I'm sorry, local. And so, if you have a local variables like x and y, let us assume that these are the first two local variables that are declared in your subroutine. Then x is going to be mapped on local 0 and y is going to be mapped on local 1. If you have more variables down the road they will be mapped on local 2, 3, and so on and so forth. What about the argument variables? Exactly the same setting. The first argument goes to argument 0. The second goes to argument 1 and so one and so forth. Static variables are mapped on the virtual segment static that is associated with the currently compiled file. And the mapping is very similar. The first static goes to static 0, the second static goes to static 1, and so on and so forth. What about the field variables? Well, the field variables of the current object are handled as follows. First of all, we have to assume that pointer 0 has been set to the this object. Someone has to do it for us. And the agent that does it is the generated code of the current subroutine. So let us assume it has been done already. Well, if this has been done then the i-th field of this object is mapped on this i at the VM level. So if x happens to be a property or a field it will go to this 0 and if y happens to also be a property it goes to this 1 and so on and so forth. So that's how we handle variables. What about arrays? Well, with arrays we propose the following convention. If you try to access any array entry, arr[i], then, here is what you should do. First you should set pointer 1 to the entry's address, which happens to be arr+i, and then once you did this initial anchoring so to speak, then you simply access the entry by accessing this 0. So, it doesn't matter what i is, whether it's 18 or 312, you always set pointer 1 to it and then you access this 0. We found out that that's the easiest way to handle arrays in our compiler. So which conventions do we have to follow when we compile subroutines? Well, in Jack, we have three kinds of subroutines. We have methods, constructors, and functions. So let's talk about each one of them separately. Let's start with methods. When we compile a Jack method, the compiler must make sure that the compiled code will begin by setting the base of the this virtual segment to argument 0. Why? Because we have a very important convention in place. And the convention says that the caller of the method is going to push the address of the object on which the method is supposed to operate as the very first argument before calling this method for its effect. So, when the method starts running, it has to work on the current object, and we achieve this obstruction by doing this. We set this to the contents of argument, 0. And this will establish access to the object on which we have to operate. Once we do this, we can refer to this 0, this 1, this 2 as we discussed previously as placeholders for the fields of the current object. So that's very convenient and it makes perfect sense. What about constructors? Well, when we compile constructors, we first of all have to create a space in memory for the object that we seek to create and once we do this, we set the base of this new block to the this segment. And by doing this, once again we establish access to this object and then once again we can use this 0, this 1, this 2 and so on for all sorts of things that the constructor may want to do. For example, constructors are fond of setting the object fields to all sorts of initial values. Well now they can do it because we have established access to the newly constructed object. And before returning, let us remember that the compiled VM code or the constructor must also remember to return the base address of the newly constructed object to the caller. Now when I think about it, I'm not sure that we even have to specify this in the standard mapping because if you recall, we actually elevated this requirement to the Jack level. In Jack when we write a constructor you must remember to always return this. And so because we require this at the Jack level, the compiler will automatically generate code for handling return this, and we don't have to mention it here as well. But there's no harm in mentioning this important convention here also. So what about compiling void functions or void methods? Well, void functions and methods don't return values, at least at the Jack level they don't return values. And yet at the VM level, they have to return something, because that's the requirement. We require that every VM function returns a value. And because we have to return something, we've decided that if you follow our standard mapping, we request that you return constant 0. By the way the caller of a void subroutine has to remember that it called a void subroutine, and therefore when the subroutine returns, the first thing that it has to do is get rid of the top of the stack, right? The element of the top of the stack, because it contains a constant 0. And that's what we'll discuss next, right? How to handle subroutine calls. What conventions do we have to follow here? Well, when we compile a typical call, like subroutine name with a set of arguments, the caller must push the arguments onto the stack and then call the subroutine for its effect. So it does push arg1, push arg2 and so on and then call subname. Now if the subroutine is a method then the caller must remember that the first thing he has to do is to push a reference to the object on which the method is supposed to operate. And only then it proceeds to push arg1, arg2, and so on and call the method for its effect. And you see how everything connects here because once you do this, the address of the current object becomes the value of argument 0 that we discussed before from the standpoint of the called method. What about calling a void a subroutine? Well, a void subroutine does not return a value in Jack but at the VM level, it returns some dummy value. We decided on constant 0 and therefore after the subroutine returns, the compiled code of the subroutine call must pop and ignore the return value. So that's how we handle the conventions of compiling subroutine calls. Finally we have to handle some constants, right? And let's see, we have three constants in Jack. We have null, false, true, and you see how each one of them is being handled. For the case of -1, we can simply generate code that pushes 1 followed by the neg command and this will put effectively a -1 at the top of the stack. Alright, actually we also have to discuss classes and subroutines, so let's do it. The basic Jack operating system is implemented as a set of eight VM classes with names like: math.vm, memory.vm and so on and so forth. We will discuss these classes at length and implement the in the next and final module in the course, module six. And all the OS classes, class files must reside in the same directory as the VM files generated by the compiler. So as you can see, this directory level there's no difference between your application files and the OS files, they're all treated as a big collection of VM files. And therefore, any VM function in your code can call any OS VM function in any one of these classes for its effect. And that's how we handle the operating system. What about some special OS services? Well, there are such services obviously. If you'll write a Jack compiler, you have to remember a few things. First of all, whenever you have a multiplication command, it has to be handled by calling Math.multiply. Whenever you have a division command or operator at the Jack code, it has to generate code that calls Math.divide. String constants are created using the constructor String.new, and the length of the required string. String assignments like x=, Whatever, NAND, N-A-N-D. Well, this string, N-A-N-D, which consists of four characters, is handled by making four calls to String.appendChar. So once again the compiler has to deliver this obstruction. Object construction requires allocating space for the new object in the RAM. And therefore somewhere in the constructor, we have to call Memory.alloc. Size is going to be derived from the number of fields in this object that we seek to create and because in Jack everything is 16-bit. Then, we have one to one mapping between the number of fields and the number of RAM words or RAM locations that we need to accommodate this object. And finally, object error recycling is handled using the OS function memory.deAlloc. And that's it. These are the things that developers of Jack compilers over our virtual machine have to keep in the back of their minds when they write the Jack compiler. In the next unit, we'll talk about how to actually structure this compiler, which API we recommend to follow. So I will meet you there.