1 /* 2 * Copyright (C) 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 1999-2001 Harri Porten (porten (at) kde.org) 4 * Copyright (C) 2001 Peter Kelly (pmk (at) post.com) 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * 20 */ 21 22 #include "config.h" 23 #include "Debugger.h" 24 25 #include "Error.h" 26 #include "Interpreter.h" 27 #include "JSFunction.h" 28 #include "JSGlobalObject.h" 29 #include "Parser.h" 30 #include "Protect.h" 31 32 namespace { 33 34 using namespace JSC; 35 36 class Recompiler { 37 public: 38 Recompiler(Debugger*); 39 ~Recompiler(); 40 void operator()(JSCell*); 41 42 private: 43 typedef HashSet<FunctionExecutable*> FunctionExecutableSet; 44 typedef HashMap<SourceProvider*, ExecState*> SourceProviderMap; 45 46 Debugger* m_debugger; 47 FunctionExecutableSet m_functionExecutables; 48 SourceProviderMap m_sourceProviders; 49 }; 50 51 inline Recompiler::Recompiler(Debugger* debugger) 52 : m_debugger(debugger) 53 { 54 } 55 56 inline Recompiler::~Recompiler() 57 { 58 // Call sourceParsed() after reparsing all functions because it will execute 59 // JavaScript in the inspector. 60 SourceProviderMap::const_iterator end = m_sourceProviders.end(); 61 for (SourceProviderMap::const_iterator iter = m_sourceProviders.begin(); iter != end; ++iter) 62 m_debugger->sourceParsed(iter->second, iter->first, -1, UString()); 63 } 64 65 inline void Recompiler::operator()(JSCell* cell) 66 { 67 if (!cell->inherits(&JSFunction::s_info)) 68 return; 69 70 JSFunction* function = asFunction(cell); 71 if (function->executable()->isHostFunction()) 72 return; 73 74 FunctionExecutable* executable = function->jsExecutable(); 75 76 // Check if the function is already in the set - if so, 77 // we've already retranslated it, nothing to do here. 78 if (!m_functionExecutables.add(executable).second) 79 return; 80 81 ExecState* exec = function->scope()->globalObject->JSGlobalObject::globalExec(); 82 executable->discardCode(); 83 if (m_debugger == function->scope()->globalObject->debugger()) 84 m_sourceProviders.add(executable->source().provider(), exec); 85 } 86 87 } // namespace 88 89 namespace JSC { 90 91 Debugger::~Debugger() 92 { 93 HashSet<JSGlobalObject*>::iterator end = m_globalObjects.end(); 94 for (HashSet<JSGlobalObject*>::iterator it = m_globalObjects.begin(); it != end; ++it) 95 (*it)->setDebugger(0); 96 } 97 98 void Debugger::attach(JSGlobalObject* globalObject) 99 { 100 ASSERT(!globalObject->debugger()); 101 globalObject->setDebugger(this); 102 m_globalObjects.add(globalObject); 103 } 104 105 void Debugger::detach(JSGlobalObject* globalObject) 106 { 107 ASSERT(m_globalObjects.contains(globalObject)); 108 m_globalObjects.remove(globalObject); 109 globalObject->setDebugger(0); 110 } 111 112 void Debugger::recompileAllJSFunctions(JSGlobalData* globalData) 113 { 114 // If JavaScript is running, it's not safe to recompile, since we'll end 115 // up throwing away code that is live on the stack. 116 ASSERT(!globalData->dynamicGlobalObject); 117 if (globalData->dynamicGlobalObject) 118 return; 119 120 Recompiler recompiler(this); 121 globalData->heap.forEach(recompiler); 122 } 123 124 JSValue evaluateInGlobalCallFrame(const UString& script, JSValue& exception, JSGlobalObject* globalObject) 125 { 126 CallFrame* globalCallFrame = globalObject->globalExec(); 127 JSGlobalData& globalData = globalObject->globalData(); 128 129 EvalExecutable* eval = EvalExecutable::create(globalCallFrame, makeSource(script), false); 130 if (!eval) { 131 exception = globalData.exception; 132 globalData.exception = JSValue(); 133 return exception; 134 } 135 136 JSValue result = globalData.interpreter->execute(eval, globalCallFrame, globalObject, globalCallFrame->scopeChain()); 137 if (globalData.exception) { 138 exception = globalData.exception; 139 globalData.exception = JSValue(); 140 } 141 ASSERT(result); 142 return result; 143 } 144 145 } // namespace JSC 146