Changeset 219639 in webkit
- Timestamp:
- Jul 18, 2017, 4:19:57 PM (8 years ago)
- Location:
- trunk
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r219638 r219639 1 2017-07-18 Joseph Pecoraro <pecoraro@apple.com> 2 3 Web Inspector: Modernize InjectedScriptSource 4 https://bugs.webkit.org/show_bug.cgi?id=173890 5 6 Reviewed by Brian Burg. 7 8 * inspector/model/remote-object-expected.txt: 9 * inspector/model/stack-trace-expected.txt: 10 Now that we use classes, implicitly strict mode, the call frame 11 for evaluate gets tail call eliminated. 12 1 13 2017-07-18 Ryosuke Niwa <rniwa@webkit.org> 2 14 -
trunk/LayoutTests/inspector/model/remote-object-expected.txt
r219612 r219639 1657 1657 "_name": "stack", 1658 1658 "_type": "string", 1659 "_value": "global code\nevaluateWithScopeExtension@[native code]\n_evaluateOn\n_evaluateAndWrap \nevaluate"1659 "_value": "global code\nevaluateWithScopeExtension@[native code]\n_evaluateOn\n_evaluateAndWrap" 1660 1660 } 1661 1661 ], … … 1696 1696 "_name": "stack", 1697 1697 "_type": "string", 1698 "_value": "eval@[native code]\nglobal code\nevaluateWithScopeEx …ative code]\n_evaluateOn\n_evaluateAndWrap\nevaluate"1698 "_value": "eval@[native code]\nglobal code\nevaluateWithScopeExtension@[native code]\n_evaluateOn\n_evaluateAndWrap" 1699 1699 } 1700 1700 ], … … 1730 1730 "_name": "stack", 1731 1731 "_type": "string", 1732 "_value": "splitText@[native code]\nglobal code\nevaluateWithSc… ative code]\n_evaluateOn\n_evaluateAndWrap\nevaluate"1732 "_value": "splitText@[native code]\nglobal code\nevaluateWithSc…ension@[native code]\n_evaluateOn\n_evaluateAndWrap" 1733 1733 }, 1734 1734 { -
trunk/LayoutTests/inspector/model/stack-trace-expected.txt
r200533 r219639 9 9 PASS: CallFrame in StackTrace has no thisObject. 10 10 PASS: CallFrame in StackTrace has no scopeChain. 11 StackTrace: 1 111 StackTrace: 10 12 12 1: foo (Anonymous Script 1 (line 1)) - nativeCode (false) programCode (false) 13 13 2: Eval Code (Anonymous Script 1 (line 1)) - nativeCode (false) programCode (true) … … 20 20 9: _evaluateOn - nativeCode (true) programCode (false) 21 21 10: _evaluateAndWrap - nativeCode (true) programCode (false) 22 11: evaluate - nativeCode (true) programCode (false)23 22 -
trunk/Source/JavaScriptCore/ChangeLog
r219636 r219639 1 2017-07-18 Joseph Pecoraro <pecoraro@apple.com> 2 3 Web Inspector: Modernize InjectedScriptSource 4 https://bugs.webkit.org/show_bug.cgi?id=173890 5 6 Reviewed by Brian Burg. 7 8 * inspector/InjectedScript.h: 9 Reorder functions to be slightly better. 10 11 * inspector/InjectedScriptSource.js: 12 - Convert to classes named InjectedScript and RemoteObject 13 - Align InjectedScript's API with the wrapper C++ interfaces 14 - Move some code to RemoteObject where appropriate (subtype, describe) 15 - Move some code to helper functions (isPrimitiveValue, isDefined) 16 - Refactor for readability and modern features 17 - Remove some unused / unnecessary code 18 1 19 2017-07-18 Mark Lam <mark.lam@apple.com> 2 20 -
trunk/Source/JavaScriptCore/inspector/InjectedScript.h
r218794 r219639 52 52 53 53 void evaluate(ErrorString&, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>* result, Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex); 54 void evaluateOnCallFrame(ErrorString&, JSC::JSValue callFrames, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>* result, Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex); 54 55 void callFunctionOn(ErrorString&, const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, RefPtr<Protocol::Runtime::RemoteObject>* result, Protocol::OptOutput<bool>* wasThrown); 55 void evaluateOnCallFrame(ErrorString&, JSC::JSValue callFrames, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>* result, Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex);56 56 void getFunctionDetails(ErrorString&, const String& functionId, RefPtr<Protocol::Debugger::FunctionDetails>* result); 57 57 void functionDetails(ErrorString&, JSC::JSValue, RefPtr<Protocol::Debugger::FunctionDetails>* result); -
trunk/Source/JavaScriptCore/inspector/InjectedScriptSource.js
r218718 r219639 68 68 } 69 69 70 var InjectedScript = function()70 function isDefined(value) 71 71 { 72 this._lastBoundObjectId = 1; 73 this._idToWrappedObject = {}; 74 this._idToObjectGroupName = {}; 75 this._objectGroups = {}; 76 this._modules = {}; 77 this._nextSavedResultIndex = 1; 78 this._savedResults = []; 72 return !!value || InjectedScriptHost.isHTMLAllCollection(value); 79 73 } 80 74 81 InjectedScript.primitiveTypes = { 82 undefined: true, 83 boolean: true, 84 number: true, 85 string: true, 75 function isPrimitiveValue(value) 76 { 77 switch (typeof value) { 78 case "boolean": 79 case "number": 80 case "string": 81 return true; 82 case "undefined": 83 return !InjectedScriptHost.isHTMLAllCollection(value); 84 default: 85 return false; 86 } 86 87 } 87 88 88 InjectedScript.CollectionMode = { 89 OwnProperties: 1 << 0, // own properties. 90 NativeGetterProperties: 1 << 1, // native getter properties in the prototype chain. 91 AllProperties: 1 << 2, // all properties in the prototype chain. 92 } 93 94 InjectedScript.prototype = { 95 isPrimitiveValue: function(object) 96 { 97 // FIXME(33716): typeof document.all is always 'undefined'. 98 return InjectedScript.primitiveTypes[typeof object] && !this._isHTMLAllCollection(object); 99 }, 100 101 previewValue: function(value) 102 { 103 return InjectedScript.RemoteObject.createObjectPreviewForValue(value, true); 104 }, 105 106 functionDetails: function(func) 107 { 108 var details = InjectedScriptHost.functionDetails(func); 109 if (!details) 110 return "Cannot resolve function details."; 111 112 return details; 113 }, 114 115 wrapObject: function(object, groupName, canAccessInspectedGlobalObject, generatePreview) 116 { 117 if (canAccessInspectedGlobalObject) 118 return this._wrapObject(object, groupName, false, generatePreview); 119 return this._fallbackWrapper(object); 120 }, 121 122 setExceptionValue: function(value) 123 { 124 this._exceptionValue = value; 125 }, 126 127 clearExceptionValue: function() 128 { 129 delete this._exceptionValue; 130 }, 131 132 _fallbackWrapper: function(object) 133 { 134 var result = {}; 135 result.type = typeof object; 136 if (this.isPrimitiveValue(object)) 137 result.value = object; 138 else 139 result.description = toString(object); 140 return result; 141 }, 142 143 wrapTable: function(canAccessInspectedGlobalObject, table, columns) 144 { 145 if (!canAccessInspectedGlobalObject) 146 return this._fallbackWrapper(table); 147 148 // FIXME: Currently columns are ignored. Instead, the frontend filters all 149 // properties based on the provided column names and in the provided order. 150 // We could filter here to avoid sending very large preview objects. 151 152 var columnNames = null; 153 if (typeof columns === "string") 154 columns = [columns]; 155 156 if (InjectedScriptHost.subtype(columns) === "array") { 157 columnNames = []; 158 for (var i = 0; i < columns.length; ++i) 159 columnNames.push(toString(columns[i])); 160 } 161 162 return this._wrapObject(table, "console", false, true, columnNames); 163 }, 164 165 inspectObject: function(object) 166 { 167 if (this._commandLineAPIImpl) 168 this._commandLineAPIImpl.inspect(object); 169 }, 170 171 _wrapObject: function(object, objectGroupName, forceValueType, generatePreview, columnNames) 172 { 173 try { 174 return new InjectedScript.RemoteObject(object, objectGroupName, forceValueType, generatePreview, columnNames); 175 } catch (e) { 176 try { 177 var description = injectedScript._describe(e); 178 } catch (ex) { 179 var description = "<failed to convert exception to string>"; 180 } 181 return new InjectedScript.RemoteObject(description); 182 } 183 }, 184 185 _bind: function(object, objectGroupName) 186 { 187 var id = this._lastBoundObjectId++; 188 this._idToWrappedObject[id] = object; 189 var objectId = "{\"injectedScriptId\":" + injectedScriptId + ",\"id\":" + id + "}"; 190 if (objectGroupName) { 191 var group = this._objectGroups[objectGroupName]; 192 if (!group) { 193 group = []; 194 this._objectGroups[objectGroupName] = group; 195 } 196 group.push(id); 197 this._idToObjectGroupName[id] = objectGroupName; 198 } 199 return objectId; 200 }, 201 202 _parseObjectId: function(objectId) 203 { 204 return InjectedScriptHost.evaluate("(" + objectId + ")"); 205 }, 206 207 releaseObjectGroup: function(objectGroupName) 208 { 209 if (objectGroupName === "console") { 210 delete this._lastResult; 211 this._nextSavedResultIndex = 1; 212 this._savedResults = []; 213 } 214 215 var group = this._objectGroups[objectGroupName]; 216 if (!group) 217 return; 218 219 for (var i = 0; i < group.length; i++) 220 this._releaseObject(group[i]); 221 222 delete this._objectGroups[objectGroupName]; 223 }, 224 225 dispatch: function(methodName, args) 226 { 227 var argsArray = InjectedScriptHost.evaluate("(" + args + ")"); 228 var result = this[methodName].apply(this, argsArray); 229 if (typeof result === "undefined") { 230 if (inspectedGlobalObject.console) 231 inspectedGlobalObject.console.error("Web Inspector error: InjectedScript.%s returns undefined", methodName); 232 result = null; 233 } 234 return result; 235 }, 236 237 getPreview: function(objectId) 89 // ------- 90 91 let InjectedScript = class InjectedScript 92 { 93 constructor() 94 { 95 this._lastBoundObjectId = 1; 96 this._idToWrappedObject = {}; 97 this._idToObjectGroupName = {}; 98 this._objectGroups = {}; 99 this._modules = {}; 100 this._nextSavedResultIndex = 1; 101 this._savedResults = []; 102 } 103 104 // InjectedScript C++ API 105 106 evaluate(expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, saveResult) 107 { 108 return this._evaluateAndWrap(InjectedScriptHost.evaluateWithScopeExtension, InjectedScriptHost, expression, objectGroup, false, injectCommandLineAPI, returnByValue, generatePreview, saveResult); 109 } 110 111 evaluateOnCallFrame(topCallFrame, callFrameId, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, saveResult) 112 { 113 let callFrame = this._callFrameForId(topCallFrame, callFrameId); 114 if (!callFrame) 115 return "Could not find call frame with given id"; 116 return this._evaluateAndWrap(callFrame.evaluateWithScopeExtension, callFrame, expression, objectGroup, true, injectCommandLineAPI, returnByValue, generatePreview, saveResult); 117 } 118 119 callFunctionOn(objectId, expression, args, returnByValue, generatePreview) 238 120 { 239 121 let parsedObjectId = this._parseObjectId(objectId); 240 122 let object = this._objectForId(parsedObjectId); 241 242 return InjectedScript.RemoteObject.createObjectPreviewForValue(object, true); 243 }, 244 245 _getProperties: function(objectId, collectionMode, generatePreview, nativeGettersAsValues) 246 { 247 var parsedObjectId = this._parseObjectId(objectId); 248 var object = this._objectForId(parsedObjectId); 249 var objectGroupName = this._idToObjectGroupName[parsedObjectId.id]; 250 251 if (!this._isDefined(object)) 252 return false; 253 254 if (isSymbol(object)) 255 return false; 256 257 var descriptors = this._propertyDescriptors(object, collectionMode, nativeGettersAsValues); 258 259 // Go over properties, wrap object values. 260 for (var i = 0; i < descriptors.length; ++i) { 261 var descriptor = descriptors[i]; 262 if ("get" in descriptor) 263 descriptor.get = this._wrapObject(descriptor.get, objectGroupName); 264 if ("set" in descriptor) 265 descriptor.set = this._wrapObject(descriptor.set, objectGroupName); 266 if ("value" in descriptor) 267 descriptor.value = this._wrapObject(descriptor.value, objectGroupName, false, generatePreview); 268 if (!("configurable" in descriptor)) 269 descriptor.configurable = false; 270 if (!("enumerable" in descriptor)) 271 descriptor.enumerable = false; 272 if ("symbol" in descriptor) 273 descriptor.symbol = this._wrapObject(descriptor.symbol, objectGroupName); 274 } 275 276 return descriptors; 277 }, 278 279 getProperties: function(objectId, ownProperties, generatePreview) 280 { 281 var nativeGettersAsValues = false; 282 var collectionMode = ownProperties ? InjectedScript.CollectionMode.OwnProperties : InjectedScript.CollectionMode.AllProperties; 283 return this._getProperties(objectId, collectionMode, generatePreview, nativeGettersAsValues); 284 }, 285 286 getDisplayableProperties: function(objectId, generatePreview) 287 { 288 var nativeGettersAsValues = true; 289 var collectionMode = InjectedScript.CollectionMode.OwnProperties | InjectedScript.CollectionMode.NativeGetterProperties; 290 return this._getProperties(objectId, collectionMode, generatePreview, nativeGettersAsValues); 291 }, 292 293 getInternalProperties: function(objectId, generatePreview) 294 { 295 var parsedObjectId = this._parseObjectId(objectId); 296 var object = this._objectForId(parsedObjectId); 297 var objectGroupName = this._idToObjectGroupName[parsedObjectId.id]; 298 299 if (!this._isDefined(object)) 300 return false; 301 302 if (isSymbol(object)) 303 return false; 304 305 var descriptors = this._internalPropertyDescriptors(object); 306 if (!descriptors) 307 return []; 308 309 // Go over properties, wrap object values. 310 for (var i = 0; i < descriptors.length; ++i) { 311 var descriptor = descriptors[i]; 312 if ("value" in descriptor) 313 descriptor.value = this._wrapObject(descriptor.value, objectGroupName, false, generatePreview); 314 } 315 316 return descriptors; 317 }, 318 319 getCollectionEntries: function(objectId, objectGroupName, startIndex, numberToFetch) 320 { 321 var parsedObjectId = this._parseObjectId(objectId); 322 var object = this._objectForId(parsedObjectId); 323 var objectGroupName = objectGroupName || this._idToObjectGroupName[parsedObjectId.id]; 324 325 if (!this._isDefined(object)) 326 return; 327 328 if (typeof object !== "object") 329 return; 330 331 var entries = this._entries(object, InjectedScriptHost.subtype(object), startIndex, numberToFetch); 332 return entries.map(function(entry) { 333 entry.value = injectedScript._wrapObject(entry.value, objectGroupName, false, true); 334 if ("key" in entry) 335 entry.key = injectedScript._wrapObject(entry.key, objectGroupName, false, true); 336 return entry; 337 }); 338 }, 339 340 saveResult: function(callArgumentJSON) 341 { 342 this._savedResultIndex = 0; 343 344 try { 345 var callArgument = InjectedScriptHost.evaluate("(" + callArgumentJSON + ")"); 346 var value = this._resolveCallArgument(callArgument); 347 this._saveResult(value); 348 } catch (e) {} 349 350 return this._savedResultIndex; 351 }, 352 353 getFunctionDetails: function(functionId) 354 { 355 var parsedFunctionId = this._parseObjectId(functionId); 356 var func = this._objectForId(parsedFunctionId); 357 if (typeof func !== "function") 358 return "Cannot resolve function by id."; 359 return injectedScript.functionDetails(func); 360 }, 361 362 releaseObject: function(objectId) 363 { 364 var parsedObjectId = this._parseObjectId(objectId); 365 this._releaseObject(parsedObjectId.id); 366 }, 367 368 _releaseObject: function(id) 369 { 370 delete this._idToWrappedObject[id]; 371 delete this._idToObjectGroupName[id]; 372 }, 373 374 evaluate: function(expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, saveResult) 375 { 376 return this._evaluateAndWrap(InjectedScriptHost.evaluateWithScopeExtension, InjectedScriptHost, expression, objectGroup, false, injectCommandLineAPI, returnByValue, generatePreview, saveResult); 377 }, 378 379 callFunctionOn: function(objectId, expression, args, returnByValue, generatePreview) 380 { 381 var parsedObjectId = this._parseObjectId(objectId); 382 var object = this._objectForId(parsedObjectId); 383 if (!this._isDefined(object)) 123 let objectGroupName = this._idToObjectGroupName[parsedObjectId.id]; 124 125 if (!isDefined(object)) 384 126 return "Could not find object with given id"; 385 127 128 let resolvedArgs = []; 386 129 if (args) { 387 var resolvedArgs = []; 388 var callArgs = InjectedScriptHost.evaluate(args); 389 for (var i = 0; i < callArgs.length; ++i) { 130 let callArgs = InjectedScriptHost.evaluate(args); 131 for (let i = 0; i < callArgs.length; ++i) { 390 132 try { 391 133 resolvedArgs[i] = this._resolveCallArgument(callArgs[i]); … … 397 139 398 140 try { 399 var objectGroup = this._idToObjectGroupName[parsedObjectId.id]; 400 var func = InjectedScriptHost.evaluate("(" + expression + ")"); 141 let func = InjectedScriptHost.evaluate("(" + expression + ")"); 401 142 if (typeof func !== "function") 402 143 return "Given expression does not evaluate to a function"; … … 404 145 return { 405 146 wasThrown: false, 406 result: this._wrapObject(func.apply(object, resolvedArgs), objectGroup, returnByValue, generatePreview)147 result: RemoteObject.create(func.apply(object, resolvedArgs), objectGroupName, returnByValue, generatePreview) 407 148 }; 408 149 } catch (e) { 409 return this._createThrownValue(e, objectGroup); 410 } 411 }, 412 413 _resolveCallArgument: function(callArgumentJSON) 150 return this._createThrownValue(e, objectGroupName); 151 } 152 } 153 154 getFunctionDetails(objectId) 155 { 156 let parsedObjectId = this._parseObjectId(objectId); 157 let object = this._objectForId(parsedObjectId); 158 if (typeof object !== "function") 159 return "Cannot resolve function by id."; 160 return this.functionDetails(object); 161 } 162 163 functionDetails(func) 164 { 165 let details = InjectedScriptHost.functionDetails(func); 166 if (!details) 167 return "Cannot resolve function details."; 168 return details; 169 } 170 171 getPreview(objectId) 172 { 173 let parsedObjectId = this._parseObjectId(objectId); 174 let object = this._objectForId(parsedObjectId); 175 return RemoteObject.createObjectPreviewForValue(object, true); 176 } 177 178 getProperties(objectId, ownProperties, generatePreview) 179 { 180 let nativeGettersAsValues = false; 181 let collectionMode = ownProperties ? InjectedScript.CollectionMode.OwnProperties : InjectedScript.CollectionMode.AllProperties; 182 return this._getProperties(objectId, collectionMode, generatePreview, nativeGettersAsValues); 183 } 184 185 getDisplayableProperties(objectId, generatePreview) 186 { 187 let nativeGettersAsValues = true; 188 let collectionMode = InjectedScript.CollectionMode.OwnProperties | InjectedScript.CollectionMode.NativeGetterProperties; 189 return this._getProperties(objectId, collectionMode, generatePreview, nativeGettersAsValues); 190 } 191 192 getInternalProperties(objectId, generatePreview) 193 { 194 let parsedObjectId = this._parseObjectId(objectId); 195 let object = this._objectForId(parsedObjectId); 196 let objectGroupName = this._idToObjectGroupName[parsedObjectId.id]; 197 198 if (!isDefined(object)) 199 return false; 200 201 if (isSymbol(object)) 202 return false; 203 204 let descriptors = this._internalPropertyDescriptors(object); 205 if (!descriptors) 206 return []; 207 208 for (let i = 0; i < descriptors.length; ++i) { 209 let descriptor = descriptors[i]; 210 if ("value" in descriptor) 211 descriptor.value = RemoteObject.create(descriptor.value, objectGroupName, false, generatePreview); 212 } 213 214 return descriptors; 215 } 216 217 getCollectionEntries(objectId, objectGroupName, startIndex, numberToFetch) 218 { 219 let parsedObjectId = this._parseObjectId(objectId); 220 let object = this._objectForId(parsedObjectId); 221 objectGroupName = objectGroupName || this._idToObjectGroupName[parsedObjectId.id]; 222 223 if (!isDefined(object)) 224 return; 225 226 if (typeof object !== "object") 227 return; 228 229 let entries = this._entries(object, InjectedScriptHost.subtype(object), startIndex, numberToFetch); 230 return entries.map(function(entry) { 231 entry.value = RemoteObject.create(entry.value, objectGroupName, false, true); 232 if ("key" in entry) 233 entry.key = RemoteObject.create(entry.key, objectGroupName, false, true); 234 return entry; 235 }); 236 } 237 238 saveResult(callArgumentJSON) 239 { 240 this._savedResultIndex = 0; 241 242 try { 243 let callArgument = InjectedScriptHost.evaluate("(" + callArgumentJSON + ")"); 244 let value = this._resolveCallArgument(callArgument); 245 this._saveResult(value); 246 } catch (e) {} 247 248 return this._savedResultIndex; 249 } 250 251 wrapCallFrames(callFrame) 252 { 253 if (!callFrame) 254 return false; 255 256 let result = []; 257 let depth = 0; 258 do { 259 result.push(new InjectedScript.CallFrameProxy(depth++, callFrame)); 260 callFrame = callFrame.caller; 261 } while (callFrame); 262 return result; 263 } 264 265 wrapObject(object, groupName, canAccessInspectedGlobalObject, generatePreview) 266 { 267 if (!canAccessInspectedGlobalObject) 268 return this._fallbackWrapper(object); 269 270 return RemoteObject.create(object, groupName, false, generatePreview); 271 } 272 273 wrapTable(canAccessInspectedGlobalObject, table, columns) 274 { 275 if (!canAccessInspectedGlobalObject) 276 return this._fallbackWrapper(table); 277 278 // FIXME: Currently columns are ignored. Instead, the frontend filters all 279 // properties based on the provided column names and in the provided order. 280 // We could filter here to avoid sending very large preview objects. 281 282 let columnNames = null; 283 if (typeof columns === "string") 284 columns = [columns]; 285 286 if (InjectedScriptHost.subtype(columns) === "array") { 287 columnNames = []; 288 for (let i = 0; i < columns.length; ++i) 289 columnNames.push(toString(columns[i])); 290 } 291 292 return RemoteObject.create(table, "console", false, true, columnNames); 293 } 294 295 previewValue(value) 296 { 297 return RemoteObject.createObjectPreviewForValue(value, true); 298 } 299 300 setExceptionValue(value) 301 { 302 this._exceptionValue = value; 303 } 304 305 clearExceptionValue() 306 { 307 delete this._exceptionValue; 308 } 309 310 findObjectById(objectId) 311 { 312 let parsedObjectId = this._parseObjectId(objectId); 313 return this._objectForId(parsedObjectId); 314 } 315 316 inspectObject(object) 317 { 318 if (this._commandLineAPIImpl) 319 this._commandLineAPIImpl.inspect(object); 320 } 321 322 releaseObject(objectId) 323 { 324 let parsedObjectId = this._parseObjectId(objectId); 325 this._releaseObject(parsedObjectId.id); 326 } 327 328 releaseObjectGroup(objectGroupName) 329 { 330 if (objectGroupName === "console") { 331 delete this._lastResult; 332 this._nextSavedResultIndex = 1; 333 this._savedResults = []; 334 } 335 336 let group = this._objectGroups[objectGroupName]; 337 if (!group) 338 return; 339 340 for (let i = 0; i < group.length; i++) 341 this._releaseObject(group[i]); 342 343 delete this._objectGroups[objectGroupName]; 344 } 345 346 // InjectedScriptModule C++ API 347 348 module(name) 349 { 350 return this._modules[name]; 351 } 352 353 injectModule(name, source, host) 354 { 355 delete this._modules[name]; 356 357 let moduleFunction = InjectedScriptHost.evaluate("(" + source + ")"); 358 if (typeof moduleFunction !== "function") { 359 if (inspectedGlobalObject.console) 360 inspectedGlobalObject.console.error("Web Inspector error: A function was expected for module %s evaluation", name); 361 return null; 362 } 363 364 let module = moduleFunction.call(inspectedGlobalObject, InjectedScriptHost, inspectedGlobalObject, injectedScriptId, this, RemoteObject, host); 365 this._modules[name] = module; 366 return module; 367 } 368 369 // InjectedScriptModule JavaScript API 370 371 isPrimitiveValue(value) 372 { 373 return isPrimitiveValue(value); 374 } 375 376 // Private 377 378 _parseObjectId(objectId) 379 { 380 return InjectedScriptHost.evaluate("(" + objectId + ")"); 381 } 382 383 _objectForId(objectId) 384 { 385 return this._idToWrappedObject[objectId.id]; 386 } 387 388 _bind(object, objectGroupName) 389 { 390 let id = this._lastBoundObjectId++; 391 let objectId = `{"injectedScriptId":${injectedScriptId},"id":${id}}`; 392 393 this._idToWrappedObject[id] = object; 394 395 if (objectGroupName) { 396 let group = this._objectGroups[objectGroupName]; 397 if (!group) { 398 group = []; 399 this._objectGroups[objectGroupName] = group; 400 } 401 group.push(id); 402 this._idToObjectGroupName[id] = objectGroupName; 403 } 404 405 return objectId; 406 } 407 408 _releaseObject(id) 409 { 410 delete this._idToWrappedObject[id]; 411 delete this._idToObjectGroupName[id]; 412 } 413 414 _fallbackWrapper(object) 415 { 416 let result = {}; 417 result.type = typeof object; 418 if (isPrimitiveValue(object)) 419 result.value = object; 420 else 421 result.description = toString(object); 422 return result; 423 } 424 425 _resolveCallArgument(callArgumentJSON) 414 426 { 415 427 if ("value" in callArgumentJSON) 416 428 return callArgumentJSON.value; 417 429 418 varobjectId = callArgumentJSON.objectId;430 let objectId = callArgumentJSON.objectId; 419 431 if (objectId) { 420 varparsedArgId = this._parseObjectId(objectId);432 let parsedArgId = this._parseObjectId(objectId); 421 433 if (!parsedArgId || parsedArgId["injectedScriptId"] !== injectedScriptId) 422 434 throw "Arguments should belong to the same JavaScript world as the target object."; 423 435 424 varresolvedArg = this._objectForId(parsedArgId);425 if (! this._isDefined(resolvedArg))436 let resolvedArg = this._objectForId(parsedArgId); 437 if (!isDefined(resolvedArg)) 426 438 throw "Could not find object with given id"; 427 439 … … 430 442 431 443 return undefined; 432 }, 433 434 _evaluateAndWrap: function(evalFunction, object, expression, objectGroup, isEvalOnCallFrame, injectCommandLineAPI, returnByValue, generatePreview, saveResult) 435 { 436 try { 437 this._savedResultIndex = 0; 438 439 var returnObject = { 440 wasThrown: false, 441 result: this._wrapObject(this._evaluateOn(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI, saveResult), objectGroup, returnByValue, generatePreview) 442 }; 443 444 if (saveResult && this._savedResultIndex) 445 returnObject.savedResultIndex = this._savedResultIndex; 446 447 return returnObject; 448 } catch (e) { 449 return this._createThrownValue(e, objectGroup); 450 } 451 }, 452 453 _createThrownValue: function(value, objectGroup) 454 { 455 var remoteObject = this._wrapObject(value, objectGroup); 444 } 445 446 _createThrownValue(value, objectGroup) 447 { 448 let remoteObject = RemoteObject.create(value, objectGroup); 456 449 try { 457 450 remoteObject.description = toStringDescription(value); … … 461 454 result: remoteObject 462 455 }; 463 }, 464 465 _evaluateOn: function(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI, saveResult) 466 { 467 var commandLineAPI = null; 456 } 457 458 _evaluateAndWrap(evalFunction, object, expression, objectGroup, isEvalOnCallFrame, injectCommandLineAPI, returnByValue, generatePreview, saveResult) 459 { 460 try { 461 this._savedResultIndex = 0; 462 463 let returnObject = { 464 wasThrown: false, 465 result: RemoteObject.create(this._evaluateOn(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI, saveResult), objectGroup, returnByValue, generatePreview) 466 }; 467 468 if (saveResult && this._savedResultIndex) 469 returnObject.savedResultIndex = this._savedResultIndex; 470 471 return returnObject; 472 } catch (e) { 473 return this._createThrownValue(e, objectGroup); 474 } 475 } 476 477 _evaluateOn(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI, saveResult) 478 { 479 let commandLineAPI = null; 468 480 if (injectCommandLineAPI) { 469 481 if (this.CommandLineAPI) … … 473 485 } 474 486 475 varresult = evalFunction.call(object, expression, commandLineAPI);487 let result = evalFunction.call(object, expression, commandLineAPI); 476 488 if (saveResult) 477 489 this._saveResult(result); 478 490 return result; 479 }, 480 481 wrapCallFrames: function(callFrame) 482 { 483 if (!callFrame) 484 return false; 485 486 var result = []; 487 var depth = 0; 488 do { 489 result.push(new InjectedScript.CallFrameProxy(depth++, callFrame)); 490 callFrame = callFrame.caller; 491 } while (callFrame); 492 return result; 493 }, 494 495 evaluateOnCallFrame: function(topCallFrame, callFrameId, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, saveResult) 496 { 497 var callFrame = this._callFrameForId(topCallFrame, callFrameId); 498 if (!callFrame) 499 return "Could not find call frame with given id"; 500 return this._evaluateAndWrap(callFrame.evaluateWithScopeExtension, callFrame, expression, objectGroup, true, injectCommandLineAPI, returnByValue, generatePreview, saveResult); 501 }, 502 503 _callFrameForId: function(topCallFrame, callFrameId) 504 { 505 var parsedCallFrameId = InjectedScriptHost.evaluate("(" + callFrameId + ")"); 506 var ordinal = parsedCallFrameId["ordinal"]; 507 var callFrame = topCallFrame; 491 } 492 493 _callFrameForId(topCallFrame, callFrameId) 494 { 495 let parsedCallFrameId = InjectedScriptHost.evaluate("(" + callFrameId + ")"); 496 let ordinal = parsedCallFrameId["ordinal"]; 497 let callFrame = topCallFrame; 508 498 while (--ordinal >= 0 && callFrame) 509 499 callFrame = callFrame.caller; 510 500 return callFrame; 511 }, 512 513 _objectForId: function(objectId) 514 { 515 return this._idToWrappedObject[objectId.id]; 516 }, 517 518 findObjectById: function(objectId) 519 { 520 var parsedObjectId = this._parseObjectId(objectId); 521 return this._objectForId(parsedObjectId); 522 }, 523 524 module: function(name) 525 { 526 return this._modules[name]; 527 }, 528 529 injectModule: function(name, source, host) 530 { 531 delete this._modules[name]; 532 533 var moduleFunction = InjectedScriptHost.evaluate("(" + source + ")"); 534 if (typeof moduleFunction !== "function") { 535 if (inspectedGlobalObject.console) 536 inspectedGlobalObject.console.error("Web Inspector error: A function was expected for module %s evaluation", name); 537 return null; 538 } 539 540 var module = moduleFunction.call(inspectedGlobalObject, InjectedScriptHost, inspectedGlobalObject, injectedScriptId, this, host); 541 this._modules[name] = module; 542 return module; 543 }, 544 545 _internalPropertyDescriptors: function(object, completeDescriptor) 546 { 547 var internalProperties = InjectedScriptHost.getInternalProperties(object); 501 } 502 503 _getProperties(objectId, collectionMode, generatePreview, nativeGettersAsValues) 504 { 505 let parsedObjectId = this._parseObjectId(objectId); 506 let object = this._objectForId(parsedObjectId); 507 let objectGroupName = this._idToObjectGroupName[parsedObjectId.id]; 508 509 if (!isDefined(object)) 510 return false; 511 512 if (isSymbol(object)) 513 return false; 514 515 let descriptors = this._propertyDescriptors(object, collectionMode, nativeGettersAsValues); 516 517 for (let i = 0; i < descriptors.length; ++i) { 518 let descriptor = descriptors[i]; 519 if ("get" in descriptor) 520 descriptor.get = RemoteObject.create(descriptor.get, objectGroupName); 521 if ("set" in descriptor) 522 descriptor.set = RemoteObject.create(descriptor.set, objectGroupName); 523 if ("value" in descriptor) 524 descriptor.value = RemoteObject.create(descriptor.value, objectGroupName, false, generatePreview); 525 if (!("configurable" in descriptor)) 526 descriptor.configurable = false; 527 if (!("enumerable" in descriptor)) 528 descriptor.enumerable = false; 529 if ("symbol" in descriptor) 530 descriptor.symbol = RemoteObject.create(descriptor.symbol, objectGroupName); 531 } 532 533 return descriptors; 534 } 535 536 _internalPropertyDescriptors(object, completeDescriptor) 537 { 538 let internalProperties = InjectedScriptHost.getInternalProperties(object); 548 539 if (!internalProperties) 549 540 return null; 550 541 551 vardescriptors = [];552 for ( vari = 0; i < internalProperties.length; i++) {553 varproperty = internalProperties[i];554 vardescriptor = {name: property.name, value: property.value};542 let descriptors = []; 543 for (let i = 0; i < internalProperties.length; i++) { 544 let property = internalProperties[i]; 545 let descriptor = {name: property.name, value: property.value}; 555 546 if (completeDescriptor) { 556 547 descriptor.writable = false; … … 562 553 } 563 554 return descriptors; 564 } ,565 566 _propertyDescriptors : function(object, collectionMode, nativeGettersAsValues)555 } 556 557 _propertyDescriptors(object, collectionMode, nativeGettersAsValues) 567 558 { 568 559 if (InjectedScriptHost.subtype(object) === "proxy") 569 560 return []; 570 561 571 vardescriptors = [];572 varnameProcessed = new Set;562 let descriptors = []; 563 let nameProcessed = new Set; 573 564 574 565 function createFakeValueDescriptor(name, symbol, descriptor, isOwnProperty, possibleNativeBindingGetter) 575 566 { 576 567 try { 577 var descriptor = {name, value: object[name], writable: descriptor.writable || false, configurable: descriptor.configurable || false, enumerable: descriptor.enumerable || false};568 let fakeDescriptor = {name, value: object[name], writable: descriptor.writable || false, configurable: descriptor.configurable || false, enumerable: descriptor.enumerable || false}; 578 569 if (possibleNativeBindingGetter) 579 descriptor.nativeGetter = true;570 fakeDescriptor.nativeGetter = true; 580 571 if (isOwnProperty) 581 descriptor.isOwn = true;572 fakeDescriptor.isOwn = true; 582 573 if (symbol) 583 descriptor.symbol = symbol;574 fakeDescriptor.symbol = symbol; 584 575 // Silence any possible unhandledrejection exceptions created from accessing a native accessor with a wrong this object. 585 if ( descriptor.value instanceof Promise)586 descriptor.value.catch(function(){});587 return descriptor;576 if (fakeDescriptor.value instanceof Promise) 577 fakeDescriptor.value.catch(function(){}); 578 return fakeDescriptor; 588 579 } catch (e) { 589 varerrorDescriptor = {name, value: e, wasThrown: true};580 let errorDescriptor = {name, value: e, wasThrown: true}; 590 581 if (isOwnProperty) 591 582 errorDescriptor.isOwn = true; … … 621 612 function processProperties(o, properties, isOwnProperty) 622 613 { 623 for ( vari = 0; i < properties.length; ++i) {624 varproperty = properties[i];614 for (let i = 0; i < properties.length; ++i) { 615 let property = properties[i]; 625 616 if (nameProcessed.has(property) || property === "__proto__") 626 617 continue; … … 628 619 nameProcessed.add(property); 629 620 630 varname = toString(property);631 varsymbol = isSymbol(property) ? property : null;632 633 vardescriptor = Object.getOwnPropertyDescriptor(o, property);621 let name = toString(property); 622 let symbol = isSymbol(property) ? property : null; 623 624 let descriptor = Object.getOwnPropertyDescriptor(o, property); 634 625 if (!descriptor) { 635 626 // FIXME: Bad descriptor. Can we get here? 636 627 // Fall back to very restrictive settings. 637 varfakeDescriptor = createFakeValueDescriptor(name, symbol, {writable: false, configurable: false, enumerable: false}, isOwnProperty);628 let fakeDescriptor = createFakeValueDescriptor(name, symbol, {writable: false, configurable: false, enumerable: false}, isOwnProperty); 638 629 processDescriptor(fakeDescriptor, isOwnProperty); 639 630 continue; … … 643 634 if (String(descriptor.get).endsWith("[native code]\n}") || (!descriptor.get && descriptor.hasOwnProperty("get") && !descriptor.set && descriptor.hasOwnProperty("set"))) { 644 635 // Developers may create such a descriptor, so we should be resilient: 645 // varx = {}; Object.defineProperty(x, "p", {get:undefined}); Object.getOwnPropertyDescriptor(x, "p")646 varfakeDescriptor = createFakeValueDescriptor(name, symbol, descriptor, isOwnProperty, true);636 // let x = {}; Object.defineProperty(x, "p", {get:undefined}); Object.getOwnPropertyDescriptor(x, "p") 637 let fakeDescriptor = createFakeValueDescriptor(name, symbol, descriptor, isOwnProperty, true); 647 638 processDescriptor(fakeDescriptor, isOwnProperty, true); 648 639 continue; … … 661 652 function arrayIndexPropertyNames(o, length) 662 653 { 663 vararray = [];664 for ( vari = 0; i < length; ++i) {654 let array = []; 655 for (let i = 0; i < length; ++i) { 665 656 if (i in o) 666 657 array.push("" + i); … … 671 662 // FIXME: <https://webkit.org/b/143589> Web Inspector: Better handling for large collections in Object Trees 672 663 // For array types with a large length we attempt to skip getOwnPropertyNames and instead just sublist of indexes. 673 varisArrayLike = false;664 let isArrayLike = false; 674 665 try { 675 isArrayLike = injectedScript._subtype(object) === "array" && isFinite(object.length) && object.length > 0;666 isArrayLike = RemoteObject.subtype(object) === "array" && isFinite(object.length) && object.length > 0; 676 667 } catch(e) {} 677 668 678 for ( var o = object; this._isDefined(o); o = Object.getPrototypeOf(o)) {679 varisOwnProperty = o === object;669 for (let o = object; isDefined(o); o = Object.getPrototypeOf(o)) { 670 let isOwnProperty = o === object; 680 671 681 672 if (isArrayLike && isOwnProperty) … … 698 689 699 690 return descriptors; 700 }, 701 702 _isDefined: function(object) 703 { 704 return !!object || this._isHTMLAllCollection(object); 705 }, 706 707 _isHTMLAllCollection: function(object) 708 { 709 // document.all is reported as undefined, but we still want to process it. 710 return (typeof object === "undefined") && InjectedScriptHost.isHTMLAllCollection(object); 711 }, 712 713 _subtype: function(obj) 714 { 715 if (obj === null) 716 return "null"; 717 718 if (this.isPrimitiveValue(obj) || isSymbol(obj)) 719 return null; 720 721 if (this._isHTMLAllCollection(obj)) 722 return "array"; 723 724 var preciseType = InjectedScriptHost.subtype(obj); 725 if (preciseType) 726 return preciseType; 727 728 // FireBug's array detection. 729 try { 730 if (typeof obj.splice === "function" && isFinite(obj.length)) 731 return "array"; 732 } catch (e) {} 733 734 return null; 735 }, 736 737 _classPreview: function(classConstructorValue) 738 { 739 return "class " + classConstructorValue.name; 740 }, 741 742 _nodePreview: function(node) 743 { 744 var isXMLDocument = node.ownerDocument && !!node.ownerDocument.xmlVersion; 745 var nodeName = isXMLDocument ? node.nodeName : node.nodeName.toLowerCase(); 746 747 switch (node.nodeType) { 748 case 1: // Node.ELEMENT_NODE 749 if (node.id) 750 return "<" + nodeName + " id=\"" + node.id + "\">"; 751 if (node.classList.length) 752 return "<" + nodeName + " class=\"" + node.classList.toString().replace(/\s+/, " ") + "\">"; 753 if (nodeName === "input" && node.type) 754 return "<" + nodeName + " type=\"" + node.type + "\">"; 755 return "<" + nodeName + ">"; 756 757 case 3: // Node.TEXT_NODE 758 return nodeName + " \"" + node.nodeValue + "\""; 759 760 case 8: // Node.COMMENT_NODE 761 return "<!--" + node.nodeValue + "-->"; 762 763 case 10: // Node.DOCUMENT_TYPE_NODE 764 return "<!DOCTYPE " + nodeName + ">"; 765 766 default: 767 return nodeName; 768 } 769 }, 770 771 _describe: function(obj) 772 { 773 if (this.isPrimitiveValue(obj)) 774 return null; 775 776 if (isSymbol(obj)) 777 return toString(obj); 778 779 var subtype = this._subtype(obj); 780 781 if (subtype === "regexp") 782 return toString(obj); 783 784 if (subtype === "date") 785 return toString(obj); 786 787 if (subtype === "error") 788 return toString(obj); 789 790 if (subtype === "proxy") 791 return "Proxy"; 792 793 if (subtype === "node") 794 return this._nodePreview(obj); 795 796 var className = InjectedScriptHost.internalConstructorName(obj); 797 if (subtype === "array") 798 return className; 799 800 if (subtype === "iterator" && Symbol.toStringTag in obj) 801 return obj[Symbol.toStringTag]; 802 803 // NodeList in JSC is a function, check for array prior to this. 804 if (typeof obj === "function") 805 return obj.toString(); 806 807 // If Object, try for a better name from the constructor. 808 if (className === "Object") { 809 var constructorName = obj.constructor && obj.constructor.name; 810 if (constructorName) 811 return constructorName; 812 } 813 814 return className; 815 }, 816 817 _getSetEntries: function(object, skip, numberToFetch) 818 { 819 var entries = []; 820 821 for (var value of object) { 691 } 692 693 _getSetEntries(object, skip, numberToFetch) 694 { 695 let entries = []; 696 697 // FIXME: This is observable if the page overrides Set.prototype[Symbol.iterator]. 698 for (let value of object) { 822 699 if (skip > 0) { 823 700 skip--; … … 832 709 833 710 return entries; 834 }, 835 836 _getMapEntries: function(object, skip, numberToFetch) 837 { 838 var entries = []; 839 840 for (var [key, value] of object) { 711 } 712 713 _getMapEntries(object, skip, numberToFetch) 714 { 715 let entries = []; 716 717 // FIXME: This is observable if the page overrides Map.prototype[Symbol.iterator]. 718 for (let [key, value] of object) { 841 719 if (skip > 0) { 842 720 skip--; … … 851 729 852 730 return entries; 853 } ,854 855 _getWeakMapEntries : function(object, numberToFetch)731 } 732 733 _getWeakMapEntries(object, numberToFetch) 856 734 { 857 735 return InjectedScriptHost.weakMapEntries(object, numberToFetch); 858 } ,859 860 _getWeakSetEntries : function(object, numberToFetch)736 } 737 738 _getWeakSetEntries(object, numberToFetch) 861 739 { 862 740 return InjectedScriptHost.weakSetEntries(object, numberToFetch); 863 } ,864 865 _getIteratorEntries : function(object, numberToFetch)741 } 742 743 _getIteratorEntries(object, numberToFetch) 866 744 { 867 745 return InjectedScriptHost.iteratorEntries(object, numberToFetch); 868 } ,869 870 _entries : function(object, subtype, startIndex, numberToFetch)746 } 747 748 _entries(object, subtype, startIndex, numberToFetch) 871 749 { 872 750 if (subtype === "set") … … 882 760 883 761 throw "unexpected type"; 884 } ,885 886 _saveResult : function(result)762 } 763 764 _saveResult(result) 887 765 { 888 766 this._lastResult = result; … … 891 769 return; 892 770 893 varexistingIndex = this._savedResults.indexOf(result);771 let existingIndex = this._savedResults.indexOf(result); 894 772 if (existingIndex !== -1) { 895 773 this._savedResultIndex = existingIndex; … … 903 781 if (this._nextSavedResultIndex >= 100) 904 782 this._nextSavedResultIndex = 1; 905 } ,906 907 _savedResult : function(index)783 } 784 785 _savedResult(index) 908 786 { 909 787 return this._savedResults[index]; … … 911 789 } 912 790 791 InjectedScript.CollectionMode = { 792 OwnProperties: 1 << 0, // own properties. 793 NativeGetterProperties: 1 << 1, // native getter properties in the prototype chain. 794 AllProperties: 1 << 2, // all properties in the prototype chain. 795 }; 796 913 797 var injectedScript = new InjectedScript; 914 798 915 916 InjectedScript.RemoteObject = function(object, objectGroupName, forceValueType, generatePreview, columnNames) 799 // ------- 800 801 let RemoteObject = class RemoteObject 917 802 { 918 this.type = typeof object; 919 920 if (this.type === "undefined" && injectedScript._isHTMLAllCollection(object)) 921 this.type = "object"; 922 923 if (injectedScript.isPrimitiveValue(object) || object === null || forceValueType) { 924 // We don't send undefined values over JSON. 925 if (this.type !== "undefined") 926 this.value = object; 927 928 // Null object is object with 'null' subtype. 929 if (object === null) 930 this.subtype = "null"; 931 932 // Provide user-friendly number values. 933 if (this.type === "number") 934 this.description = toStringDescription(object); 935 return; 936 } 937 938 this.objectId = injectedScript._bind(object, objectGroupName); 939 940 var subtype = injectedScript._subtype(object); 941 if (subtype) 942 this.subtype = subtype; 943 944 this.className = InjectedScriptHost.internalConstructorName(object); 945 this.description = injectedScript._describe(object); 946 947 if (subtype === "array") 948 this.size = typeof object.length === "number" ? object.length : 0; 949 else if (subtype === "set" || subtype === "map") 950 this.size = object.size; 951 else if (subtype === "weakmap") 952 this.size = InjectedScriptHost.weakMapSize(object); 953 else if (subtype === "weakset") 954 this.size = InjectedScriptHost.weakSetSize(object); 955 else if (subtype === "class") { 956 this.classPrototype = injectedScript._wrapObject(object.prototype, objectGroupName); 957 this.className = object.name; 958 } 959 960 if (generatePreview && this.type === "object") { 961 if (subtype === "proxy") { 962 this.preview = this._generatePreview(InjectedScriptHost.proxyTargetValue(object)); 963 this.preview.lossless = false; 964 } else 965 this.preview = this._generatePreview(object, undefined, columnNames); 966 } 967 }; 968 969 InjectedScript.RemoteObject.createObjectPreviewForValue = function(value, generatePreview, columnNames) 970 { 971 var remoteObject = new InjectedScript.RemoteObject(value, undefined, false, generatePreview, columnNames); 972 if (remoteObject.objectId) 973 injectedScript.releaseObject(remoteObject.objectId); 974 if (remoteObject.classPrototype && remoteObject.classPrototype.objectId) 975 injectedScript.releaseObject(remoteObject.classPrototype.objectId); 976 return remoteObject.preview || remoteObject._emptyPreview(); 977 }; 978 979 InjectedScript.RemoteObject.prototype = { 980 _initialPreview: function() 981 { 982 var preview = { 803 constructor(object, objectGroupName, forceValueType, generatePreview, columnNames) 804 { 805 this.type = typeof object; 806 807 if (this.type === "undefined" && InjectedScriptHost.isHTMLAllCollection(object)) 808 this.type = "object"; 809 810 if (isPrimitiveValue(object) || object === null || forceValueType) { 811 // We don't send undefined values over JSON. 812 if (this.type !== "undefined") 813 this.value = object; 814 815 // Null object is object with 'null' subtype. 816 if (object === null) 817 this.subtype = "null"; 818 819 // Provide user-friendly number values. 820 if (this.type === "number") 821 this.description = toStringDescription(object); 822 return; 823 } 824 825 this.objectId = injectedScript._bind(object, objectGroupName); 826 827 let subtype = RemoteObject.subtype(object); 828 if (subtype) 829 this.subtype = subtype; 830 831 this.className = InjectedScriptHost.internalConstructorName(object); 832 this.description = RemoteObject.describe(object); 833 834 if (subtype === "array") 835 this.size = typeof object.length === "number" ? object.length : 0; 836 else if (subtype === "set" || subtype === "map") 837 this.size = object.size; 838 else if (subtype === "weakmap") 839 this.size = InjectedScriptHost.weakMapSize(object); 840 else if (subtype === "weakset") 841 this.size = InjectedScriptHost.weakSetSize(object); 842 else if (subtype === "class") { 843 this.classPrototype = RemoteObject.create(object.prototype, objectGroupName); 844 this.className = object.name; 845 } 846 847 if (generatePreview && this.type === "object") { 848 if (subtype === "proxy") { 849 this.preview = this._generatePreview(InjectedScriptHost.proxyTargetValue(object)); 850 this.preview.lossless = false; 851 } else 852 this.preview = this._generatePreview(object, undefined, columnNames); 853 } 854 } 855 856 // Static 857 858 static create(object, objectGroupName, forceValueType, generatePreview, columnNames) 859 { 860 try { 861 return new RemoteObject(object, objectGroupName, forceValueType, generatePreview, columnNames); 862 } catch (e) { 863 let description; 864 try { 865 description = RemoteObject.describe(e); 866 } catch (ex) { 867 alert(ex.message); 868 description = "<failed to convert exception to string>"; 869 } 870 return new RemoteObject(description); 871 } 872 } 873 874 static createObjectPreviewForValue(value, generatePreview, columnNames) 875 { 876 let remoteObject = new RemoteObject(value, undefined, false, generatePreview, columnNames); 877 if (remoteObject.objectId) 878 injectedScript.releaseObject(remoteObject.objectId); 879 if (remoteObject.classPrototype && remoteObject.classPrototype.objectId) 880 injectedScript.releaseObject(remoteObject.classPrototype.objectId); 881 return remoteObject.preview || remoteObject._emptyPreview(); 882 } 883 884 static subtype(value) 885 { 886 if (value === null) 887 return "null"; 888 889 if (isPrimitiveValue(value) || isSymbol(value)) 890 return null; 891 892 if (InjectedScriptHost.isHTMLAllCollection(value)) 893 return "array"; 894 895 let preciseType = InjectedScriptHost.subtype(value); 896 if (preciseType) 897 return preciseType; 898 899 // FireBug's array detection. 900 try { 901 if (typeof value.splice === "function" && isFinite(value.length)) 902 return "array"; 903 } catch (e) {} 904 905 return null; 906 } 907 908 static describe(value) 909 { 910 if (isPrimitiveValue(value)) 911 return null; 912 913 if (isSymbol(value)) 914 return toString(value); 915 916 let subtype = RemoteObject.subtype(value); 917 918 if (subtype === "regexp") 919 return toString(value); 920 921 if (subtype === "date") 922 return toString(value); 923 924 if (subtype === "error") 925 return toString(value); 926 927 if (subtype === "proxy") 928 return "Proxy"; 929 930 if (subtype === "node") 931 return RemoteObject.nodePreview(value); 932 933 let className = InjectedScriptHost.internalConstructorName(value); 934 if (subtype === "array") 935 return className; 936 937 if (subtype === "iterator" && Symbol.toStringTag in value) 938 return value[Symbol.toStringTag]; 939 940 // NodeList in JSC is a function, check for array prior to this. 941 if (typeof value === "function") 942 return value.toString(); 943 944 // If Object, try for a better name from the constructor. 945 if (className === "Object") { 946 let constructorName = value.constructor && value.constructor.name; 947 if (constructorName) 948 return constructorName; 949 } 950 951 return className; 952 } 953 954 static nodePreview(node) 955 { 956 let isXMLDocument = node.ownerDocument && !!node.ownerDocument.xmlVersion; 957 let nodeName = isXMLDocument ? node.nodeName : node.nodeName.toLowerCase(); 958 959 switch (node.nodeType) { 960 case 1: // Node.ELEMENT_NODE 961 if (node.id) 962 return "<" + nodeName + " id=\"" + node.id + "\">"; 963 if (node.classList.length) 964 return "<" + nodeName + " class=\"" + node.classList.toString().replace(/\s+/, " ") + "\">"; 965 if (nodeName === "input" && node.type) 966 return "<" + nodeName + " type=\"" + node.type + "\">"; 967 return "<" + nodeName + ">"; 968 969 case 3: // Node.TEXT_NODE 970 return nodeName + " \"" + node.nodeValue + "\""; 971 972 case 8: // Node.COMMENT_NODE 973 return "<!--" + node.nodeValue + "-->"; 974 975 case 10: // Node.DOCUMENT_TYPE_NODE 976 return "<!DOCTYPE " + nodeName + ">"; 977 978 default: 979 return nodeName; 980 } 981 } 982 983 // Private 984 985 _initialPreview() 986 { 987 let preview = { 983 988 type: this.type, 984 989 description: this.description || toString(this.value), … … 998 1003 999 1004 return preview; 1000 } ,1001 1002 _emptyPreview : function()1003 { 1004 varpreview = this._initialPreview();1005 } 1006 1007 _emptyPreview() 1008 { 1009 let preview = this._initialPreview(); 1005 1010 1006 1011 if (this.subtype === "map" || this.subtype === "set" || this.subtype === "weakmap" || this.subtype === "weakset" || this.subtype === "iterator") { … … 1013 1018 1014 1019 return preview; 1015 } ,1016 1017 _generatePreview : function(object, firstLevelKeys, secondLevelKeys)1018 { 1019 varpreview = this._initialPreview();1020 varisTableRowsRequest = secondLevelKeys === null || secondLevelKeys;1021 varfirstLevelKeysCount = firstLevelKeys ? firstLevelKeys.length : 0;1022 1023 varpropertiesThreshold = {1020 } 1021 1022 _generatePreview(object, firstLevelKeys, secondLevelKeys) 1023 { 1024 let preview = this._initialPreview(); 1025 let isTableRowsRequest = secondLevelKeys === null || secondLevelKeys; 1026 let firstLevelKeysCount = firstLevelKeys ? firstLevelKeys.length : 0; 1027 1028 let propertiesThreshold = { 1024 1029 properties: isTableRowsRequest ? 1000 : Math.max(5, firstLevelKeysCount), 1025 1030 indexes: isTableRowsRequest ? 1000 : Math.max(10, firstLevelKeysCount) … … 1034 1039 1035 1040 // Internal Properties. 1036 varinternalPropertyDescriptors = injectedScript._internalPropertyDescriptors(object, true);1041 let internalPropertyDescriptors = injectedScript._internalPropertyDescriptors(object, true); 1037 1042 if (internalPropertyDescriptors) { 1038 1043 this._appendPropertyPreviews(object, preview, internalPropertyDescriptors, true, propertiesThreshold, firstLevelKeys, secondLevelKeys); … … 1045 1050 1046 1051 // Properties. 1047 varnativeGettersAsValues = true;1048 vardescriptors = injectedScript._propertyDescriptors(object, InjectedScript.CollectionMode.AllProperties, nativeGettersAsValues);1052 let nativeGettersAsValues = true; 1053 let descriptors = injectedScript._propertyDescriptors(object, InjectedScript.CollectionMode.AllProperties, nativeGettersAsValues); 1049 1054 this._appendPropertyPreviews(object, preview, descriptors, false, propertiesThreshold, firstLevelKeys, secondLevelKeys); 1050 1055 if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0) … … 1055 1060 1056 1061 return preview; 1057 } ,1058 1059 _appendPropertyPreviews : function(object, preview, descriptors, internal, propertiesThreshold, firstLevelKeys, secondLevelKeys)1062 } 1063 1064 _appendPropertyPreviews(object, preview, descriptors, internal, propertiesThreshold, firstLevelKeys, secondLevelKeys) 1060 1065 { 1061 1066 for (let i = 0; i < descriptors.length; ++i) { … … 1073 1078 1074 1079 // Do not show "__proto__" in preview. 1075 varname = descriptor.name;1080 let name = descriptor.name; 1076 1081 if (name === "__proto__") { 1077 1082 // Non basic __proto__ objects may have interesting, non-enumerable, methods to show. … … 1107 1112 1108 1113 // Null value. 1109 varvalue = descriptor.value;1114 let value = descriptor.value; 1110 1115 if (value === null) { 1111 1116 this._appendPropertyPreview(preview, internal, {name, type: "object", subtype: "null", value: "null"}, propertiesThreshold); … … 1114 1119 1115 1120 // Ignore non-enumerable functions. 1116 vartype = typeof value;1121 let type = typeof value; 1117 1122 if (!descriptor.enumerable && type === "function") 1118 1123 continue; 1119 1124 1120 1125 // Fix type of document.all. 1121 if ( type === "undefined" && injectedScript._isHTMLAllCollection(value))1126 if (InjectedScriptHost.isHTMLAllCollection(value)) 1122 1127 type = "object"; 1123 1128 1124 1129 // Primitive. 1125 1130 const maxLength = 100; 1126 if ( InjectedScript.primitiveTypes[type]) {1131 if (isPrimitiveValue(value)) { 1127 1132 if (type === "string" && value.length > maxLength) { 1128 1133 value = this._abbreviateString(value, maxLength, true); … … 1135 1140 // Symbol. 1136 1141 if (isSymbol(value)) { 1137 varsymbolString = toString(value);1142 let symbolString = toString(value); 1138 1143 if (symbolString.length > maxLength) { 1139 1144 symbolString = this._abbreviateString(symbolString, maxLength, true); … … 1145 1150 1146 1151 // Object. 1147 varproperty = {name, type};1148 var subtype = injectedScript._subtype(value);1152 let property = {name, type}; 1153 let subtype = RemoteObject.subtype(value); 1149 1154 if (subtype) 1150 1155 property.subtype = subtype; … … 1153 1158 if ((secondLevelKeys === null || secondLevelKeys) || this._isPreviewableObject(value, object)) { 1154 1159 // FIXME: If we want secondLevelKeys filter to continue we would need some refactoring. 1155 var subPreview = InjectedScript.RemoteObject.createObjectPreviewForValue(value, value !== object, secondLevelKeys);1160 let subPreview = RemoteObject.createObjectPreviewForValue(value, value !== object, secondLevelKeys); 1156 1161 property.valuePreview = subPreview; 1157 1162 if (!subPreview.lossless) … … 1160 1165 preview.overflow = true; 1161 1166 } else { 1162 vardescription = "";1167 let description = ""; 1163 1168 if (type !== "function" || subtype === "class") { 1164 varfullDescription;1169 let fullDescription; 1165 1170 if (subtype === "class") 1166 1171 fullDescription = "class " + value.name; 1167 1172 else if (subtype === "node") 1168 fullDescription = injectedScript._nodePreview(value);1173 fullDescription = RemoteObject.nodePreview(value); 1169 1174 else 1170 fullDescription = injectedScript._describe(value);1175 fullDescription = RemoteObject.describe(value); 1171 1176 description = this._abbreviateString(fullDescription, maxLength, subtype === "regexp"); 1172 1177 } … … 1177 1182 this._appendPropertyPreview(preview, internal, property, propertiesThreshold); 1178 1183 } 1179 } ,1180 1181 _appendPropertyPreview : function(preview, internal, property, propertiesThreshold)1184 } 1185 1186 _appendPropertyPreview(preview, internal, property, propertiesThreshold) 1182 1187 { 1183 1188 if (toString(property.name >>> 0) === property.name) … … 1196 1201 1197 1202 preview.properties.push(property); 1198 } ,1199 1200 _appendEntryPreviews : function(object, preview)1203 } 1204 1205 _appendEntryPreviews(object, preview) 1201 1206 { 1202 1207 // Fetch 6, but only return 5, so we can tell if we overflowed. 1203 varentries = injectedScript._entries(object, this.subtype, 0, 6);1208 let entries = injectedScript._entries(object, this.subtype, 0, 6); 1204 1209 if (!entries) 1205 1210 return; … … 1217 1222 1218 1223 preview.entries = entries.map(function(entry) { 1219 entry.value = InjectedScript.RemoteObject.createObjectPreviewForValue(entry.value, entry.value !== object);1224 entry.value = RemoteObject.createObjectPreviewForValue(entry.value, entry.value !== object); 1220 1225 updateMainPreview(entry.value); 1221 1226 if ("key" in entry) { 1222 entry.key = InjectedScript.RemoteObject.createObjectPreviewForValue(entry.key, entry.key !== object);1227 entry.key = RemoteObject.createObjectPreviewForValue(entry.key, entry.key !== object); 1223 1228 updateMainPreview(entry.key); 1224 1229 } 1225 1230 return entry; 1226 } , this);1227 } ,1228 1229 _isPreviewableObject : function(value, object)1231 }); 1232 } 1233 1234 _isPreviewableObject(value, object) 1230 1235 { 1231 1236 let set = new Set; … … 1233 1238 1234 1239 return this._isPreviewableObjectInternal(value, set, 1); 1235 } ,1236 1237 _isPreviewableObjectInternal : function(object, knownObjects, depth)1240 } 1241 1242 _isPreviewableObjectInternal(object, knownObjects, depth) 1238 1243 { 1239 1244 // Deep object. … … 1242 1247 1243 1248 // Primitive. 1244 if (i njectedScript.isPrimitiveValue(object) || isSymbol(object))1249 if (isPrimitiveValue(object) || isSymbol(object)) 1245 1250 return true; 1246 1251 … … 1257 1262 1258 1263 // Arrays are simple if they have 5 or less simple objects. 1259 var subtype = injectedScript._subtype(object);1264 let subtype = RemoteObject.subtype(object); 1260 1265 if (subtype === "array") { 1261 varlength = object.length;1266 let length = object.length; 1262 1267 if (length > 5) 1263 1268 return false; 1264 for ( vari = 0; i < length; ++i) {1269 for (let i = 0; i < length; ++i) { 1265 1270 if (!this._isPreviewableObjectInternal(object[i], knownObjects, depth)) 1266 1271 return false; … … 1284 1289 1285 1290 return true; 1286 } ,1287 1288 _abbreviateString : function(string, maxLength, middle)1291 } 1292 1293 _abbreviateString(string, maxLength, middle) 1289 1294 { 1290 1295 if (string.length <= maxLength) … … 1292 1297 1293 1298 if (middle) { 1294 varleftHalf = maxLength >> 1;1295 varrightHalf = maxLength - leftHalf - 1;1299 let leftHalf = maxLength >> 1; 1300 let rightHalf = maxLength - leftHalf - 1; 1296 1301 return string.substr(0, leftHalf) + "\u2026" + string.substr(string.length - rightHalf, rightHalf); 1297 1302 } … … 1300 1305 } 1301 1306 } 1307 1308 // ------- 1302 1309 1303 1310 InjectedScript.CallFrameProxy = function(ordinal, callFrame) 1304 1311 { 1305 this.callFrameId = "{\"ordinal\":" + ordinal + ",\"injectedScriptId\":" + injectedScriptId + "}";1312 this.callFrameId = `{"ordinal":${ordinal},"injectedScriptId":${injectedScriptId}}`; 1306 1313 this.functionName = callFrame.functionName; 1307 1314 this.location = {scriptId: String(callFrame.sourceID), lineNumber: callFrame.line, columnNumber: callFrame.column}; 1308 1315 this.scopeChain = this._wrapScopeChain(callFrame); 1309 this.this = injectedScript._wrapObject(callFrame.thisObject, "backtrace");1316 this.this = RemoteObject.create(callFrame.thisObject, "backtrace"); 1310 1317 this.isTailDeleted = callFrame.isTailDeleted; 1311 1318 } 1312 1319 1313 1320 InjectedScript.CallFrameProxy.prototype = { 1314 _wrapScopeChain : function(callFrame)1315 { 1316 varscopeChain = callFrame.scopeChain;1317 varscopeDescriptions = callFrame.scopeDescriptions();1318 1319 varscopeChainProxy = [];1320 for ( vari = 0; i < scopeChain.length; i++)1321 _wrapScopeChain(callFrame) 1322 { 1323 let scopeChain = callFrame.scopeChain; 1324 let scopeDescriptions = callFrame.scopeDescriptions(); 1325 1326 let scopeChainProxy = []; 1327 for (let i = 0; i < scopeChain.length; i++) 1321 1328 scopeChainProxy[i] = InjectedScript.CallFrameProxy._createScopeJson(scopeChain[i], scopeDescriptions[i], "backtrace"); 1322 1329 return scopeChainProxy; … … 1337 1344 { 1338 1345 let scope = { 1339 object: injectedScript._wrapObject(object, groupId),1346 object: RemoteObject.create(object, groupId), 1340 1347 type: InjectedScript.CallFrameProxy._scopeTypeNames[type], 1341 1348 }; … … 1353 1360 } 1354 1361 1362 // ------- 1355 1363 1356 1364 function bind(func, thisObject, ...outerArgs) -
trunk/Source/WebCore/ChangeLog
r219638 r219639 1 2017-07-18 Joseph Pecoraro <pecoraro@apple.com> 2 3 Web Inspector: Modernize InjectedScriptSource 4 https://bugs.webkit.org/show_bug.cgi?id=173890 5 6 Reviewed by Brian Burg. 7 8 Covered by existing tests. 9 10 * inspector/CommandLineAPIModuleSource.js: 11 (CommandLineAPIImpl.prototype.copy): 12 (CommandLineAPIImpl.prototype._inspect): 13 Use RemoteObject, a new parameter. 14 1 15 2017-07-18 Ryosuke Niwa <rniwa@webkit.org> 2 16 -
trunk/Source/WebCore/inspector/CommandLineAPIModuleSource.js
r201168 r219639 29 29 //# sourceURL=__InjectedScript_CommandLineAPIModuleSource.js 30 30 31 /** 32 * @param {InjectedScriptHost} InjectedScriptHost 33 * @param {Window} inspectedWindow 34 * @param {number} injectedScriptId 35 * @param {InjectedScript} injectedScript 36 * @param {CommandLineAPIHost} CommandLineAPIHost 37 */ 38 (function (InjectedScriptHost, inspectedWindow, injectedScriptId, injectedScript, CommandLineAPIHost) { 31 (function (InjectedScriptHost, inspectedWindow, injectedScriptId, injectedScript, RemoteObject, CommandLineAPIHost) { 39 32 40 33 // FIXME: <https://webkit.org/b/152294> Web Inspector: Parse InjectedScriptSource as a built-in to get guaranteed non-user-overriden built-ins … … 232 225 { 233 226 var string; 234 var subtype = injectedScript._subtype(object);227 var subtype = RemoteObject.subtype(object); 235 228 if (subtype === "node") 236 229 string = object.outerHTML; … … 316 309 return; 317 310 318 var objectId = injectedScript._wrapObject(object, "");311 var objectId = RemoteObject.create(object, ""); 319 312 var hints = {}; 320 313 321 switch ( injectedScript._describe(object)) {314 switch (RemoteObject.describe(object)) { 322 315 case "Database": 323 316 var databaseId = CommandLineAPIHost.databaseId(object)
Note:
See TracChangeset
for help on using the changeset viewer.