mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-10 22:50:58 +08:00
Merge pull request #205 from ThakeeNathees/cleanups
dlfcn removed and minor code cleanups
This commit is contained in:
commit
48102123af
12
cli/all.c
12
cli/all.c
@ -35,15 +35,3 @@
|
|||||||
// Source : https://github.com/cofyc/argparse/
|
// Source : https://github.com/cofyc/argparse/
|
||||||
// About : Command-line arguments parsing library.
|
// About : Command-line arguments parsing library.
|
||||||
#include "thirdparty/argparse/argparse.c"
|
#include "thirdparty/argparse/argparse.c"
|
||||||
|
|
||||||
// Library : dlfcn-win32
|
|
||||||
// License : MIT
|
|
||||||
// Source : https://github.com/dlfcn-win32/dlfcn-win32/
|
|
||||||
// About : An implementation of dlfcn for Windows.
|
|
||||||
#ifdef _WIN32
|
|
||||||
// FIXME:
|
|
||||||
// This library redefine the malloc family macro, which cause a compile
|
|
||||||
// time warning.
|
|
||||||
//
|
|
||||||
// #include "modules/thirdparty/dlfcn-win32/dlfcn.c"
|
|
||||||
#endif
|
|
||||||
|
17
cli/modules/thirdparty/dlfcn-win32/COPYING
vendored
17
cli/modules/thirdparty/dlfcn-win32/COPYING
vendored
@ -1,17 +0,0 @@
|
|||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
785
cli/modules/thirdparty/dlfcn-win32/dlfcn.c
vendored
785
cli/modules/thirdparty/dlfcn-win32/dlfcn.c
vendored
@ -1,785 +0,0 @@
|
|||||||
/*
|
|
||||||
* dlfcn-win32
|
|
||||||
* Copyright (c) 2007 Ramiro Polla
|
|
||||||
* Copyright (c) 2015 Tiancheng "Timothy" Gu
|
|
||||||
* Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com>
|
|
||||||
* Copyright (c) 2020 Ralf Habacker <ralf.habacker@freenet.de>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
#define _CRTDBG_MAP_ALLOC
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <crtdbg.h>
|
|
||||||
#endif
|
|
||||||
#include <windows.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
/* Older versions do not have this type */
|
|
||||||
#if _WIN32_WINNT < 0x0500
|
|
||||||
typedef ULONG ULONG_PTR;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Older SDK versions do not have these macros */
|
|
||||||
#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
|
|
||||||
#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x4
|
|
||||||
#endif
|
|
||||||
#ifndef GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
|
|
||||||
#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 0x2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
/* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */
|
|
||||||
#pragma intrinsic( _ReturnAddress )
|
|
||||||
#else
|
|
||||||
/* https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html */
|
|
||||||
#ifndef _ReturnAddress
|
|
||||||
#define _ReturnAddress( ) ( __builtin_extract_return_addr( __builtin_return_address( 0 ) ) )
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DLFCN_WIN32_SHARED
|
|
||||||
#define DLFCN_WIN32_EXPORTS
|
|
||||||
#endif
|
|
||||||
#include "dlfcn.h"
|
|
||||||
|
|
||||||
#if defined( _MSC_VER ) && _MSC_VER >= 1300
|
|
||||||
/* https://docs.microsoft.com/en-us/cpp/cpp/noinline */
|
|
||||||
#define DLFCN_NOINLINE __declspec( noinline )
|
|
||||||
#elif defined( __GNUC__ ) && ( ( __GNUC__ > 3 ) || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 1 ) )
|
|
||||||
/* https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html */
|
|
||||||
#define DLFCN_NOINLINE __attribute__(( noinline ))
|
|
||||||
#else
|
|
||||||
#define DLFCN_NOINLINE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Note:
|
|
||||||
* MSDN says these functions are not thread-safe. We make no efforts to have
|
|
||||||
* any kind of thread safety.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct local_object {
|
|
||||||
HMODULE hModule;
|
|
||||||
struct local_object *previous;
|
|
||||||
struct local_object *next;
|
|
||||||
} local_object;
|
|
||||||
|
|
||||||
static local_object first_object;
|
|
||||||
|
|
||||||
/* These functions implement a double linked list for the local objects. */
|
|
||||||
static local_object *local_search( HMODULE hModule )
|
|
||||||
{
|
|
||||||
local_object *pobject;
|
|
||||||
|
|
||||||
if( hModule == NULL )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
for( pobject = &first_object; pobject; pobject = pobject->next )
|
|
||||||
if( pobject->hModule == hModule )
|
|
||||||
return pobject;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL local_add( HMODULE hModule )
|
|
||||||
{
|
|
||||||
local_object *pobject;
|
|
||||||
local_object *nobject;
|
|
||||||
|
|
||||||
if( hModule == NULL )
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
pobject = local_search( hModule );
|
|
||||||
|
|
||||||
/* Do not add object again if it's already on the list */
|
|
||||||
if( pobject != NULL )
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
for( pobject = &first_object; pobject->next; pobject = pobject->next );
|
|
||||||
|
|
||||||
nobject = (local_object *) malloc( sizeof( local_object ) );
|
|
||||||
|
|
||||||
if( !nobject )
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
pobject->next = nobject;
|
|
||||||
nobject->next = NULL;
|
|
||||||
nobject->previous = pobject;
|
|
||||||
nobject->hModule = hModule;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void local_rem( HMODULE hModule )
|
|
||||||
{
|
|
||||||
local_object *pobject;
|
|
||||||
|
|
||||||
if( hModule == NULL )
|
|
||||||
return;
|
|
||||||
|
|
||||||
pobject = local_search( hModule );
|
|
||||||
|
|
||||||
if( pobject == NULL )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if( pobject->next )
|
|
||||||
pobject->next->previous = pobject->previous;
|
|
||||||
if( pobject->previous )
|
|
||||||
pobject->previous->next = pobject->next;
|
|
||||||
|
|
||||||
free( pobject );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one
|
|
||||||
* static buffer.
|
|
||||||
* MSDN says the buffer cannot be larger than 64K bytes, so we set it to
|
|
||||||
* the limit.
|
|
||||||
*/
|
|
||||||
static char error_buffer[65535];
|
|
||||||
static BOOL error_occurred;
|
|
||||||
|
|
||||||
static void save_err_str( const char *str, DWORD dwMessageId )
|
|
||||||
{
|
|
||||||
DWORD ret;
|
|
||||||
size_t pos, len;
|
|
||||||
|
|
||||||
len = strlen( str );
|
|
||||||
if( len > sizeof( error_buffer ) - 5 )
|
|
||||||
len = sizeof( error_buffer ) - 5;
|
|
||||||
|
|
||||||
/* Format error message to:
|
|
||||||
* "<argument to function that failed>": <Windows localized error message>
|
|
||||||
*/
|
|
||||||
pos = 0;
|
|
||||||
error_buffer[pos++] = '"';
|
|
||||||
memcpy( error_buffer + pos, str, len );
|
|
||||||
pos += len;
|
|
||||||
error_buffer[pos++] = '"';
|
|
||||||
error_buffer[pos++] = ':';
|
|
||||||
error_buffer[pos++] = ' ';
|
|
||||||
|
|
||||||
ret = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwMessageId,
|
|
||||||
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
|
|
||||||
error_buffer + pos, (DWORD) ( sizeof( error_buffer ) - pos ), NULL );
|
|
||||||
pos += ret;
|
|
||||||
|
|
||||||
/* When FormatMessageA() fails it returns zero and does not touch buffer
|
|
||||||
* so add trailing null byte */
|
|
||||||
if( ret == 0 )
|
|
||||||
error_buffer[pos] = '\0';
|
|
||||||
|
|
||||||
if( pos > 1 )
|
|
||||||
{
|
|
||||||
/* POSIX says the string must not have trailing <newline> */
|
|
||||||
if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' )
|
|
||||||
error_buffer[pos-2] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
error_occurred = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void save_err_ptr_str( const void *ptr, DWORD dwMessageId )
|
|
||||||
{
|
|
||||||
char ptr_buf[2 + 2 * sizeof( ptr ) + 1];
|
|
||||||
char num;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
ptr_buf[0] = '0';
|
|
||||||
ptr_buf[1] = 'x';
|
|
||||||
|
|
||||||
for( i = 0; i < 2 * sizeof( ptr ); i++ )
|
|
||||||
{
|
|
||||||
num = (char) ( ( ( (ULONG_PTR) ptr ) >> ( 8 * sizeof( ptr ) - 4 * ( i + 1 ) ) ) & 0xF );
|
|
||||||
ptr_buf[2 + i] = num + ( ( num < 0xA ) ? '0' : ( 'A' - 0xA ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr_buf[2 + 2 * sizeof( ptr )] = 0;
|
|
||||||
|
|
||||||
save_err_str( ptr_buf, dwMessageId );
|
|
||||||
}
|
|
||||||
|
|
||||||
static HMODULE MyGetModuleHandleFromAddress( void *addr )
|
|
||||||
{
|
|
||||||
static BOOL (WINAPI *GetModuleHandleExAPtr)(DWORD, LPCSTR, HMODULE *) = NULL;
|
|
||||||
static BOOL failed = FALSE;
|
|
||||||
HMODULE kernel32;
|
|
||||||
HMODULE hModule;
|
|
||||||
MEMORY_BASIC_INFORMATION info;
|
|
||||||
SIZE_T sLen;
|
|
||||||
|
|
||||||
if( !failed && GetModuleHandleExAPtr == NULL )
|
|
||||||
{
|
|
||||||
kernel32 = GetModuleHandleA( "Kernel32.dll" );
|
|
||||||
if( kernel32 != NULL )
|
|
||||||
GetModuleHandleExAPtr = (BOOL (WINAPI *)(DWORD, LPCSTR, HMODULE *)) GetProcAddress( kernel32, "GetModuleHandleExA" );
|
|
||||||
if( GetModuleHandleExAPtr == NULL )
|
|
||||||
failed = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !failed )
|
|
||||||
{
|
|
||||||
/* If GetModuleHandleExA is available use it with GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS */
|
|
||||||
if( !GetModuleHandleExAPtr( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) addr, &hModule ) )
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* To get HMODULE from address use undocumented hack from https://stackoverflow.com/a/2396380
|
|
||||||
* The HMODULE of a DLL is the same value as the module's base address.
|
|
||||||
*/
|
|
||||||
sLen = VirtualQuery( addr, &info, sizeof( info ) );
|
|
||||||
if( sLen != sizeof( info ) )
|
|
||||||
return NULL;
|
|
||||||
hModule = (HMODULE) info.AllocationBase;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hModule;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load Psapi.dll at runtime, this avoids linking caveat */
|
|
||||||
static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded )
|
|
||||||
{
|
|
||||||
static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD) = NULL;
|
|
||||||
static BOOL failed = FALSE;
|
|
||||||
UINT uMode;
|
|
||||||
HMODULE psapi;
|
|
||||||
|
|
||||||
if( failed )
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if( EnumProcessModulesPtr == NULL )
|
|
||||||
{
|
|
||||||
/* Windows 7 and newer versions have K32EnumProcessModules in Kernel32.dll which is always pre-loaded */
|
|
||||||
psapi = GetModuleHandleA( "Kernel32.dll" );
|
|
||||||
if( psapi != NULL )
|
|
||||||
EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( psapi, "K32EnumProcessModules" );
|
|
||||||
|
|
||||||
/* Windows Vista and older version have EnumProcessModules in Psapi.dll which needs to be loaded */
|
|
||||||
if( EnumProcessModulesPtr == NULL )
|
|
||||||
{
|
|
||||||
/* Do not let Windows display the critical-error-handler message box */
|
|
||||||
uMode = SetErrorMode( SEM_FAILCRITICALERRORS );
|
|
||||||
psapi = LoadLibraryA( "Psapi.dll" );
|
|
||||||
if( psapi != NULL )
|
|
||||||
{
|
|
||||||
EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( psapi, "EnumProcessModules" );
|
|
||||||
if( EnumProcessModulesPtr == NULL )
|
|
||||||
FreeLibrary( psapi );
|
|
||||||
}
|
|
||||||
SetErrorMode( uMode );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( EnumProcessModulesPtr == NULL )
|
|
||||||
{
|
|
||||||
failed = TRUE;
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded );
|
|
||||||
}
|
|
||||||
|
|
||||||
DLFCN_EXPORT
|
|
||||||
void *dlopen( const char *file, int mode )
|
|
||||||
{
|
|
||||||
HMODULE hModule;
|
|
||||||
UINT uMode;
|
|
||||||
|
|
||||||
error_occurred = FALSE;
|
|
||||||
|
|
||||||
/* Do not let Windows display the critical-error-handler message box */
|
|
||||||
uMode = SetErrorMode( SEM_FAILCRITICALERRORS );
|
|
||||||
|
|
||||||
if( file == NULL )
|
|
||||||
{
|
|
||||||
/* POSIX says that if the value of file is NULL, a handle on a global
|
|
||||||
* symbol object must be provided. That object must be able to access
|
|
||||||
* all symbols from the original program file, and any objects loaded
|
|
||||||
* with the RTLD_GLOBAL flag.
|
|
||||||
* The return value from GetModuleHandle( ) allows us to retrieve
|
|
||||||
* symbols only from the original program file. EnumProcessModules() is
|
|
||||||
* used to access symbols from other libraries. For objects loaded
|
|
||||||
* with the RTLD_LOCAL flag, we create our own list later on. They are
|
|
||||||
* excluded from EnumProcessModules() iteration.
|
|
||||||
*/
|
|
||||||
hModule = GetModuleHandle( NULL );
|
|
||||||
|
|
||||||
if( !hModule )
|
|
||||||
save_err_str( "(null)", GetLastError( ) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HANDLE hCurrentProc;
|
|
||||||
DWORD dwProcModsBefore, dwProcModsAfter;
|
|
||||||
char lpFileName[MAX_PATH];
|
|
||||||
size_t i, len;
|
|
||||||
|
|
||||||
len = strlen( file );
|
|
||||||
|
|
||||||
if( len >= sizeof( lpFileName ) )
|
|
||||||
{
|
|
||||||
save_err_str( file, ERROR_FILENAME_EXCED_RANGE );
|
|
||||||
hModule = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* MSDN says backslashes *must* be used instead of forward slashes. */
|
|
||||||
for( i = 0; i < len; i++ )
|
|
||||||
{
|
|
||||||
if( file[i] == '/' )
|
|
||||||
lpFileName[i] = '\\';
|
|
||||||
else
|
|
||||||
lpFileName[i] = file[i];
|
|
||||||
}
|
|
||||||
lpFileName[len] = '\0';
|
|
||||||
|
|
||||||
hCurrentProc = GetCurrentProcess( );
|
|
||||||
|
|
||||||
if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsBefore ) == 0 )
|
|
||||||
dwProcModsBefore = 0;
|
|
||||||
|
|
||||||
/* POSIX says the search path is implementation-defined.
|
|
||||||
* LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely
|
|
||||||
* to UNIX's search paths (start with system folders instead of current
|
|
||||||
* folder).
|
|
||||||
*/
|
|
||||||
hModule = LoadLibraryExA( lpFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
|
|
||||||
|
|
||||||
if( !hModule )
|
|
||||||
{
|
|
||||||
save_err_str( lpFileName, GetLastError( ) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 )
|
|
||||||
dwProcModsAfter = 0;
|
|
||||||
|
|
||||||
/* If the object was loaded with RTLD_LOCAL, add it to list of local
|
|
||||||
* objects, so that its symbols cannot be retrieved even if the handle for
|
|
||||||
* the original program file is passed. POSIX says that if the same
|
|
||||||
* file is specified in multiple invocations, and any of them are
|
|
||||||
* RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the
|
|
||||||
* symbols will remain global. If number of loaded modules was not
|
|
||||||
* changed after calling LoadLibraryEx(), it means that library was
|
|
||||||
* already loaded.
|
|
||||||
*/
|
|
||||||
if( (mode & RTLD_LOCAL) && dwProcModsBefore != dwProcModsAfter )
|
|
||||||
{
|
|
||||||
if( !local_add( hModule ) )
|
|
||||||
{
|
|
||||||
save_err_str( lpFileName, ERROR_NOT_ENOUGH_MEMORY );
|
|
||||||
FreeLibrary( hModule );
|
|
||||||
hModule = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( !(mode & RTLD_LOCAL) && dwProcModsBefore == dwProcModsAfter )
|
|
||||||
{
|
|
||||||
local_rem( hModule );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return to previous state of the error-mode bit flags. */
|
|
||||||
SetErrorMode( uMode );
|
|
||||||
|
|
||||||
return (void *) hModule;
|
|
||||||
}
|
|
||||||
|
|
||||||
DLFCN_EXPORT
|
|
||||||
int dlclose( void *handle )
|
|
||||||
{
|
|
||||||
HMODULE hModule = (HMODULE) handle;
|
|
||||||
BOOL ret;
|
|
||||||
|
|
||||||
error_occurred = FALSE;
|
|
||||||
|
|
||||||
ret = FreeLibrary( hModule );
|
|
||||||
|
|
||||||
/* If the object was loaded with RTLD_LOCAL, remove it from list of local
|
|
||||||
* objects.
|
|
||||||
*/
|
|
||||||
if( ret )
|
|
||||||
local_rem( hModule );
|
|
||||||
else
|
|
||||||
save_err_ptr_str( handle, GetLastError( ) );
|
|
||||||
|
|
||||||
/* dlclose's return value in inverted in relation to FreeLibrary's. */
|
|
||||||
ret = !ret;
|
|
||||||
|
|
||||||
return (int) ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
DLFCN_NOINLINE /* Needed for _ReturnAddress() */
|
|
||||||
DLFCN_EXPORT
|
|
||||||
void *dlsym( void *handle, const char *name )
|
|
||||||
{
|
|
||||||
FARPROC symbol;
|
|
||||||
HMODULE hCaller;
|
|
||||||
HMODULE hModule;
|
|
||||||
DWORD dwMessageId;
|
|
||||||
|
|
||||||
error_occurred = FALSE;
|
|
||||||
|
|
||||||
symbol = NULL;
|
|
||||||
hCaller = NULL;
|
|
||||||
hModule = GetModuleHandle( NULL );
|
|
||||||
dwMessageId = 0;
|
|
||||||
|
|
||||||
if( handle == RTLD_DEFAULT )
|
|
||||||
{
|
|
||||||
/* The symbol lookup happens in the normal global scope; that is,
|
|
||||||
* a search for a symbol using this handle would find the same
|
|
||||||
* definition as a direct use of this symbol in the program code.
|
|
||||||
* So use same lookup procedure as when filename is NULL.
|
|
||||||
*/
|
|
||||||
handle = hModule;
|
|
||||||
}
|
|
||||||
else if( handle == RTLD_NEXT )
|
|
||||||
{
|
|
||||||
/* Specifies the next object after this one that defines name.
|
|
||||||
* This one refers to the object containing the invocation of dlsym().
|
|
||||||
* The next object is the one found upon the application of a load
|
|
||||||
* order symbol resolution algorithm. To get caller function of dlsym()
|
|
||||||
* use _ReturnAddress() intrinsic. To get HMODULE of caller function
|
|
||||||
* use MyGetModuleHandleFromAddress() which calls either standard
|
|
||||||
* GetModuleHandleExA() function or hack via VirtualQuery().
|
|
||||||
*/
|
|
||||||
hCaller = MyGetModuleHandleFromAddress( _ReturnAddress( ) );
|
|
||||||
|
|
||||||
if( hCaller == NULL )
|
|
||||||
{
|
|
||||||
dwMessageId = ERROR_INVALID_PARAMETER;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( handle != RTLD_NEXT )
|
|
||||||
{
|
|
||||||
symbol = GetProcAddress( (HMODULE) handle, name );
|
|
||||||
|
|
||||||
if( symbol != NULL )
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the handle for the original program file is passed, also search
|
|
||||||
* in all globally loaded objects.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if( hModule == handle || handle == RTLD_NEXT )
|
|
||||||
{
|
|
||||||
HANDLE hCurrentProc;
|
|
||||||
HMODULE *modules;
|
|
||||||
DWORD cbNeeded;
|
|
||||||
DWORD dwSize;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
hCurrentProc = GetCurrentProcess( );
|
|
||||||
|
|
||||||
/* GetModuleHandle( NULL ) only returns the current program file. So
|
|
||||||
* if we want to get ALL loaded module including those in linked DLLs,
|
|
||||||
* we have to use EnumProcessModules( ).
|
|
||||||
*/
|
|
||||||
if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwSize ) != 0 )
|
|
||||||
{
|
|
||||||
modules = malloc( dwSize );
|
|
||||||
if( modules )
|
|
||||||
{
|
|
||||||
if( MyEnumProcessModules( hCurrentProc, modules, dwSize, &cbNeeded ) != 0 && dwSize == cbNeeded )
|
|
||||||
{
|
|
||||||
for( i = 0; i < dwSize / sizeof( HMODULE ); i++ )
|
|
||||||
{
|
|
||||||
if( handle == RTLD_NEXT && hCaller )
|
|
||||||
{
|
|
||||||
/* Next modules can be used for RTLD_NEXT */
|
|
||||||
if( hCaller == modules[i] )
|
|
||||||
hCaller = NULL;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if( local_search( modules[i] ) )
|
|
||||||
continue;
|
|
||||||
symbol = GetProcAddress( modules[i], name );
|
|
||||||
if( symbol != NULL )
|
|
||||||
{
|
|
||||||
free( modules );
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
free( modules );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dwMessageId = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
end:
|
|
||||||
if( symbol == NULL )
|
|
||||||
{
|
|
||||||
if( !dwMessageId )
|
|
||||||
dwMessageId = ERROR_PROC_NOT_FOUND;
|
|
||||||
save_err_str( name, dwMessageId );
|
|
||||||
}
|
|
||||||
|
|
||||||
return *(void **) (&symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
DLFCN_EXPORT
|
|
||||||
char *dlerror( void )
|
|
||||||
{
|
|
||||||
/* If this is the second consecutive call to dlerror, return NULL */
|
|
||||||
if( !error_occurred )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* POSIX says that invoking dlerror( ) a second time, immediately following
|
|
||||||
* a prior invocation, shall result in NULL being returned.
|
|
||||||
*/
|
|
||||||
error_occurred = FALSE;
|
|
||||||
|
|
||||||
return error_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* See https://docs.microsoft.com/en-us/archive/msdn-magazine/2002/march/inside-windows-an-in-depth-look-into-the-win32-portable-executable-file-format-part-2
|
|
||||||
* for details */
|
|
||||||
|
|
||||||
/* Get specific image section */
|
|
||||||
static BOOL get_image_section( HMODULE module, int index, void **ptr, DWORD *size )
|
|
||||||
{
|
|
||||||
IMAGE_DOS_HEADER *dosHeader;
|
|
||||||
IMAGE_OPTIONAL_HEADER *optionalHeader;
|
|
||||||
|
|
||||||
dosHeader = (IMAGE_DOS_HEADER *) module;
|
|
||||||
|
|
||||||
if( dosHeader->e_magic != 0x5A4D )
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
optionalHeader = (IMAGE_OPTIONAL_HEADER *) ( (BYTE *) module + dosHeader->e_lfanew + 24 );
|
|
||||||
|
|
||||||
if( optionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC )
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if( index < 0 || index > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR )
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if( optionalHeader->DataDirectory[index].Size == 0 || optionalHeader->DataDirectory[index].VirtualAddress == 0 )
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if( size != NULL )
|
|
||||||
*size = optionalHeader->DataDirectory[index].Size;
|
|
||||||
|
|
||||||
*ptr = (void *)( (BYTE *) module + optionalHeader->DataDirectory[index].VirtualAddress );
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return symbol name for a given address from export table */
|
|
||||||
static const char *get_export_symbol_name( HMODULE module, IMAGE_EXPORT_DIRECTORY *ied, void *addr, void **func_address )
|
|
||||||
{
|
|
||||||
DWORD i;
|
|
||||||
void *candidateAddr = NULL;
|
|
||||||
int candidateIndex = -1;
|
|
||||||
BYTE *base = (BYTE *) module;
|
|
||||||
DWORD *functionAddressesOffsets = (DWORD *) (base + ied->AddressOfFunctions);
|
|
||||||
DWORD *functionNamesOffsets = (DWORD *) (base + ied->AddressOfNames);
|
|
||||||
USHORT *functionNameOrdinalsIndexes = (USHORT *) (base + ied->AddressOfNameOrdinals);
|
|
||||||
|
|
||||||
for( i = 0; i < ied->NumberOfFunctions; i++ )
|
|
||||||
{
|
|
||||||
if( (void *) ( base + functionAddressesOffsets[i] ) > addr || candidateAddr >= (void *) ( base + functionAddressesOffsets[i] ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
candidateAddr = (void *) ( base + functionAddressesOffsets[i] );
|
|
||||||
candidateIndex = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( candidateIndex == -1 )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
*func_address = candidateAddr;
|
|
||||||
|
|
||||||
for( i = 0; i < ied->NumberOfNames; i++ )
|
|
||||||
{
|
|
||||||
if( functionNameOrdinalsIndexes[i] == candidateIndex )
|
|
||||||
return (const char *) ( base + functionNamesOffsets[i] );
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL is_valid_address( void *addr )
|
|
||||||
{
|
|
||||||
MEMORY_BASIC_INFORMATION info;
|
|
||||||
SIZE_T result;
|
|
||||||
|
|
||||||
if( addr == NULL )
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
/* check valid pointer */
|
|
||||||
result = VirtualQuery( addr, &info, sizeof( info ) );
|
|
||||||
|
|
||||||
if( result == 0 || info.AllocationBase == NULL || info.AllocationProtect == 0 || info.AllocationProtect == PAGE_NOACCESS )
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return state if address points to an import thunk
|
|
||||||
*
|
|
||||||
* An import thunk is setup with a 'jmp' instruction followed by an
|
|
||||||
* absolute address (32bit) or relative offset (64bit) pointing into
|
|
||||||
* the import address table (iat), which is partially maintained by
|
|
||||||
* the runtime linker.
|
|
||||||
*/
|
|
||||||
static BOOL is_import_thunk( void *addr )
|
|
||||||
{
|
|
||||||
return *(short *) addr == 0x25ff ? TRUE : FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return adress from the import address table (iat),
|
|
||||||
* if the original address points to a thunk table entry.
|
|
||||||
*/
|
|
||||||
static void *get_address_from_import_address_table( void *iat, DWORD iat_size, void *addr )
|
|
||||||
{
|
|
||||||
BYTE *thkp = (BYTE *) addr;
|
|
||||||
/* Get offset from thunk table (after instruction 0xff 0x25)
|
|
||||||
* 4018c8 <_VirtualQuery>: ff 25 4a 8a 00 00
|
|
||||||
*/
|
|
||||||
ULONG offset = *(ULONG *)( thkp + 2 );
|
|
||||||
#ifdef _WIN64
|
|
||||||
/* On 64 bit the offset is relative
|
|
||||||
* 4018c8: ff 25 4a 8a 00 00 jmpq *0x8a4a(%rip) # 40a318 <__imp_VirtualQuery>
|
|
||||||
* And can be also negative (MSVC in WDK)
|
|
||||||
* 100002f20: ff 25 3a e1 ff ff jmpq *-0x1ec6(%rip) # 0x100001060
|
|
||||||
* So cast to signed LONG type
|
|
||||||
*/
|
|
||||||
BYTE *ptr = (BYTE *)( thkp + 6 + (LONG) offset );
|
|
||||||
#else
|
|
||||||
/* On 32 bit the offset is absolute
|
|
||||||
* 4019b4: ff 25 90 71 40 00 jmp *0x40719
|
|
||||||
*/
|
|
||||||
BYTE *ptr = (BYTE *) offset;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( !is_valid_address( ptr ) || ptr < (BYTE *) iat || ptr > (BYTE *) iat + iat_size )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return *(void **) ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Holds module filename */
|
|
||||||
static char module_filename[2*MAX_PATH];
|
|
||||||
|
|
||||||
static BOOL fill_info( void *addr, Dl_info *info )
|
|
||||||
{
|
|
||||||
HMODULE hModule;
|
|
||||||
DWORD dwSize;
|
|
||||||
IMAGE_EXPORT_DIRECTORY *ied;
|
|
||||||
void *funcAddress = NULL;
|
|
||||||
|
|
||||||
/* Get module of the specified address */
|
|
||||||
hModule = MyGetModuleHandleFromAddress( addr );
|
|
||||||
|
|
||||||
if( hModule == NULL )
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
dwSize = GetModuleFileNameA( hModule, module_filename, sizeof( module_filename ) );
|
|
||||||
|
|
||||||
if( dwSize == 0 || dwSize == sizeof( module_filename ) )
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
info->dli_fname = module_filename;
|
|
||||||
info->dli_fbase = (void *) hModule;
|
|
||||||
|
|
||||||
/* Find function name and function address in module's export table */
|
|
||||||
if( get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_EXPORT, (void **) &ied, NULL ) )
|
|
||||||
info->dli_sname = get_export_symbol_name( hModule, ied, addr, &funcAddress );
|
|
||||||
else
|
|
||||||
info->dli_sname = NULL;
|
|
||||||
|
|
||||||
info->dli_saddr = info->dli_sname == NULL ? NULL : funcAddress != NULL ? funcAddress : addr;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
DLFCN_EXPORT
|
|
||||||
int dladdr( void *addr, Dl_info *info )
|
|
||||||
{
|
|
||||||
if( info == NULL )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if( !is_valid_address( addr ) )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if( is_import_thunk( addr ) )
|
|
||||||
{
|
|
||||||
void *iat;
|
|
||||||
DWORD iatSize;
|
|
||||||
HMODULE hModule;
|
|
||||||
|
|
||||||
/* Get module of the import thunk address */
|
|
||||||
hModule = MyGetModuleHandleFromAddress( addr );
|
|
||||||
|
|
||||||
if( hModule == NULL )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IAT, &iat, &iatSize ) )
|
|
||||||
{
|
|
||||||
/* Fallback for cases where the iat is not defined,
|
|
||||||
* for example i586-mingw32msvc-gcc */
|
|
||||||
IMAGE_IMPORT_DESCRIPTOR *iid;
|
|
||||||
DWORD iidSize;
|
|
||||||
|
|
||||||
if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IMPORT, (void **) &iid, &iidSize ) )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if( iid == NULL || iid->Characteristics == 0 || iid->FirstThunk == 0 )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
iat = (void *)( (BYTE *) hModule + iid->FirstThunk );
|
|
||||||
/* We assume that in this case iid and iat's are in linear order */
|
|
||||||
iatSize = iidSize - (DWORD) ( (BYTE *) iat - (BYTE *) iid );
|
|
||||||
}
|
|
||||||
|
|
||||||
addr = get_address_from_import_address_table( iat, iatSize, addr );
|
|
||||||
|
|
||||||
if( !is_valid_address( addr ) )
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !fill_info( addr, info ) )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DLFCN_WIN32_SHARED
|
|
||||||
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
|
|
||||||
{
|
|
||||||
(void) hinstDLL;
|
|
||||||
(void) fdwReason;
|
|
||||||
(void) lpvReserved;
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
#endif
|
|
94
cli/modules/thirdparty/dlfcn-win32/dlfcn.h
vendored
94
cli/modules/thirdparty/dlfcn-win32/dlfcn.h
vendored
@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* dlfcn-win32
|
|
||||||
* Copyright (c) 2007 Ramiro Polla
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DLFCN_H
|
|
||||||
#define DLFCN_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(DLFCN_WIN32_SHARED)
|
|
||||||
#if defined(DLFCN_WIN32_EXPORTS)
|
|
||||||
# define DLFCN_EXPORT __declspec(dllexport)
|
|
||||||
#else
|
|
||||||
# define DLFCN_EXPORT __declspec(dllimport)
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
# define DLFCN_EXPORT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Relocations are performed when the object is loaded. */
|
|
||||||
#define RTLD_NOW 0
|
|
||||||
|
|
||||||
/* Relocations are performed at an implementation-defined time.
|
|
||||||
* Windows API does not support lazy symbol resolving (when first reference
|
|
||||||
* to a given symbol occurs). So RTLD_LAZY implementation is same as RTLD_NOW.
|
|
||||||
*/
|
|
||||||
#define RTLD_LAZY RTLD_NOW
|
|
||||||
|
|
||||||
/* All symbols are available for relocation processing of other modules. */
|
|
||||||
#define RTLD_GLOBAL (1 << 1)
|
|
||||||
|
|
||||||
/* All symbols are not made available for relocation processing by other modules. */
|
|
||||||
#define RTLD_LOCAL (1 << 2)
|
|
||||||
|
|
||||||
/* These two were added in The Open Group Base Specifications Issue 6.
|
|
||||||
* Note: All other RTLD_* flags in any dlfcn.h are not standard compliant.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* The symbol lookup happens in the normal global scope. */
|
|
||||||
#define RTLD_DEFAULT ((void *)0)
|
|
||||||
|
|
||||||
/* Specifies the next object after this one that defines name. */
|
|
||||||
#define RTLD_NEXT ((void *)-1)
|
|
||||||
|
|
||||||
/* Structure filled in by dladdr() */
|
|
||||||
typedef struct dl_info
|
|
||||||
{
|
|
||||||
const char *dli_fname; /* Filename of defining object (thread unsafe and reused on every call to dladdr) */
|
|
||||||
void *dli_fbase; /* Load address of that object */
|
|
||||||
const char *dli_sname; /* Name of nearest lower symbol */
|
|
||||||
void *dli_saddr; /* Exact value of nearest symbol */
|
|
||||||
} Dl_info;
|
|
||||||
|
|
||||||
/* Open a symbol table handle. */
|
|
||||||
DLFCN_EXPORT void *dlopen(const char *file, int mode);
|
|
||||||
|
|
||||||
/* Close a symbol table handle. */
|
|
||||||
DLFCN_EXPORT int dlclose(void *handle);
|
|
||||||
|
|
||||||
/* Get the address of a symbol from a symbol table handle. */
|
|
||||||
DLFCN_EXPORT void *dlsym(void *handle, const char *name);
|
|
||||||
|
|
||||||
/* Get diagnostic information. */
|
|
||||||
DLFCN_EXPORT char *dlerror(void);
|
|
||||||
|
|
||||||
/* Translate address to symbolic information (no POSIX standard) */
|
|
||||||
DLFCN_EXPORT int dladdr(void *addr, Dl_info *info);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* DLFCN_H */
|
|
@ -12,7 +12,8 @@ from os.path import (join, exists, abspath,
|
|||||||
THIS_PATH = abspath(dirname(__file__))
|
THIS_PATH = abspath(dirname(__file__))
|
||||||
|
|
||||||
POCKET_HEADER = join(THIS_PATH, "../src/include/pocketlang.h")
|
POCKET_HEADER = join(THIS_PATH, "../src/include/pocketlang.h")
|
||||||
TARGET = join(THIS_PATH, "./modules/pknative.gen.c")
|
TARGET_NATIVE = join(THIS_PATH, "./modules/pknative.gen.c")
|
||||||
|
TARGET_DL = join(THIS_PATH, "./modules/std_dl_api.gen.h")
|
||||||
|
|
||||||
PK_API = "pk_api"
|
PK_API = "pk_api"
|
||||||
PK_API_TYPE = "PkNativeApi"
|
PK_API_TYPE = "PkNativeApi"
|
||||||
@ -109,15 +110,37 @@ def init_api(api_functions):
|
|||||||
assign += f"\n {PK_API}.{fn}_ptr = api->{fn}_ptr;"
|
assign += f"\n {PK_API}.{fn}_ptr = api->{fn}_ptr;"
|
||||||
return API_DEF % assign + '\n'
|
return API_DEF % assign + '\n'
|
||||||
|
|
||||||
|
def make_api(api_functions):
|
||||||
|
source = "#if defined(NATIVE_API_IMPLEMENT)\n\n"
|
||||||
|
source += f"{PK_API_TYPE} dlMakeApi() {{\n\n"
|
||||||
|
source += f" {PK_API_TYPE} api;\n\n"
|
||||||
|
for fn, params, ret in api_functions:
|
||||||
|
source += f" api.{fn}_ptr = {fn};\n"
|
||||||
|
source += "\n"
|
||||||
|
source += " return api;\n"
|
||||||
|
source += "}\n\n"
|
||||||
|
source += "#endif // NATIVE_API_IMPLEMENT\n\n"
|
||||||
|
return source
|
||||||
|
|
||||||
def generate():
|
def generate():
|
||||||
api_functions = get_api_functions()
|
api_functions = get_api_functions()
|
||||||
with open(TARGET, 'w') as fp:
|
|
||||||
|
## Generate pocket native api.
|
||||||
|
with open(TARGET_NATIVE, 'w') as fp:
|
||||||
fp.write(SOURCE_GEN)
|
fp.write(SOURCE_GEN)
|
||||||
fp.write(fn_typedefs(api_functions))
|
fp.write(fn_typedefs(api_functions))
|
||||||
fp.write(api_typedef(api_functions))
|
fp.write(api_typedef(api_functions))
|
||||||
fp.write(init_api(api_functions))
|
fp.write(init_api(api_functions))
|
||||||
fp.write(define_functions(api_functions))
|
fp.write(define_functions(api_functions))
|
||||||
|
|
||||||
|
## Generate dl module api definition.
|
||||||
|
with open(TARGET_DL, 'w') as fp:
|
||||||
|
fp.write(SOURCE_GEN)
|
||||||
|
fp.write(fn_typedefs(api_functions))
|
||||||
|
fp.write(api_typedef(api_functions))
|
||||||
|
fp.write(make_api(api_functions))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
generate()
|
generate()
|
||||||
print("Generated:", relpath(TARGET, os.getcwd()))
|
print("Generated:", relpath(TARGET_NATIVE, os.getcwd()))
|
||||||
|
print("Generated:", relpath(TARGET_DL, os.getcwd()))
|
||||||
|
@ -133,7 +133,7 @@ int repl(PKVM* vm, const PkCompileOptions* options) {
|
|||||||
if (result != PK_RESULT_SUCCESS) continue;
|
if (result != PK_RESULT_SUCCESS) continue;
|
||||||
|
|
||||||
// Compiled source would be the "main" function of the module. Run it.
|
// Compiled source would be the "main" function of the module. Run it.
|
||||||
PkHandle* _main = pkGetMainFunction(vm, module);
|
PkHandle* _main = pkModuleGetMainFunction(vm, module);
|
||||||
PkHandle* fiber = pkNewFiber(vm, _main);
|
PkHandle* fiber = pkNewFiber(vm, _main);
|
||||||
ASSERT((_main != NULL) && (fiber != NULL), OOPS);
|
ASSERT((_main != NULL) && (fiber != NULL), OOPS);
|
||||||
|
|
||||||
|
@ -74,9 +74,11 @@ typedef struct PkHandle PkHandle;
|
|||||||
// alive use `pkNewHandle()`.
|
// alive use `pkNewHandle()`.
|
||||||
typedef void* PkVar;
|
typedef void* PkVar;
|
||||||
|
|
||||||
// Type enum of the pocketlang variables, this can be used to get the type
|
// Type enum of the pocketlang's first class types. Note that Object isn't
|
||||||
// from a PkVar in the method pkGetVarType().
|
// instanciable (as of now) but they're considered first calss.
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
PK_OBJECT = 0,
|
||||||
|
|
||||||
PK_NULL,
|
PK_NULL,
|
||||||
PK_BOOL,
|
PK_BOOL,
|
||||||
PK_NUMBER,
|
PK_NUMBER,
|
||||||
@ -85,10 +87,10 @@ typedef enum {
|
|||||||
PK_MAP,
|
PK_MAP,
|
||||||
PK_RANGE,
|
PK_RANGE,
|
||||||
PK_MODULE,
|
PK_MODULE,
|
||||||
PK_FUNCTION,
|
PK_CLOSURE,
|
||||||
PK_FIBER,
|
PK_FIBER,
|
||||||
PK_CLASS,
|
PK_CLASS,
|
||||||
PK_INST,
|
PK_INSTANCE,
|
||||||
} PkVarType;
|
} PkVarType;
|
||||||
|
|
||||||
typedef struct PkStringPtr PkStringPtr;
|
typedef struct PkStringPtr PkStringPtr;
|
||||||
@ -257,7 +259,7 @@ PK_PUBLIC void pkModuleAddFunction(PKVM* vm, PkHandle* module,
|
|||||||
|
|
||||||
// Returns the main function of the [module]. When a module is compiled all of
|
// Returns the main function of the [module]. When a module is compiled all of
|
||||||
// it's statements are wrapped around an implicit main function.
|
// it's statements are wrapped around an implicit main function.
|
||||||
PK_PUBLIC PkHandle* pkGetMainFunction(PKVM* vm, PkHandle* module);
|
PK_PUBLIC PkHandle* pkModuleGetMainFunction(PKVM* vm, PkHandle* module);
|
||||||
|
|
||||||
// Compile the [module] with the provided [source]. Set the compiler options
|
// Compile the [module] with the provided [source]. Set the compiler options
|
||||||
// with the the [options] argument or set to NULL for default options.
|
// with the the [options] argument or set to NULL for default options.
|
||||||
|
@ -237,7 +237,6 @@ typedef struct {
|
|||||||
} GrammarRule;
|
} GrammarRule;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DEPTH_MODULE = -2, //< Only used for module body function's depth.
|
|
||||||
DEPTH_GLOBAL = -1, //< Global variables.
|
DEPTH_GLOBAL = -1, //< Global variables.
|
||||||
DEPTH_LOCAL, //< Local scope. Increase with inner scope.
|
DEPTH_LOCAL, //< Local scope. Increase with inner scope.
|
||||||
} Depth;
|
} Depth;
|
||||||
@ -1249,9 +1248,9 @@ static bool matchAssignment(Compiler* compiler) {
|
|||||||
static int findBuiltinFunction(const PKVM* vm,
|
static int findBuiltinFunction(const PKVM* vm,
|
||||||
const char* name, uint32_t length) {
|
const char* name, uint32_t length) {
|
||||||
for (int i = 0; i < vm->builtins_count; i++) {
|
for (int i = 0; i < vm->builtins_count; i++) {
|
||||||
uint32_t bfn_length = (uint32_t)strlen(vm->builtins[i]->fn->name);
|
uint32_t bfn_length = (uint32_t)strlen(vm->builtins_funcs[i]->fn->name);
|
||||||
if (bfn_length != length) continue;
|
if (bfn_length != length) continue;
|
||||||
if (strncmp(name, vm->builtins[i]->fn->name, length) == 0) {
|
if (strncmp(name, vm->builtins_funcs[i]->fn->name, length) == 0) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3142,10 +3141,6 @@ PkResult compile(PKVM* vm, Module* module, const char* source,
|
|||||||
Func curr_fn;
|
Func curr_fn;
|
||||||
compilerPushFunc(compiler, &curr_fn, module->body->fn);
|
compilerPushFunc(compiler, &curr_fn, module->body->fn);
|
||||||
|
|
||||||
// At the begining the compiler's scope will be DEPTH_GLOBAL and that'll be
|
|
||||||
// set to to the current functions depth. Override for the body function.
|
|
||||||
curr_fn.depth = DEPTH_MODULE;
|
|
||||||
|
|
||||||
// Lex initial tokens. current <-- next.
|
// Lex initial tokens. current <-- next.
|
||||||
lexToken(&(compiler->parser));
|
lexToken(&(compiler->parser));
|
||||||
lexToken(&(compiler->parser));
|
lexToken(&(compiler->parser));
|
||||||
|
@ -46,35 +46,41 @@ static void moduleAddFunctionInternal(PKVM* vm, Module* module,
|
|||||||
/* CORE PUBLIC API */
|
/* CORE PUBLIC API */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#define CHECK_NULL(name) \
|
||||||
|
ASSERT(name != NULL, "Argument " #name " was NULL.");
|
||||||
|
|
||||||
|
#define CHECK_TYPE(handle, type) \
|
||||||
|
do { \
|
||||||
|
CHECK_NULL(handle); \
|
||||||
|
ASSERT(IS_OBJ_TYPE(handle->value, type), \
|
||||||
|
"Given handle is not of type " #type "."); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
PkHandle* pkNewModule(PKVM* vm, const char* name) {
|
PkHandle* pkNewModule(PKVM* vm, const char* name) {
|
||||||
|
CHECK_NULL(name);
|
||||||
Module* module = newModuleInternal(vm, name);
|
Module* module = newModuleInternal(vm, name);
|
||||||
return vmNewHandle(vm, VAR_OBJ(module));
|
return vmNewHandle(vm, VAR_OBJ(module));
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkRegisterModule(PKVM* vm, PkHandle* module) {
|
void pkRegisterModule(PKVM* vm, PkHandle* module) {
|
||||||
ASSERT(module != NULL, "Argument module was NULL.");
|
CHECK_TYPE(module, OBJ_MODULE);
|
||||||
ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
|
|
||||||
"Given handle is not a module.");
|
|
||||||
Module* module_ = (Module*)AS_OBJ(module->value);
|
Module* module_ = (Module*)AS_OBJ(module->value);
|
||||||
vmRegisterModule(vm, module_, module_->name);
|
vmRegisterModule(vm, module_, module_->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkModuleAddGlobal(PKVM* vm, PkHandle* module,
|
void pkModuleAddGlobal(PKVM* vm, PkHandle* module,
|
||||||
const char* name, PkHandle* value) {
|
const char* name, PkHandle* value) {
|
||||||
ASSERT(module != NULL, "Argument module was NULL.");
|
CHECK_TYPE(module, OBJ_MODULE);
|
||||||
ASSERT(value != NULL, "Argument value was NULL.");
|
CHECK_NULL(value);
|
||||||
ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
|
|
||||||
"Given handle is not a module.");
|
|
||||||
|
|
||||||
moduleAddGlobal(vm, (Module*)AS_OBJ(module->value),
|
moduleAddGlobal(vm, (Module*)AS_OBJ(module->value),
|
||||||
name, (uint32_t)strlen(name), value->value);
|
name, (uint32_t)strlen(name), value->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
PkHandle* pkModuleGetGlobal(PKVM* vm, PkHandle* module, const char* name) {
|
PkHandle* pkModuleGetGlobal(PKVM* vm, PkHandle* module, const char* name) {
|
||||||
ASSERT(module != NULL, "Argument module was NULL.");
|
CHECK_TYPE(module, OBJ_MODULE);
|
||||||
ASSERT(name != NULL, "Argument name was NULL.");
|
CHECK_NULL(name);
|
||||||
ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
|
|
||||||
"Given handle is not a module.");
|
|
||||||
|
|
||||||
Module* module_ = (Module*)AS_OBJ(module->value);
|
Module* module_ = (Module*)AS_OBJ(module->value);
|
||||||
int index = moduleGetGlobalIndex(module_, name, (uint32_t)strlen(name));
|
int index = moduleGetGlobalIndex(module_, name, (uint32_t)strlen(name));
|
||||||
@ -84,18 +90,17 @@ PkHandle* pkModuleGetGlobal(PKVM* vm, PkHandle* module, const char* name) {
|
|||||||
|
|
||||||
void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name,
|
void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name,
|
||||||
pkNativeFn fptr, int arity) {
|
pkNativeFn fptr, int arity) {
|
||||||
ASSERT(module != NULL, "Argument module was NULL.");
|
CHECK_TYPE(module, OBJ_MODULE);
|
||||||
ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
|
CHECK_NULL(fptr);
|
||||||
"Given handle is not a module.");
|
|
||||||
moduleAddFunctionInternal(vm, (Module*)AS_OBJ(module->value),
|
moduleAddFunctionInternal(vm, (Module*)AS_OBJ(module->value),
|
||||||
name, fptr, arity,
|
name, fptr, arity,
|
||||||
NULL /*TODO: Public API for function docstring.*/);
|
NULL /*TODO: Public API for function docstring.*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
PkHandle* pkGetMainFunction(PKVM* vm, PkHandle* module) {
|
PkHandle* pkModuleGetMainFunction(PKVM* vm, PkHandle* module) {
|
||||||
ASSERT(module != NULL, "Argument module was NULL.");
|
CHECK_TYPE(module, OBJ_MODULE);
|
||||||
ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
|
|
||||||
"Given handle is not a module.");
|
|
||||||
Module* _module = (Module*)AS_OBJ(module->value);
|
Module* _module = (Module*)AS_OBJ(module->value);
|
||||||
|
|
||||||
int main_index = moduleGetGlobalIndex(_module, IMPLICIT_MAIN_NAME,
|
int main_index = moduleGetGlobalIndex(_module, IMPLICIT_MAIN_NAME,
|
||||||
@ -321,6 +326,9 @@ bool pkFiberIsDone(const PkHandle* fiber) {
|
|||||||
return _fiber->state == FIBER_DONE;
|
return _fiber->state == FIBER_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef CHECK_NULL
|
||||||
|
#undef CHECK_TYPE
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* VALIDATORS */
|
/* VALIDATORS */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -766,8 +774,8 @@ static void initializeBuiltinFN(PKVM* vm, Closure** bfn, const char* name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void initializeBuiltinFunctions(PKVM* vm) {
|
static void initializeBuiltinFunctions(PKVM* vm) {
|
||||||
#define INITIALIZE_BUILTIN_FN(name, fn, argc) \
|
#define INITIALIZE_BUILTIN_FN(name, fn, argc) \
|
||||||
initializeBuiltinFN(vm, &vm->builtins[vm->builtins_count++], name, \
|
initializeBuiltinFN(vm, &vm->builtins_funcs[vm->builtins_count++], name, \
|
||||||
(int)strlen(name), argc, fn, DOCSTRING(fn));
|
(int)strlen(name), argc, fn, DOCSTRING(fn));
|
||||||
// General functions.
|
// General functions.
|
||||||
INITIALIZE_BUILTIN_FN("type_name", coreTypeName, 1);
|
INITIALIZE_BUILTIN_FN("type_name", coreTypeName, 1);
|
||||||
@ -1467,8 +1475,8 @@ bool varContains(PKVM* vm, Var elem, Var container) {
|
|||||||
|
|
||||||
Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
||||||
|
|
||||||
#define ERR_NO_ATTRIB(vm, on, attrib) \
|
#define ERR_NO_ATTRIB(vm, on, attrib) \
|
||||||
VM_SET_ERROR(vm, stringFormat(vm, "'$' object has no attribute named '$'", \
|
VM_SET_ERROR(vm, stringFormat(vm, "'$' object has no attribute named '$'.", \
|
||||||
varTypeName(on), attrib->data))
|
varTypeName(on), attrib->data))
|
||||||
|
|
||||||
if (!IS_OBJ(on)) {
|
if (!IS_OBJ(on)) {
|
||||||
|
@ -227,7 +227,7 @@ void dumpFunctionCode(PKVM* vm, Function* func) {
|
|||||||
{
|
{
|
||||||
int index = READ_BYTE();
|
int index = READ_BYTE();
|
||||||
ASSERT_INDEX(index, vm->builtins_count);
|
ASSERT_INDEX(index, vm->builtins_count);
|
||||||
const char* name = vm->builtins[index]->fn->name;
|
const char* name = vm->builtins_funcs[index]->fn->name;
|
||||||
// Prints: %5d [Fn:%s]\n
|
// Prints: %5d [Fn:%s]\n
|
||||||
PRINT_INT(index);
|
PRINT_INT(index);
|
||||||
PRINT(" [Fn:");
|
PRINT(" [Fn:");
|
||||||
|
@ -18,29 +18,18 @@
|
|||||||
|
|
||||||
PkVarType pkGetValueType(const PkVar value) {
|
PkVarType pkGetValueType(const PkVar value) {
|
||||||
__ASSERT(value != NULL, "Given value was NULL.");
|
__ASSERT(value != NULL, "Given value was NULL.");
|
||||||
|
const Var value_ = *(const Var*)(value);
|
||||||
|
|
||||||
if (IS_NULL(*(const Var*)(value))) return PK_NULL;
|
if (IS_NULL(value_)) return PK_NULL;
|
||||||
if (IS_BOOL(*(const Var*)(value))) return PK_BOOL;
|
if (IS_BOOL(value_)) return PK_BOOL;
|
||||||
if (IS_NUM(*(const Var*)(value))) return PK_NUMBER;
|
if (IS_NUM(value_)) return PK_NUMBER;
|
||||||
|
|
||||||
__ASSERT(IS_OBJ(*(const Var*)(value)),
|
ASSERT(IS_OBJ(*(const Var*)(value)),
|
||||||
"Invalid var pointer. Might be a dangling pointer");
|
"Invalid var pointer (Might be a dangling pointer).");
|
||||||
|
|
||||||
const Object* obj = AS_OBJ(*(const Var*)(value));
|
const Object* obj = AS_OBJ(value_);
|
||||||
switch (obj->type) {
|
return getObjPkVarType(obj->type);
|
||||||
case OBJ_STRING: return PK_STRING;
|
|
||||||
case OBJ_LIST: return PK_LIST;
|
|
||||||
case OBJ_MAP: return PK_MAP;
|
|
||||||
case OBJ_RANGE: return PK_RANGE;
|
|
||||||
case OBJ_MODULE: return PK_MODULE;
|
|
||||||
case OBJ_FUNC: return PK_FUNCTION;
|
|
||||||
case OBJ_FIBER: return PK_FIBER;
|
|
||||||
case OBJ_CLASS: return PK_CLASS;
|
|
||||||
case OBJ_INST: return PK_INST;
|
|
||||||
}
|
|
||||||
|
|
||||||
UNREACHABLE();
|
|
||||||
return PK_NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PkHandle* pkNewString(PKVM* vm, const char* value) {
|
PkHandle* pkNewString(PKVM* vm, const char* value) {
|
||||||
@ -525,6 +514,7 @@ Class* newClass(PKVM* vm, Module* module, const char* name, uint32_t length,
|
|||||||
|
|
||||||
pkUintBufferInit(&cls->field_names);
|
pkUintBufferInit(&cls->field_names);
|
||||||
cls->owner = module;
|
cls->owner = module;
|
||||||
|
cls->docstring = NULL;
|
||||||
cls->name = moduleAddString(module, vm, name, length, NULL);
|
cls->name = moduleAddString(module, vm, name, length, NULL);
|
||||||
|
|
||||||
// Since characters '@' and '$' are special in stringFormat, and they
|
// Since characters '@' and '$' are special in stringFormat, and they
|
||||||
@ -1333,24 +1323,56 @@ bool instSetAttrib(PKVM* vm, Instance* inst, String* attrib, Var value) {
|
|||||||
/* UTILITY FUNCTIONS */
|
/* UTILITY FUNCTIONS */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
PkVarType getObjPkVarType(ObjectType type) {
|
||||||
|
switch (type) {
|
||||||
|
case OBJ_STRING: return PK_STRING;
|
||||||
|
case OBJ_LIST: return PK_LIST;
|
||||||
|
case OBJ_MAP: return PK_MAP;
|
||||||
|
case OBJ_RANGE: return PK_RANGE;
|
||||||
|
case OBJ_MODULE: return PK_MODULE;
|
||||||
|
case OBJ_FUNC: UNREACHABLE();
|
||||||
|
case OBJ_CLOSURE: return PK_CLOSURE;
|
||||||
|
case OBJ_UPVALUE: UNREACHABLE();
|
||||||
|
case OBJ_FIBER: return PK_FIBER;
|
||||||
|
case OBJ_CLASS: return PK_CLASS;
|
||||||
|
case OBJ_INST: return PK_INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
UNREACHABLE();
|
||||||
|
return (PkVarType) -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectType getPkVarObjType(PkVarType type) {
|
||||||
|
switch (type) {
|
||||||
|
case PK_OBJECT:
|
||||||
|
case PK_NULL:
|
||||||
|
case PK_BOOL:
|
||||||
|
case PK_NUMBER:
|
||||||
|
UNREACHABLE();
|
||||||
|
|
||||||
|
case PK_STRING: return OBJ_STRING;
|
||||||
|
case PK_LIST: return OBJ_LIST;
|
||||||
|
case PK_MAP: return OBJ_MAP;
|
||||||
|
case PK_RANGE: return OBJ_RANGE;
|
||||||
|
case PK_MODULE: return OBJ_MODULE;
|
||||||
|
case PK_CLOSURE: return OBJ_CLOSURE;
|
||||||
|
case PK_FIBER: return OBJ_FIBER;
|
||||||
|
case PK_CLASS: return OBJ_CLASS;
|
||||||
|
case PK_INSTANCE: return OBJ_INST;
|
||||||
|
}
|
||||||
|
|
||||||
|
UNREACHABLE();
|
||||||
|
return (ObjectType) -1;
|
||||||
|
}
|
||||||
|
|
||||||
const char* getPkVarTypeName(PkVarType type) {
|
const char* getPkVarTypeName(PkVarType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case PK_OBJECT: return "Object";
|
||||||
case PK_NULL: return "Null";
|
case PK_NULL: return "Null";
|
||||||
case PK_BOOL: return "Bool";
|
case PK_BOOL: return "Bool";
|
||||||
case PK_NUMBER: return "Number";
|
case PK_NUMBER: return "Number";
|
||||||
case PK_STRING: return "String";
|
default:
|
||||||
case PK_LIST: return "List";
|
return getObjectTypeName(getPkVarObjType(type));
|
||||||
case PK_MAP: return "Map";
|
|
||||||
case PK_RANGE: return "Range";
|
|
||||||
case PK_MODULE: return "Module";
|
|
||||||
|
|
||||||
// TODO: since functions are not first class citizens anymore, remove it
|
|
||||||
// and add closure (maybe with the same name PK_FUNCTION).
|
|
||||||
case PK_FUNCTION: return "Function";
|
|
||||||
|
|
||||||
case PK_FIBER: return "Fiber";
|
|
||||||
case PK_CLASS: return "Class";
|
|
||||||
case PK_INST: return "Inst";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -344,9 +344,8 @@ struct Function {
|
|||||||
// is prevent checking is_native everytime (which might be a bit faster).
|
// is prevent checking is_native everytime (which might be a bit faster).
|
||||||
int upvalue_count;
|
int upvalue_count;
|
||||||
|
|
||||||
// Docstring of the function, currently it's just the C string literal
|
// Docstring of the function. Could be either a C string literal or a string
|
||||||
// pointer, refactor this into String* so that we can support public
|
// entry in it's owner module's constant pool.
|
||||||
// native functions to provide a docstring.
|
|
||||||
const char* docstring;
|
const char* docstring;
|
||||||
|
|
||||||
// Function can be either native C function pointers or compiled pocket
|
// Function can be either native C function pointers or compiled pocket
|
||||||
@ -486,6 +485,10 @@ struct Class {
|
|||||||
// Name of the class.
|
// Name of the class.
|
||||||
String* name;
|
String* name;
|
||||||
|
|
||||||
|
// Docstring of the class. Could be either a C string literal or a string
|
||||||
|
// entry in it's owner module's constant pool.
|
||||||
|
const char* docstring;
|
||||||
|
|
||||||
Closure* ctor; //< The constructor function.
|
Closure* ctor; //< The constructor function.
|
||||||
pkUintBuffer field_names; //< Buffer of field names.
|
pkUintBuffer field_names; //< Buffer of field names.
|
||||||
// TODO: ordered names buffer for binary search.
|
// TODO: ordered names buffer for binary search.
|
||||||
@ -592,10 +595,6 @@ void markValue(PKVM* vm, Var self);
|
|||||||
// the garbage collection.
|
// the garbage collection.
|
||||||
void markVarBuffer(PKVM* vm, pkVarBuffer* self);
|
void markVarBuffer(PKVM* vm, pkVarBuffer* self);
|
||||||
|
|
||||||
// Mark the elements of the buffer as reachable at the mark-and-sweep phase of
|
|
||||||
// the garbage collection.
|
|
||||||
void markStringBuffer(PKVM* vm, pkStringBuffer* self);
|
|
||||||
|
|
||||||
// Pop the marked objects from the working set of the VM and add it's
|
// Pop the marked objects from the working set of the VM and add it's
|
||||||
// referenced objects to the working set, continue traversing and mark
|
// referenced objects to the working set, continue traversing and mark
|
||||||
// all the reachable objects.
|
// all the reachable objects.
|
||||||
@ -724,6 +723,12 @@ Var doubleToVar(double value);
|
|||||||
// Internal method behind AS_NUM(value) don't use it directly.
|
// Internal method behind AS_NUM(value) don't use it directly.
|
||||||
double varToDouble(Var value);
|
double varToDouble(Var value);
|
||||||
|
|
||||||
|
// Returns the PkVarType of the object type.
|
||||||
|
PkVarType getObjPkVarType(ObjectType type);
|
||||||
|
|
||||||
|
// Returns the ObjectType of the PkVar type.
|
||||||
|
ObjectType getPkVarObjType(PkVarType type);
|
||||||
|
|
||||||
// Returns the type name of the PkVarType enum value.
|
// Returns the type name of the PkVarType enum value.
|
||||||
const char* getPkVarTypeName(PkVarType type);
|
const char* getPkVarTypeName(PkVarType type);
|
||||||
|
|
||||||
|
18
src/pk_vm.c
18
src/pk_vm.c
@ -73,8 +73,8 @@ PKVM* pkNewVM(PkConfiguration* config) {
|
|||||||
|
|
||||||
// This is necessary to prevent garbage collection skip the entry in this
|
// This is necessary to prevent garbage collection skip the entry in this
|
||||||
// array while we're building it.
|
// array while we're building it.
|
||||||
for (int i = 0; i < OBJ_INST; i++) {
|
for (int i = 0; i < PK_INSTANCE; i++) {
|
||||||
vm->primitives[i] = NULL;
|
vm->builtin_classes[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeCore(vm);
|
initializeCore(vm);
|
||||||
@ -272,20 +272,16 @@ void vmCollectGarbage(PKVM* vm) {
|
|||||||
|
|
||||||
// Mark builtin functions.
|
// Mark builtin functions.
|
||||||
for (int i = 0; i < vm->builtins_count; i++) {
|
for (int i = 0; i < vm->builtins_count; i++) {
|
||||||
markObject(vm, &vm->builtins[i]->_super);
|
markObject(vm, &vm->builtins_funcs[i]->_super);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark primitive types' classes.
|
// Mark primitive types' classes.
|
||||||
for (int i = 0; i < (int)OBJ_INST; i++) {
|
for (int i = 0; i < PK_INSTANCE; i++) {
|
||||||
// Upvalue and functions aren't first class objects and they doesn't
|
|
||||||
// require classes.
|
|
||||||
if (i == OBJ_UPVALUE || i == OBJ_FUNC) continue;
|
|
||||||
|
|
||||||
// It's possible that a garbage collection could be triggered while we're
|
// It's possible that a garbage collection could be triggered while we're
|
||||||
// building the primitives and the class could be NULL.
|
// building the primitives and the class could be NULL.
|
||||||
if (vm->primitives[i] == NULL) continue;
|
if (vm->builtin_classes[i] == NULL) continue;
|
||||||
|
|
||||||
markObject(vm, &vm->primitives[i]->_super);
|
markObject(vm, &vm->builtin_classes[i]->_super);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the modules.
|
// Mark the modules.
|
||||||
@ -970,7 +966,7 @@ L_vm_main_loop:
|
|||||||
{
|
{
|
||||||
uint8_t index = READ_BYTE();
|
uint8_t index = READ_BYTE();
|
||||||
ASSERT_INDEX(index, vm->builtins_count);
|
ASSERT_INDEX(index, vm->builtins_count);
|
||||||
Closure* closure = vm->builtins[index];
|
Closure* closure = vm->builtins_funcs[index];
|
||||||
PUSH(VAR_OBJ(closure));
|
PUSH(VAR_OBJ(closure));
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
@ -114,13 +114,13 @@ struct PKVM {
|
|||||||
Map* modules;
|
Map* modules;
|
||||||
|
|
||||||
// Array of all builtin functions.
|
// Array of all builtin functions.
|
||||||
Closure* builtins[BUILTIN_FN_CAPACITY];
|
Closure* builtins_funcs[BUILTIN_FN_CAPACITY];
|
||||||
int builtins_count;
|
int builtins_count;
|
||||||
|
|
||||||
// An array of all the primitive types' class except for OBJ_INST. Since the
|
// An array of all the primitive types' class except for OBJ_INST. Since the
|
||||||
// type of the objects are enums starting from 0 we can directly get the
|
// type of the objects are enums starting from 0 we can directly get the
|
||||||
// class by using their enum (ex: primitives[OBJ_LIST]).
|
// class by using their enum (ex: primitives[OBJ_LIST]).
|
||||||
Class* primitives[(int)OBJ_INST];
|
Class* builtin_classes[PK_INSTANCE];
|
||||||
|
|
||||||
// Current fiber.
|
// Current fiber.
|
||||||
Fiber* fiber;
|
Fiber* fiber;
|
||||||
|
Loading…
Reference in New Issue
Block a user