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