wiki:squirrelfish

Version 3 (modified by oliver@apple.com, 16 years ago) (diff)

--

squirrelfish

List of tasks in no order -- pick one, tell everyone what you're doing:

Geoff is planning on:

Implement closures

Arguments object

Implement dynamic scope required by "with" (just like closures, but the activation doesn't need to be saved on return)

Function calls to native functions (requires revamping the List class to be an alias to the register file -- Geoff has some ideas for making this fast)

You could take something from Geoff, or make something up yourself, or do one of these:

Make everything work with a switch statement, based on macros -- for the sake of platforms without computed goto -- Oliver is working on this.

Statically detect presence of "with" and/or "catch" in the parser (required for correct scope chain behavior)

Implement more "emitCode" functions, along with support in the CodeGenerator and the Machine. IfNode would be a good place to start.

Make const work -- const info has to go in the symbol table, so writes to const vars can turn to no-ops at compile time.

Make global code work, including:

global code should only emit "overwrite var with undefined" if the var doesn't exist already.
Global code needs to deal with new vars being added. Stupid solution: always allocate a new vector, add new, then copy old. Better solution: provide pre-capacity to the existing vector. Alternative solution: just renumber the vars -- does any code depend on the old numbers? 

Zero-cost exception handling, using a table.

Function call should store offset of R, not R, since vector may reallocate. This probably solves most problems related to new evaluations in same global object, since they all occur beneath function calls

-- arguments object also holds a pointer into the register file -- probably needs to be indirect index, instead -- activation objects also hold pointers into the register file -- ditto -- lists, if we decide not to make them copy

Current function is in the register file -- gets marked automatically, marks the CodeBlock's constant pool

Must mark register file -- probably use zero fill plus type tagging to get it right

Pointers to registers and labels become invalid if the register or label vector resizes.

GC mark for constant pools

GC mark for possibly uninitialized register file

Add relevant files to AllInOneFile.cpp.

remove irrelevent files

What things should go in dedicated local variables? CodeBlock::jsValues? CodeBlock::identifiers?

VarStatementNode should just be nixed in favor of AssignmentNode.

Remove ::execute, ::evaluate, ::optimizeVariableAccess

Future optimizations:

Tile matching algorithm for emitting faster patterns of code

The introduction of op_new_func, op_call, and op_ret regressed the simple for loop tests by about 25%. Seems to have to do with the fact that these opcodes call arbitrary external functions.

Use RefPtr to indicate use of register -- moves to un-refed registers should be stripped or consolidated to other instructions.

  • i++ => ++i
  • less, jtrue => jless

emit actual instructions for var and function initialization -- often, there will be 0; often, the var initialization will be dead code. any read of variable before init can statically become "load undefined".

a single run of SunSpider performs 1,191,803 var initializations

-1 means "never happend"

var buckets: [846461] [40445] [350197] [9412] [7531] [50] [9] [178] [35000] [3] [1022] [3] [4499] [-1] [1353] [-1] [-1] [1851] [-1] [0] [-1] [0] [-1] [0] [-1] [0] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1]

fun buckets: [1297008] [7] [3] [2] [1] [0] [-1] [0] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [0] [-1] [1] [-1] [-1] [0] [-1] [0] [-1] [-1] [-1] [-1] [-1] [999] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] ]

for resolve-evaluate-put, we can have a { DontCare, Clean, Dirty } switch -- get slot and if DontCare, set clean, evaluate, set slot if clean

instead of branching to see if you've emitted code, just start out with a stub that does that emitting when invoked.

single, shared constant pool

At least for loops with fewer iterations it would probably be a win to duplicate the loop condition at the start and end of the loop

Perhaps we should have a distinguished "condition code" register for expressions in a boolean context. For relational and logical operators we can output directly to the condition code register, for other opcodes you get an extra instruction. Jump instructions can read implicitly from the condition code. That avoids the less writing to r0, it just puts a bool in the condition code register.

Can't you just make all opcodes have variants that use constant table operands directly?

A named function expression can just enter its name into the symbol table instead of adding an object to the scope chain.

Shrink instructions -- usually, don't need a whole word to store int values. Perhaps use tagging of opcodes to encode the first operand. Special work-around instructions when whole words are needed