1/* 2 * Copyright (c) 2010, Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "core/inspector/JavaScriptCallFrame.h" 33 34#include "bindings/core/v8/ScriptValue.h" 35#include "bindings/core/v8/V8Binding.h" 36#include <v8-debug.h> 37 38namespace blink { 39 40JavaScriptCallFrame::JavaScriptCallFrame(v8::Handle<v8::Context> debuggerContext, v8::Handle<v8::Object> callFrame) 41 : m_isolate(v8::Isolate::GetCurrent()) 42 , m_debuggerContext(m_isolate, debuggerContext) 43 , m_callFrame(m_isolate, callFrame) 44{ 45} 46 47JavaScriptCallFrame::~JavaScriptCallFrame() 48{ 49} 50 51JavaScriptCallFrame* JavaScriptCallFrame::caller() 52{ 53 if (!m_caller) { 54 v8::HandleScope handleScope(m_isolate); 55 v8::Handle<v8::Context> debuggerContext = m_debuggerContext.newLocal(m_isolate); 56 v8::Context::Scope contextScope(debuggerContext); 57 v8::Handle<v8::Value> callerFrame = m_callFrame.newLocal(m_isolate)->Get(v8AtomicString(m_isolate, "caller")); 58 if (callerFrame.IsEmpty() || !callerFrame->IsObject()) 59 return 0; 60 m_caller = JavaScriptCallFrame::create(debuggerContext, v8::Handle<v8::Object>::Cast(callerFrame)); 61 } 62 return m_caller.get(); 63} 64 65int JavaScriptCallFrame::callV8FunctionReturnInt(const char* name) const 66{ 67 v8::HandleScope handleScope(m_isolate); 68 v8::Context::Scope contextScope(m_debuggerContext.newLocal(m_isolate)); 69 v8::Handle<v8::Object> callFrame = m_callFrame.newLocal(m_isolate); 70 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(callFrame->Get(v8AtomicString(m_isolate, name))); 71 v8::Handle<v8::Value> result = func->Call(callFrame, 0, 0); 72 if (result.IsEmpty() || !result->IsInt32()) 73 return 0; 74 return result->Int32Value(); 75} 76 77String JavaScriptCallFrame::callV8FunctionReturnString(const char* name) const 78{ 79 v8::HandleScope handleScope(m_isolate); 80 v8::Context::Scope contextScope(m_debuggerContext.newLocal(m_isolate)); 81 v8::Handle<v8::Object> callFrame = m_callFrame.newLocal(m_isolate); 82 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(callFrame->Get(v8AtomicString(m_isolate, name))); 83 v8::Handle<v8::Value> result = func->Call(callFrame, 0, 0); 84 return toCoreStringWithUndefinedOrNullCheck(result); 85} 86 87int JavaScriptCallFrame::sourceID() const 88{ 89 return callV8FunctionReturnInt("sourceID"); 90} 91 92int JavaScriptCallFrame::line() const 93{ 94 return callV8FunctionReturnInt("line"); 95} 96 97int JavaScriptCallFrame::column() const 98{ 99 return callV8FunctionReturnInt("column"); 100} 101 102String JavaScriptCallFrame::scriptName() const 103{ 104 return callV8FunctionReturnString("scriptName"); 105} 106 107String JavaScriptCallFrame::functionName() const 108{ 109 return callV8FunctionReturnString("functionName"); 110} 111 112v8::Handle<v8::Value> JavaScriptCallFrame::scopeChain() const 113{ 114 v8::Handle<v8::Object> callFrame = m_callFrame.newLocal(m_isolate); 115 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(callFrame->Get(v8AtomicString(m_isolate, "scopeChain"))); 116 v8::Handle<v8::Array> scopeChain = v8::Handle<v8::Array>::Cast(func->Call(callFrame, 0, 0)); 117 v8::Handle<v8::Array> result = v8::Array::New(m_isolate, scopeChain->Length()); 118 for (uint32_t i = 0; i < scopeChain->Length(); i++) 119 result->Set(i, scopeChain->Get(i)); 120 return result; 121} 122 123int JavaScriptCallFrame::scopeType(int scopeIndex) const 124{ 125 v8::Handle<v8::Array> scopeType = v8::Handle<v8::Array>::Cast(m_callFrame.newLocal(m_isolate)->Get(v8AtomicString(m_isolate, "scopeType"))); 126 return scopeType->Get(scopeIndex)->Int32Value(); 127} 128 129v8::Handle<v8::Value> JavaScriptCallFrame::thisObject() const 130{ 131 return m_callFrame.newLocal(m_isolate)->Get(v8AtomicString(m_isolate, "thisObject")); 132} 133 134String JavaScriptCallFrame::stepInPositions() const 135{ 136 return callV8FunctionReturnString("stepInPositions"); 137} 138 139bool JavaScriptCallFrame::isAtReturn() const 140{ 141 v8::HandleScope handleScope(m_isolate); 142 v8::Context::Scope contextScope(m_debuggerContext.newLocal(m_isolate)); 143 v8::Handle<v8::Value> result = m_callFrame.newLocal(m_isolate)->Get(v8AtomicString(m_isolate, "isAtReturn")); 144 if (result.IsEmpty() || !result->IsBoolean()) 145 return false; 146 return result->BooleanValue(); 147} 148 149v8::Handle<v8::Value> JavaScriptCallFrame::returnValue() const 150{ 151 return m_callFrame.newLocal(m_isolate)->Get(v8AtomicString(m_isolate, "returnValue")); 152} 153 154v8::Handle<v8::Value> JavaScriptCallFrame::evaluateWithExceptionDetails(const String& expression) 155{ 156 v8::Handle<v8::Object> callFrame = m_callFrame.newLocal(m_isolate); 157 v8::Handle<v8::Function> evalFunction = v8::Handle<v8::Function>::Cast(callFrame->Get(v8AtomicString(m_isolate, "evaluate"))); 158 v8::Handle<v8::Value> argv[] = { v8String(m_debuggerContext.newLocal(m_isolate)->GetIsolate(), expression) }; 159 v8::TryCatch tryCatch; 160 v8::Handle<v8::Value> result = evalFunction->Call(callFrame, WTF_ARRAY_LENGTH(argv), argv); 161 162 v8::Handle<v8::Object> wrappedResult = v8::Object::New(m_isolate); 163 if (tryCatch.HasCaught()) { 164 wrappedResult->Set(v8::String::NewFromUtf8(m_isolate, "result"), tryCatch.Exception()); 165 wrappedResult->Set(v8::String::NewFromUtf8(m_isolate, "exceptionDetails"), createExceptionDetails(tryCatch.Message(), m_isolate)); 166 } else { 167 wrappedResult->Set(v8::String::NewFromUtf8(m_isolate, "result"), result); 168 wrappedResult->Set(v8::String::NewFromUtf8(m_isolate, "exceptionDetails"), v8::Undefined(m_isolate)); 169 } 170 return wrappedResult; 171} 172 173v8::Handle<v8::Value> JavaScriptCallFrame::restart() 174{ 175 v8::Handle<v8::Object> callFrame = m_callFrame.newLocal(m_isolate); 176 v8::Handle<v8::Function> restartFunction = v8::Handle<v8::Function>::Cast(callFrame->Get(v8AtomicString(m_isolate, "restart"))); 177 v8::Debug::SetLiveEditEnabled(m_isolate, true); 178 v8::Handle<v8::Value> result = restartFunction->Call(callFrame, 0, 0); 179 v8::Debug::SetLiveEditEnabled(m_isolate, false); 180 return result; 181} 182 183ScriptValue JavaScriptCallFrame::setVariableValue(ScriptState* scriptState, int scopeNumber, const String& variableName, const ScriptValue& newValue) 184{ 185 ScriptState::Scope scriptScope(scriptState); 186 v8::Handle<v8::Object> callFrame = m_callFrame.newLocal(m_isolate); 187 v8::Handle<v8::Function> setVariableValueFunction = v8::Handle<v8::Function>::Cast(callFrame->Get(v8AtomicString(m_isolate, "setVariableValue"))); 188 v8::Handle<v8::Value> argv[] = { 189 v8::Handle<v8::Value>(v8::Integer::New(m_isolate, scopeNumber)), 190 v8String(m_isolate, variableName), 191 newValue.v8Value() 192 }; 193 return ScriptValue(scriptState, setVariableValueFunction->Call(callFrame, WTF_ARRAY_LENGTH(argv), argv)); 194} 195 196v8::Handle<v8::Object> JavaScriptCallFrame::createExceptionDetails(v8::Handle<v8::Message> message, v8::Isolate* isolate) 197{ 198 v8::Handle<v8::Object> exceptionDetails = v8::Object::New(isolate); 199 exceptionDetails->Set(v8::String::NewFromUtf8(isolate, "text"), message->Get()); 200 exceptionDetails->Set(v8::String::NewFromUtf8(isolate, "url"), message->GetScriptOrigin().ResourceName()); 201 exceptionDetails->Set(v8::String::NewFromUtf8(isolate, "line"), v8::Integer::New(isolate, message->GetLineNumber())); 202 exceptionDetails->Set(v8::String::NewFromUtf8(isolate, "column"), v8::Integer::New(isolate, message->GetStartColumn())); 203 if (!message->GetStackTrace().IsEmpty()) 204 exceptionDetails->Set(v8::String::NewFromUtf8(isolate, "stackTrace"), message->GetStackTrace()->AsArray()); 205 else 206 exceptionDetails->Set(v8::String::NewFromUtf8(isolate, "stackTrace"), v8::Undefined(isolate)); 207 return exceptionDetails; 208} 209 210void JavaScriptCallFrame::trace(Visitor* visitor) 211{ 212 visitor->trace(m_caller); 213} 214 215} // namespace blink 216