chore: remove trailing whitespace from README.md line 42
This commit is contained in:
+689
-559
File diff suppressed because it is too large
Load Diff
+66
-1
@@ -32,7 +32,8 @@ typedef enum {
|
||||
RAVA_VAL_HASHMAP,
|
||||
RAVA_VAL_SOCKET,
|
||||
RAVA_VAL_STREAM,
|
||||
RAVA_VAL_METHOD_REF
|
||||
RAVA_VAL_METHOD_REF,
|
||||
RAVA_VAL_INETADDRESS
|
||||
} RavaValueType_e;
|
||||
|
||||
typedef struct {
|
||||
@@ -49,6 +50,7 @@ typedef struct RavaHashMap_t RavaHashMap_t;
|
||||
typedef struct RavaSocket_t RavaSocket_t;
|
||||
typedef struct RavaStream_t RavaStream_t;
|
||||
typedef struct RavaMethodRef_t RavaMethodRef_t;
|
||||
typedef struct RavaInetAddress_t RavaInetAddress_t;
|
||||
|
||||
#define RAVA_OBJECT_HASH_SIZE 32
|
||||
|
||||
@@ -79,6 +81,7 @@ struct RavaValue_t {
|
||||
RavaSocket_t *socket_val;
|
||||
RavaStream_t *stream_val;
|
||||
RavaMethodRef_t *method_ref_val;
|
||||
RavaInetAddress_t *inetaddress_val;
|
||||
} data;
|
||||
};
|
||||
|
||||
@@ -118,6 +121,9 @@ struct RavaSocket_t {
|
||||
int fd;
|
||||
bool connected;
|
||||
bool closed;
|
||||
bool bound;
|
||||
bool input_shutdown;
|
||||
bool output_shutdown;
|
||||
};
|
||||
|
||||
#define RAVA_STREAM_TYPE_INPUT 1
|
||||
@@ -140,6 +146,17 @@ struct RavaMethodRef_t {
|
||||
bool has_target;
|
||||
};
|
||||
|
||||
#define RAVA_INETADDRESS_IPV4 1
|
||||
#define RAVA_INETADDRESS_IPV6 2
|
||||
|
||||
struct RavaInetAddress_t {
|
||||
RavaGCHeader_t gc;
|
||||
int address_type;
|
||||
uint8_t address[16];
|
||||
char *hostname;
|
||||
char *hostaddress;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
RavaValue_t *values;
|
||||
size_t capacity;
|
||||
@@ -365,6 +382,53 @@ int rava_stream_read_byte(RavaStream_t *stream);
|
||||
void rava_stream_write(RavaStream_t *stream, const char *data);
|
||||
void rava_stream_write_byte(RavaStream_t *stream, int byte);
|
||||
void rava_stream_close(RavaStream_t *stream);
|
||||
int rava_stream_read_bytes(RavaStream_t *stream, RavaArray_t *arr, int off, int len);
|
||||
int rava_stream_available(RavaStream_t *stream);
|
||||
|
||||
RavaInetAddress_t* rava_inetaddress_create(void);
|
||||
RavaInetAddress_t* rava_inetaddress_get_by_name(const char *host);
|
||||
RavaInetAddress_t* rava_inetaddress_get_local_host(void);
|
||||
RavaInetAddress_t* rava_inetaddress_get_loopback(void);
|
||||
char* rava_inetaddress_get_host_name(RavaInetAddress_t *addr);
|
||||
char* rava_inetaddress_get_host_address(RavaInetAddress_t *addr);
|
||||
bool rava_inetaddress_is_loopback(RavaInetAddress_t *addr);
|
||||
bool rava_inetaddress_is_any_local(RavaInetAddress_t *addr);
|
||||
int rava_socket_get_port(RavaSocket_t *socket);
|
||||
int rava_socket_get_local_port(RavaSocket_t *socket);
|
||||
RavaInetAddress_t* rava_socket_get_inet_address(RavaSocket_t *socket);
|
||||
RavaInetAddress_t* rava_socket_get_local_address(RavaSocket_t *socket);
|
||||
int rava_server_socket_get_local_port(RavaSocket_t *socket);
|
||||
bool rava_server_socket_is_bound(RavaSocket_t *socket);
|
||||
bool rava_server_socket_is_closed(RavaSocket_t *socket);
|
||||
void rava_server_socket_set_so_timeout(RavaSocket_t *socket, int timeout);
|
||||
int rava_server_socket_get_so_timeout(RavaSocket_t *socket);
|
||||
void rava_socket_set_so_timeout(RavaSocket_t *socket, int timeout_ms);
|
||||
int rava_socket_get_so_timeout(RavaSocket_t *socket);
|
||||
void rava_socket_set_tcp_nodelay(RavaSocket_t *socket, bool nodelay);
|
||||
bool rava_socket_get_tcp_nodelay(RavaSocket_t *socket);
|
||||
void rava_socket_bind(RavaSocket_t *socket, const char *host, int port);
|
||||
bool rava_socket_is_connected(RavaSocket_t *socket);
|
||||
bool rava_socket_is_closed(RavaSocket_t *socket);
|
||||
bool rava_socket_is_bound(RavaSocket_t *socket);
|
||||
void rava_socket_shutdown_input(RavaSocket_t *socket);
|
||||
void rava_socket_shutdown_output(RavaSocket_t *socket);
|
||||
bool rava_socket_is_input_shutdown(RavaSocket_t *socket);
|
||||
bool rava_socket_is_output_shutdown(RavaSocket_t *socket);
|
||||
void rava_socket_set_send_buffer_size(RavaSocket_t *socket, int size);
|
||||
int rava_socket_get_send_buffer_size(RavaSocket_t *socket);
|
||||
void rava_socket_set_receive_buffer_size(RavaSocket_t *socket, int size);
|
||||
int rava_socket_get_receive_buffer_size(RavaSocket_t *socket);
|
||||
void rava_socket_set_keep_alive(RavaSocket_t *socket, bool keepalive);
|
||||
bool rava_socket_get_keep_alive(RavaSocket_t *socket);
|
||||
void rava_socket_set_reuse_address(RavaSocket_t *socket, bool reuse);
|
||||
bool rava_socket_get_reuse_address(RavaSocket_t *socket);
|
||||
|
||||
static inline RavaValue_t rava_value_inetaddress(RavaInetAddress_t *addr) {
|
||||
RavaValue_t val;
|
||||
val.type = RAVA_VAL_INETADDRESS;
|
||||
val.data.inetaddress_val = addr;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline RavaValue_t rava_value_socket(RavaSocket_t *socket) {
|
||||
RavaValue_t val;
|
||||
@@ -437,6 +501,7 @@ RavaValue_t rava_native_to_value(RavaNativeValue_t native);
|
||||
#define RAVA_GC_TYPE_SOCKET 6
|
||||
#define RAVA_GC_TYPE_STREAM 7
|
||||
#define RAVA_GC_TYPE_METHODREF 8
|
||||
#define RAVA_GC_TYPE_INETADDRESS 9
|
||||
|
||||
void rava_gc_init(void);
|
||||
void rava_gc_shutdown(void);
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#include "runtime_internal.h"
|
||||
|
||||
RavaExceptionStack_t* rava_exception_stack_create(void) {
|
||||
RavaExceptionStack_t *stack = calloc(1, sizeof(RavaExceptionStack_t));
|
||||
if (!stack) return NULL;
|
||||
stack->count = 0;
|
||||
return stack;
|
||||
}
|
||||
|
||||
void rava_exception_stack_destroy(RavaExceptionStack_t *stack) {
|
||||
free(stack);
|
||||
}
|
||||
|
||||
void rava_exception_stack_push(RavaExceptionStack_t *stack, RavaExceptionHandler_t handler) {
|
||||
if (stack->count >= RAVA_MAX_EXCEPTION_DEPTH) return;
|
||||
stack->handlers[stack->count++] = handler;
|
||||
}
|
||||
|
||||
bool rava_exception_stack_pop(RavaExceptionStack_t *stack, RavaExceptionHandler_t *handler) {
|
||||
if (stack->count == 0) return false;
|
||||
*handler = stack->handlers[--stack->count];
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "runtime_internal.h"
|
||||
|
||||
const char* _rava_intern_string(RavaVM_t *vm, const char *str) {
|
||||
uint32_t h = _intern_hash(str);
|
||||
for (size_t i = 0; i < RAVA_INTERN_TABLE_SIZE; i++) {
|
||||
size_t idx = (h + i) & (RAVA_INTERN_TABLE_SIZE - 1);
|
||||
if (vm->intern_table.strings[idx] == NULL) {
|
||||
if (vm->intern_table.count >= RAVA_INTERN_TABLE_SIZE - 1) {
|
||||
static bool warned = false;
|
||||
if (!warned) {
|
||||
fprintf(stderr, "Warning: String intern table full (%d entries)\n",
|
||||
RAVA_INTERN_TABLE_SIZE);
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
vm->intern_table.strings[idx] = strdup(str);
|
||||
vm->intern_table.count++;
|
||||
return vm->intern_table.strings[idx];
|
||||
}
|
||||
if (strcmp(vm->intern_table.strings[idx], str) == 0) {
|
||||
return vm->intern_table.strings[idx];
|
||||
}
|
||||
}
|
||||
return strdup(str);
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
#ifndef RAVA_RUNTIME_INTERNAL_H
|
||||
#define RAVA_RUNTIME_INTERNAL_H
|
||||
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "runtime.h"
|
||||
#include "labeltable.h"
|
||||
#include "methodcache.h"
|
||||
#include "nanbox.h"
|
||||
#include "fastframe.h"
|
||||
#include "superinst.h"
|
||||
#include "../utils/safe_alloc.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define LIKELY(x) (x)
|
||||
#define UNLIKELY(x) (x)
|
||||
#endif
|
||||
|
||||
#define STACK_ENSURE_CAPACITY(stack) do { \
|
||||
if ((stack)->top >= (stack)->capacity) { \
|
||||
(stack)->capacity *= 2; \
|
||||
RavaValue_t *_new_values = realloc((stack)->values, sizeof(RavaValue_t) * (stack)->capacity); \
|
||||
if (_new_values) (stack)->values = _new_values; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define STACK_PUSH(stack, val) do { \
|
||||
STACK_ENSURE_CAPACITY(stack); \
|
||||
(stack)->values[(stack)->top++] = (val); \
|
||||
} while(0)
|
||||
|
||||
#define STACK_POP(stack) ((stack)->top > 0 ? (stack)->values[--(stack)->top] : (RavaValue_t){0})
|
||||
|
||||
#define STACK_PEEK(stack) ((stack)->top > 0 ? (stack)->values[(stack)->top - 1] : (RavaValue_t){0})
|
||||
|
||||
#define STACK_PUSH_INT(stack, v) do { \
|
||||
STACK_ENSURE_CAPACITY(stack); \
|
||||
RavaValue_t _v; _v.type = RAVA_VAL_INT; _v.data.int_val = (v); \
|
||||
(stack)->values[(stack)->top++] = _v; \
|
||||
} while(0)
|
||||
|
||||
#define STACK_PUSH_LONG(stack, v) do { \
|
||||
STACK_ENSURE_CAPACITY(stack); \
|
||||
RavaValue_t _v; _v.type = RAVA_VAL_LONG; _v.data.long_val = (v); \
|
||||
(stack)->values[(stack)->top++] = _v; \
|
||||
} while(0)
|
||||
|
||||
#define STACK_PUSH_BOOL(stack, v) do { \
|
||||
STACK_ENSURE_CAPACITY(stack); \
|
||||
RavaValue_t _v; _v.type = RAVA_VAL_BOOLEAN; _v.data.bool_val = (v); \
|
||||
(stack)->values[(stack)->top++] = _v; \
|
||||
} while(0)
|
||||
|
||||
#define VALUE_IS_INT(v) ((v).type == RAVA_VAL_INT)
|
||||
#define VALUE_IS_LONG(v) ((v).type == RAVA_VAL_LONG)
|
||||
#define VALUE_AS_INT_FAST(v) ((v).data.int_val)
|
||||
#define VALUE_AS_LONG_FAST(v) ((v).data.long_val)
|
||||
|
||||
static inline RavaNanboxValue_t rava_value_to_nanbox(RavaValue_t val) {
|
||||
switch (val.type) {
|
||||
case RAVA_VAL_INT: return rava_nanbox_int(val.data.int_val);
|
||||
case RAVA_VAL_LONG: return rava_nanbox_long(val.data.long_val);
|
||||
case RAVA_VAL_DOUBLE: return rava_nanbox_double(val.data.double_val);
|
||||
case RAVA_VAL_FLOAT: return rava_nanbox_double((double)val.data.float_val);
|
||||
case RAVA_VAL_BOOLEAN: return rava_nanbox_bool(val.data.bool_val);
|
||||
case RAVA_VAL_NULL: return rava_nanbox_null();
|
||||
case RAVA_VAL_STRING: return rava_nanbox_string(val.data.string_val);
|
||||
case RAVA_VAL_OBJECT: return rava_nanbox_object(val.data.object_val);
|
||||
case RAVA_VAL_ARRAY: return rava_nanbox_array(val.data.array_val);
|
||||
default: return rava_nanbox_null();
|
||||
}
|
||||
}
|
||||
|
||||
static inline RavaValue_t rava_nanbox_to_value(RavaNanboxValue_t nb) {
|
||||
RavaValue_t val;
|
||||
if (rava_nanbox_is_int(nb)) {
|
||||
val.type = RAVA_VAL_INT;
|
||||
val.data.int_val = rava_nanbox_as_int(nb);
|
||||
} else if (rava_nanbox_is_long(nb)) {
|
||||
val.type = RAVA_VAL_LONG;
|
||||
val.data.long_val = rava_nanbox_as_long(nb);
|
||||
} else if (rava_nanbox_is_double(nb)) {
|
||||
val.type = RAVA_VAL_DOUBLE;
|
||||
val.data.double_val = rava_nanbox_as_double(nb);
|
||||
} else if (rava_nanbox_is_bool(nb)) {
|
||||
val.type = RAVA_VAL_BOOLEAN;
|
||||
val.data.bool_val = rava_nanbox_as_bool(nb);
|
||||
} else if (rava_nanbox_is_null(nb)) {
|
||||
val.type = RAVA_VAL_NULL;
|
||||
val.data.object_val = NULL;
|
||||
} else if (rava_nanbox_is_string(nb)) {
|
||||
val.type = RAVA_VAL_STRING;
|
||||
val.data.string_val = (char*)rava_nanbox_as_string(nb);
|
||||
} else if (rava_nanbox_is_object(nb)) {
|
||||
val.type = RAVA_VAL_OBJECT;
|
||||
val.data.object_val = rava_nanbox_as_object(nb);
|
||||
} else if (rava_nanbox_is_array(nb)) {
|
||||
val.type = RAVA_VAL_ARRAY;
|
||||
val.data.array_val = rava_nanbox_as_array(nb);
|
||||
} else {
|
||||
val.type = RAVA_VAL_NULL;
|
||||
val.data.object_val = NULL;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline uint32_t _rava_field_hash(const char *name) {
|
||||
uint32_t hash = 5381;
|
||||
while (*name) {
|
||||
hash = ((hash << 5) + hash) ^ (uint32_t)*name++;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
static inline uint32_t _rava_class_hash(const char *name) {
|
||||
uint32_t hash = 5381;
|
||||
while (*name) hash = ((hash << 5) + hash) ^ (uint32_t)*name++;
|
||||
return hash & (RAVA_CLASS_HASH_SIZE - 1);
|
||||
}
|
||||
|
||||
static inline uint32_t _rava_method_hash(const char *name) {
|
||||
uint32_t hash = 5381;
|
||||
while (*name) hash = ((hash << 5) + hash) ^ (uint32_t)*name++;
|
||||
return hash & (RAVA_METHOD_HASH_SIZE - 1);
|
||||
}
|
||||
|
||||
static inline uint32_t _rava_static_hash(const char *class_name, const char *field_name) {
|
||||
uint32_t hash = 5381;
|
||||
while (*class_name) hash = ((hash << 5) + hash) ^ (uint32_t)*class_name++;
|
||||
hash = ((hash << 5) + hash) ^ (uint32_t)'.';
|
||||
while (*field_name) hash = ((hash << 5) + hash) ^ (uint32_t)*field_name++;
|
||||
return hash;
|
||||
}
|
||||
|
||||
static inline uint32_t _intern_hash(const char *str) {
|
||||
uint32_t hash = 5381;
|
||||
while (*str) hash = ((hash << 5) + hash) ^ (uint32_t)*str++;
|
||||
return hash;
|
||||
}
|
||||
|
||||
char* _rava_get_string_buffer(RavaVM_t *vm, size_t needed);
|
||||
const char* _rava_intern_string(RavaVM_t *vm, const char *str);
|
||||
void _rava_object_set_field_vm(RavaObject_t *obj, const char *name, RavaValue_t value, RavaVM_t *vm);
|
||||
|
||||
RavaClass_t* _rava_vm_find_class(RavaVM_t *vm, const char *class_name);
|
||||
RavaMethod_t* _rava_vm_find_method(RavaVM_t *vm, const char *class_name, const char *method_name);
|
||||
RavaMethod_t* _rava_vm_find_method_cached(RavaVM_t *vm, const char *class_name, const char *method_name);
|
||||
|
||||
RavaStaticFieldTable_t* rava_static_field_table_create(void);
|
||||
void rava_static_field_table_destroy(RavaStaticFieldTable_t *table);
|
||||
RavaValue_t* rava_static_field_table_get(RavaStaticFieldTable_t *table, const char *class_name, const char *field_name);
|
||||
void rava_static_field_table_set(RavaStaticFieldTable_t *table, const char *class_name, const char *field_name, RavaValue_t value);
|
||||
|
||||
RavaExceptionStack_t* rava_exception_stack_create(void);
|
||||
void rava_exception_stack_destroy(RavaExceptionStack_t *stack);
|
||||
void rava_exception_stack_push(RavaExceptionStack_t *stack, RavaExceptionHandler_t handler);
|
||||
bool rava_exception_stack_pop(RavaExceptionStack_t *stack, RavaExceptionHandler_t *handler);
|
||||
|
||||
bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, RavaInstruction_t *instr);
|
||||
bool _rava_vm_execute_fast(RavaVM_t *vm, RavaCallFrame_t *frame);
|
||||
bool _rava_vm_execute_ultrafast(RavaVM_t *vm, RavaMethod_t *entry_method);
|
||||
bool _rava_vm_run_static_initializers(RavaVM_t *vm);
|
||||
|
||||
extern bool g_gc_initialized;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
#include "runtime_internal.h"
|
||||
|
||||
bool g_gc_initialized = false;
|
||||
|
||||
RavaClass_t* _rava_vm_find_class(RavaVM_t *vm, const char *class_name) {
|
||||
uint32_t h = _rava_class_hash(class_name);
|
||||
int idx = vm->class_hash[h];
|
||||
if (idx >= 0 && (size_t)idx < vm->program->class_count &&
|
||||
strcmp(vm->program->classes[idx]->name, class_name) == 0) {
|
||||
return vm->program->classes[idx];
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < vm->program->class_count; i++) {
|
||||
if (strcmp(vm->program->classes[i]->name, class_name) == 0) {
|
||||
vm->class_hash[h] = (int)i;
|
||||
return vm->program->classes[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RavaMethod_t* _rava_vm_find_method(RavaVM_t *vm, const char *class_name, const char *method_name) {
|
||||
const char *current_class = class_name;
|
||||
while (current_class) {
|
||||
RavaClass_t *class = _rava_vm_find_class(vm, current_class);
|
||||
if (!class) break;
|
||||
uint32_t h = _rava_method_hash(method_name);
|
||||
int idx = class->method_hash[h];
|
||||
if (idx >= 0 && (size_t)idx < class->method_count &&
|
||||
strcmp(class->methods[idx]->name, method_name) == 0) {
|
||||
return class->methods[idx];
|
||||
}
|
||||
for (size_t j = 0; j < class->method_count; j++) {
|
||||
if (strcmp(class->methods[j]->name, method_name) == 0) {
|
||||
class->method_hash[h] = (int)j;
|
||||
return class->methods[j];
|
||||
}
|
||||
}
|
||||
current_class = class->superclass;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RavaMethod_t* _rava_vm_find_method_cached(RavaVM_t *vm, const char *class_name, const char *method_name) {
|
||||
MethodCache_t *cache = (MethodCache_t*)vm->method_cache;
|
||||
RavaMethod_t *cached = rava_methodcache_lookup(cache, class_name, method_name);
|
||||
if (cached) return cached;
|
||||
RavaMethod_t *method = _rava_vm_find_method(vm, class_name, method_name);
|
||||
if (method) {
|
||||
rava_methodcache_insert(cache, class_name, method_name, method);
|
||||
}
|
||||
return method;
|
||||
}
|
||||
@@ -178,6 +178,8 @@ int32_t rava_object_hashcode(RavaValue_t value) {
|
||||
return (int32_t)((uintptr_t)value.data.socket_val >> 3);
|
||||
case RAVA_VAL_STREAM:
|
||||
return (int32_t)((uintptr_t)value.data.stream_val >> 3);
|
||||
case RAVA_VAL_INETADDRESS:
|
||||
return (int32_t)((uintptr_t)value.data.inetaddress_val >> 3);
|
||||
case RAVA_VAL_METHOD_REF:
|
||||
return (int32_t)((uintptr_t)value.data.method_ref_val >> 3);
|
||||
}
|
||||
@@ -287,6 +289,13 @@ char* rava_object_tostring(RavaValue_t value) {
|
||||
snprintf(buffer, 128, "Stream@%x",
|
||||
(unsigned int)((uintptr_t)value.data.stream_val >> 3));
|
||||
break;
|
||||
case RAVA_VAL_INETADDRESS:
|
||||
if (value.data.inetaddress_val && value.data.inetaddress_val->hostaddress) {
|
||||
snprintf(buffer, 128, "/%s", value.data.inetaddress_val->hostaddress);
|
||||
} else {
|
||||
strcpy(buffer, "/null");
|
||||
}
|
||||
break;
|
||||
case RAVA_VAL_METHOD_REF:
|
||||
if (value.data.method_ref_val) {
|
||||
snprintf(buffer, 128, "%s::%s",
|
||||
@@ -333,6 +342,8 @@ const char* rava_object_getclass(RavaValue_t value) {
|
||||
return "Socket";
|
||||
case RAVA_VAL_STREAM:
|
||||
return "Stream";
|
||||
case RAVA_VAL_INETADDRESS:
|
||||
return "InetAddress";
|
||||
case RAVA_VAL_METHOD_REF:
|
||||
return "MethodReference";
|
||||
}
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#ifndef NI_MAXHOST
|
||||
#define NI_MAXHOST 1025
|
||||
#endif
|
||||
|
||||
RavaSocket_t* rava_socket_create(void) {
|
||||
RavaSocket_t *sock = rava_gc_alloc(sizeof(RavaSocket_t), RAVA_GC_TYPE_SOCKET);
|
||||
@@ -62,6 +69,8 @@ RavaSocket_t* rava_server_socket_create(int port) {
|
||||
return sock;
|
||||
}
|
||||
|
||||
sock->bound = true;
|
||||
|
||||
if (listen(sock->fd, 10) < 0) {
|
||||
close(sock->fd);
|
||||
sock->fd = -1;
|
||||
@@ -204,3 +213,424 @@ void rava_stream_close(RavaStream_t *stream) {
|
||||
if (!stream) return;
|
||||
stream->closed = true;
|
||||
}
|
||||
|
||||
int rava_stream_read_bytes(RavaStream_t *stream, RavaArray_t *arr, int off, int len) {
|
||||
if (!stream || stream->closed || stream->fd < 0) return -1;
|
||||
if (stream->stream_type != RAVA_STREAM_TYPE_INPUT) return -1;
|
||||
if (!arr || off < 0 || len <= 0) return -1;
|
||||
if ((size_t)(off + len) > arr->length) return -1;
|
||||
|
||||
char *buffer = malloc(len);
|
||||
if (!buffer) return -1;
|
||||
|
||||
ssize_t bytes_read = read(stream->fd, buffer, len);
|
||||
if (bytes_read <= 0) {
|
||||
free(buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ssize_t i = 0; i < bytes_read; i++) {
|
||||
rava_array_set_value(arr, off + i, rava_value_int((unsigned char)buffer[i]));
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
return (int)bytes_read;
|
||||
}
|
||||
|
||||
int rava_stream_available(RavaStream_t *stream) {
|
||||
if (!stream || stream->closed || stream->fd < 0) return 0;
|
||||
if (stream->stream_type != RAVA_STREAM_TYPE_INPUT) return 0;
|
||||
|
||||
int available = 0;
|
||||
if (ioctl(stream->fd, FIONREAD, &available) < 0) {
|
||||
return 0;
|
||||
}
|
||||
return available;
|
||||
}
|
||||
|
||||
RavaInetAddress_t* rava_inetaddress_create(void) {
|
||||
RavaInetAddress_t *addr = rava_gc_alloc(sizeof(RavaInetAddress_t), RAVA_GC_TYPE_INETADDRESS);
|
||||
if (!addr) return NULL;
|
||||
memset((char*)addr + sizeof(RavaGCHeader_t), 0, sizeof(RavaInetAddress_t) - sizeof(RavaGCHeader_t));
|
||||
addr->address_type = RAVA_INETADDRESS_IPV4;
|
||||
return addr;
|
||||
}
|
||||
|
||||
RavaInetAddress_t* rava_inetaddress_get_by_name(const char *host) {
|
||||
if (!host) return NULL;
|
||||
|
||||
struct addrinfo hints, *res;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
int status = getaddrinfo(host, NULL, &hints, &res);
|
||||
if (status != 0) return NULL;
|
||||
|
||||
RavaInetAddress_t *addr = rava_inetaddress_create();
|
||||
if (!addr) {
|
||||
freeaddrinfo(res);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
addr->hostname = strdup(host);
|
||||
|
||||
if (res->ai_family == AF_INET) {
|
||||
addr->address_type = RAVA_INETADDRESS_IPV4;
|
||||
struct sockaddr_in *ipv4 = (struct sockaddr_in*)res->ai_addr;
|
||||
memcpy(addr->address, &ipv4->sin_addr, 4);
|
||||
char ip[INET_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET, &ipv4->sin_addr, ip, sizeof(ip));
|
||||
addr->hostaddress = strdup(ip);
|
||||
} else if (res->ai_family == AF_INET6) {
|
||||
addr->address_type = RAVA_INETADDRESS_IPV6;
|
||||
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6*)res->ai_addr;
|
||||
memcpy(addr->address, &ipv6->sin6_addr, 16);
|
||||
char ip[INET6_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET6, &ipv6->sin6_addr, ip, sizeof(ip));
|
||||
addr->hostaddress = strdup(ip);
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
return addr;
|
||||
}
|
||||
|
||||
RavaInetAddress_t* rava_inetaddress_get_local_host(void) {
|
||||
char hostname[256];
|
||||
if (gethostname(hostname, sizeof(hostname)) != 0) {
|
||||
return rava_inetaddress_get_loopback();
|
||||
}
|
||||
RavaInetAddress_t *addr = rava_inetaddress_get_by_name(hostname);
|
||||
if (!addr) {
|
||||
return rava_inetaddress_get_loopback();
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
RavaInetAddress_t* rava_inetaddress_get_loopback(void) {
|
||||
RavaInetAddress_t *addr = rava_inetaddress_create();
|
||||
if (!addr) return NULL;
|
||||
|
||||
addr->address_type = RAVA_INETADDRESS_IPV4;
|
||||
addr->address[0] = 127;
|
||||
addr->address[1] = 0;
|
||||
addr->address[2] = 0;
|
||||
addr->address[3] = 1;
|
||||
addr->hostname = strdup("localhost");
|
||||
addr->hostaddress = strdup("127.0.0.1");
|
||||
return addr;
|
||||
}
|
||||
|
||||
char* rava_inetaddress_get_host_name(RavaInetAddress_t *addr) {
|
||||
if (!addr) return NULL;
|
||||
if (addr->hostname) return addr->hostname;
|
||||
|
||||
char host[NI_MAXHOST];
|
||||
struct sockaddr_in sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sin_family = AF_INET;
|
||||
memcpy(&sa.sin_addr, addr->address, 4);
|
||||
|
||||
int result = getnameinfo((struct sockaddr*)&sa, sizeof(sa), host, sizeof(host), NULL, 0, 0);
|
||||
if (result == 0) {
|
||||
addr->hostname = strdup(host);
|
||||
return addr->hostname;
|
||||
}
|
||||
return addr->hostaddress;
|
||||
}
|
||||
|
||||
char* rava_inetaddress_get_host_address(RavaInetAddress_t *addr) {
|
||||
if (!addr) return NULL;
|
||||
if (addr->hostaddress) return addr->hostaddress;
|
||||
|
||||
char ip[INET6_ADDRSTRLEN];
|
||||
if (addr->address_type == RAVA_INETADDRESS_IPV4) {
|
||||
inet_ntop(AF_INET, addr->address, ip, sizeof(ip));
|
||||
} else {
|
||||
inet_ntop(AF_INET6, addr->address, ip, sizeof(ip));
|
||||
}
|
||||
addr->hostaddress = strdup(ip);
|
||||
return addr->hostaddress;
|
||||
}
|
||||
|
||||
bool rava_inetaddress_is_loopback(RavaInetAddress_t *addr) {
|
||||
if (!addr) return false;
|
||||
if (addr->address_type == RAVA_INETADDRESS_IPV4) {
|
||||
return addr->address[0] == 127;
|
||||
}
|
||||
static const uint8_t ipv6_loopback[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
|
||||
return memcmp(addr->address, ipv6_loopback, 16) == 0;
|
||||
}
|
||||
|
||||
bool rava_inetaddress_is_any_local(RavaInetAddress_t *addr) {
|
||||
if (!addr) return false;
|
||||
if (addr->address_type == RAVA_INETADDRESS_IPV4) {
|
||||
return addr->address[0] == 0 && addr->address[1] == 0 &&
|
||||
addr->address[2] == 0 && addr->address[3] == 0;
|
||||
}
|
||||
static const uint8_t ipv6_any[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
return memcmp(addr->address, ipv6_any, 16) == 0;
|
||||
}
|
||||
|
||||
int rava_socket_get_port(RavaSocket_t *socket) {
|
||||
if (!socket || socket->fd < 0) return -1;
|
||||
|
||||
struct sockaddr_in addr;
|
||||
socklen_t len = sizeof(addr);
|
||||
if (getpeername(socket->fd, (struct sockaddr*)&addr, &len) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return ntohs(addr.sin_port);
|
||||
}
|
||||
|
||||
int rava_socket_get_local_port(RavaSocket_t *socket) {
|
||||
if (!socket || socket->fd < 0) return -1;
|
||||
|
||||
struct sockaddr_in addr;
|
||||
socklen_t len = sizeof(addr);
|
||||
if (getsockname(socket->fd, (struct sockaddr*)&addr, &len) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return ntohs(addr.sin_port);
|
||||
}
|
||||
|
||||
RavaInetAddress_t* rava_socket_get_inet_address(RavaSocket_t *socket) {
|
||||
if (!socket || socket->fd < 0) return NULL;
|
||||
|
||||
struct sockaddr_in addr;
|
||||
socklen_t len = sizeof(addr);
|
||||
if (getpeername(socket->fd, (struct sockaddr*)&addr, &len) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RavaInetAddress_t *inet_addr = rava_inetaddress_create();
|
||||
if (!inet_addr) return NULL;
|
||||
|
||||
inet_addr->address_type = RAVA_INETADDRESS_IPV4;
|
||||
memcpy(inet_addr->address, &addr.sin_addr, 4);
|
||||
|
||||
char ip[INET_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET, &addr.sin_addr, ip, sizeof(ip));
|
||||
inet_addr->hostaddress = strdup(ip);
|
||||
|
||||
return inet_addr;
|
||||
}
|
||||
|
||||
RavaInetAddress_t* rava_socket_get_local_address(RavaSocket_t *socket) {
|
||||
if (!socket || socket->fd < 0) return NULL;
|
||||
|
||||
struct sockaddr_in addr;
|
||||
socklen_t len = sizeof(addr);
|
||||
if (getsockname(socket->fd, (struct sockaddr*)&addr, &len) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RavaInetAddress_t *inet_addr = rava_inetaddress_create();
|
||||
if (!inet_addr) return NULL;
|
||||
|
||||
inet_addr->address_type = RAVA_INETADDRESS_IPV4;
|
||||
memcpy(inet_addr->address, &addr.sin_addr, 4);
|
||||
|
||||
char ip[INET_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET, &addr.sin_addr, ip, sizeof(ip));
|
||||
inet_addr->hostaddress = strdup(ip);
|
||||
|
||||
return inet_addr;
|
||||
}
|
||||
|
||||
int rava_server_socket_get_local_port(RavaSocket_t *socket) {
|
||||
return rava_socket_get_local_port(socket);
|
||||
}
|
||||
|
||||
bool rava_server_socket_is_bound(RavaSocket_t *socket) {
|
||||
if (!socket || socket->fd < 0) return false;
|
||||
return socket->bound;
|
||||
}
|
||||
|
||||
bool rava_server_socket_is_closed(RavaSocket_t *socket) {
|
||||
if (!socket) return true;
|
||||
return socket->closed;
|
||||
}
|
||||
|
||||
void rava_server_socket_set_so_timeout(RavaSocket_t *socket, int timeout) {
|
||||
if (!socket || socket->fd < 0) return;
|
||||
struct timeval tv;
|
||||
tv.tv_sec = timeout / 1000;
|
||||
tv.tv_usec = (timeout % 1000) * 1000;
|
||||
setsockopt(socket->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||
}
|
||||
|
||||
int rava_server_socket_get_so_timeout(RavaSocket_t *socket) {
|
||||
if (!socket || socket->fd < 0) return 0;
|
||||
struct timeval tv;
|
||||
socklen_t len = sizeof(tv);
|
||||
if (getsockopt(socket->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &len) < 0) {
|
||||
return 0;
|
||||
}
|
||||
return (int)(tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||
}
|
||||
|
||||
void rava_socket_set_so_timeout(RavaSocket_t *socket, int timeout_ms) {
|
||||
if (!socket || socket->fd < 0) return;
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = timeout_ms / 1000;
|
||||
tv.tv_usec = (timeout_ms % 1000) * 1000;
|
||||
|
||||
setsockopt(socket->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||
setsockopt(socket->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
|
||||
}
|
||||
|
||||
int rava_socket_get_so_timeout(RavaSocket_t *socket) {
|
||||
if (!socket || socket->fd < 0) return 0;
|
||||
|
||||
struct timeval tv;
|
||||
socklen_t len = sizeof(tv);
|
||||
if (getsockopt(socket->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &len) < 0) {
|
||||
return 0;
|
||||
}
|
||||
return (int)(tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||
}
|
||||
|
||||
void rava_socket_set_tcp_nodelay(RavaSocket_t *socket, bool nodelay) {
|
||||
if (!socket || socket->fd < 0) return;
|
||||
|
||||
int flag = nodelay ? 1 : 0;
|
||||
setsockopt(socket->fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
|
||||
}
|
||||
|
||||
bool rava_socket_get_tcp_nodelay(RavaSocket_t *socket) {
|
||||
if (!socket || socket->fd < 0) return false;
|
||||
|
||||
int flag = 0;
|
||||
socklen_t len = sizeof(flag);
|
||||
if (getsockopt(socket->fd, IPPROTO_TCP, TCP_NODELAY, &flag, &len) < 0) {
|
||||
return false;
|
||||
}
|
||||
return flag != 0;
|
||||
}
|
||||
|
||||
void rava_socket_bind(RavaSocket_t *socket, const char *host, int port) {
|
||||
if (!socket || socket->fd < 0) return;
|
||||
if (socket->bound) return;
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
if (host && strcmp(host, "0.0.0.0") != 0) {
|
||||
if (inet_pton(AF_INET, host, &addr.sin_addr) <= 0) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
|
||||
if (bind(socket->fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
|
||||
socket->bound = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool rava_socket_is_connected(RavaSocket_t *socket) {
|
||||
if (!socket) return false;
|
||||
return socket->connected && !socket->closed;
|
||||
}
|
||||
|
||||
bool rava_socket_is_closed(RavaSocket_t *socket) {
|
||||
if (!socket) return true;
|
||||
return socket->closed;
|
||||
}
|
||||
|
||||
bool rava_socket_is_bound(RavaSocket_t *socket) {
|
||||
if (!socket) return false;
|
||||
return socket->bound;
|
||||
}
|
||||
|
||||
void rava_socket_shutdown_input(RavaSocket_t *socket) {
|
||||
if (!socket || socket->fd < 0) return;
|
||||
if (socket->input_shutdown) return;
|
||||
|
||||
shutdown(socket->fd, SHUT_RD);
|
||||
socket->input_shutdown = true;
|
||||
}
|
||||
|
||||
void rava_socket_shutdown_output(RavaSocket_t *socket) {
|
||||
if (!socket || socket->fd < 0) return;
|
||||
if (socket->output_shutdown) return;
|
||||
|
||||
shutdown(socket->fd, SHUT_WR);
|
||||
socket->output_shutdown = true;
|
||||
}
|
||||
|
||||
bool rava_socket_is_input_shutdown(RavaSocket_t *socket) {
|
||||
if (!socket) return false;
|
||||
return socket->input_shutdown;
|
||||
}
|
||||
|
||||
bool rava_socket_is_output_shutdown(RavaSocket_t *socket) {
|
||||
if (!socket) return false;
|
||||
return socket->output_shutdown;
|
||||
}
|
||||
|
||||
void rava_socket_set_send_buffer_size(RavaSocket_t *socket, int size) {
|
||||
if (!socket || socket->fd < 0) return;
|
||||
setsockopt(socket->fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
|
||||
}
|
||||
|
||||
int rava_socket_get_send_buffer_size(RavaSocket_t *socket) {
|
||||
if (!socket || socket->fd < 0) return 0;
|
||||
int size = 0;
|
||||
socklen_t len = sizeof(size);
|
||||
if (getsockopt(socket->fd, SOL_SOCKET, SO_SNDBUF, &size, &len) == 0) {
|
||||
return size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rava_socket_set_receive_buffer_size(RavaSocket_t *socket, int size) {
|
||||
if (!socket || socket->fd < 0) return;
|
||||
setsockopt(socket->fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
|
||||
}
|
||||
|
||||
int rava_socket_get_receive_buffer_size(RavaSocket_t *socket) {
|
||||
if (!socket || socket->fd < 0) return 0;
|
||||
int size = 0;
|
||||
socklen_t len = sizeof(size);
|
||||
if (getsockopt(socket->fd, SOL_SOCKET, SO_RCVBUF, &size, &len) == 0) {
|
||||
return size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rava_socket_set_keep_alive(RavaSocket_t *socket, bool keepalive) {
|
||||
if (!socket || socket->fd < 0) return;
|
||||
int val = keepalive ? 1 : 0;
|
||||
setsockopt(socket->fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
|
||||
}
|
||||
|
||||
bool rava_socket_get_keep_alive(RavaSocket_t *socket) {
|
||||
if (!socket || socket->fd < 0) return false;
|
||||
int val = 0;
|
||||
socklen_t len = sizeof(val);
|
||||
if (getsockopt(socket->fd, SOL_SOCKET, SO_KEEPALIVE, &val, &len) == 0) {
|
||||
return val != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void rava_socket_set_reuse_address(RavaSocket_t *socket, bool reuse) {
|
||||
if (!socket || socket->fd < 0) return;
|
||||
int val = reuse ? 1 : 0;
|
||||
setsockopt(socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
||||
}
|
||||
|
||||
bool rava_socket_get_reuse_address(RavaSocket_t *socket) {
|
||||
if (!socket || socket->fd < 0) return false;
|
||||
int val = 0;
|
||||
socklen_t len = sizeof(val);
|
||||
if (getsockopt(socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, &len) == 0) {
|
||||
return val != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
#include "runtime_internal.h"
|
||||
|
||||
RavaStack_t* rava_stack_create(size_t capacity) {
|
||||
RavaStack_t *stack = malloc(sizeof(RavaStack_t));
|
||||
if (!stack) return NULL;
|
||||
stack->capacity = capacity;
|
||||
stack->values = malloc(sizeof(RavaValue_t) * capacity);
|
||||
if (!stack->values) {
|
||||
free(stack);
|
||||
return NULL;
|
||||
}
|
||||
stack->top = 0;
|
||||
return stack;
|
||||
}
|
||||
|
||||
void rava_stack_destroy(RavaStack_t *stack) {
|
||||
if (!stack) return;
|
||||
free(stack->values);
|
||||
free(stack);
|
||||
}
|
||||
|
||||
void rava_stack_push(RavaStack_t *stack, RavaValue_t value) {
|
||||
if (stack->top >= stack->capacity) {
|
||||
stack->capacity *= 2;
|
||||
RavaValue_t *new_values = rava_safe_realloc(stack->values, sizeof(RavaValue_t) * stack->capacity);
|
||||
if (!new_values) return;
|
||||
stack->values = new_values;
|
||||
}
|
||||
stack->values[stack->top++] = value;
|
||||
}
|
||||
|
||||
RavaValue_t rava_stack_pop(RavaStack_t *stack) {
|
||||
if (stack->top == 0) {
|
||||
return rava_value_int(0);
|
||||
}
|
||||
return stack->values[--stack->top];
|
||||
}
|
||||
|
||||
RavaValue_t rava_stack_peek(RavaStack_t *stack) {
|
||||
if (stack->top == 0) {
|
||||
return rava_value_int(0);
|
||||
}
|
||||
return stack->values[stack->top - 1];
|
||||
}
|
||||
|
||||
bool rava_stack_is_empty(RavaStack_t *stack) {
|
||||
return stack->top == 0;
|
||||
}
|
||||
|
||||
RavaCallFrame_t* rava_call_frame_create(RavaMethod_t *method) {
|
||||
RavaCallFrame_t *frame = calloc(1, sizeof(RavaCallFrame_t));
|
||||
if (!frame) return NULL;
|
||||
frame->method = method;
|
||||
frame->local_count = method->local_count;
|
||||
frame->locals = calloc(method->local_count, sizeof(RavaValue_t));
|
||||
if (!frame->locals && method->local_count > 0) {
|
||||
free(frame);
|
||||
return NULL;
|
||||
}
|
||||
frame->pc = 0;
|
||||
size_t stack_size = method->max_stack > 0 ? (size_t)method->max_stack : 64;
|
||||
frame->operand_stack = rava_stack_create(stack_size);
|
||||
if (!frame->operand_stack) {
|
||||
free(frame->locals);
|
||||
free(frame);
|
||||
return NULL;
|
||||
}
|
||||
frame->has_this = false;
|
||||
frame->this_ref = rava_value_null();
|
||||
return frame;
|
||||
}
|
||||
|
||||
void rava_call_frame_destroy(RavaCallFrame_t *frame) {
|
||||
if (!frame) return;
|
||||
free(frame->locals);
|
||||
rava_stack_destroy(frame->operand_stack);
|
||||
free(frame);
|
||||
}
|
||||
|
||||
RavaCallStack_t* rava_call_stack_create(void) {
|
||||
RavaCallStack_t *stack = malloc(sizeof(RavaCallStack_t));
|
||||
if (!stack) return NULL;
|
||||
stack->capacity = 256;
|
||||
stack->frames = malloc(sizeof(RavaCallFrame_t*) * stack->capacity);
|
||||
if (!stack->frames) {
|
||||
free(stack);
|
||||
return NULL;
|
||||
}
|
||||
stack->count = 0;
|
||||
return stack;
|
||||
}
|
||||
|
||||
void rava_call_stack_destroy(RavaCallStack_t *stack) {
|
||||
if (!stack) return;
|
||||
for (size_t i = 0; i < stack->count; i++) {
|
||||
rava_call_frame_destroy(stack->frames[i]);
|
||||
}
|
||||
free(stack->frames);
|
||||
free(stack);
|
||||
}
|
||||
|
||||
#define RAVA_MAX_CALL_STACK_DEPTH 10000
|
||||
|
||||
bool rava_call_stack_push(RavaCallStack_t *stack, RavaCallFrame_t *frame) {
|
||||
if (stack->count >= RAVA_MAX_CALL_STACK_DEPTH) {
|
||||
return false;
|
||||
}
|
||||
if (stack->count >= stack->capacity) {
|
||||
stack->capacity *= 2;
|
||||
RavaCallFrame_t **new_frames = rava_safe_realloc(stack->frames, sizeof(RavaCallFrame_t*) * stack->capacity);
|
||||
if (!new_frames) return false;
|
||||
stack->frames = new_frames;
|
||||
}
|
||||
stack->frames[stack->count++] = frame;
|
||||
return true;
|
||||
}
|
||||
|
||||
RavaCallFrame_t* rava_call_stack_pop(RavaCallStack_t *stack) {
|
||||
if (stack->count == 0) return NULL;
|
||||
RavaCallFrame_t *frame = stack->frames[--stack->count];
|
||||
return frame;
|
||||
}
|
||||
|
||||
RavaCallFrame_t* rava_call_stack_current(RavaCallStack_t *stack) {
|
||||
if (stack->count == 0) return NULL;
|
||||
return stack->frames[stack->count - 1];
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
#include "runtime_internal.h"
|
||||
|
||||
RavaStaticFieldTable_t* rava_static_field_table_create(void) {
|
||||
RavaStaticFieldTable_t *table = malloc(sizeof(RavaStaticFieldTable_t));
|
||||
if (!table) return NULL;
|
||||
table->capacity = 16;
|
||||
table->fields = calloc(table->capacity, sizeof(RavaStaticField_t));
|
||||
if (!table->fields) {
|
||||
free(table);
|
||||
return NULL;
|
||||
}
|
||||
table->count = 0;
|
||||
for (int i = 0; i < RAVA_STATIC_HASH_SIZE; i++) {
|
||||
table->hash_table[i] = -1;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
void rava_static_field_table_destroy(RavaStaticFieldTable_t *table) {
|
||||
if (!table) return;
|
||||
for (size_t i = 0; i < table->count; i++) {
|
||||
free(table->fields[i].class_name);
|
||||
free(table->fields[i].field_name);
|
||||
}
|
||||
free(table->fields);
|
||||
free(table);
|
||||
}
|
||||
|
||||
RavaValue_t* rava_static_field_table_get(RavaStaticFieldTable_t *table,
|
||||
const char *class_name,
|
||||
const char *field_name) {
|
||||
uint32_t hash = _rava_static_hash(class_name, field_name);
|
||||
|
||||
for (size_t probe = 0; probe < RAVA_STATIC_HASH_SIZE; probe++) {
|
||||
uint32_t slot = (hash + probe) & (RAVA_STATIC_HASH_SIZE - 1);
|
||||
int idx = table->hash_table[slot];
|
||||
|
||||
if (idx == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((size_t)idx < table->count &&
|
||||
strcmp(table->fields[idx].class_name, class_name) == 0 &&
|
||||
strcmp(table->fields[idx].field_name, field_name) == 0) {
|
||||
return &table->fields[idx].value;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void rava_static_field_table_set(RavaStaticFieldTable_t *table,
|
||||
const char *class_name,
|
||||
const char *field_name,
|
||||
RavaValue_t value) {
|
||||
uint32_t hash = _rava_static_hash(class_name, field_name);
|
||||
|
||||
for (size_t probe = 0; probe < RAVA_STATIC_HASH_SIZE; probe++) {
|
||||
uint32_t slot = (hash + probe) & (RAVA_STATIC_HASH_SIZE - 1);
|
||||
int idx = table->hash_table[slot];
|
||||
|
||||
if (idx == -1) {
|
||||
if (table->count >= table->capacity) {
|
||||
size_t new_cap = table->capacity * 2;
|
||||
RavaStaticField_t *new_fields = rava_safe_realloc(table->fields, sizeof(RavaStaticField_t) * new_cap);
|
||||
if (!new_fields) return;
|
||||
table->fields = new_fields;
|
||||
table->capacity = new_cap;
|
||||
}
|
||||
|
||||
table->fields[table->count].class_name = strdup(class_name);
|
||||
table->fields[table->count].field_name = strdup(field_name);
|
||||
table->fields[table->count].value = value;
|
||||
table->hash_table[slot] = (int)table->count;
|
||||
table->count++;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((size_t)idx < table->count &&
|
||||
strcmp(table->fields[idx].class_name, class_name) == 0 &&
|
||||
strcmp(table->fields[idx].field_name, field_name) == 0) {
|
||||
table->fields[idx].value = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
#include "runtime_internal.h"
|
||||
|
||||
RavaValue_t rava_value_string(const char *str) {
|
||||
RavaValue_t val;
|
||||
val.type = RAVA_VAL_STRING;
|
||||
val.data.string_val = str ? strdup(str) : NULL;
|
||||
return val;
|
||||
}
|
||||
|
||||
const char* rava_value_as_string(RavaValue_t value) {
|
||||
if (value.type == RAVA_VAL_STRING) {
|
||||
return value.data.string_val ? value.data.string_val : "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
char* _rava_get_string_buffer(RavaVM_t *vm, size_t needed) {
|
||||
if (needed >= RAVA_STRING_BUFFER_SIZE) {
|
||||
return malloc(needed);
|
||||
}
|
||||
char *buf = vm->string_pool.buffers[vm->string_pool.current];
|
||||
vm->string_pool.current = (vm->string_pool.current + 1) % RAVA_STRING_BUFFER_COUNT;
|
||||
return buf;
|
||||
}
|
||||
|
||||
void _rava_object_set_field_vm(RavaObject_t *obj, const char *name, RavaValue_t value, RavaVM_t *vm) {
|
||||
if (!obj || !name) return;
|
||||
|
||||
uint32_t hash = _rava_field_hash(name);
|
||||
|
||||
for (size_t probe = 0; probe < RAVA_OBJECT_HASH_SIZE; probe++) {
|
||||
uint32_t idx = (hash + probe) & (RAVA_OBJECT_HASH_SIZE - 1);
|
||||
int field_idx = obj->field_hash[idx];
|
||||
|
||||
if (field_idx == -1) {
|
||||
if (obj->field_count >= obj->field_capacity) {
|
||||
size_t new_cap = obj->field_capacity * 2;
|
||||
char **new_names = rava_safe_realloc(obj->field_names, new_cap * sizeof(char*));
|
||||
RavaValue_t *new_values = rava_safe_realloc(obj->field_values, new_cap * sizeof(RavaValue_t));
|
||||
if (!new_names || !new_values) return;
|
||||
obj->field_names = new_names;
|
||||
obj->field_values = new_values;
|
||||
obj->field_capacity = new_cap;
|
||||
}
|
||||
obj->field_names[obj->field_count] = (char*)(vm ? _rava_intern_string(vm, name) : strdup(name));
|
||||
obj->field_values[obj->field_count] = value;
|
||||
obj->field_hash[idx] = (int)obj->field_count;
|
||||
obj->field_count++;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((size_t)field_idx < obj->field_count &&
|
||||
strcmp(obj->field_names[field_idx], name) == 0) {
|
||||
obj->field_values[field_idx] = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64_t rava_value_as_int(RavaValue_t value) {
|
||||
switch (value.type) {
|
||||
case RAVA_VAL_INT: return value.data.int_val;
|
||||
case RAVA_VAL_LONG: return value.data.long_val;
|
||||
case RAVA_VAL_FLOAT: return (int64_t)value.data.float_val;
|
||||
case RAVA_VAL_DOUBLE: return (int64_t)value.data.double_val;
|
||||
case RAVA_VAL_BOOLEAN: return value.data.bool_val ? 1 : 0;
|
||||
case RAVA_VAL_CHAR: return value.data.char_val;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t rava_value_as_long(RavaValue_t value) {
|
||||
switch (value.type) {
|
||||
case RAVA_VAL_INT: return value.data.int_val;
|
||||
case RAVA_VAL_LONG: return value.data.long_val;
|
||||
case RAVA_VAL_FLOAT: return (int64_t)value.data.float_val;
|
||||
case RAVA_VAL_DOUBLE: return (int64_t)value.data.double_val;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
double rava_value_as_double(RavaValue_t value) {
|
||||
switch (value.type) {
|
||||
case RAVA_VAL_INT: return value.data.int_val;
|
||||
case RAVA_VAL_LONG: return (double)value.data.long_val;
|
||||
case RAVA_VAL_FLOAT: return value.data.float_val;
|
||||
case RAVA_VAL_DOUBLE: return value.data.double_val;
|
||||
default: return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
bool rava_value_as_boolean(RavaValue_t value) {
|
||||
if (value.type == RAVA_VAL_BOOLEAN) {
|
||||
return value.data.bool_val;
|
||||
}
|
||||
return rava_value_as_int(value) != 0;
|
||||
}
|
||||
Reference in New Issue
Block a user