File indexing completed on 2024-05-12 15:43:16
0001 /* 0002 * This file is part of the KDE libraries 0003 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) 0004 * Copyright (C) 2001 Peter Kelly (pmk@post.com) 0005 * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. 0006 * Copyright (C) 2007, 2008 Maksim Orlovich (maksim@kde.org) 0007 * 0008 * This library is free software; you can redistribute it and/or 0009 * modify it under the terms of the GNU Library General Public 0010 * License as published by the Free Software Foundation; either 0011 * version 2 of the License, or (at your option) any later version. 0012 * 0013 * This library is distributed in the hope that it will be useful, 0014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0016 * Library General Public License for more details. 0017 * 0018 * You should have received a copy of the GNU Library General Public License 0019 * along with this library; see the file COPYING.LIB. If not, write to 0020 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0021 * Boston, MA 02110-1301, USA. 0022 * 0023 */ 0024 #ifndef COMPILE_STATE_H 0025 #define COMPILE_STATE_H 0026 0027 #include "ExecState.h" // For codetype... Kinda odd. 0028 0029 #include "opcodes.h" 0030 #include "bytecode/opargs.h" 0031 0032 #include <wtf/Assertions.h> 0033 #include <wtf/HashSet.h> 0034 #include <wtf/HashMap.h> 0035 0036 using WTF::HashSet; 0037 using WTF::HashMap; 0038 using WTF::Vector; 0039 0040 namespace KJS 0041 { 0042 0043 class RegDescriptor; 0044 class FunctionBodyNode; 0045 0046 enum CompileType { 0047 NotCompiled, 0048 Release, 0049 Debug 0050 }; 0051 0052 class CompileState 0053 { 0054 public: 0055 CompileState(CodeType ctype, CompileType compType, FunctionBodyNode *fbody, Register initialMaxTemp): 0056 localScopeVal(nullptr), thisVal(nullptr), globalScopeVal(nullptr), evalResRegister(nullptr), 0057 ctype(ctype), compType(compType), locals(initialMaxTemp, nullptr), initialMaxTemp(initialMaxTemp), 0058 maxTemp(initialMaxTemp), fbody(fbody), scopeDepth(0), finallyDepth(0), neededClosures(false) 0059 { } 0060 0061 FunctionBodyNode *functionBody() 0062 { 0063 return fbody; 0064 } 0065 0066 CodeType codeType() const 0067 { 0068 return ctype; 0069 } 0070 0071 CodeBlock &codeBlock(); 0072 0073 CompileType compileType() const 0074 { 0075 return compType; 0076 } 0077 0078 ~CompileState(); 0079 0080 // Returns true if the register is a formal temporary. 0081 bool isTemporaryReg(Register regNum) 0082 { 0083 return regNum >= initialMaxTemp; 0084 } 0085 0086 // We distinguish two kinds of temporaries --- markable and not. They'll get 0087 // corresponding bits set in localStore when that's initialized. 0088 void requestTemporary(OpType type, OpValue *value, OpValue *reference); 0089 0090 // This method is used to acquire a read value of a local... 0091 OpValue localReadVal(Register regNum); 0092 0093 // And this one returns a reference, acquiring it for (immediate) write. 0094 // If there are any active read copies, we will backup the old value to 0095 // a temporary, and petchup their register descriptor to point to the backup. 0096 OpValue localWriteRef(CodeBlock &block, Register regNum); 0097 0098 // This forces all live locals to temporaries. 0099 void localFlushAll(CodeBlock &block); 0100 0101 // This sets the registers containing the local scope and 0102 // 'this' values... It should be the rvalue, not the regnums 0103 void setPreloadRegs(OpValue *localReg, OpValue *globalReg, OpValue *thisReg) 0104 { 0105 localScopeVal = localReg; 0106 globalScopeVal = globalReg; 0107 thisVal = thisReg; 0108 } 0109 0110 OpValue *localScope() 0111 { 0112 return localScopeVal; 0113 } 0114 0115 OpValue *thisValue() 0116 { 0117 return thisVal; 0118 } 0119 0120 OpValue *globalScope() 0121 { 0122 return globalScopeVal; 0123 } 0124 0125 void setEvalResultRegister(OpValue *val) 0126 { 0127 evalResRegister = val; 0128 } 0129 0130 OpValue *evalResultReg() 0131 { 0132 return evalResRegister; 0133 } 0134 0135 // To properly implement operations like continue and break, we need to keep track whether we 0136 // are nested inside with, try-catch and try-finally operations. 0137 // This serves two purposes: 0138 // 1) if we're not jumping out of a try-finally, we have to unwind the cleanup stacks 0139 // 2) if we're inside a try-finally, we have to jump to the finally and not 0140 // do the normal operation (this applies to return as well) 0141 // Also, if we're inside a 'with' or a catch we cannot optimize local variable access. 0142 0143 enum NestType { 0144 Scope, 0145 OtherCleanup, 0146 TryFinally, 0147 ContBreakTarget 0148 }; 0149 0150 void pushNest(NestType type, Node *node = nullptr); 0151 void popNest(); 0152 0153 struct NestInfo { 0154 NestType type; 0155 Node *node; 0156 }; 0157 0158 bool inNestedScope() 0159 { 0160 return scopeDepth > 0; 0161 } 0162 0163 bool inTryFinally() 0164 { 0165 return finallyDepth > 0; 0166 } 0167 0168 const WTF::Vector<NestInfo> &nestStack() 0169 { 0170 return nests; 0171 } 0172 0173 // Some constructs can be detected at compile time to involve 0174 // taking of closures. We keep track of that and avoid stack-allocation 0175 // if those are present. 0176 bool needsClosures() 0177 { 0178 return neededClosures; 0179 } 0180 0181 void setNeedsClosures() 0182 { 0183 neededClosures = true; 0184 } 0185 0186 // Label stuff.... 0187 0188 // Registers a pending label. Returns true if the label is OK, false if it's a duplicate. 0189 // If it fails, the label stack isn't touched! 0190 bool pushLabel(const Identifier &label); 0191 void popLabel(); 0192 0193 // Binds all the labels to the given node 0194 void bindLabels(Node *node); 0195 0196 // Returns destination for the label (node will be 0 if not found) 0197 Node *resolveContinueLabel(Identifier label); 0198 Node *resolveBreakLabel(Identifier label); 0199 0200 // Sets the targets for break/continues w/o label name 0201 void pushDefaultBreak(Node *node); 0202 void pushDefaultContinue(Node *node); 0203 void popDefaultBreak(); 0204 void popDefaultContinue(); 0205 0206 // Helpers for these and resolvePendingBreak 0207 void enterLoop(Node *node) 0208 { 0209 pushNest(ContBreakTarget, node); 0210 pushDefaultBreak(node); 0211 pushDefaultContinue(node); 0212 } 0213 0214 void exitLoop(Node *node) 0215 { 0216 popNest(); 0217 popDefaultBreak(); 0218 popDefaultContinue(); 0219 resolvePendingBreaks(node, CodeGen::nextPC(this)); 0220 } 0221 0222 // Adds break/continue as needing relevant target for given node 0223 void addPendingBreak(Node *node, Addr addr); 0224 void addPendingContinue(Node *node, Addr addr); 0225 0226 // Patches up all pending break/continue statements to given destination. 0227 // LabelNode takes care of the breaks itself, the loops need to deal 0228 // with continue, though. 0229 void resolvePendingBreaks(Node *node, Addr dest); 0230 void resolvePendingContinues(Node *node, Addr dest); 0231 private: 0232 OpValue *localScopeVal; 0233 OpValue *thisVal; 0234 OpValue *globalScopeVal; 0235 OpValue *evalResRegister; 0236 0237 CodeType ctype; 0238 CompileType compType; 0239 0240 // Makes sure that any values of a local are 0241 void flushLocal(CodeBlock &block, Register reg); 0242 0243 friend class RegDescriptor; 0244 WTF::Vector<RegDescriptor *> locals; 0245 WTF::Vector<RegDescriptor *> freeMarkTemps; 0246 WTF::Vector<RegDescriptor *> freeNonMarkTemps; 0247 Register initialMaxTemp; 0248 Register maxTemp; 0249 0250 FunctionBodyNode *fbody; 0251 0252 void reuse(RegDescriptor *desc, bool markable) 0253 { 0254 if (markable) { 0255 freeMarkTemps.append(desc); 0256 } else { 0257 freeNonMarkTemps.append(desc); 0258 } 0259 } 0260 0261 // Cached version of #of Scopes's from below. 0262 int scopeDepth; 0263 0264 // Cached version of #of Finally's from below... 0265 int finallyDepth; 0266 0267 WTF::Vector<NestInfo> nests; 0268 0269 // This is true if we see code constructs that require taking a closure 0270 // inside here, which means we should not stack-allocate activations. 0271 bool neededClosures; 0272 0273 // Label resolution.. 0274 WTF::HashSet<Identifier> seenLabels; // all labels we're inside 0275 WTF::Vector <Identifier> seenLabelsStack; 0276 WTF::Vector <Identifier> pendingLabels; // labels that haven't been bound to 0277 // a statement yet. 0278 0279 // Targets for continue/break w/o destination. 0280 WTF::Vector<Node *> defaultBreakTargets; 0281 WTF::Vector<Node *> defaultContinueTargets; 0282 0283 // Named label targets 0284 WTF::HashMap<Identifier, Node *> labelTargets; 0285 0286 WTF::HashMap<Node *, WTF::Vector<Addr>* > pendingBreaks; 0287 WTF::HashMap<Node *, WTF::Vector<Addr>* > pendingContinues; 0288 }; 0289 0290 // We used register descriptors for two reasons: 0291 // 1) For temporaries, we ref-counted them by OpValue in order to manage their lifetime 0292 // 2) For locals, we use them to do COW of values... 0293 class RegDescriptor 0294 { 0295 public: 0296 RegDescriptor(CompileState *owner, Register reg, bool markable, bool temp = true): 0297 owner(owner), regNo(reg), temp(temp), markable(markable), killed(false), refCount(0) 0298 {} 0299 0300 Register reg() const 0301 { 0302 return regNo; 0303 } 0304 0305 void ref() 0306 { 0307 ++refCount; 0308 } 0309 0310 void deref() 0311 { 0312 --refCount; 0313 if (refCount == 0) { 0314 if (killed) { 0315 delete this; 0316 } else if (temp) { 0317 owner->reuse(this, markable); 0318 } 0319 } 0320 } 0321 0322 bool live() 0323 { 0324 return refCount > 0; 0325 } 0326 0327 void adopt(RegDescriptor *other) 0328 { 0329 // Make this point to the same as an another descriptor, which is about to die.. 0330 temp = other->temp; 0331 markable = other->markable; 0332 regNo = other->regNo; 0333 0334 // Mark the other descriptor as killed, as we took ownership of this. 0335 other->killed = true; 0336 } 0337 private: 0338 CompileState *owner; 0339 Register regNo; 0340 bool temp; 0341 bool markable; 0342 bool killed; 0343 int refCount; 0344 }; 0345 0346 inline OpValue OpValue::immInt32(int32_t in) 0347 { 0348 OpValue res; 0349 initImm(&res, OpType_int32); 0350 res.value.narrow.int32Val = in; 0351 return res; 0352 } 0353 0354 inline OpValue OpValue::immNumber(double in) 0355 { 0356 OpValue res; 0357 initImm(&res, OpType_number); 0358 res.value.wide.numberVal = in; 0359 return res; 0360 } 0361 0362 inline OpValue OpValue::immValue(JSValue *in) 0363 { 0364 assert(in); 0365 OpValue res; 0366 initImm(&res, OpType_value); 0367 res.value.wide.valueVal = in; 0368 return res; 0369 } 0370 0371 inline OpValue OpValue::immBool(bool in) 0372 { 0373 OpValue res; 0374 initImm(&res, OpType_bool); 0375 res.value.narrow.boolVal = in; 0376 return res; 0377 } 0378 0379 inline OpValue OpValue::immString(UString *in) 0380 { 0381 OpValue res; 0382 initImm(&res, OpType_string); 0383 res.value.wide.stringVal = in; 0384 return res; 0385 } 0386 0387 inline OpValue OpValue::immIdent(Identifier *in) 0388 { 0389 OpValue res; 0390 initImm(&res, OpType_ident); 0391 res.value.wide.identVal = in; 0392 return res; 0393 } 0394 0395 inline OpValue OpValue::immNode(KJS::Node *in) 0396 { 0397 OpValue res; 0398 initImm(&res, OpType_node); 0399 res.value.wide.nodeVal = in; 0400 return res; 0401 } 0402 0403 inline OpValue OpValue::immCStr(const char *in) 0404 { 0405 OpValue res; 0406 initImm(&res, OpType_cstr); 0407 res.value.wide.cstrVal = in; 0408 return res; 0409 } 0410 0411 inline OpValue OpValue::immAddr(Addr in) 0412 { 0413 OpValue res; 0414 initImm(&res, OpType_addr); 0415 res.value.narrow.addrVal = in; 0416 return res; 0417 } 0418 0419 inline OpValue::OpValue(): type(OpType_void) {} // since should never occur as an argument.. 0420 0421 } 0422 0423 #endif