Compare commits
5 Commits
master
...
c3629d7150
| Author | SHA1 | Date | |
|---|---|---|---|
| c3629d7150 | |||
| 3c3d2716a5 | |||
|
|
35f051b5da | ||
|
|
221a08e7dc | ||
|
|
84dcb63ea7 |
@@ -14,9 +14,7 @@ target_include_directories(njvm PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bigint/build
|
||||
# Add the library
|
||||
add_library(bigint STATIC ${CMAKE_SOURCE_DIR}/bigint/src/bigint.c
|
||||
support.c
|
||||
GC.c
|
||||
heap.c
|
||||
heap.h)
|
||||
GC.c)
|
||||
|
||||
# Include directories for the bigint library
|
||||
target_include_directories(bigint PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/bigint/build/include)
|
||||
|
||||
95
GC.c
95
GC.c
@@ -1,99 +1,14 @@
|
||||
#ifndef GC
|
||||
#define GC
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "stackslot.c"
|
||||
#include "stack.c"
|
||||
#include "bigint.h"
|
||||
#include <stdbool.h>
|
||||
#include "objref.c"
|
||||
#include "instruktion.c"
|
||||
#include "record.c"
|
||||
#include "SDA.c"
|
||||
|
||||
typedef struct {
|
||||
unsigned int freiZeiger;
|
||||
unsigned int size;
|
||||
unsigned char *data;
|
||||
} *heapPartRef;
|
||||
|
||||
// SDA
|
||||
struct sda sda;
|
||||
|
||||
// Stack
|
||||
struct stack stack;
|
||||
#define SIZE 1000;
|
||||
|
||||
//Register
|
||||
struct stack reg;
|
||||
#include "support.c"
|
||||
#include "bigint.h"
|
||||
|
||||
|
||||
//heapPartRef primary;
|
||||
//heapPartRef secondary;
|
||||
//unsigned int heapSize;
|
||||
//void initHeap(int size){
|
||||
// heapSize = 2 * sizeof (unsigned int) + size;
|
||||
// if ((primary = malloc(heapSize)) == NULL) perror("malloc");
|
||||
// if ((secondary = malloc(heapSize)) == NULL) perror("malloc");
|
||||
//}
|
||||
//
|
||||
//
|
||||
//// nimmt obj und copier es in den secondary Speicher
|
||||
//void copy(ObjRef obj){
|
||||
// if(obj->brokenHeart == true) return;
|
||||
// obj->brokenHeart = true;
|
||||
// if (IS_PRIMITIVE(obj)){
|
||||
// if(obj->size > secondary->size-secondary->freiZeiger) perror("Heap is to Small");
|
||||
// obj->forward_pointer = memcpy((void *) secondary->data[secondary->freiZeiger], obj, obj->size);
|
||||
// secondary->freiZeiger += obj->size;
|
||||
// } else {
|
||||
// if(sizeof(*obj) + (GET_ELEMENT_COUNT(obj) * sizeof(void *)) > secondary->size-secondary->freiZeiger) perror("Heap is to Small");
|
||||
// GET_ELEMENT_COUNT(obj);
|
||||
// obj->forward_pointer = memcpy((void *) secondary->data[secondary->freiZeiger], obj, sizeof(*obj) + (GET_ELEMENT_COUNT(obj) * sizeof(void *)));
|
||||
// secondary->freiZeiger += sizeof(*obj) + (GET_ELEMENT_COUNT(obj) * sizeof(void *));
|
||||
// for (int i = 0; i < GET_ELEMENT_COUNT(obj); ++i) {
|
||||
// copy(getField(obj,i));
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void runGC(){
|
||||
// int rootSize = *sda.size + *reg.size + *stack.size + 4;
|
||||
// ObjRef* rootObjs = malloc(sizeof(ObjRef) * rootSize);
|
||||
// if(rootObjs == NULL) perror("malloc");
|
||||
// int counter = 0;
|
||||
// //Bip
|
||||
// rootObjs[0] = bip.op1;
|
||||
// rootObjs[counter++] = bip.op2;
|
||||
// rootObjs[counter++] = bip.res;
|
||||
// rootObjs[counter++] = bip.rem;
|
||||
// //SDA
|
||||
// for (int i = 0; i < *sda.size; ++i) {
|
||||
// rootObjs[counter++] = sda.sda[i];
|
||||
// }
|
||||
// //REG
|
||||
// for (int i = 0; i < *reg.size; ++i) {
|
||||
// rootObjs[counter++] = reg.stack[i].u.objRef;
|
||||
// }
|
||||
// //STACK
|
||||
// for (int i = 0; i < *stack.size; ++i) {
|
||||
// rootObjs[counter++] = stack.stack[i].u.objRef;
|
||||
// }
|
||||
//
|
||||
// for (int i = 0; i < rootSize; ++i) {
|
||||
// if(rootObjs[i] == NULL) continue;
|
||||
// copy(rootObjs[i]);
|
||||
// }
|
||||
// heapPartRef temp = primary;
|
||||
// primary = secondary;
|
||||
// secondary = temp;
|
||||
//
|
||||
//}
|
||||
//
|
||||
//void *alloc(size_t size){
|
||||
// if(primary->size-primary->freiZeiger < size){
|
||||
// runGC();
|
||||
// }
|
||||
// primary->freiZeiger += size;
|
||||
// return (void *) primary->data[primary->freiZeiger - size];
|
||||
//}
|
||||
#endif
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -5,12 +5,15 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "support.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned int size; /* byte count of payload data */
|
||||
unsigned char data[1]; /* payload data, size as needed */
|
||||
typedef struct ObjRef{
|
||||
bool brokenHeart;
|
||||
struct ObjRef *forward_pointer;
|
||||
unsigned int size;
|
||||
unsigned char data[1];
|
||||
} *ObjRef;
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
33
heap.c
33
heap.c
@@ -1,33 +0,0 @@
|
||||
//
|
||||
// Created by Elias Bennour on 28.01.24.
|
||||
//
|
||||
|
||||
#ifndef HEAP
|
||||
#define HEAP
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int maxHeapSize = 8192 * 1024;
|
||||
|
||||
void* my_malloc(size_t size) {
|
||||
static size_t total_allocated = 0;
|
||||
|
||||
if (total_allocated + size > maxHeapSize) {
|
||||
perror("Memory limit exceeded\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void* ptr = malloc(size);
|
||||
if (ptr != NULL) {
|
||||
total_allocated += size;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void initHeap(int size) {
|
||||
maxHeapSize = size;
|
||||
}
|
||||
|
||||
#endif //NINJA_NJVM_H
|
||||
12
heap.h
12
heap.h
@@ -1,12 +0,0 @@
|
||||
//
|
||||
// Created by Elias Bennour on 28.01.24.
|
||||
//
|
||||
|
||||
#ifndef NINJA_HEAP_H
|
||||
#define NINJA_HEAP_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
void* my_malloc(size_t size);
|
||||
|
||||
#endif //NINJA_HEAP_H
|
||||
214
njvm.c
214
njvm.c
@@ -1,6 +1,3 @@
|
||||
#ifndef NJVM
|
||||
#define NJVM
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -11,15 +8,30 @@
|
||||
#include "debugMenu.c"
|
||||
#include "bigint.h"
|
||||
#include "record.c"
|
||||
#include "GC.c"
|
||||
#include "heap.c"
|
||||
#include "SDA.c"
|
||||
|
||||
// Debug
|
||||
int debug = 0;
|
||||
|
||||
// Purge Flag
|
||||
int purgeFlag = false;
|
||||
|
||||
// Heap Size
|
||||
int argVheapSizeKiB = 8192;
|
||||
|
||||
// Program
|
||||
struct program program;
|
||||
|
||||
// SDA
|
||||
struct sda sda;
|
||||
|
||||
// Stack
|
||||
struct stack stack;
|
||||
#define SIZE 10000
|
||||
|
||||
//Register
|
||||
struct stack reg;
|
||||
|
||||
unsigned fp;
|
||||
|
||||
void version(void) {
|
||||
@@ -39,7 +51,7 @@ void execute(struct program program) {
|
||||
ObjRef tempObj2;
|
||||
int tempInt;
|
||||
for (i = 0; i < *program.size; ++i) {
|
||||
if (debug == 1 || bp == i) debugMenu(fp, stack, &debug, i, &bp);
|
||||
//if (debug == 1 || bp == i) debugMenu(fp, stack, &debug, i, &bp);
|
||||
if(debug == 1) printf("(%i)",i);
|
||||
switch (program.program[i] >> 24) {
|
||||
case HALT:
|
||||
@@ -308,13 +320,191 @@ void execute(struct program program) {
|
||||
void tests(void) {
|
||||
}
|
||||
|
||||
/*
|
||||
* Garbage Collection
|
||||
*/
|
||||
|
||||
ObjRef *heap;
|
||||
int heapSizeKiB;
|
||||
char *memTargetPtr; //zielspeicherzeiger
|
||||
char *freeHeapPtr; //freizeiger
|
||||
char *halfHeapPtr; //halbspeicherende
|
||||
int gcCount = 0;
|
||||
|
||||
#define MSB (1 << (8 * sizeof(unsigned int) - 1))
|
||||
#define IS_PRIMITIVE(objRef) (((objRef)->size & MSB) == 0)
|
||||
#define GET_SIZE(objRef)((objRef)->size& ~MSB) //Gets the size of an ObjRef
|
||||
#define GET_REFS(objRef)((ObjRef *)((objRef)->data)) //Pointer on first ObjRef in Object
|
||||
|
||||
ObjRef copyObjectToFreeMem(ObjRef orig) {
|
||||
//printf("%s%d\n", "Size in CpyObj: ", GET_SIZE(orig) );
|
||||
int size;
|
||||
if (IS_PRIMITIVE(orig)) {
|
||||
size = GET_SIZE(orig);
|
||||
} else {
|
||||
size = sizeof(void *) + sizeof(unsigned int) + sizeof(bool) + GET_SIZE(orig) * sizeof(ObjRef *);
|
||||
}
|
||||
memcpy(freeHeapPtr, orig, size);
|
||||
ObjRef oldPtr = (ObjRef) freeHeapPtr;
|
||||
//printf("%s%d\n","size after memcpy ", GET_SIZE(oldPtr));
|
||||
//printf("%s%d\n","actual Size: ", size);
|
||||
//oldPtr->size = size;
|
||||
freeHeapPtr += size;
|
||||
return oldPtr;
|
||||
}
|
||||
|
||||
ObjRef relocate(ObjRef orig) {
|
||||
/* if (orig == NULL) {
|
||||
printf("%s\n", "null");
|
||||
} else {
|
||||
printf("%s%d\n","Size in relocate ", GET_SIZE(orig));
|
||||
}
|
||||
*/
|
||||
|
||||
ObjRef copy;
|
||||
if (orig == NULL) {
|
||||
/* relocate(nil) = nil */
|
||||
copy = NULL;
|
||||
} else {
|
||||
if (orig->brokenHeart == 1) {
|
||||
/* Objekt ist bereits kopiert */
|
||||
copy = orig->forwardPointer;
|
||||
//copy->size =orig->size;
|
||||
//printf("%s\n", "already copied");
|
||||
} else {
|
||||
/* Objekt muss noch kopiert werden*/
|
||||
copy = copyObjectToFreeMem(orig);
|
||||
orig->brokenHeart = true;
|
||||
orig->forwardPointer = copy;
|
||||
}
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
void scan(void) {
|
||||
char *scanPtr = memTargetPtr;
|
||||
while (scanPtr < freeHeapPtr) {
|
||||
/* es gibt noch Objekte, die
|
||||
* gescannt werden müssen.
|
||||
*/ ObjRef scanOr = (ObjRef) scanPtr;
|
||||
// printf("%d\n", GET_SIZE(scanOr));
|
||||
if (!IS_PRIMITIVE(scanOr)) {
|
||||
/* Ist ein Verbundobjekt */
|
||||
for (int i = 0; i < GET_SIZE(scanOr); i++) {
|
||||
GET_REFS(scanOr)[i] = relocate(GET_REFS(scanOr)[i]);
|
||||
}
|
||||
scanPtr += sizeof(bool) + (GET_SIZE(scanOr) * sizeof(ObjRef *)) + sizeof(unsigned int) + sizeof(void *);
|
||||
} else {
|
||||
//printf("%s %d\n", "is primitive, size: ", GET_SIZE(scanOr));
|
||||
scanPtr += GET_SIZE(scanOr);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void swap() {
|
||||
if (memTargetPtr == (char *) heap) {
|
||||
//printf("%s\n", "swapped to second half");
|
||||
freeHeapPtr = halfHeapPtr;
|
||||
memTargetPtr = halfHeapPtr;
|
||||
halfHeapPtr = ((char *) heap) + (heapSizeKiB * 1024);
|
||||
} else {
|
||||
//printf("%s\n", "swapped to first half");
|
||||
freeHeapPtr = ((char *) heap);
|
||||
memTargetPtr = ((char *) heap);
|
||||
halfHeapPtr = ((char *) heap) + ((heapSizeKiB * 1024) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
void garbageCollector() {
|
||||
char *memToPurgePtr = halfHeapPtr - ((heapSizeKiB * 1024) / 2);
|
||||
swap();
|
||||
//printf("%s\n", "stack");
|
||||
for (int i = 0; i < stack.current; i++) {
|
||||
if (stack.stack[i].isObjRef) {
|
||||
stack.stack[i].u.objRef = relocate(stack.stack[i].u.objRef);
|
||||
}
|
||||
}
|
||||
//printf("%s\n", "globals");
|
||||
for (int i = 0; i < sda.size; i++) {
|
||||
sda.sda[i] = relocate(sda.sda[i]);
|
||||
}
|
||||
//printf("%s\n", "retVal");
|
||||
//returnValue = relocate(returnValue);
|
||||
|
||||
//printf("%s\n", "op1");
|
||||
bip.op1 = relocate(bip.op1);
|
||||
ObjRef b = bip.op1;
|
||||
if(b!= NULL)
|
||||
//printf("%d\n", GET_SIZE(b));
|
||||
|
||||
//printf("%s\n", "op2");
|
||||
bip.op2 = relocate(bip.op2);
|
||||
b = bip.op2;
|
||||
if(b!= NULL)
|
||||
//printf("%d\n", GET_SIZE(b));
|
||||
|
||||
//printf("%s\n", "res");
|
||||
bip.res = relocate(bip.res);
|
||||
b = bip.res;
|
||||
if(b!= NULL)
|
||||
//printf("%d\n", GET_SIZE(b));
|
||||
|
||||
//printf("%s\n", "rem");
|
||||
bip.rem = relocate(bip.rem);
|
||||
b = bip.rem;
|
||||
if(b!= NULL)
|
||||
//printf("%d\n", GET_SIZE(b));
|
||||
|
||||
|
||||
scan();
|
||||
if (purgeFlag) {
|
||||
memset(memToPurgePtr, 0, heapSizeKiB * 1024 / 2);
|
||||
}
|
||||
gcCount++;
|
||||
}
|
||||
|
||||
ObjRef alloc(unsigned int size) {
|
||||
if (freeHeapPtr + size > halfHeapPtr) {
|
||||
garbageCollector();
|
||||
if (freeHeapPtr + size > halfHeapPtr) {
|
||||
fprintf(stderr, "Heap is full\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
ObjRef or;
|
||||
or = (ObjRef) freeHeapPtr;
|
||||
freeHeapPtr = freeHeapPtr + size;
|
||||
return or;
|
||||
}
|
||||
|
||||
void heapAllocator(int n) {
|
||||
heapSizeKiB = n;
|
||||
if ((heap = malloc(n * 1024)) == NULL) {
|
||||
perror("malloc");
|
||||
exit(1);
|
||||
}
|
||||
memTargetPtr = (char *) heap;
|
||||
freeHeapPtr = memTargetPtr;
|
||||
halfHeapPtr = (memTargetPtr + (n * 1024) / 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// Init the Heap
|
||||
//initHeap(1000);
|
||||
|
||||
// Initialize the Stack
|
||||
int size = SIZE;
|
||||
int current = 0;
|
||||
stack.size = &size;
|
||||
stack.current = ¤t;
|
||||
stack.stack = malloc(size * 1024);
|
||||
stack.stack = malloc(SIZE * 1024);
|
||||
if (stack.stack == NULL) {
|
||||
perror("malloc");
|
||||
}
|
||||
@@ -338,6 +528,7 @@ int main(int argc, char *argv[]) {
|
||||
int run = 0;
|
||||
int sizeSDA;
|
||||
|
||||
|
||||
if (argc > 1) {
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "--debug") == 0) {
|
||||
@@ -353,7 +544,7 @@ int main(int argc, char *argv[]) {
|
||||
// TODO: implement stack size
|
||||
} else if (strcmp(argv[i], "--heap") == 0) {
|
||||
i++;
|
||||
initHeap(atoi(argv[i]) * 1024);
|
||||
// TODO: implement heap size
|
||||
} else if (strcmp(argv[i], "--gcpurge") == 0) {
|
||||
// TODO: implement gcpurge
|
||||
} else {
|
||||
@@ -361,6 +552,11 @@ int main(int argc, char *argv[]) {
|
||||
run = 1;
|
||||
}
|
||||
}
|
||||
heapAllocator(argVheapSizeKiB);
|
||||
// Init the sda
|
||||
ObjRef s[sizeSDA];
|
||||
sda.size = &sizeSDA;
|
||||
sda.sda = s;
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
@@ -380,5 +576,3 @@ int main(int argc, char *argv[]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* ifndef NJVM */
|
||||
11
njvm.h
Normal file
11
njvm.h
Normal file
@@ -0,0 +1,11 @@
|
||||
//
|
||||
// Created by Elias Bennour on 28.01.24.
|
||||
//
|
||||
#include "objref.c"
|
||||
|
||||
#ifndef NINJA_NJVM_H
|
||||
#define NINJA_NJVM_H
|
||||
|
||||
ObjRef alloc(unsigned int size);
|
||||
|
||||
#endif //NINJA_NJVM_H
|
||||
9
objref.c
9
objref.c
@@ -1,12 +1,19 @@
|
||||
#ifndef OBJREF
|
||||
#define OBJREF
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct ObjRef{
|
||||
// if brkokenHeart and forward_pointer added at this point bip throws errors
|
||||
bool brokenHeart;
|
||||
struct ObjRef *forwardPointer;
|
||||
unsigned int size;
|
||||
unsigned char data[1];
|
||||
} *ObjRef;
|
||||
|
||||
typedef struct{
|
||||
unsigned char brokenHeart;
|
||||
ObjRef forward_pointer;
|
||||
} *ObjRefGC;
|
||||
|
||||
#endif /* ifndef OBJREF
|
||||
#define OBJREF */
|
||||
|
||||
6
record.c
6
record.c
@@ -5,11 +5,13 @@
|
||||
#define RECORD
|
||||
#include "stackslot.c"
|
||||
#include "instruktion.c"
|
||||
#include "njvm.h"
|
||||
|
||||
ObjRef newRecord(int size){
|
||||
ObjRef record;
|
||||
unsigned int objSize;
|
||||
objSize = sizeof(*record) + (size * sizeof(void *));
|
||||
if((record = my_malloc(objSize)) == NULL){
|
||||
if((record = alloc(objSize)) == NULL){
|
||||
perror("malloc");
|
||||
}
|
||||
record->size = MSB;
|
||||
@@ -47,7 +49,7 @@ void setField(ObjRef arr, int point, ObjRef value){
|
||||
else
|
||||
size = sizeof(*value) + (GET_ELEMENT_COUNT(value) * sizeof(void *));
|
||||
}
|
||||
if((GET_REFS_PTR(arr)[point] = my_malloc(size)) == NULL) perror("malloc");
|
||||
if((GET_REFS_PTR(arr)[point] = malloc(size)) == NULL) perror("malloc");
|
||||
GET_REFS_PTR(arr)[point] ->size = size;
|
||||
* (ObjRef *)GET_REFS_PTR(arr)[point]->data = value;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "objref.c"
|
||||
#include "heap.h"
|
||||
|
||||
typedef int Object;
|
||||
|
||||
@@ -20,7 +19,7 @@ typedef struct {
|
||||
ObjRef getIntObj(int val) {
|
||||
ObjRef intObject;
|
||||
unsigned int objSize = sizeof(ObjRef) + sizeof(int);
|
||||
if ((intObject = my_malloc(objSize)) == NULL) {
|
||||
if ((intObject = malloc(objSize)) == NULL) {
|
||||
perror("malloc");
|
||||
}
|
||||
*(int *) intObject->data = val;
|
||||
@@ -48,7 +47,7 @@ void setValIntObj(ObjRef iref, int val) {
|
||||
|
||||
StackSlot stackSlotWithObjRef(ObjRef val) {
|
||||
StackSlot *stackSlot;
|
||||
stackSlot = my_malloc(sizeof(StackSlot));
|
||||
stackSlot = malloc(sizeof(StackSlot));
|
||||
if(stackSlot == NULL) perror("malloc");
|
||||
stackSlot->isObjRef = true;
|
||||
stackSlot->u.objRef = val;
|
||||
@@ -57,7 +56,7 @@ StackSlot stackSlotWithObjRef(ObjRef val) {
|
||||
|
||||
StackSlot stackSlotWitchNumber(int val) {
|
||||
StackSlot *stackSlot;
|
||||
stackSlot = my_malloc(sizeof(StackSlot));
|
||||
stackSlot = malloc(sizeof(StackSlot));
|
||||
if(stackSlot == NULL) perror("malloc");
|
||||
stackSlot->isObjRef = false;
|
||||
stackSlot->u.number = val;
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#ifndef SUPPORT_C
|
||||
#define SUPPORT_C
|
||||
|
||||
#include "support.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "objref.c"
|
||||
#include "heap.h"
|
||||
#include "njvm.h"
|
||||
|
||||
void fatalError(char *msg){
|
||||
printf("Fatal error: %s\n", msg);
|
||||
@@ -13,7 +16,7 @@ void fatalError(char *msg){
|
||||
void * newPrimObject(int dataSize) {
|
||||
ObjRef bigObjRef;
|
||||
|
||||
bigObjRef = my_malloc(sizeof(unsigned int) +
|
||||
bigObjRef = alloc(sizeof(unsigned int) +
|
||||
dataSize * sizeof(unsigned char));
|
||||
if (bigObjRef == NULL) {
|
||||
fatalError("newPrimObject() got no memory");
|
||||
@@ -26,3 +29,5 @@ void * getPrimObjectDataPointer(void * obj){
|
||||
ObjRef oo = ((ObjRef) (obj));
|
||||
return oo->data;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user