Ref * sysVectorAppend( Ref * pc, class MachineClass * vm ) { // Variables here would be unaffected by a GC. unsigned long N; unsigned long lhs_n; unsigned long rhs_n; if ( vm->count != 2 ) throw Ginger::Mishap( "Wrong number of arguments in vectorAppend" ); { // May need to GC so leave on the stack. Ref rhs = vm->fastPeek(); Ref lhs = vm->fastPeek( 1 ); if ( !IsObj( lhs ) || !IsObj( rhs ) ) throw Ginger::Mishap( "Invalid arguments in vectorAppend" ); Ref * lhs_K = RefToPtr4( lhs ); Ref * rhs_K = RefToPtr4( rhs ); Ref lhs_key = *lhs_K; Ref rhs_key = *rhs_K; if ( lhs_key != rhs_key || !IsSimpleKey( lhs_key ) || KindOfSimpleKey( lhs_key ) != VECTOR_KIND ) throw Ginger::Mishap( "Invalid arguments in vectorAppend" ); lhs_n = sizeAfterKeyOfVectorLayout( lhs_K ); rhs_n = sizeAfterKeyOfVectorLayout( rhs_K ); N = lhs_n + rhs_n; } XfrClass xfr( vm->heap().preflight( pc, N + 2 ) ); // No risk of GC so safe to pop. Ref * rhs_K = RefToPtr4( vm->fastPop() ); Ref * lhs_K = RefToPtr4( vm->fastPop() ); xfr.xfrRef( ULongToSmall( N ) ); xfr.setOrigin(); xfr.xfrRef( *lhs_K ); xfr.xfrCopy( lhs_K + 1, lhs_n ); xfr.xfrCopy( rhs_K + 1, rhs_n ); vm->fastPush( xfr.makeRef() ); return pc; }
Ref * sysVectorLength( Ref *pc, class MachineClass * vm ) { if ( vm->count != 1 ) throw Ginger::Mishap( "Wrong number of arguments for vectorLength" ); Ref r = vm->fastPeek(); if ( !IsVector( r ) ) throw Ginger::Mishap( "Argument mismatch for vectorLength" ); Ref * obj_K = RefToPtr4( r ); vm->fastPeek() = LongToSmall( sizeAfterKeyOfVectorLayout( obj_K ) ); return pc; }
Ref * cgiValue( Ref * pc, class MachineClass * vm ) { if ( vm->count != 1 ) throw Ginger::Mishap( "ArgsMismatch" ); Ref r = vm->fastPeek(); if ( !IsStringKind( r ) ) throw Ginger::Mishap( "Non-string argument needed for getEnv" ); Ref * str_K = RefToPtr4( r ); char * fieldname = reinterpret_cast< char * >( str_K + 1 ); const char * value = vm->getAppContext().cgiValue( fieldname ); vm->fastPeek() = vm->heap().copyString( pc, value ); return pc; }
Ref * sysVectorExplode( Ref *pc, class MachineClass * vm ) { if ( vm->count != 1 ) throw Ginger::Mishap( "Wrong number of arguments for vectorExplode" ); Ref r = vm->fastPop(); if ( !IsVector( r ) ) throw Ginger::Mishap( "Argument mismatch for vectorExplode" ); Ref *obj_K = RefToPtr4( r ); unsigned long n = sizeAfterKeyOfVectorLayout( obj_K ); vm->checkStackRoom( n ); memcpy( vm->vp + 1, obj_K + 1, n * sizeof( Ref )); vm->vp += n; return pc; }
/** setSlot( CLASS:Class, POSITION:Small, METHOD:Method ) 1. The method is inserted into the correct position in the class's slot array. To start with, only one method per slot will be permitted. 2. A call to setMethod is then made with an unsafe access function as the method's function. The values are passed on the stack. No stack checks are needed as the size of the argument lists of the two functions are the same. */ Ref * sysSetSlot( Ref * pc, MachineClass * vm ) { if ( vm->count != 3 ) throw Ginger::Mishap( "Wrong number of arguments" ); Ref method = vm->fastPop(); Ref position = vm->fastPop(); Ref gclass = vm->fastPop(); if ( !IsMethod( method ) ) throw Ginger::Mishap( "Method needed" ).culprit( "Method", refToString( method ) ); if ( !IsSmall( position ) ) throw Ginger::Mishap( "Small needed" ).culprit( "Position", refToString( position ) ); if ( !IsClass( gclass ) ) throw Ginger::Mishap( "Class needed" ).culprit( "Class", refToString( gclass ) ); long pos = SmallToLong( position ); long nfields = SmallToLong( RefToPtr4( gclass )[ CLASS_OFFSET_NFIELDS ] ); if ( not( 1 <= pos && pos <= nfields ) ) { throw Ginger::Mishap( "Position out of range" ). culprit( "Position", pos ). culprit( "Number of fields", nfields ) ; } // Update the class-slot. INDEX( INDEX( gclass, CLASS_OFFSET_SLOTS ), pos ) = method; // Push onto the stack to get protection from garbage collection. vm->fastPush( gclass ); vm->fastPush( method ); // ENDFUNCTION does not in fact cause a garbage collection, as it // forces the heap to grow. However this is a more accurate way // to write the code. // // The following block should not be in-lined but extracted as a // service function. { CodeGen codegen = vm->codegen(); // TODO: Supply a useful name. codegen->vmiFUNCTION( 1, 1 ); codegen->vmiFIELD( pos ); codegen->vmiSYS_RETURN(); vm->fastPush( codegen->vmiENDFUNCTION() ); } // We do not need to modify vm->count, it's already 3. // Simply chain into sysSetMethod. return sysSetMethod( pc, vm ); }
Ref * sysIsUpperCase( Ref * pc, class MachineClass * vm ) { if ( vm->count != 1 ) throw Ginger::Mishap( "Wrong number of arguments" ); Ref r = vm->fastPeek(); if ( IsCharacter( r ) ) { vm->fastPeek() = isupper( CharacterToChar( r ) ) ? SYS_TRUE : SYS_FALSE; } else if ( IsString( r ) ) { Ref * str_K = RefToPtr4( r ); char * s = reinterpret_cast< char * >( &str_K[ 1 ] ); vm->fastPeek() = SYS_TRUE; while ( *s != 0 ) { if ( not isupper( *s++ ) ) { vm->fastPeek() = SYS_FALSE; break; } } } else { throw Ginger::Mishap( "Non-character argument" ).culprit( "Argument", refToShowString( r ) ); } return pc; }
Ref fastPairTail( Ref r ) { return RefToPtr4( r )[ PAIR_TAIL_OFFSET ]; }
Ref fastPairHead( Ref r ) { return RefToPtr4( r )[ PAIR_HEAD_OFFSET ]; }
Ref refVectorLayoutLength( Ref r ) { return RefToPtr4( r )[ VECTOR_OFFSET_LENGTH ]; }
gngdouble_t gngFastDoubleValue( Ref r ) { gngdouble_t d; char * double_bytes = reinterpret_cast< char * >( RefToPtr4( r ) + 1 ); memcpy( reinterpret_cast< char * >( &d ), double_bytes, sizeof( gngdouble_t ) ); return d; }
HeapObject( Cell _c ) : obj_K( RefToPtr4( _c.ref ) ) {}
Ref * sysFastVectorLength( Ref *pc, class MachineClass * vm ) { Ref r = vm->fastPeek(); Ref * obj_K = RefToPtr4( r ); vm->fastPeek() = LongToSmall( sizeAfterKeyOfVectorLayout( obj_K ) ); return pc; }