/* Oort * Copyright 2007, Soren Sandmann Pedersen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "ast.h" static void mark_used (node_t *node, gpointer data) { if (node->common.type == NODE_LOAD) { node->load.definition->used = TRUE; } else if (node->common.type == NODE_STORE) { node->store.definition->used = TRUE; } else if (node->common.type == NODE_LOAD_IND) { node->load_ind.definition->used = TRUE; } else if (node->common.type == NODE_STORE_IND) { node->store_ind.definition->used = TRUE; } } static void list_def (gpointer key, gpointer value, gpointer data) { GPtrArray *array = data; g_ptr_array_add (array, value); } static int assign_offsets (symbol_table_t *symbols, int offset, int *max) { GPtrArray *definitions = g_ptr_array_new (); int i; g_hash_table_foreach (symbols->symbols, list_def, definitions); for (i = 0; i < definitions->len; ++i) { ast_definition_t *definition = definitions->pdata[i]; if (definition->common.type == AST_VARIABLE_DEFINITION) { ast_variable_definition_t *variable = &definition->variable; if (variable->used || variable->parameter) { int size = ast_type_spec_get_size (variable->type_spec); /* Align to size */ if (offset % size != 0) offset += (size - offset % size); variable->offset = offset; offset += size; } } } g_ptr_array_free (definitions, TRUE); if (offset > *max) *max = offset; return offset; } static void do_offsets (ast_t *ast, int offset, int *max) { GList *list; symbol_table_t *symbols = NULL; if (ast_is (ast, AST_STATEMENT, AST_BLOCK_STATEMENT)) { symbols = ast->statement.block.symbol_table; } else if (ast_is (ast, AST_EXPRESSION, AST_BLOCK_EXPRESSION)) { symbols = ast->expression.block.symbol_table; } else if (ast_is (ast, AST_DEFINITION, AST_CLASS_DEFINITION)) { ast_class_definition_t *class = &(ast->definition.class); symbols = class->symbol_table; /* FIXME: we should probably fix pointers at 32 bits - see TODO */ offset = sizeof (gpointer); /* The outer pointer */ if (0) /* FIXME: For now we don't support virtual methods */ offset += sizeof (gpointer); /* The vtable pointer */ class->env_size = offset; max = &(class->env_size); } else if (ast_is (ast, AST_DEFINITION, AST_FUNCTION_DEFINITION)) { ast_function_definition_t *function = &(ast->definition.function); symbols = ast->definition.function.symbol_table; /* FIXME: we should probably fix pointers at 32 bits - see TODO */ offset = 4 * sizeof (gpointer); /* The 'outer' pointer, * the old env, * the return address * the return stack */ function->env_size = offset; max = &(function->env_size); } else if (ast->common.type == AST_PROGRAM) { ast_program_t *program = &(ast->program); symbols = ast->program.symbol_table; offset = 0; program->env_size = offset; max = &(program->env_size); } if (symbols) offset = assign_offsets (symbols, offset, max); for (list = ast->common.children->head; list != NULL; list = list->next) do_offsets (list->data, offset, max); } gboolean offsets (ast_t *ast) { program_breadth_first (&ast->program, mark_used, NULL); do_offsets (ast, 0, NULL); /* The offsets pass can never fail */ return TRUE; }