-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstack.c
193 lines (157 loc) · 5 KB
/
stack.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//
// NanoVM, a tiny java VM for the Atmel AVR family
// Copyright (C) 2005 by Till Harbaum <[email protected]>
//
// 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
//
//
// stack.c
//
#include "config.h"
#include <stdio.h>
#include "error.h"
#include "vm.h"
#include "heap.h"
#include "stack.h"
// the stack
static nvm_stack_t *stack; // the pysical base of the whole stack (incl. statics)
static nvm_stack_t *sp; // the current stack pointer
static nvm_stack_t *stackbase; // the base of the runtime stack (excl. statics)
nvm_stack_t *sp_saved = NULL;
// save current stack pointer
void stack_save_sp(void) {
if(sp_saved != NULL) {
DEBUGF("sp_saved already in use\n");
error(ERROR_VM_STACK_CORRUPTED);
}
sp_saved = sp; // save stack pointer
}
// check if current stack pointer equals saved one
void stack_verify_sp(void) {
if(sp != sp_saved) {
DEBUGF("%d bytes on stack\n", (uint8_t*)sp-(uint8_t*)sp_saved);
error(ERROR_VM_STACK_CORRUPTED);
}
sp_saved = NULL;
}
void stack_init(uint8_t static_fields) {
// the stack is generated by stealing from the heap. This
// is possible since the class file tells us how many stack
// elements the call to a method requires
stack = (nvm_stack_t*)heap_get_base();
sp = stack-1;
// steal one item for mains args and the space required for
// the static fields
heap_steal((1+static_fields)*sizeof(nvm_stack_t));
// increase stack pointer behind static fields
sp += static_fields;
}
// push an item onto the vms stack
void stack_push(nvm_stack_t val) {
*(++sp) = val;
}
// pop an item from the vms stack
nvm_stack_t stack_pop(void) {
return *(sp--);
}
// pop an item from the vm stack
nvm_int_t stack_pop_int(void) {
return nvm_stack2int(*(sp--));
}
// peek into the nvm stack
nvm_stack_t stack_peek(uint8_t index) {
return sp[-index];
}
// peek into the stack and expand 15->16 bits
nvm_int_t stack_peek_int(uint8_t index) {
return nvm_stack2int(sp[-index]);
}
// pop address from stack
void *stack_pop_addr(void) {
return vm_get_addr(*(sp--));
}
// peek into the nvm stack for address
void *stack_peek_addr(uint8_t index) {
return vm_get_addr(sp[-index]);
}
nvm_float_t stack_pop_float(void)
{
return nvm_stack2float(*(sp--));
}
nvm_float_t stack_peek_float(uint8_t index)
{
return nvm_stack2float(sp[-index]);
}
// the following two routines are used during method invocation and return
// they are used to make space for local variables on the stack
// and to determine the current stack address to be used for the local
// variables
void stack_add_sp(int8_t offset) {
sp += offset;
}
nvm_stack_t * stack_get_sp(void) {
return sp;
}
// static variables are allocated at vm startup on the stack. the following
// two routines provide access to these variables
nvm_stack_t stack_get_static(uint16_t index) {
return stack[index];
}
void stack_set_static(uint16_t index, nvm_stack_t value) {
stack[index] = value;
}
// our way to determine if the java application is being
// finished is to check if the return instruction would cause the
// stack to underflow. this happens, since the main method ends
// with a return statement like any other method. the following
// two methods are used to save the state of the empty stack (there
// may be already the static variables be on the stack) and to check
// whether the stack is filled with the static variables only (it is empty)
void stack_save_base(void) {
stackbase = stack_get_sp();
}
bool_t stack_is_empty(void) {
DEBUGF("stack base depth: %d\n", sp-stackbase);
return(sp == stackbase);
}
uint16_t stack_get_depth(void) {
return sp-stack;
}
#ifdef NVM_USE_HEAP_IDMAP
void stack_mark_heap_root_ids(void) {
uint16_t i;
DEBUGF("stack_mark_heap_root_ids()\n");
// since the locals are physically part of the stack we only need
// to search the stack
for(i=0;i<sp-stack+1;i++) {
// we are searching for heap objects only
if((stack[i] & NVM_TYPE_MASK) == NVM_TYPE_HEAP)
heap_mark_id(stack[i] & ~NVM_TYPE_MASK);
}
}
#else
bool_t stack_heap_id_in_use(heap_id_t id) {
// we are searching for heap objects only
uint16_t i;
nvm_ref_t id16 = id | NVM_TYPE_HEAP;
// since the locals are physically part of the stack we only need
// to search the stack
for(i=0;i<sp-stack+1;i++) {
// DEBUGF("Stack %d == "DBG16"\n", i, stack[i]);
if(stack[i] == id16) return TRUE;
}
return FALSE;
}
#endif