/* * Copyright (C) 2015-2021 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "JSDollarVM.h" #include "ArrayPrototype.h" #include "BuiltinNames.h" #include "CodeBlock.h" #include "ControlFlowProfiler.h" #include "DOMAttributeGetterSetter.h" #include "DOMJITGetterSetter.h" #include "Debugger.h" #include "FrameTracers.h" #include "FunctionCodeBlock.h" #include "GetterSetter.h" #include "JITSizeStatistics.h" #include "JSArray.h" #include "JSCInlines.h" #include "JSONObject.h" #include "JSString.h" #include "LinkBuffer.h" #include "Options.h" #include "Parser.h" #include "ProbeContext.h" #include "ShadowChicken.h" #include "Snippet.h" #include "SnippetParams.h" #include "TypeProfiler.h" #include "TypeProfilerLog.h" #include "VMInspector.h" #include "VMTrapsInlines.h" #include "WasmCapabilities.h" #include #include #include #include #include #include #include #include #include #if !USE(SYSTEM_MALLOC) #include #if BUSE(LIBPAS) #include #include #include #endif #endif #if ENABLE(WEBASSEMBLY) #include "JSWebAssemblyHelpers.h" #include "WasmModuleInformation.h" #include "WasmStreamingCompiler.h" #include "WasmStreamingParser.h" #endif using namespace JSC; IGNORE_WARNINGS_BEGIN("frame-address") extern "C" void ctiMasmProbeTrampoline(); namespace JSC { // This class is only here as a simple way to grant JSDollarVM friend privileges // to all the classes that it needs special access to. class JSDollarVMHelper { public: JSDollarVMHelper(VM& vm) : m_vm(vm) { } void updateVMStackLimits() { return m_vm.updateStackLimits(); }; VM& m_vm; }; } // namespace JSC namespace { static JSC_DECLARE_HOST_FUNCTION(functionDOMJITGetterComplexEnableException); static JSC_DECLARE_HOST_FUNCTION(functionDOMJITFunctionObjectWithTypeCheck); static JSC_DECLARE_HOST_FUNCTION(functionDOMJITCheckJSCastObjectWithTypeCheck); // We must RELEASE_ASSERT(Options::useDollarVM()) in all JSDollarVM functions // that are non-trivial at an eye's glance. This includes (but is not limited to): // constructors // create() factory // createStructure() factory // finishCreation() // HOST_CALL or operation functions // Constructors and methods of utility and test classes // lambda functions // // The way to do this RELEASE_ASSERT is with the DollarVMAssertScope below. // // The only exception are some constexpr constructors used for instantiating // globals (since these must have trivial constructors) e.g. DOMJITAttribute. // Instead, these constructors should always be ALWAYS_INLINE. class JSDollarVMCallFrame : public JSNonFinalObject { using Base = JSNonFinalObject; public: template static CompleteSubspace* subspaceFor(VM& vm) { return &vm.cellSpace(); } JSDollarVMCallFrame(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } static JSDollarVMCallFrame* create(JSGlobalObject* globalObject, CallFrame* callFrame, unsigned requestedFrameIndex) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); Structure* structure = createStructure(vm, globalObject, jsNull()); JSDollarVMCallFrame* frame = new (NotNull, allocateCell(vm)) JSDollarVMCallFrame(vm, structure); frame->finishCreation(vm, callFrame, requestedFrameIndex); return frame; } void finishCreation(VM& vm, CallFrame* callFrame, unsigned requestedFrameIndex) { DollarVMAssertScope assertScope; Base::finishCreation(vm); auto addProperty = [&] (VM& vm, const char* name, JSValue value) { DollarVMAssertScope assertScope; JSDollarVMCallFrame::addProperty(vm, name, value); }; unsigned frameIndex = 0; bool isValid = false; callFrame->iterate(vm, [&] (StackVisitor& visitor) { DollarVMAssertScope assertScope; if (frameIndex++ != requestedFrameIndex) return StackVisitor::Continue; addProperty(vm, "name", jsString(vm, visitor->functionName())); if (visitor->callee().isCell()) addProperty(vm, "callee", visitor->callee().asCell()); CodeBlock* codeBlock = visitor->codeBlock(); if (codeBlock) { addProperty(vm, "codeBlock", codeBlock); addProperty(vm, "unlinkedCodeBlock", codeBlock->unlinkedCodeBlock()); addProperty(vm, "executable", codeBlock->ownerExecutable()); } isValid = true; return StackVisitor::Done; }); addProperty(vm, "valid", jsBoolean(isValid)); } DECLARE_INFO; private: void addProperty(VM& vm, const char* name, JSValue value) { DollarVMAssertScope assertScope; Identifier identifier = Identifier::fromString(vm, name); putDirect(vm, identifier, value); } }; const ClassInfo JSDollarVMCallFrame::s_info = { "CallFrame", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDollarVMCallFrame) }; class ElementHandleOwner; class Root; class Element : public JSNonFinalObject { public: Element(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } typedef JSNonFinalObject Base; template static CompleteSubspace* subspaceFor(VM& vm) { return &vm.cellSpace(); } Root* root() const { return m_root.get(); } void setRoot(VM& vm, Root* root) { m_root.set(vm, this, root); } static Element* create(VM& vm, JSGlobalObject* globalObject, Root* root) { DollarVMAssertScope assertScope; Structure* structure = createStructure(vm, globalObject, jsNull()); Element* element = new (NotNull, allocateCell(vm)) Element(vm, structure); element->finishCreation(vm, root); return element; } void finishCreation(VM&, Root*); DECLARE_VISIT_CHILDREN; static ElementHandleOwner* handleOwner(); static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } DECLARE_INFO; private: WriteBarrier m_root; }; template void Element::visitChildrenImpl(JSCell* cell, Visitor& visitor) { DollarVMAssertScope assertScope; Element* thisObject = jsCast(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); Base::visitChildren(thisObject, visitor); visitor.append(thisObject->m_root); } DEFINE_VISIT_CHILDREN(Element); class ElementHandleOwner final : public WeakHandleOwner { WTF_MAKE_FAST_ALLOCATED; public: bool isReachableFromOpaqueRoots(JSC::Handle handle, void*, AbstractSlotVisitor& visitor, const char** reason) final { DollarVMAssertScope assertScope; if (UNLIKELY(reason)) *reason = "JSC::Element is opaque root"; Element* element = jsCast(handle.slot()->asCell()); return visitor.containsOpaqueRoot(element->root()); } }; class Root final : public JSDestructibleObject { public: using Base = JSDestructibleObject; template static CompleteSubspace* subspaceFor(VM& vm) { return &vm.destructibleObjectSpace(); } Root(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } Element* element() { return m_element.get(); } void setElement(Element* element) { DollarVMAssertScope assertScope; Weak newElement(element, Element::handleOwner()); m_element.swap(newElement); } static Root* create(VM& vm, JSGlobalObject* globalObject) { DollarVMAssertScope assertScope; Structure* structure = createStructure(vm, globalObject, jsNull()); Root* root = new (NotNull, allocateCell(vm)) Root(vm, structure); root->finishCreation(vm); return root; } DECLARE_INFO; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } DECLARE_VISIT_CHILDREN; private: Weak m_element; }; template void Root::visitChildrenImpl(JSCell* thisObject, Visitor& visitor) { DollarVMAssertScope assertScope; ASSERT_GC_OBJECT_INHERITS(thisObject, info()); Base::visitChildren(thisObject, visitor); visitor.addOpaqueRoot(thisObject); } DEFINE_VISIT_CHILDREN(Root); class SimpleObject : public JSNonFinalObject { public: SimpleObject(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } typedef JSNonFinalObject Base; template static CompleteSubspace* subspaceFor(VM& vm) { return &vm.cellSpace(); } static SimpleObject* create(VM& vm, JSGlobalObject* globalObject) { DollarVMAssertScope assertScope; Structure* structure = createStructure(vm, globalObject, jsNull()); SimpleObject* simpleObject = new (NotNull, allocateCell(vm)) SimpleObject(vm, structure); simpleObject->finishCreation(vm); return simpleObject; } DECLARE_VISIT_CHILDREN; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } JSValue hiddenValue() { return m_hiddenValue.get(); } void setHiddenValue(VM& vm, JSValue value) { ASSERT(value.isCell()); m_hiddenValue.set(vm, this, value); } static CallData getConstructData(JSCell*) { CallData constructData; constructData.type = CallData::Type::Native; constructData.native.function = callHostFunctionAsConstructor; return constructData; } DECLARE_INFO; private: WriteBarrier m_hiddenValue; }; template void SimpleObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) { DollarVMAssertScope assertScope; SimpleObject* thisObject = jsCast(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); Base::visitChildren(thisObject, visitor); visitor.append(thisObject->m_hiddenValue); } DEFINE_VISIT_CHILDREN(SimpleObject); class ImpureGetter : public JSNonFinalObject { public: ImpureGetter(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } DECLARE_INFO; typedef JSNonFinalObject Base; static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpure | JSC::OverridesGetOwnPropertySlot; template static CompleteSubspace* subspaceFor(VM& vm) { return &vm.cellSpace(); } static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } static ImpureGetter* create(VM& vm, Structure* structure, JSObject* delegate) { DollarVMAssertScope assertScope; ImpureGetter* getter = new (NotNull, allocateCell(vm)) ImpureGetter(vm, structure); getter->finishCreation(vm, delegate); return getter; } void finishCreation(VM& vm, JSObject* delegate) { DollarVMAssertScope assertScope; Base::finishCreation(vm); if (delegate) m_delegate.set(vm, this, delegate); } static bool getOwnPropertySlot(JSObject* object, JSGlobalObject* globalObject, PropertyName name, PropertySlot& slot) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); ImpureGetter* thisObject = jsCast(object); if (thisObject->m_delegate) { if (thisObject->m_delegate->getPropertySlot(globalObject, name, slot)) return true; RETURN_IF_EXCEPTION(scope, false); } return Base::getOwnPropertySlot(object, globalObject, name, slot); } DECLARE_VISIT_CHILDREN; void setDelegate(VM& vm, JSObject* delegate) { m_delegate.set(vm, this, delegate); } private: WriteBarrier m_delegate; }; template void ImpureGetter::visitChildrenImpl(JSCell* cell, Visitor& visitor) { DollarVMAssertScope assertScope; ASSERT_GC_OBJECT_INHERITS(cell, info()); Base::visitChildren(cell, visitor); ImpureGetter* thisObject = jsCast(cell); visitor.append(thisObject->m_delegate); } DEFINE_VISIT_CHILDREN(ImpureGetter); static JSC_DECLARE_CUSTOM_GETTER(customGetterValueGetter); static JSC_DECLARE_CUSTOM_GETTER(customGetterAcessorGetter); class CustomGetter : public JSNonFinalObject { public: CustomGetter(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } DECLARE_INFO; typedef JSNonFinalObject Base; static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::OverridesGetOwnPropertySlot; template static CompleteSubspace* subspaceFor(VM& vm) { return &vm.cellSpace(); } static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } static CustomGetter* create(VM& vm, Structure* structure) { DollarVMAssertScope assertScope; CustomGetter* getter = new (NotNull, allocateCell(vm)) CustomGetter(vm, structure); getter->finishCreation(vm); return getter; } static bool getOwnPropertySlot(JSObject* object, JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); CustomGetter* thisObject = jsCast(object); if (propertyName == PropertyName(Identifier::fromString(vm, "customGetter"))) { slot.setCacheableCustom(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum, customGetterValueGetter); return true; } if (propertyName == PropertyName(Identifier::fromString(vm, "customGetterAccessor"))) { slot.setCacheableCustom(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | PropertyAttribute::CustomAccessor, customGetterAcessorGetter); return true; } return JSObject::getOwnPropertySlot(thisObject, globalObject, propertyName, slot); } }; JSC_DEFINE_CUSTOM_GETTER(customGetterValueGetter, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); CustomGetter* thisObject = jsDynamicCast(vm, JSValue::decode(thisValue)); if (!thisObject) return throwVMTypeError(globalObject, scope); bool shouldThrow = thisObject->get(globalObject, PropertyName(Identifier::fromString(vm, "shouldThrow"))).toBoolean(globalObject); RETURN_IF_EXCEPTION(scope, encodedJSValue()); if (shouldThrow) return throwVMTypeError(globalObject, scope); return JSValue::encode(jsNumber(100)); } JSC_DEFINE_CUSTOM_GETTER(customGetterAcessorGetter, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSObject* thisObject = jsDynamicCast(vm, JSValue::decode(thisValue)); if (!thisObject) return throwVMTypeError(globalObject, scope); bool shouldThrow = thisObject->get(globalObject, PropertyName(Identifier::fromString(vm, "shouldThrow"))).toBoolean(globalObject); RETURN_IF_EXCEPTION(scope, encodedJSValue()); if (shouldThrow) return throwVMTypeError(globalObject, scope); return JSValue::encode(jsNumber(100)); } static JSC_DECLARE_CUSTOM_GETTER(runtimeArrayLengthGetter); class RuntimeArray : public JSArray { public: typedef JSArray Base; static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero; IGNORE_WARNINGS_BEGIN("unused-const-variable") static constexpr bool needsDestruction = false; IGNORE_WARNINGS_END template static CompleteSubspace* subspaceFor(VM& vm) { return &vm.cellSpace(); } static RuntimeArray* create(JSGlobalObject* globalObject, CallFrame* callFrame) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); Structure* structure = createStructure(vm, globalObject, createPrototype(vm, globalObject)); RuntimeArray* runtimeArray = new (NotNull, allocateCell(vm)) RuntimeArray(globalObject, structure); runtimeArray->finishCreation(globalObject, callFrame); vm.heap.addFinalizer(runtimeArray, destroy); return runtimeArray; } ~RuntimeArray() { } static void destroy(JSCell* cell) { DollarVMAssertScope assertScope; static_cast(cell)->RuntimeArray::~RuntimeArray(); } static bool getOwnPropertySlot(JSObject* object, JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); RuntimeArray* thisObject = jsCast(object); if (propertyName == vm.propertyNames->length) { slot.setCacheableCustom(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum, runtimeArrayLengthGetter); return true; } std::optional index = parseIndex(propertyName); if (index && index.value() < thisObject->getLength()) { slot.setValue(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::DontEnum, jsNumber(thisObject->m_vector[index.value()])); return true; } return JSObject::getOwnPropertySlot(thisObject, globalObject, propertyName, slot); } static bool getOwnPropertySlotByIndex(JSObject* object, JSGlobalObject* globalObject, unsigned index, PropertySlot& slot) { DollarVMAssertScope assertScope; RuntimeArray* thisObject = jsCast(object); if (index < thisObject->getLength()) { slot.setValue(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::DontEnum, jsNumber(thisObject->m_vector[index])); return true; } return JSObject::getOwnPropertySlotByIndex(thisObject, globalObject, index, slot); } static NO_RETURN_DUE_TO_CRASH bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&) { RELEASE_ASSERT_NOT_REACHED(); } static NO_RETURN_DUE_TO_CRASH bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&) { RELEASE_ASSERT_NOT_REACHED(); } unsigned getLength() const { return m_vector.size(); } DECLARE_INFO; static ArrayPrototype* createPrototype(VM&, JSGlobalObject* globalObject) { DollarVMAssertScope assertScope; return globalObject->arrayPrototype(); } static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(DerivedArrayType, StructureFlags), info(), ArrayClass); } protected: void finishCreation(JSGlobalObject* globalObject, CallFrame* callFrame) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); Base::finishCreation(vm); ASSERT(inherits(vm, info())); for (size_t i = 0; i < callFrame->argumentCount(); i++) m_vector.append(callFrame->argument(i).toInt32(globalObject)); } private: RuntimeArray(JSGlobalObject* globalObject, Structure* structure) : JSArray(globalObject->vm(), structure, nullptr) { DollarVMAssertScope assertScope; } Vector m_vector; }; JSC_DEFINE_CUSTOM_GETTER(runtimeArrayLengthGetter, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); RuntimeArray* thisObject = jsDynamicCast(vm, JSValue::decode(thisValue)); if (!thisObject) return throwVMTypeError(globalObject, scope); return JSValue::encode(jsNumber(thisObject->getLength())); } static JSC_DECLARE_CUSTOM_GETTER(testStaticAccessorGetter); static JSC_DECLARE_CUSTOM_SETTER(testStaticAccessorPutter); JSC_DEFINE_CUSTOM_GETTER(testStaticAccessorGetter, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSObject* thisObject = jsDynamicCast(vm, JSValue::decode(thisValue)); if (!thisObject) return throwVMTypeError(globalObject, scope); if (JSValue result = thisObject->getDirect(vm, PropertyName(Identifier::fromString(vm, "testField")))) return JSValue::encode(result); return JSValue::encode(jsUndefined()); } JSC_DEFINE_CUSTOM_SETTER(testStaticAccessorPutter, (JSGlobalObject* globalObject, EncodedJSValue thisValue, EncodedJSValue value, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSValue receiver = JSValue::decode(thisValue); JSObject* thisObject = receiver.isObject() ? asObject(receiver) : receiver.synthesizePrototype(globalObject); RETURN_IF_EXCEPTION(scope, false); RELEASE_ASSERT(thisObject); return thisObject->putDirect(vm, PropertyName(Identifier::fromString(vm, "testField")), JSValue::decode(value)); } static const struct CompactHashIndex staticCustomAccessorTableIndex[9] = { { -1, -1 }, { -1, -1 }, { 2, -1 }, { -1, -1 }, { 0, 8 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { 1, -1 }, }; static const struct HashTableValue staticCustomAccessorTableValues[3] = { { "testStaticAccessor", static_cast(PropertyAttribute::CustomAccessor), NoIntrinsic, { (intptr_t)static_cast(testStaticAccessorGetter), (intptr_t)static_cast(testStaticAccessorPutter) } }, { "testStaticAccessorDontEnum", PropertyAttribute::CustomAccessor | PropertyAttribute::DontEnum, NoIntrinsic, { (intptr_t)static_cast(testStaticAccessorGetter), (intptr_t)static_cast(testStaticAccessorPutter) } }, { "testStaticAccessorReadOnly", PropertyAttribute::CustomAccessor | PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly, NoIntrinsic, { (intptr_t)static_cast(testStaticAccessorGetter), 0 } }, }; static const struct HashTable staticCustomAccessorTable = { 3, 7, true, nullptr, staticCustomAccessorTableValues, staticCustomAccessorTableIndex }; class StaticCustomAccessor : public JSNonFinalObject { using Base = JSNonFinalObject; public: StaticCustomAccessor(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } DECLARE_INFO; static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable | OverridesGetOwnPropertySlot; template static CompleteSubspace* subspaceFor(VM& vm) { return &vm.cellSpace(); } static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } static StaticCustomAccessor* create(VM& vm, Structure* structure) { DollarVMAssertScope assertScope; StaticCustomAccessor* accessor = new (NotNull, allocateCell(vm)) StaticCustomAccessor(vm, structure); accessor->finishCreation(vm); return accessor; } static bool getOwnPropertySlot(JSObject* thisObject, JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot) { if (String(propertyName.uid()) == "thinAirCustomGetter") { slot.setCacheableCustom(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | PropertyAttribute::CustomAccessor, testStaticAccessorGetter); return true; } return JSNonFinalObject::getOwnPropertySlot(thisObject, globalObject, propertyName, slot); } }; static JSC_DECLARE_CUSTOM_GETTER(testStaticValueGetter); static JSC_DECLARE_CUSTOM_SETTER(testStaticValuePutter); static JSC_DECLARE_CUSTOM_SETTER(testStaticValuePutterSetFlag); JSC_DEFINE_CUSTOM_GETTER(testStaticValueGetter, (JSGlobalObject*, EncodedJSValue, PropertyName)) { DollarVMAssertScope assertScope; return JSValue::encode(jsUndefined()); } JSC_DEFINE_CUSTOM_SETTER(testStaticValuePutter, (JSGlobalObject* globalObject, EncodedJSValue thisValue, EncodedJSValue value, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSObject* thisObject = jsDynamicCast(vm, JSValue::decode(thisValue)); if (!thisObject) return throwVMTypeError(globalObject, scope); return thisObject->putDirect(vm, PropertyName(Identifier::fromString(vm, "testStaticValue")), JSValue::decode(value)); } JSC_DEFINE_CUSTOM_SETTER(testStaticValuePutterSetFlag, (JSGlobalObject* globalObject, EncodedJSValue thisValue, EncodedJSValue, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSObject* thisObject = jsDynamicCast(vm, JSValue::decode(thisValue)); if (!thisObject) return throwVMTypeError(globalObject, scope); return thisObject->putDirect(vm, PropertyName(Identifier::fromString(vm, "testStaticValueSetterCalled")), jsBoolean(true)); } static const struct CompactHashIndex staticCustomValueTableIndex[8] = { { 1, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { 3, -1 }, { 2, -1 }, { 0, -1 }, { -1, -1 }, }; static const struct HashTableValue staticCustomValueTableValues[4] = { { "testStaticValue", static_cast(PropertyAttribute::CustomValue), NoIntrinsic, { (intptr_t)static_cast(testStaticValueGetter), (intptr_t)static_cast(testStaticValuePutter) } }, { "testStaticValueNoSetter", PropertyAttribute::CustomValue | PropertyAttribute::DontEnum, NoIntrinsic, { (intptr_t)static_cast(testStaticValueGetter), 0 } }, { "testStaticValueReadOnly", PropertyAttribute::CustomValue | PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly, NoIntrinsic, { (intptr_t)static_cast(testStaticValueGetter), 0 } }, { "testStaticValueSetFlag", static_cast(PropertyAttribute::CustomValue), NoIntrinsic, { (intptr_t)static_cast(testStaticValueGetter), (intptr_t)static_cast(testStaticValuePutterSetFlag) } }, }; static const struct HashTable staticCustomValueTable = { 4, 7, true, nullptr, staticCustomValueTableValues, staticCustomValueTableIndex }; class StaticCustomValue : public JSNonFinalObject { using Base = JSNonFinalObject; public: StaticCustomValue(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } DECLARE_INFO; static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable; template static CompleteSubspace* subspaceFor(VM& vm) { return &vm.cellSpace(); } static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } static StaticCustomValue* create(VM& vm, Structure* structure) { DollarVMAssertScope assertScope; StaticCustomValue* accessor = new (NotNull, allocateCell(vm)) StaticCustomValue(vm, structure); accessor->finishCreation(vm); return accessor; } }; class ObjectDoingSideEffectPutWithoutCorrectSlotStatus : public JSNonFinalObject { using Base = JSNonFinalObject; static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesPut; public: template static CompleteSubspace* subspaceFor(VM& vm) { return &vm.cellSpace(); } ObjectDoingSideEffectPutWithoutCorrectSlotStatus(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } DECLARE_INFO; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } static ObjectDoingSideEffectPutWithoutCorrectSlotStatus* create(VM& vm, Structure* structure) { DollarVMAssertScope assertScope; ObjectDoingSideEffectPutWithoutCorrectSlotStatus* accessor = new (NotNull, allocateCell(vm)) ObjectDoingSideEffectPutWithoutCorrectSlotStatus(vm, structure); accessor->finishCreation(vm); return accessor; } static bool put(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { DollarVMAssertScope assertScope; auto* thisObject = jsCast(cell); auto throwScope = DECLARE_THROW_SCOPE(globalObject->vm()); auto* string = value.toString(globalObject); RETURN_IF_EXCEPTION(throwScope, false); RELEASE_AND_RETURN(throwScope, Base::put(thisObject, globalObject, propertyName, string, slot)); } }; class DOMJITNode : public JSNonFinalObject { public: DOMJITNode(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } DECLARE_INFO; typedef JSNonFinalObject Base; static constexpr unsigned StructureFlags = Base::StructureFlags; template static CompleteSubspace* subspaceFor(VM& vm) { return &vm.cellSpace(); } static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info()); } #if ENABLE(JIT) static Ref checkSubClassSnippet() { DollarVMAssertScope assertScope; Ref snippet = Snippet::create(); snippet->setGenerator([=] (CCallHelpers& jit, SnippetParams& params) { DollarVMAssertScope assertScope; CCallHelpers::JumpList failureCases; failureCases.append(jit.branchIfNotType(params[0].gpr(), JSC::JSType(LastJSCObjectType + 1))); return failureCases; }); return snippet; } #endif static DOMJITNode* create(VM& vm, Structure* structure) { DollarVMAssertScope assertScope; DOMJITNode* getter = new (NotNull, allocateCell(vm)) DOMJITNode(vm, structure); getter->finishCreation(vm); return getter; } int32_t value() const { return m_value; } static ptrdiff_t offsetOfValue() { return OBJECT_OFFSETOF(DOMJITNode, m_value); } private: int32_t m_value { 42 }; }; static JSC_DECLARE_CUSTOM_GETTER(domJITGetterCustomGetter); extern "C" { static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(domJITGetterSlowCall, EncodedJSValue, (JSGlobalObject*, void*)); } class DOMJITGetter : public DOMJITNode { public: DOMJITGetter(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } DECLARE_INFO; typedef DOMJITNode Base; static constexpr unsigned StructureFlags = Base::StructureFlags; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info()); } static DOMJITGetter* create(VM& vm, Structure* structure) { DollarVMAssertScope assertScope; DOMJITGetter* getter = new (NotNull, allocateCell(vm)) DOMJITGetter(vm, structure); getter->finishCreation(vm); return getter; } class DOMJITAttribute : public DOMJIT::GetterSetter { public: ALWAYS_INLINE constexpr DOMJITAttribute() : DOMJIT::GetterSetter( domJITGetterCustomGetter, #if ENABLE(JIT) &callDOMGetter, #else nullptr, #endif SpecInt32Only) { } #if ENABLE(JIT) static Ref callDOMGetter() { DollarVMAssertScope assertScope; Ref snippet = DOMJIT::CallDOMGetterSnippet::create(); snippet->requireGlobalObject = true; snippet->setGenerator([=] (CCallHelpers& jit, SnippetParams& params) { DollarVMAssertScope assertScope; JSValueRegs results = params[0].jsValueRegs(); GPRReg domGPR = params[1].gpr(); GPRReg globalObjectGPR = params[2].gpr(); params.addSlowPathCall(jit.jump(), jit, domJITGetterSlowCall, results, globalObjectGPR, domGPR); return CCallHelpers::JumpList(); }); return snippet; } #endif }; private: void finishCreation(VM&); }; static const DOMJITGetter::DOMJITAttribute DOMJITGetterDOMJIT; void DOMJITGetter::finishCreation(VM& vm) { DollarVMAssertScope assertScope; Base::finishCreation(vm); { const DOMJIT::GetterSetter* domJIT = &DOMJITGetterDOMJIT; auto* customGetterSetter = DOMAttributeGetterSetter::create(vm, domJIT->getter(), nullptr, DOMAttributeAnnotation { DOMJITNode::info(), domJIT }); putDirectCustomAccessor(vm, Identifier::fromString(vm, "customGetter"), customGetterSetter, PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor); } { auto* customGetterSetter = DOMAttributeGetterSetter::create(vm, domJITGetterCustomGetter, nullptr, DOMAttributeAnnotation { DOMJITNode::info(), nullptr }); putDirectCustomAccessor(vm, Identifier::fromString(vm, "customGetter2"), customGetterSetter, PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor); } } JSC_DEFINE_CUSTOM_GETTER(domJITGetterCustomGetter, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); DOMJITNode* thisObject = jsDynamicCast(vm, JSValue::decode(thisValue)); if (!thisObject) return throwVMTypeError(globalObject, scope); return JSValue::encode(jsNumber(thisObject->value())); } JSC_DEFINE_JIT_OPERATION(domJITGetterSlowCall, EncodedJSValue, (JSGlobalObject* globalObject, void* pointer)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); CallFrame* callFrame = DECLARE_CALL_FRAME(vm); JITOperationPrologueCallFrameTracer tracer(vm, callFrame); return JSValue::encode(jsNumber(static_cast(pointer)->value())); } static JSC_DECLARE_CUSTOM_GETTER(domJITGetterNoEffectCustomGetter); extern "C" { static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(domJITGetterNoEffectSlowCall, EncodedJSValue, (JSGlobalObject*, void*)); } class DOMJITGetterNoEffects : public DOMJITNode { public: DOMJITGetterNoEffects(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } DECLARE_INFO; typedef DOMJITNode Base; static constexpr unsigned StructureFlags = Base::StructureFlags; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info()); } static DOMJITGetterNoEffects* create(VM& vm, Structure* structure) { DollarVMAssertScope assertScope; DOMJITGetterNoEffects* getter = new (NotNull, allocateCell(vm)) DOMJITGetterNoEffects(vm, structure); getter->finishCreation(vm); return getter; } class DOMJITAttribute : public DOMJIT::GetterSetter { public: ALWAYS_INLINE constexpr DOMJITAttribute() : DOMJIT::GetterSetter( domJITGetterNoEffectCustomGetter, #if ENABLE(JIT) &callDOMGetter, #else nullptr, #endif SpecInt32Only) { } #if ENABLE(JIT) static Ref callDOMGetter() { DollarVMAssertScope assertScope; Ref snippet = DOMJIT::CallDOMGetterSnippet::create(); snippet->effect = DOMJIT::Effect::forRead(DOMJIT::HeapRange(10, 11)); snippet->requireGlobalObject = true; snippet->setGenerator([=] (CCallHelpers& jit, SnippetParams& params) { DollarVMAssertScope assertScope; JSValueRegs results = params[0].jsValueRegs(); GPRReg domGPR = params[1].gpr(); GPRReg globalObjectGPR = params[2].gpr(); params.addSlowPathCall(jit.jump(), jit, domJITGetterNoEffectSlowCall, results, globalObjectGPR, domGPR); return CCallHelpers::JumpList(); }); return snippet; } #endif }; private: void finishCreation(VM&); }; static const DOMJITGetterNoEffects::DOMJITAttribute DOMJITGetterNoEffectsDOMJIT; void DOMJITGetterNoEffects::finishCreation(VM& vm) { DollarVMAssertScope assertScope; Base::finishCreation(vm); const DOMJIT::GetterSetter* domJIT = &DOMJITGetterNoEffectsDOMJIT; auto* customGetterSetter = DOMAttributeGetterSetter::create(vm, domJIT->getter(), nullptr, DOMAttributeAnnotation { DOMJITNode::info(), domJIT }); putDirectCustomAccessor(vm, Identifier::fromString(vm, "customGetter"), customGetterSetter, PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor); } JSC_DEFINE_CUSTOM_GETTER(domJITGetterNoEffectCustomGetter, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); DOMJITNode* thisObject = jsDynamicCast(vm, JSValue::decode(thisValue)); if (!thisObject) return throwVMTypeError(globalObject, scope); return JSValue::encode(jsNumber(thisObject->value())); } JSC_DEFINE_JIT_OPERATION(domJITGetterNoEffectSlowCall, EncodedJSValue, (JSGlobalObject* globalObject, void* pointer)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); CallFrame* callFrame = DECLARE_CALL_FRAME(vm); JITOperationPrologueCallFrameTracer tracer(vm, callFrame); return JSValue::encode(jsNumber(static_cast(pointer)->value())); } static JSC_DECLARE_CUSTOM_GETTER(domJITGetterComplexCustomGetter); extern "C" { static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(domJITGetterComplexSlowCall, EncodedJSValue, (JSGlobalObject*, void*)); } class DOMJITGetterComplex : public DOMJITNode { public: DOMJITGetterComplex(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } DECLARE_INFO; typedef DOMJITNode Base; static constexpr unsigned StructureFlags = Base::StructureFlags; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info()); } static DOMJITGetterComplex* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) { DollarVMAssertScope assertScope; DOMJITGetterComplex* getter = new (NotNull, allocateCell(vm)) DOMJITGetterComplex(vm, structure); getter->finishCreation(vm, globalObject); return getter; } class DOMJITAttribute : public DOMJIT::GetterSetter { public: ALWAYS_INLINE constexpr DOMJITAttribute() : DOMJIT::GetterSetter( domJITGetterComplexCustomGetter, #if ENABLE(JIT) &callDOMGetter, #else nullptr, #endif SpecInt32Only) { } #if ENABLE(JIT) static Ref callDOMGetter() { DollarVMAssertScope assertScope; Ref snippet = DOMJIT::CallDOMGetterSnippet::create(); static_assert(GPRInfo::numberOfRegisters >= 4, "Number of registers should be larger or equal to 4."); unsigned numGPScratchRegisters = GPRInfo::numberOfRegisters - 4; snippet->numGPScratchRegisters = numGPScratchRegisters; snippet->numFPScratchRegisters = 3; snippet->requireGlobalObject = true; snippet->setGenerator([=] (CCallHelpers& jit, SnippetParams& params) { DollarVMAssertScope assertScope; JSValueRegs results = params[0].jsValueRegs(); GPRReg domGPR = params[1].gpr(); GPRReg globalObjectGPR = params[2].gpr(); for (unsigned i = 0; i < numGPScratchRegisters; ++i) jit.move(CCallHelpers::TrustedImm32(42), params.gpScratch(i)); params.addSlowPathCall(jit.jump(), jit, domJITGetterComplexSlowCall, results, globalObjectGPR, domGPR); return CCallHelpers::JumpList(); }); return snippet; } #endif }; void finishCreation(VM&, JSGlobalObject*); bool m_enableException { false }; }; JSC_DEFINE_HOST_FUNCTION(functionDOMJITGetterComplexEnableException, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto* object = jsDynamicCast(vm, callFrame->thisValue()); if (object) object->m_enableException = true; return JSValue::encode(jsUndefined()); } JSC_DEFINE_CUSTOM_GETTER(domJITGetterComplexCustomGetter, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); auto* thisObject = jsDynamicCast(vm, JSValue::decode(thisValue)); if (!thisObject) return throwVMTypeError(globalObject, scope); if (thisObject->m_enableException) return JSValue::encode(throwException(globalObject, scope, createError(globalObject, "DOMJITGetterComplex slow call exception"_s))); return JSValue::encode(jsNumber(thisObject->value())); } JSC_DEFINE_JIT_OPERATION(domJITGetterComplexSlowCall, EncodedJSValue, (JSGlobalObject* globalObject, void* pointer)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); CallFrame* callFrame = DECLARE_CALL_FRAME(vm); JITOperationPrologueCallFrameTracer tracer(vm, callFrame); auto scope = DECLARE_THROW_SCOPE(vm); auto* object = static_cast(pointer); auto* domjitGetterComplex = jsDynamicCast(vm, object); if (domjitGetterComplex) { if (domjitGetterComplex->m_enableException) return JSValue::encode(throwException(globalObject, scope, createError(globalObject, "DOMJITGetterComplex slow call exception"_s))); } return JSValue::encode(jsNumber(object->value())); } static const DOMJITGetterComplex::DOMJITAttribute DOMJITGetterComplexDOMJIT; void DOMJITGetterComplex::finishCreation(VM& vm, JSGlobalObject* globalObject) { DollarVMAssertScope assertScope; Base::finishCreation(vm); const DOMJIT::GetterSetter* domJIT = &DOMJITGetterComplexDOMJIT; auto* customGetterSetter = DOMAttributeGetterSetter::create(vm, domJIT->getter(), nullptr, DOMAttributeAnnotation { DOMJITGetterComplex::info(), domJIT }); putDirectCustomAccessor(vm, Identifier::fromString(vm, "customGetter"), customGetterSetter, PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor); putDirectNativeFunction(vm, globalObject, Identifier::fromString(vm, "enableException"), 0, functionDOMJITGetterComplexEnableException, NoIntrinsic, 0); } extern "C" { static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(functionDOMJITFunctionObjectWithoutTypeCheck, EncodedJSValue, (JSGlobalObject* globalObject, DOMJITNode*)); } class DOMJITFunctionObject : public DOMJITNode { public: DOMJITFunctionObject(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } DECLARE_INFO; typedef DOMJITNode Base; static constexpr unsigned StructureFlags = Base::StructureFlags; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info()); } static DOMJITFunctionObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) { DollarVMAssertScope assertScope; DOMJITFunctionObject* object = new (NotNull, allocateCell(vm)) DOMJITFunctionObject(vm, structure); object->finishCreation(vm, globalObject); return object; } #if ENABLE(JIT) static Ref checkSubClassSnippet() { DollarVMAssertScope assertScope; Ref snippet = Snippet::create(); snippet->numFPScratchRegisters = 1; snippet->setGenerator([=] (CCallHelpers& jit, SnippetParams& params) { DollarVMAssertScope assertScope; static const double value = 42.0; CCallHelpers::JumpList failureCases; // May use scratch registers. jit.loadDouble(CCallHelpers::TrustedImmPtr(&value), params.fpScratch(0)); failureCases.append(jit.branchIfNotType(params[0].gpr(), JSC::JSType(LastJSCObjectType + 1))); return failureCases; }); return snippet; } #endif private: void finishCreation(VM&, JSGlobalObject*); }; JSC_DEFINE_HOST_FUNCTION(functionDOMJITFunctionObjectWithTypeCheck, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); DOMJITNode* thisObject = jsDynamicCast(vm, callFrame->thisValue()); if (!thisObject) return throwVMTypeError(globalObject, scope); return JSValue::encode(jsNumber(thisObject->value())); } JSC_DEFINE_JIT_OPERATION(functionDOMJITFunctionObjectWithoutTypeCheck, EncodedJSValue, (JSGlobalObject* globalObject, DOMJITNode* node)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); CallFrame* callFrame = DECLARE_CALL_FRAME(vm); JITOperationPrologueCallFrameTracer tracer(vm, callFrame); return JSValue::encode(jsNumber(node->value())); } static const DOMJIT::Signature DOMJITFunctionObjectSignature(functionDOMJITFunctionObjectWithoutTypeCheck, DOMJITFunctionObject::info(), DOMJIT::Effect::forRead(DOMJIT::HeapRange(DOMJIT::HeapRange::ConstExpr, 0, 1)), SpecInt32Only); void DOMJITFunctionObject::finishCreation(VM& vm, JSGlobalObject* globalObject) { DollarVMAssertScope assertScope; Base::finishCreation(vm); putDirectNativeFunction(vm, globalObject, Identifier::fromString(vm, "func"), 0, functionDOMJITFunctionObjectWithTypeCheck, NoIntrinsic, &DOMJITFunctionObjectSignature, static_cast(PropertyAttribute::ReadOnly)); } extern "C" { static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(functionDOMJITCheckJSCastObjectWithoutTypeCheck, EncodedJSValue, (JSGlobalObject* globalObject, DOMJITNode* node)); } class DOMJITCheckJSCastObject : public DOMJITNode { public: DOMJITCheckJSCastObject(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } DECLARE_INFO; typedef DOMJITNode Base; static constexpr unsigned StructureFlags = Base::StructureFlags; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info()); } static DOMJITCheckJSCastObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) { DollarVMAssertScope assertScope; DOMJITCheckJSCastObject* object = new (NotNull, allocateCell(vm)) DOMJITCheckJSCastObject(vm, structure); object->finishCreation(vm, globalObject); return object; } private: void finishCreation(VM&, JSGlobalObject*); }; JSC_DEFINE_HOST_FUNCTION(functionDOMJITCheckJSCastObjectWithTypeCheck, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); auto* thisObject = jsDynamicCast(vm, callFrame->thisValue()); if (!thisObject) return throwVMTypeError(globalObject, scope); return JSValue::encode(jsNumber(thisObject->value())); } JSC_DEFINE_JIT_OPERATION(functionDOMJITCheckJSCastObjectWithoutTypeCheck, EncodedJSValue, (JSGlobalObject* globalObject, DOMJITNode* node)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); CallFrame* callFrame = DECLARE_CALL_FRAME(vm); JITOperationPrologueCallFrameTracer tracer(vm, callFrame); return JSValue::encode(jsNumber(node->value())); } static const DOMJIT::Signature DOMJITCheckJSCastObjectSignature(functionDOMJITCheckJSCastObjectWithoutTypeCheck, DOMJITCheckJSCastObject::info(), DOMJIT::Effect::forRead(DOMJIT::HeapRange::top()), SpecInt32Only); void DOMJITCheckJSCastObject::finishCreation(VM& vm, JSGlobalObject* globalObject) { DollarVMAssertScope assertScope; Base::finishCreation(vm); putDirectNativeFunction(vm, globalObject, Identifier::fromString(vm, "func"), 0, functionDOMJITCheckJSCastObjectWithTypeCheck, NoIntrinsic, &DOMJITCheckJSCastObjectSignature, static_cast(PropertyAttribute::ReadOnly)); } static JSC_DECLARE_CUSTOM_GETTER(domJITGetterBaseJSObjectCustomGetter); extern "C" { static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(domJITGetterBaseJSObjectSlowCall, EncodedJSValue, (JSGlobalObject*, void*)); } class DOMJITGetterBaseJSObject : public DOMJITNode { public: DOMJITGetterBaseJSObject(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } DECLARE_INFO; using Base = DOMJITNode; static constexpr unsigned StructureFlags = Base::StructureFlags; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info()); } static DOMJITGetterBaseJSObject* create(VM& vm, Structure* structure) { DollarVMAssertScope assertScope; DOMJITGetterBaseJSObject* getter = new (NotNull, allocateCell(vm)) DOMJITGetterBaseJSObject(vm, structure); getter->finishCreation(vm); return getter; } class DOMJITAttribute : public DOMJIT::GetterSetter { public: ALWAYS_INLINE constexpr DOMJITAttribute() : DOMJIT::GetterSetter( domJITGetterBaseJSObjectCustomGetter, #if ENABLE(JIT) &callDOMGetter, #else nullptr, #endif SpecBytecodeTop) { } #if ENABLE(JIT) static Ref callDOMGetter() { DollarVMAssertScope assertScope; Ref snippet = DOMJIT::CallDOMGetterSnippet::create(); snippet->requireGlobalObject = true; snippet->setGenerator([=] (CCallHelpers& jit, SnippetParams& params) { DollarVMAssertScope assertScope; JSValueRegs results = params[0].jsValueRegs(); GPRReg domGPR = params[1].gpr(); GPRReg globalObjectGPR = params[2].gpr(); params.addSlowPathCall(jit.jump(), jit, domJITGetterBaseJSObjectSlowCall, results, globalObjectGPR, domGPR); return CCallHelpers::JumpList(); }); return snippet; } #endif }; private: void finishCreation(VM&); }; static const DOMJITGetterBaseJSObject::DOMJITAttribute DOMJITGetterBaseJSObjectDOMJIT; void DOMJITGetterBaseJSObject::finishCreation(VM& vm) { DollarVMAssertScope assertScope; Base::finishCreation(vm); const DOMJIT::GetterSetter* domJIT = &DOMJITGetterBaseJSObjectDOMJIT; auto* customGetterSetter = DOMAttributeGetterSetter::create(vm, domJIT->getter(), nullptr, DOMAttributeAnnotation { JSObject::info(), domJIT }); putDirectCustomAccessor(vm, Identifier::fromString(vm, "customGetter"), customGetterSetter, PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor); } JSC_DEFINE_CUSTOM_GETTER(domJITGetterBaseJSObjectCustomGetter, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSObject* thisObject = jsDynamicCast(vm, JSValue::decode(thisValue)); if (!thisObject) return throwVMTypeError(globalObject, scope); return JSValue::encode(thisObject->getPrototypeDirect(vm)); } JSC_DEFINE_JIT_OPERATION(domJITGetterBaseJSObjectSlowCall, EncodedJSValue, (JSGlobalObject* globalObject, void* pointer)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); CallFrame* callFrame = DECLARE_CALL_FRAME(vm); JITOperationPrologueCallFrameTracer tracer(vm, callFrame); JSObject* object = static_cast(pointer); return JSValue::encode(object->getPrototypeDirect(vm)); } class Message : public ThreadSafeRefCounted { public: Message(ArrayBufferContents&&, int32_t); ~Message(); ArrayBufferContents&& releaseContents() { return WTFMove(m_contents); } int32_t index() const { return m_index; } private: ArrayBufferContents m_contents; int32_t m_index { 0 }; }; class JSTestCustomGetterSetter : public JSNonFinalObject { public: using Base = JSNonFinalObject; static constexpr unsigned StructureFlags = Base::StructureFlags; template static CompleteSubspace* subspaceFor(VM& vm) { return &vm.cellSpace(); } JSTestCustomGetterSetter(VM& vm, Structure* structure) : Base(vm, structure) { DollarVMAssertScope assertScope; } static JSTestCustomGetterSetter* create(VM& vm, JSGlobalObject*, Structure* structure) { DollarVMAssertScope assertScope; JSTestCustomGetterSetter* result = new (NotNull, allocateCell(vm)) JSTestCustomGetterSetter(vm, structure); result->finishCreation(vm); return result; } void finishCreation(VM&); static Structure* createStructure(VM& vm, JSGlobalObject* globalObject) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, globalObject->objectPrototype(), TypeInfo(ObjectType, StructureFlags), info()); } DECLARE_INFO; }; static JSC_DECLARE_CUSTOM_GETTER(customGetAccessor); static JSC_DECLARE_CUSTOM_GETTER(customGetValue); static JSC_DECLARE_CUSTOM_GETTER(customGetValue2); static JSC_DECLARE_CUSTOM_GETTER(customGetAccessorGlobalObject); static JSC_DECLARE_CUSTOM_GETTER(customGetValueGlobalObject); static JSC_DECLARE_CUSTOM_SETTER(customSetAccessor); static JSC_DECLARE_CUSTOM_SETTER(customSetAccessorGlobalObject); static JSC_DECLARE_CUSTOM_SETTER(customSetValue); static JSC_DECLARE_CUSTOM_SETTER(customSetValue2); static JSC_DECLARE_CUSTOM_SETTER(customSetValueGlobalObject); static JSC_DECLARE_CUSTOM_SETTER(customFunctionSetter); JSC_DEFINE_CUSTOM_GETTER(customGetAccessor, (JSGlobalObject*, EncodedJSValue thisValue, PropertyName)) { // Passed |this| return thisValue; } JSC_DEFINE_CUSTOM_GETTER(customGetValue, (JSGlobalObject* globalObject, EncodedJSValue slotValue, PropertyName)) { RELEASE_ASSERT(JSValue::decode(slotValue).inherits(globalObject->vm())); // Passed property holder. return slotValue; } JSC_DEFINE_CUSTOM_GETTER(customGetValue2, (JSGlobalObject* globalObject, EncodedJSValue slotValue, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); RELEASE_ASSERT(JSValue::decode(slotValue).inherits(globalObject->vm())); auto* target = jsCast(JSValue::decode(slotValue)); JSValue value = target->getDirect(vm, Identifier::fromString(vm, "value2")); return JSValue::encode(value ? value : jsUndefined()); } JSC_DEFINE_CUSTOM_GETTER(customGetAccessorGlobalObject, (JSGlobalObject* globalObject, EncodedJSValue, PropertyName)) { return JSValue::encode(globalObject); } JSC_DEFINE_CUSTOM_GETTER(customGetValueGlobalObject, (JSGlobalObject* globalObject, EncodedJSValue, PropertyName)) { return JSValue::encode(globalObject); } JSC_DEFINE_CUSTOM_SETTER(customSetAccessor, (JSGlobalObject* globalObject, EncodedJSValue thisObject, EncodedJSValue encodedValue, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSValue value = JSValue::decode(encodedValue); if (!value.isObject()) return false; JSObject* object = asObject(value); PutPropertySlot slot(object); object->put(object, globalObject, Identifier::fromString(vm, "result"), JSValue::decode(thisObject), slot); return true; } JSC_DEFINE_CUSTOM_SETTER(customSetAccessorGlobalObject, (JSGlobalObject* globalObject, EncodedJSValue, EncodedJSValue encodedValue, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSValue value = JSValue::decode(encodedValue); if (!value.isObject()) return false; JSObject* object = asObject(value); PutPropertySlot slot(object); object->put(object, globalObject, Identifier::fromString(vm, "result"), globalObject, slot); return true; } JSC_DEFINE_CUSTOM_SETTER(customSetValue, (JSGlobalObject* globalObject, EncodedJSValue slotValue, EncodedJSValue encodedValue, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); RELEASE_ASSERT(JSValue::decode(slotValue).inherits(globalObject->vm())); JSValue value = JSValue::decode(encodedValue); if (!value.isObject()) return false; JSObject* object = asObject(value); PutPropertySlot slot(object); object->put(object, globalObject, Identifier::fromString(vm, "result"), JSValue::decode(slotValue), slot); return true; } JSC_DEFINE_CUSTOM_SETTER(customSetValueGlobalObject, (JSGlobalObject* globalObject, EncodedJSValue slotValue, EncodedJSValue encodedValue, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); RELEASE_ASSERT(JSValue::decode(slotValue).inherits(globalObject->vm())); JSValue value = JSValue::decode(encodedValue); if (!value.isObject()) return false; JSObject* object = asObject(value); PutPropertySlot slot(object); object->put(object, globalObject, Identifier::fromString(vm, "result"), globalObject, slot); return true; } JSC_DEFINE_CUSTOM_SETTER(customSetValue2, (JSGlobalObject* globalObject, EncodedJSValue slotValue, EncodedJSValue encodedValue, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); RELEASE_ASSERT(JSValue::decode(slotValue).inherits(vm)); auto* target = jsCast(JSValue::decode(slotValue)); PutPropertySlot slot(target); target->putDirect(vm, Identifier::fromString(vm, "value2"), JSValue::decode(encodedValue)); return true; } JSC_DEFINE_CUSTOM_SETTER(customFunctionSetter, (JSGlobalObject* globalObject, EncodedJSValue, EncodedJSValue encodedValue, PropertyName)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSValue value = JSValue::decode(encodedValue); JSFunction* function = jsDynamicCast(vm, value); if (!function) return false; auto callData = getCallData(vm, function); MarkedArgumentBuffer args; call(globalObject, function, callData, jsUndefined(), args); return true; } void JSTestCustomGetterSetter::finishCreation(VM& vm) { DollarVMAssertScope assertScope; Base::finishCreation(vm); putDirectCustomAccessor(vm, Identifier::fromString(vm, "customValue"), CustomGetterSetter::create(vm, customGetValue, customSetValue), 0); putDirectCustomAccessor(vm, Identifier::fromString(vm, "customValue2"), CustomGetterSetter::create(vm, customGetValue2, customSetValue2), static_cast(PropertyAttribute::CustomValue)); putDirectCustomAccessor(vm, Identifier::fromString(vm, "customAccessor"), CustomGetterSetter::create(vm, customGetAccessor, customSetAccessor), static_cast(PropertyAttribute::CustomAccessor)); putDirectCustomAccessor(vm, Identifier::fromString(vm, "customValueGlobalObject"), CustomGetterSetter::create(vm, customGetValueGlobalObject, customSetValueGlobalObject), static_cast(PropertyAttribute::CustomValue)); putDirectCustomAccessor(vm, Identifier::fromString(vm, "customAccessorGlobalObject"), CustomGetterSetter::create(vm, customGetAccessorGlobalObject, customSetAccessorGlobalObject), static_cast(PropertyAttribute::CustomAccessor)); putDirectCustomAccessor(vm, Identifier::fromString(vm, "customValueNoSetter"), CustomGetterSetter::create(vm, customGetValue, nullptr), static_cast(PropertyAttribute::CustomValue)); putDirectCustomAccessor(vm, Identifier::fromString(vm, "customAccessorReadOnly"), CustomGetterSetter::create(vm, customGetAccessor, nullptr), PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly); putDirectCustomAccessor(vm, Identifier::fromString(vm, "customFunction"), CustomGetterSetter::create(vm, customGetAccessor, customFunctionSetter), static_cast(PropertyAttribute::CustomAccessor)); } const ClassInfo Element::s_info = { "Element", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(Element) }; const ClassInfo Root::s_info = { "Root", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(Root) }; const ClassInfo SimpleObject::s_info = { "SimpleObject", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(SimpleObject) }; const ClassInfo ImpureGetter::s_info = { "ImpureGetter", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(ImpureGetter) }; const ClassInfo CustomGetter::s_info = { "CustomGetter", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(CustomGetter) }; const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(RuntimeArray) }; #if ENABLE(JIT) const ClassInfo DOMJITNode::s_info = { "DOMJITNode", &Base::s_info, nullptr, &DOMJITNode::checkSubClassSnippet, CREATE_METHOD_TABLE(DOMJITNode) }; #else const ClassInfo DOMJITNode::s_info = { "DOMJITNode", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DOMJITNode) }; #endif const ClassInfo DOMJITGetter::s_info = { "DOMJITGetter", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DOMJITGetter) }; const ClassInfo DOMJITGetterNoEffects::s_info = { "DOMJITGetterNoEffects", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DOMJITGetterNoEffects) }; const ClassInfo DOMJITGetterComplex::s_info = { "DOMJITGetterComplex", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DOMJITGetterComplex) }; const ClassInfo DOMJITGetterBaseJSObject::s_info = { "DOMJITGetterBaseJSObject", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DOMJITGetterBaseJSObject) }; #if ENABLE(JIT) const ClassInfo DOMJITFunctionObject::s_info = { "DOMJITFunctionObject", &Base::s_info, nullptr, &DOMJITFunctionObject::checkSubClassSnippet, CREATE_METHOD_TABLE(DOMJITFunctionObject) }; #else const ClassInfo DOMJITFunctionObject::s_info = { "DOMJITFunctionObject", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DOMJITFunctionObject) }; #endif const ClassInfo DOMJITCheckJSCastObject::s_info = { "DOMJITCheckJSCastObject", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DOMJITCheckJSCastObject) }; const ClassInfo JSTestCustomGetterSetter::s_info = { "JSTestCustomGetterSetter", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTestCustomGetterSetter) }; const ClassInfo StaticCustomAccessor::s_info = { "StaticCustomAccessor", &Base::s_info, &staticCustomAccessorTable, nullptr, CREATE_METHOD_TABLE(StaticCustomAccessor) }; const ClassInfo StaticCustomValue::s_info = { "StaticCustomValue", &Base::s_info, &staticCustomValueTable, nullptr, CREATE_METHOD_TABLE(StaticCustomValue) }; const ClassInfo ObjectDoingSideEffectPutWithoutCorrectSlotStatus::s_info = { "ObjectDoingSideEffectPutWithoutCorrectSlotStatus", &Base::s_info, &staticCustomAccessorTable, nullptr, CREATE_METHOD_TABLE(ObjectDoingSideEffectPutWithoutCorrectSlotStatus) }; ElementHandleOwner* Element::handleOwner() { DollarVMAssertScope assertScope; static ElementHandleOwner* owner = nullptr; if (!owner) owner = new ElementHandleOwner(); return owner; } void Element::finishCreation(VM& vm, Root* root) { DollarVMAssertScope assertScope; Base::finishCreation(vm); setRoot(vm, root); m_root->setElement(this); } #if ENABLE(WEBASSEMBLY) static JSC_DECLARE_HOST_FUNCTION(functionWasmStreamingParserAddBytes); static JSC_DECLARE_HOST_FUNCTION(functionWasmStreamingParserFinalize); class WasmStreamingParser : public JSDestructibleObject { public: using Base = JSDestructibleObject; template static CompleteSubspace* subspaceFor(VM& vm) { return &vm.destructibleObjectSpace(); } class Client final : public Wasm::StreamingParserClient { public: explicit Client(WasmStreamingParser* parser) : m_parser(parser) { } bool didReceiveSectionData(Wasm::Section) final { return true; } bool didReceiveFunctionData(unsigned, const Wasm::FunctionData&) final { return true; } void didFinishParsing() final { } WasmStreamingParser* m_parser; }; WasmStreamingParser(VM& vm, Structure* structure) : Base(vm, structure) , m_info(Wasm::ModuleInformation::create()) , m_client(this) , m_streamingParser(m_info.get(), m_client) { DollarVMAssertScope assertScope; } static WasmStreamingParser* create(VM& vm, JSGlobalObject* globalObject) { DollarVMAssertScope assertScope; Structure* structure = createStructure(vm, globalObject, jsNull()); WasmStreamingParser* result = new (NotNull, allocateCell(vm)) WasmStreamingParser(vm, structure); result->finishCreation(vm); return result; } static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } Wasm::StreamingParser& streamingParser() { return m_streamingParser; } void finishCreation(VM& vm) { DollarVMAssertScope assertScope; Base::finishCreation(vm); JSGlobalObject* globalObject = this->globalObject(vm); putDirectNativeFunction(vm, globalObject, Identifier::fromString(vm, "addBytes"), 0, functionWasmStreamingParserAddBytes, NoIntrinsic, static_cast(PropertyAttribute::DontEnum)); putDirectNativeFunction(vm, globalObject, Identifier::fromString(vm, "finalize"), 0, functionWasmStreamingParserFinalize, NoIntrinsic, static_cast(PropertyAttribute::DontEnum)); } DECLARE_INFO; Ref m_info; Client m_client; Wasm::StreamingParser m_streamingParser; }; const ClassInfo WasmStreamingParser::s_info = { "WasmStreamingParser", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(WasmStreamingParser) }; JSC_DEFINE_HOST_FUNCTION(functionWasmStreamingParserAddBytes, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); auto* thisObject = jsDynamicCast(vm, callFrame->thisValue()); if (!thisObject) RELEASE_AND_RETURN(scope, JSValue::encode(jsBoolean(false))); auto data = getWasmBufferFromValue(globalObject, callFrame->argument(0)); RETURN_IF_EXCEPTION(scope, encodedJSValue()); RELEASE_AND_RETURN(scope, JSValue::encode(jsNumber(static_cast(thisObject->streamingParser().addBytes(bitwise_cast(data.first), data.second))))); } JSC_DEFINE_HOST_FUNCTION(functionWasmStreamingParserFinalize, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto* thisObject = jsDynamicCast(vm, callFrame->thisValue()); if (!thisObject) return JSValue::encode(jsBoolean(false)); return JSValue::encode(jsNumber(static_cast(thisObject->streamingParser().finalize()))); } static JSC_DECLARE_HOST_FUNCTION(functionWasmStreamingCompilerAddBytes); class WasmStreamingCompiler : public JSDestructibleObject { public: using Base = JSDestructibleObject; template static CompleteSubspace* subspaceFor(VM& vm) { return &vm.destructibleObjectSpace(); } WasmStreamingCompiler(VM& vm, Structure* structure, Wasm::CompilerMode compilerMode, JSGlobalObject* globalObject, JSPromise* promise, JSObject* importObject) : Base(vm, structure) , m_promise(vm, this, promise) , m_streamingCompiler(Wasm::StreamingCompiler::create(vm, compilerMode, globalObject, promise, importObject)) { DollarVMAssertScope assertScope; } static WasmStreamingCompiler* create(VM& vm, JSGlobalObject* globalObject, Wasm::CompilerMode compilerMode, JSObject* importObject) { DollarVMAssertScope assertScope; JSPromise* promise = JSPromise::create(vm, globalObject->promiseStructure()); Structure* structure = createStructure(vm, globalObject, jsNull()); WasmStreamingCompiler* result = new (NotNull, allocateCell(vm)) WasmStreamingCompiler(vm, structure, compilerMode, globalObject, promise, importObject); result->finishCreation(vm); return result; } static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { DollarVMAssertScope assertScope; return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } Wasm::StreamingCompiler& streamingCompiler() { return m_streamingCompiler.get(); } JSPromise* promise() const { return m_promise.get(); } void finishCreation(VM& vm) { DollarVMAssertScope assertScope; Base::finishCreation(vm); JSGlobalObject* globalObject = this->globalObject(vm); putDirectNativeFunction(vm, globalObject, Identifier::fromString(vm, "addBytes"), 0, functionWasmStreamingCompilerAddBytes, NoIntrinsic, static_cast(PropertyAttribute::DontEnum)); } DECLARE_VISIT_CHILDREN; DECLARE_INFO; WriteBarrier m_promise; Ref m_streamingCompiler; }; template void WasmStreamingCompiler::visitChildrenImpl(JSCell* cell, Visitor& visitor) { DollarVMAssertScope assertScope; auto* thisObject = jsCast(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); Base::visitChildren(thisObject, visitor); visitor.append(thisObject->m_promise); } DEFINE_VISIT_CHILDREN(WasmStreamingCompiler); const ClassInfo WasmStreamingCompiler::s_info = { "WasmStreamingCompiler", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(WasmStreamingCompiler) }; JSC_DEFINE_HOST_FUNCTION(functionWasmStreamingCompilerAddBytes, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); auto* thisObject = jsDynamicCast(vm, callFrame->thisValue()); if (!thisObject) RELEASE_AND_RETURN(scope, JSValue::encode(jsBoolean(false))); auto data = getWasmBufferFromValue(globalObject, callFrame->argument(0)); RETURN_IF_EXCEPTION(scope, { }); thisObject->streamingCompiler().addBytes(bitwise_cast(data.first), data.second); return JSValue::encode(jsUndefined()); } #endif } // namespace namespace JSC { static NO_RETURN_DUE_TO_CRASH JSC_DECLARE_HOST_FUNCTION(functionCrash); static JSC_DECLARE_HOST_FUNCTION(functionBreakpoint); static JSC_DECLARE_HOST_FUNCTION(functionDFGTrue); static JSC_DECLARE_HOST_FUNCTION(functionFTLTrue); static JSC_DECLARE_HOST_FUNCTION(functionCpuMfence); static JSC_DECLARE_HOST_FUNCTION(functionCpuRdtsc); static JSC_DECLARE_HOST_FUNCTION(functionCpuCpuid); static JSC_DECLARE_HOST_FUNCTION(functionCpuPause); static JSC_DECLARE_HOST_FUNCTION(functionCpuClflush); static JSC_DECLARE_HOST_FUNCTION(functionLLintTrue); static JSC_DECLARE_HOST_FUNCTION(functionBaselineJITTrue); static JSC_DECLARE_HOST_FUNCTION(functionNoInline); static JSC_DECLARE_HOST_FUNCTION(functionGC); static JSC_DECLARE_HOST_FUNCTION(functionEdenGC); static JSC_DECLARE_HOST_FUNCTION(functionGCSweepAsynchronously); static JSC_DECLARE_HOST_FUNCTION(functionDumpSubspaceHashes); static JSC_DECLARE_HOST_FUNCTION(functionCallFrame); static JSC_DECLARE_HOST_FUNCTION(functionCodeBlockForFrame); static JSC_DECLARE_HOST_FUNCTION(functionCodeBlockFor); static JSC_DECLARE_HOST_FUNCTION(functionDumpSourceFor); static JSC_DECLARE_HOST_FUNCTION(functionDumpBytecodeFor); static JSC_DECLARE_HOST_FUNCTION(functionDataLog); static JSC_DECLARE_HOST_FUNCTION(functionPrint); static JSC_DECLARE_HOST_FUNCTION(functionDumpCallFrame); static JSC_DECLARE_HOST_FUNCTION(functionDumpStack); static JSC_DECLARE_HOST_FUNCTION(functionDumpRegisters); static JSC_DECLARE_HOST_FUNCTION(functionDumpCell); static JSC_DECLARE_HOST_FUNCTION(functionIndexingMode); static JSC_DECLARE_HOST_FUNCTION(functionInlineCapacity); static JSC_DECLARE_HOST_FUNCTION(functionClearLinkBufferStats); static JSC_DECLARE_HOST_FUNCTION(functionLinkBufferStats); static JSC_DECLARE_HOST_FUNCTION(functionValue); static JSC_DECLARE_HOST_FUNCTION(functionGetPID); static JSC_DECLARE_HOST_FUNCTION(functionHaveABadTime); static JSC_DECLARE_HOST_FUNCTION(functionIsHavingABadTime); static JSC_DECLARE_HOST_FUNCTION(functionCallWithStackSize); static JSC_DECLARE_HOST_FUNCTION(functionCreateGlobalObject); static JSC_DECLARE_HOST_FUNCTION(functionCreateProxy); static JSC_DECLARE_HOST_FUNCTION(functionCreateRuntimeArray); static JSC_DECLARE_HOST_FUNCTION(functionCreateNullRopeString); static JSC_DECLARE_HOST_FUNCTION(functionCreateImpureGetter); static JSC_DECLARE_HOST_FUNCTION(functionCreateCustomGetterObject); static JSC_DECLARE_HOST_FUNCTION(functionCreateDOMJITNodeObject); static JSC_DECLARE_HOST_FUNCTION(functionCreateDOMJITGetterObject); static JSC_DECLARE_HOST_FUNCTION(functionCreateDOMJITGetterNoEffectsObject); static JSC_DECLARE_HOST_FUNCTION(functionCreateDOMJITGetterComplexObject); static JSC_DECLARE_HOST_FUNCTION(functionCreateDOMJITFunctionObject); static JSC_DECLARE_HOST_FUNCTION(functionCreateDOMJITCheckJSCastObject); static JSC_DECLARE_HOST_FUNCTION(functionCreateDOMJITGetterBaseJSObject); #if ENABLE(WEBASSEMBLY) static JSC_DECLARE_HOST_FUNCTION(functionCreateWasmStreamingParser); static JSC_DECLARE_HOST_FUNCTION(functionCreateWasmStreamingCompilerForCompile); static JSC_DECLARE_HOST_FUNCTION(functionCreateWasmStreamingCompilerForInstantiate); #endif static JSC_DECLARE_HOST_FUNCTION(functionCreateStaticCustomAccessor); static JSC_DECLARE_HOST_FUNCTION(functionCreateStaticCustomValue); static JSC_DECLARE_HOST_FUNCTION(functionCreateObjectDoingSideEffectPutWithoutCorrectSlotStatus); static JSC_DECLARE_HOST_FUNCTION(functionCreateEmptyFunctionWithName); static JSC_DECLARE_HOST_FUNCTION(functionSetImpureGetterDelegate); static JSC_DECLARE_HOST_FUNCTION(functionCreateBuiltin); static JSC_DECLARE_HOST_FUNCTION(functionGetPrivateProperty); static JSC_DECLARE_HOST_FUNCTION(functionCreateRoot); static JSC_DECLARE_HOST_FUNCTION(functionCreateElement); static JSC_DECLARE_HOST_FUNCTION(functionGetElement); static JSC_DECLARE_HOST_FUNCTION(functionCreateSimpleObject); static JSC_DECLARE_HOST_FUNCTION(functionGetHiddenValue); static JSC_DECLARE_HOST_FUNCTION(functionSetHiddenValue); static JSC_DECLARE_HOST_FUNCTION(functionShadowChickenFunctionsOnStack); static JSC_DECLARE_HOST_FUNCTION(functionSetGlobalConstRedeclarationShouldNotThrow); static JSC_DECLARE_HOST_FUNCTION(functionFindTypeForExpression); static JSC_DECLARE_HOST_FUNCTION(functionReturnTypeFor); static JSC_DECLARE_HOST_FUNCTION(functionFlattenDictionaryObject); static JSC_DECLARE_HOST_FUNCTION(functionDumpBasicBlockExecutionRanges); static JSC_DECLARE_HOST_FUNCTION(functionHasBasicBlockExecuted); static JSC_DECLARE_HOST_FUNCTION(functionBasicBlockExecutionCount); static JSC_DECLARE_HOST_FUNCTION(functionEnableDebuggerModeWhenIdle); static JSC_DECLARE_HOST_FUNCTION(functionDisableDebuggerModeWhenIdle); static JSC_DECLARE_HOST_FUNCTION(functionDeleteAllCodeWhenIdle); static JSC_DECLARE_HOST_FUNCTION(functionGlobalObjectCount); static JSC_DECLARE_HOST_FUNCTION(functionGlobalObjectForObject); static JSC_DECLARE_HOST_FUNCTION(functionGetGetterSetter); static JSC_DECLARE_HOST_FUNCTION(functionLoadGetterFromGetterSetter); static JSC_DECLARE_HOST_FUNCTION(functionCreateCustomTestGetterSetter); static JSC_DECLARE_HOST_FUNCTION(functionDeltaBetweenButterflies); static JSC_DECLARE_HOST_FUNCTION(functionCurrentCPUTime); static JSC_DECLARE_HOST_FUNCTION(functionTotalGCTime); static JSC_DECLARE_HOST_FUNCTION(functionParseCount); static JSC_DECLARE_HOST_FUNCTION(functionIsWasmSupported); static JSC_DECLARE_HOST_FUNCTION(functionMake16BitStringIfPossible); static JSC_DECLARE_HOST_FUNCTION(functionGetStructureTransitionList);; static JSC_DECLARE_HOST_FUNCTION(functionGetConcurrently); static JSC_DECLARE_HOST_FUNCTION(functionHasOwnLengthProperty); static JSC_DECLARE_HOST_FUNCTION(functionRejectPromiseAsHandled); static JSC_DECLARE_HOST_FUNCTION(functionSetUserPreferredLanguages); static JSC_DECLARE_HOST_FUNCTION(functionICUVersion); static JSC_DECLARE_HOST_FUNCTION(functionICUHeaderVersion); static JSC_DECLARE_HOST_FUNCTION(functionAssertEnabled); static JSC_DECLARE_HOST_FUNCTION(functionSecurityAssertEnabled); static JSC_DECLARE_HOST_FUNCTION(functionAsanEnabled); static JSC_DECLARE_HOST_FUNCTION(functionIsMemoryLimited); static JSC_DECLARE_HOST_FUNCTION(functionUseJIT); static JSC_DECLARE_HOST_FUNCTION(functionIsGigacageEnabled); static JSC_DECLARE_HOST_FUNCTION(functionToCacheableDictionary); static JSC_DECLARE_HOST_FUNCTION(functionToUncacheableDictionary); static JSC_DECLARE_HOST_FUNCTION(functionIsPrivateSymbol); static JSC_DECLARE_HOST_FUNCTION(functionDumpAndResetPasDebugSpectrum); static JSC_DECLARE_HOST_FUNCTION(functionMonotonicTimeNow); static JSC_DECLARE_HOST_FUNCTION(functionWallTimeNow); static JSC_DECLARE_HOST_FUNCTION(functionApproximateTimeNow); #if ENABLE(JIT) static JSC_DECLARE_HOST_FUNCTION(functionJITSizeStatistics); static JSC_DECLARE_HOST_FUNCTION(functionDumpJITSizeStatistics); static JSC_DECLARE_HOST_FUNCTION(functionResetJITSizeStatistics); #endif static JSC_DECLARE_HOST_FUNCTION(functionEnsureArrayStorage); const ClassInfo JSDollarVM::s_info = { "DollarVM", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDollarVM) }; static EncodedJSValue doPrint(JSGlobalObject* globalObject, CallFrame* callFrame, bool addLineFeed) { DollarVMAssertScope assertScope; auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); for (unsigned i = 0; i < callFrame->argumentCount(); ++i) { JSValue arg = callFrame->uncheckedArgument(i); if (arg.isCell() && !arg.isObject() && !arg.isString() && !arg.isBigInt()) { dataLog(arg); continue; } String argStr = callFrame->uncheckedArgument(i).toWTFString(globalObject); RETURN_IF_EXCEPTION(scope, encodedJSValue()); dataLog(argStr); } if (addLineFeed) dataLog("\n"); return JSValue::encode(jsUndefined()); } // Triggers a crash after dumping any paramater passed to it. // Usage: $vm.crash(...) JSC_DEFINE_HOST_FUNCTION_WITH_ATTRIBUTES(functionCrash, NO_RETURN_DUE_TO_CRASH, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_CATCH_SCOPE(vm); if (callFrame->argumentCount()) { dataLogLn("Dumping ", callFrame->argumentCount(), " values before crashing:"); const bool addLineFeed = true; doPrint(globalObject, callFrame, addLineFeed); if (scope.exception()) { JSValue value = scope.exception()->value(); scope.clearException(); dataLogLn("Error thrown while crashing: ", value.toWTFString(globalObject)); } } CRASH(); } // Executes a breakpoint instruction if the first argument is truthy or is unset. // Usage: $vm.breakpoint() JSC_DEFINE_HOST_FUNCTION(functionBreakpoint, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; // Nothing should throw here but we might as well double check... VM& vm = globalObject->vm(); auto scope = DECLARE_CATCH_SCOPE(vm); UNUSED_PARAM(scope); if (!callFrame->argumentCount() || callFrame->argument(0).toBoolean(globalObject)) WTFBreakpointTrap(); return encodedJSUndefined(); } // Returns true if the current frame is a DFG frame. // Usage: isDFG = $vm.dfgTrue() JSC_DEFINE_HOST_FUNCTION(functionDFGTrue, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; return JSValue::encode(jsBoolean(false)); } // Returns true if the current frame is a FTL frame. // Usage: isFTL = $vm.ftlTrue() JSC_DEFINE_HOST_FUNCTION(functionFTLTrue, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; return JSValue::encode(jsBoolean(false)); } JSC_DEFINE_HOST_FUNCTION(functionCpuMfence, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; #if CPU(X86_64) && !OS(WINDOWS) asm volatile("mfence" ::: "memory"); #endif return JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(functionCpuRdtsc, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; #if CPU(X86_64) && !OS(WINDOWS) unsigned high; unsigned low; asm volatile ("rdtsc" : "=a"(low), "=d"(high)); return JSValue::encode(jsNumber(low)); #else return JSValue::encode(jsNumber(0)); #endif } JSC_DEFINE_HOST_FUNCTION(functionCpuCpuid, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; #if CPU(X86_64) && !OS(WINDOWS) WTF::x86_cpuid(); #endif return JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(functionCpuPause, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; #if CPU(X86_64) && !OS(WINDOWS) asm volatile ("pause" ::: "memory"); #endif return JSValue::encode(jsUndefined()); } // This takes either a JSArrayBuffer, JSArrayBufferView*, or any other object as its first // argument. The second argument is expected to be an integer. // // If the first argument is a JSArrayBuffer, it'll clflush on that buffer // plus the second argument as a byte offset. It'll also flush on the object // itself so its length, etc, aren't in the cache. // // If the first argument is not a JSArrayBuffer, we load the butterfly // and clflush at the address of the butterfly. JSC_DEFINE_HOST_FUNCTION(functionCpuClflush, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; #if CPU(X86_64) && !OS(WINDOWS) VM& vm = globalObject->vm(); if (!callFrame->argument(1).isUInt32()) return JSValue::encode(jsBoolean(false)); auto clflush = [] (void* ptr) { DollarVMAssertScope assertScope; char* ptrToFlush = static_cast(ptr); asm volatile ("clflush %0" :: "m"(*ptrToFlush) : "memory"); }; Vector toFlush; uint32_t offset = callFrame->argument(1).asUInt32(); if (JSArrayBufferView* view = jsDynamicCast(vm, callFrame->argument(0))) toFlush.append(bitwise_cast(view->vector()) + offset); else if (JSObject* object = jsDynamicCast(vm, callFrame->argument(0))) { switch (object->indexingType()) { case ALL_INT32_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: case ALL_DOUBLE_INDEXING_TYPES: toFlush.append(bitwise_cast(object->butterfly()) + Butterfly::offsetOfVectorLength()); toFlush.append(bitwise_cast(object->butterfly()) + Butterfly::offsetOfPublicLength()); } } if (!toFlush.size()) return JSValue::encode(jsBoolean(false)); for (void* ptr : toFlush) clflush(ptr); return JSValue::encode(jsBoolean(true)); #else UNUSED_PARAM(globalObject); UNUSED_PARAM(callFrame); return JSValue::encode(jsBoolean(false)); #endif } class CallerFrameJITTypeFunctor { public: CallerFrameJITTypeFunctor() { DollarVMAssertScope assertScope; } StackVisitor::Status operator()(StackVisitor& visitor) const { unsigned index = m_currentFrame++; // First frame (index 0) is `llintTrue` etc. function itself. if (index == 1) { if (visitor->codeBlock()) m_jitType = visitor->codeBlock()->jitType(); return StackVisitor::Done; } return StackVisitor::Continue; } JITType jitType() { return m_jitType; } private: mutable unsigned m_currentFrame { 0 }; mutable JITType m_jitType { JITType::None }; }; static FunctionExecutable* getExecutableForFunction(JSValue theFunctionValue) { DollarVMAssertScope assertScope; if (!theFunctionValue.isCell()) return nullptr; VM& vm = theFunctionValue.asCell()->vm(); JSFunction* theFunction = jsDynamicCast(vm, theFunctionValue); if (!theFunction) return nullptr; FunctionExecutable* executable = jsDynamicCast(vm, theFunction->executable()); return executable; } // Returns true if the current frame is a LLInt frame. // Usage: isLLInt = $vm.llintTrue() JSC_DEFINE_HOST_FUNCTION(functionLLintTrue, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); if (!callFrame) return JSValue::encode(jsUndefined()); CallerFrameJITTypeFunctor functor; callFrame->iterate(vm, functor); return JSValue::encode(jsBoolean(functor.jitType() == JITType::InterpreterThunk)); } // Returns true if the current frame is a baseline JIT frame. // Usage: isBaselineJIT = $vm.baselineJITTrue() JSC_DEFINE_HOST_FUNCTION(functionBaselineJITTrue, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); if (!callFrame) return JSValue::encode(jsUndefined()); CallerFrameJITTypeFunctor functor; callFrame->iterate(vm, functor); return JSValue::encode(jsBoolean(functor.jitType() == JITType::BaselineJIT)); } // Set that the argument function should not be inlined. // Usage: // function f() { }; // $vm.noInline(f); JSC_DEFINE_HOST_FUNCTION(functionNoInline, (JSGlobalObject*, CallFrame* callFrame)) { DollarVMAssertScope assertScope; if (callFrame->argumentCount() < 1) return JSValue::encode(jsUndefined()); JSValue theFunctionValue = callFrame->uncheckedArgument(0); if (FunctionExecutable* executable = getExecutableForFunction(theFunctionValue)) executable->setNeverInline(true); return JSValue::encode(jsUndefined()); } // Runs a full GC synchronously. // Usage: $vm.gc() JSC_DEFINE_HOST_FUNCTION(functionGC, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VMInspector::gc(&globalObject->vm()); return JSValue::encode(jsUndefined()); } // Runs the edenGC synchronously. // Usage: $vm.edenGC() JSC_DEFINE_HOST_FUNCTION(functionEdenGC, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VMInspector::edenGC(&globalObject->vm()); return JSValue::encode(jsUndefined()); } // Runs a full GC, but sweep asynchronously. // Usage: $vm.gcSweepAsynchronously() JSC_DEFINE_HOST_FUNCTION(functionGCSweepAsynchronously, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; globalObject->vm().heap.collectNow(Async, CollectionScope::Full); return JSValue::encode(jsUndefined()); } // Dumps the hashes of all subspaces currently registered with the VM. // Usage: $vm.dumpSubspaceHashes() JSC_DEFINE_HOST_FUNCTION(functionDumpSubspaceHashes, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); VMInspector::dumpSubspaceHashes(&vm); return JSValue::encode(jsUndefined()); } // Gets a JSDollarVMCallFrame for a specified frame index. // Usage: var callFrame = $vm.callFrame(0) // frame 0 is the top frame. // Usage: var callFrame = $vm.callFrame() // implies frame 0 i.e. current frame. // // This gives you the ability to query the following: // callFrame.valid; // false if we asked for a frame beyond the end of the stack, else true. // callFrame.callee; // callFrame.codeBlock; // callFrame.unlinkedCodeBlock; // callFrame.executable; // // Note: you cannot toString() a codeBlock, unlinkedCodeBlock, or executable because // there are internal objects and not a JS object. Hence, you cannot do string // concatenation with them. JSC_DEFINE_HOST_FUNCTION(functionCallFrame, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; unsigned frameNumber = 1; if (callFrame->argumentCount() >= 1) { JSValue value = callFrame->uncheckedArgument(0); if (!value.isUInt32()) return JSValue::encode(jsUndefined()); // We need to inc the frame number because the caller would consider // its own frame as frame 0. Hence, we need discount the frame for this // function. frameNumber = value.asUInt32() + 1; } return JSValue::encode(JSDollarVMCallFrame::create(globalObject, callFrame, frameNumber)); } // Gets a token for the CodeBlock for a specified frame index. // Usage: codeBlockToken = $vm.codeBlockForFrame(0) // frame 0 is the top frame. // Usage: codeBlockToken = $vm.codeBlockForFrame() // implies frame 0 i.e. current frame. JSC_DEFINE_HOST_FUNCTION(functionCodeBlockForFrame, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; unsigned frameNumber = 1; if (callFrame->argumentCount() >= 1) { JSValue value = callFrame->uncheckedArgument(0); if (!value.isUInt32()) return JSValue::encode(jsUndefined()); // We need to inc the frame number because the caller would consider // its own frame as frame 0. Hence, we need discount the frame for this // function. frameNumber = value.asUInt32() + 1; } CodeBlock* codeBlock = VMInspector::codeBlockForFrame(&globalObject->vm(), callFrame, frameNumber); if (codeBlock) return JSValue::encode(codeBlock); return JSValue::encode(jsUndefined()); } static CodeBlock* codeBlockFromArg(JSGlobalObject* globalObject, CallFrame* callFrame) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); if (callFrame->argumentCount() < 1) return nullptr; JSValue value = callFrame->uncheckedArgument(0); CodeBlock* candidateCodeBlock = nullptr; if (value.isCell()) { JSFunction* func = jsDynamicCast(vm, value.asCell()); if (func) { if (func->isHostFunction()) candidateCodeBlock = nullptr; else candidateCodeBlock = func->jsExecutable()->eitherCodeBlock(); } else candidateCodeBlock = static_cast(value.asCell()); } if (candidateCodeBlock && VMInspector::isValidCodeBlock(&vm, candidateCodeBlock)) return candidateCodeBlock; if (candidateCodeBlock) dataLog("Invalid codeBlock: ", RawPointer(candidateCodeBlock), " ", value, "\n"); else dataLog("Invalid codeBlock: ", value, "\n"); return nullptr; } // Usage: $vm.print("codeblock = ", $vm.codeBlockFor(functionObj)) // Usage: $vm.print("codeblock = ", $vm.codeBlockFor(codeBlockToken)) // Note: you cannot toString() a codeBlock because it's an internal object and not // a JS object. Hence, you cannot do string concatenation with it. JSC_DEFINE_HOST_FUNCTION(functionCodeBlockFor, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; CodeBlock* codeBlock = codeBlockFromArg(globalObject, callFrame); WTF::StringPrintStream stream; if (codeBlock) { stream.print(*codeBlock); return JSValue::encode(jsString(globalObject->vm(), stream.toString())); } return JSValue::encode(jsUndefined()); } // Usage: $vm.dumpSourceFor(functionObj) // Usage: $vm.dumpSourceFor(codeBlockToken) JSC_DEFINE_HOST_FUNCTION(functionDumpSourceFor, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; CodeBlock* codeBlock = codeBlockFromArg(globalObject, callFrame); if (codeBlock) codeBlock->dumpSource(); return JSValue::encode(jsUndefined()); } // Usage: $vm.dumpBytecodeFor(functionObj) // Usage: $vm.dumpBytecodeFor(codeBlock) JSC_DEFINE_HOST_FUNCTION(functionDumpBytecodeFor, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; CodeBlock* codeBlock = codeBlockFromArg(globalObject, callFrame); if (codeBlock) codeBlock->dumpBytecode(); return JSValue::encode(jsUndefined()); } // Prints a series of comma separate strings without appending a newline. // Usage: $vm.dataLog(str1, str2, str3) JSC_DEFINE_HOST_FUNCTION(functionDataLog, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; const bool addLineFeed = false; return doPrint(globalObject, callFrame, addLineFeed); } // Prints a series of comma separate strings and appends a newline. // Usage: $vm.print(str1, str2, str3) JSC_DEFINE_HOST_FUNCTION(functionPrint, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; const bool addLineFeed = true; return doPrint(globalObject, callFrame, addLineFeed); } // Dumps the current CallFrame. // Usage: $vm.dumpCallFrame() JSC_DEFINE_HOST_FUNCTION(functionDumpCallFrame, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; // When the callers call this function, they are expecting to dump their // own frame. So skip 1 for this frame. VMInspector::dumpCallFrame(&globalObject->vm(), callFrame, 1); return JSValue::encode(jsUndefined()); } // Dumps the JS stack. // Usage: $vm.printStack() JSC_DEFINE_HOST_FUNCTION(functionDumpStack, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; // When the callers call this function, they are expecting to dump the // stack starting their own frame. So skip 1 for this frame. VMInspector::dumpStack(&globalObject->vm(), callFrame, 1); return JSValue::encode(jsUndefined()); } // Dumps the current CallFrame. // Usage: $vm.dumpRegisters(N) // dump the registers of the Nth CallFrame. // Usage: $vm.dumpRegisters() // dump the registers of the current CallFrame. // FIXME: Currently, this function dumps the physical frame. We should make // it dump the logical frame (i.e. be able to dump inlined frames as well). JSC_DEFINE_HOST_FUNCTION(functionDumpRegisters, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); unsigned requestedFrameIndex = 1; if (callFrame->argumentCount() >= 1) { JSValue value = callFrame->uncheckedArgument(0); if (!value.isUInt32()) return JSValue::encode(jsUndefined()); // We need to inc the frame number because the caller would consider // its own frame as frame 0. Hence, we need discount the frame for this // function. requestedFrameIndex = value.asUInt32() + 1; } unsigned frameIndex = 0; callFrame->iterate(vm, [&] (StackVisitor& visitor) { DollarVMAssertScope assertScope; if (frameIndex++ != requestedFrameIndex) return StackVisitor::Continue; VMInspector::dumpRegisters(visitor->callFrame()); return StackVisitor::Done; }); return encodedJSUndefined(); } // Dumps the internal memory layout of a JSCell. // Usage: $vm.dumpCell(cell) JSC_DEFINE_HOST_FUNCTION(functionDumpCell, (JSGlobalObject*, CallFrame* callFrame)) { DollarVMAssertScope assertScope; JSValue value = callFrame->argument(0); if (!value.isCell()) return encodedJSUndefined(); VMInspector::dumpCellMemory(value.asCell()); return encodedJSUndefined(); } // Gets the dataLog dump of the indexingMode of the passed value. // Usage: $vm.print("indexingMode = " + $vm.indexingMode(jsValue)) JSC_DEFINE_HOST_FUNCTION(functionIndexingMode, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; if (!callFrame->argument(0).isObject()) return encodedJSUndefined(); WTF::StringPrintStream stream; stream.print(IndexingTypeDump(callFrame->uncheckedArgument(0).getObject()->indexingMode())); return JSValue::encode(jsString(globalObject->vm(), stream.toString())); } JSC_DEFINE_HOST_FUNCTION(functionInlineCapacity, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); if (auto* object = jsDynamicCast(vm, callFrame->argument(0))) return JSValue::encode(jsNumber(object->structure(vm)->inlineCapacity())); return encodedJSUndefined(); } // Clears the LinkBuffer profile statistics. // Usage: $vm.clearLinkBufferStats() JSC_DEFINE_HOST_FUNCTION(functionClearLinkBufferStats, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; #if ENABLE(ASSEMBLER) LinkBuffer::clearProfileStatistics(); #endif return JSValue::encode(jsUndefined()); } // Dumps the LinkBuffer profile statistics as a string. // Usage: $vm.print($vm.linkBufferStats()) JSC_DEFINE_HOST_FUNCTION(functionLinkBufferStats, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; #if ENABLE(ASSEMBLER) WTF::StringPrintStream stream; LinkBuffer::dumpProfileStatistics(&stream); return JSValue::encode(jsString(globalObject->vm(), stream.toString())); #else UNUSED_PARAM(globalObject); return JSValue::encode(jsUndefined()); #endif } // Gets the dataLog dump of a given JS value as a string. // Usage: $vm.print("value = " + $vm.value(jsValue)) JSC_DEFINE_HOST_FUNCTION(functionValue, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; WTF::StringPrintStream stream; for (unsigned i = 0; i < callFrame->argumentCount(); ++i) { if (i) stream.print(", "); stream.print(callFrame->uncheckedArgument(i)); } return JSValue::encode(jsString(globalObject->vm(), stream.toString())); } // Gets the pid of the current process. // Usage: $vm.print("pid = " + $vm.getpid()) JSC_DEFINE_HOST_FUNCTION(functionGetPID, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; return JSValue::encode(jsNumber(getCurrentProcessID())); } // Make the globalObject have a bad time. Does nothing if the object is not a JSGlobalObject. // Usage: $vm.haveABadTime(globalObject) JSC_DEFINE_HOST_FUNCTION(functionHaveABadTime, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSGlobalObject* target = globalObject; if (!callFrame->argument(0).isUndefined()) { JSObject* obj = callFrame->argument(0).getObject(); if (!obj) return throwVMTypeError(globalObject, scope, "haveABadTime expects first argument to be an object if provided"); target = obj->globalObject(); } target->haveABadTime(vm); return JSValue::encode(jsBoolean(true)); } // Checks if the object (or its global if the object is not a global) is having a bad time. // Usage: $vm.isHavingABadTime(obj) JSC_DEFINE_HOST_FUNCTION(functionIsHavingABadTime, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSGlobalObject* target = globalObject; if (!callFrame->argument(0).isUndefined()) { JSObject* obj = callFrame->argument(0).getObject(); if (!obj) return throwVMTypeError(globalObject, scope, "isHavingABadTime expects first argument to be an object if provided"); target = obj->globalObject(); } return JSValue::encode(jsBoolean(target->isHavingABadTime())); } // Calls the specified test function after adjusting the stack to have the specified // remaining size from the end of the physical stack. // Usage: $vm.callWithStackSize(funcToCall, desiredStackSize) // // This function will only work in test configurations, specifically, only if JSC // options are not frozen. For the jsc shell, the --disableOptionsFreezingForTesting // argument needs to be passed in on the command line. #if ENABLE(ASSEMBLER) static void callWithStackSizeProbeFunction(Probe::State* state) { JSGlobalObject* globalObject = bitwise_cast(state->arg); // The bits loaded from state->probeFunction will be tagged like // a C function. So, we'll need to untag it to extract the bits // for the JSFunction*. JSFunction* function = bitwise_cast(untagCodePtr(state->probeFunction)); state->initializeStackFunction = nullptr; state->initializeStackArg = nullptr; DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto callData = getCallData(vm, function); MarkedArgumentBuffer args; call(globalObject, function, callData, jsUndefined(), args); } #endif // ENABLE(ASSEMBLER) JSC_DEFINE_HOST_FUNCTION_WITH_ATTRIBUTES(functionCallWithStackSize, SUPPRESS_ASAN, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); auto throwScope = DECLARE_THROW_SCOPE(vm); #if OS(DARWIN) && CPU(X86_64) constexpr bool isSupportedByPlatform = true; #else constexpr bool isSupportedByPlatform = false; #endif if (!isSupportedByPlatform) return throwVMError(globalObject, throwScope, "Not supported for this platform"); #if ENABLE(ASSEMBLER) if (g_jscConfig.isPermanentlyFrozen() || !g_jscConfig.disabledFreezingForTesting) return throwVMError(globalObject, throwScope, "Options are frozen"); if (callFrame->argumentCount() < 2) return throwVMError(globalObject, throwScope, "Invalid number of arguments"); JSValue arg0 = callFrame->argument(0); JSValue arg1 = callFrame->argument(1); if (!arg0.isCallable(vm)) return throwVMError(globalObject, throwScope, "arg0 should be a function"); if (!arg1.isNumber()) return throwVMError(globalObject, throwScope, "arg1 should be a number"); JSFunction* function = jsCast(arg0); size_t desiredStackSize = arg1.asNumber(); const StackBounds& bounds = Thread::current().stack(); uint8_t* currentStackPosition = bitwise_cast(currentStackPointer()); uint8_t* end = bitwise_cast(bounds.end()); uint8_t* desiredStart = end + desiredStackSize; if (desiredStart >= currentStackPosition) return throwVMError(globalObject, throwScope, "Unable to setup desired stack size"); JSDollarVMHelper helper(vm); unsigned originalMaxPerThreadStackUsage = Options::maxPerThreadStackUsage(); void* originalVMSoftStackLimit = vm.softStackLimit(); void* originalVMStackLimit = vm.stackLimit(); // This is a hack to make the VM think it's stack limits are near the end // of the physical stack. uint8_t* vmStackStart = bitwise_cast(vm.stackPointerAtVMEntry()); uint8_t* vmStackEnd = vmStackStart - originalMaxPerThreadStackUsage; ptrdiff_t sizeDiff = vmStackEnd - end; RELEASE_ASSERT(sizeDiff >= 0); RELEASE_ASSERT(static_cast(sizeDiff) < UINT_MAX); Options::maxPerThreadStackUsage() = originalMaxPerThreadStackUsage + sizeDiff; helper.updateVMStackLimits(); #if OS(DARWIN) && CPU(X86_64) __asm__ volatile ( "subq %[sizeDiff], %%rsp" "\n" "pushq %%rax" "\n" "pushq %%rcx" "\n" "pushq %%rdx" "\n" "pushq %%rbx" "\n" "callq *%%rax" "\n" "addq %[sizeDiff], %%rsp" "\n" : : "a" (ctiMasmProbeTrampoline) , "c" (callWithStackSizeProbeFunction) , "d" (function) , "b" (globalObject) , [sizeDiff] "rm" (sizeDiff) : "memory" ); #else UNUSED_PARAM(function); #if !COMPILER(MSVC) UNUSED_PARAM(callWithStackSizeProbeFunction); #endif #endif // OS(DARWIN) && CPU(X86_64) Options::maxPerThreadStackUsage() = originalMaxPerThreadStackUsage; helper.updateVMStackLimits(); RELEASE_ASSERT(vm.softStackLimit() == originalVMSoftStackLimit); RELEASE_ASSERT(vm.stackLimit() == originalVMStackLimit); throwScope.release(); return encodedJSUndefined(); #else // not ENABLE(ASSEMBLER) UNUSED_PARAM(callFrame); return throwVMError(globalObject, throwScope, "Not supported for this platform"); #endif // ENABLE(ASSEMBLER) } // Creates a new global object. // Usage: $vm.createGlobalObject() JSC_DEFINE_HOST_FUNCTION(functionCreateGlobalObject, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); return JSValue::encode(JSGlobalObject::create(vm, JSGlobalObject::createStructure(vm, jsNull()))); } JSC_DEFINE_HOST_FUNCTION(functionCreateProxy, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); JSValue target = callFrame->argument(0); if (!target.isObject()) return JSValue::encode(jsUndefined()); JSObject* jsTarget = asObject(target.asCell()); Structure* structure = JSProxy::createStructure(vm, globalObject, jsTarget->getPrototypeDirect(vm)); JSProxy* proxy = JSProxy::create(vm, structure, jsTarget); return JSValue::encode(proxy); } JSC_DEFINE_HOST_FUNCTION(functionCreateRuntimeArray, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; JSLockHolder lock(globalObject); RuntimeArray* array = RuntimeArray::create(globalObject, callFrame); return JSValue::encode(array); } JSC_DEFINE_HOST_FUNCTION(functionCreateNullRopeString, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); return JSValue::encode(JSRopeString::createNullForTesting(vm)); } JSC_DEFINE_HOST_FUNCTION(functionCreateImpureGetter, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); JSValue target = callFrame->argument(0); JSObject* delegate = nullptr; if (target.isObject()) delegate = asObject(target.asCell()); Structure* structure = ImpureGetter::createStructure(vm, globalObject, jsNull()); ImpureGetter* result = ImpureGetter::create(vm, structure, delegate); return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(functionCreateCustomGetterObject, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); Structure* structure = CustomGetter::createStructure(vm, globalObject, jsNull()); CustomGetter* result = CustomGetter::create(vm, structure); return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(functionCreateDOMJITNodeObject, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); Structure* structure = DOMJITNode::createStructure(vm, globalObject, DOMJITGetter::create(vm, DOMJITGetter::createStructure(vm, globalObject, jsNull()))); DOMJITNode* result = DOMJITNode::create(vm, structure); return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(functionCreateDOMJITGetterObject, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); Structure* structure = DOMJITGetter::createStructure(vm, globalObject, jsNull()); DOMJITGetter* result = DOMJITGetter::create(vm, structure); return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(functionCreateDOMJITGetterNoEffectsObject, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); Structure* structure = DOMJITGetterNoEffects::createStructure(vm, globalObject, jsNull()); DOMJITGetterNoEffects* result = DOMJITGetterNoEffects::create(vm, structure); return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(functionCreateDOMJITGetterComplexObject, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); Structure* structure = DOMJITGetterComplex::createStructure(vm, globalObject, jsNull()); DOMJITGetterComplex* result = DOMJITGetterComplex::create(vm, globalObject, structure); return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(functionCreateDOMJITFunctionObject, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); Structure* structure = DOMJITFunctionObject::createStructure(vm, globalObject, jsNull()); DOMJITFunctionObject* result = DOMJITFunctionObject::create(vm, globalObject, structure); return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(functionCreateDOMJITCheckJSCastObject, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); Structure* structure = DOMJITCheckJSCastObject::createStructure(vm, globalObject, jsNull()); DOMJITCheckJSCastObject* result = DOMJITCheckJSCastObject::create(vm, globalObject, structure); return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(functionCreateDOMJITGetterBaseJSObject, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); Structure* structure = DOMJITGetterBaseJSObject::createStructure(vm, globalObject, jsNull()); DOMJITGetterBaseJSObject* result = DOMJITGetterBaseJSObject::create(vm, structure); return JSValue::encode(result); } #if ENABLE(WEBASSEMBLY) JSC_DEFINE_HOST_FUNCTION(functionCreateWasmStreamingParser, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); return JSValue::encode(WasmStreamingParser::create(vm, globalObject)); } JSC_DEFINE_HOST_FUNCTION(functionCreateWasmStreamingCompilerForCompile, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); auto scope = DECLARE_THROW_SCOPE(vm); auto callback = jsDynamicCast(vm, callFrame->argument(0)); if (!callback) return throwVMTypeError(globalObject, scope, "First argument is not a JS function"_s); auto compiler = WasmStreamingCompiler::create(vm, globalObject, Wasm::CompilerMode::Validation, nullptr); MarkedArgumentBuffer args; args.append(compiler); call(globalObject, callback, jsUndefined(), args, "You shouldn't see this..."); if (UNLIKELY(scope.exception())) scope.clearException(); compiler->streamingCompiler().finalize(globalObject); RETURN_IF_EXCEPTION(scope, { }); return JSValue::encode(compiler->promise()); } JSC_DEFINE_HOST_FUNCTION(functionCreateWasmStreamingCompilerForInstantiate, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); auto scope = DECLARE_THROW_SCOPE(vm); auto callback = jsDynamicCast(vm, callFrame->argument(0)); if (!callback) return throwVMTypeError(globalObject, scope, "First argument is not a JS function"_s); JSValue importArgument = callFrame->argument(1); JSObject* importObject = importArgument.getObject(); if (UNLIKELY(!importArgument.isUndefined() && !importObject)) return throwVMTypeError(globalObject, scope); auto compiler = WasmStreamingCompiler::create(vm, globalObject, Wasm::CompilerMode::FullCompile, importObject); MarkedArgumentBuffer args; args.append(compiler); call(globalObject, callback, jsUndefined(), args, "You shouldn't see this..."); if (UNLIKELY(scope.exception())) scope.clearException(); compiler->streamingCompiler().finalize(globalObject); RETURN_IF_EXCEPTION(scope, { }); return JSValue::encode(compiler->promise()); } #endif JSC_DEFINE_HOST_FUNCTION(functionCreateStaticCustomAccessor, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); Structure* structure = StaticCustomAccessor::createStructure(vm, globalObject, jsNull()); auto* result = StaticCustomAccessor::create(vm, structure); return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(functionCreateStaticCustomValue, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); Structure* structure = StaticCustomValue::createStructure(vm, globalObject, jsNull()); auto* result = StaticCustomValue::create(vm, structure); return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(functionCreateObjectDoingSideEffectPutWithoutCorrectSlotStatus, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); auto* dollarVM = jsDynamicCast(vm, callFrame->thisValue()); RELEASE_ASSERT(dollarVM); auto* result = ObjectDoingSideEffectPutWithoutCorrectSlotStatus::create(vm, dollarVM->objectDoingSideEffectPutWithoutCorrectSlotStatusStructure()); return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(functionCreateEmptyFunctionWithName, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); auto scope = DECLARE_THROW_SCOPE(vm); const String name = callFrame->argument(0).toWTFString(globalObject); RETURN_IF_EXCEPTION(scope, encodedJSValue()); RELEASE_AND_RETURN(scope, JSValue::encode(JSFunction::create(vm, globalObject, 1, name, functionCreateEmptyFunctionWithName))); } JSC_DEFINE_HOST_FUNCTION(functionSetImpureGetterDelegate, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); auto scope = DECLARE_THROW_SCOPE(vm); JSValue base = callFrame->argument(0); if (!base.isObject()) return JSValue::encode(jsUndefined()); JSValue delegate = callFrame->argument(1); if (!delegate.isObject()) return JSValue::encode(jsUndefined()); ImpureGetter* impureGetter = jsDynamicCast(vm, asObject(base.asCell())); if (UNLIKELY(!impureGetter)) { throwTypeError(globalObject, scope, "argument is not an ImpureGetter"_s); return encodedJSValue(); } impureGetter->setDelegate(vm, asObject(delegate.asCell())); return JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(functionCreateBuiltin, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (callFrame->argumentCount() < 1 || !callFrame->argument(0).isString()) return JSValue::encode(jsUndefined()); String functionText = asString(callFrame->argument(0))->value(globalObject); RETURN_IF_EXCEPTION(scope, encodedJSValue()); SourceCode source = makeSource(functionText, { }); JSFunction* func = JSFunction::create(vm, createBuiltinExecutable(vm, source, Identifier::fromString(vm, "foo"), ConstructorKind::None, ConstructAbility::CannotConstruct)->link(vm, nullptr, source), globalObject); return JSValue::encode(func); } JSC_DEFINE_HOST_FUNCTION(functionGetPrivateProperty, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (callFrame->argumentCount() < 2 || !callFrame->argument(1).isString()) return encodedJSUndefined(); String str = asString(callFrame->argument(1))->value(globalObject); RETURN_IF_EXCEPTION(scope, encodedJSValue()); SymbolImpl* symbol = vm.propertyNames->builtinNames().lookUpPrivateName(str); if (!symbol) return throwVMError(globalObject, scope, "Unknown private name."); RELEASE_AND_RETURN(scope, JSValue::encode(callFrame->argument(0).get(globalObject, symbol))); } JSC_DEFINE_HOST_FUNCTION(functionCreateRoot, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); return JSValue::encode(Root::create(vm, globalObject)); } JSC_DEFINE_HOST_FUNCTION(functionCreateElement, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); auto scope = DECLARE_THROW_SCOPE(vm); Root* root = jsDynamicCast(vm, callFrame->argument(0)); if (!root) return JSValue::encode(throwException(globalObject, scope, createError(globalObject, "Cannot create Element without a Root."_s))); return JSValue::encode(Element::create(vm, globalObject, root)); } JSC_DEFINE_HOST_FUNCTION(functionGetElement, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); Root* root = jsDynamicCast(vm, callFrame->argument(0)); if (!root) return JSValue::encode(jsUndefined()); Element* result = root->element(); return JSValue::encode(result ? result : jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(functionCreateSimpleObject, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); return JSValue::encode(SimpleObject::create(vm, globalObject)); } JSC_DEFINE_HOST_FUNCTION(functionGetHiddenValue, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); auto scope = DECLARE_THROW_SCOPE(vm); SimpleObject* simpleObject = jsDynamicCast(vm, callFrame->argument(0)); if (UNLIKELY(!simpleObject)) { throwTypeError(globalObject, scope, "Invalid use of getHiddenValue test function"_s); return encodedJSValue(); } return JSValue::encode(simpleObject->hiddenValue()); } JSC_DEFINE_HOST_FUNCTION(functionSetHiddenValue, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSLockHolder lock(vm); auto scope = DECLARE_THROW_SCOPE(vm); SimpleObject* simpleObject = jsDynamicCast(vm, callFrame->argument(0)); if (UNLIKELY(!simpleObject)) { throwTypeError(globalObject, scope, "Invalid use of setHiddenValue test function"_s); return encodedJSValue(); } JSValue value = callFrame->argument(1); simpleObject->setHiddenValue(vm, value); return JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(functionShadowChickenFunctionsOnStack, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); DeferTermination deferScope(vm); auto scope = DECLARE_THROW_SCOPE(vm); if (auto* shadowChicken = vm.shadowChicken()) { scope.release(); return JSValue::encode(shadowChicken->functionsOnStack(globalObject, callFrame)); } JSArray* result = constructEmptyArray(globalObject, nullptr); RETURN_IF_EXCEPTION(scope, { }); StackVisitor::visit(callFrame, vm, [&] (StackVisitor& visitor) -> StackVisitor::Status { DollarVMAssertScope assertScope; if (visitor->isInlinedFrame()) return StackVisitor::Continue; if (visitor->isWasmFrame()) return StackVisitor::Continue; result->push(globalObject, jsCast(visitor->callee().asCell())); scope.releaseAssertNoException(); // This function is only called from tests. return StackVisitor::Continue; }); RETURN_IF_EXCEPTION(scope, { }); return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(functionSetGlobalConstRedeclarationShouldNotThrow, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); vm.setGlobalConstRedeclarationShouldThrow(false); return JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(functionFindTypeForExpression, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); RELEASE_ASSERT(vm.typeProfiler()); vm.typeProfilerLog()->processLogEntries(vm, "jsc Testing API: functionFindTypeForExpression"_s); JSValue functionValue = callFrame->argument(0); RELEASE_ASSERT(functionValue.isCallable(vm)); FunctionExecutable* executable = (jsDynamicCast(vm, functionValue.asCell()->getObject()))->jsExecutable(); RELEASE_ASSERT(callFrame->argument(1).isString()); String substring = asString(callFrame->argument(1))->value(globalObject); String sourceCodeText = executable->source().view().toString(); unsigned offset = static_cast(sourceCodeText.find(substring) + executable->source().startOffset()); String jsonString = vm.typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorNormal, offset, executable->sourceID(), vm); return JSValue::encode(JSONParse(globalObject, jsonString)); } JSC_DEFINE_HOST_FUNCTION(functionReturnTypeFor, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); RELEASE_ASSERT(vm.typeProfiler()); vm.typeProfilerLog()->processLogEntries(vm, "jsc Testing API: functionReturnTypeFor"_s); JSValue functionValue = callFrame->argument(0); RELEASE_ASSERT(functionValue.isCallable(vm)); FunctionExecutable* executable = (jsDynamicCast(vm, functionValue.asCell()->getObject()))->jsExecutable(); unsigned offset = executable->typeProfilingStartOffset(vm); String jsonString = vm.typeProfiler()->typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptorFunctionReturn, offset, executable->sourceID(), vm); return JSValue::encode(JSONParse(globalObject, jsonString)); } JSC_DEFINE_HOST_FUNCTION(functionFlattenDictionaryObject, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSValue value = callFrame->argument(0); RELEASE_ASSERT(value.isObject() && value.getObject()->structure()->isDictionary()); value.getObject()->flattenDictionaryObject(vm); return encodedJSUndefined(); } JSC_DEFINE_HOST_FUNCTION(functionDumpBasicBlockExecutionRanges, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); RELEASE_ASSERT(vm.controlFlowProfiler()); vm.controlFlowProfiler()->dumpData(); return JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(functionHasBasicBlockExecuted, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); RELEASE_ASSERT(vm.controlFlowProfiler()); JSValue functionValue = callFrame->argument(0); RELEASE_ASSERT(functionValue.isCallable(vm)); FunctionExecutable* executable = (jsDynamicCast(vm, functionValue.asCell()->getObject()))->jsExecutable(); RELEASE_ASSERT(callFrame->argument(1).isString()); String substring = asString(callFrame->argument(1))->value(globalObject); String sourceCodeText = executable->source().view().toString(); RELEASE_ASSERT(sourceCodeText.contains(substring)); int offset = sourceCodeText.find(substring) + executable->source().startOffset(); bool hasExecuted = vm.controlFlowProfiler()->hasBasicBlockAtTextOffsetBeenExecuted(offset, executable->sourceID(), vm); return JSValue::encode(jsBoolean(hasExecuted)); } JSC_DEFINE_HOST_FUNCTION(functionBasicBlockExecutionCount, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); RELEASE_ASSERT(vm.controlFlowProfiler()); JSValue functionValue = callFrame->argument(0); RELEASE_ASSERT(functionValue.isCallable(vm)); FunctionExecutable* executable = (jsDynamicCast(vm, functionValue.asCell()->getObject()))->jsExecutable(); RELEASE_ASSERT(callFrame->argument(1).isString()); String substring = asString(callFrame->argument(1))->value(globalObject); String sourceCodeText = executable->source().view().toString(); RELEASE_ASSERT(sourceCodeText.contains(substring)); int offset = sourceCodeText.find(substring) + executable->source().startOffset(); size_t executionCount = vm.controlFlowProfiler()->basicBlockExecutionCountAtTextOffset(offset, executable->sourceID(), vm); return JSValue::encode(JSValue(executionCount)); } class DoNothingDebugger final : public Debugger { WTF_MAKE_NONCOPYABLE(DoNothingDebugger); WTF_MAKE_FAST_ALLOCATED; public: DoNothingDebugger(VM& vm) : Debugger(vm) { DollarVMAssertScope assertScope; setSuppressAllPauses(true); } private: void sourceParsed(JSGlobalObject*, SourceProvider*, int, const WTF::String&) final { DollarVMAssertScope assertScope; } }; static EncodedJSValue changeDebuggerModeWhenIdle(JSGlobalObject* globalObject, OptionSet codeGenerationMode) { DollarVMAssertScope assertScope; bool debuggerRequested = codeGenerationMode.contains(CodeGenerationMode::Debugger); if (debuggerRequested == globalObject->hasDebugger()) return JSValue::encode(jsUndefined()); VM* vm = &globalObject->vm(); vm->whenIdle([=] () { DollarVMAssertScope assertScope; if (debuggerRequested) { Debugger* debugger = new DoNothingDebugger(globalObject->vm()); globalObject->setDebugger(debugger); debugger->activateBreakpoints(); // Also deletes all code. } else { Debugger* debugger = globalObject->debugger(); debugger->deactivateBreakpoints(); // Also deletes all code. globalObject->setDebugger(nullptr); delete debugger; } }); return JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(functionEnableDebuggerModeWhenIdle, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; return changeDebuggerModeWhenIdle(globalObject, { CodeGenerationMode::Debugger }); } JSC_DEFINE_HOST_FUNCTION(functionDisableDebuggerModeWhenIdle, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; return changeDebuggerModeWhenIdle(globalObject, { }); } JSC_DEFINE_HOST_FUNCTION(functionDeleteAllCodeWhenIdle, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM* vm = &globalObject->vm(); vm->whenIdle([=] () { DollarVMAssertScope assertScope; vm->deleteAllCode(PreventCollectionAndDeleteAllCode); }); return JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(functionGlobalObjectCount, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; return JSValue::encode(jsNumber(globalObject->vm().heap.globalObjectCount())); } JSC_DEFINE_HOST_FUNCTION(functionGlobalObjectForObject, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; JSValue value = callFrame->argument(0); RELEASE_ASSERT(value.isObject()); JSGlobalObject* result = jsCast(value)->globalObject(globalObject->vm()); RELEASE_ASSERT(result); return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(functionGetGetterSetter, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSValue value = callFrame->argument(0); if (!value.isObject()) return JSValue::encode(jsUndefined()); JSValue property = callFrame->argument(1); if (!property.isString()) return JSValue::encode(jsUndefined()); auto propertyName = asString(property)->toIdentifier(globalObject); RETURN_IF_EXCEPTION(scope, { }); PropertySlot slot(value, PropertySlot::InternalMethodType::VMInquiry, &vm); value.getPropertySlot(globalObject, propertyName, slot); RETURN_IF_EXCEPTION(scope, { }); JSValue result; if (slot.isCacheableGetter()) result = slot.getterSetter(); else result = jsNull(); return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(functionLoadGetterFromGetterSetter, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); GetterSetter* getterSetter = jsDynamicCast(vm, callFrame->argument(0)); if (UNLIKELY(!getterSetter)) { throwTypeError(globalObject, scope, "Invalid use of loadGetterFromGetterSetter test function: argument is not a GetterSetter"_s); return encodedJSValue(); } JSObject* getter = getterSetter->getter(); RELEASE_ASSERT(getter); return JSValue::encode(getter); } JSC_DEFINE_HOST_FUNCTION(functionCreateCustomTestGetterSetter, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); return JSValue::encode(JSTestCustomGetterSetter::create(vm, globalObject, JSTestCustomGetterSetter::createStructure(vm, globalObject))); } JSC_DEFINE_HOST_FUNCTION(functionDeltaBetweenButterflies, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSObject* a = jsDynamicCast(vm, callFrame->argument(0)); JSObject* b = jsDynamicCast(vm, callFrame->argument(1)); if (!a || !b) return JSValue::encode(jsNumber(PNaN)); ptrdiff_t delta = bitwise_cast(a->butterfly()) - bitwise_cast(b->butterfly()); if (delta < 0) return JSValue::encode(jsNumber(PNaN)); if (delta > std::numeric_limits::max()) return JSValue::encode(jsNumber(PNaN)); return JSValue::encode(jsNumber(static_cast(delta))); } JSC_DEFINE_HOST_FUNCTION(functionCurrentCPUTime, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; return JSValue::encode(jsNumber(CPUTime::forCurrentThread().value())); } JSC_DEFINE_HOST_FUNCTION(functionTotalGCTime, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); return JSValue::encode(jsNumber(vm.heap.totalGCTime().seconds())); } JSC_DEFINE_HOST_FUNCTION(functionParseCount, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; return JSValue::encode(jsNumber(globalParseCount.load())); } JSC_DEFINE_HOST_FUNCTION(functionIsWasmSupported, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; #if ENABLE(WEBASSEMBLY) return JSValue::encode(jsBoolean(Wasm::isSupported())); #else return JSValue::encode(jsBoolean(false)); #endif } JSC_DEFINE_HOST_FUNCTION(functionMake16BitStringIfPossible, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); String string = callFrame->argument(0).toWTFString(globalObject); RETURN_IF_EXCEPTION(scope, { }); if (!string.is8Bit()) return JSValue::encode(jsString(vm, WTFMove(string))); Vector buffer; buffer.resize(string.length()); StringImpl::copyCharacters(buffer.data(), string.characters8(), string.length()); return JSValue::encode(jsString(vm, String::adopt(WTFMove(buffer)))); } JSC_DEFINE_HOST_FUNCTION(functionGetStructureTransitionList, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSObject* obj = callFrame->argument(0).toObject(globalObject); RETURN_IF_EXCEPTION(scope, { }); if (!obj) return JSValue::encode(jsNull()); Vector structures; for (auto* structure = obj->structure(); structure; structure = structure->previousID()) structures.append(structure); JSArray* result = JSArray::tryCreate(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), 0); RETURN_IF_EXCEPTION(scope, { }); for (size_t i = 0; i < structures.size(); ++i) { auto* structure = structures[structures.size() - i - 1]; result->push(globalObject, JSValue(structure->id())); RETURN_IF_EXCEPTION(scope, { }); result->push(globalObject, JSValue(structure->transitionOffset())); RETURN_IF_EXCEPTION(scope, { }); result->push(globalObject, JSValue(structure->maxOffset())); RETURN_IF_EXCEPTION(scope, { }); if (structure->transitionPropertyName()) result->push(globalObject, jsString(vm, String(*structure->transitionPropertyName()))); else result->push(globalObject, jsNull()); RETURN_IF_EXCEPTION(scope, { }); result->push(globalObject, jsNumber(static_cast(structure->transitionKind()))); RETURN_IF_EXCEPTION(scope, { }); } return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(functionGetConcurrently, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSObject* obj = callFrame->argument(0).toObject(globalObject); RETURN_IF_EXCEPTION(scope, { }); if (!obj) return JSValue::encode(jsNull()); String property = callFrame->argument(1).toWTFString(globalObject); RETURN_IF_EXCEPTION(scope, { }); auto name = PropertyName(Identifier::fromString(vm, property)); auto offset = obj->structure()->getConcurrently(name.uid()); if (offset != invalidOffset) ASSERT(JSValue::encode(obj->getDirect(offset))); JSValue result = JSValue(offset != invalidOffset); RETURN_IF_EXCEPTION(scope, { }); return JSValue::encode(result); } JSC_DEFINE_HOST_FUNCTION(functionHasOwnLengthProperty, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSObject* target = asObject(callFrame->uncheckedArgument(0)); JSFunction* function = jsDynamicCast(vm, target); return JSValue::encode(jsBoolean(function->canAssumeNameAndLengthAreOriginal(vm))); } JSC_DEFINE_HOST_FUNCTION(functionRejectPromiseAsHandled, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; JSPromise* promise = jsCast(callFrame->uncheckedArgument(0)); JSValue reason = callFrame->uncheckedArgument(1); promise->rejectAsHandled(globalObject, reason); return JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(functionSetUserPreferredLanguages, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSArray* array = jsDynamicCast(vm, callFrame->argument(0)); if (!array) return throwVMTypeError(globalObject, scope, "Expected first argument to be an array"_s); Vector languages; unsigned length = array->length(); for (unsigned i = 0; i < length; i++) { String language = array->get(globalObject, i).toWTFString(globalObject); RETURN_IF_EXCEPTION(scope, encodedJSValue()); languages.append(language); } overrideUserPreferredLanguages(languages); return JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(functionICUVersion, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; return JSValue::encode(jsNumber(WTF::ICU::majorVersion())); } JSC_DEFINE_HOST_FUNCTION(functionICUHeaderVersion, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; return JSValue::encode(jsNumber(U_ICU_VERSION_MAJOR_NUM)); } JSC_DEFINE_HOST_FUNCTION(functionAssertEnabled, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; return JSValue::encode(jsBoolean(ASSERT_ENABLED)); } JSC_DEFINE_HOST_FUNCTION(functionSecurityAssertEnabled, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; #if ENABLE(SECURITY_ASSERTIONS) return JSValue::encode(jsBoolean(true)); #else return JSValue::encode(jsBoolean(false)); #endif } JSC_DEFINE_HOST_FUNCTION(functionAsanEnabled, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; return JSValue::encode(jsBoolean(ASAN_ENABLED)); } JSC_DEFINE_HOST_FUNCTION(functionIsMemoryLimited, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; #if PLATFORM(IOS) || PLATFORM(APPLETV) || PLATFORM(WATCHOS) return JSValue::encode(jsBoolean(true)); #else return JSValue::encode(jsBoolean(false)); #endif } JSC_DEFINE_HOST_FUNCTION(functionUseJIT, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; return JSValue::encode(jsBoolean(Options::useJIT())); } JSC_DEFINE_HOST_FUNCTION(functionIsGigacageEnabled, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; return JSValue::encode(jsBoolean(Gigacage::isEnabled())); } JSC_DEFINE_HOST_FUNCTION(functionToCacheableDictionary, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSObject* object = jsDynamicCast(vm, callFrame->argument(0)); if (!object) return throwVMTypeError(globalObject, scope, "Expected first argument to be an object"_s); if (!object->structure(vm)->isUncacheableDictionary()) object->convertToDictionary(vm); return JSValue::encode(object); } JSC_DEFINE_HOST_FUNCTION(functionToUncacheableDictionary, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSObject* object = jsDynamicCast(vm, callFrame->argument(0)); if (!object) return throwVMTypeError(globalObject, scope, "Expected first argument to be an object"_s); object->convertToUncacheableDictionary(vm); return JSValue::encode(object); } JSC_DEFINE_HOST_FUNCTION(functionIsPrivateSymbol, (JSGlobalObject*, CallFrame* callFrame)) { DollarVMAssertScope assertScope; if (!(callFrame->argument(0).isSymbol())) return JSValue::encode(jsBoolean(false)); return JSValue::encode(jsBoolean(asSymbol(callFrame->argument(0))->uid().isPrivate())); } JSC_DEFINE_HOST_FUNCTION(functionDumpAndResetPasDebugSpectrum, (JSGlobalObject*, CallFrame*)) { DollarVMAssertScope assertScope; #if !USE(SYSTEM_MALLOC) #if BUSE(LIBPAS) pas_heap_lock_lock(); pas_debug_spectrum_dump(&pas_log_stream.base); pas_debug_spectrum_reset(); pas_heap_lock_unlock(); #endif #endif return JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(functionMonotonicTimeNow, (JSGlobalObject*, CallFrame*)) { return JSValue::encode(jsNumber(MonotonicTime::now().secondsSinceEpoch().milliseconds())); } JSC_DEFINE_HOST_FUNCTION(functionWallTimeNow, (JSGlobalObject*, CallFrame*)) { return JSValue::encode(jsNumber(WallTime::now().secondsSinceEpoch().milliseconds())); } JSC_DEFINE_HOST_FUNCTION(functionApproximateTimeNow, (JSGlobalObject*, CallFrame*)) { return JSValue::encode(jsNumber(ApproximateTime::now().secondsSinceEpoch().milliseconds())); } #if ENABLE(JIT) JSC_DEFINE_HOST_FUNCTION(functionJITSizeStatistics, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); if (!vm.jitSizeStatistics) return JSValue::encode(jsUndefined()); WTF::StringPrintStream stream; stream.print(*vm.jitSizeStatistics); return JSValue::encode(jsString(vm, stream.toString())); } JSC_DEFINE_HOST_FUNCTION(functionDumpJITSizeStatistics, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); if (!vm.jitSizeStatistics) return JSValue::encode(jsUndefined()); dataLogLn(*vm.jitSizeStatistics); return JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(functionResetJITSizeStatistics, (JSGlobalObject* globalObject, CallFrame*)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); if (!vm.jitSizeStatistics) return JSValue::encode(jsUndefined()); vm.jitSizeStatistics->reset(); return JSValue::encode(jsUndefined()); } #endif JSC_DEFINE_HOST_FUNCTION(functionEnsureArrayStorage, (JSGlobalObject* globalObject, CallFrame* callFrame)) { DollarVMAssertScope assertScope; VM& vm = globalObject->vm(); JSValue arg = callFrame->argument(0); if (arg.isObject()) asObject(arg)->ensureArrayStorage(vm); return JSValue::encode(jsUndefined()); } constexpr unsigned jsDollarVMPropertyAttributes = PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | PropertyAttribute::DontDelete; void JSDollarVM::finishCreation(VM& vm) { DollarVMAssertScope assertScope; Base::finishCreation(vm); JSGlobalObject* globalObject = this->globalObject(vm); auto addFunction = [&] (VM& vm, const char* name, NativeFunction function, unsigned arguments) { DollarVMAssertScope assertScope; JSDollarVM::addFunction(vm, globalObject, name, function, arguments); }; auto addConstructibleFunction = [&] (VM& vm, const char* name, NativeFunction function, unsigned arguments) { DollarVMAssertScope assertScope; JSDollarVM::addConstructibleFunction(vm, globalObject, name, function, arguments); }; addFunction(vm, "abort", functionCrash, 0); addFunction(vm, "crash", functionCrash, 0); addFunction(vm, "breakpoint", functionBreakpoint, 0); putDirectNativeFunction(vm, globalObject, Identifier::fromString(vm, "dfgTrue"), 0, functionDFGTrue, DFGTrueIntrinsic, jsDollarVMPropertyAttributes); putDirectNativeFunction(vm, globalObject, Identifier::fromString(vm, "ftlTrue"), 0, functionFTLTrue, FTLTrueIntrinsic, jsDollarVMPropertyAttributes); putDirectNativeFunction(vm, globalObject, Identifier::fromString(vm, "cpuMfence"), 0, functionCpuMfence, CPUMfenceIntrinsic, jsDollarVMPropertyAttributes); putDirectNativeFunction(vm, globalObject, Identifier::fromString(vm, "cpuRdtsc"), 0, functionCpuRdtsc, CPURdtscIntrinsic, jsDollarVMPropertyAttributes); putDirectNativeFunction(vm, globalObject, Identifier::fromString(vm, "cpuCpuid"), 0, functionCpuCpuid, CPUCpuidIntrinsic, jsDollarVMPropertyAttributes); putDirectNativeFunction(vm, globalObject, Identifier::fromString(vm, "cpuPause"), 0, functionCpuPause, CPUPauseIntrinsic, jsDollarVMPropertyAttributes); addFunction(vm, "cpuClflush", functionCpuClflush, 2); addFunction(vm, "llintTrue", functionLLintTrue, 0); addFunction(vm, "baselineJITTrue", functionBaselineJITTrue, 0); addFunction(vm, "noInline", functionNoInline, 1); addFunction(vm, "gc", functionGC, 0); addFunction(vm, "gcSweepAsynchronously", functionGCSweepAsynchronously, 0); addFunction(vm, "edenGC", functionEdenGC, 0); addFunction(vm, "dumpSubspaceHashes", functionDumpSubspaceHashes, 0); addFunction(vm, "callFrame", functionCallFrame, 1); addFunction(vm, "codeBlockFor", functionCodeBlockFor, 1); addFunction(vm, "codeBlockForFrame", functionCodeBlockForFrame, 1); addFunction(vm, "dumpSourceFor", functionDumpSourceFor, 1); addFunction(vm, "dumpBytecodeFor", functionDumpBytecodeFor, 1); addFunction(vm, "dataLog", functionDataLog, 1); addFunction(vm, "print", functionPrint, 1); addFunction(vm, "dumpCallFrame", functionDumpCallFrame, 0); addFunction(vm, "dumpStack", functionDumpStack, 0); addFunction(vm, "dumpRegisters", functionDumpRegisters, 1); addFunction(vm, "dumpCell", functionDumpCell, 1); addFunction(vm, "indexingMode", functionIndexingMode, 1); addFunction(vm, "inlineCapacity", functionInlineCapacity, 1); addFunction(vm, "clearLinkBufferStats", functionClearLinkBufferStats, 0); addFunction(vm, "linkBufferStats", functionLinkBufferStats, 0); addFunction(vm, "value", functionValue, 1); addFunction(vm, "getpid", functionGetPID, 0); addFunction(vm, "haveABadTime", functionHaveABadTime, 1); addFunction(vm, "isHavingABadTime", functionIsHavingABadTime, 1); addFunction(vm, "callWithStackSize", functionCallWithStackSize, 2); addFunction(vm, "createGlobalObject", functionCreateGlobalObject, 0); addFunction(vm, "createProxy", functionCreateProxy, 1); addFunction(vm, "createRuntimeArray", functionCreateRuntimeArray, 0); addFunction(vm, "createNullRopeString", functionCreateNullRopeString, 0); addFunction(vm, "createImpureGetter", functionCreateImpureGetter, 1); addFunction(vm, "createCustomGetterObject", functionCreateCustomGetterObject, 0); addFunction(vm, "createDOMJITNodeObject", functionCreateDOMJITNodeObject, 0); addFunction(vm, "createDOMJITGetterObject", functionCreateDOMJITGetterObject, 0); addFunction(vm, "createDOMJITGetterNoEffectsObject", functionCreateDOMJITGetterNoEffectsObject, 0); addFunction(vm, "createDOMJITGetterComplexObject", functionCreateDOMJITGetterComplexObject, 0); addFunction(vm, "createDOMJITFunctionObject", functionCreateDOMJITFunctionObject, 0); addFunction(vm, "createDOMJITCheckJSCastObject", functionCreateDOMJITCheckJSCastObject, 0); addFunction(vm, "createDOMJITGetterBaseJSObject", functionCreateDOMJITGetterBaseJSObject, 0); addFunction(vm, "createBuiltin", functionCreateBuiltin, 2); #if ENABLE(WEBASSEMBLY) addFunction(vm, "createWasmStreamingParser", functionCreateWasmStreamingParser, 0); addFunction(vm, "createWasmStreamingCompilerForCompile", functionCreateWasmStreamingCompilerForCompile, 0); addFunction(vm, "createWasmStreamingCompilerForInstantiate", functionCreateWasmStreamingCompilerForInstantiate, 0); #endif addFunction(vm, "createStaticCustomAccessor", functionCreateStaticCustomAccessor, 0); addFunction(vm, "createStaticCustomValue", functionCreateStaticCustomValue, 0); addFunction(vm, "createObjectDoingSideEffectPutWithoutCorrectSlotStatus", functionCreateObjectDoingSideEffectPutWithoutCorrectSlotStatus, 0); addFunction(vm, "createEmptyFunctionWithName", functionCreateEmptyFunctionWithName, 1); addFunction(vm, "getPrivateProperty", functionGetPrivateProperty, 2); addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2); addConstructibleFunction(vm, "Root", functionCreateRoot, 0); addConstructibleFunction(vm, "Element", functionCreateElement, 1); addFunction(vm, "getElement", functionGetElement, 1); addConstructibleFunction(vm, "SimpleObject", functionCreateSimpleObject, 0); addFunction(vm, "getHiddenValue", functionGetHiddenValue, 1); addFunction(vm, "setHiddenValue", functionSetHiddenValue, 2); addFunction(vm, "shadowChickenFunctionsOnStack", functionShadowChickenFunctionsOnStack, 0); addFunction(vm, "setGlobalConstRedeclarationShouldNotThrow", functionSetGlobalConstRedeclarationShouldNotThrow, 0); addFunction(vm, "findTypeForExpression", functionFindTypeForExpression, 2); addFunction(vm, "returnTypeFor", functionReturnTypeFor, 1); addFunction(vm, "flattenDictionaryObject", functionFlattenDictionaryObject, 1); addFunction(vm, "dumpBasicBlockExecutionRanges", functionDumpBasicBlockExecutionRanges , 0); addFunction(vm, "hasBasicBlockExecuted", functionHasBasicBlockExecuted, 2); addFunction(vm, "basicBlockExecutionCount", functionBasicBlockExecutionCount, 2); addFunction(vm, "enableDebuggerModeWhenIdle", functionEnableDebuggerModeWhenIdle, 0); addFunction(vm, "disableDebuggerModeWhenIdle", functionDisableDebuggerModeWhenIdle, 0); addFunction(vm, "deleteAllCodeWhenIdle", functionDeleteAllCodeWhenIdle, 0); addFunction(vm, "globalObjectCount", functionGlobalObjectCount, 0); addFunction(vm, "globalObjectForObject", functionGlobalObjectForObject, 1); addFunction(vm, "getGetterSetter", functionGetGetterSetter, 2); addFunction(vm, "loadGetterFromGetterSetter", functionLoadGetterFromGetterSetter, 1); addFunction(vm, "createCustomTestGetterSetter", functionCreateCustomTestGetterSetter, 1); addFunction(vm, "deltaBetweenButterflies", functionDeltaBetweenButterflies, 2); addFunction(vm, "currentCPUTime", functionCurrentCPUTime, 0); addFunction(vm, "totalGCTime", functionTotalGCTime, 0); addFunction(vm, "parseCount", functionParseCount, 0); addFunction(vm, "isWasmSupported", functionIsWasmSupported, 0); addFunction(vm, "make16BitStringIfPossible", functionMake16BitStringIfPossible, 1); addFunction(vm, "getStructureTransitionList", functionGetStructureTransitionList, 1); addFunction(vm, "getConcurrently", functionGetConcurrently, 2); addFunction(vm, "hasOwnLengthProperty", functionHasOwnLengthProperty, 1); addFunction(vm, "rejectPromiseAsHandled", functionRejectPromiseAsHandled, 1); addFunction(vm, "setUserPreferredLanguages", functionSetUserPreferredLanguages, 1); addFunction(vm, "icuVersion", functionICUVersion, 0); addFunction(vm, "icuHeaderVersion", functionICUHeaderVersion, 0); addFunction(vm, "assertEnabled", functionAssertEnabled, 0); addFunction(vm, "securityAssertEnabled", functionSecurityAssertEnabled, 0); addFunction(vm, "asanEnabled", functionAsanEnabled, 0); addFunction(vm, "isMemoryLimited", functionIsMemoryLimited, 0); addFunction(vm, "useJIT", functionUseJIT, 0); addFunction(vm, "isGigacageEnabled", functionIsGigacageEnabled, 0); addFunction(vm, "toCacheableDictionary", functionToCacheableDictionary, 1); addFunction(vm, "toUncacheableDictionary", functionToUncacheableDictionary, 1); addFunction(vm, "isPrivateSymbol", functionIsPrivateSymbol, 1); addFunction(vm, "dumpAndResetPasDebugSpectrum", functionDumpAndResetPasDebugSpectrum, 0); addFunction(vm, "monotonicTimeNow", functionMonotonicTimeNow, 0); addFunction(vm, "wallTimeNow", functionWallTimeNow, 0); addFunction(vm, "approximateTimeNow", functionApproximateTimeNow, 0); #if ENABLE(JIT) addFunction(vm, "jitSizeStatistics", functionJITSizeStatistics, 0); addFunction(vm, "dumpJITSizeStatistics", functionDumpJITSizeStatistics, 0); addFunction(vm, "resetJITSizeStatistics", functionResetJITSizeStatistics, 0); #endif addFunction(vm, "ensureArrayStorage", functionEnsureArrayStorage, 1); m_objectDoingSideEffectPutWithoutCorrectSlotStatusStructure.set(vm, this, ObjectDoingSideEffectPutWithoutCorrectSlotStatus::createStructure(vm, globalObject, jsNull())); } void JSDollarVM::addFunction(VM& vm, JSGlobalObject* globalObject, const char* name, NativeFunction function, unsigned arguments) { DollarVMAssertScope assertScope; Identifier identifier = Identifier::fromString(vm, name); putDirect(vm, identifier, JSFunction::create(vm, globalObject, arguments, identifier.string(), function), jsDollarVMPropertyAttributes); } void JSDollarVM::addConstructibleFunction(VM& vm, JSGlobalObject* globalObject, const char* name, NativeFunction function, unsigned arguments) { DollarVMAssertScope assertScope; Identifier identifier = Identifier::fromString(vm, name); putDirect(vm, identifier, JSFunction::create(vm, globalObject, arguments, identifier.string(), function, NoIntrinsic, function), jsDollarVMPropertyAttributes); } template void JSDollarVM::visitChildrenImpl(JSCell* cell, Visitor& visitor) { JSDollarVM* thisObject = jsCast(cell); Base::visitChildren(thisObject, visitor); visitor.append(thisObject->m_objectDoingSideEffectPutWithoutCorrectSlotStatusStructure); } DEFINE_VISIT_CHILDREN(JSDollarVM); } // namespace JSC IGNORE_WARNINGS_END