| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "core/inspector/PromiseTracker.h" | |
| 6 | |
| 7 #include "bindings/core/v8/ScriptCallStackFactory.h" | |
| 8 #include "core/inspector/ScriptAsyncCallStack.h" | |
| 9 #include "wtf/CurrentTime.h" | |
| 10 #include "wtf/PassOwnPtr.h" | |
| 11 #include "wtf/WeakPtr.h" | |
| 12 | |
| 13 using blink::TypeBuilder::Array; | |
| 14 using blink::TypeBuilder::Console::CallFrame; | |
| 15 using blink::TypeBuilder::Debugger::PromiseDetails; | |
| 16 | |
| 17 namespace blink { | |
| 18 | |
| 19 class PromiseTracker::PromiseWeakCallbackData final { | |
| 20 WTF_MAKE_NONCOPYABLE(PromiseWeakCallbackData); | |
| 21 public: | |
| 22 PromiseWeakCallbackData(PromiseTracker* tracker, int id) | |
| 23 : m_tracker(tracker->m_weakPtrFactory.createWeakPtr()) | |
| 24 , m_id(id) | |
| 25 { | |
| 26 } | |
| 27 | |
| 28 ~PromiseWeakCallbackData() | |
| 29 { | |
| 30 if (!m_tracker) | |
| 31 return; | |
| 32 RefPtr<PromiseDetails> promiseDetails = PromiseDetails::create().setId(m
_id); | |
| 33 m_tracker->m_listener->didUpdatePromise(InspectorFrontend::Debugger::Eve
ntType::Gc, promiseDetails.release()); | |
| 34 } | |
| 35 | |
| 36 WeakPtr<PromiseTracker> m_tracker; | |
| 37 int m_id; | |
| 38 }; | |
| 39 | |
| 40 PromiseTracker::IdToPromiseMapTraits::WeakCallbackDataType* PromiseTracker::IdTo
PromiseMapTraits::WeakCallbackParameter(MapType* map, int key, v8::Local<v8::Obj
ect>& value) | |
| 41 { | |
| 42 // This method is called when promise is added into the map, hence the map m
ust be alive at this point. The tracker in turn must be alive too. | |
| 43 PromiseTracker* tracker = reinterpret_cast<PromiseTracker*>(reinterpret_cast
<intptr_t>(map) - offsetof(PromiseTracker, m_idToPromise)); | |
| 44 return new PromiseWeakCallbackData(tracker, key); | |
| 45 } | |
| 46 | |
| 47 void PromiseTracker::IdToPromiseMapTraits::DisposeCallbackData(WeakCallbackDataT
ype* callbackData) | |
| 48 { | |
| 49 delete callbackData; | |
| 50 } | |
| 51 | |
| 52 void PromiseTracker::IdToPromiseMapTraits::DisposeWeak(const v8::WeakCallbackInf
o<WeakCallbackDataType>& data) | |
| 53 { | |
| 54 delete data.GetParameter(); | |
| 55 } | |
| 56 | |
| 57 PromiseTracker::IdToPromiseMapTraits::MapType* PromiseTracker::IdToPromiseMapTra
its::MapFromWeakCallbackInfo(const v8::WeakCallbackInfo<WeakCallbackDataType>& i
nfo) | |
| 58 { | |
| 59 return &info.GetParameter()->m_tracker->m_idToPromise; | |
| 60 } | |
| 61 | |
| 62 int PromiseTracker::IdToPromiseMapTraits::KeyFromWeakCallbackInfo(const v8::Weak
CallbackInfo<WeakCallbackDataType>& info) | |
| 63 { | |
| 64 return info.GetParameter()->m_id; | |
| 65 } | |
| 66 | |
| 67 PromiseTracker::PromiseTracker(Listener* listener, v8::Isolate* isolate) | |
| 68 : m_circularSequentialId(0) | |
| 69 , m_isEnabled(false) | |
| 70 , m_captureStacks(false) | |
| 71 , m_listener(listener) | |
| 72 , m_isolate(isolate) | |
| 73 , m_weakPtrFactory(this) | |
| 74 , m_idToPromise(isolate) | |
| 75 { | |
| 76 clear(); | |
| 77 } | |
| 78 | |
| 79 PromiseTracker::~PromiseTracker() | |
| 80 { | |
| 81 } | |
| 82 | |
| 83 void PromiseTracker::setEnabled(bool enabled, bool captureStacks) | |
| 84 { | |
| 85 m_isEnabled = enabled; | |
| 86 m_captureStacks = captureStacks; | |
| 87 if (!enabled) | |
| 88 clear(); | |
| 89 } | |
| 90 | |
| 91 void PromiseTracker::clear() | |
| 92 { | |
| 93 v8::HandleScope scope(m_isolate); | |
| 94 m_promiseToId.Reset(m_isolate, v8::NativeWeakMap::New(m_isolate)); | |
| 95 m_idToPromise.Clear(); | |
| 96 } | |
| 97 | |
| 98 int PromiseTracker::circularSequentialId() | |
| 99 { | |
| 100 ++m_circularSequentialId; | |
| 101 if (m_circularSequentialId <= 0) | |
| 102 m_circularSequentialId = 1; | |
| 103 return m_circularSequentialId; | |
| 104 } | |
| 105 | |
| 106 int PromiseTracker::promiseId(v8::Local<v8::Object> promise, bool* isNewPromise) | |
| 107 { | |
| 108 v8::HandleScope scope(m_isolate); | |
| 109 v8::Local<v8::NativeWeakMap> map = v8::Local<v8::NativeWeakMap>::New(m_isola
te, m_promiseToId); | |
| 110 v8::Local<v8::Value> value = map->Get(promise); | |
| 111 if (value->IsInt32()) { | |
| 112 *isNewPromise = false; | |
| 113 return value.As<v8::Int32>()->Value(); | |
| 114 } | |
| 115 *isNewPromise = true; | |
| 116 int id = circularSequentialId(); | |
| 117 map->Set(promise, v8::Int32::New(m_isolate, id)); | |
| 118 m_idToPromise.Set(id, promise); | |
| 119 return id; | |
| 120 } | |
| 121 | |
| 122 void PromiseTracker::didReceiveV8PromiseEvent(v8::Local<v8::Context> context, v8
::Local<v8::Object> promise, v8::Local<v8::Value> parentPromise, int status) | |
| 123 { | |
| 124 ASSERT(isEnabled()); | |
| 125 ASSERT(!context.IsEmpty()); | |
| 126 | |
| 127 bool isNewPromise = false; | |
| 128 int id = promiseId(promise, &isNewPromise); | |
| 129 | |
| 130 InspectorFrontend::Debugger::EventType::Enum eventType = isNewPromise ? Insp
ectorFrontend::Debugger::EventType::New : InspectorFrontend::Debugger::EventType
::Update; | |
| 131 | |
| 132 PromiseDetails::Status::Enum promiseStatus; | |
| 133 switch (status) { | |
| 134 case 0: | |
| 135 promiseStatus = PromiseDetails::Status::Pending; | |
| 136 break; | |
| 137 case 1: | |
| 138 promiseStatus = PromiseDetails::Status::Resolved; | |
| 139 break; | |
| 140 default: | |
| 141 promiseStatus = PromiseDetails::Status::Rejected; | |
| 142 }; | |
| 143 RefPtr<PromiseDetails> promiseDetails = PromiseDetails::create().setId(id); | |
| 144 promiseDetails->setStatus(promiseStatus); | |
| 145 | |
| 146 if (!parentPromise.IsEmpty() && parentPromise->IsObject()) { | |
| 147 v8::Local<v8::Object> handle = parentPromise->ToObject(context->GetIsola
te()); | |
| 148 bool parentIsNewPromise = false; | |
| 149 int parentPromiseId = promiseId(handle, &parentIsNewPromise); | |
| 150 promiseDetails->setParentId(parentPromiseId); | |
| 151 } else { | |
| 152 if (!status) { | |
| 153 if (isNewPromise) { | |
| 154 promiseDetails->setCreationTime(currentTimeMS()); | |
| 155 RefPtr<ScriptCallStack> stack = currentScriptCallStack(m_capture
Stacks ? ScriptCallStack::maxCallStackSizeToCapture : 1); | |
| 156 if (stack) { | |
| 157 if (stack->size()) { | |
| 158 promiseDetails->setCallFrame(stack->at(0).buildInspector
Object()); | |
| 159 if (m_captureStacks) | |
| 160 promiseDetails->setCreationStack(stack->buildInspect
orArray()); | |
| 161 } | |
| 162 RefPtr<ScriptAsyncCallStack> asyncCallStack = stack->asyncCa
llStack(); | |
| 163 if (m_captureStacks && asyncCallStack) | |
| 164 promiseDetails->setAsyncCreationStack(asyncCallStack->bu
ildInspectorObject()); | |
| 165 } | |
| 166 } | |
| 167 } else { | |
| 168 promiseDetails->setSettlementTime(currentTimeMS()); | |
| 169 if (m_captureStacks) { | |
| 170 RefPtr<ScriptCallStack> stack = currentScriptCallStack(ScriptCal
lStack::maxCallStackSizeToCapture); | |
| 171 if (stack) { | |
| 172 if (stack->size()) | |
| 173 promiseDetails->setSettlementStack(stack->buildInspector
Array()); | |
| 174 if (RefPtr<ScriptAsyncCallStack> asyncCallStack = stack->asy
ncCallStack()) | |
| 175 promiseDetails->setAsyncSettlementStack(asyncCallStack->
buildInspectorObject()); | |
| 176 } | |
| 177 } | |
| 178 } | |
| 179 } | |
| 180 | |
| 181 m_listener->didUpdatePromise(eventType, promiseDetails.release()); | |
| 182 } | |
| 183 | |
| 184 v8::Local<v8::Object> PromiseTracker::promiseById(int promiseId) | |
| 185 { | |
| 186 ASSERT(isEnabled()); | |
| 187 return m_idToPromise.Get(promiseId); | |
| 188 } | |
| 189 | |
| 190 } // namespace blink | |
| OLD | NEW |