File: rtsentry.cpp

package info (click to toggle)
polyml 5.8.1-1~exp1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 57,736 kB
  • sloc: cpp: 44,918; ansic: 26,921; asm: 13,495; sh: 4,670; makefile: 610; exp: 525; python: 253; awk: 91
file content (191 lines) | stat: -rw-r--r-- 5,739 bytes parent folder | download
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.
};