File indexing completed on 2024-05-12 15:43:19

0001 /*
0002  *  This file is part of the KDE libraries
0003  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
0004  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
0005  *  Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved.
0006  *  Copyright (C) 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 
0025 #include "ExecState.h"
0026 #include "function.h"
0027 #include "scriptfunction.h"
0028 #include "internal.h"
0029 #include "nodes.h"
0030 #include "debugger.h"
0031 
0032 namespace KJS
0033 {
0034 
0035 Interpreter *ExecState::lexicalInterpreter() const
0036 {
0037     JSObject *outerScope = scopeChain().bottom();
0038     assert(outerScope->isGlobalObject());
0039 
0040     Interpreter *result = static_cast<JSGlobalObject *>(outerScope)->interpreter();
0041 
0042     if (!result) {
0043         return dynamicInterpreter();
0044     }
0045 
0046     return result;
0047 }
0048 
0049 void ExecState::markSelf()
0050 {
0051     if (m_codeType != FunctionCode && m_localStore) {
0052         //### some code dupe here with JSVariableObject::mark. Not sure how to best
0053         // restructure.
0054 
0055         // Note: the m_localStore check is needed here, since for non-function code,
0056         // we may create function object in declaration elaboration stage, before
0057         // compilation and set up of this
0058         size_t size                = m_localStoreSize;
0059         LocalStorageEntry *entries = m_localStore;
0060 
0061         for (size_t i = 0; i < size; ++i) {
0062             JSValue *value = entries[i].val.valueVal;
0063             if (!(entries[i].attributes & DontMark) && !JSValue::marked(value)) {
0064                 JSValue::mark(value);
0065             }
0066         }
0067     }
0068 
0069     for (size_t i = 0; i < m_deferredCompletions.size(); ++i) {
0070         JSValue *e = m_deferredCompletions[i].value();
0071         if (e && !JSValue::marked(e)) {
0072             JSValue::mark(e);
0073         }
0074     }
0075 
0076     JSValue *e = m_completion.value();
0077     if (e && !JSValue::marked(e)) {
0078         JSValue::mark(e);
0079     }
0080 
0081     scope.mark();
0082 
0083     // Propagate up to other eval chains..
0084     if (m_savedExec && m_savedExec != m_callingExec) {
0085         ASSERT(m_savedExec != this);
0086         m_savedExec->mark();
0087     }
0088 }
0089 
0090 void ExecState::mark()
0091 {
0092     for (ExecState *exec = this; exec; exec = exec->m_callingExec) {
0093         exec->markSelf();
0094     }
0095 }
0096 
0097 ExecState::ExecState(Interpreter *intp, ExecState *save) :
0098     m_interpreter(intp),
0099     m_propertyNames(CommonIdentifiers::shared()),
0100     m_callingExec(nullptr),
0101     m_savedExec(save),
0102     m_currentBody(nullptr),
0103     m_function(nullptr),
0104     m_localStore(nullptr),
0105     m_pcBase(nullptr),
0106     m_pc(nullptr),
0107     m_machineLocalStore(nullptr)
0108 {
0109     /**
0110      The reason we need m_savedExec and can't just be content with m_callingExec is two-fold.
0111      First of all, in many cases KHTML (and ktranscript) invoke functions such as event handlers
0112      on globalExec. When that happens, we still need to be able to mark the previous call-chain.
0113      Also, it is possible for the client to call Interpreter::evaluate again; and we still
0114      need to mark things from the outside when that happens
0115     */
0116 
0117     if (m_callingExec && m_savedExec && m_callingExec != m_savedExec) {
0118         assert(m_callingExec == intp->globalExec());
0119     }
0120     m_interpreter->setExecState(this);
0121 }
0122 
0123 ExecState::~ExecState()
0124 {
0125     m_interpreter->setExecState(m_savedExec);
0126 }
0127 
0128 void ExecState::pushExceptionHandler(HandlerType type, Addr addr)
0129 {
0130     m_exceptionHandlers.append(ExceptionHandler(type, addr));
0131 }
0132 
0133 void ExecState::popExceptionHandler()
0134 {
0135     m_exceptionHandlers.removeLast();
0136 }
0137 
0138 JSValue *ExecState::reactivateCompletion(bool insideTryFinally)
0139 {
0140     // First, unwind and get the old completion..
0141     ASSERT(m_exceptionHandlers.last().type == RemoveDeferred);
0142     popExceptionHandler();
0143     Completion comp = m_deferredCompletions.last();
0144     m_deferredCompletions.removeLast();
0145 
0146     // Now, our behavior behaves on whether we're inside an another
0147     // try..finally or not. If we're, we must route even
0148     // continue/break/return completions via the EH machinery;
0149     // if not, we execute them directly
0150     if (comp.complType() == Normal) {
0151         // We just straight fell into 'finally'. Nothing fancy to do.
0152         return nullptr;
0153     }
0154 
0155     if (comp.complType() == Throw || insideTryFinally) {
0156         setAbruptCompletion(comp);
0157     } else {
0158         if (comp.complType() == ReturnValue) {
0159             return comp.value();
0160         } else {
0161             assert(comp.complType() == Break || comp.complType() == Continue);
0162             *m_pc = m_pcBase + comp.target();
0163         }
0164     }
0165 
0166     return nullptr;
0167 }
0168 
0169 void ExecState::setException(JSValue *e)
0170 {
0171     if (e) {
0172         setAbruptCompletion(Completion(Throw, e));
0173     } else {
0174         clearException();
0175     }
0176 }
0177 
0178 void ExecState::setAbruptCompletion(Completion comp)
0179 {
0180     // If we already had an exception, merely update the object, to permit
0181     // users to refine the exception, being careful not to double-unwind.
0182     // However, warn about it in debug builds.
0183     if (hadException()) {
0184 #ifndef NDEBUG
0185         printInfo(this, "warning: overriding already set exception ", m_completion.value());
0186         printInfo(this, "with ", comp.value());
0187 #endif
0188 
0189         m_completion = comp;
0190         return;
0191     }
0192 
0193     // Trace to debugger if needed.
0194     Debugger *dbg = dynamicInterpreter()->debugger();
0195     if (dbg && comp.complType() == Throw) {
0196         dbg->reportException(this, comp.value());
0197     }
0198 
0199     m_completion = comp;
0200 
0201     while (!m_exceptionHandlers.isEmpty()) {
0202         switch (m_exceptionHandlers.last().type) {
0203         case JumpToCatch:
0204             *m_pc = m_pcBase + m_exceptionHandlers.last().dest;
0205             m_exceptionHandlers.removeLast();
0206             return; // done handling it
0207         case PopScope:
0208             popScope();
0209             m_exceptionHandlers.removeLast();
0210             continue; // get the next handler
0211         case RemoveDeferred:
0212             m_deferredCompletions.removeLast();
0213             m_exceptionHandlers.removeLast();
0214             continue; // get the next handler
0215         case Silent:
0216             // Exception blocked by tracing code. nothing to do.
0217             return;
0218         }
0219     }
0220 }
0221 
0222 void ExecState::quietUnwind(int depth)
0223 {
0224     ASSERT(m_exceptionHandlers.size() >= size_t(depth));
0225     for (int e = 0; e < depth; ++e) {
0226         HandlerType type = m_exceptionHandlers.last().type;
0227         m_exceptionHandlers.removeLast();
0228 
0229         switch (type) {
0230         case JumpToCatch:
0231             break; //Nothing to do here!
0232         case PopScope:
0233             popScope();
0234             break;
0235         case RemoveDeferred:
0236             m_deferredCompletions.removeLast();
0237             break;
0238         case Silent:
0239             ASSERT(0); // Should not happen in the middle of the code.
0240             break;
0241         }
0242     }
0243 }
0244 
0245 GlobalExecState::GlobalExecState(Interpreter *intp, JSGlobalObject *glob): ExecState(intp, nullptr /* nothing else constructed yet*/)
0246 {
0247     scope.push(glob);
0248     m_codeType  = GlobalCode;
0249     m_variable = glob;
0250     m_thisVal  = glob;
0251 }
0252 
0253 InterpreterExecState::InterpreterExecState(Interpreter *intp, JSGlobalObject *glob,
0254         JSObject *thisObject, ProgramNode *body):
0255     ExecState(intp, intp->execState())
0256 {
0257     m_currentBody = body;
0258     scope.push(glob);
0259     m_codeType = GlobalCode;
0260     m_variable = glob;
0261     // Per 10.2.1, we should use the global object here, but
0262     // Interpreter::evaluate permits it to be overridden, e.g. for LiveConnect.
0263     m_thisVal  = thisObject;
0264 }
0265 
0266 EvalExecState::EvalExecState(Interpreter *intp, JSGlobalObject *glob,
0267                              ProgramNode *body, ExecState *callingExecState):
0268     ExecState(intp, intp->execState())
0269 {
0270     m_currentBody = body;
0271     m_codeType    = EvalCode;
0272     m_callingExec = callingExecState;
0273     if (m_callingExec) {
0274         scope = m_callingExec->scopeChain();
0275         m_variable = m_callingExec->variableObject();
0276         m_thisVal  = m_callingExec->thisValue();
0277         return;
0278     }
0279 
0280     // 10.2.2 talks about the behavior w/o a calling context here,
0281     // saying it should be like global code. This can not happen
0282     // in actual JS code, but it may be synthesized by e.g.
0283     // the JS debugger calling 'eval' itself, from globalExec
0284     m_thisVal  = glob;
0285     m_variable = glob;
0286     scope.push(glob);
0287 }
0288 
0289 FunctionExecState::FunctionExecState(Interpreter *intp, JSObject *thisObject,
0290                                      FunctionBodyNode *body, ExecState *callingExecState,
0291                                      FunctionImp *function): ExecState(intp, intp->execState())
0292 {
0293     m_function    = function;
0294     m_currentBody = body;
0295 
0296     m_codeType    = FunctionCode;
0297     m_callingExec = callingExecState;
0298     scope = function->scope(); // Activation will push itself when setting up
0299     m_variable = m_interpreter->getRecycledActivation();// TODO: DontDelete ? (ECMA 10.2.3)
0300     if (!m_variable) {
0301         m_variable = new ActivationImp();
0302     }
0303     m_thisVal  = thisObject;
0304 }
0305 
0306 } // namespace KJS
0307