21 * questions. |
21 * questions. |
22 * |
22 * |
23 */ |
23 */ |
24 |
24 |
25 class ValueStack: public CompilationResourceObj { |
25 class ValueStack: public CompilationResourceObj { |
|
26 public: |
|
27 enum Kind { |
|
28 Parsing, // During abstract interpretation in GraphBuilder |
|
29 CallerState, // Caller state when inlining |
|
30 StateBefore, // Before before execution of instruction |
|
31 StateAfter, // After execution of instruction |
|
32 ExceptionState, // Exception handling of instruction |
|
33 EmptyExceptionState, // Exception handling of instructions not covered by an xhandler |
|
34 BlockBeginState // State of BlockBegin instruction with phi functions of this block |
|
35 }; |
|
36 |
26 private: |
37 private: |
27 IRScope* _scope; // the enclosing scope |
38 IRScope* _scope; // the enclosing scope |
28 bool _lock_stack; // indicates that this ValueStack is for an exception site |
39 ValueStack* _caller_state; |
|
40 int _bci; |
|
41 Kind _kind; |
|
42 |
29 Values _locals; // the locals |
43 Values _locals; // the locals |
30 Values _stack; // the expression stack |
44 Values _stack; // the expression stack |
31 Values _locks; // the monitor stack (holding the locked values) |
45 Values _locks; // the monitor stack (holding the locked values) |
32 |
46 |
33 Value check(ValueTag tag, Value t) { |
47 Value check(ValueTag tag, Value t) { |
34 assert(tag == t->type()->tag() || tag == objectTag && t->type()->tag() == addressTag, "types must correspond"); |
48 assert(tag == t->type()->tag() || tag == objectTag && t->type()->tag() == addressTag, "types must correspond"); |
35 return t; |
49 return t; |
36 } |
50 } |
37 |
51 |
38 Value check(ValueTag tag, Value t, Value h) { |
52 Value check(ValueTag tag, Value t, Value h) { |
39 assert(h->as_HiWord()->lo_word() == t, "incorrect stack pair"); |
53 assert(h == NULL, "hi-word of doubleword value must be NULL"); |
40 return check(tag, t); |
54 return check(tag, t); |
41 } |
55 } |
42 |
56 |
43 // helper routine |
57 // helper routine |
44 static void apply(Values list, ValueVisitor* f); |
58 static void apply(Values list, ValueVisitor* f); |
45 |
59 |
|
60 // for simplified copying |
|
61 ValueStack(ValueStack* copy_from, Kind kind, int bci); |
|
62 |
46 public: |
63 public: |
47 // creation |
64 // creation |
48 ValueStack(IRScope* scope, int locals_size, int max_stack_size); |
65 ValueStack(IRScope* scope, ValueStack* caller_state); |
49 |
66 |
50 // merging |
67 ValueStack* copy() { return new ValueStack(this, _kind, _bci); } |
51 ValueStack* copy(); // returns a copy of this w/ cleared locals |
68 ValueStack* copy(Kind new_kind, int new_bci) { return new ValueStack(this, new_kind, new_bci); } |
52 ValueStack* copy_locks(); // returns a copy of this w/ cleared locals and stack |
69 ValueStack* copy_for_parsing() { return new ValueStack(this, Parsing, -99); } |
53 // Note that when inlining of methods with exception |
70 |
54 // handlers is enabled, this stack may have a |
71 void set_caller_state(ValueStack* s) { assert(kind() == EmptyExceptionState, "only EmptyExceptionStates can be modified"); _caller_state = s; } |
55 // non-empty expression stack (size defined by |
72 |
56 // scope()->lock_stack_size()) |
|
57 bool is_same(ValueStack* s); // returns true if this & s's types match (w/o checking locals) |
73 bool is_same(ValueStack* s); // returns true if this & s's types match (w/o checking locals) |
58 bool is_same_across_scopes(ValueStack* s); // same as is_same but returns true even if stacks are in different scopes (used for block merging w/inlining) |
|
59 |
74 |
60 // accessors |
75 // accessors |
61 IRScope* scope() const { return _scope; } |
76 IRScope* scope() const { return _scope; } |
62 bool is_lock_stack() const { return _lock_stack; } |
77 ValueStack* caller_state() const { return _caller_state; } |
|
78 int bci() const { return _bci; } |
|
79 Kind kind() const { return _kind; } |
|
80 |
63 int locals_size() const { return _locals.length(); } |
81 int locals_size() const { return _locals.length(); } |
64 int stack_size() const { return _stack.length(); } |
82 int stack_size() const { return _stack.length(); } |
65 int locks_size() const { return _locks.length(); } |
83 int locks_size() const { return _locks.length(); } |
66 int max_stack_size() const { return _stack.capacity(); } |
|
67 bool stack_is_empty() const { return _stack.is_empty(); } |
84 bool stack_is_empty() const { return _stack.is_empty(); } |
68 bool no_active_locks() const { return _locks.is_empty(); } |
85 bool no_active_locks() const { return _locks.is_empty(); } |
69 ValueStack* caller_state() const; |
86 int total_locks_size() const; |
70 |
87 |
71 // locals access |
88 // locals access |
72 void clear_locals(); // sets all locals to NULL; |
89 void clear_locals(); // sets all locals to NULL; |
73 |
90 |
74 // Kill local i. Also kill local i+1 if i was a long or double. |
|
75 void invalidate_local(int i) { |
91 void invalidate_local(int i) { |
|
92 assert(_locals.at(i)->type()->is_single_word() || |
|
93 _locals.at(i + 1) == NULL, "hi-word of doubleword value must be NULL"); |
|
94 _locals.at_put(i, NULL); |
|
95 } |
|
96 |
|
97 Value local_at(int i) const { |
76 Value x = _locals.at(i); |
98 Value x = _locals.at(i); |
77 if (x != NULL && x->type()->is_double_word()) { |
99 assert(x == NULL || x->type()->is_single_word() || |
78 assert(_locals.at(i + 1)->as_HiWord()->lo_word() == x, "locals inconsistent"); |
100 _locals.at(i + 1) == NULL, "hi-word of doubleword value must be NULL"); |
79 _locals.at_put(i + 1, NULL); |
|
80 } |
|
81 _locals.at_put(i, NULL); |
|
82 } |
|
83 |
|
84 |
|
85 Value load_local(int i) const { |
|
86 Value x = _locals.at(i); |
|
87 if (x != NULL && x->type()->is_illegal()) return NULL; |
|
88 assert(x == NULL || x->as_HiWord() == NULL, "index points to hi word"); |
|
89 assert(x == NULL || x->type()->is_illegal() || x->type()->is_single_word() || x == _locals.at(i+1)->as_HiWord()->lo_word(), "locals inconsistent"); |
|
90 return x; |
101 return x; |
91 } |
102 } |
92 |
103 |
93 Value local_at(int i) const { return _locals.at(i); } |
|
94 |
|
95 // Store x into local i. |
|
96 void store_local(int i, Value x) { |
104 void store_local(int i, Value x) { |
97 // Kill the old value |
105 // When overwriting local i, check if i - 1 was the start of a |
98 invalidate_local(i); |
106 // double word local and kill it. |
99 _locals.at_put(i, x); |
|
100 |
|
101 // Writing a double word can kill other locals |
|
102 if (x != NULL && x->type()->is_double_word()) { |
|
103 // If x + i was the start of a double word local then kill i + 2. |
|
104 Value x2 = _locals.at(i + 1); |
|
105 if (x2 != NULL && x2->type()->is_double_word()) { |
|
106 _locals.at_put(i + 2, NULL); |
|
107 } |
|
108 |
|
109 // If x is a double word local, also update i + 1. |
|
110 #ifdef ASSERT |
|
111 _locals.at_put(i + 1, x->hi_word()); |
|
112 #else |
|
113 _locals.at_put(i + 1, NULL); |
|
114 #endif |
|
115 } |
|
116 // If x - 1 was the start of a double word local then kill i - 1. |
|
117 if (i > 0) { |
107 if (i > 0) { |
118 Value prev = _locals.at(i - 1); |
108 Value prev = _locals.at(i - 1); |
119 if (prev != NULL && prev->type()->is_double_word()) { |
109 if (prev != NULL && prev->type()->is_double_word()) { |
120 _locals.at_put(i - 1, NULL); |
110 _locals.at_put(i - 1, NULL); |
121 } |
111 } |
122 } |
112 } |
123 } |
113 |
124 |
114 _locals.at_put(i, x); |
125 void replace_locals(ValueStack* with); |
115 if (x->type()->is_double_word()) { |
|
116 // hi-word of doubleword value is always NULL |
|
117 _locals.at_put(i + 1, NULL); |
|
118 } |
|
119 } |
126 |
120 |
127 // stack access |
121 // stack access |
128 Value stack_at(int i) const { |
122 Value stack_at(int i) const { |
129 Value x = _stack.at(i); |
123 Value x = _stack.at(i); |
130 assert(x->as_HiWord() == NULL, "index points to hi word"); |
|
131 assert(x->type()->is_single_word() || |
124 assert(x->type()->is_single_word() || |
132 x->subst() == _stack.at(i+1)->as_HiWord()->lo_word(), "stack inconsistent"); |
125 _stack.at(i + 1) == NULL, "hi-word of doubleword value must be NULL"); |
133 return x; |
126 return x; |
134 } |
127 } |
135 |
128 |
136 Value stack_at_inc(int& i) const { |
129 Value stack_at_inc(int& i) const { |
137 Value x = stack_at(i); |
130 Value x = stack_at(i); |
144 |
137 |
145 // iteration |
138 // iteration |
146 void values_do(ValueVisitor* f); |
139 void values_do(ValueVisitor* f); |
147 |
140 |
148 // untyped manipulation (for dup_x1, etc.) |
141 // untyped manipulation (for dup_x1, etc.) |
149 void clear_stack() { _stack.clear(); } |
|
150 void truncate_stack(int size) { _stack.trunc_to(size); } |
142 void truncate_stack(int size) { _stack.trunc_to(size); } |
151 void raw_push(Value t) { _stack.push(t); } |
143 void raw_push(Value t) { _stack.push(t); } |
152 Value raw_pop() { return _stack.pop(); } |
144 Value raw_pop() { return _stack.pop(); } |
153 |
145 |
154 // typed manipulation |
146 // typed manipulation |
155 void ipush(Value t) { _stack.push(check(intTag , t)); } |
147 void ipush(Value t) { _stack.push(check(intTag , t)); } |
156 void fpush(Value t) { _stack.push(check(floatTag , t)); } |
148 void fpush(Value t) { _stack.push(check(floatTag , t)); } |
157 void apush(Value t) { _stack.push(check(objectTag , t)); } |
149 void apush(Value t) { _stack.push(check(objectTag , t)); } |
158 void rpush(Value t) { _stack.push(check(addressTag, t)); } |
150 void rpush(Value t) { _stack.push(check(addressTag, t)); } |
159 #ifdef ASSERT |
|
160 // in debug mode, use HiWord for 2-word values |
|
161 void lpush(Value t) { _stack.push(check(longTag , t)); _stack.push(new HiWord(t)); } |
|
162 void dpush(Value t) { _stack.push(check(doubleTag , t)); _stack.push(new HiWord(t)); } |
|
163 #else |
|
164 // in optimized mode, use NULL for 2-word values |
|
165 void lpush(Value t) { _stack.push(check(longTag , t)); _stack.push(NULL); } |
151 void lpush(Value t) { _stack.push(check(longTag , t)); _stack.push(NULL); } |
166 void dpush(Value t) { _stack.push(check(doubleTag , t)); _stack.push(NULL); } |
152 void dpush(Value t) { _stack.push(check(doubleTag , t)); _stack.push(NULL); } |
167 #endif // ASSERT |
|
168 |
153 |
169 void push(ValueType* type, Value t) { |
154 void push(ValueType* type, Value t) { |
170 switch (type->tag()) { |
155 switch (type->tag()) { |
171 case intTag : ipush(t); return; |
156 case intTag : ipush(t); return; |
172 case longTag : lpush(t); return; |
157 case longTag : lpush(t); return; |
180 |
165 |
181 Value ipop() { return check(intTag , _stack.pop()); } |
166 Value ipop() { return check(intTag , _stack.pop()); } |
182 Value fpop() { return check(floatTag , _stack.pop()); } |
167 Value fpop() { return check(floatTag , _stack.pop()); } |
183 Value apop() { return check(objectTag , _stack.pop()); } |
168 Value apop() { return check(objectTag , _stack.pop()); } |
184 Value rpop() { return check(addressTag, _stack.pop()); } |
169 Value rpop() { return check(addressTag, _stack.pop()); } |
185 #ifdef ASSERT |
|
186 // in debug mode, check for HiWord consistency |
|
187 Value lpop() { Value h = _stack.pop(); return check(longTag , _stack.pop(), h); } |
170 Value lpop() { Value h = _stack.pop(); return check(longTag , _stack.pop(), h); } |
188 Value dpop() { Value h = _stack.pop(); return check(doubleTag, _stack.pop(), h); } |
171 Value dpop() { Value h = _stack.pop(); return check(doubleTag, _stack.pop(), h); } |
189 #else |
|
190 // in optimized mode, ignore HiWord since it is NULL |
|
191 Value lpop() { _stack.pop(); return check(longTag , _stack.pop()); } |
|
192 Value dpop() { _stack.pop(); return check(doubleTag, _stack.pop()); } |
|
193 #endif // ASSERT |
|
194 |
172 |
195 Value pop(ValueType* type) { |
173 Value pop(ValueType* type) { |
196 switch (type->tag()) { |
174 switch (type->tag()) { |
197 case intTag : return ipop(); |
175 case intTag : return ipop(); |
198 case longTag : return lpop(); |
176 case longTag : return lpop(); |