Le 10-05-05 16:30 , chevalma@iro.umontreal.ca a écrit :
Pretty cool. Does it require the C++ functions to take V8 implementation specific objects as arguments (eg: some JSObject class), or do we declare the types that the C++ functions take?
They use an Arguments wrapper object. I'll dig further into this.
Just wondering if we will be able to use the same C++ code directly in V8 and in our own implementation.
- Maxime
Erick
I just found that the option to call native functions can simply be passed as an argument to the d8 executable.
Ex:
./d8 --allow_natives_syntax d8> var f = %CompileString("var x = 2;",false); d8> f function var x = 2; d8> f() d8>x 2
For other options, simply type:
./d8 --help
As a side note, to read a file as a string from the d8 prompt, simply do:
var s = read("my_test_file.js");
Erick
Le 10-05-05 14:49 , Erick Lavoie a écrit :
V8 provides a nice developer shell to interactively execute and debug javascript code using their Engine.
The build instructions as well as the dependencies can be found here http://code.google.com/apis/v8/build.html.
To allow calling native C++ functions from javascript directly such as what is done in the standard libraries (see src/v8natives.js), simply set the "allow_natives_syntax" flag from src/flag-definitions.h to "true". This will allow calling functions like %CompileString directly.
To see how C++ functions can be exposed to javascript, look at void Shell::Initialize() from src/d8.cc.
When an error occurs, the d8 shell automatically enters debug mode. The listing of available commands can be found at "function DebugRequest" of src/d8.js.
Erick
Tachyon-list mailing list Tachyon-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/tachyon-list
Afficher les réponses par date
I shared a file containing preliminary JavaScript programming guidelines in the Tachyon Google Docs folder. You should all have access to it.
The conventions are mostly what Erick, Marc and I discussed. I added some extra points, which I'd like your opinion on, if you disagree.
You are also free to add other points there or introduce more examples. We all have edit access to the file.
- Maxime
Seems OK. Except this passage:
Certain programming conventions should be respected in the hopes of facilitating the optimization of the Tachyon source code. In particular, we emphasize an OOP style which easily translates to that of languages such as Java and C++.
Using an OOP style does not facilitate optimization. Imagine a constructor like:
function Foo() { this.field = ...; this.meth = function () { ... this.field = ... } }
It will be hard for a compiler to determine that the call x.meth() is actually calling the method "meth" in Foo (not only does the compiler have to determine that x is always an instance of the constructor Foo, but you have to ensure that there have been no mutations of the field "meth" in the instance bound to x). So it is hard to inline that method in place of the call x.meth(). Moreover, space has to be reserved in all instances of Foo for all the methods in the non-optimized case, and it is not clear how these fields can be eliminated.
On the other hand, if the program was written using a procedural OOP style, such as:
function Foo() { this.field = ...; }
function meth(self) { ... self.field = ... }
then it is much easier to inline the method "meth" in place of the call meth(x) and there is no extra space required in the instances.
Note that the inlining must still be guarded (by an absence of mutation to the global variable "meth") but other than that it requires a trivial data flow analysis (looking for all the mutations of the global variable "meth").
So please explain why you propose using a C++/Java style OOP style. Why not use the procedural variant?
Marc
On 2010-05-06, at 6:18 PM, chevalma@iro.umontreal.ca wrote:
I shared a file containing preliminary JavaScript programming guidelines in the Tachyon Google Docs folder. You should all have access to it.
The conventions are mostly what Erick, Marc and I discussed. I added some extra points, which I'd like your opinion on, if you disagree.
You are also free to add other points there or introduce more examples. We all have edit access to the file.
- Maxime
Tachyon-list mailing list Tachyon-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/tachyon-list
please explain why you propose using a C++/Java style OOP style. Why
not use the procedural variant?
For one, I believe the OOP style is the one we agreed on when we discussed this earlier today in your office. The OOP style is the one you've already been using in the parser code you've showed us.
Another reason is that the OOP style is clearer, and allows us to use things like the prototype chain for inheritance, as well as other JavaScript facilities. The whole point of programming this VM in JavaScript is to simplify the implementation and make us more productive.
There is also the issue of name collision. Your method won't be called meth(). It will need to be called FooMeth. Or, in a more realistic example BasicBlockGetParents(), or something of the sort. Longer, uglier method names everywhere. We also still would need to use local functions in the case where virtual method calls are actually what we want, thereby forcing us to use x.meth1() in some cases, and FooMeth2(x) in other cases.
Let's not adopt coding standards that complicate our lives and essentially turn JavaScript into C, and make our lives harder, because then, we might as well use a *proven* approach, such as implementing this all in C++. That would perform well. I can guarantee it. It has type annotations, and the compilers already do inlining for you. We wouldn't even need to worry about all this bootstrapping business...
It will be hard for a compiler to determine that the call x.meth()
is actually calling the method "meth" in Foo (not only does the compiler have to determine that x is always an instance of the constructor Foo, but you have to ensure that there have been no mutations of the field "meth" in the instance bound to x). So it is hard to inline that method in place of the call x.meth().
Being able to know this kind of thing is the whole point of my Ph.D. thesis, as far as I'm concerned. A pretty simple flow-insensitive analysis could deduce those facts, and I intend to do better than that. You also have to realize. Knowing the type of x in a call to x.foo() is essential to gaining high performance levels. Inlining foo(x) won't gain you that much if your foo() function is naively compiled and full of dynamic dispatch. Furthermore, I believe it's possible for us to set some fields as read-only, thereby avoiding the problem of the field being modified.
Moreover, space has to be reserved in all instances of Foo for all
the methods in the non-optimized case, and it is not clear how these fields can be eliminated.
Not if the fields are read only. Not if the methods belong to a class we inherit from in the prototype hierarchy. Furthermore, is space really that much of an issue at this point?
- Maxime
On 2010-05-07, at 12:52 AM, Maxime Chevalier-Boisvert wrote:
please explain why you propose using a C++/Java style OOP style. Why
not use the procedural variant?
For one, I believe the OOP style is the one we agreed on when we discussed this earlier today in your office. The OOP style is the one you've already been using in the parser code you've showed us.
The code I showed you was my first attempt to explore how to express an OOP style in Javascript. There is more than one way, in fact you mentioned yesterday having a preference for defining the methods outside the constructor. In my message I mention the x.meth() and meth(x) variants, which are both OOP styles based on slightly different syntax. It is important to make our design decisions in a reasoned way, which is why I am questioning the choice of using the x.meth() variant. We should analyze our options before we commit to a particular variant. If we do adopt the x.meth() variant we should understand why and accept the consequences. I raise the issue that the x.meth() variant will very likely be less efficient than the meth(x) variant, at least until our compiler is "sufficiently intelligent". I did a simple speed test with V8 and the meth(x) variant is 10% faster than the x.meth() variant. I think the difference could be larger if the compiler did some simple inlining optimization. This can easily be done by having a compiler switch (or annotation) to tell the compiler it can assume toplevel functions will not be redefined (which I hope will be the case for the source code of the Tachyon compiler), and doing a "whole program" compilation (by basically concatenating all the source code of the compiler's modules).
By the way, the argument that "a sufficiently intelligent compiler should optimize this away" is a dangerous one that has caused much grief in the past in the field of programming languages and compilers. It is better to plan for the worst (i.e. what we know is doable) and hope for the best (i.e. what we are trying to demonstrate).
Another reason is that the OOP style is clearer, and allows us to use things like the prototype chain for inheritance, as well as other JavaScript facilities. The whole point of programming this VM in JavaScript is to simplify the implementation and make us more productive.
I'm not against an OOP style, but as I say there is more than one way to express OOP in JS.
There is also the issue of name collision. Your method won't be called meth(). It will need to be called FooMeth. Or, in a more realistic example BasicBlockGetParents(), or something of the sort. Longer, uglier method names everywhere.
I'm not sure this is as big an issue as you say because the Tachyon compiler will in any case have to have a mechanism to separate the namespace of the compiler's code and the code of the application. In other words, there has to be more than one toplevel environment otherwise the compiler and the application will interfere. The namespace could be implemented by having the compiler automatically append a prefix to all the global names it sees, with a prefix that is a command-line option of the compiler. So all the compiler's code would be in the compiler's namespace. Note that the prefix could be something like "%tachyon_" (which is illegal in pure JS), so that no interference with the application is possible.
We also still would need to use local functions in the case where virtual method calls are actually what we want, thereby forcing us to use x.meth1() in some cases, and FooMeth2(x) in other cases.
This is not necessarily bad, because it highlights the use of virtual methods. Moreover, this can still be hidden in a toplevel function if that's desired, i.e.
function FooMeth1(self) { return self.meth1(); }
Let's not adopt coding standards that complicate our lives and essentially turn JavaScript into C, and make our lives harder, because then, we might as well use a *proven* approach, such as implementing this all in C++. That would perform well. I can guarantee it. It has type annotations, and the compilers already do inlining for you. We wouldn't even need to worry about all this bootstrapping business...
This "bootstrapping business" is part of our research objectives and is (probably) an important part of Erick's MS thesis!
I can guarantee that using C/C++ will cause problems (as we have discussed previously).
It will be hard for a compiler to determine that the call x.meth()
is actually calling the method "meth" in Foo (not only does the compiler have to determine that x is always an instance of the constructor Foo, but you have to ensure that there have been no mutations of the field "meth" in the instance bound to x). So it is hard to inline that method in place of the call x.meth().
Being able to know this kind of thing is the whole point of my Ph.D. thesis, as far as I'm concerned. A pretty simple flow-insensitive analysis could deduce those facts, and I intend to do better than that. You also have to realize. Knowing the type of x in a call to x.foo() is essential to gaining high performance levels. Inlining foo(x) won't gain you that much if your foo() function is naively compiled and full of dynamic dispatch. Furthermore, I believe it's possible for us to set some fields as read-only, thereby avoiding the problem of the field being modified.
I understand you are trying to demonstrate this in your Ph.D. I think it is much harder than you think ("simple flow-insensitive analysis"). Perhaps you should look into this soon to explore how it can be done for JS. This will shed some light on the issues specific to JS. Unfortunately, you can only prove this for sure by building a compiler and implementing your ideas. I guess we have a chicken and egg problem!
By the way, how can fields be marked as "read-only" in Javascript?
Moreover, space has to be reserved in all instances of Foo for all
the methods in the non-optimized case, and it is not clear how these fields can be eliminated.
Not if the fields are read only. Not if the methods belong to a class we inherit from in the prototype hierarchy. Furthermore, is space really that much of an issue at this point?
Imagine a 2D point "class" with 2 fields (x and y) and 20 methods (add points, compare points, print points, magnitude, etc). That would entail a 1000% space overhead! That is significant. A similar situation could happen for Tachyon, think of an AST node class where AST nodes have few fields but a large number of methods. In a fancy compiler, it is not unusual to see very high memory usage in the analysis and optimization phases (for doing various flow analyses). GCC for example can use gigabytes of memory for compiling some programs. If we use 10 times more memory than we need to this will hinder the kinds of analyses the compiler can perform and prevent us from achieving our objectives.
Marc
By the way, the argument that "a sufficiently intelligent compiler
should optimize this away" is a dangerous one that has caused much grief in the past in the field of programming languages and compilers. It is better to plan for the worst (i.e. what we know is doable) and hope for the best (i.e. what we are trying to demonstrate).
Except that we are designing the compiler here, and I still think my point stands. A simple flow-insensitive whole-program analysis could deduce those facts. That being said, I agree that we could use special compilation modes for the compiler code. We will have to, in fact, to allow access to low-level primitives the rest of the JS code shouldn't have access to.
I'm not against an OOP style, but as I say there is more than one
way to express OOP in JS.
The canonical way is definitely the x.meth() style, however.
The namespace could be implemented by having the compiler
automatically append a prefix to all the global names it sees, with a prefix that is a command-line option of the compiler. So all the compiler's code would be in the compiler's namespace. Note that the prefix could be something like "%tachyon_" (which is illegal in pure JS), so that no interference with the application is possible.
This is starting to sound like C++ name mangling. We could perhaps implement it as separate "global objects" (top level JS environments), with the global objects being essentially unnamed (and therefore, making Tachyon invisible to the normal JS code), and the special tachyon primitives appearing only in its own environment. The tachyon global object could have a pointer to the JS global object in its own top level environment, as well as primitives to inspect and modify it, as well as its own top level environment.
This is not necessarily bad, because it highlights the use of
virtual methods. Moreover, this can still be hidden in a toplevel function if that's desired
I'd rather not hide it. In fact, I think I'm OK with the idea of non-method operators so long as you're OK with using virtual method calls where appropriate. I simply don't want our coding practices to get in the way of the simplicity JavaScript has to offer.
This "bootstrapping business" is part of our research objectives and
is (probably) an important part of Erick's MS thesis! I can guarantee that using C/C++ will cause problems (as we have discussed previously).
I know it's important and I've taken a liking to the idea. I'm simply saying that I don't think we should take the more complicated approach at every turn, because then, we are really making our life much harder.
I understand you are trying to demonstrate this in your Ph.D. I
think it is much harder than you think ("simple flow-insensitive analysis"). Perhaps you should look into this soon to explore how it can be done for JS. This will shed some light on the issues specific to JS. Unfortunately, you can only prove this for sure by building a compiler and implementing your ideas. I guess we have a chicken and egg problem!
I'd like to start working on simple analyses soon after we have implemented an intermediate representation. We have a parser in progress, we need to design an AST, and after that, I'd like to work with you and Erick on designing a high-level intermediate representation we can transform the code into. Something that will be easy for analyses to work with, and that we can progressively translate into a lower level IR, and ultimately machine code, hopefully all within the same framework.
By the way, how can fields be marked as "read-only" in Javascript?
In the JS standard:
15.2.3.6 Object.defineProperty ( O, P, Attributes )
Attributes would be something like { Writable : false }
I don't think the syntax is very convenient, but it's possible.
Imagine a 2D point "class" with 2 fields (x and y) and 20 methods
(add points, compare points, print points, magnitude, etc). That would entail a 1000% space overhead! That is significant. A similar situation could happen for Tachyon, think of an AST node class where AST nodes have few fields but a large number of methods. In a fancy compiler, it is not unusual to see very high memory usage in the analysis and optimization phases (for doing various flow analyses). GCC for example can use gigabytes of memory for compiling some programs. If we use 10 times more memory than we need to this will hinder the kinds of analyses the compiler can perform and prevent us from achieving our objectives.
The AST classes are precisely the classes that will need virtual methods, however. Fortunately, there will only be a need to store methods that are redefined for the leaf nodes of the AST tree. The others will already be defined up the prototype chain... And hopefully we can work on optimized object representations at some point, and make it so that constant fields for a given class can be stored in the class rather than the object itself.
This is a case where I really think we should go with the natural OOP style, at least at first... Because AST and IR nodes will be used all over the place, and we do want the code to be simple and concise.
- Maxime
I have an appointment I can't move on Wednesday morning, and will only be available from 1:30-2:00 PM. Would you guys be available at that time, or should we meet on Thursday?
- Maxime
On 2010-05-10, at 11:52 , Maxime Chevalier-Boisvert wrote:
I have an appointment I can't move on Wednesday morning, and will only be available from 1:30-2:00 PM. Would you guys be available at that time, or should we meet on Thursday?
I already have a meeting at that time, but I could try to postpone it if needed. I'll be out of the country on thursday (until next monday).
Bruno
I'm available at that time. So lets plan to meet at 2PM at my office if Bruno can move his meeting.
Marc
On 2010-05-10, at 11:57 AM, Bruno Dufour wrote:
On 2010-05-10, at 11:52 , Maxime Chevalier-Boisvert wrote:
I have an appointment I can't move on Wednesday morning, and will only be available from 1:30-2:00 PM. Would you guys be available at that time, or should we meet on Thursday?
I already have a meeting at that time, but I could try to postpone it if needed. I'll be out of the country on thursday (until next monday).
Bruno _______________________________________________ Tachyon-list mailing list Tachyon-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/tachyon-list
On 2010-05-10, at 12:01 , Marc Feeley wrote:
I'm available at that time. So lets plan to meet at 2PM at my office if Bruno can move his meeting.
I'll try to move my meeting, but didn't Maxime say she wouldn't be available after 2pm?
Bruno
Marc
On 2010-05-10, at 11:57 AM, Bruno Dufour wrote:
On 2010-05-10, at 11:52 , Maxime Chevalier-Boisvert wrote:
I have an appointment I can't move on Wednesday morning, and will only be available from 1:30-2:00 PM. Would you guys be available at that time, or should we meet on Thursday?
I already have a meeting at that time, but I could try to postpone it if needed. I'll be out of the country on thursday (until next monday).
Bruno _______________________________________________ Tachyon-list mailing list Tachyon-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/tachyon-list
I will be available after 2 PM, possibly earlier.
- Maxime
Bruno Dufour wrote:
On 2010-05-10, at 12:01 , Marc Feeley wrote:
I'm available at that time. So lets plan to meet at 2PM at my office if Bruno can move his meeting.
I'll try to move my meeting, but didn't Maxime say she wouldn't be available after 2pm?
Bruno
Marc
On 2010-05-10, at 11:57 AM, Bruno Dufour wrote:
On 2010-05-10, at 11:52 , Maxime Chevalier-Boisvert wrote:
I have an appointment I can't move on Wednesday morning, and will only be available from 1:30-2:00 PM. Would you guys be available at that time, or should we meet on Thursday?
I already have a meeting at that time, but I could try to postpone it if needed. I'll be out of the country on thursday (until next monday).
Bruno _______________________________________________ Tachyon-list mailing list Tachyon-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/tachyon-list
Tachyon-list mailing list Tachyon-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/tachyon-list
1:30-2:00 PM is fine for me.
Erick
Le 10-05-10 11:52 , Maxime Chevalier-Boisvert a écrit :
I have an appointment I can't move on Wednesday morning, and will only be available from 1:30-2:00 PM. Would you guys be available at that time, or should we meet on Thursday?
- Maxime
Tachyon-list mailing list Tachyon-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/tachyon-list
I found an interesting article on the topic of inline object allocation, in the context of dynamic languages: http://reference.kfupm.edu.sa/content/a/u/automatic_inline_allocation_of_obj...
They use interprocedural dataflow analysis and global program transformation to inline object fields. I find the explanation of their analysis somewhat unclear, but they seem to get good results. We probably don't want to experiment with object inlining anytime soon, but it's good to know it seems to work fairly well in practice.
In the medium term, I think we could work on optimized object representation that can inline booleans, doubles, and integers (numbers found to be int32/uint32), and benefits from type information to remove dynamic checks.
I started writing some type analysis notes on Google docs, which I've been expanding on as I'm reading papers and the JS spec. I believe I've found a way to factor in which fields are defined/undefined inside objects into a type analysis, using a simple 32-bit bit-map to propagate the information around. This way, checks to test which fields are undefined in an object can be individually tailored to each field access point, instead of having to check everywhere.
- Maxime