13 #define ALLOCATE_OBJECT(type, objectType) \
14 (type*)allocateObject(sizeof(type), objectType)
16 #ifndef KRK_DISABLE_THREADS
17 static volatile int _stringLock = 0;
18 static volatile int _objectLock = 0;
23 memset(
object,0,size);
26 _obtain_lock(_objectLock);
27 object->next =
vm.objects;
30 _release_lock(_objectLock);
32 object->hash = (uint32_t)((intptr_t)(object) >> 4 | ((intptr_t)
object & 0xf) << 28);
39 out[0] = (0xF0 | (value >> 18));
40 out[1] = (0x80 | ((value >> 12) & 0x3F));
41 out[2] = (0x80 | ((value >> 6) & 0x3F));
42 out[3] = (0x80 | ((value) & 0x3F));
44 }
else if (value > 0x7FF) {
45 out[0] = (0xE0 | (value >> 12));
46 out[1] = (0x80 | ((value >> 6) & 0x3F));
47 out[2] = (0x80 | (value & 0x3F));
49 }
else if (value > 0x7F) {
50 out[0] = (0xC0 | (value >> 6));
51 out[1] = (0x80 | (value & 0x3F));
54 out[0] = (
unsigned char)value;
62 static inline uint32_t decode(uint32_t* state, uint32_t* codep, uint32_t
byte) {
63 static const int state_table[32] = {
64 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
72 static const int mask_bytes[32] = {
73 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
74 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
75 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
82 static const int next[5] = {
90 if (*state == UTF8_ACCEPT) {
91 if (
byte >= 0x80 &&
byte <= 0xC1)
goto _reject;
92 *codep =
byte & mask_bytes[
byte >> 3];
93 *state = state_table[
byte >> 3];
94 }
else if (*state > 0) {
95 if (byte < 0x80 || byte >= 0xC0)
goto _reject;
96 *codep = (
byte & 0x3F) | (*codep << 6);
97 *state = next[*state];
101 *state = UTF8_REJECT;
105 static int checkString(
const char * chars,
size_t length,
size_t *codepointCount) {
107 uint32_t codepoint = 0;
108 unsigned char * end = (
unsigned char *)chars + length;
109 uint32_t maxCodepoint = 0;
110 for (
unsigned char * c = (
unsigned char *)chars; c < end; ++c) {
111 if (!decode(&state, &codepoint, *c)) {
112 if (codepoint > maxCodepoint) maxCodepoint = codepoint;
114 }
else if (state == UTF8_REJECT) {
115 _release_lock(_stringLock);
121 if (maxCodepoint > 0xFFFF) {
122 return KRK_OBJ_FLAGS_STRING_UCS4;
123 }
else if (maxCodepoint > 0xFF) {
124 return KRK_OBJ_FLAGS_STRING_UCS2;
125 }
else if (maxCodepoint > 0x7F) {
126 return KRK_OBJ_FLAGS_STRING_UCS1;
128 return KRK_OBJ_FLAGS_STRING_ASCII;
132 #define GENREADY(size,type) \
133 static void _readyUCS ## size (KrkString * string) { \
134 uint32_t state = 0; \
135 uint32_t codepoint = 0; \
136 unsigned char * end = (unsigned char *)string->chars + string->length; \
137 string->codes = malloc(sizeof(type) * string->codesLength); \
138 type *outPtr = (type *)string->codes; \
139 for (unsigned char * c = (unsigned char *)string->chars; c < end; ++c) { \
140 if (!decode(&state, &codepoint, *c)) { \
141 *(outPtr++) = (type)codepoint; \
142 } else if (state == UTF8_REJECT) { \
153 if (string->
codes)
return string->codes;
154 else if ((string->
obj.
flags & KRK_OBJ_FLAGS_STRING_MASK) == KRK_OBJ_FLAGS_STRING_UCS1) _readyUCS1(
string);
155 else if ((string->
obj.
flags & KRK_OBJ_FLAGS_STRING_MASK) == KRK_OBJ_FLAGS_STRING_UCS2) _readyUCS2(
string);
156 else if ((string->
obj.
flags & KRK_OBJ_FLAGS_STRING_MASK) == KRK_OBJ_FLAGS_STRING_UCS4) _readyUCS4(
string);
158 return string->codes;
163 switch (string->
obj.
flags & KRK_OBJ_FLAGS_STRING_MASK) {
164 case KRK_OBJ_FLAGS_STRING_ASCII:
165 case KRK_OBJ_FLAGS_STRING_UCS1:
return ((uint8_t*)string->
codes)[index];
166 case KRK_OBJ_FLAGS_STRING_UCS2:
return ((uint16_t*)string->
codes)[index];
167 case KRK_OBJ_FLAGS_STRING_UCS4:
return ((uint32_t*)string->
codes)[index];
174 static KrkString * allocateString(
char * chars,
size_t length, uint32_t hash) {
175 size_t codesLength = 0;
176 int type = checkString(chars,length,&codesLength);
181 string->length = length;
182 string->chars = chars;
183 string->obj.hash = hash;
184 string->obj.flags |= KRK_OBJ_FLAGS_VALID_HASH | type;
185 string->codesLength = codesLength;
186 string->codes = NULL;
187 if (type == KRK_OBJ_FLAGS_STRING_ASCII)
string->codes =
string->chars;
191 _release_lock(_stringLock);
195 static uint32_t hashString(
const char * key,
size_t length) {
199 for (
size_t i = 0; i < length; ++i) {
200 krk_hash_advance(hash,key[i]);
206 uint32_t hash = hashString(chars, length);
207 _obtain_lock(_stringLock);
209 if (interned != NULL) {
211 _release_lock(_stringLock);
217 KrkString * result = allocateString(chars, length, hash);
222 uint32_t hash = hashString(chars, length);
223 _obtain_lock(_stringLock);
226 _release_lock(_stringLock);
229 char * heapChars = ALLOCATE(
char, length + 1);
230 memcpy(heapChars, chars ? chars :
"", length);
231 heapChars[length] =
'\0';
232 KrkString * result = allocateString(heapChars, length, hash);
233 if (result->
chars != heapChars) free(heapChars);
234 _release_lock(_stringLock);
239 _obtain_lock(_stringLock);
241 if (interned != NULL) {
242 FREE_ARRAY(
char, chars, length + 1);
243 _release_lock(_stringLock);
247 string->length = length;
248 string->chars = chars;
249 string->obj.hash = hash;
250 string->obj.flags |= KRK_OBJ_FLAGS_VALID_HASH | type;
251 string->codesLength = codesLength;
252 string->codes = NULL;
253 if (type == KRK_OBJ_FLAGS_STRING_ASCII)
string->codes =
string->chars;
257 _release_lock(_stringLock);
267 codeobject->
name = NULL;
288 for (
size_t i = 0; i <
function->upvalueCount; ++i) {
297 if (IS_INSTANCE(globals)) {
298 if (AS_INSTANCE(globals)->_class ==
vm.baseClasses->dictClass) {
304 fprintf(stderr,
"Invalid globals context: %s\n",
krk_typeName(globals));
314 upvalue->
next = NULL;
315 upvalue->
closed = NONE_VAL();
328 _class->
base = baseClass;
341 instance->
_class = _class;
368 bytes->
bytes = ALLOCATE(uint8_t, length);
371 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)
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.
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.
Definitions for primitive stack references.
Core API for the bytecode virtual machine.
#define vm
Convenience macro for namespacing.
KrkValue krk_pop(void)
Pop the top of the stack.
threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
void krk_push(KrkValue value)
Push a stack value.