Some more bytecode questions :)

Started by
15 comments, last by wodinoneeye 16 years, 11 months ago
!!!

So you can simply just... store a float as an int in one line? That's amazing! Heheh.
Advertisement
I have come up with a new question. This one has been annoying me while I've been working on this VM. It's about classes, how they work, and how they compile. How are objects created, and how do you know that they link with the methods and variables inside the class?
Well, an object is basically a chunk of memory that has a certain size. The size can be determined by summing up the individual sizes of all instance variables (aka member variables). If you want inheritance, you will also need to take into acount the member variables you inherit from all the parent classes.
When creating a new object, you typically write something like this:

MyClass c = new MyClass();


this could compile to the following

NEW 145  ; Allocate memory for an object of type MyClass (145 would be an index into some sort of class table) and push a reference to it onto the stackDUP  ; Duplicate the referenceSTORE1 ; Store the reference in local variable 1CALL 123 ; Call constructor for MyClass, where 123 is some offset


That said, what's a class? It's basically a template for creating objects. However, while many modern programming languages like Java or C# retain type information at runtime, you can also do classes entirely at compile time. If you look at compiled C++ code, you won't see classes anywhere. That information is lost at compile time which is why C++ doesn't natively support introspection.

One thing to consider is: how is a method different from a regular function. The short and simple answer is that a method (or member function) is implicitly passed a reference to the current object (aka "this") when it's invoked.

A piece of code like this:

myObject.doSomething(1, 2, 3);


could compile to something like this

LOAD0  ; Push the local variable "0" onto the stack (slot 0 holds the this-reference)ILOAD1ILOAD2ILOAD3 ; Push 1, 2, 3 onto the stackCALL 243 ; Call function at offset 234


So the key difference here is the "LOAD0". In order for that to work, you need to make sure that when a method is invoked, you lay-out the stack frame in a way that the this-reference can be easily accessed (e.g. local variable 0).

So now you have the connection between a method and an object. What's interesting to note is that things like informating hiding happen entirely at compile-time. So if you want to support private methods, you will need to add the appropriate checks to your compiler (e.g. when your compiler sees a method call and the method is declared as private, raise an error).

If you want to do inheritance, be warned that this can be somewhat tough. Take a look at the following snippet

ISomeInterface a;if (someUserInput == 1) {    a = new SomeClass();} else {    a = new SomeOtherClass();}a.someMethod();


ISomeInterface is an interface (a class with virtual methods) and SomeClass/SomeOtherClass are two classes implementing that interface. As you can see, there's no way for the compiler to know at compile time, which method it will have to invoke. However, this code still works as expected. The concept behind this is called "dynamic dispatch" and it's probably one of the most important concepts of object oriented programming. However, it's not exactly easy to implement.
Hmmm yeah that all seems to make sense. I have one problem though, about memory. Take this for example. I make a variable inside a class, like char* name; . 'name' could change anytime, so how does it have a constant amount of memory?
if you have a class like this:

class Blah {private:  char* myStr;  int myInt;  double myDouble;}


the size of an instance of that class can be determined at compile time. This may seem surprising since the length of myStr is definitely unknown at compile time. However, an instance of Blah doesn't actually contain the string, it only contains a reference to the string. And the size of a reference is known at compile time (it's typically 4 bytes).

Quote:Original post by Zotoaster
!!!

So you can simply just... store a float as an int throw away type safety in one line? That's amazing horrific!


;-)



You could give the programmer the choice to inline or not.

Depending on how your subroutines pass data and return results, it would pay CPU speedwise to inline a short routine to bypass all the call overhead.

Fore example - Typical get/set routines commonly used in object oriented stuff does very little processing.
--------------------------------------------[size="1"]Ratings are Opinion, not Fact

This topic is closed to new replies.

Advertisement