fix logic
[personal-kdelibs.git] / kjs / CompileState.h
blob84191c44c7d2ff1eecedd8353293d7e1c33277d5
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)
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.
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.
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.
25 #ifndef COMPILE_STATE_H
26 #define COMPILE_STATE_H
28 #include "ExecState.h" // For codetype... Kinda odd.
30 #include "opcodes.h"
31 #include "bytecode/opargs.h"
33 #include <wtf/Assertions.h>
34 #include <wtf/HashSet.h>
35 #include <wtf/HashMap.h>
37 using WTF::HashSet;
38 using WTF::HashMap;
39 using WTF::Vector;
42 namespace KJS {
44 class RegDescriptor;
45 class FunctionBodyNode;
48 enum CompileType
50 NotCompiled,
51 Release,
52 Debug
55 class CompileState
57 public:
58 CompileState(CodeType ctype, CompileType compType, FunctionBodyNode* fbody, Register initialMaxTemp):
59 localScopeVal(0), thisVal(0), globalScopeVal(0), evalResRegister(0),
60 ctype(ctype), compType(compType), locals(initialMaxTemp, 0), initialMaxTemp(initialMaxTemp),
61 maxTemp(initialMaxTemp), fbody(fbody), scopeDepth(0), finallyDepth(0), neededClosures(false)
62 { }
64 FunctionBodyNode* functionBody() {
65 return fbody;
68 CodeType codeType() const {
69 return ctype;
72 CodeBlock& codeBlock();
74 CompileType compileType() const {
75 return compType;
79 ~CompileState();
81 // Returns true if the register is a formal temporary.
82 bool isTemporaryReg(Register regNum) {
83 return regNum >= initialMaxTemp;
86 // We distinguish two kinds of temporaries --- markable and not. They'll get
87 // corresponding bits set in localStore when that's initialized.
88 void requestTemporary(OpType type, OpValue* value, OpValue* reference);
90 // This method is used to acquire a read value of a local...
91 OpValue localReadVal(Register regNum);
93 // And this one returns a reference, acquiring it for (immediate) write.
94 // If there are any active read copies, we will backup the old value to
95 // a temporary, and petchup their register descriptor to point to the backup.
96 OpValue localWriteRef(CodeBlock& block, Register regNum);
98 // This forces all live locals to temporaries.
99 void localFlushAll(CodeBlock& block);
101 // This sets the registers containing the local scope and
102 // 'this' values... It should be the rvalue, not the regnums
103 void setPreloadRegs(OpValue* localReg, OpValue* globalReg, OpValue* thisReg) {
104 localScopeVal = localReg;
105 globalScopeVal = globalReg;
106 thisVal = thisReg;
109 OpValue* localScope() {
110 return localScopeVal;
113 OpValue* thisValue() {
114 return thisVal;
117 OpValue* globalScope() {
118 return globalScopeVal;
121 void setEvalResultRegister(OpValue* val) {
122 evalResRegister = val;
125 OpValue* evalResultReg() {
126 return evalResRegister;
129 // To properly implement operations like continue and break, we need to keep track whether we
130 // are nested inside with, try-catch and try-finally operations.
131 // This serves two purposes:
132 // 1) if we're not jumping out of a try-finally, we have to unwind the cleanup stacks
133 // 2) if we're inside a try-finally, we have to jump to the finally and not
134 // do the normal operation (this applies to return as well)
135 // Also, if we're inside a 'with' or a catch we cannot optimize local variable access.
137 enum NestType {
138 Scope,
139 OtherCleanup,
140 TryFinally,
141 ContBreakTarget
144 void pushNest(NestType type, Node* node = 0);
145 void popNest ();
147 struct NestInfo {
148 NestType type;
149 Node* node;
152 bool inNestedScope() {
153 return scopeDepth > 0;
156 bool inTryFinally() {
157 return finallyDepth > 0;
160 const WTF::Vector<NestInfo>& nestStack() {
161 return nests;
164 // Some constructs can be detected at compile time to involve
165 // taking of closures. We keep track of that and avoid stack-allocation
166 // if those are present.
167 bool needsClosures() {
168 return neededClosures;
171 void setNeedsClosures() {
172 neededClosures = true;
175 // Label stuff....
177 // Registers a pending label. Returns true if the label is OK, false if it's a duplicate.
178 // If it fails, the label stack isn't touched!
179 bool pushLabel(const Identifier& label);
180 void popLabel();
182 // Binds all the labels to the given node
183 void bindLabels(Node* node);
185 // Returns destination for the label (node will be 0 if not found)
186 Node* resolveContinueLabel(Identifier label);
187 Node* resolveBreakLabel (Identifier label);
189 // Sets the targets for break/continues w/o label name
190 void pushDefaultBreak (Node* node);
191 void pushDefaultContinue(Node* node);
192 void popDefaultBreak ();
193 void popDefaultContinue();
195 // Helpers for these and resolvePendingBreak
196 void enterLoop(Node* node) {
197 pushNest(ContBreakTarget, node);
198 pushDefaultBreak(node);
199 pushDefaultContinue(node);
202 void exitLoop(Node* node) {
203 popNest();
204 popDefaultBreak();
205 popDefaultContinue();
206 resolvePendingBreaks(node, CodeGen::nextPC(this));
209 // Adds break/continue as needing relevant target for given node
210 void addPendingBreak (Node* node, Addr addr);
211 void addPendingContinue(Node* node, Addr addr);
213 // Patches up all pending break/continue statements to given destination.
214 // LabelNode takes care of the breaks itself, the loops need to deal
215 // with continue, though.
216 void resolvePendingBreaks (Node* node, Addr dest);
217 void resolvePendingContinues(Node* node, Addr dest);
218 private:
219 OpValue* localScopeVal;
220 OpValue* thisVal;
221 OpValue* globalScopeVal;
222 OpValue* evalResRegister;
224 CodeType ctype;
225 CompileType compType;
227 // Makes sure that any values of a local are
228 void flushLocal(CodeBlock& block, Register reg);
230 friend class RegDescriptor;
231 WTF::Vector<RegDescriptor*> locals;
232 WTF::Vector<RegDescriptor*> freeMarkTemps;
233 WTF::Vector<RegDescriptor*> freeNonMarkTemps;
234 Register initialMaxTemp;
235 Register maxTemp;
237 FunctionBodyNode* fbody;
239 void reuse(RegDescriptor* desc, bool markable) {
240 if (markable)
241 freeMarkTemps.append(desc);
242 else
243 freeNonMarkTemps.append(desc);
246 // Cached version of #of Scopes's from below.
247 int scopeDepth;
249 // Cached version of #of Finally's from below...
250 int finallyDepth;
252 WTF::Vector<NestInfo> nests;
254 // This is true if we see code constructs that require taking a closure
255 // inside here, which means we should not stack-allocate activations.
256 bool neededClosures;
258 // Label resolution..
259 WTF::HashSet<Identifier> seenLabels; // all labels we're inside
260 WTF::Vector <Identifier> seenLabelsStack;
261 WTF::Vector <Identifier> pendingLabels; // labels tha that haven't been bound to
262 // a statement yet.
264 // Targets for continue/break w/o destination.
265 WTF::Vector<Node*> defaultBreakTargets;
266 WTF::Vector<Node*> defaultContinueTargets;
268 // Named label targets
269 WTF::HashMap<Identifier, Node*> labelTargets;
271 WTF::HashMap<Node*, WTF::Vector<Addr>* > pendingBreaks;
272 WTF::HashMap<Node*, WTF::Vector<Addr>* > pendingContinues;
275 // We used register descriptors for two reasons:
276 // 1) For temporaries, we ref-counted them by OpValue in order to manage their lifetime
277 // 2) For locals, we use them to do COW of values...
278 class RegDescriptor
280 public:
281 RegDescriptor(CompileState* owner, Register reg, bool markable, bool temp = true):
282 owner(owner), regNo(reg), temp(temp), markable(markable), killed(false), refCount(0)
285 Register reg() const {
286 return regNo;
289 void ref() {
290 ++refCount;
293 void deref() {
294 --refCount;
295 if (refCount == 0) {
296 if (killed)
297 delete this;
298 else if (temp)
299 owner->reuse(this, markable);
303 bool live() {
304 return refCount > 0;
307 void adopt(RegDescriptor* other) {
308 // Make this point to the same as an another descriptor, which is about to die..
309 temp = other->temp;
310 markable = other->markable;
311 regNo = other->regNo;
313 // Mark the other descriptor as killed, as we took ownership of this.
314 other->killed = true;
316 private:
317 CompileState* owner;
318 Register regNo;
319 bool temp;
320 bool markable;
321 bool killed;
322 int refCount;
325 inline OpValue OpValue::immInt32(int32_t in) {
326 OpValue res;
327 initImm(&res, OpType_int32);
328 res.value.narrow.int32Val = in;
329 return res;
332 inline OpValue OpValue::immNumber(double in) {
333 OpValue res;
334 initImm(&res, OpType_number);
335 res.value.wide.numberVal = in;
336 return res;
339 inline OpValue OpValue::immValue(JSValue* in) {
340 OpValue res;
341 initImm(&res, OpType_value);
342 res.value.wide.valueVal = in;
343 return res;
346 inline OpValue OpValue::immBool(bool in) {
347 OpValue res;
348 initImm(&res, OpType_bool);
349 res.value.narrow.boolVal = in;
350 return res;
353 inline OpValue OpValue::immString(UString* in) {
354 OpValue res;
355 initImm(&res, OpType_string);
356 res.value.wide.stringVal = in;
357 return res;
360 inline OpValue OpValue::immIdent(Identifier* in) {
361 OpValue res;
362 initImm(&res, OpType_ident);
363 res.value.wide.identVal = in;
364 return res;
367 inline OpValue OpValue::immNode(KJS::Node* in) {
368 OpValue res;
369 initImm(&res, OpType_node);
370 res.value.wide.nodeVal = in;
371 return res;
374 inline OpValue OpValue::immCStr(const char* in) {
375 OpValue res;
376 initImm(&res, OpType_cstr);
377 res.value.wide.cstrVal = in;
378 return res;
381 inline OpValue OpValue::immAddr(Addr in) {
382 OpValue res;
383 initImm(&res, OpType_addr);
384 res.value.narrow.addrVal = in;
385 return res;
388 inline OpValue::OpValue(): type(OpType_void) {} // since should never occur as an argument..
392 #endif
393 // kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;