home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / md / mac / mdmac.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  19.7 KB  |  843 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include <Types.h>
  20. #include <Timer.h>
  21. #include <Files.h>
  22. #include <Errors.h>
  23. #include <Folders.h>
  24. #include <Events.h>
  25. #include <Processes.h>
  26. #include <TextUtils.h>
  27. #include <MixedMode.h>
  28. #include <LowMem.h>
  29.  
  30. #include <fcntl.h>
  31. #include <string.h>
  32. #include <stdio.h>
  33. #include <stat.h>
  34. #include <stdarg.h>
  35. #include <unix.h>
  36.  
  37. #include "MacErrorHandling.h"
  38.  
  39. #include "primpl.h"
  40. #include "prgc.h"
  41. #include "MacMemAllocator.h"
  42.  
  43. enum {
  44.     kGarbageCollectionEmergencyFundSize = 16 * 1024,
  45.     kGarbageCollectionMemTightFundSize    = 48 * 1024
  46. };
  47.  
  48. enum {
  49.     uppExitToShellProcInfo                 = kPascalStackBased,
  50.     uppStackSpaceProcInfo                = kRegisterBased 
  51.                                           | RESULT_SIZE(SIZE_CODE(sizeof(long)))
  52.                                           | REGISTER_RESULT_LOCATION(kRegisterD0)
  53.                                            | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(UInt16)))
  54. };
  55.  
  56.  
  57. #define UNIMPLEMENTED_ROUTINE            \
  58.     DebugStr("\pNot Implemented Yet");    \
  59.     return 0;
  60.  
  61. //
  62. // Local routines
  63. //
  64. void PStrFromCStr(const char *, Str255);
  65. unsigned char GarbageCollectorCacheFlusher(PRUint32 size);
  66.  
  67. extern PRThread *gPrimaryThread;
  68.  
  69. pascal void ExitToShellPatch(void);
  70.  
  71. UniversalProcPtr    gExitToShellPatchCallThru = NULL;
  72. #if GENERATINGCFM
  73. RoutineDescriptor     gExitToShellPatchRD = BUILD_ROUTINE_DESCRIPTOR(uppExitToShellProcInfo, &ExitToShellPatch);
  74. #else
  75. #define gExitToShellPatchRD ExitToShellPatch
  76. #endif
  77.  
  78. UniversalProcPtr    gStackSpacePatchCallThru = NULL;
  79. #if GENERATINGCFM
  80. pascal long StackSpacePatch(UInt16);
  81. RoutineDescriptor     StackSpacePatchRD = BUILD_ROUTINE_DESCRIPTOR(uppStackSpaceProcInfo, &StackSpacePatch);
  82. #else
  83. pascal long StackSpacePatch();
  84. asm pascal long StackSpacePatchGlue();
  85. #endif
  86.  
  87.  
  88. //##############################################################################
  89. //##############################################################################
  90. #pragma mark -
  91. #pragma mark CREATING MACINTOSH THREAD STACKS
  92.  
  93.  
  94. #if !GENERATINGCFM
  95.  
  96. asm long pascal StackSpacePatchCallThruGlue(long theAddress)
  97. {
  98.     move.l    4(sp), a0
  99.     jsr        (a0)
  100.     move.l    (sp)+, a0
  101.     add        #0x8, sp 
  102.     move.l    d0, -(sp)
  103.     jmp        (a0)
  104. }
  105.  
  106. asm pascal long StackSpacePatchGlue()
  107. {
  108.  
  109.     //    Check out LocalA5.  If it is zero, then
  110.     //    it is our first time through, and we should
  111.     //    store away our A5.  If not, then we are
  112.     //    a real time manager callback, so we should
  113.     //    store away A5, set up our local a5, jsr
  114.     //    to our callback, and then restore the
  115.     //    previous A5.
  116.     
  117.     lea            LocalA5, a0
  118.     move.l        (a0), d0
  119.     cmpi.l        #0, d0
  120.     bne            DoStackSpace
  121.     
  122.     move.l        a5, (a0)
  123.     rts
  124.  
  125. DoStackSpace:
  126.     
  127.     //    Save A5, restore our local A5
  128.     
  129.     move.l        a5, -(sp)
  130.     move.l        d0, a5 
  131.     
  132.     //    Jump to our C routine
  133.     
  134.     clr.l        -(sp)
  135.     jsr         StackSpacePatch
  136.     move.l        (sp)+, d0
  137.     
  138.     //    Restore the previous A5
  139.     
  140.     move.l        (sp)+, a5
  141.  
  142.     rts
  143.  
  144. LocalA5:
  145.  
  146.     dc.l        0
  147.     
  148. }
  149.  
  150. #endif
  151.  
  152. #if GENERATINGCFM
  153. pascal long StackSpacePatch(UInt16 trapNo)
  154. #else
  155. pascal long StackSpacePatch()
  156. #endif
  157. {
  158.     char        tos;
  159.     PRThread    *thisThread;
  160.     
  161.     thisThread = PR_CurrentThread();
  162.     
  163.     //    If we are the primary thread, then call through to the
  164.     //    good ol' fashion stack space implementation.  Otherwise,
  165.     //    compute it by hand.
  166.     if ((thisThread == gPrimaryThread) ||     
  167.         (&tos < thisThread->stack->stackBottom) || 
  168.         (&tos > thisThread->stack->stackTop)) {
  169. #if GENERATINGCFM
  170.         return CallOSTrapUniversalProc(gStackSpacePatchCallThru, uppStackSpaceProcInfo, trapNo);
  171. #else
  172.         return StackSpacePatchCallThruGlue((long)gStackSpacePatchCallThru);
  173. #endif
  174.     }
  175.     else {
  176.         return &tos - thisThread->stack->stackBottom;
  177.     }
  178. }
  179.  
  180.  
  181. //##############################################################################
  182. //##############################################################################
  183. #pragma mark -
  184. #pragma mark ENVIRONMENT VARIABLES
  185.  
  186.  
  187. typedef struct EnvVariable EnvVariable;
  188.  
  189. struct EnvVariable {
  190.     char             *variable;
  191.     char            *value;
  192.     EnvVariable        *next;
  193. };
  194.  
  195. EnvVariable        *gEnvironmentVariables = NULL;
  196.  
  197. char *_MD_GetEnv(const char *name)
  198. {
  199.     EnvVariable     *currentVariable = gEnvironmentVariables;
  200.  
  201.     while (currentVariable) {
  202.         if (!strcmp(currentVariable->variable, name))
  203.             return currentVariable->value;
  204.             
  205.         currentVariable = currentVariable->next;
  206.     }
  207.  
  208.     return NULL;
  209. }
  210.  
  211. PR_IMPLEMENT(int) 
  212. _MD_PutEnv(const char *string)
  213. {
  214.     EnvVariable     *currentVariable = gEnvironmentVariables;
  215.     char            *variableCopy,
  216.                     *value,
  217.                     *current;
  218.                     
  219.     variableCopy = strdup(string);
  220.     PR_ASSERT(variableCopy != NULL);
  221.  
  222.     current = variableCopy;
  223.     while (*current != '=')
  224.         current++;
  225.  
  226.     *current = 0;
  227.     current++;
  228.  
  229.     value = current;
  230.  
  231.     while (currentVariable) {
  232.         if (!strcmp(currentVariable->variable, variableCopy))
  233.             break;
  234.         
  235.         currentVariable = currentVariable->next;
  236.     }
  237.  
  238.     if (currentVariable == NULL) {
  239.         currentVariable = PR_NEW(EnvVariable);
  240.         
  241.         if (currentVariable == NULL) {
  242.             PR_DELETE(variableCopy);
  243.             return PR_FALSE;
  244.         }
  245.         
  246.         currentVariable->variable = strdup(variableCopy);
  247.         currentVariable->value = strdup(value);
  248.         currentVariable->next = gEnvironmentVariables;
  249.         gEnvironmentVariables = currentVariable;
  250.     }
  251.     
  252.     else {
  253.         PR_DELETE(currentVariable->value);
  254.         currentVariable->value = strdup(current);
  255.  
  256.         /* This is a temporary hack.  Working on a real fix, remove this when done. */
  257.         /* OK, there are two ways to access the  */
  258.         /* library path, getenv() and PR_GetLibraryPath().  Take a look at PR_GetLibraryPath(). */
  259.         /* You'll see that we keep the path in a global which is intialized at startup from */
  260.         /* a call to getenv().  From then on, they have nothing in common. */
  261.         /* We need to keep them in synch.  */
  262.         if (strcmp(currentVariable->variable, "LD_LIBRARY_PATH") == 0)
  263.             PR_SetLibraryPath(currentVariable->value);
  264.     }
  265.     
  266.     PR_DELETE(variableCopy);
  267.     return PR_TRUE;
  268. }
  269.  
  270.  
  271.  
  272. //##############################################################################
  273. //##############################################################################
  274. #pragma mark -
  275. #pragma mark MISCELLANEOUS
  276.  
  277. PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
  278. {
  279.     if (isCurrent) {
  280.     (void) setjmp(t->md.jb);
  281.     }
  282.     *np = sizeof(t->md.jb) / sizeof(PRUint32);
  283.     return (PRWord*) (t->md.jb);
  284. }
  285.  
  286. void _MD_GetRegisters(PRUint32 *to)
  287. {
  288.   (void) setjmp((void*) to);
  289. }
  290.  
  291. void _MD_EarlyInit()
  292. {
  293.     Handle        environmentVariables;
  294.  
  295. #if !defined(MAC_NSPR_STANDALONE)
  296.     // MacintoshInitializeMemory();  Moved to mdmacmem.c: AllocateRawMemory(Size blockSize)
  297. #else
  298.     MacintoshInitializeMemory();
  299. #endif
  300.     MacintoshInitializeTime();
  301.     
  302.     //    Install resource-controlled environment variables.
  303.     
  304.     environmentVariables = GetResource('Envi', 128);
  305.     if (environmentVariables != NULL) {
  306.     
  307.         Size     resourceSize;
  308.         char    *currentPutEnvString = (char *)*environmentVariables,
  309.                 *currentScanChar = currentPutEnvString;
  310.                 
  311.         resourceSize = GetHandleSize(environmentVariables);            
  312.         DetachResource(environmentVariables);
  313.         HLock(environmentVariables);
  314.         
  315.         while (resourceSize--) {
  316.         
  317.             if ((*currentScanChar == '\n') || (*currentScanChar == '\r')) {
  318.                 *currentScanChar = 0;
  319.                 _MD_PutEnv (currentPutEnvString);
  320.                 currentPutEnvString = currentScanChar + 1;
  321.             }
  322.         
  323.             currentScanChar++;
  324.         
  325.         }
  326.         
  327.         DisposeHandle(environmentVariables);
  328.  
  329.     }
  330.  
  331. #ifdef PR_INTERNAL_LOGGING
  332.     _MD_PutEnv ("NSPR_LOG_MODULES=clock:6,cmon:6,io:6,mon:6,linker:6,cvar:6,sched:6,thread:6");
  333. #endif
  334.     
  335. #if GENERATINGCFM
  336.     gStackSpacePatchCallThru = GetOSTrapAddress(0x0065);
  337.     SetOSTrapAddress((UniversalProcPtr)&StackSpacePatchRD, 0x0065);
  338.     {
  339.         long foo;
  340.         foo = StackSpace();
  341.     }
  342. #else
  343.     gStackSpacePatchCallThru = GetOSTrapAddress(0x0065);
  344.     SetOSTrapAddress((UniversalProcPtr)&StackSpacePatchGlue, 0x0065);
  345.     StackSpace();
  346. #endif
  347.  
  348.     //    THIS IS VERY IMPORTANT.  Install our ExitToShell patch.  
  349.     //    This allows us to deactivate our Time Mananger task even
  350.     //    if we are not totally gracefully exited.  If this is not
  351.     //    done then we will randomly crash at later times when the
  352.     //    task is called after the app heap is gone.
  353.     
  354.     gExitToShellPatchCallThru = GetToolboxTrapAddress(0x01F4);
  355.     SetToolboxTrapAddress((UniversalProcPtr)&gExitToShellPatchRD, 0x01F4);
  356.  
  357. }
  358.  
  359. void _MD_FinalInit()
  360. {
  361.     _MD_InitNetAccess();
  362. }
  363.  
  364. void PR_InitMemory(void) {
  365. #ifndef NSPR_AS_SHARED_LIB
  366.     //    Needed for Mac browsers without Java.  We don╒t want them calling PR_INIT, since it
  367.     //    brings in all of the thread support.  But we do need to allow them to initialize
  368.     //    the NSPR memory package.
  369.     //    This should go away when all clients of the NSPR want threads AND memory.
  370.     MacintoshInitializeMemory();
  371. #endif
  372. }
  373.  
  374. //##############################################################################
  375. //##############################################################################
  376. #pragma mark -
  377. #pragma mark TERMINATION
  378.  
  379. typedef pascal void (* ExitToShellProc)(void);  
  380.  
  381. //    THIS IS *** VERY *** IMPORTANT... our ExitToShell patch.
  382. //    This allows us to deactivate our Time Mananger task even
  383. //    if we are not totally gracefully exited.  If this is not
  384. //    done then we will randomly crash at later times when the
  385. //    task is called after the app heap is gone.
  386.  
  387. extern TMTask        gTimeManagerTaskElem;
  388.  
  389. pascal void ExitToShellPatch(void)
  390. {
  391.     _MD_StopInterrupts();    
  392.  
  393.     CloseOpenTransport();    
  394.  
  395. #if GENERATINGCFM
  396.     CallUniversalProc(gExitToShellPatchCallThru, uppExitToShellProcInfo);
  397. #else 
  398.     {
  399.         ExitToShellProc    *exitProc = (ExitToShellProc *)&gExitToShellPatchCallThru;
  400.         (*exitProc)();
  401.     }
  402. #endif
  403.  
  404. }
  405.  
  406.  
  407.  
  408. //##############################################################################
  409. //##############################################################################
  410. #pragma mark -
  411. #pragma mark STRING OPERATIONS
  412.  
  413. #if !defined(MAC_NSPR_STANDALONE)
  414.  
  415. //    PStrFromCStr converts the source C string to a destination
  416. //    pascal string as it copies. The dest string will
  417. //    be truncated to fit into an Str255 if necessary.
  418. //  If the C String pointer is NULL, the pascal string's length is set to zero
  419. //
  420. extern void 
  421. PStrFromCStr(const char* src, Str255 dst)
  422. {
  423.     short     length  = 0;
  424.     
  425.     // handle case of overlapping strings
  426.     if ( (void*)src == (void*)dst )
  427.     {
  428.         unsigned char*        curdst = &dst[1];
  429.         unsigned char        thisChar;
  430.                 
  431.         thisChar = *(const unsigned char*)src++;
  432.         while ( thisChar != '\0' ) 
  433.         {
  434.             unsigned char    nextChar;
  435.             
  436.             // use nextChar so we don't overwrite what we are about to read
  437.             nextChar = *(const unsigned char*)src++;
  438.             *curdst++ = thisChar;
  439.             thisChar = nextChar;
  440.             
  441.             if ( ++length >= 255 )
  442.                 break;
  443.         }
  444.     }
  445.     else if ( src != NULL )
  446.     {
  447.         unsigned char*        curdst = &dst[1];
  448.         short                 overflow = 255;        // count down so test it loop is faster
  449.         register char        temp;
  450.     
  451.         // Can't do the K&R C thing of ╥while (*s++ = *t++)╙ because it will copy trailing zero
  452.         // which might overrun pascal buffer.  Instead we use a temp variable.
  453.         while ( (temp = *src++) != 0 ) 
  454.         {
  455.             *(char*)curdst++ = temp;
  456.                 
  457.             if ( --overflow <= 0 )
  458.                 break;
  459.         }
  460.         length = 255 - overflow;
  461.     }
  462.     dst[0] = length;
  463. }
  464.  
  465.  
  466. void CStrFromPStr(ConstStr255Param pString, char **cString)
  467. {
  468.     // Allocates a cString and copies a Pascal string into it.
  469.     unsigned int    len;
  470.     
  471.     len = pString[0];
  472.     *cString = malloc(len+1);
  473.     
  474.     if (*cString != NULL) {
  475.         strncpy(*cString, (char *)&pString[1], len);
  476.         (*cString)[len] = NULL;
  477.     }
  478. }
  479.  
  480.  
  481. void dprintf(const char *format, ...)
  482. {
  483. #if DEBUG
  484.     va_list ap;
  485.     char    *buffer;
  486.     
  487.     va_start(ap, format);
  488.     buffer = PR_vsmprintf(format, ap);
  489.     va_end(ap);
  490.     
  491.     c2pstr(buffer);
  492.     DebugStr( (unsigned char *)buffer);
  493.     free(buffer);
  494. #endif /* DEBUG */
  495. }
  496.  
  497. #else
  498.  
  499. void debugstr(const char *debuggerMsg)
  500. {
  501.     Str255        pStr;
  502.     
  503.     PStrFromCStr(debuggerMsg, pStr);
  504.     DebugStr(pStr);
  505. }
  506.  
  507.  
  508. char *strdup(const char *source)
  509. {
  510.     char     *newAllocation;
  511.     size_t    stringLength;
  512.  
  513. #ifdef DEBUG
  514.     PR_ASSERT(source);
  515. #endif
  516.     
  517.     stringLength = strlen(source) + 1;
  518.     
  519.     newAllocation = (char *)PR_MALLOC(stringLength);
  520.     if (newAllocation == NULL)
  521.         return NULL;
  522.     BlockMoveData(source, newAllocation, stringLength);
  523.     return newAllocation;
  524. }
  525.  
  526. //    PStrFromCStr converts the source C string to a destination
  527. //    pascal string as it copies. The dest string will
  528. //    be truncated to fit into an Str255 if necessary.
  529. //  If the C String pointer is NULL, the pascal string's length is set to zero
  530. //
  531. void PStrFromCStr(const char* src, Str255 dst)
  532. {
  533.     short     length  = 0;
  534.     
  535.     // handle case of overlapping strings
  536.     if ( (void*)src == (void*)dst )
  537.     {
  538.         unsigned char*        curdst = &dst[1];
  539.         unsigned char        thisChar;
  540.                 
  541.         thisChar = *(const unsigned char*)src++;
  542.         while ( thisChar != '\0' ) 
  543.         {
  544.             unsigned char    nextChar;
  545.             
  546.             // use nextChar so we don't overwrite what we are about to read
  547.             nextChar = *(const unsigned char*)src++;
  548.             *curdst++ = thisChar;
  549.             thisChar = nextChar;
  550.             
  551.             if ( ++length >= 255 )
  552.                 break;
  553.         }
  554.     }
  555.     else if ( src != NULL )
  556.     {
  557.         unsigned char*        curdst = &dst[1];
  558.         short                 overflow = 255;        // count down so test it loop is faster
  559.         register char        temp;
  560.     
  561.         // Can't do the K&R C thing of ╥while (*s++ = *t++)╙ because it will copy trailing zero
  562.         // which might overrun pascal buffer.  Instead we use a temp variable.
  563.         while ( (temp = *src++) != 0 ) 
  564.         {
  565.             *(char*)curdst++ = temp;
  566.                 
  567.             if ( --overflow <= 0 )
  568.                 break;
  569.         }
  570.         length = 255 - overflow;
  571.     }
  572.     dst[0] = length;
  573. }
  574.  
  575.  
  576. void CStrFromPStr(ConstStr255Param pString, char **cString)
  577. {
  578.     // Allocates a cString and copies a Pascal string into it.
  579.     unsigned int    len;
  580.     
  581.     len = pString[0];
  582.     *cString = PR_MALLOC(len+1);
  583.     
  584.     if (*cString != NULL) {
  585.         strncpy(*cString, (char *)&pString[1], len);
  586.         (*cString)[len] = NULL;
  587.     }
  588. }
  589.  
  590.  
  591. size_t strlen(const char *source)
  592. {
  593.     size_t currentLength = 0;
  594.     
  595.     if (source == NULL)
  596.         return currentLength;
  597.             
  598.     while (*source++ != '\0')
  599.         currentLength++;
  600.         
  601.     return currentLength;
  602. }
  603.  
  604. int strcmpcore(const char *str1, const char *str2, int caseSensitive)
  605. {
  606.     char     currentChar1, currentChar2;
  607.  
  608.     while (1) {
  609.     
  610.         currentChar1 = *str1;
  611.         currentChar2 = *str2;
  612.         
  613.         if (!caseSensitive) {
  614.             
  615.             if ((currentChar1 >= 'a') && (currentChar1 <= 'z'))
  616.                 currentChar1 += ('A' - 'a');
  617.         
  618.             if ((currentChar2 >= 'a') && (currentChar2 <= 'z'))
  619.                 currentChar2 += ('A' - 'a');
  620.         
  621.         }
  622.     
  623.         if (currentChar1 == '\0')
  624.             break;
  625.     
  626.         if (currentChar1 != currentChar2)
  627.             return currentChar1 - currentChar2;
  628.             
  629.         str1++;
  630.         str2++;
  631.     
  632.     }
  633.     
  634.     return currentChar1 - currentChar2;
  635. }
  636.  
  637. int strcmp(const char *str1, const char *str2)
  638. {
  639.     return strcmpcore(str1, str2, true);
  640. }
  641.  
  642. int strcasecmp(const char *str1, const char *str2)
  643. {
  644.     return strcmpcore(str1, str2, false);
  645. }
  646.  
  647. #if GENERATING68K
  648. asm void *memset(void *target, int pattern, size_t length)                                        // Legal asm qualifier
  649. {
  650.                 MOVEA.L        4(SP),A0            // target -> A0
  651.                 MOVE.W        10(SP),D0            // pattern -> D0, length -> D1
  652.                 MOVE.L        12(SP),D1
  653.                 CMPI.L        #30,D1
  654.                 BLT            end
  655.                 
  656.                 // Fill D0 with the pattern
  657.                 MOVEQ        #0,D2                // Clear D2, we╒ll use it as scratch
  658.                 MOVE.B        D0,D2                // Fill the bottom byte
  659.                 LSL.W        #8,D0                //  
  660.                 OR.W        D0,D2
  661.                 MOVE.L        D2,D0
  662.                 SWAP        D2
  663.                 OR.L        D2,D0
  664.                 
  665.                 // Are we odd aligned?
  666.                 MOVE.L        A0,D2                // Copy target address into scratch
  667.                 LSR.B        #1,D2                // Sets C bit
  668.                 BCC.S        checkAlign2            // If even, check for 16-byte alignment
  669.                 MOVE.B        D0,(A0)+            // Take care of odd byte
  670.                 SUBQ.L        #1,D1                // Update length
  671.                 
  672.                 // Are we odd 16-byte word alligned?
  673. checkAlign2:    LSR.B        #1,D2                // Still set from last check
  674.                 BCC            totallyAligned
  675.                 MOVE.W        D0,(A0)+
  676.                 SUBQ.L        #2,D1
  677.             
  678. totallyAligned:    MOVE.L        D1,D2
  679.                 LSR.L        #4,D2
  680.                 SUBQ.L        #1,D2
  681. copyHunk:        MOVE.L        D0,(A0)+
  682.                 MOVE.L        D0,(A0)+
  683.                 MOVE.L        D0,(A0)+
  684.                 MOVE.L        D0,(A0)+
  685.                 SUBQ.L        #1,D2
  686.                 BCC            copyHunk
  687.                 ANDI.W        #15,D1                // Check done?
  688.                 BRA            end
  689. dribble:        MOVE.B        D0,(A0)+
  690. end:            DBF            D1,dribble
  691.                 MOVE.L        4(SP),D0            // Return the target
  692.                 RTS                                
  693. }
  694. #endif
  695.  
  696. void *memcpy(void *to, const void *from, size_t size)
  697. {
  698.     if (size != 0) {
  699. #if DEBUG
  700.         if ((UInt32)to < 0x1000)
  701.             DebugStr("\pmemcpy has illegal to argument");
  702.         if ((UInt32)from < 0x1000)
  703.             DebugStr("\pmemcpy has illegal from argument");
  704. #endif
  705.         BlockMoveData(from, to, size);
  706.     }
  707.     return to;
  708. }
  709.  
  710. void dprintf(const char *format, ...)
  711. {
  712.     va_list ap;
  713.     char    *buffer;
  714.     
  715.     va_start(ap, format);
  716.     buffer = (char *)PR_vsmprintf(format, ap);
  717.     va_end(ap);
  718.     
  719.     debugstr(buffer);
  720.     PR_DELETE(buffer);
  721. }
  722.  
  723. void
  724. exit(int result)
  725. {
  726. #pragma unused (result)
  727.  
  728.         ExitToShell();
  729. }
  730.  
  731. void abort(void)
  732. {
  733.     exit(-1);
  734. }
  735.  
  736. #endif
  737.  
  738. //##############################################################################
  739. //##############################################################################
  740. #pragma mark -
  741. #pragma mark FLUSHING THE GARBAGE COLLECTOR
  742.  
  743. #if !defined(MAC_NSPR_STANDALONE)
  744.  
  745. unsigned char GarbageCollectorCacheFlusher(PRUint32)
  746. {
  747.  
  748.     PRIntn is;
  749.  
  750.     UInt32        oldPriority;
  751.  
  752.     //    If java wasn't completely initialized, then bail 
  753.     //    harmlessly.
  754.     
  755.     if (PR_GetGCInfo()->lock == NULL)
  756.         return false;
  757.  
  758. #if DEBUG
  759.     if (_MD_GET_INTSOFF() == 1)
  760.         DebugStr("\pGarbageCollectorCacheFlusher at interrupt time!");
  761. #endif
  762.  
  763.     //    The synchronization here is very tricky.  We really
  764.     //    don't want any other threads to run while we are 
  765.     //    cleaning up the gc heap... they could call malloc,
  766.     //    and then we would be in trouble in a big way.  So,
  767.     //    we jack up our priority and that of the finalizer
  768.     //    so that we won't yield to other threads.
  769.     //    dkc 5/17/96
  770.  
  771.     oldPriority = PR_GetThreadPriority(PR_GetCurrentThread());
  772.     _PR_INTSOFF(is);
  773.     _PR_SetThreadPriority(PR_GetCurrentThread(), (PRThreadPriority)30);
  774.     _PR_INTSON(is);
  775.  
  776.     //    Garbage collect twice.  This will finalize any
  777.     //    dangling AWT resources (images, components), and
  778.     //    then free up their GC space, too.
  779.     //    dkc 2/15/96
  780.     //  interrupts must be on during PR_GC
  781.     
  782.     PR_GC();
  783.     
  784.     //    By setting the finalizer priority to 31, then we 
  785.     //    ensure it will run before us.  When it finishes
  786.     //    its list of finalizations, it returns to us
  787.     //    for the second garbage collection.
  788.     
  789.     PR_Yield();
  790.  
  791.     PR_GC();
  792.     
  793.     //    Restore our old priorities.
  794.     
  795.     _PR_INTSOFF(is);
  796.     _PR_SetThreadPriority(PR_GetCurrentThread(), (PRThreadPriority)oldPriority);
  797.     _PR_INTSON(is);
  798.  
  799.     return false;
  800. }
  801.  
  802. #endif
  803.  
  804. //##############################################################################
  805. //##############################################################################
  806. #pragma mark -
  807. #pragma mark MISCELLANEOUS-HACKS
  808.  
  809.  
  810. //
  811. //        ***** HACK  FIX THESE ****
  812. //
  813. extern long _MD_GetOSName(char *buf, long count)
  814. {
  815.     long    len;
  816.     
  817.     len = PR_snprintf(buf, count, "Mac OS");
  818.     
  819.     return 0;
  820. }
  821.  
  822. extern long _MD_GetOSVersion(char *buf, long count)
  823. {
  824.     long    len;
  825.     
  826.     len = PR_snprintf(buf, count, "7.5");
  827.  
  828.     return 0;
  829. }
  830.  
  831. extern long _MD_GetArchitecture(char *buf, long count)
  832. {
  833.     long    len;
  834.     
  835. #if defined(GENERATINGPOWERPC) && GENERATINGPOWERPC    
  836.     len = PR_snprintf(buf, count, "PowerPC");
  837. #else
  838.     len = PR_snprintf(buf, count, "Motorola68k");
  839. #endif
  840.  
  841.     return 0;
  842. }
  843.