14 #define ALLOCATE_OBJECT(type, objectType) \
15 (type*)allocateObject(sizeof(type), objectType)
17 #ifndef KRK_DISABLE_THREADS
18 static volatile int _stringLock = 0;
19 static volatile int _objectLock = 0;
24 memset(
object,0,size);
27 _obtain_lock(_objectLock);
28 object->next =
vm.objects;
31 _release_lock(_objectLock);
33 object->hash = (uint32_t)((intptr_t)(object) >> 4 | ((intptr_t)
object & 0xf) << 28);
40 out[0] = (0xF0 | (value >> 18));
41 out[1] = (0x80 | ((value >> 12) & 0x3F));
42 out[2] = (0x80 | ((value >> 6) & 0x3F));
43 out[3] = (0x80 | ((value) & 0x3F));
45 }
else if (value > 0x7FF) {
46 out[0] = (0xE0 | (value >> 12));
47 out[1] = (0x80 | ((value >> 6) & 0x3F));
48 out[2] = (0x80 | (value & 0x3F));
50 }
else if (value > 0x7F) {
51 out[0] = (0xC0 | (value >> 6));
52 out[1] = (0x80 | (value & 0x3F));
55 out[0] = (
unsigned char)value;
63 static inline uint32_t decode(uint32_t* state, uint32_t* codep, uint32_t
byte) {
64 static const int state_table[32] = {
65 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
73 static const int mask_bytes[32] = {
74 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
75 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
76 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
83 static const int next[5] = {
91 if (*state == UTF8_ACCEPT) {
92 if (
byte >= 0x80 &&
byte <= 0xC1)
goto _reject;
93 *codep =
byte & mask_bytes[
byte >> 3];
94 *state = state_table[
byte >> 3];
95 }
else if (*state > 0) {
96 if (byte < 0x80 || byte >= 0xC0)
goto _reject;
97 *codep = (
byte & 0x3F) | (*codep << 6);
98 *state = next[*state];
102 *state = UTF8_REJECT;
106 static int checkString(
const char * chars,
size_t length,
size_t *codepointCount) {
108 uint32_t codepoint = 0;
109 unsigned char * end = (
unsigned char *)chars + length;
110 uint32_t maxCodepoint = 0;
111 for (
unsigned char * c = (
unsigned char *)chars; c < end; ++c) {
112 if (!decode(&state, &codepoint, *c)) {
113 if (codepoint > maxCodepoint) maxCodepoint = codepoint;
115 }
else if (state == UTF8_REJECT) {
116 _release_lock(_stringLock);
122 if (maxCodepoint > 0xFFFF) {
123 return KRK_OBJ_FLAGS_STRING_UCS4;
124 }
else if (maxCodepoint > 0xFF) {
125 return KRK_OBJ_FLAGS_STRING_UCS2;
126 }
else if (maxCodepoint > 0x7F) {
127 return KRK_OBJ_FLAGS_STRING_UCS1;
129 return KRK_OBJ_FLAGS_STRING_ASCII;
133 #define GENREADY(size,type) \
134 static void _readyUCS ## size (KrkString * string) { \
135 uint32_t state = 0; \
136 uint32_t codepoint = 0; \
137 unsigned char * end = (unsigned char *)string->chars + string->length; \
138 string->codes = malloc(sizeof(type) * string->codesLength); \
139 type *outPtr = (type *)string->codes; \
140 for (unsigned char * c = (unsigned char *)string->chars; c < end; ++c) { \
141 if (!decode(&state, &codepoint, *c)) { \
142 *(outPtr++) = (type)codepoint; \
143 } else if (state == UTF8_REJECT) { \
154 if (string->
codes)
return string->codes;
155 else if ((string->
obj.
flags & KRK_OBJ_FLAGS_STRING_MASK) == KRK_OBJ_FLAGS_STRING_UCS1) _readyUCS1(
string);
156 else if ((string->
obj.
flags & KRK_OBJ_FLAGS_STRING_MASK) == KRK_OBJ_FLAGS_STRING_UCS2) _readyUCS2(
string);
157 else if ((string->
obj.
flags & KRK_OBJ_FLAGS_STRING_MASK) == KRK_OBJ_FLAGS_STRING_UCS4) _readyUCS4(
string);
159 return string->codes;
164 switch (string->
obj.
flags & KRK_OBJ_FLAGS_STRING_MASK) {
165 case KRK_OBJ_FLAGS_STRING_ASCII:
166 case KRK_OBJ_FLAGS_STRING_UCS1:
return ((uint8_t*)string->
codes)[index];
167 case KRK_OBJ_FLAGS_STRING_UCS2:
return ((uint16_t*)string->
codes)[index];
168 case KRK_OBJ_FLAGS_STRING_UCS4:
return ((uint32_t*)string->
codes)[index];
177 static KrkString * allocateString(
char * chars,
size_t length, uint32_t hash) {
178 size_t codesLength = 0;
179 int type = checkString(chars,length,&codesLength);
184 string->length = length;
185 string->chars = chars;
186 string->obj.hash = hash;
187 string->obj.flags |= KRK_OBJ_FLAGS_VALID_HASH | type;
188 string->codesLength = codesLength;
189 string->codes = NULL;
190 if (type == KRK_OBJ_FLAGS_STRING_ASCII)
string->codes =
string->chars;
192 krk_tableSetExact(&
vm.strings, OBJECT_VAL(
string), NONE_VAL());
194 _release_lock(_stringLock);
198 static uint32_t hashString(
const char * key,
size_t length) {
202 for (
size_t i = 0; i < length; ++i) {
203 krk_hash_advance(hash,key[i]);
209 uint32_t hash = hashString(chars, length);
210 _obtain_lock(_stringLock);
212 if (interned != NULL) {
214 _release_lock(_stringLock);
220 KrkString * result = allocateString(chars, length, hash);
225 uint32_t hash = hashString(chars, length);
226 _obtain_lock(_stringLock);
229 _release_lock(_stringLock);
232 char * heapChars = KRK_ALLOCATE(
char, length + 1);
233 memcpy(heapChars, chars ? chars :
"", length);
234 heapChars[length] =
'\0';
235 KrkString * result = allocateString(heapChars, length, hash);
236 if (result->
chars != heapChars) free(heapChars);
237 _release_lock(_stringLock);
242 _obtain_lock(_stringLock);
244 if (interned != NULL) {
245 KRK_FREE_ARRAY(
char, chars, length + 1);
246 _release_lock(_stringLock);
250 string->length = length;
251 string->chars = chars;
252 string->obj.hash = hash;
253 string->obj.flags |= KRK_OBJ_FLAGS_VALID_HASH | type;
254 string->codesLength = codesLength;
255 string->codes = NULL;
256 if (type == KRK_OBJ_FLAGS_STRING_ASCII)
string->codes =
string->chars;
258 krk_tableSetExact(&
vm.strings, OBJECT_VAL(
string), NONE_VAL());
260 _release_lock(_stringLock);
270 codeobject->
name = NULL;
292 for (
size_t i = 0; i <
function->upvalueCount; ++i) {
301 if (IS_INSTANCE(globals)) {
302 if (AS_INSTANCE(globals)->_class ==
vm.baseClasses->dictClass) {
308 fprintf(stderr,
"Invalid globals context: %s\n",
krk_typeName(globals));
318 upvalue->
next = NULL;
319 upvalue->
closed = NONE_VAL();
332 _class->
base = baseClass;
345 instance->
_class = _class;
372 bytes->
bytes = KRK_ALLOCATE(uint8_t, length);
375 memcpy(bytes->
bytes, source, length);
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Functions for dealing with garbage collection and memory allocation.
void * krk_reallocate(void *ptr, size_t old, size_t new)
Resize an allocated heap object.
void krk_gcTakeBytes(const void *ptr, size_t size)
Assume ownership of size bytes at ptr.
Struct definitions for core object types.
KrkStringType
String compact storage type.
struct KrkInstance KrkInstance
An object of a class.
KrkObjType
Union tag for heap objects.
A function that has been attached to an object to serve as a method.
KrkBoundMethod * krk_newBoundMethod(KrkValue receiver, KrkObj *method)
Create a new bound method.
KrkValue receiver
Object to pass as implicit first argument.
KrkObj * method
Function to call.
Immutable sequence of bytes.
size_t length
Length of data in bytes.
uint8_t * bytes
Pointer to separately-stored bytes data.
KrkBytes * krk_newBytes(size_t length, uint8_t *source)
Create a new byte array.
void krk_initChunk(KrkChunk *chunk)
Initialize an opcode chunk.
KrkCleanupCallback _ongcsweep
C function to call when the garbage collector is discarding an instance of this class.
KrkClass * krk_newClass(KrkString *name, KrkClass *base)
Create a new class object.
KrkCleanupCallback _ongcscan
C function to call when the garbage collector visits an instance of this class in the scan phase.
KrkString * name
Name of the class.
struct KrkClass * base
Pointer to base class implementation.
KrkTable subclasses
Set of classes that subclass this class.
size_t allocSize
Size to allocate when creating instances of this class.
KrkTable methods
General attributes table.
KrkCodeObject * function
The codeobject containing the bytecode run when this function is called.
KrkValue globalsOwner
Owner of the globals table for this function.
size_t upvalueCount
Number of entries in upvalues.
KrkTable * globalsTable
Pointer to globals table with owner object.
KrkClosure * krk_newClosure(KrkCodeObject *function, KrkValue globals)
Create a new function object.
KrkValue annotations
Dictionary of type hints.
KrkUpvalue ** upvalues
Array of upvalues collected from the surrounding context when the closure was created.
KrkTable fields
Object attributes table.
unsigned short potentialPositionals
Precalculated positional arguments for complex argument processing.
KrkChunk chunk
Bytecode data.
size_t upvalueCount
Number of upvalues this function collects as a closure.
KrkValueArray positionalArgNames
Array of names for positional arguments (and *args)
KrkValue jumpTargets
Possibly a set of jump targets...
KrkLocalEntry * localNames
Stores the names of local variables used in the function, for debugging.
unsigned short keywordArgs
Arity of keyword (default) arguments.
unsigned short requiredArgs
Arity of required (non-default) arguments.
KrkString * docstring
Docstring attached to the function.
KrkValueArray keywordArgNames
Array of names for keyword-only arguments (and **kwargs)
KrkCodeObject * krk_newCodeObject(void)
Create a new, uninitialized code object.
size_t localNameCount
Number of entries in localNames.
KrkString * name
Name of the function.
KrkValue krk_dict_of(int argc, const KrkValue argv[], int hasKw)
Create a dict object.
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
KrkTable fields
Attributes table.
Managed binding to a C function.
const char * doc
Docstring to supply from __doc__.
const char * name
Name to use when repring.
NativeFn function
C function pointer.
KrkNative * krk_newNative(NativeFn function, const char *name, int type)
Create a native function binding object.
The most basic object type.
uint32_t hash
Cached hash value for table keys.
uint16_t flags
General object flags, mostly related to garbage collection.
Immutable sequence of Unicode codepoints.
uint32_t krk_unicodeCodepoint(KrkString *string, size_t index)
Obtain the codepoint at a given index in a string.
void * krk_unicodeString(KrkString *string)
Ensure that a codepoint representation of a string is available.
KrkString * krk_copyString(const char *chars, size_t length)
Obtain a string object representation of the given C string.
KrkString * krk_takeString(char *chars, size_t length)
Yield ownership of a C string to the GC and obtain a string object.
char * chars
UTF8 canonical data.
void * codes
Codepoint data.
KrkString * krk_takeStringVetted(char *chars, size_t length, size_t codesLength, KrkStringType type, uint32_t hash)
Like krk_takeString but for when the caller has already calculated code lengths, hash,...
size_t krk_codepointToBytes(krk_integer_type value, unsigned char *out)
Convert an integer codepoint to a UTF-8 byte representation.
Simple hash table of arbitrary keys to values.
void krk_initTable(KrkTable *table)
Initialize a hash table.
int krk_tableSet(KrkTable *table, KrkValue key, KrkValue value)
Assign a value to a key in a table.
struct KrkString * krk_tableFindString(KrkTable *table, const char *chars, size_t length, uint32_t hash)
Find a character sequence in the string interning table.
KrkValue scratchSpace[KRK_THREAD_SCRATCH_SIZE]
Immutable sequence of arbitrary values.
KrkValueArray values
Stores the length, capacity, and actual values of the tuple.
KrkTuple * krk_newTuple(size_t length)
Create a new tuple.
Storage for values referenced from nested functions.
int location
Stack offset or -1 if closed.
KrkValue closed
Heap storage for closed value.
struct KrkThreadState * owner
The thread that owns the stack this upvalue belongs in.
struct KrkUpvalue * next
Invasive linked list pointer to next upvalue.
KrkUpvalue * krk_newUpvalue(int slot)
Create an upvalue slot.
void krk_initValueArray(KrkValueArray *array)
Initialize a value array.
Stack reference or primative value.
const char * krk_typeName(KrkValue value)
Get the name of the type of a value.
Implementation of a generic hash table.
Convience header for providing atomic operations to threads.
Definitions for primitive stack references.
Core API for the bytecode virtual machine.
krk_threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
#define vm
Convenience macro for namespacing.
KrkValue krk_pop(void)
Pop the top of the stack.
void krk_push(KrkValue value)
Push a stack value.