Преглед изворни кода

Added more memory protection during allocation (vm parameter added to mem_alloc macro). Some code refactoring and other minor issues fixed. Version raised to 0.3.5.

Marco Bambini пре 8 година
родитељ
комит
0e0ac57571

+ 1 - 1
src/cli/gravity.c

@@ -213,7 +213,7 @@ int main (int argc, const char* argv[]) {
         
         // create closure to execute inline code
         if (type == OP_INLINE_RUN) {
-            char *buffer = mem_alloc(size+1024);
+            char *buffer = mem_alloc(NULL, size+1024);
             assert(buffer);
             size = snprintf(buffer, size+1024, "func main() {%s};", input_file);
             source_code = buffer;

+ 66 - 66
src/compiler/gravity_ast.c

@@ -20,19 +20,19 @@
 // MARK: -
 
 void_r *void_array_create (void) {
-	void_r *r = mem_alloc(sizeof(void_r));
+	void_r *r = mem_alloc(NULL, sizeof(void_r));
 	marray_init(*r);
 	return r;
 }
 
 cstring_r *cstring_array_create (void) {
-	cstring_r *r = mem_alloc(sizeof(cstring_r));
+	cstring_r *r = mem_alloc(NULL, sizeof(cstring_r));
 	gnode_array_init(r);
 	return r;
 }
 
 gnode_r *gnode_array_create (void) {
-	gnode_r *r = mem_alloc(sizeof(gnode_r));
+	gnode_r *r = mem_alloc(NULL, sizeof(gnode_r));
 	gnode_array_init(r);
 	return r;
 }
@@ -73,7 +73,7 @@ gnode_r *gnode_array_remove_byindex(gnode_r *old_list, size_t index) {
 gupvalue_t *gnode_function_add_upvalue(gnode_function_decl_t *f, gnode_var_t *symbol, uint16_t n) {
 	// create uplist if necessary
 	if (!f->uplist) {
-		f->uplist = mem_alloc(sizeof(gupvalue_r));
+		f->uplist = mem_alloc(NULL, sizeof(gupvalue_r));
 		gnode_array_init(f->uplist);
 	}
 	
@@ -85,7 +85,7 @@ gupvalue_t *gnode_function_add_upvalue(gnode_function_decl_t *f, gnode_var_t *sy
 	}, gupvalue_t *);
 	
 	// symbol not found in uplist so add it
-	gupvalue_t *upvalue = mem_alloc(sizeof(gupvalue_t));
+	gupvalue_t *upvalue = mem_alloc(NULL, sizeof(gupvalue_t));
 	upvalue->node = (gnode_t *)symbol;
 	upvalue->index = (n == 1) ? symbol->index : (uint32_t)gnode_array_size(f->uplist);
 	upvalue->selfindex = (uint32_t)gnode_array_size(f->uplist);
@@ -99,7 +99,7 @@ gupvalue_t *gnode_function_add_upvalue(gnode_function_decl_t *f, gnode_var_t *sy
 // MARK: - Statements initializers -
 
 gnode_t *gnode_jump_stat_create (gtoken_s token, gnode_t *expr, gnode_t *decl) {
-	gnode_jump_stmt_t *node = (gnode_jump_stmt_t *)mem_alloc(sizeof(gnode_jump_stmt_t));
+	gnode_jump_stmt_t *node = (gnode_jump_stmt_t *)mem_alloc(NULL, sizeof(gnode_jump_stmt_t));
 	
 	SETBASE(node, NODE_JUMP_STAT, token, NULL);
     SETDECL(node, decl);
@@ -108,7 +108,7 @@ gnode_t *gnode_jump_stat_create (gtoken_s token, gnode_t *expr, gnode_t *decl) {
 }
 
 gnode_t *gnode_label_stat_create (gtoken_s token, gnode_t *expr, gnode_t *stmt, gnode_t *decl) {
-	gnode_label_stmt_t *node = (gnode_label_stmt_t *)mem_alloc(sizeof(gnode_label_stmt_t));
+	gnode_label_stmt_t *node = (gnode_label_stmt_t *)mem_alloc(NULL, sizeof(gnode_label_stmt_t));
 	
 	SETBASE(node, NODE_LABEL_STAT, token, NULL);
     SETDECL(node, decl);
@@ -118,7 +118,7 @@ gnode_t *gnode_label_stat_create (gtoken_s token, gnode_t *expr, gnode_t *stmt,
 }
 
 gnode_t *gnode_flow_stat_create (gtoken_s token, gnode_t *cond, gnode_t *stmt1, gnode_t *stmt2, gnode_t *decl) {
-	gnode_flow_stmt_t *node = (gnode_flow_stmt_t *)mem_alloc(sizeof(gnode_flow_stmt_t));
+	gnode_flow_stmt_t *node = (gnode_flow_stmt_t *)mem_alloc(NULL, sizeof(gnode_flow_stmt_t));
 	
 	SETBASE(node, NODE_FLOW_STAT, token, NULL);
     SETDECL(node, decl);
@@ -129,7 +129,7 @@ gnode_t *gnode_flow_stat_create (gtoken_s token, gnode_t *cond, gnode_t *stmt1,
 }
 
 gnode_t *gnode_loop_stat_create (gtoken_s token, gnode_t *cond, gnode_t *stmt, gnode_t *expr, gnode_t *decl) {
-	gnode_loop_stmt_t *node = (gnode_loop_stmt_t *)mem_alloc(sizeof(gnode_loop_stmt_t));
+	gnode_loop_stmt_t *node = (gnode_loop_stmt_t *)mem_alloc(NULL, sizeof(gnode_loop_stmt_t));
 	
 	SETBASE(node, NODE_LOOP_STAT, token, NULL);
     SETDECL(node, decl);
@@ -141,7 +141,7 @@ gnode_t *gnode_loop_stat_create (gtoken_s token, gnode_t *cond, gnode_t *stmt, g
 }
 
 gnode_t *gnode_block_stat_create (gnode_n type, gtoken_s token, gnode_r *stmts, gnode_t *decl) {
-	gnode_compound_stmt_t *node = (gnode_compound_stmt_t *)mem_alloc(sizeof(gnode_compound_stmt_t));
+	gnode_compound_stmt_t *node = (gnode_compound_stmt_t *)mem_alloc(NULL, sizeof(gnode_compound_stmt_t));
 	
 	SETBASE(node, type, token, NULL);
     SETDECL(node, decl);
@@ -151,7 +151,7 @@ gnode_t *gnode_block_stat_create (gnode_n type, gtoken_s token, gnode_r *stmts,
 }
 
 gnode_t *gnode_empty_stat_create (gtoken_s token, gnode_t *decl) {
-	gnode_empty_stmt_t *node = (gnode_empty_stmt_t *)mem_alloc(sizeof(gnode_empty_stmt_t));
+	gnode_empty_stmt_t *node = (gnode_empty_stmt_t *)mem_alloc(NULL, sizeof(gnode_empty_stmt_t));
 	
 	SETBASE(node, NODE_EMPTY_STAT, token, NULL);
     SETDECL(node, decl);
@@ -161,7 +161,7 @@ gnode_t *gnode_empty_stat_create (gtoken_s token, gnode_t *decl) {
 // MARK: - Declarations initializers -
 
 gnode_t *gnode_class_decl_create (gtoken_s token, const char *identifier, gtoken_t access_specifier, gtoken_t storage_specifier, gnode_t *superclass, gnode_r *protocols, gnode_r *declarations, bool is_struct, void *meta, gnode_t *decl) {
-	gnode_class_decl_t *node = (gnode_class_decl_t *)mem_alloc(sizeof(gnode_class_decl_t));
+	gnode_class_decl_t *node = (gnode_class_decl_t *)mem_alloc(NULL, sizeof(gnode_class_decl_t));
 	node->is_struct = is_struct;
 	
 	SETBASE(node, NODE_CLASS_DECL, token, meta);
@@ -180,7 +180,7 @@ gnode_t *gnode_class_decl_create (gtoken_s token, const char *identifier, gtoken
 }
 
 gnode_t *gnode_module_decl_create (gtoken_s token, const char *identifier, gtoken_t access_specifier, gtoken_t storage_specifier, gnode_r *declarations, void *meta, gnode_t *decl) {
-	gnode_module_decl_t *node = (gnode_module_decl_t *)mem_alloc(sizeof(gnode_module_decl_t));
+	gnode_module_decl_t *node = (gnode_module_decl_t *)mem_alloc(NULL, sizeof(gnode_module_decl_t));
 	
 	SETBASE(node, NODE_MODULE_DECL, token, meta);
     SETDECL(node, decl);
@@ -193,7 +193,7 @@ gnode_t *gnode_module_decl_create (gtoken_s token, const char *identifier, gtoke
 }
 
 gnode_t *gnode_enum_decl_create (gtoken_s token, const char *identifier, gtoken_t access_specifier, gtoken_t storage_specifier, symboltable_t *symtable, void *meta, gnode_t *decl) {
-	gnode_enum_decl_t *node = (gnode_enum_decl_t *)mem_alloc(sizeof(gnode_enum_decl_t));
+	gnode_enum_decl_t *node = (gnode_enum_decl_t *)mem_alloc(NULL, sizeof(gnode_enum_decl_t));
 	
 	SETBASE(node, NODE_ENUM_DECL, token, meta);
     SETDECL(node, decl);
@@ -201,12 +201,12 @@ gnode_t *gnode_enum_decl_create (gtoken_s token, const char *identifier, gtoken_
 	node->access = access_specifier;
 	node->storage = storage_specifier;
 	node->symtable= symtable;
-	
+    
 	return (gnode_t *)node;
 }
 
 gnode_t *gnode_function_decl_create (gtoken_s token, const char *identifier, gtoken_t access_specifier, gtoken_t storage_specifier, gnode_r *params, gnode_compound_stmt_t *block, void *meta, gnode_t *decl) {
-	gnode_function_decl_t *node = (gnode_function_decl_t *)mem_alloc(sizeof(gnode_function_decl_t));
+	gnode_function_decl_t *node = (gnode_function_decl_t *)mem_alloc(NULL, sizeof(gnode_function_decl_t));
 	
 	SETBASE(node, NODE_FUNCTION_DECL, token, meta);
     SETDECL(node, decl);
@@ -222,7 +222,7 @@ gnode_t *gnode_function_decl_create (gtoken_s token, const char *identifier, gto
 }
 
 gnode_t *gnode_variable_decl_create (gtoken_s token, gtoken_t type, gtoken_t access_specifier, gtoken_t storage_specifier, gnode_r *declarations, void *meta, gnode_t *decl) {
-	gnode_variable_decl_t *node = (gnode_variable_decl_t *)mem_alloc(sizeof(gnode_variable_decl_t));
+	gnode_variable_decl_t *node = (gnode_variable_decl_t *)mem_alloc(NULL, sizeof(gnode_variable_decl_t));
 	
 	SETBASE(node, NODE_VARIABLE_DECL, token, meta);
     SETDECL(node, decl);
@@ -235,7 +235,7 @@ gnode_t *gnode_variable_decl_create (gtoken_s token, gtoken_t type, gtoken_t acc
 }
 
 gnode_t *gnode_variable_create (gtoken_s token, const char *identifier, const char *annotation_type, gtoken_t access_specifier, gnode_t *expr, gnode_t *decl) {
-	gnode_var_t *node = (gnode_var_t *)mem_alloc(sizeof(gnode_var_t));
+	gnode_var_t *node = (gnode_var_t *)mem_alloc(NULL, sizeof(gnode_var_t));
 	
 	SETBASE(node, NODE_VARIABLE, token, NULL);
     SETDECL(node, decl);
@@ -298,7 +298,7 @@ bool gnode_is_literal_number (gnode_t *node) {
 gnode_t *gnode_binary_expr_create (gtoken_t op, gnode_t *left, gnode_t *right, gnode_t *decl) {
 	if (!left || !right) return NULL;
 	
-	gnode_binary_expr_t	*node = (gnode_binary_expr_t *)mem_alloc(sizeof(gnode_binary_expr_t));
+	gnode_binary_expr_t	*node = (gnode_binary_expr_t *)mem_alloc(NULL, sizeof(gnode_binary_expr_t));
 	SETBASE(node, NODE_BINARY_EXPR, left->token, NULL);
     SETDECL(node, decl);
 	node->op = op;
@@ -310,7 +310,7 @@ gnode_t *gnode_binary_expr_create (gtoken_t op, gnode_t *left, gnode_t *right, g
 gnode_t *gnode_unary_expr_create (gtoken_t op, gnode_t *expr, gnode_t *decl) {
 	if (!expr) return NULL;
 	
-	gnode_unary_expr_t *node = (gnode_unary_expr_t *)mem_alloc(sizeof(gnode_unary_expr_t));
+	gnode_unary_expr_t *node = (gnode_unary_expr_t *)mem_alloc(NULL, sizeof(gnode_unary_expr_t));
 	SETBASE(node, NODE_UNARY_EXPR, expr->token, NULL);
     SETDECL(node, decl);
 	node->op = op;
@@ -321,7 +321,7 @@ gnode_t *gnode_unary_expr_create (gtoken_t op, gnode_t *expr, gnode_t *decl) {
 gnode_t *gnode_file_expr_create (gtoken_s token, cstring_r *list, gnode_t *decl) {
 	if (!list) return NULL;
 	
-	gnode_file_expr_t *node = (gnode_file_expr_t *)mem_alloc(sizeof(gnode_file_expr_t));
+	gnode_file_expr_t *node = (gnode_file_expr_t *)mem_alloc(NULL, sizeof(gnode_file_expr_t));
 	SETBASE(node, NODE_FILE_EXPR, token, NULL);
     SETDECL(node, decl);
 	node->identifiers = list;
@@ -331,7 +331,7 @@ gnode_t *gnode_file_expr_create (gtoken_s token, cstring_r *list, gnode_t *decl)
 gnode_t *gnode_identifier_expr_create (gtoken_s token, const char *identifier, const char *identifier2, gnode_t *decl) {
 	if (!identifier) return NULL;
 	
-	gnode_identifier_expr_t *node = (gnode_identifier_expr_t *)mem_alloc(sizeof(gnode_identifier_expr_t));
+	gnode_identifier_expr_t *node = (gnode_identifier_expr_t *)mem_alloc(NULL, sizeof(gnode_identifier_expr_t));
 	SETBASE(node, NODE_IDENTIFIER_EXPR, token, NULL);
     SETDECL(node, decl);
 	node->value = identifier;
@@ -351,7 +351,7 @@ void gnode_literal_dump (gnode_literal_expr_t *node, char *buffer, int buffersiz
 }
 
 static gnode_t *gnode_literal_value_expr_create (gtoken_s token, gliteral_t type, const char *s, double d, int64_t n64, gnode_t *decl) {
-	gnode_literal_expr_t *node = (gnode_literal_expr_t *)mem_alloc(sizeof(gnode_literal_expr_t));
+	gnode_literal_expr_t *node = (gnode_literal_expr_t *)mem_alloc(NULL, sizeof(gnode_literal_expr_t));
 	
 	SETBASE(node, NODE_LITERAL_EXPR, token, NULL);
     SETDECL(node, decl);
@@ -375,18 +375,18 @@ gnode_t *gnode_string_interpolation_create (gtoken_s token, gnode_r *r, gnode_t
 	node->value.r = r;
 	return (gnode_t *)node;
 }
-	
+
 gnode_t *gnode_literal_string_expr_create (gtoken_s token, char *s, uint32_t len, bool allocated, gnode_t *decl) {
 	gnode_literal_expr_t *node = (gnode_literal_expr_t *)gnode_literal_value_expr_create(token, LITERAL_STRING, NULL, 0, 0, decl);
 	
-		node->len = len;
+	node->len = len;
 	if (allocated) {
 		node->value.str = s;
 	} else {
-		node->value.str = (char *)mem_alloc(len+1);
+		node->value.str = (char *)mem_alloc(NULL, len+1);
 		memcpy((void *)node->value.str, (const void *)s, len);
 	}
-	
+		
 	return (gnode_t *)node;
 }
 
@@ -403,7 +403,7 @@ gnode_t *gnode_literal_bool_expr_create (gtoken_s token, int32_t n, gnode_t *dec
 }
 
 gnode_t *gnode_keyword_expr_create (gtoken_s token, gnode_t *decl) {
-	gnode_keyword_expr_t *node = (gnode_keyword_expr_t *)mem_alloc(sizeof(gnode_keyword_expr_t));
+	gnode_keyword_expr_t *node = (gnode_keyword_expr_t *)mem_alloc(NULL, sizeof(gnode_keyword_expr_t));
 	
 	SETBASE(node, NODE_KEYWORD_EXPR, token, NULL);
     SETDECL(node, decl);
@@ -411,7 +411,7 @@ gnode_t *gnode_keyword_expr_create (gtoken_s token, gnode_t *decl) {
 }
 
 gnode_t *gnode_postfix_subexpr_create (gtoken_s token, gnode_n type, gnode_t *expr, gnode_r *list, gnode_t *decl) {
-	gnode_postfix_subexpr_t *node = (gnode_postfix_subexpr_t *)mem_alloc(sizeof(gnode_postfix_subexpr_t));
+	gnode_postfix_subexpr_t *node = (gnode_postfix_subexpr_t *)mem_alloc(NULL, sizeof(gnode_postfix_subexpr_t));
 	
     SETBASE(node, type, token, NULL);
     SETDECL(node, decl);
@@ -423,17 +423,17 @@ gnode_t *gnode_postfix_subexpr_create (gtoken_s token, gnode_n type, gnode_t *ex
 }
 
 gnode_t *gnode_postfix_expr_create (gtoken_s token, gnode_t *id, gnode_r *list, gnode_t *decl) {
-	gnode_postfix_expr_t *node = (gnode_postfix_expr_t *)mem_alloc(sizeof(gnode_postfix_expr_t));
+	gnode_postfix_expr_t *node = (gnode_postfix_expr_t *)mem_alloc(NULL, sizeof(gnode_postfix_expr_t));
 	
 	SETBASE(node, NODE_POSTFIX_EXPR, token, NULL);
     SETDECL(node, decl);
-	node->id = id;
-	node->list = list;
+    node->id = id;
+    node->list = list;
 	return (gnode_t *)node;
 }
 
 gnode_t *gnode_list_expr_create (gtoken_s token, gnode_r *list1, gnode_r *list2, bool ismap, gnode_t *decl) {
-	gnode_list_expr_t *node = (gnode_list_expr_t *)mem_alloc(sizeof(gnode_list_expr_t));
+	gnode_list_expr_t *node = (gnode_list_expr_t *)mem_alloc(NULL, sizeof(gnode_list_expr_t));
 	
 	SETBASE(node, NODE_LIST_EXPR, token, NULL);
     SETDECL(node, decl);
@@ -664,7 +664,7 @@ static void free_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
 	mem_free((gnode_t*)node);
 }
 
-static void free_file_expr (gvisitor_t *self, gnode_file_expr_t *node) {
+static void free_file_expr (gvisitor_t *self, gnode_file_expr_t *node) {    
 	#pragma unused(self)
 	CHECK_REFCOUNT(node);
 	cstring_array_each(node->identifiers, {
@@ -716,41 +716,41 @@ static void free_list_expr (gvisitor_t *self, gnode_list_expr_t *node) {
 // MARK: -
 
 void gnode_free (gnode_t *ast) {
-	gvisitor_t visitor = {
-		.nerr = 0,
-		.data = NULL,
-		.delegate = NULL,
-		
+    gvisitor_t visitor = {
+        .nerr = 0,
+        .data = NULL,
+        .delegate = NULL,
+        
         // COMMON
         .visit_pre = NULL,
         .visit_post = NULL,
         
-		// STATEMENTS: 7
-		.visit_list_stmt = free_list_stmt,
-		.visit_compound_stmt = free_compound_stmt,
-		.visit_label_stmt = free_label_stmt,
-		.visit_flow_stmt = free_flow_stmt,
-		.visit_loop_stmt = free_loop_stmt,
-		.visit_jump_stmt = free_jump_stmt,
-		.visit_empty_stmt = free_empty_stmt,
-		
-		// DECLARATIONS: 5
-		.visit_function_decl = free_function_decl,
-		.visit_variable_decl = free_variable_decl,
-		.visit_enum_decl = free_enum_decl,
-		.visit_class_decl = free_class_decl,
-		.visit_module_decl = free_module_decl,
-		
-		// EXPRESSIONS: 7+1
-		.visit_binary_expr = free_binary_expr,
-		.visit_unary_expr = free_unary_expr,
-		.visit_file_expr = free_file_expr,
-		.visit_literal_expr = free_literal_expr,
-		.visit_identifier_expr = free_identifier_expr,
-		.visit_keyword_expr = free_keyword_expr,
-		.visit_list_expr = free_list_expr,
-		.visit_postfix_expr = free_postfix_expr
-	};
-	
+        // STATEMENTS: 7
+        .visit_list_stmt = free_list_stmt,
+        .visit_compound_stmt = free_compound_stmt,
+        .visit_label_stmt = free_label_stmt,
+        .visit_flow_stmt = free_flow_stmt,
+        .visit_loop_stmt = free_loop_stmt,
+        .visit_jump_stmt = free_jump_stmt,
+        .visit_empty_stmt = free_empty_stmt,
+        
+        // DECLARATIONS: 5
+        .visit_function_decl = free_function_decl,
+        .visit_variable_decl = free_variable_decl,
+        .visit_enum_decl = free_enum_decl,
+        .visit_class_decl = free_class_decl,
+        .visit_module_decl = free_module_decl,
+        
+        // EXPRESSIONS: 7+1
+        .visit_binary_expr = free_binary_expr,
+        .visit_unary_expr = free_unary_expr,
+        .visit_file_expr = free_file_expr,
+        .visit_literal_expr = free_literal_expr,
+        .visit_identifier_expr = free_identifier_expr,
+        .visit_keyword_expr = free_keyword_expr,
+        .visit_list_expr = free_list_expr,
+        .visit_postfix_expr = free_postfix_expr
+    };
+    
     gvisit(&visitor, ast);
 }

+ 1 - 1
src/compiler/gravity_compiler.c

@@ -68,7 +68,7 @@ static void internal_vm_cleanup (gravity_vm *vm) {
 // MARK: -
 
 gravity_compiler_t *gravity_compiler_create (gravity_delegate_t *delegate) {
-	gravity_compiler_t *compiler = mem_alloc(sizeof(gravity_compiler_t));
+	gravity_compiler_t *compiler = mem_alloc(NULL, sizeof(gravity_compiler_t));
 	if (!compiler) return NULL;
 	
 	compiler->ast = NULL;

+ 5 - 5
src/compiler/gravity_ircode.c

@@ -32,14 +32,14 @@ struct ircode_t {
 };
 
 ircode_t *ircode_create (uint16_t nlocals) {
-	ircode_t *code = (ircode_t *)mem_alloc(sizeof(ircode_t));
+	ircode_t *code = (ircode_t *)mem_alloc(NULL, sizeof(ircode_t));
 	code->label_counter = 0;
 	code->nlocals = nlocals;
 	code->ntemps = 0;
 	code->maxtemp = 0;
 	code->error = false;
 	
-	code->list = mem_alloc(sizeof(code_r));
+	code->list = mem_alloc(NULL, sizeof(code_r));
 	marray_init(*code->list);
 	marray_init(code->label_true);
 	marray_init(code->label_false);
@@ -118,7 +118,7 @@ static inst_t *inst_new (opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3, opt
 	}
 	#endif
 	
-	inst_t *inst = (inst_t *)mem_alloc(sizeof(inst_t));
+	inst_t *inst = (inst_t *)mem_alloc(NULL, sizeof(inst_t));
 	inst->op = op;
 	inst->tag = tag;
 	inst->p1 = p1;
@@ -162,7 +162,7 @@ void ircode_patch_init (ircode_t *code, uint16_t index) {
 	ircode_register_pop(code);
 	
 	// create new instruction list
-	code_r		*list = mem_alloc(sizeof(code_r));
+	code_r		*list = mem_alloc(NULL, sizeof(code_r));
 	marray_init(*list);
 	
 	// add newly create instructions
@@ -410,7 +410,7 @@ static void dump_context(bool *context) {
 #endif
 
 void ircode_push_context (ircode_t *code) {
-	bool *context = mem_alloc(sizeof(bool) * MAX_REGISTERS);
+	bool *context = mem_alloc(NULL, sizeof(bool) * MAX_REGISTERS);
 	marray_push(bool *, code->context, context);
 }
 

+ 1 - 1
src/compiler/gravity_lexer.c

@@ -525,7 +525,7 @@ static gtoken_t lexer_scan_preprocessor(gravity_lexer_t *lexer) {
 // MARK: -
 
 gravity_lexer_t *gravity_lexer_create (const char *source, size_t len, uint32_t fileid, bool is_static) {
-	gravity_lexer_t *lexer = mem_alloc(sizeof(gravity_lexer_t));
+	gravity_lexer_t *lexer = mem_alloc(NULL, sizeof(gravity_lexer_t));
 	if (!lexer) return NULL;
 	bzero(lexer, sizeof(gravity_lexer_t));
 	

+ 1 - 1
src/compiler/gravity_optimizer.c

@@ -71,7 +71,7 @@ static void finalize_function (gravity_function_t *f) {
 	
 	// +1 is just a trick so the VM switch loop terminates with an implicit RET0 instruction (RET0 has opcode 0)
 	f->ninsts = ninst;
-	bytecode = (uint32_t *)mem_alloc((ninst+1) * sizeof(uint32_t));
+	bytecode = (uint32_t *)mem_alloc(NULL, (ninst+1) * sizeof(uint32_t));
 	assert(bytecode);
 	
 	uint32_t j=0;

+ 51 - 48
src/compiler/gravity_parser.c

@@ -72,13 +72,13 @@ typedef struct {
 } grammar_rule;
 
 // This table defines all of the parsing rules for the prefix and infix expressions in the grammar.
-#define RULE(prec, fn1, fn2)			(grammar_rule){ fn1, fn2, prec, NULL, false}
-#define PREFIX(prec, fn)				(grammar_rule){ fn, NULL, prec, NULL, false}
-#define INFIX(prec, fn)					(grammar_rule){ NULL, fn, prec, NULL, false}
-#define INFIX_OPERATOR(prec, name)		(grammar_rule){ NULL, parse_infix, prec, name, false}
-#define INFIX_OPERATOR_RIGHT(prec,name) (grammar_rule){ NULL, parse_infix, prec, name, true}
-#define PREFIX_OPERATOR(name)			(grammar_rule){ parse_unary, NULL, PREC_LOWEST, name, false}
-#define OPERATOR(prec, name)			(grammar_rule){ parse_unary, parse_infix, prec, name, false}
+#define RULE(prec, fn1, fn2)					(grammar_rule){ fn1, fn2, prec, NULL, false}
+#define PREFIX(prec, fn)						(grammar_rule){ fn, NULL, prec, NULL, false}
+#define INFIX(prec, fn)							(grammar_rule){ NULL, fn, prec, NULL, false}
+#define INFIX_OPERATOR(prec, name)				(grammar_rule){ NULL, parse_infix, prec, name, false}
+#define INFIX_OPERATOR_RIGHT(prec,name)			(grammar_rule){ NULL, parse_infix, prec, name, true}
+#define PREFIX_OPERATOR(name)					(grammar_rule){ parse_unary, NULL, PREC_LOWEST, name, false}
+#define OPERATOR(prec, name)					(grammar_rule){ parse_unary, parse_infix, prec, name, false}
 
 // Global singleton grammar rule table
 static grammar_rule rules[TOK_END];
@@ -111,7 +111,7 @@ static grammar_rule rules[TOK_END];
 // MARK: - Prototypes -
 static const char *parse_identifier (gravity_parser_t *parser);
 static gnode_t *parse_statement (gravity_parser_t *parser);
-static gnode_r *parse_optional_parameter_declaration (gravity_parser_t *parser);
+static gnode_r *parse_optional_parameter_declaration (gravity_parser_t *parser, bool is_implicit);
 static gnode_t *parse_compound_statement (gravity_parser_t *parser);
 static gnode_t *parse_expression (gravity_parser_t *parser);
 static gnode_t *parse_declaration_statement (gravity_parser_t *parser);
@@ -260,7 +260,7 @@ static bool parse_semicolon (gravity_parser_t *parser) {
 
 gnode_t *parse_function (gravity_parser_t *parser, bool is_declaration, gtoken_t access_specifier, gtoken_t storage_specifier) {
 	DECLARE_LEXER;
-	
+    
     // consume optional meta
     gravity_hash_t *meta = (is_declaration) ? parser_getmeta(parser, true): NULL;
     
@@ -286,7 +286,7 @@ gnode_t *parse_function (gravity_parser_t *parser, bool is_declaration, gtoken_t
         identifier = (token_isoperator(peek)) ? string_dup(token_name(gravity_lexer_next(lexer))) : parse_identifier(parser);
 		DEBUG_PARSER("parse_function_declaration %s", identifier);
 	}
-	
+    
     // create func declaration node
     gnode_function_decl_t *func = (gnode_function_decl_t *) gnode_function_decl_create(token, identifier, access_specifier, storage_specifier, NULL, NULL, meta,LAST_DECLARATION());
 	
@@ -294,7 +294,7 @@ gnode_t *parse_function (gravity_parser_t *parser, bool is_declaration, gtoken_t
 	if (!is_implicit) parse_required(parser, TOK_OP_OPEN_PARENTHESIS);
 	
 	// parse optional parameter declaration clause
-	gnode_r *params = (!is_implicit) ? parse_optional_parameter_declaration(parser) : NULL;
+	gnode_r *params = parse_optional_parameter_declaration(parser, is_implicit);
 	
 	// check and consume TOK_OP_CLOSED_PARENTHESIS
 	if (!is_implicit) parse_required(parser, TOK_OP_CLOSED_PARENTHESIS);
@@ -318,7 +318,7 @@ static char *cstring_from_token (gravity_parser_t *parser, gtoken_s token) {
 	uint32_t len = 0;
 	const char *buffer = token_string(token, &len);
 	
-	char *str = (char *)mem_alloc(len+1);
+	char *str = (char *)mem_alloc(NULL, len+1);
 	memcpy(str, buffer, len);
 	return str;
 }
@@ -592,7 +592,7 @@ static gnode_t *parse_identifier_expression (gravity_parser_t *parser) {
 	DEBUG_PARSER("parse_identifier_expression");
 	DECLARE_LEXER;
 	
-	const char	*identifier = parse_identifier(parser);
+	const char *identifier = parse_identifier(parser);
 	if (!identifier) return NULL;
 	DEBUG_PARSER("IDENTIFIER: %s", identifier);
 	
@@ -706,7 +706,7 @@ static gnode_t *parse_analyze_literal_string (gravity_parser_t *parser, gtoken_s
 	gnode_r *r = NULL;
 	
 	// analyze s (of length len) for escaped characters or for interpolations
-	char *buffer = mem_alloc(len+1);
+	char *buffer = mem_alloc(NULL, len+1);
 	uint32_t length = 0;
 	
 	for (uint32_t i=0; i<len;) {
@@ -795,17 +795,17 @@ static gnode_t *parse_analyze_literal_string (gravity_parser_t *parser, gtoken_s
 					
 					// add expression to r
                     if (subnode) {
-						if (!r) r = gnode_array_create();
-						if (length) gnode_array_push(r, gnode_literal_string_expr_create(token, buffer, length, true, LAST_DECLARATION()));
-						gnode_array_push(r, subnode);
+                        if (!r) r = gnode_array_create();
+                        if (length) gnode_array_push(r, gnode_literal_string_expr_create(token, buffer, length, true, LAST_DECLARATION()));
+                        gnode_array_push(r, subnode);
                     }
-					
+                        
 					// free temp lexer
 					marray_pop(*parser->lexer);
 					gravity_lexer_free(sublexer);
                     if (!subnode) goto return_string;
 					
-					buffer = mem_alloc(len+1);
+					buffer = mem_alloc(NULL, len+1);
 					length = 0;
 					
 					continue;
@@ -1012,7 +1012,7 @@ static gnode_t *parse_precedence(gravity_parser_t *parser, prec_level precedence
     }
 	gnode_t *node = (prefix) ? prefix(parser) : NULL;
     if (prefix) --parser->expr_depth;
-	
+    
 	if (!prefix || !node) {
 		// we need to consume next token because error was triggered in peek
 		gravity_lexer_next(lexer);
@@ -1220,7 +1220,7 @@ static gnode_t *parse_getter_setter (gravity_parser_t *parser, gravity_hash_t *m
 			// check if parameters are explicit
 			if (gravity_lexer_peek(lexer) == TOK_OP_OPEN_PARENTHESIS) {
 				parse_required(parser, TOK_OP_OPEN_PARENTHESIS);
-				params = parse_optional_parameter_declaration(parser);	// add implicit SELF
+				params = parse_optional_parameter_declaration(parser, false);	// add implicit SELF
 				parse_required(parser, TOK_OP_CLOSED_PARENTHESIS);
 			} else {
 				params = gnode_array_create();	// add implicit SELF and VALUE params
@@ -1270,7 +1270,7 @@ static gnode_t *parse_variable_declaration (gravity_parser_t *parser, bool issta
 	gtoken_t	type;
 	gtoken_t	peek;
 	gtoken_s	token, token2;
-	
+    
 	// access_specifier? storage_specifier? variable_declaration ';'
 	// variable_declaration: variable_declarator decl_item
 	// variable_declarator: 'const' | 'var'
@@ -1367,7 +1367,7 @@ static gnode_t *parse_enum_declaration (gravity_parser_t *parser, gtoken_t acces
 	// enum_list_item: IDENTIFIER ('=' LITERAL)?
 	
 	// NODE_ENUM_DECL
-	
+    
 	// optional scope already consumed
 	gtoken_t type = gravity_lexer_next(lexer);
 	gtoken_s token = gravity_lexer_token(lexer);
@@ -1522,7 +1522,7 @@ static gnode_t *parse_enum_declaration (gravity_parser_t *parser, gtoken_t acces
 
 static gnode_t *parse_module_declaration (gravity_parser_t *parser, gtoken_t access_specifier, gtoken_t storage_specifier) {
 	DEBUG_PARSER("parse_module_declaration");
-	
+    
 	// 'module' IDENTIFIER '{' declaration_statement* '}' ';'
 	
 	// optional scope already consumed
@@ -1563,7 +1563,7 @@ static gnode_t *parse_module_declaration (gravity_parser_t *parser, gtoken_t acc
 
 static gnode_t *parse_event_declaration (gravity_parser_t *parser, gtoken_t access_specifier, gtoken_t storage_specifier) {
 	#pragma unused(parser, access_specifier, storage_specifier)
-	
+    
 	// 'event' IDENTIFIER '(' parameter_declaration_clause? ')' ';'
 	
 	// NODE_EVENT_DECL
@@ -1594,7 +1594,7 @@ static gnode_t *parse_function_declaration (gravity_parser_t *parser, gtoken_t a
 	// so next semantic checks can perform
 	// identifier uniqueness checks
 	gnode_t *node = parse_function(parser, true, access_specifier, storage_specifier);
-	
+    
 	if (IS_FUNCTION_ENCLOSED()) return local_store_declaration(parser, ((gnode_function_decl_t *)node)->identifier, access_specifier, storage_specifier, node);
 	return node;
 }
@@ -1657,7 +1657,7 @@ abort:
 static gnode_t *parse_class_declaration (gravity_parser_t *parser, gtoken_t access_specifier, gtoken_t storage_specifier) {
 	DEBUG_PARSER("parse_class_declaration");
 	DECLARE_LEXER;
-	
+    
     // consume optional meta
     gravity_hash_t *meta = parser_getmeta(parser, true);
 	
@@ -1691,7 +1691,7 @@ static gnode_t *parse_class_declaration (gravity_parser_t *parser, gtoken_t acce
 	}
 	
 	// check and consume TOK_OP_OPEN_CURLYBRACE
-	parse_required(parser, TOK_OP_OPEN_CURLYBRACE);
+	if (storage_specifier != TOK_KEY_EXTERN) parse_required(parser, TOK_OP_OPEN_CURLYBRACE);
 	gnode_r *declarations = gnode_array_create();
 	
 	// if class is declared inside another class then a hidden implicit privare "outer" instance var at index 0
@@ -1704,21 +1704,23 @@ static gnode_t *parse_class_declaration (gravity_parser_t *parser, gtoken_t acce
 		gnode_t *outer_decl = gnode_variable_decl_create(NO_TOKEN, TOK_KEY_VAR, TOK_KEY_PRIVATE, 0, decls, NULL, LAST_DECLARATION());
 		gnode_array_push(declarations, outer_decl);
 	}
-	
+    
     // create class declaration node
     gnode_class_decl_t *node = (gnode_class_decl_t*) gnode_class_decl_create(token, identifier, access_specifier, storage_specifier, super, protocols, NULL, is_struct, meta, LAST_DECLARATION());
-	
-	PUSH_DECLARATION(node);
-    peek = gravity_lexer_peek(lexer);
-	while (token_isdeclaration_statement(peek) || token_ismacro(peek)) {
-		gnode_t *decl = parse_declaration_statement(parser);
-        if (decl) gnode_array_push(declarations, decl_check_access_specifier(decl));
+    
+    if (storage_specifier != TOK_KEY_EXTERN) {
+        PUSH_DECLARATION(node);
         peek = gravity_lexer_peek(lexer);
-	}
-	POP_DECLARATION();
+        while (token_isdeclaration_statement(peek) || token_ismacro(peek)) {
+            gnode_t *decl = parse_declaration_statement(parser);
+            if (decl) gnode_array_push(declarations, decl_check_access_specifier(decl));
+            peek = gravity_lexer_peek(lexer);
+        }
+        POP_DECLARATION();
+    }
 	
 	// check and consume TOK_OP_CLOSED_CURLYBRACE
-	parse_required(parser, TOK_OP_CLOSED_CURLYBRACE);
+	if (storage_specifier != TOK_KEY_EXTERN) parse_required(parser, TOK_OP_CLOSED_CURLYBRACE);
 	
 	// to check
 	parse_semicolon(parser);
@@ -1730,7 +1732,7 @@ static gnode_t *parse_class_declaration (gravity_parser_t *parser, gtoken_t acce
 	return (gnode_t *)node;
 }
 
-static gnode_r *parse_optional_parameter_declaration (gravity_parser_t *parser) {
+static gnode_r *parse_optional_parameter_declaration (gravity_parser_t *parser, bool is_implicit) {
 	DEBUG_PARSER("parse_parameter_declaration");
 	DECLARE_LEXER;
 	
@@ -1755,6 +1757,7 @@ static gnode_r *parse_optional_parameter_declaration (gravity_parser_t *parser)
 	// memory for the identifier will be deallocated
 	node = gnode_variable_create(token, string_dup(SELF_PARAMETER_NAME), type_annotation, 0, NULL, LAST_DECLARATION());
 	if (node) gnode_array_push(params, node);
+    if (is_implicit) return params;
 		
 	// parameter declaration clause is ALWAYS optional
 	gtoken_t peek = gravity_lexer_peek(lexer);
@@ -2024,7 +2027,7 @@ loop:
 	} else {
 		REPORT_ERROR(token, "Unable to load file %s.", module_name);
 	}
-	
+    
     // cleanup memory
     if (module_name) mem_free(module_name);
     
@@ -2280,7 +2283,7 @@ static gnode_t *parse_compound_statement (gravity_parser_t *parser) {
         }
 		gnode_t *node = parse_statement(parser);
         --parser->depth;
-		if (node) gnode_array_push(stmts, node);
+        if (node) gnode_array_push(stmts, node);
 	}
 	
 	// check and consume TOK_OP_CLOSED_CURLYBRACE
@@ -2324,7 +2327,7 @@ static gnode_t *parse_declaration_statement (gravity_parser_t *parser) {
 	if ((peek == TOK_OP_SEMICOLON) && ((access_specifier) || (storage_specifier))) {
 		REPORT_ERROR(gravity_lexer_token(lexer), "%s", "Access or storage specifier cannot be used here.");
 	}
-	
+    
 	switch (peek) {
         case TOK_MACRO: return parse_macro_statement(parser);
 		case TOK_KEY_FUNC: return parse_function_declaration(parser, access_specifier, storage_specifier);
@@ -2353,7 +2356,7 @@ static gnode_t *parse_import_statement (gravity_parser_t *parser) {
 	gravity_lexer_next(lexer);
 	return NULL;
 }
-
+	
 static gnode_t *parse_macro_statement (gravity_parser_t *parser) {
 	typedef enum {
 		MACRO_UNKNOWN = 0,
@@ -2408,7 +2411,7 @@ static gnode_t *parse_macro_statement (gravity_parser_t *parser) {
 		case MACRO_INCLUDE:
 			return parse_include_macro(parser);
 			break;
-			
+            
         case MACRO_META:
             return parse_meta_macro(parser);
             break;
@@ -2489,7 +2492,7 @@ static gnode_t *parse_statement (gravity_parser_t *parser) {
 
 static void parser_register_core_classes (gravity_parser_t *parser) {
 	const char **list = gravity_core_identifiers();
-	
+    
 	// for each core identifier create a dummy extern variable node
 	gnode_r	*decls = gnode_array_create();
     
@@ -2531,7 +2534,7 @@ static uint32_t parser_run (gravity_parser_t *parser) {
 	do {
 		while (gravity_lexer_peek(CURRENT_LEXER)) {
 			gnode_t *node = parse_statement(parser);
-			if (node) gnode_array_push(parser->statements, node);
+            if (node) gnode_array_push(parser->statements, node);
 		}
 		
 		// since it is a stack of lexers then check if it is a real EOF
@@ -2578,13 +2581,13 @@ static void parser_appendcode (const char *source, gravity_parser_t *parser) {
 gravity_parser_t *gravity_parser_create (const char *source, size_t len, uint32_t fileid, bool is_static) {
 	init_grammer_rules();
 	
-	gravity_parser_t *parser = mem_alloc(sizeof(gravity_parser_t));
+	gravity_parser_t *parser = mem_alloc(NULL, sizeof(gravity_parser_t));
 	if (!parser) return NULL;
 	
 	gravity_lexer_t *lexer = gravity_lexer_create(source, len, fileid, is_static);
 	if (!lexer) goto abort_init;
 	
-	parser->lexer = mem_alloc(sizeof(lexer_r));
+	parser->lexer = mem_alloc(NULL, sizeof(lexer_r));
 	marray_init(*parser->lexer);
 	marray_push(gravity_lexer_t*, *parser->lexer, lexer);
 	

+ 0 - 1
src/compiler/gravity_semacheck2.c

@@ -854,7 +854,6 @@ static void visit_class_decl (gvisitor_t *self, gnode_class_decl_t *node) {
             REPORT_ERROR(id, "Unable to find superclass %s for class %s.", id->value, node->identifier);
         } else {
             gnode_class_decl_t *target_class = NODE_ISA(target, NODE_CLASS_DECL) ? (gnode_class_decl_t *)target : NULL;
-            
             if (!target_class) {
                 REPORT_ERROR(id, "Unable to set non class %s as superclass of %s.", id->value, node->identifier);
             } else if ((gnode_class_decl_t *)node == (gnode_class_decl_t *)target_class->superclass) {

+ 2 - 2
src/compiler/gravity_symboltable.c

@@ -63,14 +63,14 @@ static void symboltable_keyvalue_free (gravity_hash_t *hashtable, gravity_value_
 }
 
 symboltable_t *symboltable_create (bool is_enum) {
-	symboltable_t	*table = mem_alloc(sizeof(symboltable_t));
+	symboltable_t	*table = mem_alloc(NULL, sizeof(symboltable_t));
 	gravity_hash_t	*hash = gravity_hash_create(0, gravity_value_hash, gravity_value_equals,
 												(is_enum) ? symboltable_keyvalue_free : symboltable_hash_free, NULL);
 	if (!table) return NULL;
 	
 	// init symbol table
 	table->counter = 0;
-	table->stack = mem_alloc(sizeof(ghash_r));
+	table->stack = mem_alloc(NULL, sizeof(ghash_r));
 	scope_stack_init(table->stack);
 	scope_stack_push(table->stack, hash);
 	

+ 89 - 89
src/runtime/gravity_core.c

@@ -159,7 +159,7 @@ static bool convert_object_string (gravity_vm *vm, gravity_value_t *args, uint16
 static inline gravity_value_t convert_map2string (gravity_vm *vm, gravity_map_t *map) {
     // allocate initial memory to a 512 buffer
     uint32_t len = 512;
-    char *buffer = mem_alloc(len+1);
+    char *buffer = mem_alloc(NULL, len+1);
     buffer[0] = '[';
     uint32_t pos = 1;
     
@@ -198,7 +198,7 @@ static inline gravity_value_t convert_map2string (gravity_vm *vm, gravity_map_t
         // check if buffer needs to be reallocated
         if (len1 + len2 + pos + 4 > len) {
             len = (len1 + len2 + pos + 4) + len;
-            buffer = mem_realloc(buffer, len);
+            buffer = mem_realloc(NULL, buffer, len);
         }
         
         // copy key string to new buffer
@@ -232,7 +232,7 @@ static inline gravity_value_t convert_map2string (gravity_vm *vm, gravity_map_t
 static inline gravity_value_t convert_list2string (gravity_vm *vm, gravity_list_t *list) {
 	// allocate initial memory to a 512 buffer
 	uint32_t len = 512;
-	char *buffer = mem_alloc(len+1);
+	char *buffer = mem_alloc(NULL, len+1);
 	buffer[0] = '[';
 	uint32_t pos = 1;
 	
@@ -244,7 +244,7 @@ static inline gravity_value_t convert_list2string (gravity_vm *vm, gravity_list_
         if (VALUE_ISA_LIST(value) && (VALUE_AS_LIST(value) == list)) {
             string = NULL;
         } else {
-			gravity_value_t value2 = convert_value2string(vm, value);
+            gravity_value_t value2 = convert_value2string(vm, value);
             string = VALUE_ISA_VALID(value2) ? VALUE_AS_STRING(value2) : NULL;
         }
 		
@@ -254,7 +254,7 @@ static inline gravity_value_t convert_list2string (gravity_vm *vm, gravity_list_
 		// check if buffer needs to be reallocated
 		if (len1+pos+2 > len) {
 			len = (len1+pos+2) + len;
-			buffer = mem_realloc(buffer, len);
+			buffer = mem_realloc(NULL, buffer, len);
 		}
 		
 		// copy string to new buffer
@@ -293,7 +293,7 @@ inline gravity_value_t convert_value2int (gravity_vm *vm, gravity_value_t v) {
 	// sanity check (and break recursion)
 	if ((!closure) || ((closure->f->tag == EXEC_TYPE_INTERNAL) && (closure->f->internal == convert_object_int)) ||
         gravity_vm_getclosure(vm) == closure) return VALUE_FROM_ERROR(NULL);
-	
+    
 	// execute closure and return its value
 	if (gravity_vm_runclosure(vm, closure, v, NULL, 0)) return gravity_vm_result(vm);
 	
@@ -493,7 +493,7 @@ static bool object_not (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, u
 
 static bool object_real_load (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex, bool is_super) {
 	#pragma unused(vm, nargs)
-	
+    
 	// if there is a possibility that gravity_vm_runclosure is called then it is MANDATORY to save arguments before the call
 	gravity_value_t target = GET_VALUE(0);
 	gravity_value_t key = GET_VALUE(1);
@@ -526,7 +526,7 @@ static bool object_real_load (gravity_vm *vm, gravity_value_t *args, uint16_t na
         // sanity check
         uint32_t nivar = c->nivars;
         uint32_t nindex = (uint32_t)key.n;
-        if (nindex >= nivar) RETURN_ERROR("Out of bounds ivar index.");
+        if (nindex >= nivar) RETURN_ERROR("Out of bounds ivar index in load operation (1).");
         
 		if (instance) RETURN_VALUE(instance->ivars[nindex], rindex);	// instance case
 		RETURN_VALUE(c->ivars[nindex], rindex);                         // class case
@@ -540,12 +540,12 @@ static bool object_real_load (gravity_vm *vm, gravity_value_t *args, uint16_t na
 	// lookup key in class c
 	gravity_object_t *obj = (gravity_object_t *)gravity_class_lookup(c, key);
     if (!obj) {
-			// not explicitly declared so check for dynamic property in bridge case
-			gravity_delegate_t *delegate = gravity_vm_delegate(vm);
-			if ((instance) && (instance->xdata) && (delegate) && (delegate->bridge_getundef)) {
-				if (delegate->bridge_getundef(vm, instance->xdata, target, VALUE_AS_CSTRING(key), rindex)) return true;
-			}
-		}
+        // not explicitly declared so check for dynamic property in bridge case
+        gravity_delegate_t *delegate = gravity_vm_delegate(vm);
+        if ((instance) && (instance->xdata) && (delegate) && (delegate->bridge_getundef)) {
+            if (delegate->bridge_getundef(vm, instance->xdata, target, VALUE_AS_CSTRING(key), rindex)) return true;
+        }
+    }
 	if (!obj) goto execute_notfound;
 	
 	gravity_closure_t *closure;
@@ -559,9 +559,9 @@ static bool object_real_load (gravity_vm *vm, gravity_value_t *args, uint16_t na
                 // sanity check
                 uint32_t nivar = c->nivars;
                 uint32_t nindex = closure->f->index;
-                if (nindex >= nivar) RETURN_ERROR("Out of bounds ivar index.");
+                if (nindex >= nivar) RETURN_ERROR("Out of bounds ivar index in load operation (2).");
                 
-				if (instance) RETURN_VALUE(instance->ivars[closure->f->index], rindex);
+                if (instance) RETURN_VALUE(instance->ivars[closure->f->index], rindex);
 				RETURN_VALUE(c->ivars[closure->f->index], rindex);
 			}
 			
@@ -620,7 +620,7 @@ static bool object_store (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
         // sanity check
         uint32_t nivar = c->nivars;
         uint32_t nindex = (uint32_t)key.n;
-        if (nindex >= nivar) RETURN_ERROR("Out of bounds ivar index.");
+        if (nindex >= nivar) RETURN_ERROR("Out of bounds ivar index in store operation (1).");
         
 		if (instance) instance->ivars[nindex] = value;
 		else c->ivars[nindex] = value;
@@ -635,12 +635,12 @@ static bool object_store (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
 	// lookup key in class c
 	gravity_object_t *obj = gravity_class_lookup(c, key);
     if (!obj) {
-			// not explicitly declared so check for dynamic property in bridge case
-			gravity_delegate_t *delegate = gravity_vm_delegate(vm);
-			if ((instance) && (instance->xdata) && (delegate) && (delegate->bridge_setundef)) {
-				if (delegate->bridge_setundef(vm, instance->xdata, target, VALUE_AS_CSTRING(key), value)) RETURN_NOVALUE();
-			}
-		}
+        // not explicitly declared so check for dynamic property in bridge case
+        gravity_delegate_t *delegate = gravity_vm_delegate(vm);
+        if ((instance) && (instance->xdata) && (delegate) && (delegate->bridge_setundef)) {
+            if (delegate->bridge_setundef(vm, instance->xdata, target, VALUE_AS_CSTRING(key), value)) RETURN_NOVALUE();
+        }
+    }
 	if (!obj) goto execute_notfound;
 	
 	gravity_closure_t *closure;
@@ -655,7 +655,7 @@ static bool object_store (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
                 // sanity check
                 uint32_t nivar = c->nivars;
                 uint32_t nindex = closure->f->index;
-                if (nindex >= nivar) RETURN_ERROR("Out of bounds ivar index.");
+                if (nindex >= nivar) RETURN_ERROR("Out of bounds ivar index in store operation (2).");
                 
                 if (instance) instance->ivars[nindex] = value;
                 else c->ivars[nindex] = value;
@@ -793,10 +793,10 @@ static bool list_indexOf (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
             break;
         }
         ++i;
-	 }
- 
-	RETURN_VALUE(result, rindex);
- }
+    }
+    
+    RETURN_VALUE(result, rindex);
+}
 
 static bool list_loadat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
 	#pragma unused(vm, nargs)
@@ -842,7 +842,7 @@ static bool list_storeat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
 
 static bool list_push (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
 	#pragma unused(nargs)
-	gravity_list_t	*list = VALUE_AS_LIST(GET_VALUE(0));
+	gravity_list_t *list = VALUE_AS_LIST(GET_VALUE(0));
 	gravity_value_t value = GET_VALUE(1);
 	marray_push(gravity_value_t, list->array, value);
 	RETURN_VALUE(VALUE_FROM_INT(marray_size(list->array)), rindex);
@@ -856,7 +856,7 @@ static bool list_pop (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uin
 	gravity_value_t value = marray_pop(list->array);
 	RETURN_VALUE(value, rindex);
 }
-	
+
 static bool list_remove (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
     #pragma unused(nargs)
     gravity_list_t *list = VALUE_AS_LIST(GET_VALUE(0));
@@ -935,12 +935,10 @@ static bool list_join (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, ui
 	
 	// create a new empty buffer
 	uint32_t alloc = (uint32_t) (marray_size(list->array) * 64);
-    if (alloc > MAX_MEMORY_BLOCK) RETURN_ERROR("Maximum memory block size reached (max %d, requested %d).", MAX_MEMORY_BLOCK, alloc);
-    
 	uint32_t len = 0;
 	uint32_t seplen = (sep) ? VALUE_AS_STRING(GET_VALUE(1))->len : 0;
-	char *_buffer = mem_alloc(alloc);
-	if (!_buffer) RETURN_ERROR("Not enought memory to allocate a buffer for the join operation.");
+	char *_buffer = mem_alloc(vm, alloc);
+    CHECK_MEM_ALLOC(_buffer);
 	
 	register gravity_int_t n = marray_size(list->array);
 	register gravity_int_t i = 0;
@@ -957,25 +955,18 @@ static bool list_join (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, ui
 		const char *s2 = VALUE_AS_STRING(value)->s;
 		uint32_t req = VALUE_AS_STRING(value)->len;
 		uint32_t free_mem = alloc - len;
-		
+        
 		// check if buffer needs to be reallocated
 		if (free_mem < req + seplen) {
             uint64_t to_alloc = alloc + (req + seplen) * 2 + 4096;
-            
-            // sanity check
-            if (to_alloc > MAX_MEMORY_BLOCK) {
-                mem_free(_buffer);
-                RETURN_ERROR("Maximum memory block size reached (max %d, requested %llu).", MAX_MEMORY_BLOCK, to_alloc);
-            }
-            
-			_buffer = mem_realloc(_buffer, (uint32_t)to_alloc);
+			_buffer = mem_realloc(vm, _buffer, (uint32_t)to_alloc);
             if (!_buffer) {
                 mem_free(_buffer);
-                RETURN_ERROR("Not enought memory to re-allocate a buffer for the join operation.");
+                RETURN_ERROR_SIMPLE();
             }
 			alloc = (uint32_t)to_alloc;
 		}
-		
+        
 		// copy s2 to into buffer
 		memcpy(_buffer+len, s2, req);
 		len += req;
@@ -1028,7 +1019,7 @@ static bool map_loadat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, u
 	gravity_map_t *map = VALUE_AS_MAP(GET_VALUE(0));
 	gravity_value_t key = GET_VALUE(1);
 	if (VALUE_ISA_NOTVALID(key)) RETURN_ERROR("Invalid map key.");
-	
+    
     #ifdef GRAVITY_MAP_DOTSUGAR
     gravity_object_t *obj = (gravity_object_t *)gravity_class_lookup(gravity_class_map, key);
     if (obj) {
@@ -1066,7 +1057,7 @@ static bool map_storeat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
 	gravity_map_t *map = VALUE_AS_MAP(GET_VALUE(0));
 	gravity_value_t key = GET_VALUE(1);
 	gravity_value_t value = GET_VALUE(2);
-	
+    
 //    #ifdef GRAVITY_MAP_DOTSUGAR
 //    gravity_object_t *obj = (gravity_object_t *)gravity_class_lookup(gravity_class_map, key);
 //    if (obj) RETURN_VALUE(VALUE_FROM_OBJECT(obj), rindex);
@@ -1270,7 +1261,7 @@ static bool closure_disassemble (gravity_vm *vm, gravity_value_t *args, uint16_t
 	RETURN_VALUE(gravity_string_to_value(vm, buffer, AUTOLENGTH), rindex);
 }
 
-static bool closure_apply (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+static bool closure_apply (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {    
 	if (nargs != 3) RETURN_ERROR("Two arguments are needed by the apply function.");
 	if (!VALUE_ISA_LIST(GET_VALUE(2))) RETURN_ERROR("A list of arguments is required in the apply function.");
 	
@@ -1675,8 +1666,11 @@ static bool operator_string_add (gravity_vm *vm, gravity_value_t *args, uint16_t
 	char *s = NULL;
 	
 	// check if I can save an allocation
-	if (len+1<sizeof(buffer)) s = buffer;
-	else s = mem_alloc(len+1);
+	if (len+1 < sizeof(buffer)) s = buffer;
+    else {
+        s = mem_alloc(vm, len+1);
+        CHECK_MEM_ALLOC(s);
+    }
 	
 	memcpy(s, s1->s, s1->len);
 	memcpy(s+s1->len, s2->s, s2->len);
@@ -1706,10 +1700,11 @@ static bool operator_string_sub (gravity_vm *vm, gravity_value_t *args, uint16_t
 	if (flen == s2->len) RETURN_VALUE(VALUE_FROM_STRING(vm, s1->s, (uint32_t)(found - s1->s)), rindex);
 	// sanity check for malformed strings
     if (flen < s2->len) RETURN_ERROR("Malformed string.");
-    
+	
 	// substring found but cannot be entirely considered
 	uint32_t alloc = MAXNUM(s1->len + s2->len +1, DEFAULT_MINSTRING_SIZE);
-	char *s = mem_alloc(alloc);
+	char *s = mem_alloc(vm, alloc);
+    CHECK_MEM_ALLOC(s);
 	
 	uint32_t seek = (uint32_t)(found - s1->s);
 	uint32_t len = seek + (flen - s2->len);
@@ -1849,15 +1844,15 @@ static bool string_repeat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs
 
 	// figure out the size of the array we need to make to hold the new string
 	uint32_t new_size = (uint32_t)(main_str->len * times_to_repeat);
-	char *new_str = mem_alloc(new_size+1);
-	if (!new_str) RETURN_ERROR("Unable to allocate a String so big (%d)", new_size);
-	
+	char *new_str = mem_alloc(vm, new_size+1);
+    CHECK_MEM_ALLOC(new_str);
+    
     uint32_t seek = 0;
 	for (uint32_t i = 0; i < times_to_repeat; ++i) {
         memcpy(new_str+seek, main_str->s, main_str->len);
         seek += main_str->len;
 	}
-
+    
     gravity_string_t *s = gravity_string_new(vm, new_str, new_size, new_size);
 	RETURN_VALUE(VALUE_FROM_OBJECT(s), rindex);
 }
@@ -1865,8 +1860,8 @@ static bool string_repeat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs
 static bool string_upper (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
 	gravity_string_t *main_str = VALUE_AS_STRING(GET_VALUE(0));
 
-	char *ret = mem_alloc(main_str->len + 1);
-	if (!ret) RETURN_ERROR("Unable to allocate a String so big (%d)", main_str->len);
+	char *ret = mem_alloc(vm, main_str->len + 1);
+	CHECK_MEM_ALLOC(ret);
 	strcpy(ret, main_str->s);
 
 	// if no arguments passed, change the whole string to uppercase
@@ -1904,8 +1899,8 @@ static bool string_upper (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
 static bool string_lower (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
 	gravity_string_t *main_str = VALUE_AS_STRING(GET_VALUE(0));
 
-	char *ret = mem_alloc(main_str->len + 1);
-	if (!ret) RETURN_ERROR("Unable to allocate a String so big (%d)", main_str->len);
+	char *ret = mem_alloc(vm, main_str->len + 1);
+    CHECK_MEM_ALLOC(ret);
 	strcpy(ret, main_str->s);
 
 	// if no arguments passed, change the whole string to lowercase
@@ -1944,10 +1939,10 @@ static bool string_loadat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs
 	#pragma unused(nargs)
 	gravity_string_t *string = VALUE_AS_STRING(GET_VALUE(0));
 	gravity_value_t value = GET_VALUE(1);
-
+	
 	int32_t first_index;
 	int32_t second_index;
-
+	
 	if (VALUE_ISA_INT(value)) {
 		first_index = (int32_t)VALUE_AS_INT(value);
 		second_index = first_index;
@@ -1971,12 +1966,13 @@ static bool string_loadat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs
 
 	bool is_forward = first_index <= second_index;
 	if (!is_forward) {
-		char *original = mem_alloc(string->len);
-		if (!original) RETURN_ERROR("Unable to allocate a String so big (%d)", string->len);
+		char *original = mem_alloc(vm, string->len);
+        CHECK_MEM_ALLOC(original);
+		
 		// without copying it, we would be modifying the original string
 		strncpy((char *)original, string->s, string->len);
 		uint32_t original_len = (uint32_t) string->len;
-		
+	
 		// Reverse the string, and reverse the indices
 		first_index = original_len - first_index -1;
 
@@ -2050,7 +2046,7 @@ static bool string_split (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
 			break;
 		}
 		marray_push(gravity_value_t, list->array, VALUE_FROM_STRING(vm, original, (uint32_t)(p-original)));
-		
+        
         // update pointer and slen
 		original = p + seplen;
         slen = (uint32_t)(original - string->s);        
@@ -2170,13 +2166,13 @@ static bool fiber_yield (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
     
     // in no caller then this is just a NOP
     if (fiber->caller) {
-		gravity_vm_setfiber(vm, fiber->caller);
-	
-		// unhook this fiber from the one that called it
-		fiber->caller = NULL;
-		fiber->trying = false;
+        gravity_vm_setfiber(vm, fiber->caller);
+    
+        // unhook this fiber from the one that called it
+        fiber->caller = NULL;
+        fiber->trying = false;
 	
-		RETURN_FIBER();
+        RETURN_FIBER();
     } else {
         RETURN_NOVALUE();
     }
@@ -2463,7 +2459,7 @@ static void gravity_core_init (void) {
     // Meta
     gravity_class_t *null_meta = gravity_class_get_meta(gravity_class_null);
     gravity_class_bind(null_meta, GRAVITY_INTERNAL_EXEC_NAME, NEW_CLOSURE_VALUE(null_exec));
-	
+    
 	// CLASS CLASS
 	gravity_class_bind(gravity_class_class, "name", NEW_CLOSURE_VALUE(class_name));
 	gravity_class_bind(gravity_class_class, GRAVITY_INTERNAL_EXEC_NAME, NEW_CLOSURE_VALUE(class_exec));
@@ -2503,7 +2499,7 @@ static void gravity_core_init (void) {
 	gravity_class_bind(gravity_class_map, GRAVITY_INTERNAL_LOAD_NAME, NEW_CLOSURE_VALUE(map_loadat));
 	gravity_class_bind(gravity_class_map, GRAVITY_INTERNAL_STORE_NAME, NEW_CLOSURE_VALUE(map_storeat));
 	#endif
-	
+    
 	// RANGE CLASS
     closure = computed_property_create(NULL, NEW_FUNCTION(range_count), NULL);
 	gravity_class_bind(gravity_class_range, "count", VALUE_FROM_OBJECT(closure));
@@ -2514,7 +2510,7 @@ static void gravity_core_init (void) {
     // Meta
     gravity_class_t *range_meta = gravity_class_get_meta(gravity_class_range);
     gravity_class_bind(range_meta, GRAVITY_INTERNAL_EXEC_NAME, NEW_CLOSURE_VALUE(range_exec));
-	
+    
 	// INT CLASS
 	gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_ADD_NAME, NEW_CLOSURE_VALUE(operator_int_add));
 	gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_SUB_NAME, NEW_CLOSURE_VALUE(operator_int_sub));
@@ -2604,7 +2600,7 @@ static void gravity_core_init (void) {
     // Meta
     gravity_class_t *string_meta = gravity_class_get_meta(gravity_class_string);
     gravity_class_bind(string_meta, GRAVITY_INTERNAL_EXEC_NAME, NEW_CLOSURE_VALUE(string_exec));
-
+	
 	// FIBER CLASS
 	gravity_class_t *fiber_meta = gravity_class_get_meta(gravity_class_fiber);
 	gravity_class_bind(fiber_meta, "create", NEW_CLOSURE_VALUE(fiber_create));
@@ -2643,10 +2639,12 @@ static void gravity_core_init (void) {
 	
     closure = computed_property_create(NULL, NEW_FUNCTION(system_get), NEW_FUNCTION(system_set));
 	gravity_value_t value = VALUE_FROM_OBJECT(closure);
-	gravity_class_bind(system_meta, "gcenabled", value);
-	gravity_class_bind(system_meta, "gcminthreshold", value);
-	gravity_class_bind(system_meta, "gcthreshold", value);
-	gravity_class_bind(system_meta, "gcratio", value);
+	gravity_class_bind(system_meta, GRAVITY_VM_GCENABLED_KEY, value);
+	gravity_class_bind(system_meta, GRAVITY_VM_GCMINTHRESHOLD_KEY, value);
+	gravity_class_bind(system_meta, GRAVITY_VM_GCTHRESHOLD_KEY, value);
+	gravity_class_bind(system_meta, GRAVITY_VM_GCRATIO_KEY, value);
+    gravity_class_bind(system_meta, GRAVITY_VM_MAXCALLS_KEY, value);
+    gravity_class_bind(system_meta, GRAVITY_VM_MAXBLOCK_KEY, value);
 	
 	// INIT META
 	SETMETA_INITED(gravity_class_int);
@@ -2693,8 +2691,8 @@ void gravity_core_free (void) {
     computed_property_free(gravity_class_float, "radians", true);
     computed_property_free(gravity_class_float, "degrees", true);
     gravity_class_t *system_meta = gravity_class_get_meta(gravity_class_system);
-    computed_property_free(system_meta, "gcenabled", true);
-        
+    computed_property_free(system_meta, GRAVITY_VM_GCENABLED_KEY, true);
+    
 	gravity_class_free_core(NULL, gravity_class_get_meta(gravity_class_int));
 	gravity_class_free_core(NULL, gravity_class_int);
 	gravity_class_free_core(NULL, gravity_class_get_meta(gravity_class_float));
@@ -2723,9 +2721,11 @@ void gravity_core_free (void) {
 	gravity_class_free_core(NULL, gravity_class_upvalue);
 	
 	// before freeing the meta class we need to remove entries with duplicated functions
-	{STATICVALUE_FROM_STRING(key, "gcminthreshold", strlen("gcminthreshold")); gravity_hash_remove(system_meta->htable, key);}
-	{STATICVALUE_FROM_STRING(key, "gcthreshold", strlen("gcthreshold")); gravity_hash_remove(system_meta->htable, key);}
-	{STATICVALUE_FROM_STRING(key, "gcratio", strlen("gcratio")); gravity_hash_remove(system_meta->htable, key);}
+	{STATICVALUE_FROM_STRING(key, GRAVITY_VM_GCMINTHRESHOLD_KEY, strlen(GRAVITY_VM_GCMINTHRESHOLD_KEY)); gravity_hash_remove(system_meta->htable, key);}
+	{STATICVALUE_FROM_STRING(key, GRAVITY_VM_GCTHRESHOLD_KEY, strlen(GRAVITY_VM_GCTHRESHOLD_KEY)); gravity_hash_remove(system_meta->htable, key);}
+	{STATICVALUE_FROM_STRING(key, GRAVITY_VM_GCRATIO_KEY, strlen(GRAVITY_VM_GCRATIO_KEY)); gravity_hash_remove(system_meta->htable, key);}
+    {STATICVALUE_FROM_STRING(key, GRAVITY_VM_MAXCALLS_KEY, strlen(GRAVITY_VM_MAXCALLS_KEY)); gravity_hash_remove(system_meta->htable, key);}
+    {STATICVALUE_FROM_STRING(key, GRAVITY_VM_MAXBLOCK_KEY, strlen(GRAVITY_VM_MAXBLOCK_KEY)); gravity_hash_remove(system_meta->htable, key);}
 	gravity_class_free_core(NULL, system_meta);
 	gravity_class_free_core(NULL, gravity_class_system);
 	
@@ -2814,10 +2814,10 @@ gravity_class_t *gravity_core_class_from_name (const char *name) {
 bool gravity_iscore_class (gravity_class_t *c) {
 	// first check if it is a class
 	if ((c == gravity_class_object) || (c == gravity_class_class) || (c == gravity_class_bool) ||
-			(c == gravity_class_null) || (c == gravity_class_int) || (c == gravity_class_float) ||
-			(c == gravity_class_function) || (c == gravity_class_fiber) || (c == gravity_class_string) ||
-			(c == gravity_class_instance) || (c == gravity_class_list) || (c == gravity_class_map) ||
-			(c == gravity_class_range) || (c == gravity_class_system) || (c == gravity_class_closure) ||
+		(c == gravity_class_null) || (c == gravity_class_int) || (c == gravity_class_float) ||
+		(c == gravity_class_function) || (c == gravity_class_fiber) || (c == gravity_class_string) ||
+		(c == gravity_class_instance) || (c == gravity_class_list) || (c == gravity_class_map) ||
+		(c == gravity_class_range) || (c == gravity_class_system) || (c == gravity_class_closure) ||
 		(c == gravity_class_upvalue)) return true;
 	
 	// if class check is false then check for meta

+ 41 - 33
src/runtime/gravity_vm.c

@@ -37,9 +37,9 @@ struct gravity_vm {
 	uint32_t			pc;									// program counter
 	double				time;								// useful timer for the main function
 	bool				aborted;							// set when VM has generated a runtime error
-    uint32_t            maxncalls;                          // maximum number of nested c calls
+    uint32_t            maxccalls;                          // maximum number of nested c calls
     uint32_t            nccalls;                            // current number of nested c calls
-	
+    
 	// anonymous names
 	uint32_t			nanon;								// counter for anonymous classes (used in object_bind)
 	char				temp[64];							// temprary buffer used for anonymous names generator
@@ -52,6 +52,7 @@ struct gravity_vm {
 	// garbage collector
 	bool				gcenabled;							// flag to enable/disable garbage collector
 	gravity_int_t		memallocated;						// total number of allocated memory
+    gravity_int_t       maxmemblock;                        // maximum block memory size allowed to allocate
 	gravity_object_t	*gchead;							// head of garbage collected objects
 	gravity_int_t		gcminthreshold;						// minimum GC threshold size to avoid spending too much time in GC
 	gravity_int_t		gcthreshold;						// memory required to trigger a GC
@@ -170,7 +171,7 @@ static inline gravity_callframe_t *gravity_new_callframe (gravity_vm *vm, gravit
 	// check if there are enought slots in the call frame and optionally create new cframes
 	if (fiber->framesalloc - fiber->nframes < 1) {
 		uint32_t new_size = fiber->framesalloc * 2;
-        void *ptr = mem_realloc(fiber->frames, sizeof(gravity_callframe_t) * new_size);
+        void *ptr = mem_realloc(NULL, fiber->frames, sizeof(gravity_callframe_t) * new_size);
         if (!ptr) {
             // frames reallocation failed means that there is a very high probability to be into an infinite loop
             report_runtime_error(vm, GRAVITY_ERROR_RUNTIME, "Infinite loop detected. Current execution must be aborted.");
@@ -199,11 +200,11 @@ static inline bool gravity_check_stack (gravity_vm *vm, gravity_fiber_t *fiber,
 	uint32_t stack_needed = MAXNUM(stack_size + rneeds, DEFAULT_MINSTACK_SIZE);
 	if (fiber->stackalloc >= stack_needed) return true;
 	gravity_value_t *old_stack = fiber->stack;
-	
+    
 	// perform stack reallocation (power_of2_ceil returns 0 if argument is bigger than 2^31)
 	uint32_t new_size = power_of2_ceil(fiber->stackalloc + stack_needed);
     bool size_condition = (new_size && (uint64_t)new_size >= (uint64_t)(fiber->stackalloc + stack_needed) && ((sizeof(gravity_value_t) * new_size) < SIZE_MAX));
-    void *ptr = (size_condition) ? mem_realloc(fiber->stack, sizeof(gravity_value_t) * new_size) : NULL;
+    void *ptr = (size_condition) ? mem_realloc(NULL, fiber->stack, sizeof(gravity_value_t) * new_size) : NULL;
     if (!ptr) {
         // restore stacktop to previous state
         fiber->stacktop -= rneeds;
@@ -381,7 +382,7 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 						gravity_value_t r1copy = STACK_GET(r1);
 						if (!closure->f->internal(vm, &stackstart[rwin], 2, r1)) {
                             if (vm->aborted) return false;
-							
+                            
 							// check for special getter trick
 							if (VALUE_ISA_CLOSURE(STACK_GET(r1))) {
 								closure = VALUE_AS_CLOSURE(STACK_GET(r1));
@@ -599,10 +600,10 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 				// get registers
 				DEFINE_STACK_VARIABLE(v2,r2);
 				DEFINE_STACK_VARIABLE(v3,r3);
-				
+                
 				// prepare function call for binary operation
 				PREPARE_FUNC_CALL2(closure, v2, v3, (op == ISA) ? GRAVITY_ISA_INDEX : GRAVITY_MATCH_INDEX, rwin);
-				
+                
 				// call function f
 				CALL_FUNC(ISA, closure, r1, 2, rwin);
 				
@@ -1304,8 +1305,8 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 	return true;
 }
 
-gravity_vm *gravity_vm_new (gravity_delegate_t *delegate/*, uint32_t context_size, gravity_int_t gcminthreshold, gravity_int_t gcthreshold, gravity_float_t gcratio*/) {
-	gravity_vm *vm = mem_alloc(sizeof(gravity_vm));
+gravity_vm *gravity_vm_new (gravity_delegate_t *delegate) {
+	gravity_vm *vm = mem_alloc(NULL, sizeof(gravity_vm));
 	if (!vm) return NULL;
 	
 	// setup default callbacks
@@ -1314,18 +1315,19 @@ gravity_vm *gravity_vm_new (gravity_delegate_t *delegate/*, uint32_t context_siz
 	
 	// allocate default fiber
 	vm->fiber = gravity_fiber_new(vm, NULL, 0, 0);
-    vm->maxncalls = MAX_CCALLS;
-	
+    vm->maxccalls = MAX_CCALLS;
+    
 	vm->pc = 0;
 	vm->delegate = delegate;
-	vm->context = gravity_hash_create(/*(context_size) ? context_size : */DEFAULT_CONTEXT_SIZE, gravity_value_hash, gravity_value_equals, NULL, NULL);
+	vm->context = gravity_hash_create(DEFAULT_CONTEXT_SIZE, gravity_value_hash, gravity_value_equals, NULL, NULL);
 	
 	// garbage collector
 	vm->gcenabled = true;
-	vm->gcminthreshold = /*(gcminthreshold) ? gcminthreshold :*/ DEFAULT_CG_MINTHRESHOLD;
-	vm->gcthreshold = /*(gcthreshold) ? gcthreshold :*/ DEFAULT_CG_THRESHOLD;
-	vm->gcratio = /*(gcratio) ? gcratio :*/ DEFAULT_CG_RATIO;
+	vm->gcminthreshold = DEFAULT_CG_MINTHRESHOLD;
+	vm->gcthreshold = DEFAULT_CG_THRESHOLD;
+	vm->gcratio = DEFAULT_CG_RATIO;
 	vm->memallocated = 0;
+    vm->maxmemblock = MAX_MEMORY_BLOCK;
 	marray_init(vm->graylist);
 	marray_init(vm->gcsave);
 	
@@ -1338,7 +1340,7 @@ gravity_vm *gravity_vm_new (gravity_delegate_t *delegate/*, uint32_t context_siz
 }
 
 gravity_vm *gravity_vm_newmini (void) {
-	gravity_vm *vm = mem_alloc(sizeof(gravity_vm));
+	gravity_vm *vm = mem_alloc(NULL, sizeof(gravity_vm));
 	return vm;
 }
 
@@ -1399,7 +1401,7 @@ void gravity_vm_seterror (gravity_vm* vm, const char *format, ...) {
 	
 	if (fiber->error) mem_free(fiber->error);
 	size_t err_size = 2048;
-	fiber->error = mem_alloc(err_size);
+	fiber->error = mem_alloc(NULL, err_size);
 	
 	va_list arg;
 	va_start (arg, format);
@@ -1523,7 +1525,7 @@ bool gravity_vm_runclosure (gravity_vm *vm, gravity_closure_t *closure, gravity_
 	switch (f->tag) {
 		case EXEC_TYPE_NATIVE:
             ++vm->nccalls;
-            if (vm->nccalls > vm->maxncalls) RUNTIME_ERROR("Maximum number of nested C calls reached (%d).", vm->maxncalls);
+            if (vm->nccalls > vm->maxccalls) RUNTIME_ERROR("Maximum number of nested C calls reached (%d).", vm->maxccalls);
 			result = gravity_vm_exec(vm);
             --vm->nccalls;
 			break;
@@ -1646,26 +1648,32 @@ void gravity_vm_memupdate (gravity_vm *vm, gravity_int_t value) {
 	vm->memallocated += value;
 }
 
+gravity_int_t gravity_vm_maxmemblock (gravity_vm *vm) {
+    return vm->maxmemblock;
+}
+
 // MARK: - Get/Set Internal Settings -
 
 gravity_value_t gravity_vm_get (gravity_vm *vm, const char *key) {
 	if (key) {
-		if (strcmp(key, "gcenabled") == 0) return VALUE_FROM_BOOL(vm->gcenabled);
-		if (strcmp(key, "gcminthreshold") == 0) return VALUE_FROM_INT(vm->gcminthreshold);
-		if (strcmp(key, "gcthreshold") == 0) return VALUE_FROM_INT(vm->gcthreshold);
-		if (strcmp(key, "gcratio") == 0) return VALUE_FROM_FLOAT(vm->gcratio);
-        if (strcmp(key, "maxncalls") == 0) return VALUE_FROM_INT(vm->maxncalls);
+		if (strcmp(key, GRAVITY_VM_GCENABLED_KEY) == 0) return VALUE_FROM_BOOL(vm->gcenabled);
+		if (strcmp(key, GRAVITY_VM_GCMINTHRESHOLD_KEY) == 0) return VALUE_FROM_INT(vm->gcminthreshold);
+		if (strcmp(key, GRAVITY_VM_GCTHRESHOLD_KEY) == 0) return VALUE_FROM_INT(vm->gcthreshold);
+		if (strcmp(key, GRAVITY_VM_GCRATIO_KEY) == 0) return VALUE_FROM_FLOAT(vm->gcratio);
+        if (strcmp(key, GRAVITY_VM_MAXCALLS_KEY) == 0) return VALUE_FROM_INT(vm->maxccalls);
+        if (strcmp(key, GRAVITY_VM_MAXBLOCK_KEY) == 0) return VALUE_FROM_INT(vm->maxmemblock);
 	}
 	return VALUE_FROM_NULL;
 }
 
 bool gravity_vm_set (gravity_vm *vm, const char *key, gravity_value_t value) {
 	if (key) {
-		if ((strcmp(key, "gcenabled") == 0) && VALUE_ISA_BOOL(value)) {vm->gcenabled = VALUE_AS_BOOL(value); return true;}
-		if ((strcmp(key, "gcminthreshold") == 0) && VALUE_ISA_INT(value)) {vm->gcminthreshold = VALUE_AS_INT(value); return true;}
-		if ((strcmp(key, "gcthreshold") == 0) && VALUE_ISA_INT(value)) {vm->gcthreshold = VALUE_AS_INT(value); return true;}
-		if ((strcmp(key, "gcratio") == 0) && VALUE_ISA_FLOAT(value)) {vm->gcratio = VALUE_AS_FLOAT(value); return true;}
-        if ((strcmp(key, "maxncalls") == 0) && VALUE_ISA_INT(value)) {vm->maxncalls = (uint32_t)VALUE_AS_INT(value); return true;}
+		if ((strcmp(key, GRAVITY_VM_GCENABLED_KEY) == 0) && VALUE_ISA_BOOL(value)) {vm->gcenabled = VALUE_AS_BOOL(value); return true;}
+		if ((strcmp(key, GRAVITY_VM_GCMINTHRESHOLD_KEY) == 0) && VALUE_ISA_INT(value)) {vm->gcminthreshold = VALUE_AS_INT(value); return true;}
+		if ((strcmp(key, GRAVITY_VM_GCTHRESHOLD_KEY) == 0) && VALUE_ISA_INT(value)) {vm->gcthreshold = VALUE_AS_INT(value); return true;}
+		if ((strcmp(key, GRAVITY_VM_GCRATIO_KEY) == 0) && VALUE_ISA_FLOAT(value)) {vm->gcratio = VALUE_AS_FLOAT(value); return true;}
+        if ((strcmp(key, GRAVITY_VM_MAXCALLS_KEY) == 0) && VALUE_ISA_INT(value)) {vm->maxccalls = (uint32_t)VALUE_AS_INT(value); return true;}
+        if ((strcmp(key, GRAVITY_VM_MAXBLOCK_KEY) == 0) && VALUE_ISA_INT(value)) {vm->maxmemblock = (uint32_t)VALUE_AS_INT(value); return true;}
 	}
 	return false;
 }
@@ -1794,10 +1802,10 @@ gravity_closure_t *gravity_vm_loadfile (gravity_vm *vm, const char *path) {
 }
 
 gravity_closure_t *gravity_vm_loadbuffer (gravity_vm *vm, const char *buffer, size_t len) {
-	// state buffer for further processing super classes
-	void_r objects;
-	marray_init(objects);
-	
+    // state buffer for further processing super classes
+    void_r objects;
+    marray_init(objects);
+    
     // start json parsing
 	json_value *json = json_parse (buffer, len);
 	if (!json) goto abort_load;

+ 8 - 1
src/runtime/gravity_vm.h

@@ -15,6 +15,13 @@
 #ifdef __cplusplus
 extern "C" {
 #endif
+    
+#define GRAVITY_VM_GCENABLED_KEY            "gcenabled"
+#define GRAVITY_VM_GCMINTHRESHOLD_KEY       "gcminthreshold"
+#define GRAVITY_VM_GCTHRESHOLD_KEY          "gcthreshold"
+#define GRAVITY_VM_GCRATIO_KEY              "gcratio"
+#define GRAVITY_VM_MAXCALLS_KEY             "maxcalls"
+#define GRAVITY_VM_MAXBLOCK_KEY             "maxblock"
 
 typedef bool (*vm_filter_cb) (gravity_object_t *obj);
 typedef void (*vm_transfer_cb) (gravity_vm *vm, gravity_object_t *obj);
@@ -44,7 +51,6 @@ GRAVITY_API bool				gravity_vm_isaborted (gravity_vm *vm);
 GRAVITY_API void				gravity_vm_setaborted (gravity_vm *vm);
 GRAVITY_API gravity_closure_t   *gravity_vm_getclosure (gravity_vm *vm);
     
-
 GRAVITY_API void				gravity_gray_value (gravity_vm* vm, gravity_value_t v);
 GRAVITY_API void				gravity_gray_object (gravity_vm* vm, gravity_object_t *obj);
 GRAVITY_API void				gravity_gc_start (gravity_vm* vm);
@@ -66,6 +72,7 @@ GRAVITY_API gravity_value_t		gravity_vm_getslot (gravity_vm *vm, uint32_t index)
 GRAVITY_API void				gravity_vm_setdata (gravity_vm *vm, void *data);
 GRAVITY_API void				*gravity_vm_getdata (gravity_vm *vm);
 GRAVITY_API void				gravity_vm_memupdate (gravity_vm *vm, gravity_int_t value);
+GRAVITY_API gravity_int_t       gravity_vm_maxmemblock (gravity_vm *vm);
 
 GRAVITY_API gravity_value_t		gravity_vm_get (gravity_vm *vm, const char *key);
 GRAVITY_API bool				gravity_vm_set (gravity_vm *vm, const char *key, gravity_value_t value);

+ 5 - 1
src/runtime/gravity_vmmacros.h

@@ -280,7 +280,11 @@
                                                         gravity_vm_setslot(vm, VALUE_FROM_NULL, rindex);                                    \
                                                         return false;                                                                       \
                                                     } while(0)
-
+#define RETURN_ERROR_SIMPLE()                       do {                                                                                    \
+                                                        gravity_vm_setslot(vm, VALUE_FROM_NULL, rindex);                                    \
+                                                        return false;                                                                       \
+                                                    } while(0)
+#define CHECK_MEM_ALLOC(_ptr)                       if (!_ptr) RETURN_ERROR_SIMPLE();
 #define DECLARE_1VARIABLE(_v,_idx)                  register gravity_value_t _v = GET_VALUE(_idx)
 #define DECLARE_2VARIABLES(_v1,_v2,_idx1,_idx2)     DECLARE_1VARIABLE(_v1,_idx1);DECLARE_1VARIABLE(_v2,_idx2)
 

+ 4 - 4
src/shared/gravity_hash.c

@@ -162,9 +162,9 @@ gravity_hash_t *gravity_hash_create (uint32_t size, gravity_hash_compute_fn comp
 	if ((!compute) || (!isequal)) return NULL;
 	if (size == 0) size = GRAVITYHASH_DEFAULT_SIZE;
 	
-	gravity_hash_t *hashtable = (gravity_hash_t *)mem_alloc(sizeof(gravity_hash_t));
+	gravity_hash_t *hashtable = (gravity_hash_t *)mem_alloc(NULL, sizeof(gravity_hash_t));
 	if (!hashtable) return NULL;
-	if (!(hashtable->nodes = mem_calloc(size, sizeof(hash_node_t*)))) {mem_free(hashtable); return NULL;}
+	if (!(hashtable->nodes = mem_calloc(NULL, size, sizeof(hash_node_t*)))) {mem_free(hashtable); return NULL;}
 	
 	hashtable->compute_fn = compute;
 	hashtable->isequal_fn = isequal;
@@ -211,7 +211,7 @@ static inline int gravity_hash_resize (gravity_hash_t *hashtable) {
 		.isequal_fn = hashtable->isequal_fn,
 		.compute_fn = hashtable->compute_fn
 	};
-	if (!(newtbl.nodes = mem_calloc(size, sizeof(hash_node_t*)))) return -1;
+	if (!(newtbl.nodes = mem_calloc(NULL, size, sizeof(hash_node_t*)))) return -1;
 	
 	hash_node_t *node, *next;
 	for (uint32_t n = 0; n < hashtable->size; ++n) {
@@ -285,7 +285,7 @@ bool gravity_hash_insert (gravity_hash_t *hashtable, gravity_value_t key, gravit
 	}
 	
 	// allocate new entry and set new data
-	if (!(node = mem_alloc(sizeof(hash_node_t)))) return -1;
+	if (!(node = mem_alloc(NULL, sizeof(hash_node_t)))) return -1;
 	node->key = key;
 	node->hash = hash;
 	node->value = value;

+ 30 - 10
src/shared/gravity_memory.c

@@ -7,11 +7,27 @@
 //
 
 #include "gravity_memory.h"
-#if GRAVITY_MEMORY_DEBUG
+#include "gravity_vm.h"
 
-#include <stdlib.h>
-#include <strings.h>
+#if !GRAVITY_MEMORY_DEBUG
 
+void *gravity_calloc(gravity_vm *vm, size_t count, size_t size) {
+    if (vm && ((count * size) >= gravity_vm_maxmemblock(vm))) {
+        gravity_vm_seterror(vm, "Maximum memory allocation block size reached (req: %d, max: %lld).", (count * size), (int64_t)gravity_vm_maxmemblock(vm));
+        return NULL;
+    }
+    return calloc(count, size);;
+}
+
+void *gravity_realloc(gravity_vm *vm, void *ptr, size_t new_size) {
+    if (vm && (new_size >= gravity_vm_maxmemblock(vm))) {
+        gravity_vm_seterror(vm, "Maximum memory re-allocation block size reached (req: %d, max: %lld).", new_size, (int64_t)gravity_vm_maxmemblock(vm));
+        return NULL;
+    }
+    return realloc(ptr, new_size);
+}
+
+#else
 #if _WIN32
 #include <imagehlp.h>
 #else
@@ -93,7 +109,8 @@ void memdebug_init (void) {
 	memdebug.aslot = SLOT_MIN;
 }
 
-void *memdebug_malloc(size_t size) {
+void *memdebug_malloc(gravity_vm *vm, size_t size) {
+    #pragma unused(vm)
 	void *ptr = malloc(size);
 	if (!ptr) {
 		BUILD_ERROR("Unable to allocated a block of %zu bytes", size);
@@ -106,11 +123,13 @@ void *memdebug_malloc(size_t size) {
 	return ptr;
 }
 
-void *memdebug_malloc0(size_t size) {
-	return memdebug_calloc(1, size);
+void *memdebug_malloc0(gravity_vm *vm, size_t size) {
+    #pragma unused(vm)
+	return memdebug_calloc(vm, 1, size);
 }
 
-void *memdebug_calloc(size_t num, size_t size) {
+void *memdebug_calloc(gravity_vm *vm, size_t num, size_t size) {
+    #pragma unused(vm)
 	void *ptr = calloc(num, size);
 	if (!ptr) {
 		BUILD_ERROR("Unable to allocated a block of %zu bytes", size);
@@ -123,7 +142,8 @@ void *memdebug_calloc(size_t num, size_t size) {
 	return ptr;
 }
 
-void *memdebug_realloc(void *ptr, size_t new_size) {
+void *memdebug_realloc(gravity_vm *vm, void *ptr, size_t new_size) {
+    #pragma unused(vm)
 	// ensure ptr has been previously allocated by malloc, calloc or realloc and not yet freed with free
 	uint32_t index = _ptr_lookup(ptr);
 	if (index == SLOT_NOTFOUND) {
@@ -312,8 +332,8 @@ uint32_t _ptr_lookup (void *ptr) {
 
 char **_ptr_stacktrace (size_t *nframes) {
 	#if _WIN32
-	http://www.codeproject.com/Articles/11132/Walking-the-callstack
-	https://spin.atomicobject.com/2013/01/13/exceptions-stack-traces-c/
+	// http://www.codeproject.com/Articles/11132/Walking-the-callstack
+	// https://spin.atomicobject.com/2013/01/13/exceptions-stack-traces-c/
 	#else
 	void *callstack[STACK_DEPTH];
 	int n = backtrace(callstack, STACK_DEPTH);

+ 36 - 27
src/shared/gravity_memory.h

@@ -12,46 +12,55 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdbool.h>
+#include <strings.h>
 
-// memory debugger must be turned on ONLY with GuardMalloc ON
-#define GRAVITY_MEMORY_DEBUG		0
+// memory debugger must be turned on ONLY with Xcode GuardMalloc ON
+#define GRAVITY_MEMORY_DEBUG            0
+
+#ifndef GRAVITY_VM_DEFINED
+#define GRAVITY_VM_DEFINED
+typedef struct gravity_vm				gravity_vm;
+#endif
 
 #if GRAVITY_MEMORY_DEBUG
-#define mem_init()					memdebug_init()
-#define mem_stat()					memdebug_stat()
-#define mem_alloc					memdebug_malloc0
-#define mem_calloc					memdebug_calloc
-#define mem_realloc					memdebug_realloc
-#define mem_free(v)					memdebug_free((void *)v)
-#define mem_check(v)				memdebug_setcheck(v)
-#define mem_status					memdebug_status
-#define mem_leaks()					memdebug_leaks()
-#define mem_remove					memdebug_remove
+#define mem_init()                      memdebug_init()
+#define mem_stat()                      memdebug_stat()
+#define mem_alloc(_vm,_size)            memdebug_malloc0(_vm,_size)
+#define mem_calloc(_vm,_count,_size)    memdebug_calloc(_vm,_count,_size)
+#define mem_realloc(_vm,_ptr,_size)     memdebug_realloc(_vm,_ptr,_size)
+#define mem_free(v)                     memdebug_free((void *)v)
+#define mem_check(v)                    memdebug_setcheck(v)
+#define mem_status                      memdebug_status
+#define mem_leaks()                     memdebug_leaks()
+#define mem_remove                      memdebug_remove
 #else
 #define mem_init()
 #define mem_stat()
-#define mem_alloc(size)				calloc(1, size)
-#define mem_calloc					calloc
-#define mem_realloc					realloc
-#define mem_free(v)					free((void *)v)
+#define mem_alloc(_vm,_size)            gravity_calloc(_vm, 1, _size)
+#define mem_calloc(_vm,_count,_size)	gravity_calloc(_vm, _count, _size)
+#define mem_realloc(_vm,_ptr,_size)     gravity_realloc(_vm, _ptr, _size)
+#define mem_free(v)                     free((void *)v)
 #define mem_check(v)
-#define mem_status()				0
-#define mem_leaks()					0
+#define mem_status()                    0
+#define mem_leaks()                     0
 #define mem_remove(_v)
 #endif
 
 #if GRAVITY_MEMORY_DEBUG
-void	memdebug_init(void);
-void	*memdebug_malloc(size_t size);
-void	*memdebug_malloc0(size_t size);
-void	*memdebug_calloc(size_t num, size_t size);
-void	*memdebug_realloc(void *ptr, size_t new_size);
-void	memdebug_free(void *ptr);
+void	memdebug_init (void);
+void	*memdebug_malloc (gravity_vm *vm, size_t size);
+void	*memdebug_malloc0 (gravity_vm *vm, size_t size);
+void	*memdebug_calloc (gravity_vm *vm, size_t num, size_t size);
+void	*memdebug_realloc (gravity_vm *vm, void *ptr, size_t new_size);
+void	memdebug_free (void *ptr);
 size_t	memdebug_leaks (void);
 size_t	memdebug_status (void);
-void	memdebug_setcheck(bool flag);
-void	memdebug_stat(void);
-bool	memdebug_remove(void *ptr);
+void	memdebug_setcheck (bool flag);
+void	memdebug_stat (void);
+bool	memdebug_remove (void *ptr);
+#else
+void    *gravity_calloc (gravity_vm *vm, size_t count, size_t size);
+void    *gravity_realloc (gravity_vm *vm, void *ptr, size_t new_size);
 #endif
 
 #endif

+ 34 - 34
src/shared/gravity_value.c

@@ -82,7 +82,7 @@ static void gravity_hash_gray (gravity_hash_t *table, gravity_value_t key, gravi
 // MARK: -
 
 gravity_module_t *gravity_module_new (gravity_vm *vm, const char *identifier) {
-	gravity_module_t *m = (gravity_module_t *)mem_alloc(sizeof(gravity_module_t));
+	gravity_module_t *m = (gravity_module_t *)mem_alloc(NULL, sizeof(gravity_module_t));
 	assert(m);
 	
 	m->isa = gravity_class_module;
@@ -131,7 +131,7 @@ bool gravity_class_grow (gravity_class_t *c, uint32_t n) {
 	if (c->ivars) mem_free(c->ivars);
 	if (c->nivars + n >= MAX_IVARS) return false;
 	c->nivars += n;
-	c->ivars = (gravity_value_t *)mem_alloc(c->nivars * sizeof(gravity_value_t));
+	c->ivars = (gravity_value_t *)mem_alloc(NULL, c->nivars * sizeof(gravity_value_t));
 	for (uint32_t i=0; i<c->nivars; ++i) c->ivars[i] = VALUE_FROM_NULL;
 	return true;
 }
@@ -153,7 +153,7 @@ bool gravity_class_setsuper (gravity_class_t *baseclass, gravity_class_t *superc
 }
 
 gravity_class_t *gravity_class_new_single (gravity_vm *vm, const char *identifier, uint32_t nivar) {
-	gravity_class_t *c = (gravity_class_t *)mem_alloc(sizeof(gravity_class_t));
+	gravity_class_t *c = (gravity_class_t *)mem_alloc(NULL, sizeof(gravity_class_t));
 	assert(c);
 	
 	c->isa = gravity_class_class;
@@ -162,7 +162,7 @@ gravity_class_t *gravity_class_new_single (gravity_vm *vm, const char *identifie
 	c->nivars = nivar;
 	c->htable = gravity_hash_create(0, gravity_value_hash, gravity_value_equals, gravity_hash_keyfree, NULL);
 	if (nivar) {
-		c->ivars = (gravity_value_t *)mem_alloc(nivar * sizeof(gravity_value_t));
+		c->ivars = (gravity_value_t *)mem_alloc(NULL, nivar * sizeof(gravity_value_t));
 		for (uint32_t i=0; i<nivar; ++i) c->ivars[i] = VALUE_FROM_NULL;
 	}
 	
@@ -457,7 +457,7 @@ void gravity_class_blacken (gravity_vm *vm, gravity_class_t *c) {
 // MARK: -
 
 gravity_function_t *gravity_function_new (gravity_vm *vm, const char *identifier, uint16_t nparams, uint16_t nlocals, uint16_t ntemps, void *code) {
-	gravity_function_t *f = (gravity_function_t *)mem_alloc(sizeof(gravity_function_t));
+	gravity_function_t *f = (gravity_function_t *)mem_alloc(NULL, sizeof(gravity_function_t));
 	assert(f);
 	
 	f->isa = gravity_class_function;
@@ -581,7 +581,7 @@ static void gravity_function_bytecode_serialize (gravity_function_t *f, json_t *
 	
 	uint32_t ninst = f->ninsts;
 	uint32_t length = ninst * 2 * sizeof(uint32_t);
-	uint8_t *hexchar = (uint8_t*) mem_alloc(sizeof(uint8_t) * length);
+	uint8_t *hexchar = (uint8_t*) mem_alloc(NULL, sizeof(uint8_t) * length);
 	
 	for (uint32_t k=0, i=0; i < ninst; ++i) {
 		uint32_t value = f->bytecode[i];
@@ -598,7 +598,7 @@ static void gravity_function_bytecode_serialize (gravity_function_t *f, json_t *
 
 uint32_t *gravity_bytecode_deserialize (const char *buffer, size_t len, uint32_t *n) {
 	uint32_t ninst = (uint32_t)len / 8;
-	uint32_t *bytecode = (uint32_t *)mem_alloc(sizeof(uint32_t) * (ninst + 1));	// +1 to get a 0 terminated bytecode (0 is opcode RET0)
+	uint32_t *bytecode = (uint32_t *)mem_alloc(NULL, sizeof(uint32_t) * (ninst + 1));	// +1 to get a 0 terminated bytecode (0 is opcode RET0)
 	
 	for (uint32_t j=0; j<ninst; ++j) {
 		register uint32_t v = 0;
@@ -633,7 +633,7 @@ uint32_t *gravity_bytecode_deserialize (const char *buffer, size_t len, uint32_t
 	return bytecode;
 	
 abort_conversion:
-	*n = 0;
+    *n = 0;
 	if (bytecode) mem_free(bytecode);
 	return NULL;
 }
@@ -849,11 +849,11 @@ gravity_function_t *gravity_function_deserialize (gravity_vm *vm, json_value *js
             if (value->type == json_null) {
                 // if function is empty then just one RET0 implicit bytecode instruction
                 f->ninsts = 0;
-                f->bytecode = (uint32_t *)mem_alloc(sizeof(uint32_t) * (f->ninsts + 1));
+                f->bytecode = (uint32_t *)mem_alloc(NULL, sizeof(uint32_t) * (f->ninsts + 1));
             } else {
-			if (value->type != json_string) goto abort_load;
-            if (f->tag != EXEC_TYPE_NATIVE) goto abort_load;
-			f->bytecode = gravity_bytecode_deserialize(value->u.string.ptr, value->u.string.length, &f->ninsts);
+                if (value->type != json_string) goto abort_load;
+                if (f->tag != EXEC_TYPE_NATIVE) goto abort_load;
+                f->bytecode = gravity_bytecode_deserialize(value->u.string.ptr, value->u.string.length, &f->ninsts);
             }
             bytecode_parsed = true;
 			continue;
@@ -888,14 +888,14 @@ gravity_function_t *gravity_function_deserialize (gravity_vm *vm, json_value *js
 						
 					case json_object: {
 						gravity_object_t *obj = gravity_object_deserialize(vm, r);
-						if (!obj) goto abort_load;
+						if (!obj) goto abort_load;						
 						gravity_function_cpool_add(NULL, f, VALUE_FROM_OBJECT(obj));
 						break;
 					}
 						
 					case json_array: {
 						uint32_t count = r->u.array.length;
-						gravity_list_t *list = gravity_list_new(NULL, count);
+						gravity_list_t *list = gravity_list_new (NULL, count);
                         if (!list) continue;
                         
 						for (uint32_t k=0; k<count; ++k) {
@@ -949,7 +949,7 @@ void gravity_function_free (gravity_vm *vm, gravity_function_t *f) {
 		if (f->bytecode) mem_free((void *)f->bytecode);
 		// DO NOT FREE EACH INDIVIDUAL CPOOL ITEM HERE
 		marray_destroy(f->cpool);
-	}
+    }    
 	mem_free((void *)f);
 }
 
@@ -999,7 +999,7 @@ void gravity_function_blacken (gravity_vm *vm, gravity_function_t *f) {
 gravity_closure_t *gravity_closure_new (gravity_vm *vm, gravity_function_t *f) {
 	#pragma unused(vm)
 	
-	gravity_closure_t *closure = (gravity_closure_t *)mem_alloc(sizeof(gravity_closure_t));
+	gravity_closure_t *closure = (gravity_closure_t *)mem_alloc(NULL, sizeof(gravity_closure_t));
 	assert(closure);
 	
 	closure->isa = gravity_class_closure;
@@ -1007,7 +1007,7 @@ gravity_closure_t *gravity_closure_new (gravity_vm *vm, gravity_function_t *f) {
 	
 	// allocate upvalue array (+1 so I can simplify the iterator without the needs to access closure->f->nupvalues)
 	uint16_t nupvalues = (f) ? f->nupvalues : 0;
-	closure->upvalue = (nupvalues) ? (gravity_upvalue_t **)mem_alloc(sizeof(gravity_upvalue_t*) * (f->nupvalues + 1)) : NULL;
+	closure->upvalue = (nupvalues) ? (gravity_upvalue_t **)mem_alloc(NULL, sizeof(gravity_upvalue_t*) * (f->nupvalues + 1)) : NULL;
 	
 	if (vm) gravity_vm_transfer(vm, (gravity_object_t*)closure);
 	return closure;
@@ -1052,7 +1052,7 @@ void gravity_closure_blacken (gravity_vm *vm, gravity_closure_t *closure) {
 
 gravity_upvalue_t *gravity_upvalue_new (gravity_vm *vm, gravity_value_t *value) {
 	#pragma unused(vm)
-	gravity_upvalue_t *upvalue = (gravity_upvalue_t *)mem_alloc(sizeof(gravity_upvalue_t));
+	gravity_upvalue_t *upvalue = (gravity_upvalue_t *)mem_alloc(NULL, sizeof(gravity_upvalue_t));
 	
 	upvalue->isa = gravity_class_upvalue;
 	upvalue->value = value;
@@ -1084,7 +1084,7 @@ void gravity_upvalue_free(gravity_vm *vm, gravity_upvalue_t *upvalue) {
 // MARK: -
 
 gravity_fiber_t *gravity_fiber_new (gravity_vm *vm, gravity_closure_t *closure, uint32_t nstack, uint32_t nframes) {
-	gravity_fiber_t *fiber = (gravity_fiber_t *)mem_alloc(sizeof(gravity_fiber_t));
+	gravity_fiber_t *fiber = (gravity_fiber_t *)mem_alloc(NULL, sizeof(gravity_fiber_t));
 	assert(fiber);
 	
 	fiber->isa = gravity_class_fiber;
@@ -1092,12 +1092,12 @@ gravity_fiber_t *gravity_fiber_new (gravity_vm *vm, gravity_closure_t *closure,
 	fiber->result = VALUE_FROM_NULL;
 	
 	if (nstack < DEFAULT_MINSTACK_SIZE) nstack = DEFAULT_MINSTACK_SIZE;
-	fiber->stack = (gravity_value_t *)mem_alloc(sizeof(gravity_value_t) * nstack);
+	fiber->stack = (gravity_value_t *)mem_alloc(NULL, sizeof(gravity_value_t) * nstack);
 	fiber->stacktop = fiber->stack;
 	fiber->stackalloc = nstack;
 	
 	if (nframes < DEFAULT_MINCFRAME_SIZE) nframes = DEFAULT_MINCFRAME_SIZE;
-	fiber->frames = (gravity_callframe_t *)mem_alloc(sizeof(gravity_callframe_t) * nframes);
+	fiber->frames = (gravity_callframe_t *)mem_alloc(NULL, sizeof(gravity_callframe_t) * nframes);
 	fiber->framesalloc = nframes;
 	fiber->nframes = 1;
 	
@@ -1358,7 +1358,7 @@ void gravity_object_blacken (gravity_vm *vm, gravity_object_t *obj) {
 // MARK: -
 
 gravity_instance_t *gravity_instance_new (gravity_vm *vm, gravity_class_t *c) {
-	gravity_instance_t *instance = (gravity_instance_t *)mem_alloc(sizeof(gravity_instance_t) + (c->nivars * sizeof(gravity_value_t)));
+	gravity_instance_t *instance = (gravity_instance_t *)mem_alloc(NULL, sizeof(gravity_instance_t) + (c->nivars * sizeof(gravity_value_t)));
 	
 	instance->isa = gravity_class_instance;
 	instance->objclass = c;
@@ -1371,7 +1371,7 @@ gravity_instance_t *gravity_instance_new (gravity_vm *vm, gravity_class_t *c) {
 gravity_instance_t *gravity_instance_dup (gravity_vm *vm, gravity_instance_t *src) {
 	gravity_class_t *c = src->objclass;
 	
-	gravity_instance_t *instance = (gravity_instance_t *)mem_alloc(sizeof(gravity_instance_t) + (c->nivars * sizeof(gravity_value_t)));
+	gravity_instance_t *instance = (gravity_instance_t *)mem_alloc(NULL, sizeof(gravity_instance_t) + (c->nivars * sizeof(gravity_value_t)));
 	instance->objclass = c;
 	for (uint32_t i=0; i<c->nivars; ++i) instance->ivars[i] = src->ivars[i];
 	
@@ -1464,7 +1464,7 @@ bool gravity_value_equals (gravity_value_t v1, gravity_value_t v2) {
 	
 	// check same class
 	if (v1.isa != v2.isa) return false;
-	
+    
 	// check same value for value types
 	if ((v1.isa == gravity_class_int) || (v1.isa == gravity_class_bool) || (v1.isa == gravity_class_null)) {
 		return (v1.n == v2.n);
@@ -1500,13 +1500,13 @@ bool gravity_value_equals (gravity_value_t v1, gravity_value_t v2) {
         gravity_map_t *map1 = VALUE_AS_MAP(v1);
         gravity_map_t *map2 = VALUE_AS_MAP(v2);
         return gravity_hash_compare(map1->hash, map2->hash, hash_value_compare_cb, NULL);
-	}
+    }
 	
 	// if here means that they are two heap allocated objects
 	gravity_object_t *obj1 = VALUE_AS_OBJECT(v1);
 	gravity_object_t *obj2 = VALUE_AS_OBJECT(v2);
 	if (obj1->isa != obj2->isa) return false;
-	
+    
 	return (obj1 == obj2);
 }
 
@@ -1768,7 +1768,7 @@ void gravity_value_dump (gravity_vm *vm, gravity_value_t v, char *buffer, uint16
 gravity_list_t *gravity_list_new (gravity_vm *vm, uint32_t n) {
     if (n > MAX_ALLOCATION) return NULL;
     
-	gravity_list_t *list = (gravity_list_t *)mem_alloc(sizeof(gravity_list_t));
+	gravity_list_t *list = (gravity_list_t *)mem_alloc(NULL, sizeof(gravity_list_t));
 	
 	list->isa = gravity_class_list;
 	marray_init(list->array);
@@ -1779,7 +1779,7 @@ gravity_list_t *gravity_list_new (gravity_vm *vm, uint32_t n) {
 }
 
 gravity_list_t *gravity_list_from_array (gravity_vm *vm, uint32_t n, gravity_value_t *p) {
-	gravity_list_t *list = (gravity_list_t *)mem_alloc(sizeof(gravity_list_t));
+	gravity_list_t *list = (gravity_list_t *)mem_alloc(NULL, sizeof(gravity_list_t));
 	
 	list->isa = gravity_class_list;
 	marray_init(list->array);
@@ -1828,7 +1828,7 @@ void gravity_list_blacken (gravity_vm *vm, gravity_list_t *list) {
 
 // MARK: -
 gravity_map_t *gravity_map_new (gravity_vm *vm, uint32_t n) {
-	gravity_map_t *map = (gravity_map_t *)mem_alloc(sizeof(gravity_map_t));
+	gravity_map_t *map = (gravity_map_t *)mem_alloc(NULL, sizeof(gravity_map_t));
 	
 	map->isa = gravity_class_map;
 	map->hash = gravity_hash_create(n, gravity_value_hash, gravity_value_equals, NULL, NULL);
@@ -1865,7 +1865,7 @@ static gravity_map_t *gravity_map_deserialize (gravity_vm *vm, json_value *json)
 	for (uint32_t i=1; i<n; ++i) { // from 1 to skip type
 		const char *label = json->u.object.values[i].name;
 		json_value *jsonv = json->u.object.values[i].value;
-		
+        
 		gravity_value_t	key = VALUE_FROM_CSTRING(vm, label);
 		gravity_value_t	value;
 		
@@ -1901,7 +1901,7 @@ void gravity_map_blacken (gravity_vm *vm, gravity_map_t *map) {
 // MARK: -
 
 gravity_range_t *gravity_range_new (gravity_vm *vm, gravity_int_t from_range, gravity_int_t to_range, bool inclusive) {
-	gravity_range_t *range = mem_alloc(sizeof(gravity_range_t));
+	gravity_range_t *range = mem_alloc(NULL, sizeof(gravity_range_t));
 	
 	range->isa = gravity_class_range;
 	range->from = from_range;
@@ -1930,11 +1930,11 @@ void gravity_range_blacken (gravity_vm *vm, gravity_range_t *range) {
 // MARK: -
 
 inline gravity_value_t gravity_string_to_value (gravity_vm *vm, const char *s, uint32_t len) {
-	gravity_string_t *obj = mem_alloc(sizeof(gravity_string_t));
+	gravity_string_t *obj = mem_alloc(NULL, sizeof(gravity_string_t));
 	if (len == AUTOLENGTH) len = (uint32_t)strlen(s);
 	
 	uint32_t alloc = MAXNUM(len+1, DEFAULT_MINSTRING_SIZE);
-	char *ptr = mem_alloc(alloc);
+	char *ptr = mem_alloc(NULL, alloc);
 	memcpy(ptr, s, len);
 	
 	obj->isa = gravity_class_string;
@@ -1952,7 +1952,7 @@ inline gravity_value_t gravity_string_to_value (gravity_vm *vm, const char *s, u
 }
 
 inline gravity_string_t *gravity_string_new (gravity_vm *vm, char *s, uint32_t len, uint32_t alloc) {
-	gravity_string_t *obj = mem_alloc(sizeof(gravity_string_t));
+	gravity_string_t *obj = mem_alloc(NULL, sizeof(gravity_string_t));
 	if (len == AUTOLENGTH) len = (uint32_t)strlen(s);
 	
 	obj->isa = gravity_class_string;

+ 11 - 6
src/shared/gravity_value.h

@@ -66,8 +66,8 @@
 extern "C" {
 #endif
 
-#define GRAVITY_VERSION						"0.3.0"     // git tag 0.3.0
-#define GRAVITY_VERSION_NUMBER				0x000300    // git push --tags
+#define GRAVITY_VERSION						"0.3.5"     // git tag 0.3.5
+#define GRAVITY_VERSION_NUMBER				0x000305    // git push --tags
 #define GRAVITY_BUILD_DATE					__DATE__
 
 #ifndef GRAVITY_ENABLE_DOUBLE
@@ -89,10 +89,10 @@ extern "C" {
 #ifndef GRAVITY_MAP_DOTSUGAR
 #define GRAVITY_MAP_DOTSUGAR				1			// if 1 then map objects can be accessed with both map[key] and map.key
 #endif
-
+    
 #ifdef _MSC_VER
 #undef GRAVITY_COMPUTED_GOTO
-#define GRAVITY_COMPUTED_GOTO 0 // MSVC does not support it
+#define GRAVITY_COMPUTED_GOTO               0           // MSVC does not support it
 #endif
 
 #define MAIN_FUNCTION						"main"
@@ -128,7 +128,7 @@ extern "C" {
 #define MAX_ALLOCATION                      4194304     // 1024 * 1024 * 4 (about 4 millions entry)
 #define MAX_CCALLS                          100         // default maximum number of nested C calls
 #define MAX_MEMORY_BLOCK                    157286400   // 150MB
-
+    
 #define DEFAULT_CONTEXT_SIZE				256			// default VM context entries (can grow)
 #define DEFAULT_MINSTRING_SIZE				32			// minimum string allocation size
 #define DEFAULT_MINSTACK_SIZE				256			// sizeof(gravity_value_t) * 256	 = 16 * 256 => 4 KB
@@ -136,7 +136,7 @@ extern "C" {
 #define DEFAULT_CG_THRESHOLD				5*1024*1024 // 5MB
 #define DEFAULT_CG_MINTHRESHOLD				1024*1024	// 1MB
 #define DEFAULT_CG_RATIO					0.5			// 50%
-
+    
 #define MAXNUM(a,b)							((a) > (b) ? a : b)
 #define MINNUM(a,b)							((a) < (b) ? a : b)
 #define EPSILON								0.000001
@@ -214,7 +214,12 @@ typedef marray_t(gravity_value_t)		gravity_value_r;		// array of values
 #define GRAVITY_HASH_DEFINED
 typedef struct gravity_hash_t			gravity_hash_t;			// forward declaration
 #endif
+    
+#ifndef GRAVITY_VM_DEFINED
+#define GRAVITY_VM_DEFINED
 typedef struct gravity_vm				gravity_vm;				// vm is an opaque data type
+#endif
+    
 typedef bool (*gravity_c_internal)(gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex);
 
 typedef enum {

+ 1 - 1
src/utils/gravity_debug.c

@@ -68,7 +68,7 @@ const char *gravity_disassemble (const char *bcode, uint32_t blen, bool deserial
 	// allocate a buffer big enought to fit all disassembled bytecode
 	// I assume that each instruction (each row) will be 256 chars long
 	balloc = ninsts * rowlen;
-	buffer = mem_alloc(balloc);
+	buffer = mem_alloc(NULL, balloc);
 	if (!buffer) goto abort_disassemble;
 		
 	// conversion loop

+ 5 - 5
src/utils/gravity_json.c

@@ -82,10 +82,10 @@ struct json_t {
 };
 
 json_t *json_new (void) {
-	json_t *json = mem_alloc(sizeof(json_t));
+	json_t *json = mem_alloc(NULL, sizeof(json_t));
 	assert(json);
 	
-	json->buffer = mem_alloc(JSON_MINSIZE);
+	json->buffer = mem_alloc(NULL, JSON_MINSIZE);
 	assert(json->buffer);
 	
 	json->blen = JSON_MINSIZE;
@@ -103,7 +103,7 @@ static void json_write_raw (json_t *json, const char *buffer, size_t len, bool e
 	// check buffer reallocation
 	size_t reqlen = json->bused + len + prettylen + escapelen + JSON_MINSIZE;
 	if (reqlen >= json->blen) {
-		json->buffer = mem_realloc(json->buffer, json->blen + reqlen);
+		json->buffer = mem_realloc(NULL, json->buffer, json->blen + reqlen);
 		assert(json->buffer);
 		json->blen += reqlen;
 	}
@@ -135,7 +135,7 @@ static void json_write_escaped (json_t *json, const char *buffer, size_t len, bo
 		return;
 	}
 	
-	char	*new_buffer = mem_alloc (len*2);
+	char	*new_buffer = mem_alloc(NULL, len*2);
 	size_t	j = 0;
 	assert(new_buffer);
 	
@@ -368,7 +368,7 @@ typedef struct
 static void * default_alloc (size_t size, int zero, void * user_data)
 {
 	#pragma unused(zero, user_data)
-	return mem_alloc(size);
+	return mem_alloc(NULL, size);
 	//return zero ? calloc (1, size) : malloc (size);
 }
 

+ 7 - 6
src/utils/gravity_utils.c

@@ -141,7 +141,7 @@ const char *file_read(const char *path, size_t *len) {
 	fd = open(path, O_RDONLY);
 	if (fd < 0) goto abort_read;
 	
-	buffer = (char *)mem_alloc((size_t)fsize + 1);
+	buffer = (char *)mem_alloc(NULL, (size_t)fsize + 1);
 	if (buffer == NULL) goto abort_read;
 	buffer[fsize] = 0;
 	
@@ -190,7 +190,7 @@ const char *file_buildpath (const char *filename, const char *dirpath) {
 	size_t len2 = strlen(dirpath);
 	size_t len = len1+len2+2;
 	
-	char *full_path = (char *)mem_alloc(len);
+	char *full_path = (char *)mem_alloc(NULL, len);
 	if (!full_path) return NULL;
 	
 	if ((len2) && (dirpath[len2-1] != '/'))
@@ -245,7 +245,7 @@ DIRREF directory_init (const char *dirpath) {
 	WCHAR			dirpathW[MAX_PATH];
 	HANDLE			hFind;
 	(void)hFind;
-
+	
 	// convert dirpath to dirpathW
 	MultiByteToWideChar(CP_UTF8, 0, dirpath, -1, dirpathW, MAX_PATH);
 	
@@ -323,14 +323,15 @@ int string_cmp (const char *s1, const char *s2) {
 
 const char *string_dup (const char *s1) {
 	size_t	len = (size_t)strlen(s1);
-	char	*s = (char *)mem_alloc(len + 1);
-	
+	char	*s = (char *)mem_alloc(NULL, len + 1);
+	if (!s) return NULL;
 	memcpy(s, s1, len);
 	return s;
 }
 
 const char *string_ndup (const char *s1, size_t n) {
-	char *s = (char *)mem_alloc(n + 1);
+	char *s = (char *)mem_alloc(NULL, n + 1);
+    if (!s) return NULL;
 	memcpy(s, s1, n);
 	return s;
 }

+ 20 - 0
test/unittest/max_mem_block.gravity

@@ -0,0 +1,20 @@
+#unittest {
+    name: "Max memory block protection.";
+    error: RUNTIME;
+};
+
+func main () {
+    var s = "AAAAAAAAAAAAA";
+    
+    s = s+1000000
+    
+    var ret = ""
+    for (var c in s) {
+        if (c == "A") {
+            while(true) {
+                ret += ret+c;
+            }
+        }
+    }
+    return ret;
+}