@@ -363,7 +363,7 @@ the address of the boxes content. Likewise with pairs.
363363We use a register, @racket['rbx ], to hold the address of the next free
364364memory location in memory. To allocate memory, we simply increment
365365the content of @racket['rbx ] by a multiple of 8. To initialize the
366- memory, we just write into the memory at that location. To contruct a
366+ memory, we just write into the memory at that location. To construct a
367367pair or box value, we just tag the unused bits of the address.
368368
369369
@@ -392,28 +392,41 @@ dereferencing the memory:
392392 (Mov 'rax (Offset 'rax 0 ))) ; load memory into rax
393393)
394394
395- Pairs are similar. Suppose we want to make @racket[(cons 3 4 )]:
395+ Pairs are similar, only they are represented as tagged pointers to two
396+ words of memory. Suppose we want to make @racket[(cons 3 4 )]:
396397
397398@#reader scribble/comment-reader
398399(racketblock
399- (seq (Mov 'rax (value->bits 3 ))
400- (Mov (Offset 'rbx 0 ) 'rax ) ; write '3 ' into address held by rbx
401- (Mov 'rax (value->bits 4 ))
402- (Mov (Offset 'rbx 8 ) 'rax ) ; write '4 ' into word after address held by rbx
400+ (seq (Mov 'rax (value->bits 4 ))
401+ (Mov (Offset 'rbx 0 ) 'rax ) ; write '4 ' into address held by rbx
402+ (Mov 'rax (value->bits 3 ))
403+ (Mov (Offset 'rbx 8 ) 'rax ) ; write '3 ' into word after address held by rbx
403404 (Mov 'rax rbx) ; copy pointer into return register
404- (Or 'rax type-pair ) ; tag pointer as a pair
405+ (Or 'rax type-cons ) ; tag pointer as a pair
405406 (Add 'rbx 16 )) ; advance rbx 2 words
406407)
407408
409+ This code writes two words of memory and leaves a tagged pointer in
410+ @racket['rax ]. It's worth noting that we chose to write the
411+ @racket[cdr] of the pair into the @emph{first} word of memory and the
412+ @racket[car] into the @emph{second}. This may seem like a strange
413+ choice, but how we lay out the memory is in some sense an arbitrary
414+ choice, so long as all our pair operations respect this layout. We
415+ could have just as easily done the @racket[car] first and @racket[cdr]
416+ second. The reason for laying out pairs as we did will make things
417+ slightly more convenient when implementing the @racket[cons] primitive
418+ as we'll see later.
419+
420+
408421If @racket['rax ] holds a pair value, we can project out the elements
409422by erasing the pair tag , leaving just the address of the pair contents,
410423then dereferencing either the first or second word of memory:
411424
412425@#reader scribble/comment-reader
413426(racketblock
414- (seq (Xor 'rax type-pair ) ; erase the pair tag
415- (Mov 'rax (Offset 'rax 0 )) ; load car into rax
416- (Mov 'rax (Offset 'rax 8 ))) ; or... load cdr into rax
427+ (seq (Xor 'rax type-cons ) ; erase the pair tag
428+ (Mov 'rax (Offset 'rax 8 )) ; load car into rax
429+ (Mov 'rax (Offset 'rax 0 ))) ; or... load cdr into rax
417430)
418431
419432From here, writing the compiler for @racket[box], @racket[unbox],
@@ -469,6 +482,16 @@ one:
469482(show '(cdr x) '(x))
470483]
471484
485+ We can now see why we chose to layout pairs with the @racket[cdr]
486+ first and @racket[car] second. Since @racket[cons] is a binary
487+ operation, the expression which produces the @racket[car] value will
488+ be evaluated first and pushed on the stack. Then the expression that
489+ produces the @racket[cdr] value will execute with its result sitting
490+ in @racket[rax]. So at this point it's easiest to write out the
491+ @racket[cdr] since it's already sitting in a register. Once we do
492+ that, we can pop the @racket[car] value into @racket['rax ] and write
493+ that. Hence our choice for the layout.
494+
472495@section[#:tag "hustle-run-time " ]{A Run-Time for @this-lang}
473496
474497First, we extend our runtime system's view of values to include
0 commit comments