]>
git.saurik.com Git - apple/javascriptcore.git/blob - inspector/JSInjectedScriptHost.cpp
2 * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "JSInjectedScriptHost.h"
29 #include "DateInstance.h"
30 #include "DirectArguments.h"
32 #include "InjectedScriptHost.h"
33 #include "IteratorOperations.h"
35 #include "JSArrayIterator.h"
36 #include "JSBoundFunction.h"
37 #include "JSCInlines.h"
38 #include "JSFunction.h"
39 #include "JSInjectedScriptHostPrototype.h"
41 #include "JSMapIterator.h"
43 #include "JSSetIterator.h"
44 #include "JSStringIterator.h"
45 #include "JSTypedArrays.h"
46 #include "JSWeakMap.h"
47 #include "JSWeakSet.h"
48 #include "ObjectConstructor.h"
49 #include "RegExpObject.h"
50 #include "ScopedArguments.h"
51 #include "SourceCode.h"
52 #include "TypedArrayInlines.h"
53 #include "WeakMapData.h"
56 #include "JSPromise.h"
63 const ClassInfo
JSInjectedScriptHost::s_info
= { "InjectedScriptHost", &Base::s_info
, 0, CREATE_METHOD_TABLE(JSInjectedScriptHost
) };
65 JSInjectedScriptHost::JSInjectedScriptHost(VM
& vm
, Structure
* structure
, PassRefPtr
<InjectedScriptHost
> impl
)
66 : JSDestructibleObject(vm
, structure
)
67 , m_impl(impl
.leakRef())
71 void JSInjectedScriptHost::finishCreation(VM
& vm
)
73 Base::finishCreation(vm
);
74 ASSERT(inherits(info()));
77 JSObject
* JSInjectedScriptHost::createPrototype(VM
& vm
, JSGlobalObject
* globalObject
)
79 return JSInjectedScriptHostPrototype::create(vm
, globalObject
, JSInjectedScriptHostPrototype::createStructure(vm
, globalObject
, globalObject
->objectPrototype()));
82 void JSInjectedScriptHost::destroy(JSC::JSCell
* cell
)
84 JSInjectedScriptHost
* thisObject
= static_cast<JSInjectedScriptHost
*>(cell
);
85 thisObject
->JSInjectedScriptHost::~JSInjectedScriptHost();
88 void JSInjectedScriptHost::releaseImpl()
90 if (auto impl
= std::exchange(m_impl
, nullptr))
94 JSInjectedScriptHost::~JSInjectedScriptHost()
99 JSValue
JSInjectedScriptHost::evaluate(ExecState
* exec
) const
101 JSGlobalObject
* globalObject
= exec
->lexicalGlobalObject();
102 return globalObject
->evalFunction();
105 JSValue
JSInjectedScriptHost::internalConstructorName(ExecState
* exec
)
107 if (exec
->argumentCount() < 1)
108 return jsUndefined();
110 JSObject
* object
= jsCast
<JSObject
*>(exec
->uncheckedArgument(0).toThis(exec
, NotStrictMode
));
111 return jsString(exec
, JSObject::calculatedClassName(object
));
114 JSValue
JSInjectedScriptHost::isHTMLAllCollection(ExecState
* exec
)
116 if (exec
->argumentCount() < 1)
117 return jsUndefined();
119 JSValue value
= exec
->uncheckedArgument(0);
120 return jsBoolean(impl().isHTMLAllCollection(value
));
123 JSValue
JSInjectedScriptHost::subtype(ExecState
* exec
)
125 if (exec
->argumentCount() < 1)
126 return jsUndefined();
128 JSValue value
= exec
->uncheckedArgument(0);
129 if (value
.isString())
130 return exec
->vm().smallStrings
.stringString();
131 if (value
.isBoolean())
132 return exec
->vm().smallStrings
.booleanString();
133 if (value
.isNumber())
134 return exec
->vm().smallStrings
.numberString();
135 if (value
.isSymbol())
136 return exec
->vm().smallStrings
.symbolString();
138 JSObject
* object
= asObject(value
);
140 if (object
->isErrorInstance())
141 return jsNontrivialString(exec
, ASCIILiteral("error"));
143 // Consider class constructor functions class objects.
144 JSFunction
* function
= jsDynamicCast
<JSFunction
*>(value
);
145 if (function
&& function
->isClassConstructorFunction())
146 return jsNontrivialString(exec
, ASCIILiteral("class"));
149 if (value
.inherits(JSArray::info()))
150 return jsNontrivialString(exec
, ASCIILiteral("array"));
151 if (value
.inherits(DirectArguments::info()) || value
.inherits(ScopedArguments::info()))
152 return jsNontrivialString(exec
, ASCIILiteral("array"));
154 if (value
.inherits(DateInstance::info()))
155 return jsNontrivialString(exec
, ASCIILiteral("date"));
156 if (value
.inherits(RegExpObject::info()))
157 return jsNontrivialString(exec
, ASCIILiteral("regexp"));
159 if (value
.inherits(JSMap::info()))
160 return jsNontrivialString(exec
, ASCIILiteral("map"));
161 if (value
.inherits(JSSet::info()))
162 return jsNontrivialString(exec
, ASCIILiteral("set"));
163 if (value
.inherits(JSWeakMap::info()))
164 return jsNontrivialString(exec
, ASCIILiteral("weakmap"));
165 if (value
.inherits(JSWeakSet::info()))
166 return jsNontrivialString(exec
, ASCIILiteral("weakset"));
168 if (value
.inherits(JSArrayIterator::info())
169 || value
.inherits(JSMapIterator::info())
170 || value
.inherits(JSSetIterator::info())
171 || value
.inherits(JSStringIterator::info()))
172 return jsNontrivialString(exec
, ASCIILiteral("iterator"));
174 if (value
.inherits(JSInt8Array::info()) || value
.inherits(JSInt16Array::info()) || value
.inherits(JSInt32Array::info()))
175 return jsNontrivialString(exec
, ASCIILiteral("array"));
176 if (value
.inherits(JSUint8Array::info()) || value
.inherits(JSUint16Array::info()) || value
.inherits(JSUint32Array::info()))
177 return jsNontrivialString(exec
, ASCIILiteral("array"));
178 if (value
.inherits(JSFloat32Array::info()) || value
.inherits(JSFloat64Array::info()))
179 return jsNontrivialString(exec
, ASCIILiteral("array"));
181 return impl().subtype(exec
, value
);
184 JSValue
JSInjectedScriptHost::functionDetails(ExecState
* exec
)
186 if (exec
->argumentCount() < 1)
187 return jsUndefined();
189 JSValue value
= exec
->uncheckedArgument(0);
190 if (!value
.asCell()->inherits(JSFunction::info()))
191 return jsUndefined();
193 // FIXME: This should provide better details for JSBoundFunctions.
195 JSFunction
* function
= jsCast
<JSFunction
*>(value
);
196 const SourceCode
* sourceCode
= function
->sourceCode();
198 return jsUndefined();
200 // In the inspector protocol all positions are 0-based while in SourceCode they are 1-based
201 int lineNumber
= sourceCode
->firstLine();
204 int columnNumber
= sourceCode
->startColumn();
208 String scriptID
= String::number(sourceCode
->provider()->asID());
209 JSObject
* location
= constructEmptyObject(exec
);
210 location
->putDirect(exec
->vm(), Identifier::fromString(exec
, "scriptId"), jsString(exec
, scriptID
));
211 location
->putDirect(exec
->vm(), Identifier::fromString(exec
, "lineNumber"), jsNumber(lineNumber
));
212 location
->putDirect(exec
->vm(), Identifier::fromString(exec
, "columnNumber"), jsNumber(columnNumber
));
214 JSObject
* result
= constructEmptyObject(exec
);
215 result
->putDirect(exec
->vm(), Identifier::fromString(exec
, "location"), location
);
217 String name
= function
->name(exec
);
219 result
->putDirect(exec
->vm(), Identifier::fromString(exec
, "name"), jsString(exec
, name
));
221 String displayName
= function
->displayName(exec
);
222 if (!displayName
.isEmpty())
223 result
->putDirect(exec
->vm(), Identifier::fromString(exec
, "displayName"), jsString(exec
, displayName
));
225 // FIXME: provide function scope data in "scopesRaw" property when JSC supports it.
226 // <https://webkit.org/b/87192> [JSC] expose function (closure) inner context to debugger
231 static JSObject
* constructInternalProperty(ExecState
* exec
, const String
& name
, JSValue value
)
233 JSObject
* result
= constructEmptyObject(exec
);
234 result
->putDirect(exec
->vm(), Identifier::fromString(exec
, "name"), jsString(exec
, name
));
235 result
->putDirect(exec
->vm(), Identifier::fromString(exec
, "value"), value
);
239 JSValue
JSInjectedScriptHost::getInternalProperties(ExecState
* exec
)
241 if (exec
->argumentCount() < 1)
242 return jsUndefined();
244 JSValue value
= exec
->uncheckedArgument(0);
247 if (JSPromise
* promise
= jsDynamicCast
<JSPromise
*>(value
)) {
249 JSArray
* array
= constructEmptyArray(exec
, nullptr);
250 switch (promise
->status(exec
->vm())) {
251 case JSPromise::Status::Pending
:
252 array
->putDirectIndex(exec
, index
++, constructInternalProperty(exec
, ASCIILiteral("status"), jsNontrivialString(exec
, ASCIILiteral("pending"))));
254 case JSPromise::Status::Fulfilled
:
255 array
->putDirectIndex(exec
, index
++, constructInternalProperty(exec
, ASCIILiteral("status"), jsNontrivialString(exec
, ASCIILiteral("resolved"))));
256 array
->putDirectIndex(exec
, index
++, constructInternalProperty(exec
, ASCIILiteral("result"), promise
->result(exec
->vm())));
258 case JSPromise::Status::Rejected
:
259 array
->putDirectIndex(exec
, index
++, constructInternalProperty(exec
, ASCIILiteral("status"), jsNontrivialString(exec
, ASCIILiteral("rejected"))));
260 array
->putDirectIndex(exec
, index
++, constructInternalProperty(exec
, ASCIILiteral("result"), promise
->result(exec
->vm())));
263 // FIXME: <https://webkit.org/b/141664> Web Inspector: ES6: Improved Support for Promises - Promise Reactions
268 if (JSBoundFunction
* boundFunction
= jsDynamicCast
<JSBoundFunction
*>(value
)) {
270 JSArray
* array
= constructEmptyArray(exec
, nullptr, 3);
271 array
->putDirectIndex(exec
, index
++, constructInternalProperty(exec
, "targetFunction", boundFunction
->targetFunction()));
272 array
->putDirectIndex(exec
, index
++, constructInternalProperty(exec
, "boundThis", boundFunction
->boundThis()));
273 array
->putDirectIndex(exec
, index
++, constructInternalProperty(exec
, "boundArgs", boundFunction
->boundArgs()));
277 if (JSArrayIterator
* arrayIterator
= jsDynamicCast
<JSArrayIterator
*>(value
)) {
279 switch (arrayIterator
->kind(exec
)) {
280 case ArrayIterateKey
:
281 kind
= ASCIILiteral("key");
283 case ArrayIterateValue
:
284 kind
= ASCIILiteral("value");
286 case ArrayIterateKeyValue
:
287 kind
= ASCIILiteral("key+value");
291 JSArray
* array
= constructEmptyArray(exec
, nullptr, 2);
292 array
->putDirectIndex(exec
, index
++, constructInternalProperty(exec
, "array", arrayIterator
->iteratedValue(exec
)));
293 array
->putDirectIndex(exec
, index
++, constructInternalProperty(exec
, "kind", jsNontrivialString(exec
, kind
)));
297 if (JSMapIterator
* mapIterator
= jsDynamicCast
<JSMapIterator
*>(value
)) {
299 switch (mapIterator
->kind()) {
301 kind
= ASCIILiteral("key");
303 case MapIterateValue
:
304 kind
= ASCIILiteral("value");
306 case MapIterateKeyValue
:
307 kind
= ASCIILiteral("key+value");
311 JSArray
* array
= constructEmptyArray(exec
, nullptr, 2);
312 array
->putDirectIndex(exec
, index
++, constructInternalProperty(exec
, "map", mapIterator
->iteratedValue()));
313 array
->putDirectIndex(exec
, index
++, constructInternalProperty(exec
, "kind", jsNontrivialString(exec
, kind
)));
317 if (JSSetIterator
* setIterator
= jsDynamicCast
<JSSetIterator
*>(value
)) {
319 switch (setIterator
->kind()) {
321 kind
= ASCIILiteral("key");
323 case SetIterateValue
:
324 kind
= ASCIILiteral("value");
326 case SetIterateKeyValue
:
327 kind
= ASCIILiteral("key+value");
331 JSArray
* array
= constructEmptyArray(exec
, nullptr, 2);
332 array
->putDirectIndex(exec
, index
++, constructInternalProperty(exec
, "set", setIterator
->iteratedValue()));
333 array
->putDirectIndex(exec
, index
++, constructInternalProperty(exec
, "kind", jsNontrivialString(exec
, kind
)));
337 if (JSStringIterator
* stringIterator
= jsDynamicCast
<JSStringIterator
*>(value
)) {
339 JSArray
* array
= constructEmptyArray(exec
, nullptr, 1);
340 array
->putDirectIndex(exec
, index
++, constructInternalProperty(exec
, "string", stringIterator
->iteratedValue(exec
)));
344 return jsUndefined();
347 JSValue
JSInjectedScriptHost::weakMapSize(ExecState
* exec
)
349 if (exec
->argumentCount() < 1)
350 return jsUndefined();
352 JSValue value
= exec
->uncheckedArgument(0);
353 JSWeakMap
* weakMap
= jsDynamicCast
<JSWeakMap
*>(value
);
355 return jsUndefined();
357 return jsNumber(weakMap
->weakMapData()->size());
360 JSValue
JSInjectedScriptHost::weakMapEntries(ExecState
* exec
)
362 if (exec
->argumentCount() < 1)
363 return jsUndefined();
365 JSValue value
= exec
->uncheckedArgument(0);
366 JSWeakMap
* weakMap
= jsDynamicCast
<JSWeakMap
*>(value
);
368 return jsUndefined();
370 unsigned fetched
= 0;
371 unsigned numberToFetch
= 100;
373 JSValue numberToFetchArg
= exec
->argument(1);
374 double fetchDouble
= numberToFetchArg
.toInteger(exec
);
375 if (fetchDouble
>= 0)
376 numberToFetch
= static_cast<unsigned>(fetchDouble
);
378 JSArray
* array
= constructEmptyArray(exec
, nullptr);
379 for (auto it
= weakMap
->weakMapData()->begin(); it
!= weakMap
->weakMapData()->end(); ++it
) {
380 JSObject
* entry
= constructEmptyObject(exec
);
381 entry
->putDirect(exec
->vm(), Identifier::fromString(exec
, "key"), it
->key
);
382 entry
->putDirect(exec
->vm(), Identifier::fromString(exec
, "value"), it
->value
.get());
383 array
->putDirectIndex(exec
, fetched
++, entry
);
384 if (numberToFetch
&& fetched
>= numberToFetch
)
391 JSValue
JSInjectedScriptHost::weakSetSize(ExecState
* exec
)
393 if (exec
->argumentCount() < 1)
394 return jsUndefined();
396 JSValue value
= exec
->uncheckedArgument(0);
397 JSWeakSet
* weakSet
= jsDynamicCast
<JSWeakSet
*>(value
);
399 return jsUndefined();
401 return jsNumber(weakSet
->weakMapData()->size());
404 JSValue
JSInjectedScriptHost::weakSetEntries(ExecState
* exec
)
406 if (exec
->argumentCount() < 1)
407 return jsUndefined();
409 JSValue value
= exec
->uncheckedArgument(0);
410 JSWeakSet
* weakSet
= jsDynamicCast
<JSWeakSet
*>(value
);
412 return jsUndefined();
414 unsigned fetched
= 0;
415 unsigned numberToFetch
= 100;
417 JSValue numberToFetchArg
= exec
->argument(1);
418 double fetchDouble
= numberToFetchArg
.toInteger(exec
);
419 if (fetchDouble
>= 0)
420 numberToFetch
= static_cast<unsigned>(fetchDouble
);
422 JSArray
* array
= constructEmptyArray(exec
, nullptr);
423 for (auto it
= weakSet
->weakMapData()->begin(); it
!= weakSet
->weakMapData()->end(); ++it
) {
424 JSObject
* entry
= constructEmptyObject(exec
);
425 entry
->putDirect(exec
->vm(), Identifier::fromString(exec
, "value"), it
->key
);
426 array
->putDirectIndex(exec
, fetched
++, entry
);
427 if (numberToFetch
&& fetched
>= numberToFetch
)
434 JSValue
JSInjectedScriptHost::iteratorEntries(ExecState
* exec
)
436 if (exec
->argumentCount() < 1)
437 return jsUndefined();
440 JSValue value
= exec
->uncheckedArgument(0);
441 if (JSArrayIterator
* arrayIterator
= jsDynamicCast
<JSArrayIterator
*>(value
))
442 iterator
= arrayIterator
->clone(exec
);
443 else if (JSMapIterator
* mapIterator
= jsDynamicCast
<JSMapIterator
*>(value
))
444 iterator
= mapIterator
->clone(exec
);
445 else if (JSSetIterator
* setIterator
= jsDynamicCast
<JSSetIterator
*>(value
))
446 iterator
= setIterator
->clone(exec
);
447 else if (JSStringIterator
* stringIterator
= jsDynamicCast
<JSStringIterator
*>(value
))
448 iterator
= stringIterator
->clone(exec
);
450 return jsUndefined();
452 unsigned numberToFetch
= 5;
453 JSValue numberToFetchArg
= exec
->argument(1);
454 double fetchDouble
= numberToFetchArg
.toInteger(exec
);
455 if (fetchDouble
>= 0)
456 numberToFetch
= static_cast<unsigned>(fetchDouble
);
458 JSArray
* array
= constructEmptyArray(exec
, nullptr);
460 for (unsigned i
= 0; i
< numberToFetch
; ++i
) {
461 JSValue next
= iteratorStep(exec
, iterator
);
462 if (exec
->hadException())
467 JSValue nextValue
= iteratorValue(exec
, next
);
468 if (exec
->hadException())
471 JSObject
* entry
= constructEmptyObject(exec
);
472 entry
->putDirect(exec
->vm(), Identifier::fromString(exec
, "value"), nextValue
);
473 array
->putDirectIndex(exec
, i
, entry
);
476 iteratorClose(exec
, iterator
);
481 JSValue
toJS(ExecState
* exec
, JSGlobalObject
* globalObject
, InjectedScriptHost
* impl
)
486 JSObject
* prototype
= JSInjectedScriptHost::createPrototype(exec
->vm(), globalObject
);
487 Structure
* structure
= JSInjectedScriptHost::createStructure(exec
->vm(), globalObject
, prototype
);
488 JSInjectedScriptHost
* injectedScriptHost
= JSInjectedScriptHost::create(exec
->vm(), structure
, impl
);
490 return injectedScriptHost
;
493 JSInjectedScriptHost
* toJSInjectedScriptHost(JSValue value
)
495 return value
.inherits(JSInjectedScriptHost::info()) ? jsCast
<JSInjectedScriptHost
*>(value
) : nullptr;
498 } // namespace Inspector