1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
/*
Title: rtsentry.cpp - Entry points to the run-time system
Copyright (c) 2016, 2017 David C. J. Matthews
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License version 2.1 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#elif defined(_WIN32)
#include "winconfig.h"
#else
#error "No configuration file"
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_ASSERT_H
#include <assert.h>
#define ASSERT(x) assert(x)
#else
#define ASSERT(x)
#endif
#include "globals.h"
#include "rtsentry.h"
#include "save_vec.h"
#include "processes.h"
#include "run_time.h"
#include "polystring.h"
#include "arb.h"
#include "basicio.h"
#include "polyffi.h"
#include "xwindows.h"
#include "os_specific.h"
#include "timing.h"
#include "sighandler.h"
#include "sharedata.h"
#include "run_time.h"
#include "reals.h"
#include "profiling.h"
#include "processes.h"
#include "process_env.h"
#include "poly_specific.h"
#include "objsize.h"
#include "network.h"
#include "exporter.h"
#include "statistics.h"
#include "savestate.h"
extern struct _entrypts rtsCallEPT[];
static entrypts entryPointTable[] =
{
rtsCallEPT,
arbitraryPrecisionEPT,
basicIOEPT,
polyFFIEPT,
xwindowsEPT,
osSpecificEPT,
timingEPT,
sigHandlerEPT,
shareDataEPT,
runTimeEPT,
realsEPT,
profilingEPT,
processesEPT,
processEnvEPT,
polySpecificEPT,
objSizeEPT,
networkingEPT,
exporterEPT,
statisticsEPT,
savestateEPT,
NULL
};
extern "C" {
#ifdef _MSC_VER
__declspec(dllexport)
#endif
POLYUNSIGNED PolyCreateEntryPointObject(PolyObject *threadId, PolyWord arg);
};
// Create an entry point containing the address of the entry and the
// string name. Having the string in there allows us to export the entry.
Handle creatEntryPointObject(TaskData *taskData, Handle entryH, bool isFuncPtr)
{
TempCString entryName(Poly_string_to_C_alloc(entryH->Word()));
if ((const char *)entryName == 0) raise_syscall(taskData, "Insufficient memory", ENOMEM);
// Create space for the address followed by the name as a C string.
uintptr_t space = 1 + (strlen(entryName) + 1 + (isFuncPtr ? 0 : 1) + sizeof(polyRTSFunction*) - 1) / sizeof(PolyWord);
// Allocate a byte, weak, mutable, no-overwrite cell. It's not clear if
// it actually needs to be mutable but if it is it needs to be no-overwrite.
Handle refH = alloc_and_save(taskData, space, F_BYTE_OBJ|F_WEAK_BIT|F_MUTABLE_BIT|F_NO_OVERWRITE);
PolyObject *p = refH->WordP();
*(polyRTSFunction*)p = 0; // Clear it
char *entryPtr = (char*)(p->AsBytePtr() + sizeof(polyRTSFunction*));
if (! isFuncPtr) *entryPtr++ = 1; // Put in a type entry
strcpy(entryPtr, entryName);
return refH;
}
// Return the string entry point.
const char *getEntryPointName(PolyObject *p, bool *isFuncPtr)
{
if (p->Length() <= sizeof(polyRTSFunction*)/sizeof(PolyWord)) return 0; // Doesn't contain an entry point
const char *entryPtr = (const char*)(p->AsBytePtr() + sizeof(polyRTSFunction*));
*isFuncPtr = *entryPtr != 1; // If the type is 1 it is a data entry point
if (*entryPtr < ' ') entryPtr++; // Skip the type byte
return entryPtr;
}
// Sets the address of the entry point in an entry point object.
bool setEntryPoint(PolyObject *p)
{
if (p->Length() == 0) return false;
*(polyRTSFunction*)p = 0; // Clear it by default
if (p->Length() == 1) return false;
const char *entryName = (const char*)(p->AsBytePtr()+sizeof(polyRTSFunction*));
if (*entryName < ' ') entryName++; // Skip the type byte
// Search the entry point table list.
for (entrypts *ept=entryPointTable; *ept != NULL; ept++)
{
entrypts entryPtTable = *ept;
if (entryPtTable != 0)
{
for (struct _entrypts *ep = entryPtTable; ep->entry != NULL; ep++)
{
if (strcmp(entryName, ep->name) == 0)
{
polyRTSFunction entry = ep->entry;
*(polyRTSFunction*)p = entry;
return true;
}
}
}
}
return false;
}
// External call
POLYUNSIGNED PolyCreateEntryPointObject(PolyObject *threadId, PolyWord arg)
{
TaskData *taskData = TaskData::FindTaskForId(threadId);
ASSERT(taskData != 0);
taskData->PreRTSCall();
Handle reset = taskData->saveVec.mark();
Handle pushedArg = taskData->saveVec.push(arg);
Handle result = 0;
try {
result = creatEntryPointObject(taskData, pushedArg, true /* Always functions */);
if (!setEntryPoint(result->WordP()))
raise_fail(taskData, "entry point not found");
} catch (...) { } // If an ML exception is raised
taskData->saveVec.reset(reset); // Ensure the save vec is reset
taskData->PostRTSCall();
if (result == 0) return TAGGED(0).AsUnsigned();
else return result->Word().AsUnsigned();
}
struct _entrypts rtsCallEPT[] =
{
{ "PolyCreateEntryPointObject", (polyRTSFunction)&PolyCreateEntryPointObject},
{ NULL, NULL} // End of list.
};
|