Arc Forumnew | comments | leaders | submitlogin
2 points by drcode 5719 days ago | link | parent

Hmm... the reason I was thinking it wouldn't help is because arc objects are just glorified hash tables. This means that if we implemented an arc2js program it would use a hash table on the js end...

It's possible though that you could implement arc hash tables using js objects, since they, too, are just glorified hash tables in a different way.

Looking briefly on the web, it looks like it might be possible to fully implement hashtables with js objects. In that case, arc objects could benefit from hidden classes. OTOH, regular hash tables may underperform due to innappropriate attempts to force hidden classes on them.



3 points by almkglor 5719 days ago | link

We can actually implement hash tables as hidden classes on Arc-on-mzscheme.

Basically calls on the arc side are compiled thusly:

  (fn (bar)
    (foo bar))
   =>
  (lambda (bar)
    (ar-funcall1 __foo bar)) ; the 1 here means there is one argument
Now we only need to perform some kind of let-lifting:

  (let ((callsite1 (ar-funcaller1)))
    (lambda (bar)
      (callsite1 __foo bar)))
where ar-funcaller1 would be:

  ; scheme!!
  (define (ar-funcaller1)
    (lambda (f arg1)
      ;dispatch based on f, argument types, etc.
      ...))
(I've actually already implemented this experimentally, but the performance didn't increase much - however this was before I implemented serious multimethods (which I haven't actually completed implementing anyway...), so I suppose I can bring this back to amortize multimethod lookup.)

By using a callsite lambda object, we can keep track of previous multimethod etc. lookups.

And then we can make the compiler emit code especially for (foo 'bar) forms:

  (fn (foo) foo!bar)
    =>
  (let ((callsite1 (ar-quotecaller1 'bar)))
    (lambda (foo)
      (callsite1 foo)))
callsite1 can then cache lookups on hidden classes.

  (define (always-false . rest) #f)
  (define (ar-quotecaller1 quoted)
    ; use only a single variable to prevent
    ; race conditions in multi-threaded code
    ; (might not always work if using true
    ; threads instead of green ones though)
    (let ((checker-and-dispatch (cons always-false #f)))
      (lambda (ob)
        ; copy to our own local variable to
        ; prevent race conditions (assuming
        ; the read is atomic anyway)
        (let* ((my-checker-and-dispatch checker-and-dispatch)
               (checker (car my-checker-and-dispatch)))
          (if (not (checker ob))
              (begin
                (set! my-checker-and-dispatch
                      (patch-quotecaller1 ob quoted))
                (set! checker-and-dispatch my-checker-and-dispatch)))
          ((cdr my-checker-and-dispatch) ob quoted)))))
  (define (patch-quotecaller1 ob quoted)
    (cond
      ((table-with-hidden-class? ob) ; implemented however you will
        (let* ((hidden-class (hidden-class-get ob))
               (hidden-class-index (hidden-class-index-lookup hidden-class quoted)))
          (cons
            ; checker
            (lambda (ob _)
              (and (table-with-hidden-class? ob)
                   (eq? hidden-class (hidden-class-get ob))))
            ; dispatcher
            (lambda (ob _)
              (hidden-class-ref ob hidden-class-index)))))
      (... ;other conditions: functions, methods, other data types...
        )))

I was actually going to implement this, but then I thought that using arc hash tables as objects - and in particular the (tb 'key) form - wasn't actually that common enough (at least in Arc) to justify optimizing for it. Hmm.

-----