1 | /* |
2 | * Copyright (C) 2015-2018 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
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. |
12 | * |
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. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include "JSDollarVM.h" |
28 | |
29 | #include "BuiltinExecutableCreator.h" |
30 | #include "CodeBlock.h" |
31 | #include "DOMAttributeGetterSetter.h" |
32 | #include "DOMJITGetterSetter.h" |
33 | #include "FrameTracers.h" |
34 | #include "FunctionCodeBlock.h" |
35 | #include "GetterSetter.h" |
36 | #include "JSArray.h" |
37 | #include "JSArrayBuffer.h" |
38 | #include "JSCInlines.h" |
39 | #include "JSFunction.h" |
40 | #include "JSONObject.h" |
41 | #include "JSProxy.h" |
42 | #include "JSString.h" |
43 | #include "ShadowChicken.h" |
44 | #include "Snippet.h" |
45 | #include "SnippetParams.h" |
46 | #include "TypeProfiler.h" |
47 | #include "TypeProfilerLog.h" |
48 | #include "VMInspector.h" |
49 | #include <wtf/Atomics.h> |
50 | #include <wtf/DataLog.h> |
51 | #include <wtf/ProcessID.h> |
52 | #include <wtf/StringPrintStream.h> |
53 | |
54 | #if ENABLE(WEBASSEMBLY) |
55 | #include "JSWebAssemblyHelpers.h" |
56 | #include "WasmStreamingParser.h" |
57 | #endif |
58 | |
59 | using namespace JSC; |
60 | |
61 | namespace { |
62 | |
63 | class JSDollarVMCallFrame : public JSDestructibleObject { |
64 | using Base = JSDestructibleObject; |
65 | public: |
66 | JSDollarVMCallFrame(VM& vm, Structure* structure) |
67 | : Base(vm, structure) |
68 | { } |
69 | |
70 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) |
71 | { |
72 | return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); |
73 | } |
74 | |
75 | static JSDollarVMCallFrame* create(ExecState* exec, unsigned requestedFrameIndex) |
76 | { |
77 | VM& vm = exec->vm(); |
78 | JSGlobalObject* globalObject = exec->lexicalGlobalObject(); |
79 | Structure* structure = createStructure(vm, globalObject, jsNull()); |
80 | JSDollarVMCallFrame* frame = new (NotNull, allocateCell<JSDollarVMCallFrame>(vm.heap, sizeof(JSDollarVMCallFrame))) JSDollarVMCallFrame(vm, structure); |
81 | frame->finishCreation(vm, exec, requestedFrameIndex); |
82 | return frame; |
83 | } |
84 | |
85 | void finishCreation(VM& vm, CallFrame* frame, unsigned requestedFrameIndex) |
86 | { |
87 | Base::finishCreation(vm); |
88 | |
89 | auto addProperty = [&] (VM& vm, const char* name, JSValue value) { |
90 | JSDollarVMCallFrame::addProperty(vm, name, value); |
91 | }; |
92 | |
93 | unsigned frameIndex = 0; |
94 | bool isValid = false; |
95 | frame->iterate([&] (StackVisitor& visitor) { |
96 | |
97 | if (frameIndex++ != requestedFrameIndex) |
98 | return StackVisitor::Continue; |
99 | |
100 | addProperty(vm, "name" , jsString(&vm, visitor->functionName())); |
101 | |
102 | if (visitor->callee().isCell()) |
103 | addProperty(vm, "callee" , visitor->callee().asCell()); |
104 | |
105 | CodeBlock* codeBlock = visitor->codeBlock(); |
106 | if (codeBlock) { |
107 | addProperty(vm, "codeBlock" , codeBlock); |
108 | addProperty(vm, "unlinkedCodeBlock" , codeBlock->unlinkedCodeBlock()); |
109 | addProperty(vm, "executable" , codeBlock->ownerExecutable()); |
110 | } |
111 | isValid = true; |
112 | |
113 | return StackVisitor::Done; |
114 | }); |
115 | |
116 | addProperty(vm, "valid" , jsBoolean(isValid)); |
117 | } |
118 | |
119 | DECLARE_INFO; |
120 | |
121 | private: |
122 | void addProperty(VM& vm, const char* name, JSValue value) |
123 | { |
124 | Identifier identifier = Identifier::fromString(&vm, name); |
125 | putDirect(vm, identifier, value); |
126 | } |
127 | }; |
128 | |
129 | const ClassInfo JSDollarVMCallFrame::s_info = { "CallFrame" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDollarVMCallFrame) }; |
130 | |
131 | class ElementHandleOwner; |
132 | class Root; |
133 | |
134 | class Element : public JSNonFinalObject { |
135 | public: |
136 | Element(VM& vm, Structure* structure) |
137 | : Base(vm, structure) |
138 | { |
139 | } |
140 | |
141 | typedef JSNonFinalObject Base; |
142 | |
143 | Root* root() const { return m_root.get(); } |
144 | void setRoot(VM& vm, Root* root) { m_root.set(vm, this, root); } |
145 | |
146 | static Element* create(VM& vm, JSGlobalObject* globalObject, Root* root) |
147 | { |
148 | Structure* structure = createStructure(vm, globalObject, jsNull()); |
149 | Element* element = new (NotNull, allocateCell<Element>(vm.heap, sizeof(Element))) Element(vm, structure); |
150 | element->finishCreation(vm, root); |
151 | return element; |
152 | } |
153 | |
154 | void finishCreation(VM&, Root*); |
155 | |
156 | static void visitChildren(JSCell* cell, SlotVisitor& visitor) |
157 | { |
158 | Element* thisObject = jsCast<Element*>(cell); |
159 | ASSERT_GC_OBJECT_INHERITS(thisObject, info()); |
160 | Base::visitChildren(thisObject, visitor); |
161 | visitor.append(thisObject->m_root); |
162 | } |
163 | |
164 | static ElementHandleOwner* handleOwner(); |
165 | |
166 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) |
167 | { |
168 | return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); |
169 | } |
170 | |
171 | DECLARE_INFO; |
172 | |
173 | private: |
174 | WriteBarrier<Root> m_root; |
175 | }; |
176 | |
177 | class ElementHandleOwner : public WeakHandleOwner { |
178 | public: |
179 | bool isReachableFromOpaqueRoots(Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason) override |
180 | { |
181 | if (UNLIKELY(reason)) |
182 | *reason = "JSC::Element is opaque root" ; |
183 | Element* element = jsCast<Element*>(handle.slot()->asCell()); |
184 | return visitor.containsOpaqueRoot(element->root()); |
185 | } |
186 | }; |
187 | |
188 | class Root : public JSDestructibleObject { |
189 | public: |
190 | Root(VM& vm, Structure* structure) |
191 | : Base(vm, structure) |
192 | { |
193 | } |
194 | |
195 | Element* element() |
196 | { |
197 | return m_element.get(); |
198 | } |
199 | |
200 | void setElement(Element* element) |
201 | { |
202 | Weak<Element> newElement(element, Element::handleOwner()); |
203 | m_element.swap(newElement); |
204 | } |
205 | |
206 | static Root* create(VM& vm, JSGlobalObject* globalObject) |
207 | { |
208 | Structure* structure = createStructure(vm, globalObject, jsNull()); |
209 | Root* root = new (NotNull, allocateCell<Root>(vm.heap, sizeof(Root))) Root(vm, structure); |
210 | root->finishCreation(vm); |
211 | return root; |
212 | } |
213 | |
214 | typedef JSDestructibleObject Base; |
215 | |
216 | DECLARE_INFO; |
217 | |
218 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) |
219 | { |
220 | return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); |
221 | } |
222 | |
223 | static void visitChildren(JSCell* thisObject, SlotVisitor& visitor) |
224 | { |
225 | Base::visitChildren(thisObject, visitor); |
226 | visitor.addOpaqueRoot(thisObject); |
227 | } |
228 | |
229 | private: |
230 | Weak<Element> m_element; |
231 | }; |
232 | |
233 | class SimpleObject : public JSNonFinalObject { |
234 | public: |
235 | SimpleObject(VM& vm, Structure* structure) |
236 | : Base(vm, structure) |
237 | { |
238 | } |
239 | |
240 | typedef JSNonFinalObject Base; |
241 | static const bool needsDestruction = false; |
242 | |
243 | static SimpleObject* create(VM& vm, JSGlobalObject* globalObject) |
244 | { |
245 | Structure* structure = createStructure(vm, globalObject, jsNull()); |
246 | SimpleObject* simpleObject = new (NotNull, allocateCell<SimpleObject>(vm.heap, sizeof(SimpleObject))) SimpleObject(vm, structure); |
247 | simpleObject->finishCreation(vm); |
248 | return simpleObject; |
249 | } |
250 | |
251 | static void visitChildren(JSCell* cell, SlotVisitor& visitor) |
252 | { |
253 | SimpleObject* thisObject = jsCast<SimpleObject*>(cell); |
254 | ASSERT_GC_OBJECT_INHERITS(thisObject, info()); |
255 | Base::visitChildren(thisObject, visitor); |
256 | visitor.append(thisObject->m_hiddenValue); |
257 | } |
258 | |
259 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) |
260 | { |
261 | return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); |
262 | } |
263 | |
264 | JSValue hiddenValue() |
265 | { |
266 | return m_hiddenValue.get(); |
267 | } |
268 | |
269 | void setHiddenValue(VM& vm, JSValue value) |
270 | { |
271 | ASSERT(value.isCell()); |
272 | m_hiddenValue.set(vm, this, value); |
273 | } |
274 | |
275 | DECLARE_INFO; |
276 | |
277 | private: |
278 | WriteBarrier<JSC::Unknown> m_hiddenValue; |
279 | }; |
280 | |
281 | class ImpureGetter : public JSNonFinalObject { |
282 | public: |
283 | ImpureGetter(VM& vm, Structure* structure) |
284 | : Base(vm, structure) |
285 | { |
286 | } |
287 | |
288 | DECLARE_INFO; |
289 | typedef JSNonFinalObject Base; |
290 | static const unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpure | JSC::OverridesGetOwnPropertySlot; |
291 | |
292 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) |
293 | { |
294 | return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); |
295 | } |
296 | |
297 | static ImpureGetter* create(VM& vm, Structure* structure, JSObject* delegate) |
298 | { |
299 | ImpureGetter* getter = new (NotNull, allocateCell<ImpureGetter>(vm.heap, sizeof(ImpureGetter))) ImpureGetter(vm, structure); |
300 | getter->finishCreation(vm, delegate); |
301 | return getter; |
302 | } |
303 | |
304 | void finishCreation(VM& vm, JSObject* delegate) |
305 | { |
306 | Base::finishCreation(vm); |
307 | if (delegate) |
308 | m_delegate.set(vm, this, delegate); |
309 | } |
310 | |
311 | static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName name, PropertySlot& slot) |
312 | { |
313 | VM& vm = exec->vm(); |
314 | auto scope = DECLARE_THROW_SCOPE(vm); |
315 | ImpureGetter* thisObject = jsCast<ImpureGetter*>(object); |
316 | |
317 | if (thisObject->m_delegate) { |
318 | if (thisObject->m_delegate->getPropertySlot(exec, name, slot)) |
319 | return true; |
320 | RETURN_IF_EXCEPTION(scope, false); |
321 | } |
322 | |
323 | return Base::getOwnPropertySlot(object, exec, name, slot); |
324 | } |
325 | |
326 | static void visitChildren(JSCell* cell, SlotVisitor& visitor) |
327 | { |
328 | Base::visitChildren(cell, visitor); |
329 | ImpureGetter* thisObject = jsCast<ImpureGetter*>(cell); |
330 | visitor.append(thisObject->m_delegate); |
331 | } |
332 | |
333 | void setDelegate(VM& vm, JSObject* delegate) |
334 | { |
335 | m_delegate.set(vm, this, delegate); |
336 | } |
337 | |
338 | private: |
339 | WriteBarrier<JSObject> m_delegate; |
340 | }; |
341 | |
342 | class CustomGetter : public JSNonFinalObject { |
343 | public: |
344 | CustomGetter(VM& vm, Structure* structure) |
345 | : Base(vm, structure) |
346 | { |
347 | } |
348 | |
349 | DECLARE_INFO; |
350 | typedef JSNonFinalObject Base; |
351 | static const unsigned StructureFlags = Base::StructureFlags | JSC::OverridesGetOwnPropertySlot; |
352 | |
353 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) |
354 | { |
355 | return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); |
356 | } |
357 | |
358 | static CustomGetter* create(VM& vm, Structure* structure) |
359 | { |
360 | CustomGetter* getter = new (NotNull, allocateCell<CustomGetter>(vm.heap, sizeof(CustomGetter))) CustomGetter(vm, structure); |
361 | getter->finishCreation(vm); |
362 | return getter; |
363 | } |
364 | |
365 | static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) |
366 | { |
367 | CustomGetter* thisObject = jsCast<CustomGetter*>(object); |
368 | if (propertyName == PropertyName(Identifier::fromString(exec, "customGetter" ))) { |
369 | slot.setCacheableCustom(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum, thisObject->customGetter); |
370 | return true; |
371 | } |
372 | |
373 | if (propertyName == PropertyName(Identifier::fromString(exec, "customGetterAccessor" ))) { |
374 | slot.setCacheableCustom(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | PropertyAttribute::CustomAccessor, thisObject->customGetterAcessor); |
375 | return true; |
376 | } |
377 | |
378 | return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot); |
379 | } |
380 | |
381 | private: |
382 | static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName) |
383 | { |
384 | VM& vm = exec->vm(); |
385 | auto scope = DECLARE_THROW_SCOPE(vm); |
386 | |
387 | CustomGetter* thisObject = jsDynamicCast<CustomGetter*>(vm, JSValue::decode(thisValue)); |
388 | if (!thisObject) |
389 | return throwVMTypeError(exec, scope); |
390 | bool shouldThrow = thisObject->get(exec, PropertyName(Identifier::fromString(exec, "shouldThrow" ))).toBoolean(exec); |
391 | RETURN_IF_EXCEPTION(scope, encodedJSValue()); |
392 | if (shouldThrow) |
393 | return throwVMTypeError(exec, scope); |
394 | return JSValue::encode(jsNumber(100)); |
395 | } |
396 | |
397 | static EncodedJSValue customGetterAcessor(ExecState* exec, EncodedJSValue thisValue, PropertyName) |
398 | { |
399 | VM& vm = exec->vm(); |
400 | auto scope = DECLARE_THROW_SCOPE(vm); |
401 | |
402 | JSObject* thisObject = jsDynamicCast<JSObject*>(vm, JSValue::decode(thisValue)); |
403 | if (!thisObject) |
404 | return throwVMTypeError(exec, scope); |
405 | bool shouldThrow = thisObject->get(exec, PropertyName(Identifier::fromString(exec, "shouldThrow" ))).toBoolean(exec); |
406 | RETURN_IF_EXCEPTION(scope, encodedJSValue()); |
407 | if (shouldThrow) |
408 | return throwVMTypeError(exec, scope); |
409 | return JSValue::encode(jsNumber(100)); |
410 | } |
411 | }; |
412 | |
413 | class RuntimeArray : public JSArray { |
414 | public: |
415 | typedef JSArray Base; |
416 | static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames; |
417 | |
418 | static RuntimeArray* create(ExecState* exec) |
419 | { |
420 | VM& vm = exec->vm(); |
421 | JSGlobalObject* globalObject = exec->lexicalGlobalObject(); |
422 | Structure* structure = createStructure(vm, globalObject, createPrototype(vm, globalObject)); |
423 | RuntimeArray* runtimeArray = new (NotNull, allocateCell<RuntimeArray>(vm.heap)) RuntimeArray(exec, structure); |
424 | runtimeArray->finishCreation(exec); |
425 | vm.heap.addFinalizer(runtimeArray, destroy); |
426 | return runtimeArray; |
427 | } |
428 | |
429 | ~RuntimeArray() { } |
430 | |
431 | static void destroy(JSCell* cell) |
432 | { |
433 | static_cast<RuntimeArray*>(cell)->RuntimeArray::~RuntimeArray(); |
434 | } |
435 | |
436 | static const bool needsDestruction = false; |
437 | |
438 | static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) |
439 | { |
440 | VM& vm = exec->vm(); |
441 | RuntimeArray* thisObject = jsCast<RuntimeArray*>(object); |
442 | if (propertyName == vm.propertyNames->length) { |
443 | slot.setCacheableCustom(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum, thisObject->lengthGetter); |
444 | return true; |
445 | } |
446 | |
447 | Optional<uint32_t> index = parseIndex(propertyName); |
448 | if (index && index.value() < thisObject->getLength()) { |
449 | slot.setValue(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::DontEnum, jsNumber(thisObject->m_vector[index.value()])); |
450 | return true; |
451 | } |
452 | |
453 | return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot); |
454 | } |
455 | |
456 | static bool getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot) |
457 | { |
458 | RuntimeArray* thisObject = jsCast<RuntimeArray*>(object); |
459 | if (index < thisObject->getLength()) { |
460 | slot.setValue(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::DontEnum, jsNumber(thisObject->m_vector[index])); |
461 | return true; |
462 | } |
463 | |
464 | return JSObject::getOwnPropertySlotByIndex(thisObject, exec, index, slot); |
465 | } |
466 | |
467 | static NO_RETURN_DUE_TO_CRASH bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&) |
468 | { |
469 | RELEASE_ASSERT_NOT_REACHED(); |
470 | } |
471 | |
472 | static NO_RETURN_DUE_TO_CRASH bool deleteProperty(JSCell*, ExecState*, PropertyName) |
473 | { |
474 | RELEASE_ASSERT_NOT_REACHED(); |
475 | } |
476 | |
477 | unsigned getLength() const { return m_vector.size(); } |
478 | |
479 | DECLARE_INFO; |
480 | |
481 | static ArrayPrototype* createPrototype(VM&, JSGlobalObject* globalObject) |
482 | { |
483 | return globalObject->arrayPrototype(); |
484 | } |
485 | |
486 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) |
487 | { |
488 | return Structure::create(vm, globalObject, prototype, TypeInfo(DerivedArrayType, StructureFlags), info(), ArrayClass); |
489 | } |
490 | |
491 | protected: |
492 | void finishCreation(ExecState* exec) |
493 | { |
494 | VM& vm = exec->vm(); |
495 | Base::finishCreation(vm); |
496 | ASSERT(inherits(vm, info())); |
497 | |
498 | for (size_t i = 0; i < exec->argumentCount(); i++) |
499 | m_vector.append(exec->argument(i).toInt32(exec)); |
500 | } |
501 | |
502 | private: |
503 | RuntimeArray(ExecState* exec, Structure* structure) |
504 | : JSArray(exec->vm(), structure, 0) |
505 | { |
506 | } |
507 | |
508 | static EncodedJSValue lengthGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName) |
509 | { |
510 | VM& vm = exec->vm(); |
511 | auto scope = DECLARE_THROW_SCOPE(vm); |
512 | |
513 | RuntimeArray* thisObject = jsDynamicCast<RuntimeArray*>(vm, JSValue::decode(thisValue)); |
514 | if (!thisObject) |
515 | return throwVMTypeError(exec, scope); |
516 | return JSValue::encode(jsNumber(thisObject->getLength())); |
517 | } |
518 | |
519 | Vector<int> m_vector; |
520 | }; |
521 | |
522 | class DOMJITNode : public JSNonFinalObject { |
523 | public: |
524 | DOMJITNode(VM& vm, Structure* structure) |
525 | : Base(vm, structure) |
526 | { |
527 | } |
528 | |
529 | DECLARE_INFO; |
530 | typedef JSNonFinalObject Base; |
531 | static const unsigned StructureFlags = Base::StructureFlags; |
532 | |
533 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) |
534 | { |
535 | return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info()); |
536 | } |
537 | |
538 | #if ENABLE(JIT) |
539 | static Ref<Snippet> checkSubClassSnippet() |
540 | { |
541 | Ref<Snippet> snippet = Snippet::create(); |
542 | snippet->setGenerator([=](CCallHelpers& jit, SnippetParams& params) { |
543 | CCallHelpers::JumpList failureCases; |
544 | failureCases.append(jit.branchIfNotType(params[0].gpr(), JSC::JSType(LastJSCObjectType + 1))); |
545 | return failureCases; |
546 | }); |
547 | return snippet; |
548 | } |
549 | #endif |
550 | |
551 | static DOMJITNode* create(VM& vm, Structure* structure) |
552 | { |
553 | DOMJITNode* getter = new (NotNull, allocateCell<DOMJITNode>(vm.heap, sizeof(DOMJITNode))) DOMJITNode(vm, structure); |
554 | getter->finishCreation(vm); |
555 | return getter; |
556 | } |
557 | |
558 | int32_t value() const |
559 | { |
560 | return m_value; |
561 | } |
562 | |
563 | static ptrdiff_t offsetOfValue() { return OBJECT_OFFSETOF(DOMJITNode, m_value); } |
564 | |
565 | private: |
566 | int32_t m_value { 42 }; |
567 | }; |
568 | |
569 | class DOMJITGetter : public DOMJITNode { |
570 | public: |
571 | DOMJITGetter(VM& vm, Structure* structure) |
572 | : Base(vm, structure) |
573 | { |
574 | } |
575 | |
576 | DECLARE_INFO; |
577 | typedef DOMJITNode Base; |
578 | static const unsigned StructureFlags = Base::StructureFlags; |
579 | |
580 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) |
581 | { |
582 | return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info()); |
583 | } |
584 | |
585 | static DOMJITGetter* create(VM& vm, Structure* structure) |
586 | { |
587 | DOMJITGetter* getter = new (NotNull, allocateCell<DOMJITGetter>(vm.heap, sizeof(DOMJITGetter))) DOMJITGetter(vm, structure); |
588 | getter->finishCreation(vm); |
589 | return getter; |
590 | } |
591 | |
592 | class DOMJITAttribute : public DOMJIT::GetterSetter { |
593 | public: |
594 | constexpr DOMJITAttribute() |
595 | : DOMJIT::GetterSetter( |
596 | DOMJITGetter::customGetter, |
597 | #if ENABLE(JIT) |
598 | &callDOMGetter, |
599 | #else |
600 | nullptr, |
601 | #endif |
602 | SpecInt32Only) |
603 | { |
604 | } |
605 | |
606 | #if ENABLE(JIT) |
607 | static EncodedJSValue JIT_OPERATION slowCall(ExecState* exec, void* pointer) |
608 | { |
609 | VM& vm = exec->vm(); |
610 | NativeCallFrameTracer tracer(&vm, exec); |
611 | return JSValue::encode(jsNumber(static_cast<DOMJITGetter*>(pointer)->value())); |
612 | } |
613 | |
614 | static Ref<DOMJIT::CallDOMGetterSnippet> callDOMGetter() |
615 | { |
616 | Ref<DOMJIT::CallDOMGetterSnippet> snippet = DOMJIT::CallDOMGetterSnippet::create(); |
617 | snippet->requireGlobalObject = false; |
618 | snippet->setGenerator([=](CCallHelpers& jit, SnippetParams& params) { |
619 | JSValueRegs results = params[0].jsValueRegs(); |
620 | GPRReg dom = params[1].gpr(); |
621 | params.addSlowPathCall(jit.jump(), jit, slowCall, results, dom); |
622 | return CCallHelpers::JumpList(); |
623 | |
624 | }); |
625 | return snippet; |
626 | } |
627 | #endif |
628 | }; |
629 | |
630 | private: |
631 | void finishCreation(VM&); |
632 | |
633 | static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName) |
634 | { |
635 | VM& vm = exec->vm(); |
636 | DOMJITNode* thisObject = jsDynamicCast<DOMJITNode*>(vm, JSValue::decode(thisValue)); |
637 | ASSERT(thisObject); |
638 | return JSValue::encode(jsNumber(thisObject->value())); |
639 | } |
640 | }; |
641 | |
642 | static const DOMJITGetter::DOMJITAttribute DOMJITGetterDOMJIT; |
643 | |
644 | void DOMJITGetter::finishCreation(VM& vm) |
645 | { |
646 | Base::finishCreation(vm); |
647 | const DOMJIT::GetterSetter* domJIT = &DOMJITGetterDOMJIT; |
648 | auto* customGetterSetter = DOMAttributeGetterSetter::create(vm, domJIT->getter(), nullptr, DOMAttributeAnnotation { DOMJITNode::info(), domJIT }); |
649 | putDirectCustomAccessor(vm, Identifier::fromString(&vm, "customGetter" ), customGetterSetter, PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor); |
650 | } |
651 | |
652 | class DOMJITGetterComplex : public DOMJITNode { |
653 | public: |
654 | DOMJITGetterComplex(VM& vm, Structure* structure) |
655 | : Base(vm, structure) |
656 | { |
657 | } |
658 | |
659 | DECLARE_INFO; |
660 | typedef DOMJITNode Base; |
661 | static const unsigned StructureFlags = Base::StructureFlags; |
662 | |
663 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) |
664 | { |
665 | return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info()); |
666 | } |
667 | |
668 | static DOMJITGetterComplex* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) |
669 | { |
670 | DOMJITGetterComplex* getter = new (NotNull, allocateCell<DOMJITGetterComplex>(vm.heap, sizeof(DOMJITGetterComplex))) DOMJITGetterComplex(vm, structure); |
671 | getter->finishCreation(vm, globalObject); |
672 | return getter; |
673 | } |
674 | |
675 | class DOMJITAttribute : public DOMJIT::GetterSetter { |
676 | public: |
677 | constexpr DOMJITAttribute() |
678 | : DOMJIT::GetterSetter( |
679 | DOMJITGetterComplex::customGetter, |
680 | #if ENABLE(JIT) |
681 | &callDOMGetter, |
682 | #else |
683 | nullptr, |
684 | #endif |
685 | SpecInt32Only) |
686 | { |
687 | } |
688 | |
689 | #if ENABLE(JIT) |
690 | static EncodedJSValue JIT_OPERATION slowCall(ExecState* exec, void* pointer) |
691 | { |
692 | VM& vm = exec->vm(); |
693 | NativeCallFrameTracer tracer(&vm, exec); |
694 | auto scope = DECLARE_THROW_SCOPE(vm); |
695 | auto* object = static_cast<DOMJITNode*>(pointer); |
696 | auto* domjitGetterComplex = jsDynamicCast<DOMJITGetterComplex*>(vm, object); |
697 | if (domjitGetterComplex) { |
698 | if (domjitGetterComplex->m_enableException) |
699 | return JSValue::encode(throwException(exec, scope, createError(exec, "DOMJITGetterComplex slow call exception"_s ))); |
700 | } |
701 | return JSValue::encode(jsNumber(object->value())); |
702 | } |
703 | |
704 | static Ref<DOMJIT::CallDOMGetterSnippet> callDOMGetter() |
705 | { |
706 | Ref<DOMJIT::CallDOMGetterSnippet> snippet = DOMJIT::CallDOMGetterSnippet::create(); |
707 | static_assert(GPRInfo::numberOfRegisters >= 4, "Number of registers should be larger or equal to 4." ); |
708 | unsigned numGPScratchRegisters = GPRInfo::numberOfRegisters - 4; |
709 | snippet->numGPScratchRegisters = numGPScratchRegisters; |
710 | snippet->numFPScratchRegisters = 3; |
711 | snippet->setGenerator([=](CCallHelpers& jit, SnippetParams& params) { |
712 | JSValueRegs results = params[0].jsValueRegs(); |
713 | GPRReg domGPR = params[1].gpr(); |
714 | for (unsigned i = 0; i < numGPScratchRegisters; ++i) |
715 | jit.move(CCallHelpers::TrustedImm32(42), params.gpScratch(i)); |
716 | |
717 | params.addSlowPathCall(jit.jump(), jit, slowCall, results, domGPR); |
718 | return CCallHelpers::JumpList(); |
719 | }); |
720 | return snippet; |
721 | } |
722 | #endif |
723 | }; |
724 | |
725 | private: |
726 | void finishCreation(VM&, JSGlobalObject*); |
727 | |
728 | static EncodedJSValue JSC_HOST_CALL functionEnableException(ExecState* exec) |
729 | { |
730 | VM& vm = exec->vm(); |
731 | auto* object = jsDynamicCast<DOMJITGetterComplex*>(vm, exec->thisValue()); |
732 | if (object) |
733 | object->m_enableException = true; |
734 | return JSValue::encode(jsUndefined()); |
735 | } |
736 | |
737 | static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName) |
738 | { |
739 | VM& vm = exec->vm(); |
740 | auto scope = DECLARE_THROW_SCOPE(vm); |
741 | |
742 | auto* thisObject = jsDynamicCast<DOMJITGetterComplex*>(vm, JSValue::decode(thisValue)); |
743 | ASSERT(thisObject); |
744 | if (thisObject->m_enableException) |
745 | return JSValue::encode(throwException(exec, scope, createError(exec, "DOMJITGetterComplex slow call exception"_s ))); |
746 | return JSValue::encode(jsNumber(thisObject->value())); |
747 | } |
748 | |
749 | bool m_enableException { false }; |
750 | }; |
751 | |
752 | static const DOMJITGetterComplex::DOMJITAttribute DOMJITGetterComplexDOMJIT; |
753 | |
754 | void DOMJITGetterComplex::finishCreation(VM& vm, JSGlobalObject* globalObject) |
755 | { |
756 | Base::finishCreation(vm); |
757 | const DOMJIT::GetterSetter* domJIT = &DOMJITGetterComplexDOMJIT; |
758 | auto* customGetterSetter = DOMAttributeGetterSetter::create(vm, domJIT->getter(), nullptr, DOMAttributeAnnotation { DOMJITGetterComplex::info(), domJIT }); |
759 | putDirectCustomAccessor(vm, Identifier::fromString(&vm, "customGetter" ), customGetterSetter, PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor); |
760 | putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "enableException" ), 0, functionEnableException, NoIntrinsic, 0); |
761 | } |
762 | |
763 | class DOMJITFunctionObject : public DOMJITNode { |
764 | public: |
765 | DOMJITFunctionObject(VM& vm, Structure* structure) |
766 | : Base(vm, structure) |
767 | { |
768 | } |
769 | |
770 | DECLARE_INFO; |
771 | typedef DOMJITNode Base; |
772 | static const unsigned StructureFlags = Base::StructureFlags; |
773 | |
774 | |
775 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) |
776 | { |
777 | return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info()); |
778 | } |
779 | |
780 | static DOMJITFunctionObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) |
781 | { |
782 | DOMJITFunctionObject* object = new (NotNull, allocateCell<DOMJITFunctionObject>(vm.heap, sizeof(DOMJITFunctionObject))) DOMJITFunctionObject(vm, structure); |
783 | object->finishCreation(vm, globalObject); |
784 | return object; |
785 | } |
786 | |
787 | static EncodedJSValue JSC_HOST_CALL safeFunction(ExecState* exec) |
788 | { |
789 | VM& vm = exec->vm(); |
790 | auto scope = DECLARE_THROW_SCOPE(vm); |
791 | |
792 | DOMJITNode* thisObject = jsDynamicCast<DOMJITNode*>(vm, exec->thisValue()); |
793 | if (!thisObject) |
794 | return throwVMTypeError(exec, scope); |
795 | return JSValue::encode(jsNumber(thisObject->value())); |
796 | } |
797 | |
798 | static EncodedJSValue JIT_OPERATION unsafeFunction(ExecState* exec, DOMJITNode* node) |
799 | { |
800 | VM& vm = exec->vm(); |
801 | NativeCallFrameTracer tracer(&vm, exec); |
802 | return JSValue::encode(jsNumber(node->value())); |
803 | } |
804 | |
805 | #if ENABLE(JIT) |
806 | static Ref<Snippet> checkSubClassSnippet() |
807 | { |
808 | Ref<Snippet> snippet = Snippet::create(); |
809 | snippet->numFPScratchRegisters = 1; |
810 | snippet->setGenerator([=](CCallHelpers& jit, SnippetParams& params) { |
811 | static const double value = 42.0; |
812 | CCallHelpers::JumpList failureCases; |
813 | // May use scratch registers. |
814 | jit.loadDouble(CCallHelpers::TrustedImmPtr(&value), params.fpScratch(0)); |
815 | failureCases.append(jit.branchIfNotType(params[0].gpr(), JSC::JSType(LastJSCObjectType + 1))); |
816 | return failureCases; |
817 | }); |
818 | return snippet; |
819 | } |
820 | #endif |
821 | |
822 | private: |
823 | void finishCreation(VM&, JSGlobalObject*); |
824 | }; |
825 | |
826 | static const DOMJIT::Signature DOMJITFunctionObjectSignature((uintptr_t)DOMJITFunctionObject::unsafeFunction, DOMJITFunctionObject::info(), DOMJIT::Effect::forRead(DOMJIT::HeapRange::top()), SpecInt32Only); |
827 | |
828 | void DOMJITFunctionObject::finishCreation(VM& vm, JSGlobalObject* globalObject) |
829 | { |
830 | Base::finishCreation(vm); |
831 | putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "func" ), 0, safeFunction, NoIntrinsic, &DOMJITFunctionObjectSignature, static_cast<unsigned>(PropertyAttribute::ReadOnly)); |
832 | } |
833 | |
834 | class DOMJITCheckSubClassObject : public DOMJITNode { |
835 | public: |
836 | DOMJITCheckSubClassObject(VM& vm, Structure* structure) |
837 | : Base(vm, structure) |
838 | { |
839 | } |
840 | |
841 | DECLARE_INFO; |
842 | typedef DOMJITNode Base; |
843 | static const unsigned StructureFlags = Base::StructureFlags; |
844 | |
845 | |
846 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) |
847 | { |
848 | return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info()); |
849 | } |
850 | |
851 | static DOMJITCheckSubClassObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) |
852 | { |
853 | DOMJITCheckSubClassObject* object = new (NotNull, allocateCell<DOMJITCheckSubClassObject>(vm.heap, sizeof(DOMJITCheckSubClassObject))) DOMJITCheckSubClassObject(vm, structure); |
854 | object->finishCreation(vm, globalObject); |
855 | return object; |
856 | } |
857 | |
858 | static EncodedJSValue JSC_HOST_CALL safeFunction(ExecState* exec) |
859 | { |
860 | VM& vm = exec->vm(); |
861 | auto scope = DECLARE_THROW_SCOPE(vm); |
862 | |
863 | auto* thisObject = jsDynamicCast<DOMJITCheckSubClassObject*>(vm, exec->thisValue()); |
864 | if (!thisObject) |
865 | return throwVMTypeError(exec, scope); |
866 | return JSValue::encode(jsNumber(thisObject->value())); |
867 | } |
868 | |
869 | static EncodedJSValue JIT_OPERATION unsafeFunction(ExecState* exec, DOMJITNode* node) |
870 | { |
871 | VM& vm = exec->vm(); |
872 | NativeCallFrameTracer tracer(&vm, exec); |
873 | return JSValue::encode(jsNumber(node->value())); |
874 | } |
875 | |
876 | private: |
877 | void finishCreation(VM&, JSGlobalObject*); |
878 | }; |
879 | |
880 | static const DOMJIT::Signature DOMJITCheckSubClassObjectSignature((uintptr_t)DOMJITCheckSubClassObject::unsafeFunction, DOMJITCheckSubClassObject::info(), DOMJIT::Effect::forRead(DOMJIT::HeapRange::top()), SpecInt32Only); |
881 | |
882 | void DOMJITCheckSubClassObject::finishCreation(VM& vm, JSGlobalObject* globalObject) |
883 | { |
884 | Base::finishCreation(vm); |
885 | putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "func" ), 0, safeFunction, NoIntrinsic, &DOMJITCheckSubClassObjectSignature, static_cast<unsigned>(PropertyAttribute::ReadOnly)); |
886 | } |
887 | |
888 | class DOMJITGetterBaseJSObject : public DOMJITNode { |
889 | public: |
890 | DOMJITGetterBaseJSObject(VM& vm, Structure* structure) |
891 | : Base(vm, structure) |
892 | { |
893 | } |
894 | |
895 | DECLARE_INFO; |
896 | using Base = DOMJITNode; |
897 | static const unsigned StructureFlags = Base::StructureFlags; |
898 | |
899 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) |
900 | { |
901 | return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info()); |
902 | } |
903 | |
904 | static DOMJITGetterBaseJSObject* create(VM& vm, Structure* structure) |
905 | { |
906 | DOMJITGetterBaseJSObject* getter = new (NotNull, allocateCell<DOMJITGetterBaseJSObject>(vm.heap, sizeof(DOMJITGetterBaseJSObject))) DOMJITGetterBaseJSObject(vm, structure); |
907 | getter->finishCreation(vm); |
908 | return getter; |
909 | } |
910 | |
911 | class DOMJITAttribute : public DOMJIT::GetterSetter { |
912 | public: |
913 | constexpr DOMJITAttribute() |
914 | : DOMJIT::GetterSetter( |
915 | DOMJITGetterBaseJSObject::customGetter, |
916 | #if ENABLE(JIT) |
917 | &callDOMGetter, |
918 | #else |
919 | nullptr, |
920 | #endif |
921 | SpecBytecodeTop) |
922 | { |
923 | } |
924 | |
925 | #if ENABLE(JIT) |
926 | static EncodedJSValue JIT_OPERATION slowCall(ExecState* exec, void* pointer) |
927 | { |
928 | VM& vm = exec->vm(); |
929 | NativeCallFrameTracer tracer(&vm, exec); |
930 | JSObject* object = static_cast<JSObject*>(pointer); |
931 | return JSValue::encode(object->getPrototypeDirect(vm)); |
932 | } |
933 | |
934 | static Ref<DOMJIT::CallDOMGetterSnippet> callDOMGetter() |
935 | { |
936 | Ref<DOMJIT::CallDOMGetterSnippet> snippet = DOMJIT::CallDOMGetterSnippet::create(); |
937 | snippet->requireGlobalObject = false; |
938 | snippet->setGenerator([=](CCallHelpers& jit, SnippetParams& params) { |
939 | JSValueRegs results = params[0].jsValueRegs(); |
940 | GPRReg dom = params[1].gpr(); |
941 | params.addSlowPathCall(jit.jump(), jit, slowCall, results, dom); |
942 | return CCallHelpers::JumpList(); |
943 | |
944 | }); |
945 | return snippet; |
946 | } |
947 | #endif |
948 | }; |
949 | |
950 | private: |
951 | void finishCreation(VM&); |
952 | |
953 | static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName) |
954 | { |
955 | VM& vm = exec->vm(); |
956 | JSObject* thisObject = jsDynamicCast<JSObject*>(vm, JSValue::decode(thisValue)); |
957 | RELEASE_ASSERT(thisObject); |
958 | return JSValue::encode(thisObject->getPrototypeDirect(vm)); |
959 | } |
960 | }; |
961 | |
962 | static const DOMJITGetterBaseJSObject::DOMJITAttribute DOMJITGetterBaseJSObjectDOMJIT; |
963 | |
964 | void DOMJITGetterBaseJSObject::finishCreation(VM& vm) |
965 | { |
966 | Base::finishCreation(vm); |
967 | const DOMJIT::GetterSetter* domJIT = &DOMJITGetterBaseJSObjectDOMJIT; |
968 | auto* customGetterSetter = DOMAttributeGetterSetter::create(vm, domJIT->getter(), nullptr, DOMAttributeAnnotation { JSObject::info(), domJIT }); |
969 | putDirectCustomAccessor(vm, Identifier::fromString(&vm, "customGetter" ), customGetterSetter, PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor); |
970 | } |
971 | |
972 | class Message : public ThreadSafeRefCounted<Message> { |
973 | public: |
974 | Message(ArrayBufferContents&&, int32_t); |
975 | ~Message(); |
976 | |
977 | ArrayBufferContents&& releaseContents() { return WTFMove(m_contents); } |
978 | int32_t index() const { return m_index; } |
979 | |
980 | private: |
981 | ArrayBufferContents m_contents; |
982 | int32_t m_index { 0 }; |
983 | }; |
984 | |
985 | class JSTestCustomGetterSetter : public JSNonFinalObject { |
986 | public: |
987 | using Base = JSNonFinalObject; |
988 | static const unsigned StructureFlags = Base::StructureFlags; |
989 | |
990 | JSTestCustomGetterSetter(VM& vm, Structure* structure) |
991 | : Base(vm, structure) |
992 | { } |
993 | |
994 | static JSTestCustomGetterSetter* create(VM& vm, JSGlobalObject*, Structure* structure) |
995 | { |
996 | JSTestCustomGetterSetter* result = new (NotNull, allocateCell<JSTestCustomGetterSetter>(vm.heap, sizeof(JSTestCustomGetterSetter))) JSTestCustomGetterSetter(vm, structure); |
997 | result->finishCreation(vm); |
998 | return result; |
999 | } |
1000 | |
1001 | void finishCreation(VM&); |
1002 | |
1003 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject) |
1004 | { |
1005 | return Structure::create(vm, globalObject, globalObject->objectPrototype(), TypeInfo(ObjectType, StructureFlags), info()); |
1006 | } |
1007 | |
1008 | DECLARE_INFO; |
1009 | }; |
1010 | |
1011 | |
1012 | static EncodedJSValue customGetAccessor(ExecState*, EncodedJSValue thisValue, PropertyName) |
1013 | { |
1014 | // Passed |this| |
1015 | return thisValue; |
1016 | } |
1017 | |
1018 | static EncodedJSValue customGetValue(ExecState* exec, EncodedJSValue slotValue, PropertyName) |
1019 | { |
1020 | RELEASE_ASSERT(JSValue::decode(slotValue).inherits<JSTestCustomGetterSetter>(exec->vm())); |
1021 | // Passed property holder. |
1022 | return slotValue; |
1023 | } |
1024 | |
1025 | static bool customSetAccessor(ExecState* exec, EncodedJSValue thisObject, EncodedJSValue encodedValue) |
1026 | { |
1027 | VM& vm = exec->vm(); |
1028 | |
1029 | JSValue value = JSValue::decode(encodedValue); |
1030 | RELEASE_ASSERT(value.isObject()); |
1031 | JSObject* object = asObject(value); |
1032 | PutPropertySlot slot(object); |
1033 | object->put(object, exec, Identifier::fromString(&vm, "result" ), JSValue::decode(thisObject), slot); |
1034 | |
1035 | return true; |
1036 | } |
1037 | |
1038 | static bool customSetValue(ExecState* exec, EncodedJSValue slotValue, EncodedJSValue encodedValue) |
1039 | { |
1040 | VM& vm = exec->vm(); |
1041 | |
1042 | RELEASE_ASSERT(JSValue::decode(slotValue).inherits<JSTestCustomGetterSetter>(exec->vm())); |
1043 | |
1044 | JSValue value = JSValue::decode(encodedValue); |
1045 | RELEASE_ASSERT(value.isObject()); |
1046 | JSObject* object = asObject(value); |
1047 | PutPropertySlot slot(object); |
1048 | object->put(object, exec, Identifier::fromString(&vm, "result" ), JSValue::decode(slotValue), slot); |
1049 | |
1050 | return true; |
1051 | } |
1052 | |
1053 | void JSTestCustomGetterSetter::finishCreation(VM& vm) |
1054 | { |
1055 | Base::finishCreation(vm); |
1056 | |
1057 | putDirectCustomAccessor(vm, Identifier::fromString(&vm, "customValue" ), |
1058 | CustomGetterSetter::create(vm, customGetValue, customSetValue), 0); |
1059 | putDirectCustomAccessor(vm, Identifier::fromString(&vm, "customAccessor" ), |
1060 | CustomGetterSetter::create(vm, customGetAccessor, customSetAccessor), static_cast<unsigned>(PropertyAttribute::CustomAccessor)); |
1061 | } |
1062 | |
1063 | const ClassInfo Element::s_info = { "Element" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(Element) }; |
1064 | const ClassInfo Root::s_info = { "Root" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(Root) }; |
1065 | const ClassInfo SimpleObject::s_info = { "SimpleObject" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(SimpleObject) }; |
1066 | const ClassInfo ImpureGetter::s_info = { "ImpureGetter" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(ImpureGetter) }; |
1067 | const ClassInfo CustomGetter::s_info = { "CustomGetter" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(CustomGetter) }; |
1068 | const ClassInfo RuntimeArray::s_info = { "RuntimeArray" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(RuntimeArray) }; |
1069 | #if ENABLE(JIT) |
1070 | const ClassInfo DOMJITNode::s_info = { "DOMJITNode" , &Base::s_info, nullptr, &DOMJITNode::checkSubClassSnippet, CREATE_METHOD_TABLE(DOMJITNode) }; |
1071 | #else |
1072 | const ClassInfo DOMJITNode::s_info = { "DOMJITNode" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DOMJITNode) }; |
1073 | #endif |
1074 | const ClassInfo DOMJITGetter::s_info = { "DOMJITGetter" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DOMJITGetter) }; |
1075 | const ClassInfo DOMJITGetterComplex::s_info = { "DOMJITGetterComplex" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DOMJITGetterComplex) }; |
1076 | const ClassInfo DOMJITGetterBaseJSObject::s_info = { "DOMJITGetterBaseJSObject" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DOMJITGetterBaseJSObject) }; |
1077 | #if ENABLE(JIT) |
1078 | const ClassInfo DOMJITFunctionObject::s_info = { "DOMJITFunctionObject" , &Base::s_info, nullptr, &DOMJITFunctionObject::checkSubClassSnippet, CREATE_METHOD_TABLE(DOMJITFunctionObject) }; |
1079 | #else |
1080 | const ClassInfo DOMJITFunctionObject::s_info = { "DOMJITFunctionObject" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DOMJITFunctionObject) }; |
1081 | #endif |
1082 | const ClassInfo DOMJITCheckSubClassObject::s_info = { "DOMJITCheckSubClassObject" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DOMJITCheckSubClassObject) }; |
1083 | const ClassInfo JSTestCustomGetterSetter::s_info = { "JSTestCustomGetterSetter" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTestCustomGetterSetter) }; |
1084 | |
1085 | ElementHandleOwner* Element::handleOwner() |
1086 | { |
1087 | static ElementHandleOwner* owner = 0; |
1088 | if (!owner) |
1089 | owner = new ElementHandleOwner(); |
1090 | return owner; |
1091 | } |
1092 | |
1093 | void Element::finishCreation(VM& vm, Root* root) |
1094 | { |
1095 | Base::finishCreation(vm); |
1096 | setRoot(vm, root); |
1097 | m_root->setElement(this); |
1098 | } |
1099 | |
1100 | #if ENABLE(WEBASSEMBLY) |
1101 | |
1102 | static EncodedJSValue JSC_HOST_CALL functionWasmStreamingParserAddBytes(ExecState*); |
1103 | static EncodedJSValue JSC_HOST_CALL functionWasmStreamingParserFinalize(ExecState*); |
1104 | |
1105 | class WasmStreamingParser : public JSDestructibleObject { |
1106 | public: |
1107 | WasmStreamingParser(VM& vm, Structure* structure) |
1108 | : Base(vm, structure) |
1109 | , m_info(Wasm::ModuleInformation::create()) |
1110 | , m_streamingParser(m_info.get()) |
1111 | { |
1112 | } |
1113 | |
1114 | using Base = JSDestructibleObject; |
1115 | |
1116 | static WasmStreamingParser* create(VM& vm, JSGlobalObject* globalObject) |
1117 | { |
1118 | Structure* structure = createStructure(vm, globalObject, jsNull()); |
1119 | WasmStreamingParser* result = new (NotNull, allocateCell<WasmStreamingParser>(vm.heap, sizeof(WasmStreamingParser))) WasmStreamingParser(vm, structure); |
1120 | result->finishCreation(vm); |
1121 | return result; |
1122 | } |
1123 | |
1124 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) |
1125 | { |
1126 | return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); |
1127 | } |
1128 | |
1129 | Wasm::StreamingParser& streamingParser() { return m_streamingParser; } |
1130 | |
1131 | void finishCreation(VM& vm) |
1132 | { |
1133 | Base::finishCreation(vm); |
1134 | |
1135 | JSGlobalObject* globalObject = this->globalObject(vm); |
1136 | putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "addBytes" ), 0, functionWasmStreamingParserAddBytes, NoIntrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum)); |
1137 | putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "finalize" ), 0, functionWasmStreamingParserFinalize, NoIntrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum)); |
1138 | } |
1139 | |
1140 | DECLARE_INFO; |
1141 | |
1142 | Ref<Wasm::ModuleInformation> m_info; |
1143 | Wasm::StreamingParser m_streamingParser; |
1144 | }; |
1145 | |
1146 | const ClassInfo WasmStreamingParser::s_info = { "WasmStreamingParser" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(WasmStreamingParser) }; |
1147 | |
1148 | EncodedJSValue JSC_HOST_CALL functionWasmStreamingParserAddBytes(ExecState* exec) |
1149 | { |
1150 | VM& vm = exec->vm(); |
1151 | auto scope = DECLARE_THROW_SCOPE(exec->vm()); |
1152 | auto* thisObject = jsDynamicCast<WasmStreamingParser*>(vm, exec->thisValue()); |
1153 | if (!thisObject) |
1154 | RELEASE_AND_RETURN(scope, JSValue::encode(jsBoolean(false))); |
1155 | |
1156 | auto data = getWasmBufferFromValue(exec, exec->argument(0)); |
1157 | RETURN_IF_EXCEPTION(scope, encodedJSValue()); |
1158 | RELEASE_AND_RETURN(scope, JSValue::encode(jsNumber(static_cast<int32_t>(thisObject->streamingParser().addBytes(bitwise_cast<const uint8_t*>(data.first), data.second))))); |
1159 | } |
1160 | |
1161 | EncodedJSValue JSC_HOST_CALL functionWasmStreamingParserFinalize(ExecState* exec) |
1162 | { |
1163 | VM& vm = exec->vm(); |
1164 | auto* thisObject = jsDynamicCast<WasmStreamingParser*>(vm, exec->thisValue()); |
1165 | if (!thisObject) |
1166 | return JSValue::encode(jsBoolean(false)); |
1167 | return JSValue::encode(jsNumber(static_cast<int32_t>(thisObject->streamingParser().finalize()))); |
1168 | } |
1169 | |
1170 | #endif |
1171 | |
1172 | } // namespace |
1173 | |
1174 | namespace JSC { |
1175 | |
1176 | const ClassInfo JSDollarVM::s_info = { "DollarVM" , &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDollarVM) }; |
1177 | |
1178 | // Triggers a crash immediately. |
1179 | // Usage: $vm.crash() |
1180 | static NO_RETURN_DUE_TO_CRASH EncodedJSValue JSC_HOST_CALL functionCrash(ExecState*) |
1181 | { |
1182 | CRASH(); |
1183 | } |
1184 | |
1185 | // Executes a breakpoint instruction if the first argument is truthy or is unset. |
1186 | // Usage: $vm.breakpoint(<condition>) |
1187 | static EncodedJSValue JSC_HOST_CALL functionBreakpoint(ExecState* exec) |
1188 | { |
1189 | // Nothing should throw here but we might as well double check... |
1190 | VM& vm = exec->vm(); |
1191 | auto scope = DECLARE_CATCH_SCOPE(vm); |
1192 | UNUSED_PARAM(scope); |
1193 | if (!exec->argumentCount() || exec->argument(0).toBoolean(exec)) |
1194 | WTFBreakpointTrap(); |
1195 | |
1196 | return encodedJSUndefined(); |
1197 | } |
1198 | |
1199 | // Returns true if the current frame is a DFG frame. |
1200 | // Usage: isDFG = $vm.dfgTrue() |
1201 | static EncodedJSValue JSC_HOST_CALL functionDFGTrue(ExecState*) |
1202 | { |
1203 | return JSValue::encode(jsBoolean(false)); |
1204 | } |
1205 | |
1206 | // Returns true if the current frame is a FTL frame. |
1207 | // Usage: isFTL = $vm.ftlTrue() |
1208 | static EncodedJSValue JSC_HOST_CALL functionFTLTrue(ExecState*) |
1209 | { |
1210 | return JSValue::encode(jsBoolean(false)); |
1211 | } |
1212 | |
1213 | static EncodedJSValue JSC_HOST_CALL functionCpuMfence(ExecState*) |
1214 | { |
1215 | #if CPU(X86_64) && !OS(WINDOWS) |
1216 | asm volatile("mfence" ::: "memory" ); |
1217 | #endif |
1218 | return JSValue::encode(jsUndefined()); |
1219 | } |
1220 | |
1221 | static EncodedJSValue JSC_HOST_CALL functionCpuRdtsc(ExecState*) |
1222 | { |
1223 | #if CPU(X86_64) && !OS(WINDOWS) |
1224 | unsigned high; |
1225 | unsigned low; |
1226 | asm volatile ("rdtsc" : "=a" (low), "=d" (high)); |
1227 | return JSValue::encode(jsNumber(low)); |
1228 | #else |
1229 | return JSValue::encode(jsNumber(0)); |
1230 | #endif |
1231 | } |
1232 | |
1233 | static EncodedJSValue JSC_HOST_CALL functionCpuCpuid(ExecState*) |
1234 | { |
1235 | #if CPU(X86_64) && !OS(WINDOWS) |
1236 | WTF::x86_cpuid(); |
1237 | #endif |
1238 | return JSValue::encode(jsUndefined()); |
1239 | } |
1240 | |
1241 | static EncodedJSValue JSC_HOST_CALL functionCpuPause(ExecState*) |
1242 | { |
1243 | #if CPU(X86_64) && !OS(WINDOWS) |
1244 | asm volatile ("pause" ::: "memory" ); |
1245 | #endif |
1246 | return JSValue::encode(jsUndefined()); |
1247 | } |
1248 | |
1249 | // This takes either a JSArrayBuffer, JSArrayBufferView*, or any other object as its first |
1250 | // argument. The second argument is expected to be an integer. |
1251 | // |
1252 | // If the first argument is a JSArrayBuffer, it'll clflush on that buffer |
1253 | // plus the second argument as a byte offset. It'll also flush on the object |
1254 | // itself so its length, etc, aren't in the cache. |
1255 | // |
1256 | // If the first argument is not a JSArrayBuffer, we load the butterfly |
1257 | // and clflush at the address of the butterfly. |
1258 | static EncodedJSValue JSC_HOST_CALL functionCpuClflush(ExecState* exec) |
1259 | { |
1260 | #if CPU(X86_64) && !OS(WINDOWS) |
1261 | VM& vm = exec->vm(); |
1262 | |
1263 | if (!exec->argument(1).isInt32()) |
1264 | return JSValue::encode(jsBoolean(false)); |
1265 | |
1266 | auto clflush = [] (void* ptr) { |
1267 | char* ptrToFlush = static_cast<char*>(ptr); |
1268 | asm volatile ("clflush %0" :: "m" (*ptrToFlush) : "memory" ); |
1269 | }; |
1270 | |
1271 | Vector<void*> toFlush; |
1272 | |
1273 | uint32_t offset = exec->argument(1).asUInt32(); |
1274 | |
1275 | if (JSArrayBufferView* view = jsDynamicCast<JSArrayBufferView*>(vm, exec->argument(0))) |
1276 | toFlush.append(bitwise_cast<char*>(view->vector()) + offset); |
1277 | else if (JSObject* object = jsDynamicCast<JSObject*>(vm, exec->argument(0))) { |
1278 | switch (object->indexingType()) { |
1279 | case ALL_INT32_INDEXING_TYPES: |
1280 | case ALL_CONTIGUOUS_INDEXING_TYPES: |
1281 | case ALL_DOUBLE_INDEXING_TYPES: |
1282 | toFlush.append(bitwise_cast<char*>(object->butterfly()) + Butterfly::offsetOfVectorLength()); |
1283 | toFlush.append(bitwise_cast<char*>(object->butterfly()) + Butterfly::offsetOfPublicLength()); |
1284 | } |
1285 | } |
1286 | |
1287 | if (!toFlush.size()) |
1288 | return JSValue::encode(jsBoolean(false)); |
1289 | |
1290 | for (void* ptr : toFlush) |
1291 | clflush(ptr); |
1292 | return JSValue::encode(jsBoolean(true)); |
1293 | #else |
1294 | UNUSED_PARAM(exec); |
1295 | return JSValue::encode(jsBoolean(false)); |
1296 | #endif |
1297 | } |
1298 | |
1299 | class CallerFrameJITTypeFunctor { |
1300 | public: |
1301 | CallerFrameJITTypeFunctor() |
1302 | : m_currentFrame(0) |
1303 | , m_jitType(JITType::None) |
1304 | { |
1305 | } |
1306 | |
1307 | StackVisitor::Status operator()(StackVisitor& visitor) const |
1308 | { |
1309 | if (m_currentFrame++ > 1) { |
1310 | m_jitType = visitor->codeBlock()->jitType(); |
1311 | return StackVisitor::Done; |
1312 | } |
1313 | return StackVisitor::Continue; |
1314 | } |
1315 | |
1316 | JITType jitType() { return m_jitType; } |
1317 | |
1318 | private: |
1319 | mutable unsigned m_currentFrame; |
1320 | mutable JITType m_jitType; |
1321 | }; |
1322 | |
1323 | static FunctionExecutable* getExecutableForFunction(JSValue theFunctionValue) |
1324 | { |
1325 | if (!theFunctionValue.isCell()) |
1326 | return nullptr; |
1327 | |
1328 | VM& vm = *theFunctionValue.asCell()->vm(); |
1329 | JSFunction* theFunction = jsDynamicCast<JSFunction*>(vm, theFunctionValue); |
1330 | if (!theFunction) |
1331 | return nullptr; |
1332 | |
1333 | FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>(vm, |
1334 | theFunction->executable()); |
1335 | |
1336 | return executable; |
1337 | } |
1338 | |
1339 | // Returns true if the current frame is a LLInt frame. |
1340 | // Usage: isLLInt = $vm.llintTrue() |
1341 | static EncodedJSValue JSC_HOST_CALL functionLLintTrue(ExecState* exec) |
1342 | { |
1343 | if (!exec) |
1344 | return JSValue::encode(jsUndefined()); |
1345 | CallerFrameJITTypeFunctor functor; |
1346 | exec->iterate(functor); |
1347 | return JSValue::encode(jsBoolean(functor.jitType() == JITType::InterpreterThunk)); |
1348 | } |
1349 | |
1350 | // Returns true if the current frame is a baseline JIT frame. |
1351 | // Usage: isBaselineJIT = $vm.jitTrue() |
1352 | static EncodedJSValue JSC_HOST_CALL functionJITTrue(ExecState* exec) |
1353 | { |
1354 | if (!exec) |
1355 | return JSValue::encode(jsUndefined()); |
1356 | CallerFrameJITTypeFunctor functor; |
1357 | exec->iterate(functor); |
1358 | return JSValue::encode(jsBoolean(functor.jitType() == JITType::BaselineJIT)); |
1359 | } |
1360 | |
1361 | // Set that the argument function should not be inlined. |
1362 | // Usage: |
1363 | // function f() { }; |
1364 | // $vm.noInline(f); |
1365 | static EncodedJSValue JSC_HOST_CALL functionNoInline(ExecState* exec) |
1366 | { |
1367 | if (exec->argumentCount() < 1) |
1368 | return JSValue::encode(jsUndefined()); |
1369 | |
1370 | JSValue theFunctionValue = exec->uncheckedArgument(0); |
1371 | |
1372 | if (FunctionExecutable* executable = getExecutableForFunction(theFunctionValue)) |
1373 | executable->setNeverInline(true); |
1374 | |
1375 | return JSValue::encode(jsUndefined()); |
1376 | } |
1377 | |
1378 | // Runs a full GC synchronously. |
1379 | // Usage: $vm.gc() |
1380 | static EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec) |
1381 | { |
1382 | VMInspector::gc(exec); |
1383 | return JSValue::encode(jsUndefined()); |
1384 | } |
1385 | |
1386 | // Runs the edenGC synchronously. |
1387 | // Usage: $vm.edenGC() |
1388 | static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec) |
1389 | { |
1390 | VMInspector::edenGC(exec); |
1391 | return JSValue::encode(jsUndefined()); |
1392 | } |
1393 | |
1394 | // Gets a JSDollarVMCallFrame for a specified frame index. |
1395 | // Usage: var callFrame = $vm.callFrame(0) // frame 0 is the top frame. |
1396 | // Usage: var callFrame = $vm.callFrame() // implies frame 0 i.e. current frame. |
1397 | // |
1398 | // This gives you the ability to query the following: |
1399 | // callFrame.valid; // false if we asked for a frame beyond the end of the stack, else true. |
1400 | // callFrame.callee; |
1401 | // callFrame.codeBlock; |
1402 | // callFrame.unlinkedCodeBlock; |
1403 | // callFrame.executable; |
1404 | // |
1405 | // Note: you cannot toString() a codeBlock, unlinkedCodeBlock, or executable because |
1406 | // there are internal objects and not a JS object. Hence, you cannot do string |
1407 | // concatenation with them. |
1408 | static EncodedJSValue JSC_HOST_CALL functionCallFrame(ExecState* exec) |
1409 | { |
1410 | unsigned = 1; |
1411 | if (exec->argumentCount() >= 1) { |
1412 | JSValue value = exec->uncheckedArgument(0); |
1413 | if (!value.isUInt32()) |
1414 | return JSValue::encode(jsUndefined()); |
1415 | |
1416 | // We need to inc the frame number because the caller would consider |
1417 | // its own frame as frame 0. Hence, we need discount the frame for this |
1418 | // function. |
1419 | frameNumber = value.asUInt32() + 1; |
1420 | } |
1421 | |
1422 | return JSValue::encode(JSDollarVMCallFrame::create(exec, frameNumber)); |
1423 | } |
1424 | |
1425 | // Gets a token for the CodeBlock for a specified frame index. |
1426 | // Usage: codeBlockToken = $vm.codeBlockForFrame(0) // frame 0 is the top frame. |
1427 | // Usage: codeBlockToken = $vm.codeBlockForFrame() // implies frame 0 i.e. current frame. |
1428 | static EncodedJSValue JSC_HOST_CALL functionCodeBlockForFrame(ExecState* exec) |
1429 | { |
1430 | unsigned = 1; |
1431 | if (exec->argumentCount() >= 1) { |
1432 | JSValue value = exec->uncheckedArgument(0); |
1433 | if (!value.isUInt32()) |
1434 | return JSValue::encode(jsUndefined()); |
1435 | |
1436 | // We need to inc the frame number because the caller would consider |
1437 | // its own frame as frame 0. Hence, we need discount the frame for this |
1438 | // function. |
1439 | frameNumber = value.asUInt32() + 1; |
1440 | } |
1441 | |
1442 | CodeBlock* codeBlock = VMInspector::codeBlockForFrame(exec, frameNumber); |
1443 | if (codeBlock) |
1444 | return JSValue::encode(codeBlock); |
1445 | return JSValue::encode(jsUndefined()); |
1446 | } |
1447 | |
1448 | static CodeBlock* codeBlockFromArg(ExecState* exec) |
1449 | { |
1450 | VM& vm = exec->vm(); |
1451 | if (exec->argumentCount() < 1) |
1452 | return nullptr; |
1453 | |
1454 | JSValue value = exec->uncheckedArgument(0); |
1455 | CodeBlock* candidateCodeBlock = nullptr; |
1456 | if (value.isCell()) { |
1457 | JSFunction* func = jsDynamicCast<JSFunction*>(vm, value.asCell()); |
1458 | if (func) { |
1459 | if (func->isHostFunction()) |
1460 | candidateCodeBlock = nullptr; |
1461 | else |
1462 | candidateCodeBlock = func->jsExecutable()->eitherCodeBlock(); |
1463 | } else |
1464 | candidateCodeBlock = static_cast<CodeBlock*>(value.asCell()); |
1465 | } |
1466 | |
1467 | if (candidateCodeBlock && VMInspector::isValidCodeBlock(exec, candidateCodeBlock)) |
1468 | return candidateCodeBlock; |
1469 | |
1470 | if (candidateCodeBlock) |
1471 | dataLog("Invalid codeBlock: " , RawPointer(candidateCodeBlock), " " , value, "\n" ); |
1472 | else |
1473 | dataLog("Invalid codeBlock: " , value, "\n" ); |
1474 | return nullptr; |
1475 | } |
1476 | |
1477 | // Usage: $vm.print("codeblock = ", $vm.codeBlockFor(functionObj)) |
1478 | // Usage: $vm.print("codeblock = ", $vm.codeBlockFor(codeBlockToken)) |
1479 | // Note: you cannot toString() a codeBlock because it's an internal object and not |
1480 | // a JS object. Hence, you cannot do string concatenation with it. |
1481 | static EncodedJSValue JSC_HOST_CALL functionCodeBlockFor(ExecState* exec) |
1482 | { |
1483 | CodeBlock* codeBlock = codeBlockFromArg(exec); |
1484 | WTF::StringPrintStream stream; |
1485 | if (codeBlock) { |
1486 | stream.print(*codeBlock); |
1487 | return JSValue::encode(jsString(exec, stream.toString())); |
1488 | } |
1489 | return JSValue::encode(jsUndefined()); |
1490 | } |
1491 | |
1492 | // Usage: $vm.dumpSourceFor(functionObj) |
1493 | // Usage: $vm.dumpSourceFor(codeBlockToken) |
1494 | static EncodedJSValue JSC_HOST_CALL functionDumpSourceFor(ExecState* exec) |
1495 | { |
1496 | CodeBlock* codeBlock = codeBlockFromArg(exec); |
1497 | if (codeBlock) |
1498 | codeBlock->dumpSource(); |
1499 | return JSValue::encode(jsUndefined()); |
1500 | } |
1501 | |
1502 | // Usage: $vm.dumpBytecodeFor(functionObj) |
1503 | // Usage: $vm.dumpBytecodeFor(codeBlock) |
1504 | static EncodedJSValue JSC_HOST_CALL functionDumpBytecodeFor(ExecState* exec) |
1505 | { |
1506 | CodeBlock* codeBlock = codeBlockFromArg(exec); |
1507 | if (codeBlock) |
1508 | codeBlock->dumpBytecode(); |
1509 | return JSValue::encode(jsUndefined()); |
1510 | } |
1511 | |
1512 | static EncodedJSValue doPrint(ExecState* exec, bool addLineFeed) |
1513 | { |
1514 | auto scope = DECLARE_THROW_SCOPE(exec->vm()); |
1515 | for (unsigned i = 0; i < exec->argumentCount(); ++i) { |
1516 | JSValue arg = exec->uncheckedArgument(i); |
1517 | if (arg.isCell() |
1518 | && !arg.isObject() |
1519 | && !arg.isString() |
1520 | && !arg.isBigInt()) { |
1521 | dataLog(arg); |
1522 | continue; |
1523 | } |
1524 | String argStr = exec->uncheckedArgument(i).toWTFString(exec); |
1525 | RETURN_IF_EXCEPTION(scope, encodedJSValue()); |
1526 | dataLog(argStr); |
1527 | } |
1528 | if (addLineFeed) |
1529 | dataLog("\n" ); |
1530 | return JSValue::encode(jsUndefined()); |
1531 | } |
1532 | |
1533 | // Prints a series of comma separate strings without appending a newline. |
1534 | // Usage: $vm.dataLog(str1, str2, str3) |
1535 | static EncodedJSValue JSC_HOST_CALL functionDataLog(ExecState* exec) |
1536 | { |
1537 | const bool addLineFeed = false; |
1538 | return doPrint(exec, addLineFeed); |
1539 | } |
1540 | |
1541 | // Prints a series of comma separate strings and appends a newline. |
1542 | // Usage: $vm.print(str1, str2, str3) |
1543 | static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec) |
1544 | { |
1545 | const bool addLineFeed = true; |
1546 | return doPrint(exec, addLineFeed); |
1547 | } |
1548 | |
1549 | // Dumps the current CallFrame. |
1550 | // Usage: $vm.dumpCallFrame() |
1551 | static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec) |
1552 | { |
1553 | // When the callers call this function, they are expecting to dump their |
1554 | // own frame. So skip 1 for this frame. |
1555 | VMInspector::dumpCallFrame(exec, 1); |
1556 | return JSValue::encode(jsUndefined()); |
1557 | } |
1558 | |
1559 | // Dumps the JS stack. |
1560 | // Usage: $vm.printStack() |
1561 | static EncodedJSValue JSC_HOST_CALL functionDumpStack(ExecState* exec) |
1562 | { |
1563 | // When the callers call this function, they are expecting to dump the |
1564 | // stack starting their own frame. So skip 1 for this frame. |
1565 | VMInspector::dumpStack(exec, 1); |
1566 | return JSValue::encode(jsUndefined()); |
1567 | } |
1568 | |
1569 | // Dumps the current CallFrame. |
1570 | // Usage: $vm.dumpRegisters(N) // dump the registers of the Nth CallFrame. |
1571 | // Usage: $vm.dumpRegisters() // dump the registers of the current CallFrame. |
1572 | // FIXME: Currently, this function dumps the physical frame. We should make |
1573 | // it dump the logical frame (i.e. be able to dump inlined frames as well). |
1574 | static EncodedJSValue JSC_HOST_CALL functionDumpRegisters(ExecState* exec) |
1575 | { |
1576 | unsigned requestedFrameIndex = 1; |
1577 | if (exec->argumentCount() >= 1) { |
1578 | JSValue value = exec->uncheckedArgument(0); |
1579 | if (!value.isUInt32()) |
1580 | return JSValue::encode(jsUndefined()); |
1581 | |
1582 | // We need to inc the frame number because the caller would consider |
1583 | // its own frame as frame 0. Hence, we need discount the frame for this |
1584 | // function. |
1585 | requestedFrameIndex = value.asUInt32() + 1; |
1586 | } |
1587 | |
1588 | unsigned frameIndex = 0; |
1589 | exec->iterate([&] (StackVisitor& visitor) { |
1590 | if (frameIndex++ != requestedFrameIndex) |
1591 | return StackVisitor::Continue; |
1592 | VMInspector::dumpRegisters(visitor->callFrame()); |
1593 | return StackVisitor::Done; |
1594 | }); |
1595 | |
1596 | return encodedJSUndefined(); |
1597 | } |
1598 | |
1599 | // Dumps the internal memory layout of a JSCell. |
1600 | // Usage: $vm.dumpCell(cell) |
1601 | static EncodedJSValue JSC_HOST_CALL functionDumpCell(ExecState* exec) |
1602 | { |
1603 | JSValue value = exec->argument(0); |
1604 | if (!value.isCell()) |
1605 | return encodedJSUndefined(); |
1606 | |
1607 | VMInspector::dumpCellMemory(value.asCell()); |
1608 | return encodedJSUndefined(); |
1609 | } |
1610 | |
1611 | // Gets the dataLog dump of the indexingMode of the passed value. |
1612 | // Usage: $vm.print("indexingMode = " + $vm.indexingMode(jsValue)) |
1613 | static EncodedJSValue JSC_HOST_CALL functionIndexingMode(ExecState* exec) |
1614 | { |
1615 | if (!exec->argument(0).isObject()) |
1616 | return encodedJSUndefined(); |
1617 | |
1618 | WTF::StringPrintStream stream; |
1619 | stream.print(IndexingTypeDump(exec->uncheckedArgument(0).getObject()->indexingMode())); |
1620 | return JSValue::encode(jsString(exec, stream.toString())); |
1621 | } |
1622 | |
1623 | static EncodedJSValue JSC_HOST_CALL functionInlineCapacity(ExecState* exec) |
1624 | { |
1625 | VM& vm = exec->vm(); |
1626 | if (auto* object = jsDynamicCast<JSObject*>(vm, exec->argument(0))) |
1627 | return JSValue::encode(jsNumber(object->structure(vm)->inlineCapacity())); |
1628 | |
1629 | return encodedJSUndefined(); |
1630 | } |
1631 | |
1632 | // Gets the dataLog dump of a given JS value as a string. |
1633 | // Usage: $vm.print("value = " + $vm.value(jsValue)) |
1634 | static EncodedJSValue JSC_HOST_CALL functionValue(ExecState* exec) |
1635 | { |
1636 | WTF::StringPrintStream stream; |
1637 | for (unsigned i = 0; i < exec->argumentCount(); ++i) { |
1638 | if (i) |
1639 | stream.print(", " ); |
1640 | stream.print(exec->uncheckedArgument(i)); |
1641 | } |
1642 | |
1643 | return JSValue::encode(jsString(exec, stream.toString())); |
1644 | } |
1645 | |
1646 | // Gets the pid of the current process. |
1647 | // Usage: $vm.print("pid = " + $vm.getpid()) |
1648 | static EncodedJSValue JSC_HOST_CALL functionGetPID(ExecState*) |
1649 | { |
1650 | return JSValue::encode(jsNumber(getCurrentProcessID())); |
1651 | } |
1652 | |
1653 | // Make the globalObject have a bad time. Does nothing if the object is not a JSGlobalObject. |
1654 | // Usage: $vm.haveABadTime(globalObject) |
1655 | static EncodedJSValue JSC_HOST_CALL functionHaveABadTime(ExecState* exec) |
1656 | { |
1657 | VM& vm = exec->vm(); |
1658 | JSLockHolder lock(vm); |
1659 | JSValue objValue = exec->argument(0); |
1660 | if (!objValue.isObject()) |
1661 | return JSValue::encode(jsBoolean(false)); |
1662 | |
1663 | JSObject* obj = asObject(objValue.asCell()); |
1664 | JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(vm, obj); |
1665 | if (!globalObject) |
1666 | JSValue::encode(jsBoolean(false)); |
1667 | |
1668 | globalObject->haveABadTime(vm); |
1669 | return JSValue::encode(jsBoolean(true)); |
1670 | } |
1671 | |
1672 | // Checks if the object (or its global if the object is not a global) is having a bad time. |
1673 | // Usage: $vm.isHavingABadTime(obj) |
1674 | static EncodedJSValue JSC_HOST_CALL functionIsHavingABadTime(ExecState* exec) |
1675 | { |
1676 | VM& vm = exec->vm(); |
1677 | JSLockHolder lock(vm); |
1678 | JSValue objValue = exec->argument(0); |
1679 | if (!objValue.isObject()) |
1680 | return JSValue::encode(jsUndefined()); |
1681 | |
1682 | JSObject* obj = asObject(objValue.asCell()); |
1683 | JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(vm, obj); |
1684 | if (globalObject) |
1685 | JSValue::encode(jsBoolean(globalObject->isHavingABadTime())); |
1686 | |
1687 | globalObject = obj->globalObject(); |
1688 | if (!globalObject) |
1689 | return JSValue::encode(jsUndefined()); |
1690 | |
1691 | return JSValue::encode(jsBoolean(globalObject->isHavingABadTime())); |
1692 | } |
1693 | |
1694 | // Creates a new global object. |
1695 | // Usage: $vm.createGlobalObject() |
1696 | static EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState* exec) |
1697 | { |
1698 | VM& vm = exec->vm(); |
1699 | JSLockHolder lock(vm); |
1700 | JSGlobalObject* globalObject = JSGlobalObject::create(vm, JSGlobalObject::createStructure(vm, jsNull())); |
1701 | return JSValue::encode(globalObject); |
1702 | } |
1703 | |
1704 | static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState* exec) |
1705 | { |
1706 | VM& vm = exec->vm(); |
1707 | JSLockHolder lock(vm); |
1708 | JSValue target = exec->argument(0); |
1709 | if (!target.isObject()) |
1710 | return JSValue::encode(jsUndefined()); |
1711 | JSObject* jsTarget = asObject(target.asCell()); |
1712 | Structure* structure = JSProxy::createStructure(vm, exec->lexicalGlobalObject(), jsTarget->getPrototypeDirect(vm), ImpureProxyType); |
1713 | JSProxy* proxy = JSProxy::create(vm, structure, jsTarget); |
1714 | return JSValue::encode(proxy); |
1715 | } |
1716 | |
1717 | static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState* exec) |
1718 | { |
1719 | JSLockHolder lock(exec); |
1720 | RuntimeArray* array = RuntimeArray::create(exec); |
1721 | return JSValue::encode(array); |
1722 | } |
1723 | |
1724 | static EncodedJSValue JSC_HOST_CALL functionCreateNullRopeString(ExecState* exec) |
1725 | { |
1726 | VM& vm = exec->vm(); |
1727 | JSLockHolder lock(vm); |
1728 | return JSValue::encode(JSRopeString::createNullForTesting(vm)); |
1729 | } |
1730 | |
1731 | static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState* exec) |
1732 | { |
1733 | VM& vm = exec->vm(); |
1734 | JSLockHolder lock(vm); |
1735 | JSValue target = exec->argument(0); |
1736 | JSObject* delegate = nullptr; |
1737 | if (target.isObject()) |
1738 | delegate = asObject(target.asCell()); |
1739 | Structure* structure = ImpureGetter::createStructure(vm, exec->lexicalGlobalObject(), jsNull()); |
1740 | ImpureGetter* result = ImpureGetter::create(vm, structure, delegate); |
1741 | return JSValue::encode(result); |
1742 | } |
1743 | |
1744 | static EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState* exec) |
1745 | { |
1746 | VM& vm = exec->vm(); |
1747 | JSLockHolder lock(vm); |
1748 | Structure* structure = CustomGetter::createStructure(vm, exec->lexicalGlobalObject(), jsNull()); |
1749 | CustomGetter* result = CustomGetter::create(vm, structure); |
1750 | return JSValue::encode(result); |
1751 | } |
1752 | |
1753 | static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState* exec) |
1754 | { |
1755 | VM& vm = exec->vm(); |
1756 | JSLockHolder lock(vm); |
1757 | Structure* structure = DOMJITNode::createStructure(vm, exec->lexicalGlobalObject(), DOMJITGetter::create(vm, DOMJITGetter::createStructure(vm, exec->lexicalGlobalObject(), jsNull()))); |
1758 | DOMJITNode* result = DOMJITNode::create(vm, structure); |
1759 | return JSValue::encode(result); |
1760 | } |
1761 | |
1762 | static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState* exec) |
1763 | { |
1764 | VM& vm = exec->vm(); |
1765 | JSLockHolder lock(vm); |
1766 | Structure* structure = DOMJITGetter::createStructure(vm, exec->lexicalGlobalObject(), jsNull()); |
1767 | DOMJITGetter* result = DOMJITGetter::create(vm, structure); |
1768 | return JSValue::encode(result); |
1769 | } |
1770 | |
1771 | static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterComplexObject(ExecState* exec) |
1772 | { |
1773 | VM& vm = exec->vm(); |
1774 | JSLockHolder lock(vm); |
1775 | Structure* structure = DOMJITGetterComplex::createStructure(vm, exec->lexicalGlobalObject(), jsNull()); |
1776 | DOMJITGetterComplex* result = DOMJITGetterComplex::create(vm, exec->lexicalGlobalObject(), structure); |
1777 | return JSValue::encode(result); |
1778 | } |
1779 | |
1780 | static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITFunctionObject(ExecState* exec) |
1781 | { |
1782 | VM& vm = exec->vm(); |
1783 | JSLockHolder lock(vm); |
1784 | Structure* structure = DOMJITFunctionObject::createStructure(vm, exec->lexicalGlobalObject(), jsNull()); |
1785 | DOMJITFunctionObject* result = DOMJITFunctionObject::create(vm, exec->lexicalGlobalObject(), structure); |
1786 | return JSValue::encode(result); |
1787 | } |
1788 | |
1789 | static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITCheckSubClassObject(ExecState* exec) |
1790 | { |
1791 | VM& vm = exec->vm(); |
1792 | JSLockHolder lock(vm); |
1793 | Structure* structure = DOMJITCheckSubClassObject::createStructure(vm, exec->lexicalGlobalObject(), jsNull()); |
1794 | DOMJITCheckSubClassObject* result = DOMJITCheckSubClassObject::create(vm, exec->lexicalGlobalObject(), structure); |
1795 | return JSValue::encode(result); |
1796 | } |
1797 | |
1798 | static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterBaseJSObject(ExecState* exec) |
1799 | { |
1800 | VM& vm = exec->vm(); |
1801 | JSLockHolder lock(vm); |
1802 | Structure* structure = DOMJITGetterBaseJSObject::createStructure(vm, exec->lexicalGlobalObject(), jsNull()); |
1803 | DOMJITGetterBaseJSObject* result = DOMJITGetterBaseJSObject::create(vm, structure); |
1804 | return JSValue::encode(result); |
1805 | } |
1806 | |
1807 | #if ENABLE(WEBASSEMBLY) |
1808 | static EncodedJSValue JSC_HOST_CALL functionCreateWasmStreamingParser(ExecState* exec) |
1809 | { |
1810 | VM& vm = exec->vm(); |
1811 | JSLockHolder lock(vm); |
1812 | return JSValue::encode(WasmStreamingParser::create(vm, exec->lexicalGlobalObject())); |
1813 | } |
1814 | #endif |
1815 | |
1816 | static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec) |
1817 | { |
1818 | VM& vm = exec->vm(); |
1819 | JSLockHolder lock(vm); |
1820 | auto scope = DECLARE_THROW_SCOPE(vm); |
1821 | |
1822 | JSValue base = exec->argument(0); |
1823 | if (!base.isObject()) |
1824 | return JSValue::encode(jsUndefined()); |
1825 | JSValue delegate = exec->argument(1); |
1826 | if (!delegate.isObject()) |
1827 | return JSValue::encode(jsUndefined()); |
1828 | ImpureGetter* impureGetter = jsDynamicCast<ImpureGetter*>(vm, asObject(base.asCell())); |
1829 | if (UNLIKELY(!impureGetter)) { |
1830 | throwTypeError(exec, scope, "argument is not an ImpureGetter"_s ); |
1831 | return encodedJSValue(); |
1832 | } |
1833 | impureGetter->setDelegate(vm, asObject(delegate.asCell())); |
1834 | return JSValue::encode(jsUndefined()); |
1835 | } |
1836 | |
1837 | static EncodedJSValue JSC_HOST_CALL functionCreateBuiltin(ExecState* exec) |
1838 | { |
1839 | VM& vm = exec->vm(); |
1840 | auto scope = DECLARE_THROW_SCOPE(vm); |
1841 | |
1842 | if (exec->argumentCount() < 1 || !exec->argument(0).isString()) |
1843 | return JSValue::encode(jsUndefined()); |
1844 | |
1845 | String functionText = asString(exec->argument(0))->value(exec); |
1846 | RETURN_IF_EXCEPTION(scope, encodedJSValue()); |
1847 | |
1848 | const SourceCode& source = makeSource(functionText, { }); |
1849 | JSFunction* func = JSFunction::create(vm, createBuiltinExecutable(vm, source, Identifier::fromString(&vm, "foo" ), ConstructorKind::None, ConstructAbility::CannotConstruct)->link(vm, nullptr, source), exec->lexicalGlobalObject()); |
1850 | |
1851 | return JSValue::encode(func); |
1852 | } |
1853 | |
1854 | static EncodedJSValue JSC_HOST_CALL functionGetPrivateProperty(ExecState* exec) |
1855 | { |
1856 | VM& vm = exec->vm(); |
1857 | auto scope = DECLARE_THROW_SCOPE(vm); |
1858 | |
1859 | if (exec->argumentCount() < 2 || !exec->argument(1).isString()) |
1860 | return encodedJSUndefined(); |
1861 | |
1862 | String str = asString(exec->argument(1))->value(exec); |
1863 | |
1864 | SymbolImpl* symbol = vm.propertyNames->lookUpPrivateName(Identifier::fromString(exec, str)); |
1865 | if (!symbol) |
1866 | return throwVMError(exec, scope, "Unknown private name." ); |
1867 | |
1868 | RELEASE_AND_RETURN(scope, JSValue::encode(exec->argument(0).get(exec, symbol))); |
1869 | } |
1870 | |
1871 | static EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState* exec) |
1872 | { |
1873 | VM& vm = exec->vm(); |
1874 | JSLockHolder lock(vm); |
1875 | return JSValue::encode(Root::create(vm, exec->lexicalGlobalObject())); |
1876 | } |
1877 | |
1878 | static EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState* exec) |
1879 | { |
1880 | VM& vm = exec->vm(); |
1881 | JSLockHolder lock(vm); |
1882 | auto scope = DECLARE_THROW_SCOPE(vm); |
1883 | |
1884 | Root* root = jsDynamicCast<Root*>(vm, exec->argument(0)); |
1885 | if (!root) |
1886 | return JSValue::encode(throwException(exec, scope, createError(exec, "Cannot create Element without a Root."_s ))); |
1887 | return JSValue::encode(Element::create(vm, exec->lexicalGlobalObject(), root)); |
1888 | } |
1889 | |
1890 | static EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState* exec) |
1891 | { |
1892 | VM& vm = exec->vm(); |
1893 | JSLockHolder lock(vm); |
1894 | Root* root = jsDynamicCast<Root*>(vm, exec->argument(0)); |
1895 | if (!root) |
1896 | return JSValue::encode(jsUndefined()); |
1897 | Element* result = root->element(); |
1898 | return JSValue::encode(result ? result : jsUndefined()); |
1899 | } |
1900 | |
1901 | static EncodedJSValue JSC_HOST_CALL functionCreateSimpleObject(ExecState* exec) |
1902 | { |
1903 | VM& vm = exec->vm(); |
1904 | JSLockHolder lock(vm); |
1905 | return JSValue::encode(SimpleObject::create(vm, exec->lexicalGlobalObject())); |
1906 | } |
1907 | |
1908 | static EncodedJSValue JSC_HOST_CALL functionGetHiddenValue(ExecState* exec) |
1909 | { |
1910 | VM& vm = exec->vm(); |
1911 | JSLockHolder lock(vm); |
1912 | auto scope = DECLARE_THROW_SCOPE(vm); |
1913 | |
1914 | SimpleObject* simpleObject = jsDynamicCast<SimpleObject*>(vm, exec->argument(0)); |
1915 | if (UNLIKELY(!simpleObject)) { |
1916 | throwTypeError(exec, scope, "Invalid use of getHiddenValue test function"_s ); |
1917 | return encodedJSValue(); |
1918 | } |
1919 | return JSValue::encode(simpleObject->hiddenValue()); |
1920 | } |
1921 | |
1922 | static EncodedJSValue JSC_HOST_CALL functionSetHiddenValue(ExecState* exec) |
1923 | { |
1924 | VM& vm = exec->vm(); |
1925 | JSLockHolder lock(vm); |
1926 | auto scope = DECLARE_THROW_SCOPE(vm); |
1927 | |
1928 | SimpleObject* simpleObject = jsDynamicCast<SimpleObject*>(vm, exec->argument(0)); |
1929 | if (UNLIKELY(!simpleObject)) { |
1930 | throwTypeError(exec, scope, "Invalid use of setHiddenValue test function"_s ); |
1931 | return encodedJSValue(); |
1932 | } |
1933 | JSValue value = exec->argument(1); |
1934 | simpleObject->setHiddenValue(vm, value); |
1935 | return JSValue::encode(jsUndefined()); |
1936 | } |
1937 | |
1938 | static EncodedJSValue JSC_HOST_CALL functionShadowChickenFunctionsOnStack(ExecState* exec) |
1939 | { |
1940 | VM& vm = exec->vm(); |
1941 | auto scope = DECLARE_THROW_SCOPE(vm); |
1942 | if (auto* shadowChicken = vm.shadowChicken()) { |
1943 | scope.release(); |
1944 | return JSValue::encode(shadowChicken->functionsOnStack(exec)); |
1945 | } |
1946 | |
1947 | JSArray* result = constructEmptyArray(exec, 0); |
1948 | RETURN_IF_EXCEPTION(scope, { }); |
1949 | StackVisitor::visit(exec, &vm, [&] (StackVisitor& visitor) -> StackVisitor::Status { |
1950 | if (visitor->isInlinedFrame()) |
1951 | return StackVisitor::Continue; |
1952 | if (visitor->isWasmFrame()) |
1953 | return StackVisitor::Continue; |
1954 | result->push(exec, jsCast<JSObject*>(visitor->callee().asCell())); |
1955 | scope.releaseAssertNoException(); // This function is only called from tests. |
1956 | return StackVisitor::Continue; |
1957 | }); |
1958 | RETURN_IF_EXCEPTION(scope, { }); |
1959 | return JSValue::encode(result); |
1960 | } |
1961 | |
1962 | static EncodedJSValue JSC_HOST_CALL functionSetGlobalConstRedeclarationShouldNotThrow(ExecState* exec) |
1963 | { |
1964 | VM& vm = exec->vm(); |
1965 | vm.setGlobalConstRedeclarationShouldThrow(false); |
1966 | return JSValue::encode(jsUndefined()); |
1967 | } |
1968 | |
1969 | static EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState* exec) |
1970 | { |
1971 | VM& vm = exec->vm(); |
1972 | RELEASE_ASSERT(vm.typeProfiler()); |
1973 | vm.typeProfilerLog()->processLogEntries(vm, "jsc Testing API: functionFindTypeForExpression"_s ); |
1974 | |
1975 | JSValue functionValue = exec->argument(0); |
1976 | RELEASE_ASSERT(functionValue.isFunction(vm)); |
1977 | FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(vm, functionValue.asCell()->getObject()))->jsExecutable(); |
1978 | |
1979 | RELEASE_ASSERT(exec->argument(1).isString()); |
1980 | String substring = asString(exec->argument(1))->value(exec); |
1981 | String sourceCodeText = executable->source().view().toString(); |
1982 | unsigned offset = static_cast<unsigned>(sourceCodeText.find(substring) + executable->source().startOffset()); |
1983 | |
1984 | String jsonString = vm.typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorNormal, offset, executable->sourceID(), vm); |
1985 | return JSValue::encode(JSONParse(exec, jsonString)); |
1986 | } |
1987 | |
1988 | static EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState* exec) |
1989 | { |
1990 | VM& vm = exec->vm(); |
1991 | RELEASE_ASSERT(vm.typeProfiler()); |
1992 | vm.typeProfilerLog()->processLogEntries(vm, "jsc Testing API: functionReturnTypeFor"_s ); |
1993 | |
1994 | JSValue functionValue = exec->argument(0); |
1995 | RELEASE_ASSERT(functionValue.isFunction(vm)); |
1996 | FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(vm, functionValue.asCell()->getObject()))->jsExecutable(); |
1997 | |
1998 | unsigned offset = executable->typeProfilingStartOffset(vm); |
1999 | String jsonString = vm.typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorFunctionReturn, offset, executable->sourceID(), vm); |
2000 | return JSValue::encode(JSONParse(exec, jsonString)); |
2001 | } |
2002 | |
2003 | static EncodedJSValue JSC_HOST_CALL functionFlattenDictionaryObject(ExecState* exec) |
2004 | { |
2005 | VM& vm = exec->vm(); |
2006 | JSValue value = exec->argument(0); |
2007 | RELEASE_ASSERT(value.isObject() && value.getObject()->structure()->isDictionary()); |
2008 | value.getObject()->flattenDictionaryObject(vm); |
2009 | return encodedJSUndefined(); |
2010 | } |
2011 | |
2012 | static EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState* exec) |
2013 | { |
2014 | VM& vm = exec->vm(); |
2015 | RELEASE_ASSERT(vm.controlFlowProfiler()); |
2016 | vm.controlFlowProfiler()->dumpData(); |
2017 | return JSValue::encode(jsUndefined()); |
2018 | } |
2019 | |
2020 | static EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState* exec) |
2021 | { |
2022 | VM& vm = exec->vm(); |
2023 | RELEASE_ASSERT(vm.controlFlowProfiler()); |
2024 | |
2025 | JSValue functionValue = exec->argument(0); |
2026 | RELEASE_ASSERT(functionValue.isFunction(vm)); |
2027 | FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(vm, functionValue.asCell()->getObject()))->jsExecutable(); |
2028 | |
2029 | RELEASE_ASSERT(exec->argument(1).isString()); |
2030 | String substring = asString(exec->argument(1))->value(exec); |
2031 | String sourceCodeText = executable->source().view().toString(); |
2032 | RELEASE_ASSERT(sourceCodeText.contains(substring)); |
2033 | int offset = sourceCodeText.find(substring) + executable->source().startOffset(); |
2034 | |
2035 | bool hasExecuted = vm.controlFlowProfiler()->hasBasicBlockAtTextOffsetBeenExecuted(offset, executable->sourceID(), vm); |
2036 | return JSValue::encode(jsBoolean(hasExecuted)); |
2037 | } |
2038 | |
2039 | static EncodedJSValue JSC_HOST_CALL functionBasicBlockExecutionCount(ExecState* exec) |
2040 | { |
2041 | VM& vm = exec->vm(); |
2042 | RELEASE_ASSERT(vm.controlFlowProfiler()); |
2043 | |
2044 | JSValue functionValue = exec->argument(0); |
2045 | RELEASE_ASSERT(functionValue.isFunction(vm)); |
2046 | FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(vm, functionValue.asCell()->getObject()))->jsExecutable(); |
2047 | |
2048 | RELEASE_ASSERT(exec->argument(1).isString()); |
2049 | String substring = asString(exec->argument(1))->value(exec); |
2050 | String sourceCodeText = executable->source().view().toString(); |
2051 | RELEASE_ASSERT(sourceCodeText.contains(substring)); |
2052 | int offset = sourceCodeText.find(substring) + executable->source().startOffset(); |
2053 | |
2054 | size_t executionCount = vm.controlFlowProfiler()->basicBlockExecutionCountAtTextOffset(offset, executable->sourceID(), vm); |
2055 | return JSValue::encode(JSValue(executionCount)); |
2056 | } |
2057 | |
2058 | static EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*) |
2059 | { |
2060 | Options::useExceptionFuzz() = true; |
2061 | return JSValue::encode(jsUndefined()); |
2062 | } |
2063 | |
2064 | static EncodedJSValue changeDebuggerModeWhenIdle(ExecState* exec, OptionSet<CodeGenerationMode> codeGenerationMode) |
2065 | { |
2066 | bool newDebuggerMode = codeGenerationMode.contains(CodeGenerationMode::Debugger); |
2067 | if (Options::forceDebuggerBytecodeGeneration() == newDebuggerMode) |
2068 | return JSValue::encode(jsUndefined()); |
2069 | |
2070 | VM* vm = &exec->vm(); |
2071 | vm->whenIdle([=] () { |
2072 | Options::forceDebuggerBytecodeGeneration() = newDebuggerMode; |
2073 | vm->deleteAllCode(PreventCollectionAndDeleteAllCode); |
2074 | if (newDebuggerMode) |
2075 | vm->ensureShadowChicken(); |
2076 | }); |
2077 | return JSValue::encode(jsUndefined()); |
2078 | } |
2079 | |
2080 | static EncodedJSValue JSC_HOST_CALL functionEnableDebuggerModeWhenIdle(ExecState* exec) |
2081 | { |
2082 | return changeDebuggerModeWhenIdle(exec, { CodeGenerationMode::Debugger }); |
2083 | } |
2084 | |
2085 | static EncodedJSValue JSC_HOST_CALL functionDisableDebuggerModeWhenIdle(ExecState* exec) |
2086 | { |
2087 | return changeDebuggerModeWhenIdle(exec, { }); |
2088 | } |
2089 | |
2090 | static EncodedJSValue JSC_HOST_CALL functionDeleteAllCodeWhenIdle(ExecState* exec) |
2091 | { |
2092 | VM* vm = &exec->vm(); |
2093 | vm->whenIdle([=] () { |
2094 | vm->deleteAllCode(PreventCollectionAndDeleteAllCode); |
2095 | }); |
2096 | return JSValue::encode(jsUndefined()); |
2097 | } |
2098 | |
2099 | static EncodedJSValue JSC_HOST_CALL functionGlobalObjectCount(ExecState* exec) |
2100 | { |
2101 | return JSValue::encode(jsNumber(exec->vm().heap.globalObjectCount())); |
2102 | } |
2103 | |
2104 | static EncodedJSValue JSC_HOST_CALL functionGlobalObjectForObject(ExecState* exec) |
2105 | { |
2106 | JSValue value = exec->argument(0); |
2107 | RELEASE_ASSERT(value.isObject()); |
2108 | JSGlobalObject* globalObject = jsCast<JSObject*>(value)->globalObject(exec->vm()); |
2109 | RELEASE_ASSERT(globalObject); |
2110 | return JSValue::encode(globalObject); |
2111 | } |
2112 | |
2113 | static EncodedJSValue JSC_HOST_CALL functionGetGetterSetter(ExecState* exec) |
2114 | { |
2115 | VM& vm = exec->vm(); |
2116 | auto scope = DECLARE_THROW_SCOPE(vm); |
2117 | |
2118 | JSValue value = exec->argument(0); |
2119 | if (!value.isObject()) |
2120 | return JSValue::encode(jsUndefined()); |
2121 | |
2122 | JSValue property = exec->argument(1); |
2123 | if (!property.isString()) |
2124 | return JSValue::encode(jsUndefined()); |
2125 | |
2126 | auto propertyName = asString(property)->toIdentifier(exec); |
2127 | RETURN_IF_EXCEPTION(scope, { }); |
2128 | |
2129 | PropertySlot slot(value, PropertySlot::InternalMethodType::VMInquiry); |
2130 | value.getPropertySlot(exec, propertyName, slot); |
2131 | RETURN_IF_EXCEPTION(scope, { }); |
2132 | |
2133 | JSValue result; |
2134 | if (slot.isCacheableGetter()) |
2135 | result = slot.getterSetter(); |
2136 | else |
2137 | result = jsNull(); |
2138 | |
2139 | return JSValue::encode(result); |
2140 | } |
2141 | |
2142 | static EncodedJSValue JSC_HOST_CALL functionLoadGetterFromGetterSetter(ExecState* exec) |
2143 | { |
2144 | VM& vm = exec->vm(); |
2145 | auto scope = DECLARE_THROW_SCOPE(vm); |
2146 | |
2147 | GetterSetter* getterSetter = jsDynamicCast<GetterSetter*>(vm, exec->argument(0)); |
2148 | if (UNLIKELY(!getterSetter)) { |
2149 | throwTypeError(exec, scope, "Invalid use of loadGetterFromGetterSetter test function: argument is not a GetterSetter"_s ); |
2150 | return encodedJSValue(); |
2151 | } |
2152 | |
2153 | JSObject* getter = getterSetter->getter(); |
2154 | RELEASE_ASSERT(getter); |
2155 | return JSValue::encode(getter); |
2156 | } |
2157 | |
2158 | static EncodedJSValue JSC_HOST_CALL functionCreateCustomTestGetterSetter(ExecState* exec) |
2159 | { |
2160 | VM& vm = exec->vm(); |
2161 | JSGlobalObject* globalObject = exec->lexicalGlobalObject(); |
2162 | return JSValue::encode(JSTestCustomGetterSetter::create(vm, globalObject, JSTestCustomGetterSetter::createStructure(vm, globalObject))); |
2163 | } |
2164 | |
2165 | static EncodedJSValue JSC_HOST_CALL functionDeltaBetweenButterflies(ExecState* exec) |
2166 | { |
2167 | VM& vm = exec->vm(); |
2168 | JSObject* a = jsDynamicCast<JSObject*>(vm, exec->argument(0)); |
2169 | JSObject* b = jsDynamicCast<JSObject*>(vm, exec->argument(1)); |
2170 | if (!a || !b) |
2171 | return JSValue::encode(jsNumber(PNaN)); |
2172 | |
2173 | ptrdiff_t delta = bitwise_cast<char*>(a->butterfly()) - bitwise_cast<char*>(b->butterfly()); |
2174 | if (delta < 0) |
2175 | return JSValue::encode(jsNumber(PNaN)); |
2176 | if (delta > std::numeric_limits<int32_t>::max()) |
2177 | return JSValue::encode(jsNumber(PNaN)); |
2178 | return JSValue::encode(jsNumber(static_cast<int32_t>(delta))); |
2179 | } |
2180 | |
2181 | static EncodedJSValue JSC_HOST_CALL functionTotalGCTime(ExecState* exec) |
2182 | { |
2183 | VM& vm = exec->vm(); |
2184 | return JSValue::encode(jsNumber(vm.heap.totalGCTime().seconds())); |
2185 | } |
2186 | |
2187 | void JSDollarVM::finishCreation(VM& vm) |
2188 | { |
2189 | Base::finishCreation(vm); |
2190 | |
2191 | JSGlobalObject* globalObject = this->globalObject(vm); |
2192 | |
2193 | auto addFunction = [&] (VM& vm, const char* name, NativeFunction function, unsigned arguments) { |
2194 | JSDollarVM::addFunction(vm, globalObject, name, function, arguments); |
2195 | }; |
2196 | auto addConstructibleFunction = [&] (VM& vm, const char* name, NativeFunction function, unsigned arguments) { |
2197 | JSDollarVM::addConstructibleFunction(vm, globalObject, name, function, arguments); |
2198 | }; |
2199 | |
2200 | addFunction(vm, "abort" , functionCrash, 0); |
2201 | addFunction(vm, "crash" , functionCrash, 0); |
2202 | addFunction(vm, "breakpoint" , functionBreakpoint, 0); |
2203 | |
2204 | putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "dfgTrue" ), 0, functionDFGTrue, DFGTrueIntrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum)); |
2205 | putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "ftlTrue" ), 0, functionFTLTrue, FTLTrueIntrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum)); |
2206 | |
2207 | putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "cpuMfence" ), 0, functionCpuMfence, CPUMfenceIntrinsic, 0); |
2208 | putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "cpuRdtsc" ), 0, functionCpuRdtsc, CPURdtscIntrinsic, 0); |
2209 | putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "cpuCpuid" ), 0, functionCpuCpuid, CPUCpuidIntrinsic, 0); |
2210 | putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "cpuPause" ), 0, functionCpuPause, CPUPauseIntrinsic, 0); |
2211 | addFunction(vm, "cpuClflush" , functionCpuClflush, 2); |
2212 | |
2213 | addFunction(vm, "llintTrue" , functionLLintTrue, 0); |
2214 | addFunction(vm, "jitTrue" , functionJITTrue, 0); |
2215 | |
2216 | addFunction(vm, "noInline" , functionNoInline, 1); |
2217 | |
2218 | addFunction(vm, "gc" , functionGC, 0); |
2219 | addFunction(vm, "edenGC" , functionEdenGC, 0); |
2220 | |
2221 | addFunction(vm, "callFrame" , functionCallFrame, 1); |
2222 | addFunction(vm, "codeBlockFor" , functionCodeBlockFor, 1); |
2223 | addFunction(vm, "codeBlockForFrame" , functionCodeBlockForFrame, 1); |
2224 | addFunction(vm, "dumpSourceFor" , functionDumpSourceFor, 1); |
2225 | addFunction(vm, "dumpBytecodeFor" , functionDumpBytecodeFor, 1); |
2226 | |
2227 | addFunction(vm, "dataLog" , functionDataLog, 1); |
2228 | addFunction(vm, "print" , functionPrint, 1); |
2229 | addFunction(vm, "dumpCallFrame" , functionDumpCallFrame, 0); |
2230 | addFunction(vm, "dumpStack" , functionDumpStack, 0); |
2231 | addFunction(vm, "dumpRegisters" , functionDumpRegisters, 1); |
2232 | |
2233 | addFunction(vm, "dumpCell" , functionDumpCell, 1); |
2234 | |
2235 | addFunction(vm, "indexingMode" , functionIndexingMode, 1); |
2236 | addFunction(vm, "inlineCapacity" , functionInlineCapacity, 1); |
2237 | addFunction(vm, "value" , functionValue, 1); |
2238 | addFunction(vm, "getpid" , functionGetPID, 0); |
2239 | |
2240 | addFunction(vm, "haveABadTime" , functionHaveABadTime, 1); |
2241 | addFunction(vm, "isHavingABadTime" , functionIsHavingABadTime, 1); |
2242 | |
2243 | addFunction(vm, "createGlobalObject" , functionCreateGlobalObject, 0); |
2244 | addFunction(vm, "createProxy" , functionCreateProxy, 1); |
2245 | addFunction(vm, "createRuntimeArray" , functionCreateRuntimeArray, 0); |
2246 | addFunction(vm, "createNullRopeString" , functionCreateNullRopeString, 0); |
2247 | |
2248 | addFunction(vm, "createImpureGetter" , functionCreateImpureGetter, 1); |
2249 | addFunction(vm, "createCustomGetterObject" , functionCreateCustomGetterObject, 0); |
2250 | addFunction(vm, "createDOMJITNodeObject" , functionCreateDOMJITNodeObject, 0); |
2251 | addFunction(vm, "createDOMJITGetterObject" , functionCreateDOMJITGetterObject, 0); |
2252 | addFunction(vm, "createDOMJITGetterComplexObject" , functionCreateDOMJITGetterComplexObject, 0); |
2253 | addFunction(vm, "createDOMJITFunctionObject" , functionCreateDOMJITFunctionObject, 0); |
2254 | addFunction(vm, "createDOMJITCheckSubClassObject" , functionCreateDOMJITCheckSubClassObject, 0); |
2255 | addFunction(vm, "createDOMJITGetterBaseJSObject" , functionCreateDOMJITGetterBaseJSObject, 0); |
2256 | addFunction(vm, "createBuiltin" , functionCreateBuiltin, 2); |
2257 | #if ENABLE(WEBASSEMBLY) |
2258 | addFunction(vm, "createWasmStreamingParser" , functionCreateWasmStreamingParser, 0); |
2259 | #endif |
2260 | addFunction(vm, "getPrivateProperty" , functionGetPrivateProperty, 2); |
2261 | addFunction(vm, "setImpureGetterDelegate" , functionSetImpureGetterDelegate, 2); |
2262 | |
2263 | addConstructibleFunction(vm, "Root" , functionCreateRoot, 0); |
2264 | addConstructibleFunction(vm, "Element" , functionCreateElement, 1); |
2265 | addFunction(vm, "getElement" , functionGetElement, 1); |
2266 | |
2267 | addConstructibleFunction(vm, "SimpleObject" , functionCreateSimpleObject, 0); |
2268 | addFunction(vm, "getHiddenValue" , functionGetHiddenValue, 1); |
2269 | addFunction(vm, "setHiddenValue" , functionSetHiddenValue, 2); |
2270 | |
2271 | addFunction(vm, "shadowChickenFunctionsOnStack" , functionShadowChickenFunctionsOnStack, 0); |
2272 | addFunction(vm, "setGlobalConstRedeclarationShouldNotThrow" , functionSetGlobalConstRedeclarationShouldNotThrow, 0); |
2273 | |
2274 | addFunction(vm, "findTypeForExpression" , functionFindTypeForExpression, 2); |
2275 | addFunction(vm, "returnTypeFor" , functionReturnTypeFor, 1); |
2276 | |
2277 | addFunction(vm, "flattenDictionaryObject" , functionFlattenDictionaryObject, 1); |
2278 | |
2279 | addFunction(vm, "dumpBasicBlockExecutionRanges" , functionDumpBasicBlockExecutionRanges , 0); |
2280 | addFunction(vm, "hasBasicBlockExecuted" , functionHasBasicBlockExecuted, 2); |
2281 | addFunction(vm, "basicBlockExecutionCount" , functionBasicBlockExecutionCount, 2); |
2282 | |
2283 | addFunction(vm, "enableExceptionFuzz" , functionEnableExceptionFuzz, 0); |
2284 | |
2285 | addFunction(vm, "enableDebuggerModeWhenIdle" , functionEnableDebuggerModeWhenIdle, 0); |
2286 | addFunction(vm, "disableDebuggerModeWhenIdle" , functionDisableDebuggerModeWhenIdle, 0); |
2287 | |
2288 | addFunction(vm, "deleteAllCodeWhenIdle" , functionDeleteAllCodeWhenIdle, 0); |
2289 | |
2290 | addFunction(vm, "globalObjectCount" , functionGlobalObjectCount, 0); |
2291 | addFunction(vm, "globalObjectForObject" , functionGlobalObjectForObject, 1); |
2292 | |
2293 | addFunction(vm, "getGetterSetter" , functionGetGetterSetter, 2); |
2294 | addFunction(vm, "loadGetterFromGetterSetter" , functionLoadGetterFromGetterSetter, 1); |
2295 | addFunction(vm, "createCustomTestGetterSetter" , functionCreateCustomTestGetterSetter, 1); |
2296 | |
2297 | addFunction(vm, "deltaBetweenButterflies" , functionDeltaBetweenButterflies, 2); |
2298 | |
2299 | addFunction(vm, "totalGCTime" , functionTotalGCTime, 0); |
2300 | } |
2301 | |
2302 | void JSDollarVM::addFunction(VM& vm, JSGlobalObject* globalObject, const char* name, NativeFunction function, unsigned arguments) |
2303 | { |
2304 | Identifier identifier = Identifier::fromString(&vm, name); |
2305 | putDirect(vm, identifier, JSFunction::create(vm, globalObject, arguments, identifier.string(), function)); |
2306 | } |
2307 | |
2308 | void JSDollarVM::addConstructibleFunction(VM& vm, JSGlobalObject* globalObject, const char* name, NativeFunction function, unsigned arguments) |
2309 | { |
2310 | Identifier identifier = Identifier::fromString(&vm, name); |
2311 | putDirect(vm, identifier, JSFunction::create(vm, globalObject, arguments, identifier.string(), function, NoIntrinsic, function)); |
2312 | } |
2313 | |
2314 | } // namespace JSC |
2315 | |