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 "platform/v8_inspector/PromiseTracker.h" | |
6 | |
7 #include "platform/inspector_protocol/String16.h" | |
8 #include "platform/v8_inspector/V8DebuggerAgentImpl.h" | |
9 #include "platform/v8_inspector/V8StackTraceImpl.h" | |
10 #include "platform/v8_inspector/public/V8DebuggerClient.h" | |
11 #include "wtf/PassOwnPtr.h" | |
12 | |
13 using namespace blink::protocol; | |
14 | |
15 namespace blink { | |
16 | |
17 class PromiseTracker::PromiseWrapper { | |
18 public: | |
19 PromiseWrapper(PromiseTracker* tracker, int id, v8::Local<v8::Object> promis
e) | |
20 : m_tracker(tracker) | |
21 , m_id(id) | |
22 , m_promise(tracker->m_isolate, promise) { } | |
23 | |
24 ~PromiseWrapper() | |
25 { | |
26 OwnPtr<Debugger::PromiseDetails> promiseDetails = Debugger::PromiseDetai
ls::create().setId(m_id).build(); | |
27 m_tracker->m_agent->didUpdatePromise(Debugger::PromiseUpdated::EventType
Enum::Gc, promiseDetails.release()); | |
28 } | |
29 | |
30 private: | |
31 friend class PromiseTracker; | |
32 | |
33 PromiseTracker* m_tracker; | |
34 int m_id; | |
35 v8::Global<v8::Object> m_promise; | |
36 }; | |
37 | |
38 PromiseTracker::PromiseTracker(V8DebuggerAgentImpl* agent, v8::Isolate* isolate) | |
39 : m_circularSequentialId(0) | |
40 , m_isEnabled(false) | |
41 , m_captureStacks(false) | |
42 , m_agent(agent) | |
43 , m_isolate(isolate) | |
44 { | |
45 clear(); | |
46 } | |
47 | |
48 PromiseTracker::~PromiseTracker() | |
49 { | |
50 } | |
51 | |
52 void PromiseTracker::setEnabled(bool enabled, bool captureStacks) | |
53 { | |
54 m_isEnabled = enabled; | |
55 m_captureStacks = captureStacks; | |
56 if (!enabled) | |
57 clear(); | |
58 } | |
59 | |
60 void PromiseTracker::clear() | |
61 { | |
62 v8::HandleScope scope(m_isolate); | |
63 m_promiseToId.Reset(m_isolate, v8::NativeWeakMap::New(m_isolate)); | |
64 m_idToPromise.clear(); | |
65 } | |
66 | |
67 int PromiseTracker::circularSequentialId() | |
68 { | |
69 ++m_circularSequentialId; | |
70 if (m_circularSequentialId <= 0) | |
71 m_circularSequentialId = 1; | |
72 return m_circularSequentialId; | |
73 } | |
74 | |
75 void PromiseTracker::weakCallback(const v8::WeakCallbackInfo<PromiseWrapper>& da
ta) | |
76 { | |
77 PromiseWrapper* wrapper = data.GetParameter(); | |
78 wrapper->m_tracker->m_idToPromise.remove(wrapper->m_id); | |
79 } | |
80 | |
81 void PromiseTracker::promiseCollected(int id) | |
82 { | |
83 } | |
84 | |
85 int PromiseTracker::promiseId(v8::Local<v8::Object> promise, bool* isNewPromise) | |
86 { | |
87 v8::HandleScope scope(m_isolate); | |
88 v8::Local<v8::NativeWeakMap> map = v8::Local<v8::NativeWeakMap>::New(m_isola
te, m_promiseToId); | |
89 v8::Local<v8::Value> value = map->Get(promise); | |
90 if (value->IsInt32()) { | |
91 *isNewPromise = false; | |
92 return value.As<v8::Int32>()->Value(); | |
93 } | |
94 *isNewPromise = true; | |
95 int id = circularSequentialId(); | |
96 map->Set(promise, v8::Int32::New(m_isolate, id)); | |
97 | |
98 OwnPtr<PromiseWrapper> wrapper = adoptPtr(new PromiseWrapper(this, id, promi
se)); | |
99 wrapper->m_promise.SetWeak(wrapper.get(), weakCallback, v8::WeakCallbackType
::kParameter); | |
100 m_idToPromise.set(id, wrapper.release()); | |
101 return id; | |
102 } | |
103 | |
104 void PromiseTracker::didReceiveV8PromiseEvent(v8::Local<v8::Context> context, v8
::Local<v8::Object> promise, v8::Local<v8::Value> parentPromise, int status) | |
105 { | |
106 ASSERT(isEnabled()); | |
107 ASSERT(!context.IsEmpty()); | |
108 | |
109 bool isNewPromise = false; | |
110 int id = promiseId(promise, &isNewPromise); | |
111 | |
112 blink::protocol::String16 eventType = isNewPromise ? Debugger::PromiseUpdate
d::EventTypeEnum::New : Debugger::PromiseUpdated::EventTypeEnum::Update; | |
113 | |
114 blink::protocol::String16 promiseStatus; | |
115 switch (status) { | |
116 case 0: | |
117 promiseStatus = Debugger::PromiseDetails::StatusEnum::Pending; | |
118 break; | |
119 case 1: | |
120 promiseStatus = Debugger::PromiseDetails::StatusEnum::Resolved; | |
121 break; | |
122 default: | |
123 promiseStatus = Debugger::PromiseDetails::StatusEnum::Rejected; | |
124 }; | |
125 OwnPtr<Debugger::PromiseDetails> promiseDetails = Debugger::PromiseDetails::
create().setId(id).setStatus(promiseStatus).build(); | |
126 | |
127 if (!parentPromise.IsEmpty() && parentPromise->IsObject()) { | |
128 v8::Local<v8::Object> handle = parentPromise->ToObject(context->GetIsola
te()); | |
129 bool parentIsNewPromise = false; | |
130 int parentPromiseId = promiseId(handle, &parentIsNewPromise); | |
131 promiseDetails->setParentId(parentPromiseId); | |
132 } else { | |
133 if (!status) { | |
134 if (isNewPromise) { | |
135 promiseDetails->setCreationTime(m_agent->debugger().client()->cu
rrentTimeMS()); | |
136 OwnPtr<V8StackTraceImpl> stack = V8StackTraceImpl::capture(m_age
nt, m_captureStacks ? V8StackTraceImpl::maxCallStackSizeToCapture : 1); | |
137 if (stack) | |
138 promiseDetails->setCreationStack(stack->buildInspectorObject
()); | |
139 } | |
140 } else { | |
141 promiseDetails->setSettlementTime(m_agent->debugger().client()->curr
entTimeMS()); | |
142 if (m_captureStacks) { | |
143 OwnPtr<V8StackTraceImpl> stack = V8StackTraceImpl::capture(m_age
nt, V8StackTrace::maxCallStackSizeToCapture); | |
144 if (stack) | |
145 promiseDetails->setSettlementStack(stack->buildInspectorObje
ct()); | |
146 } | |
147 } | |
148 } | |
149 | |
150 m_agent->didUpdatePromise(eventType, promiseDetails.release()); | |
151 } | |
152 | |
153 v8::Local<v8::Object> PromiseTracker::promiseById(int promiseId) | |
154 { | |
155 ASSERT(isEnabled()); | |
156 PromiseWrapper* wrapper = m_idToPromise.get(promiseId); | |
157 return wrapper ? wrapper->m_promise.Get(m_isolate) : v8::Local<v8::Object>()
; | |
158 } | |
159 | |
160 } // namespace blink | |
OLD | NEW |