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