1 | // -*- c-basic-offset: 2 -*- |
2 | /* |
3 | * This file is part of the KDE libraries |
4 | * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) |
5 | * Copyright (C) 2001 Peter Kelly (pmk@post.com) |
6 | * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. |
7 | * Copyright (C) 2007, 2008 Maksim Orlovich (maksim@kde.org) |
8 | * |
9 | * This library is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU Library General Public |
11 | * License as published by the Free Software Foundation; either |
12 | * version 2 of the License, or (at your option) any later version. |
13 | * |
14 | * This library is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | * Library General Public License for more details. |
18 | * |
19 | * You should have received a copy of the GNU Library General Public License |
20 | * along with this library; see the file COPYING.LIB. If not, write to |
21 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
22 | * Boston, MA 02110-1301, USA. |
23 | * |
24 | */ |
25 | #include "CompileState.h" |
26 | #include "nodes.h" |
27 | |
28 | #include <wtf/Assertions.h> |
29 | #include <wtf/Vector.h> |
30 | |
31 | namespace KJS { |
32 | |
33 | CompileState::~CompileState() |
34 | { |
35 | deleteAllValues(locals); |
36 | deleteAllValues(freeMarkTemps); |
37 | deleteAllValues(freeNonMarkTemps); |
38 | } |
39 | |
40 | CodeBlock& CompileState::codeBlock() |
41 | { |
42 | return fbody->code(); |
43 | } |
44 | |
45 | void CompileState::requestTemporary(OpType type, OpValue* value, OpValue* reference) |
46 | { |
47 | ASSERT(type == OpType_value || type == OpType_bool || type == OpType_int32 || type == OpType_number); |
48 | |
49 | value->type = type; |
50 | value->immediate = false; |
51 | |
52 | reference->type = OpType_reg; |
53 | reference->immediate = true; |
54 | |
55 | RegDescriptor* temp = 0; |
56 | |
57 | bool markable = (type == OpType_value); |
58 | |
59 | if (markable && !freeMarkTemps.isEmpty()) { |
60 | temp = freeMarkTemps.last(); |
61 | freeMarkTemps.removeLast(); |
62 | } else if (!markable && !freeNonMarkTemps.isEmpty()) { |
63 | temp = freeNonMarkTemps.last(); |
64 | freeNonMarkTemps.removeLast(); |
65 | } |
66 | |
67 | if (!temp) { |
68 | Register id = maxTemp; |
69 | fbody->reserveSlot(id, markable); |
70 | temp = new RegDescriptor(this, id, markable); |
71 | ++maxTemp; |
72 | } |
73 | |
74 | value->ownedReg = temp; |
75 | |
76 | reference->ownedReg = temp; |
77 | reference->value.narrow.regVal = temp->reg(); |
78 | } |
79 | |
80 | OpValue CompileState::localReadVal(Register regNum) |
81 | { |
82 | OpValue val; |
83 | val.immediate = false; |
84 | val.type = OpType_value; |
85 | |
86 | RegDescriptor* desc = locals[regNum]; |
87 | if (!desc) { |
88 | desc = new RegDescriptor(this, regNum, true, false /*not a temp!*/); |
89 | locals[regNum] = desc; |
90 | } |
91 | |
92 | val.ownedReg = desc; |
93 | return val; |
94 | } |
95 | |
96 | void CompileState::localFlushAll(CodeBlock& block) |
97 | { |
98 | for (Register r = 0; r < initialMaxTemp; ++r) { |
99 | if (locals[r] && locals[r]->live()) |
100 | flushLocal(block, r); |
101 | } |
102 | } |
103 | |
104 | void CompileState::flushLocal(CodeBlock& /*block*/, Register regNum) |
105 | { |
106 | if (locals[regNum] && locals[regNum]->live()) { |
107 | OpValue localVal; |
108 | localVal.immediate = false; |
109 | localVal.type = OpType_value; |
110 | localVal.ownedReg = locals[regNum]; |
111 | |
112 | OpValue out, outReg; |
113 | requestTemporary(OpType_value, &out, &outReg); |
114 | |
115 | CodeGen::emitOp(this, Op_RegPutValue, 0, &outReg, &localVal); |
116 | |
117 | // Now, patch up the descriptor to point to the same place as the temporary, and to |
118 | // take ownership of it, and remove it from local descriptors list. |
119 | locals[regNum]->adopt(out.ownedReg.get()); |
120 | locals[regNum] = 0; |
121 | } |
122 | } |
123 | |
124 | OpValue CompileState::localWriteRef(CodeBlock& block, Register regNum) |
125 | { |
126 | // Detach any live value copies. |
127 | flushLocal(block, regNum); |
128 | |
129 | OpValue rval; |
130 | rval.immediate = true; |
131 | rval.type = OpType_reg; |
132 | rval.value.narrow.regVal = regNum; |
133 | return rval; |
134 | } |
135 | |
136 | bool CompileState::pushLabel(const Identifier& label) |
137 | { |
138 | if (!seenLabels.add(label).second) |
139 | return false; // Dupe! |
140 | |
141 | seenLabelsStack.append(label); |
142 | pendingLabels.append(label); |
143 | |
144 | return true; |
145 | } |
146 | |
147 | void CompileState::popLabel() |
148 | { |
149 | Identifier name = seenLabelsStack.last(); |
150 | |
151 | seenLabelsStack.removeLast(); |
152 | seenLabels.remove (name); |
153 | labelTargets.remove(name); |
154 | ASSERT(pendingLabels.isEmpty()); |
155 | } |
156 | |
157 | void CompileState::bindLabels(Node* node) |
158 | { |
159 | for (size_t l = 0; l < pendingLabels.size(); ++l) |
160 | labelTargets.set(pendingLabels[l], node); |
161 | pendingLabels.clear(); |
162 | } |
163 | |
164 | Node* CompileState::resolveBreakLabel(Identifier label) |
165 | { |
166 | if (label.isEmpty()) { |
167 | if (defaultBreakTargets.isEmpty()) |
168 | return 0; |
169 | else |
170 | return defaultBreakTargets.last(); |
171 | } else { |
172 | return labelTargets.get(label); |
173 | } |
174 | } |
175 | |
176 | Node* CompileState::resolveContinueLabel(Identifier label) |
177 | { |
178 | if (label.isEmpty()) { |
179 | if (defaultContinueTargets.isEmpty()) |
180 | return 0; |
181 | else |
182 | return defaultContinueTargets.last(); |
183 | } else { |
184 | return labelTargets.get(label); |
185 | } |
186 | } |
187 | |
188 | void CompileState::pushNest(NestType type, Node* node) |
189 | { |
190 | if (type == Scope) |
191 | ++scopeDepth; |
192 | else if (type == TryFinally) |
193 | ++finallyDepth; |
194 | |
195 | NestInfo inf; |
196 | inf.type = type; |
197 | inf.node = node; |
198 | nests.append(inf); |
199 | |
200 | assert(!(type == ContBreakTarget && !node)); |
201 | } |
202 | |
203 | void CompileState::popNest() |
204 | { |
205 | if (nests.last().type == Scope) |
206 | --scopeDepth; |
207 | else if (nests.last().type == TryFinally) |
208 | --finallyDepth; |
209 | |
210 | nests.removeLast(); |
211 | } |
212 | |
213 | void CompileState::pushDefaultBreak(Node* node) |
214 | { |
215 | defaultBreakTargets.append(node); |
216 | } |
217 | |
218 | void CompileState::pushDefaultContinue(Node* node) |
219 | { |
220 | defaultContinueTargets.append(node); |
221 | } |
222 | |
223 | void CompileState::popDefaultBreak() |
224 | { |
225 | defaultBreakTargets.removeLast(); |
226 | } |
227 | |
228 | void CompileState::popDefaultContinue() |
229 | { |
230 | defaultContinueTargets.removeLast(); |
231 | } |
232 | |
233 | void CompileState::addPendingBreak(Node* node, Addr addr) |
234 | { |
235 | if (!pendingBreaks.contains(node)) |
236 | pendingBreaks.set(node, new WTF::Vector<Addr>()); |
237 | pendingBreaks.get(node)->append(addr); |
238 | } |
239 | |
240 | void CompileState::addPendingContinue(Node* node, Addr addr) |
241 | { |
242 | if (!pendingContinues.contains(node)) |
243 | pendingContinues.set(node, new WTF::Vector<Addr>()); |
244 | pendingContinues.get(node)->append(addr); |
245 | } |
246 | |
247 | void CompileState::resolvePendingBreaks(Node* node, Addr dest) |
248 | { |
249 | const WTF::Vector<Addr>* stats = pendingBreaks.get(node); |
250 | if (!stats) |
251 | return; |
252 | |
253 | CodeBlock& block = codeBlock(); |
254 | OpValue newDest = OpValue::immAddr(dest); |
255 | for (size_t c = 0; c < stats->size(); ++c) |
256 | CodeGen::patchOpArgument(block, (*stats)[c], 0, newDest); |
257 | |
258 | pendingBreaks.remove(node); |
259 | delete stats; |
260 | } |
261 | |
262 | void CompileState::resolvePendingContinues(Node* node, Addr dest) |
263 | { |
264 | const WTF::Vector<Addr>* stats = pendingContinues.get(node); |
265 | if (!stats) |
266 | return; |
267 | |
268 | CodeBlock& block = codeBlock(); |
269 | OpValue newDest = OpValue::immAddr(dest); |
270 | for (size_t c = 0; c < stats->size(); ++c) |
271 | CodeGen::patchOpArgument(block, (*stats)[c], 0, newDest); |
272 | |
273 | pendingContinues.remove(node); |
274 | delete stats; |
275 | } |
276 | |
277 | |
278 | static OpValue* addrDummy; |
279 | |
280 | OpValue* OpValue::dummyAddr() |
281 | { |
282 | if (!addrDummy) { |
283 | addrDummy = new OpValue; |
284 | *addrDummy = OpValue::immAddr(0); |
285 | } |
286 | return addrDummy; |
287 | } |
288 | |
289 | |
290 | } //namespace KJS |
291 | |
292 | // kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on; |
293 | |