/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "jit/VMFunctions.h" #include "mozilla/FloatingPoint.h" #include "builtin/MapObject.h" #include "builtin/String.h" #include "ds/OrderedHashTable.h" #include "gc/Cell.h" #include "gc/GC.h" #include "jit/arm/Simulator-arm.h" #include "jit/AtomicOperations.h" #include "jit/BaselineIC.h" #include "jit/CalleeToken.h" #include "jit/JitFrames.h" #include "jit/JitRuntime.h" #include "jit/mips32/Simulator-mips32.h" #include "jit/mips64/Simulator-mips64.h" #include "jit/Simulator.h" #include "js/experimental/JitInfo.h" #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_* #include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit #include "js/friend/WindowProxy.h" // js::IsWindow #include "js/Printf.h" #include "js/TraceKind.h" #include "vm/ArrayObject.h" #include "vm/Compartment.h" #include "vm/Interpreter.h" #include "vm/JSAtom.h" #include "vm/PlainObject.h" // js::PlainObject #include "vm/SelfHosting.h" #include "vm/StaticStrings.h" #include "vm/TypedArrayObject.h" #include "vm/Watchtower.h" #include "wasm/WasmGcObject.h" #include "debugger/DebugAPI-inl.h" #include "jit/BaselineFrame-inl.h" #include "jit/VMFunctionList-inl.h" #include "vm/Interpreter-inl.h" #include "vm/JSScript-inl.h" #include "vm/NativeObject-inl.h" #include "vm/PlainObject-inl.h" // js::CreateThis #include "vm/StringObject-inl.h" using namespace js; using namespace js::jit; namespace js { class ArgumentsObject; class NamedLambdaObject; class AsyncFunctionGeneratorObject; class RegExpObject; namespace jit { struct IonOsrTempData; struct PopValues { uint8_t numValues; explicit constexpr PopValues(uint8_t numValues) : numValues(numValues) {} }; template struct ReturnTypeToDataType { /* Unexpected return type for a VMFunction. */ }; template <> struct ReturnTypeToDataType { static const DataType result = Type_Void; }; template <> struct ReturnTypeToDataType { static const DataType result = Type_Bool; }; template struct ReturnTypeToDataType { // Assume by default that any pointer return types are cells. static_assert(std::is_base_of_v); static const DataType result = Type_Cell; }; // Convert argument types to properties of the argument known by the jit. template struct TypeToArgProperties { static const uint32_t result = (sizeof(T) <= sizeof(void*) ? VMFunctionData::Word : VMFunctionData::Double); }; template <> struct TypeToArgProperties { static const uint32_t result = TypeToArgProperties::result | VMFunctionData::ByRef; }; template <> struct TypeToArgProperties { static const uint32_t result = TypeToArgProperties::result | VMFunctionData::ByRef; }; template <> struct TypeToArgProperties { static const uint32_t result = TypeToArgProperties::result | VMFunctionData::ByRef; }; template <> struct TypeToArgProperties { static const uint32_t result = TypeToArgProperties::result | VMFunctionData::ByRef; }; template struct TypeToArgProperties> { // Assume by default that any pointer handle types are cells. static_assert(std::is_base_of_v); static const uint32_t result = TypeToArgProperties::result | VMFunctionData::ByRef; }; template struct TypeToArgProperties> { // Fail for Handle types that aren't specialized above. }; // Convert argument type to whether or not it should be passed in a float // register on platforms that have them, like x64. template struct TypeToPassInFloatReg { static const uint32_t result = 0; }; template <> struct TypeToPassInFloatReg { static const uint32_t result = 1; }; // Convert argument types to root types used by the gc, see TraceJitExitFrame. template struct TypeToRootType { static const uint32_t result = VMFunctionData::RootNone; }; template <> struct TypeToRootType { static const uint32_t result = VMFunctionData::RootValue; }; template <> struct TypeToRootType { static const uint32_t result = VMFunctionData::RootValue; }; template <> struct TypeToRootType { static const uint32_t result = VMFunctionData::RootId; }; template struct TypeToRootType> { // Assume by default that any pointer types are cells. static_assert(std::is_base_of_v); static constexpr uint32_t rootType() { using JS::TraceKind; switch (JS::MapTypeToTraceKind::kind) { case TraceKind::Object: return VMFunctionData::RootObject; case TraceKind::BigInt: return VMFunctionData::RootBigInt; case TraceKind::String: return VMFunctionData::RootString; case TraceKind::Shape: case TraceKind::Script: case TraceKind::Scope: return VMFunctionData::RootCell; case TraceKind::Symbol: case TraceKind::BaseShape: case TraceKind::Null: case TraceKind::JitCode: case TraceKind::RegExpShared: case TraceKind::GetterSetter: case TraceKind::PropMap: MOZ_CRASH("Unexpected trace kind"); } } static constexpr uint32_t result = rootType(); }; template struct TypeToRootType> { // Fail for Handle types that aren't specialized above. }; template struct OutParamToDataType { static const DataType result = Type_Void; }; template struct OutParamToDataType { // Const pointers can't be output parameters. static const DataType result = Type_Void; }; template <> struct OutParamToDataType { // Already used as an input type, so it can't be used as an output param. static const DataType result = Type_Void; }; template <> struct OutParamToDataType { // Already used as an input type, so it can't be used as an output param. static const DataType result = Type_Void; }; template <> struct OutParamToDataType { // Already used as an input type, so it can't be used as an output param. static const DataType result = Type_Void; }; template <> struct OutParamToDataType { // Already used as an input type, so it can't be used as an output param. static const DataType result = Type_Void; }; template <> struct OutParamToDataType { // Already used as an input type, so it can't be used as an output param. static const DataType result = Type_Void; }; template <> struct OutParamToDataType { static const DataType result = Type_Value; }; template <> struct OutParamToDataType { static const DataType result = Type_Int32; }; template <> struct OutParamToDataType { static const DataType result = Type_Int32; }; template <> struct OutParamToDataType { static const DataType result = Type_Bool; }; template <> struct OutParamToDataType { static const DataType result = Type_Double; }; template struct OutParamToDataType { // Fail for pointer types that aren't specialized above. }; template struct OutParamToDataType { static const DataType result = Type_Pointer; }; template struct OutParamToDataType> { static const DataType result = Type_Handle; }; template struct OutParamToRootType { static const VMFunctionData::RootType result = VMFunctionData::RootNone; }; template <> struct OutParamToRootType { static const VMFunctionData::RootType result = VMFunctionData::RootValue; }; template <> struct OutParamToRootType { static const VMFunctionData::RootType result = VMFunctionData::RootObject; }; template <> struct OutParamToRootType { static const VMFunctionData::RootType result = VMFunctionData::RootString; }; template <> struct OutParamToRootType { static const VMFunctionData::RootType result = VMFunctionData::RootBigInt; }; // Construct a bit mask from a list of types. The mask is constructed as an OR // of the mask produced for each argument. The result of each argument is // shifted by its index, such that the result of the first argument is on the // low bits of the mask, and the result of the last argument in part of the // high bits of the mask. template