I thought about the required work for bootstrapping Photon with OMeta
and decided to find the operations needed in the compiler. I did a
static analysis to find them and their frequency in the source code.
For those interested, the OMeta code is given at the end.
I apply the analysis to the following files needed for the bootstrap (I
still need to make sure I do not need the other stdlib files). To give
an idea of the size of each file, I list the number of lines beside it:
135 utility/debug.js
938 utility/num.js
505 utility/misc.js
141 utility/iterators.js
270 utility/arrays.js
624 stdlib/array.js
1146 stdlib/string.js
160 stdlib/function.js
194 stdlib/object.js
1302 backend/asm.js
3352 backend/x86/asm.js
180 ometa-js/lib.js
513 ometa-js/ometa-base.js
46 ometa-js/parser.js
136 ometa-js/photon-compiler.js
405 photon-lib.js
58 photon-test.js
10105 total
I get the following frequencies. I put an 'X' beside supported
operations, '/' beside partially supported operations and ' ' beside
not supported operations:
get: 9728 / -> need to add support for scope chain lookup
string: 9194 X
getp: 7179
call: 3693 X
this: 3072 X
var: 2545 X
binop: 1863
'===': 409 X
'+': 379 X
'<': 204 X
'-': 169 X
'&&': 126 / -> need to fix semantic to only evaluate
second operand
when the first is true
'>=': 94
'||': 93 / -> ... when the first is false
'!==': 69 X
'>': 52
'!=': 43 -> I am surprised to see those, I'll need to
further
investigate where they come from
'&': 41
'<<': 32
'>>': 29
'<=': 26
'==': 21 -> idem
'*': 20 / -> need to add type test
'/': 18
'instanceof': 14
'%': 10
'^': 9
'|': 5
set: 1669 / -> need to add support for assignment in a
parent
closure/global object or a regular object
number: 1548 X
return: 1529 X
func: 1419 / -> need to add support for closures
begin: 1236 X
if: 501 X
arr: 261
case: 219
binding: 211 X
unop: 173
'-': 64 / -> need to add type test and overflow check
'!': 60
'typeof': 46
'delete': 3
postop: 148
'++': 119
'--': 29
for: 119
condExpr: 112 X
throw: 98 -> need to add support for exceptions
preop: 89
'++': 77
'--': 12
switch: 79
break: 73
default: 72
new: 53
json: 52
mset: 48
'+': 39
'-': 5
'>>': 2
'*': 2
while: 44 X
forIn: 12
try: 12 -> need to add support for exceptions
doWhile: 9
continue: 7
No support for a GC will be done at this time and the bootstrap will be
done in memory.
I plan to do the following in order:
1. Add support for binop, unop, preop, postop, mset(partial), arr, for,
switch/case/default, json, doWhile, continue, break
(except operations requiring Constructors)
-> Should be enough to compile C-like code
2. Rewrite the semantic of the object model in extended JS (< 600l of C
code)
3. Add support for extension of objects and arrays
4. Add support for the global object
5. Add support for closures and scope chain
6. Add support for exceptions
7. Add support for constructors
8. Add inline cache invalidation mecanism
9. Add reuse of maps
10.Add support for variadic functions and arguments object
11.Port stdlib tachyon-specific operations to photon
12.Try bootstrap, fix bugs, add missing support, rinse, repeat
(13.) Optimize get/set property and variable on the scope chain
(14.) Optimize string internalization with a dictionary
(15.) Optimize lookup of properties on a map with a dictionary
(16.) Optimize construction of objects
Help would be appreciated, especially on steps 4-11. Those can mostly be
done in parallel once 1-3 have been done. I'll be glad to explain the
current system to interested people.
Erick
PS: Here is ASTFrequency Ometa analysis:
ometa ASTFrequency <: PhotonASTTraversal {
trans = [:t apply(t):ans] -> {self.nodes[t] = (self.nodes[t]
=== undefined) ? 1 : self.nodes[t] + 1; self;},
binop :op trans:x trans:y -> {if (self.ops.binop[op] ===
undefined) self.ops.binop[op] = 0; self.ops.binop[op] += 1;},
preop :op trans:x -> {if (self.ops.preop[op] ===
undefined) self.ops.preop[op] = 0; self.ops.preop[op] += 1;},
unop :op trans:x -> {if (self.ops.unop[op] ===
undefined) self.ops.unop[op] = 0; self.ops.unop[op] += 1;},
mset trans:lhs :op trans:rhs -> {if (self.ops.mset[op] ===
undefined) self.ops.mset[op] = 0; self.ops.mset[op] += 1;},
postop :op trans:x -> {if (self.ops.postop[op] ===
undefined) self.ops.postop[op] = 0; self.ops.postop[op] += 1;}
};
ASTFrequency.initialize = function ()
{
this.nodes = {};
this.ops = {
binop:{},
preop:{},
mset:{},
unop:{},
postop:{}
};
this.freqs = function ()
{
function sorta(a, b)
{
return b[1] - a[1];
}
var total = 0;
for (var n in this.nodes)
{
total += this.nodes[n];
}
var numbers = [];
for (var n in this.nodes)
{
numbers.push([n, this.nodes[n]]);
}
numbers.sort(sorta);
for (var i = 0; i < numbers.length; ++i)
{
print(numbers[i][0] + ": " + numbers[i][1]);
var n = numbers[i][0];
if (this.ops[n] !== undefined)
{
var op_numbers = [];
for (var op in this.ops[n])
{
op_numbers.push([op, this.ops[n][op]]);
}
op_numbers.sort(sorta);
for (var j = 0; j < op_numbers.length; ++j)
{
print(" '" + op_numbers[j][0] + "': " +
op_numbers[j][1]);
}
}
}
};
};
PPS: Here is the base grammar to traverse the AST:
ometa PhotonASTTraversal {
trans = [:t apply(t):ans],
curlyTrans = [#begin curlyTrans:r]
| [#begin trans*:rs]
| trans:r,
this end,
break end,
continue end,
number :n,
string :s,
arr trans*:xs,
unop :op trans:x,
getp trans:fd trans:x,
get :x,
set trans:lhs trans:rhs,
mset trans:lhs :op trans:rhs,
binop :op trans:x trans:y,
preop :op trans:x,
postop :op trans:x,
return trans:x,
with trans:x curlyTrans:s,
if trans:cond curlyTrans:t curlyTrans:e,
condExpr trans:cond trans:t trans:e,
while trans:cond curlyTrans:body,
doWhile curlyTrans:body trans:cond,
for trans:init trans:cond trans:upd
curlyTrans:body,
forIn trans:x trans:arr curlyTrans:body,
begin trans:x end,
begin trans*:xs,
func :args :scope curlyTrans:body,
call trans:fn trans*:args,
send :msg trans:recv trans*:args,
new :cls trans*:args,
var :name trans:val,
throw trans:x,
try curlyTrans:x :name curlyTrans:c curlyTrans:f,
json trans*:props,
binding :name trans:val,
switch trans:x trans*:cases,
case trans:x trans:y,
default trans:y,
global_return trans:x,
ref :s,
gets trans:fd trans:x,
mreturn trans:x trans:y
}