-
Notifications
You must be signed in to change notification settings - Fork 101
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Optimise field access by computing the minimal positional index (#2708)
Formerly we did a linear search from field № 0 until finding the right hash. But frequently the _positional index_ where we find the hash can be given a static lower bound: - when we have a supertype approximation of the actual memory object, we can sort the field hashes and anticipate (some of) the layout - then statically search for the accessed field's hash to obtain the lower bound for starting the linear search. The only drawback I see is that some (generated template) code is duplicated, by getting new functions for each lower bound. So basically this is a tradeoff. Maybe this optimisation should reside behind a performance flag. Code duplication also means that we potentially get more cache-cold code on the nodes, but I think that is not reflected in our cost model. Next move: generate stubs `<lower_bound, hash>` that call a common worker. -------- ## Background On the surface (Motoko) you index fields by name (which is by hash value in the machine model). Under the hood we have two _parallel arrays_: `[field_hashes_sorted]` and `[field_values]`. See the ASCII art below `module Object` (in `compile.ml`). Example: ``` | field | hash | +-------+------+ | foo | 789 | | bar | 613 | | baz | 915 | ``` So when you want to access field `(o : { foo : Int, bar : Int, baz : Int}).foo` with `o` in reality having more fields potentially than the (super)type indicates, you'll find that hash array will be `[613, .., 789, .., 915]` because of sorting. We statically know that the lowest _positional index_ for `foo` is 1, since hash `613` already occupies position 0.
- Loading branch information
Showing
2 changed files
with
62 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
class CO4() { | ||
public type b = Nat; | ||
public let a : b = 25; | ||
public let foo : b = 8; | ||
public let field : b = 42; | ||
public let other : b = 83 | ||
}; | ||
|
||
type O1 = { field : Int }; // "\ba\94\93\00" | ||
type O2 = { a: Int; field : Int }; // "a\00\00\00\ba\94\93\00" | ||
type O3 = { a: Int; field : Int; other : Int }; // "a\00\00\00\ba\94\93\00\d0fv6" | ||
type O4 = { a: Int; foo : Int; field : Int; other : Int }; // "a\00\00\00\06\c7M\00\ba\94\93\00\d0fv6" | ||
|
||
func go1(o : O1) : () = inner o; | ||
func go2(o : O2) : () = inner o; | ||
func go3(o : O3) : () = inner o; | ||
func go4(o : O4) : () { assert o.a == 25; assert o.field == 42; assert o.other == 83; assert o.foo == 8; inner o }; | ||
|
||
func inner(o : O1) { assert o.field == 42 }; | ||
|
||
func go() { | ||
go1({ field = 42 }); // field: 9671866 | ||
go2({ a = 25; field = 42 }); | ||
go3({ a = 25; field = 42; other = 83 }); | ||
go4({ a = 25; foo = 8; field = 42; other = 83 }); | ||
let co4 = CO4(); | ||
let a = co4.a; | ||
go4(co4) | ||
}; | ||
|
||
go(); |