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