new built-in getCurrentScriptDirectory; new cli option syntax; added -p option to profile programs and -H to set heap size; fixed a bug in string.cat

This commit is contained in:
Francesco Cozzuto
2023-01-19 20:14:23 +01:00
parent 37420cdea2
commit 9cc7121cd9
21 changed files with 631 additions and 255 deletions
+33 -2
View File
@@ -28,18 +28,22 @@
** +--------------------------------------------------------------------------+
*/
#include <time.h>
#include <assert.h>
#include <stdlib.h>
#include "../utils/defs.h"
#include "../objects/objects.h"
#include "timing.h"
#include "runtime.h"
typedef struct {
Object base;
const char *name;
Runtime *runtime;
Executable *exe;
int index, argc;
Object *closure;
TimingID timing_id;
} FunctionObject;
static _Bool free_(Object *self, Error *error)
@@ -108,10 +112,28 @@ static int call(Object *self, Object **argv, unsigned int argc, Object *rets[sta
// The right amount of arguments was provided.
argv2 = argv;
clock_t begin;
TimingID timing_id;
TimingTable *timing_table = Runtime_GetTimingTable(func->runtime);
if (timing_table != NULL) {
begin = clock();
// Need to save the object's member
// before the run function since it
// may trigger a GC cycle invalidating
// the object pointer.
timing_id = func->timing_id;
}
int retc = run(func->runtime, error, func->exe, func->index, func->closure, argv2, expected_argc, rets);
// NOTE: Every object reference is invalidated from here.
if (timing_table != NULL) {
double time = (double) (clock() - begin) / CLOCKS_PER_SEC;
TimingTable_sumCallTime(timing_table, timing_id, time);
}
// NOTE: Every object reference is invalidated from here.
if(argv2 != argv)
free(argv2);
@@ -157,7 +179,7 @@ static TypeObject t_func = {
* The newly created object. If an error occurred, NULL is returned
* and information about the error is stored in the [error] argument.
*/
Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, int argc, Object *closure, Heap *heap, Error *error)
Object *Object_FromNojaFunction(Runtime *runtime, const char *name, Executable *exe, int index, int argc, Object *closure, Heap *heap, Error *error)
{
assert(runtime != NULL);
assert(exe != NULL);
@@ -180,10 +202,19 @@ Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, in
}
func->runtime = runtime;
func->name = name; // Should this be copied?
func->exe = exe_copy;
func->index = index;
func->argc = argc;
func->closure = closure;
TimingTable *table = Runtime_GetTimingTable(runtime);
if (table != NULL) {
#warning "TODO: Calculate line number"
size_t line = 0;
Source *src = Executable_GetSource(exe);
func->timing_id = TimingTable_newEntry(table, src, line, name);
}
return (Object*) func;
}
+71 -51
View File
@@ -31,6 +31,7 @@
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include "runtime.h"
#include "../utils/path.h"
#include "../utils/defs.h"
@@ -49,16 +50,25 @@ struct xFrame {
};
struct xRuntime {
void *callback_userp;
_Bool (*callback_addr)(Runtime*, void*);
bool interrupt;
RuntimeCallback callback;
_Bool free_heap;
Object *builtins;
int depth;
Frame *frame;
Stack *stack;
Heap *heap;
TimingTable *timing;
};
RuntimeConfig Runtime_GetDefaultConfigs()
{
return (RuntimeConfig) {
.stack = 1024,
.callback = { .func = NULL, .data = NULL },
.time = false,
};
}
// Returns the length written in buff (not considering the zero byte)
size_t Runtime_GetCurrentScriptFolder(Runtime *runtime, char *buff, size_t buffsize)
@@ -153,50 +163,69 @@ Executable *Runtime_GetCurrentExecutable(Runtime *runtime)
return runtime->frame->exe;
}
Runtime *Runtime_New2(int stack_size, Heap *heap, _Bool free_heap, void *callback_userp, _Bool (*callback_addr)(Runtime*, void*))
TimingTable *Runtime_GetTimingTable(Runtime *runtime)
{
if(stack_size < 0)
stack_size = 1024;
return runtime->timing;
}
void Runtime_Interrupt(Runtime *runtime)
{
runtime->interrupt = true;
}
Runtime *Runtime_New2(Heap *heap, _Bool free_it, RuntimeConfig config)
{
Runtime *runtime = malloc(sizeof(Runtime));
if (runtime == NULL)
return NULL;
if(runtime != NULL)
{
runtime->heap = heap;
runtime->stack = Stack_New(stack_size);
if(runtime->stack == NULL)
{
Heap_Free(runtime->heap);
free(runtime);
}
runtime->free_heap = free_heap;
runtime->callback_userp = callback_userp;
runtime->callback_addr = callback_addr;
runtime->builtins = NULL;
runtime->frame = NULL;
runtime->depth = 0;
runtime->stack = Stack_New(config.stack);
if(runtime->stack == NULL) {
if (free_it)
Heap_Free(heap);
free(runtime);
return NULL;
}
TimingTable *timing_table = NULL;
if (config.time) {
timing_table = TimingTable_new();
if (timing_table == NULL) {
if (free_it)
Heap_Free(heap);
free(runtime);
return NULL;
}
}
runtime->interrupt = false;
runtime->timing = timing_table;
runtime->heap = heap;
runtime->free_heap = free_it;
runtime->callback = config.callback;
runtime->builtins = NULL;
runtime->frame = NULL;
runtime->depth = 0;
return runtime;
}
Runtime *Runtime_New(int stack_size, int heap_size, void *callback_userp, _Bool (*callback_addr)(Runtime*, void*))
Runtime *Runtime_New(int heap_size, RuntimeConfig config)
{
if(heap_size < 0)
heap_size = 65536;
Heap *heap = Heap_New(heap_size);
if(heap == NULL) return NULL;
if(heap == NULL)
return NULL;
return Runtime_New2(stack_size, heap, 1, callback_userp, callback_addr);
return Runtime_New2(heap, 1, config);
}
void Runtime_Free(Runtime *runtime)
{
if (runtime->timing != NULL)
TimingTable_free(runtime->timing);
if(runtime->free_heap)
Heap_Free(runtime->heap);
Stack_Free(runtime->stack);
@@ -839,6 +868,7 @@ static _Bool step(Runtime *runtime, Error *error)
{
ASSERT(opc == 1);
ASSERT(ops[0].type == OPTP_STRING);
const char *name = ops[0].as_string;
if(runtime->frame->used == 0)
{
@@ -849,7 +879,7 @@ static _Bool step(Runtime *runtime, Error *error)
Object *val = Stack_Top(runtime->stack, 0);
ASSERT(val != NULL);
Object *key = Object_FromString(ops[0].as_string, -1, runtime->heap, error);
Object *key = Object_FromString(name, -1, runtime->heap, error);
if(key == NULL)
return 0;
@@ -1204,16 +1234,17 @@ static _Bool step(Runtime *runtime, Error *error)
case OPCODE_PUSHFUN:
{
ASSERT(opc == 2);
ASSERT(opc == 3);
ASSERT(ops[0].type == OPTP_IDX);
ASSERT(ops[1].type == OPTP_INT);
ASSERT(ops[2].type == OPTP_STRING);
Object *closure = Object_NewClosure(runtime->frame->closure, runtime->frame->locals, Runtime_GetHeap(runtime), error);
if(closure == NULL)
return 0;
Object *obj = Object_FromNojaFunction(runtime, runtime->frame->exe, ops[0].as_int, ops[1].as_int, closure, runtime->heap, error);
Object *obj = Object_FromNojaFunction(runtime, ops[2].as_string, runtime->frame->exe, ops[0].as_int, ops[1].as_int, closure, runtime->heap, error);
if(obj == NULL)
return 0;
@@ -1470,34 +1501,23 @@ int run(Runtime *runtime, Error *error,
// Run the code.
if(runtime->callback_addr != NULL)
{
if(!runtime->callback_addr(runtime, runtime->callback_userp))
Error_Report(error, 0, "Forced abortion");
else
while(step(runtime, error))
{
if(!runtime->callback_addr(runtime, runtime->callback_userp))
{
Error_Report(error, 0, "Forced abortion");
break;
}
//printf("%2.2f%% percent.\n", Heap_GetUsagePercentage(runtime->heap));
if(Heap_GetUsagePercentage(runtime->heap) > 100)
if(!collect(runtime, error))
break;
}
}
if(runtime->interrupt || (runtime->callback.func != NULL && !runtime->callback.func(runtime, runtime->callback.data)))
Error_Report(error, 0, "Forced abortion");
else
while(step(runtime, error))
{
if(runtime->interrupt || (runtime->callback.func != NULL && !runtime->callback.func(runtime, runtime->callback.data)))
{
Error_Report(error, 0, "Forced abortion");
break;
}
//printf("%2.2f%% percent.\n", Heap_GetUsagePercentage(runtime->heap));
if(Heap_GetUsagePercentage(runtime->heap) > 100)
if(!collect(runtime, error))
break;
//printf("%2.2f%% percent.\n", Heap_GetUsagePercentage(runtime->heap));
}
// If an error occurred, we want to return NULL.
+31 -14
View File
@@ -32,6 +32,7 @@
#define RUNTIME_H
#include <stdio.h> // meh.. just for the definition of FILE.
#include "timing.h"
#include "../utils/error.h"
#include "../utils/stack.h"
#include "../objects/objects.h"
@@ -40,19 +41,34 @@
typedef struct xRuntime Runtime;
typedef struct xSnapshot Snapshot;
Runtime* Runtime_New(int stack_size, int heap_size, void *callback_userp, _Bool (*callback_addr)(Runtime*, void*));
Runtime* Runtime_New2(int stack_size, Heap *heap, _Bool free_heap, void *callback_userp, _Bool (*callback_addr)(Runtime*, void*));
void Runtime_Free(Runtime *runtime);
_Bool Runtime_Pop(Runtime *runtime, Error *error, unsigned int n);
_Bool Runtime_Push(Runtime *runtime, Error *error, Object *obj);
Heap* Runtime_GetHeap(Runtime *runtime);
Stack* Runtime_GetStack(Runtime *runtime);
Object* Runtime_GetBuiltins(Runtime *runtime);
void Runtime_SetBuiltins(Runtime *runtime, Object *builtins);
int Runtime_GetCurrentIndex(Runtime *runtime);
Executable *Runtime_GetCurrentExecutable(Runtime *runtime);
size_t Runtime_GetCurrentScriptFolder(Runtime *runtime, char *buff, size_t buffsize);
const char *Runtime_GetCurrentScriptAbsolutePath(Runtime *runtime);
typedef struct {
bool (*func)(Runtime*, void*);
void *data;
} RuntimeCallback;
typedef struct {
bool time;
size_t stack;
RuntimeCallback callback;
} RuntimeConfig;
Runtime* Runtime_New(int heap_size, RuntimeConfig config);
Runtime* Runtime_New2(Heap *heap, bool free_it, RuntimeConfig config);
void Runtime_Free(Runtime *runtime);
_Bool Runtime_Pop(Runtime *runtime, Error *error, unsigned int n);
_Bool Runtime_Push(Runtime *runtime, Error *error, Object *obj);
void Runtime_Interrupt(Runtime *runtime);
Heap* Runtime_GetHeap(Runtime *runtime);
Stack* Runtime_GetStack(Runtime *runtime);
Object* Runtime_GetBuiltins(Runtime *runtime);
void Runtime_SetBuiltins(Runtime *runtime, Object *builtins);
int Runtime_GetCurrentIndex(Runtime *runtime);
Executable *Runtime_GetCurrentExecutable(Runtime *runtime);
size_t Runtime_GetCurrentScriptFolder(Runtime *runtime, char *buff, size_t buffsize);
const char *Runtime_GetCurrentScriptAbsolutePath(Runtime *runtime);
TimingTable *Runtime_GetTimingTable(Runtime *runtime);
RuntimeConfig Runtime_GetDefaultConfigs();
Snapshot *Snapshot_New(Runtime *runtime);
void Snapshot_Free(Snapshot *snapshot);
void Snapshot_Print(Snapshot *snapshot, FILE *fp);
@@ -90,8 +106,9 @@ struct StaticMapSlot {
};
Object *Object_NewStaticMap(StaticMapSlot slots[], void (*initfn)(StaticMapSlot[]), Runtime *runt, Error *error);
Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, int argc, Object *closure, Heap *heap, Error *error);
Object *Object_FromNojaFunction(Runtime *runtime, const char *name, Executable *exe, int index, int argc, Object *closure, Heap *heap, Error *error);
Object *Object_FromNativeFunction(Runtime *runtime, int (*callback)(Runtime*, Object**, unsigned int, Object*[static MAX_RETS], Error*), int argc, Heap *heap, Error *error);
typedef struct {
Error base;
Runtime *runtime;
+76
View File
@@ -0,0 +1,76 @@
#include <stdlib.h>
#include <string.h>
#include "timing.h"
#include "../utils/defs.h"
struct TimingTable {
FunctionExecutionSummary *entries;
size_t size, used;
};
TimingTable *TimingTable_new()
{
TimingTable *table = malloc(sizeof(TimingTable));
if (table == NULL)
return NULL;
table->entries = NULL;
table->size = 0;
table->used = 0;
return table;
}
void TimingTable_free(TimingTable *table)
{
if (table != NULL) {
for(size_t i = 0; i < table->used; i++) {
free(table->entries[i].name);
Source_Free(table->entries[i].src);
}
free(table->entries);
free(table);
}
}
void TimingTable_sumCallTime(TimingTable *table, TimingID id, double time)
{
if (id < 0 || id >= (int) table->used)
abort();
table->entries[id].calls++;
table->entries[id].time += time;
}
TimingID TimingTable_newEntry(TimingTable *table, Source *src, size_t line, const char *name)
{
if (table->size == table->used) {
size_t new_size = 2 * table->size;
if (new_size == 0) new_size = 8;
void *temp = realloc(table->entries, new_size * sizeof(FunctionExecutionSummary));
if (temp == NULL) abort();
table->entries = temp;
table->size = new_size;
}
char *name2 = strdup(name);
if (name2 == NULL)
abort();
TimingID id = (int) table->used++;
table->entries[id].src = Source_Copy(src);
table->entries[id].line = line;
table->entries[id].name = name2;
table->entries[id].time = 0;
table->entries[id].calls = 0;
return id;
}
const FunctionExecutionSummary*
TimingTable_getSummary(TimingTable *table, size_t *count)
{
ASSERT(table != NULL && count != NULL);
*count = table->used;
return table->entries;
}
+23
View File
@@ -0,0 +1,23 @@
#ifndef TIMING_H
#define TIMING_H
#include <stddef.h>
#include "../utils/source.h"
typedef struct {
size_t calls;
double time;
size_t line;
char *name;
Source *src;
} FunctionExecutionSummary;
typedef int TimingID;
typedef struct TimingTable TimingTable;
TimingTable *TimingTable_new();
void TimingTable_free(TimingTable *table);
TimingID TimingTable_newEntry(TimingTable *table, Source *src, size_t line, const char *name);
void TimingTable_sumCallTime(TimingTable *table, TimingID id, double time);
TimingTable *TimingTable_getDefaultTable();
const FunctionExecutionSummary *TimingTable_getSummary(TimingTable *table, size_t *count);
#endif