ExecutionTracerIntegration.cpp (6858B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "ExecutionTracerIntegration.h" 8 9 #include "mozilla/dom/Attr.h" 10 #include "mozilla/dom/BindingUtils.h" 11 #include "mozilla/dom/Document.h" 12 #include "mozilla/dom/DocumentFragment.h" 13 #include "mozilla/dom/DOMException.h" 14 #include "mozilla/dom/DOMExceptionBinding.h" 15 #include "mozilla/dom/Element.h" 16 #include "mozilla/dom/Location.h" 17 #include "nsDOMAttributeMap.h" 18 #include "nsQueryObject.h" 19 20 #ifdef MOZ_EXECUTION_TRACING 21 22 using namespace mozilla; 23 using namespace mozilla::dom; 24 25 template <prototypes::ID PrototypeID> 26 bool DOMClassHasInterface(const DOMJSClass* aDomClass) { 27 return aDomClass->mInterfaceChain[PrototypeTraits<PrototypeID>::Depth] == 28 PrototypeID; 29 } 30 31 bool ExecutionTracerIntegration::WriteNodeSummary( 32 JSContext* aCx, nsINode* aNode, bool aNested, 33 JS_TracerSummaryWriter* aWriter) { 34 uint16_t nodeType = aNode->NodeType(); 35 const nsString& nodeName = aNode->NodeName(); 36 bool isConnected = aNode->IsInComposedDoc(); 37 38 aWriter->writeUint8(uint8_t(SummaryKind::Node)); 39 aWriter->writeUint16(nodeType); 40 aWriter->writeTwoByteString(nodeName.get()); 41 42 if (RefPtr<Element> el = do_QueryObject(aNode)) { 43 aWriter->writeUint8(uint8_t(isConnected) << 7 | 44 uint8_t(NodeSubkind::Element)); 45 46 nsDOMAttributeMap* attributes = el->Attributes(); 47 uint32_t attributesLength = attributes->Length(); 48 49 aWriter->writeUint32(attributesLength); 50 for (uint32_t i = 0; 51 i < attributesLength && i < JS::ValueSummary::MAX_COLLECTION_VALUES; 52 ++i) { 53 nsAutoString attrName; 54 attributes->Item(i)->GetName(attrName); 55 aWriter->writeTwoByteString(attrName.get()); 56 57 nsAutoString attrValue; 58 attributes->Item(i)->GetValue(attrValue); 59 aWriter->writeTwoByteString(attrValue.get()); 60 } 61 } else if (RefPtr<Document> doc = do_QueryObject(aNode)) { 62 aWriter->writeUint8(uint8_t(isConnected) << 7 | 63 uint8_t(NodeSubkind::Document)); 64 RefPtr<Location> location = doc->GetLocation(); 65 nsAutoCString href; 66 if (location->GetHref(href) != NS_OK) { 67 JS_ReportErrorASCII(aCx, "Failed to get document location's href"); 68 return false; 69 } 70 aWriter->writeUTF8String(href.get()); 71 } else if (Attr* attr = Attr::FromNode(aNode)) { 72 aWriter->writeUint8(uint8_t(isConnected) << 7 | uint8_t(NodeSubkind::Attr)); 73 nsAutoString value; 74 attr->GetValue(value); 75 aWriter->writeTwoByteString(value.get()); 76 } else if (aNode->IsDocumentFragment()) { 77 aWriter->writeUint8(uint8_t(isConnected) << 7 | 78 uint8_t(NodeSubkind::DocumentFragment)); 79 80 nsCOMPtr<nsINodeList> children = aNode->ChildNodes(); 81 if (!children) { 82 JS_ReportErrorASCII(aCx, "OOM getting node's children"); 83 return false; 84 } 85 86 uint32_t numChildren = children->Length(); 87 aWriter->writeUint32(numChildren); 88 89 if (!aNested) { 90 for (uint32_t i = 0; 91 i < numChildren && i < JS::ValueSummary::MAX_COLLECTION_VALUES; 92 ++i) { 93 nsCOMPtr<nsINode> child = children->Item(i); 94 if (!child) { 95 JS_ReportErrorASCII(aCx, "Failed getting child node"); 96 return false; 97 } 98 99 JS::Rooted<JS::Value> childValue(aCx); 100 if (!ToJSValue(aCx, child.get(), &childValue)) { 101 return false; 102 } 103 104 if (!aWriter->writeValue(aCx, childValue)) { 105 return false; 106 } 107 } 108 } 109 } else if (aNode->IsText() || aNode->IsComment()) { 110 if (aNode->IsText()) { 111 aWriter->writeUint8(uint8_t(isConnected) << 7 | 112 uint8_t(NodeSubkind::Text)); 113 } else { 114 aWriter->writeUint8(uint8_t(isConnected) << 7 | 115 uint8_t(NodeSubkind::Comment)); 116 } 117 nsAutoString content; 118 ErrorResult rv; 119 aNode->GetTextContent(content, IgnoreErrors()); 120 aWriter->writeTwoByteString(content.get()); 121 } else { 122 aWriter->writeUint8(uint8_t(isConnected) << 7 | 123 uint8_t(NodeSubkind::Other)); 124 } 125 126 return true; 127 } 128 129 bool ExecutionTracerIntegration::WriteExceptionSummary( 130 JSContext* aCx, JS::Handle<JSObject*> aObj, bool aNested, 131 JS_TracerSummaryWriter* aWriter) { 132 RefPtr<DOMException> domException; 133 RefPtr<Exception> exception; 134 UNWRAP_OBJECT(DOMException, aObj, domException); 135 if (domException) { 136 exception = domException; 137 } else { 138 // Not a DOM Exception, try XPC Exception. 139 UNWRAP_OBJECT(Exception, aObj, exception); 140 if (!exception) { 141 return false; 142 } 143 } 144 aWriter->writeUint8(uint8_t(SummaryKind::Exception)); 145 146 nsAutoString name; 147 exception->GetName(name); 148 aWriter->writeTwoByteString(name.get()); 149 150 nsAutoString message; 151 exception->GetMessageMoz(message); 152 aWriter->writeTwoByteString(message.get()); 153 154 if (domException) { 155 uint16_t code = domException->Code(); 156 aWriter->writeUint16(code); 157 } else { 158 aWriter->writeUint16(0); 159 } 160 161 uint32_t result = exception->Result(); 162 aWriter->writeUint32(result); 163 164 nsAutoCString fileName; 165 exception->GetFilename(aCx, fileName); 166 aWriter->writeUTF8String(fileName.get()); 167 168 uint32_t line = exception->LineNumber(aCx); 169 aWriter->writeUint32(line); 170 171 uint32_t column = exception->ColumnNumber(aCx); 172 aWriter->writeUint32(column); 173 174 nsCOMPtr<nsIStackFrame> stack = exception->GetLocation(); 175 nsAutoString stackString; 176 if (stack) { 177 stack->GetFormattedStack(aCx, stackString); 178 aWriter->writeTwoByteString(stackString.get()); 179 } else { 180 aWriter->writeTwoByteString(u""); 181 } 182 183 return true; 184 } 185 186 // static 187 bool ExecutionTracerIntegration::Callback(JSContext* aCx, 188 JS::Handle<JSObject*> aObj, 189 bool aNested, 190 JS_TracerSummaryWriter* aWriter) { 191 aWriter->writeUint8(uint8_t(VERSION)); 192 193 const DOMJSClass* domClass = GetDOMClass(aObj); 194 if (!domClass) { 195 aWriter->writeUint8(uint8_t(SummaryKind::Other)); 196 return true; 197 } 198 199 if (DOMClassHasInterface<prototypes::id::Node>(domClass)) { 200 nsINode* node = UnwrapDOMObject<nsINode>(aObj); 201 if (!WriteNodeSummary(aCx, node, aNested, aWriter)) { 202 return false; 203 } 204 return true; 205 } 206 207 if (DOMClassHasInterface<prototypes::id::DOMException>(domClass) || 208 DOMClassHasInterface<prototypes::id::Exception>(domClass)) { 209 if (!WriteExceptionSummary(aCx, aObj, aNested, aWriter)) { 210 return false; 211 } 212 return true; 213 } 214 215 aWriter->writeUint8(uint8_t(SummaryKind::Other)); 216 return true; 217 } 218 219 #endif