@@ -154,14 +154,26 @@ type SlotMap = Map<LocalIndex,SlotIndex>;
154154type TempMap = Map < NativeType , LocalIndex > ;
155155
156156/** Attempts to match the `__tostack(value)` pattern. Returns `value` if a match, otherwise `0`. */
157- function matchTostack ( module : Module , expr : ExpressionRef ) : ExpressionRef {
157+ function matchPattern ( module : Module , expr : ExpressionRef ) : ExpressionRef {
158158 if ( _BinaryenExpressionGetId ( expr ) == ExpressionId . Call && module . readStringCached ( _BinaryenCallGetTarget ( expr ) ) == BuiltinNames . tostack ) {
159159 assert ( _BinaryenCallGetNumOperands ( expr ) == 1 ) ;
160160 return _BinaryenCallGetOperandAt ( expr , 0 ) ;
161161 }
162162 return 0 ;
163163}
164164
165+ /** Tests whether a `value` matched by `matchTostack` needs a slot. */
166+ function needsSlot ( module : Module , value : ExpressionRef ) : bool {
167+ switch ( _BinaryenExpressionGetId ( value ) ) {
168+ // no need to stack null pointers
169+ case ExpressionId . Const : return ! isConstZero ( value ) ;
170+ // already kept in another slot
171+ case ExpressionId . LocalGet :
172+ case ExpressionId . LocalSet : return false ; // tee
173+ }
174+ return true ;
175+ }
176+
165177/** Instruments a module with a shadow stack for precise GC. */
166178export class ShadowStackPass extends Pass {
167179 /** Stack frame slots, per function. */
@@ -320,9 +332,9 @@ export class ShadowStackPass extends Pass {
320332 var numSlots = 0 ;
321333 for ( let i = 0 , k = operands . length ; i < k ; ++ i ) {
322334 let operand = operands [ i ] ;
323- let match = matchTostack ( module , operand ) ;
335+ let match = matchPattern ( module , operand ) ;
324336 if ( ! match ) continue ;
325- if ( isConstZero ( match ) ) {
337+ if ( ! needsSlot ( module , match ) ) {
326338 operands [ i ] = match ;
327339 continue ;
328340 }
@@ -366,10 +378,10 @@ export class ShadowStackPass extends Pass {
366378 operands [ i ] = _BinaryenCallGetOperandAt ( call , i ) ;
367379 }
368380 let numSlots = this . updateCallOperands ( operands ) ;
381+ for ( let i = 0 , k = operands . length ; i < k ; ++ i ) {
382+ _BinaryenCallSetOperandAt ( call , i , operands [ i ] ) ;
383+ }
369384 if ( numSlots ) {
370- for ( let i = 0 , k = operands . length ; i < k ; ++ i ) {
371- _BinaryenCallSetOperandAt ( call , i , operands [ i ] ) ;
372- }
373385 // Reserve these slots for us so nested calls use their own
374386 this . callSlotOffset += numSlots ;
375387 }
@@ -390,10 +402,10 @@ export class ShadowStackPass extends Pass {
390402 operands [ i ] = _BinaryenCallIndirectGetOperandAt ( callIndirect , i ) ;
391403 }
392404 let numSlots = this . updateCallOperands ( operands ) ;
405+ for ( let i = 0 , k = operands . length ; i < k ; ++ i ) {
406+ _BinaryenCallIndirectSetOperandAt ( callIndirect , i , operands [ i ] ) ;
407+ }
393408 if ( numSlots ) {
394- for ( let i = 0 , k = operands . length ; i < k ; ++ i ) {
395- _BinaryenCallIndirectSetOperandAt ( callIndirect , i , operands [ i ] ) ;
396- }
397409 // Reserve these slots for us so nested calls use their own
398410 this . callSlotOffset += numSlots ;
399411 }
@@ -408,14 +420,14 @@ export class ShadowStackPass extends Pass {
408420
409421 /** @override */
410422 visitLocalSet ( localSet : ExpressionRef ) : void {
423+ let module = this . module ;
411424 let value = _BinaryenLocalSetGetValue ( localSet ) ;
412- let match = matchTostack ( this . module , value ) ;
425+ let match = matchPattern ( module , value ) ;
413426 if ( ! match ) return ;
414- if ( isConstZero ( match ) ) {
427+ if ( ! needsSlot ( module , match ) ) {
415428 _BinaryenLocalSetSetValue ( localSet , match ) ;
416429 return ;
417430 }
418- var module = this . module ;
419431 let index = _BinaryenLocalSetGetIndex ( localSet ) ;
420432 let slotIndex = this . noteSlot ( this . currentFunction , index ) ;
421433 let stmts = new Array < ExpressionRef > ( ) ;
0 commit comments