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
31namespace KJS {
32
33CompileState::~CompileState()
34{
35 deleteAllValues(locals);
36 deleteAllValues(freeMarkTemps);
37 deleteAllValues(freeNonMarkTemps);
38}
39
40CodeBlock& CompileState::codeBlock()
41{
42 return fbody->code();
43}
44
45void 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
80OpValue 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
96void 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
104void 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
124OpValue 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
136bool 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
147void 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
157void 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
164Node* 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
176Node* 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
188void 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
203void 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
213void CompileState::pushDefaultBreak(Node* node)
214{
215 defaultBreakTargets.append(node);
216}
217
218void CompileState::pushDefaultContinue(Node* node)
219{
220 defaultContinueTargets.append(node);
221}
222
223void CompileState::popDefaultBreak()
224{
225 defaultBreakTargets.removeLast();
226}
227
228void CompileState::popDefaultContinue()
229{
230 defaultContinueTargets.removeLast();
231}
232
233void 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
240void 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
247void 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
262void 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
278static OpValue* addrDummy;
279
280OpValue* 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