Bug 1530937 part 17 - Remove now unused VMFunction code. r=nbp
authorJan de Mooij <jdemooij@mozilla.com>
Tue, 12 Mar 2019 14:47:50 +0000
changeset 521567 3aa21d7302e7
parent 521566 aaf573c47a9c
child 521568 aa1745f5137c
push id10867
push userdvarga@mozilla.com
push dateThu, 14 Mar 2019 15:20:45 +0000
treeherdermozilla-beta@abad13547875 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs1530937
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1530937 part 17 - Remove now unused VMFunction code. r=nbp Differential Revision: https://phabricator.services.mozilla.com/D23137
js/src/jit/BaselineIC.cpp
js/src/jit/BaselineIC.h
js/src/jit/Ion.cpp
js/src/jit/JitFrames.cpp
js/src/jit/MacroAssembler.cpp
js/src/jit/MacroAssembler.h
js/src/jit/VMFunctionList-inl.h
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
js/src/jit/arm/Trampoline-arm.cpp
js/src/jit/arm64/Trampoline-arm64.cpp
js/src/jit/x64/Trampoline-x64.cpp
js/src/jit/x86/Trampoline-x86.cpp
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -1768,23 +1768,16 @@ bool DoTypeUpdateFallback(JSContext* cx,
     // instance we may reallocate dynamic slots before calling this),
     // so ignore OOMs if we failed to attach a stub.
     cx->recoverFromOutOfMemory();
   }
 
   return true;
 }
 
-typedef bool (*DoTypeUpdateFallbackFn)(JSContext*, BaselineFrame*,
-                                       ICUpdatedStub*, HandleValue,
-                                       HandleValue);
-const VMFunction DoTypeUpdateFallbackInfo =
-    FunctionInfo<DoTypeUpdateFallbackFn>(DoTypeUpdateFallback,
-                                         "DoTypeUpdateFallback", NonTailCall);
-
 bool ICTypeUpdate_Fallback::Compiler::generateStubCode(MacroAssembler& masm) {
   // Just store false into R1.scratchReg() and return.
   masm.move32(Imm32(0), R1.scratchReg());
   EmitReturnFromIC(masm);
   return true;
 }
 
 bool ICTypeUpdate_PrimitiveSet::Compiler::generateStubCode(
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -1485,18 +1485,16 @@ class ICTypeMonitor_AnyValue : public IC
     ICTypeMonitor_AnyValue* getStub(ICStubSpace* space) override {
       return newStub<ICTypeMonitor_AnyValue>(space, getStubCode());
     }
   };
 };
 
 // TypeUpdate
 
-extern const VMFunction DoTypeUpdateFallbackInfo;
-
 // The TypeUpdate fallback is not a regular fallback, since it just
 // forwards to a different entry point in the main fallback stub.
 class ICTypeUpdate_Fallback : public ICStub {
   friend class ICStubSpace;
 
   explicit ICTypeUpdate_Fallback(JitCode* stubCode)
       : ICStub(ICStub::TypeUpdate_Fallback, stubCode) {}
 
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -160,32 +160,29 @@ JitRuntime::JitRuntime()
       argumentsRectifierReturnOffset_(0),
       invalidatorOffset_(0),
       lazyLinkStubOffset_(0),
       interpreterStubOffset_(0),
       doubleToInt32ValueStubOffset_(0),
       debugTrapHandler_(nullptr),
       baselineDebugModeOSRHandler_(nullptr),
       trampolineCode_(nullptr),
-      functionWrappers_(nullptr),
       jitcodeGlobalTable_(nullptr),
 #ifdef DEBUG
       ionBailAfter_(0),
 #endif
       numFinishedBuilders_(0),
       ionLazyLinkListSize_(0) {
 }
 
 JitRuntime::~JitRuntime() {
   MOZ_ASSERT(numFinishedBuilders_ == 0);
   MOZ_ASSERT(ionLazyLinkListSize_ == 0);
   MOZ_ASSERT(ionLazyLinkList_.ref().isEmpty());
 
-  js_delete(functionWrappers_.ref());
-
   // By this point, the jitcode global table should be empty.
   MOZ_ASSERT_IF(jitcodeGlobalTable_, jitcodeGlobalTable_->empty());
   js_delete(jitcodeGlobalTable_.ref());
 }
 
 uint32_t JitRuntime::startTrampolineCode(MacroAssembler& masm) {
   masm.assumeUnreachable("Shouldn't get here");
   masm.flushBuffer();
@@ -196,21 +193,16 @@ uint32_t JitRuntime::startTrampolineCode
 
 bool JitRuntime::initialize(JSContext* cx) {
   MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
 
   AutoAllocInAtomsZone az(cx);
 
   JitContext jctx(cx, nullptr);
 
-  functionWrappers_ = cx->new_<VMWrapperMap>(cx);
-  if (!functionWrappers_) {
-    return false;
-  }
-
   StackMacroAssembler masm;
 
   Label bailoutTail;
   JitSpew(JitSpew_Codegen, "# Emitting bailout tail stub");
   generateBailoutTailStub(masm, &bailoutTail);
 
   if (cx->runtime()->jitSupportsFloatingPoint) {
     JitSpew(JitSpew_Codegen, "# Emitting bailout tables");
@@ -285,32 +277,16 @@ bool JitRuntime::initialize(JSContext* c
   JitSpew(JitSpew_Codegen, "# Emitting double-to-int32-value stub");
   generateDoubleToInt32ValueStub(masm);
 
   JitSpew(JitSpew_Codegen, "# Emitting VM function wrappers");
   if (!generateVMWrappers(cx, masm)) {
     return false;
   }
 
-  // TODO(bug 1530937): remove this after converting all VM functions.
-  for (VMFunction* fun = VMFunction::functions; fun; fun = fun->next) {
-    if (functionWrappers_->has(fun)) {
-      // Duplicate VMFunction definition. See VMFunction::hash.
-      continue;
-    }
-    JitSpew(JitSpew_Codegen, "# VM function wrapper (%s)", fun->name());
-    uint32_t offset;
-    if (!generateVMWrapper(cx, masm, *fun, fun->wrapped, &offset)) {
-      return false;
-    }
-    if (!functionWrappers_->putNew(fun, offset)) {
-      return false;
-    }
-  }
-
   JitSpew(JitSpew_Codegen, "# Emitting profiler exit frame tail stub");
   Label profilerExitTail;
   generateProfilerExitFrameTailStub(masm, &profilerExitTail);
 
   JitSpew(JitSpew_Codegen, "# Emitting exception tail stub");
   void* handler = JS_FUNC_TO_DATA_PTR(void*, jit::HandleException);
   generateExceptionTailStub(masm, handler, &profilerExitTail);
 
@@ -629,26 +605,16 @@ TrampolinePtr JitRuntime::getBailoutTabl
 }
 
 uint32_t JitRuntime::getBailoutTableSize(
     const FrameSizeClass& frameClass) const {
   MOZ_ASSERT(frameClass != FrameSizeClass::None());
   return bailoutTables_.ref()[frameClass.classId()].size;
 }
 
-TrampolinePtr JitRuntime::getVMWrapper(const VMFunction& f) const {
-  MOZ_ASSERT(functionWrappers_);
-  MOZ_ASSERT(trampolineCode_);
-
-  JitRuntime::VMWrapperMap::Ptr p =
-      functionWrappers_->readonlyThreadsafeLookup(&f);
-  MOZ_ASSERT(p);
-  return trampolineCode(p->value());
-}
-
 void JitCodeHeader::init(JitCode* jitCode) {
   // As long as JitCode isn't moveable, we can avoid tracing this and
   // mutating executable data.
   MOZ_ASSERT(!gc::IsMovableKind(gc::AllocKind::JITCODE));
   jitCode_ = jitCode;
 
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
   // On AMD Bobcat processors that may have eratas, insert a NOP slide to reduce
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -1028,22 +1028,22 @@ static void TraceJitExitFrameCopiedArgum
   uint8_t* doubleArgs = reinterpret_cast<uint8_t*>(footer);
   doubleArgs = alignDoubleSpillWithOffset(doubleArgs, sizeof(intptr_t));
   if (f->outParam == Type_Handle) {
     doubleArgs -= sizeof(Value);
   }
   doubleArgs -= f->doubleByRefArgs() * sizeof(double);
 
   for (uint32_t explicitArg = 0; explicitArg < f->explicitArgs; explicitArg++) {
-    if (f->argProperties(explicitArg) == VMFunction::DoubleByRef) {
+    if (f->argProperties(explicitArg) == VMFunctionData::DoubleByRef) {
       // Arguments with double size can only have RootValue type.
-      if (f->argRootType(explicitArg) == VMFunction::RootValue) {
+      if (f->argRootType(explicitArg) == VMFunctionData::RootValue) {
         TraceRoot(trc, reinterpret_cast<Value*>(doubleArgs), "ion-vm-args");
       } else {
-        MOZ_ASSERT(f->argRootType(explicitArg) == VMFunction::RootNone);
+        MOZ_ASSERT(f->argRootType(explicitArg) == VMFunctionData::RootNone);
       }
       doubleArgs += sizeof(double);
     }
   }
 }
 #else
 static void TraceJitExitFrameCopiedArguments(JSTracer* trc,
                                              const VMFunctionData* f,
@@ -1131,76 +1131,76 @@ static void TraceJitExitFrame(JSTracer* 
 
   const VMFunctionData* f = footer->function();
   MOZ_ASSERT(f);
 
   // Trace arguments of the VM wrapper.
   uint8_t* argBase = frame.exitFrame()->argBase();
   for (uint32_t explicitArg = 0; explicitArg < f->explicitArgs; explicitArg++) {
     switch (f->argRootType(explicitArg)) {
-      case VMFunction::RootNone:
+      case VMFunctionData::RootNone:
         break;
-      case VMFunction::RootObject: {
+      case VMFunctionData::RootObject: {
         // Sometimes we can bake in HandleObjects to nullptr.
         JSObject** pobj = reinterpret_cast<JSObject**>(argBase);
         if (*pobj) {
           TraceRoot(trc, pobj, "ion-vm-args");
         }
         break;
       }
-      case VMFunction::RootString:
+      case VMFunctionData::RootString:
         TraceRoot(trc, reinterpret_cast<JSString**>(argBase), "ion-vm-args");
         break;
-      case VMFunction::RootFunction:
+      case VMFunctionData::RootFunction:
         TraceRoot(trc, reinterpret_cast<JSFunction**>(argBase), "ion-vm-args");
         break;
-      case VMFunction::RootValue:
+      case VMFunctionData::RootValue:
         TraceRoot(trc, reinterpret_cast<Value*>(argBase), "ion-vm-args");
         break;
-      case VMFunction::RootId:
+      case VMFunctionData::RootId:
         TraceRoot(trc, reinterpret_cast<jsid*>(argBase), "ion-vm-args");
         break;
-      case VMFunction::RootCell:
+      case VMFunctionData::RootCell:
         TraceGenericPointerRoot(trc, reinterpret_cast<gc::Cell**>(argBase),
                                 "ion-vm-args");
         break;
     }
 
     switch (f->argProperties(explicitArg)) {
-      case VMFunction::WordByValue:
-      case VMFunction::WordByRef:
+      case VMFunctionData::WordByValue:
+      case VMFunctionData::WordByRef:
         argBase += sizeof(void*);
         break;
-      case VMFunction::DoubleByValue:
-      case VMFunction::DoubleByRef:
+      case VMFunctionData::DoubleByValue:
+      case VMFunctionData::DoubleByRef:
         argBase += 2 * sizeof(void*);
         break;
     }
   }
 
   if (f->outParam == Type_Handle) {
     switch (f->outParamRootType) {
-      case VMFunction::RootNone:
+      case VMFunctionData::RootNone:
         MOZ_CRASH("Handle outparam must have root type");
-      case VMFunction::RootObject:
+      case VMFunctionData::RootObject:
         TraceRoot(trc, footer->outParam<JSObject*>(), "ion-vm-out");
         break;
-      case VMFunction::RootString:
+      case VMFunctionData::RootString:
         TraceRoot(trc, footer->outParam<JSString*>(), "ion-vm-out");
         break;
-      case VMFunction::RootFunction:
+      case VMFunctionData::RootFunction:
         TraceRoot(trc, footer->outParam<JSFunction*>(), "ion-vm-out");
         break;
-      case VMFunction::RootValue:
+      case VMFunctionData::RootValue:
         TraceRoot(trc, footer->outParam<Value>(), "ion-vm-outvp");
         break;
-      case VMFunction::RootId:
+      case VMFunctionData::RootId:
         TraceRoot(trc, footer->outParam<jsid>(), "ion-vm-outvp");
         break;
-      case VMFunction::RootCell:
+      case VMFunctionData::RootCell:
         TraceGenericPointerRoot(trc, footer->outParam<gc::Cell*>(),
                                 "ion-vm-out");
         break;
     }
   }
 
   TraceJitExitFrameCopiedArguments(trc, f, footer);
 }
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -2990,48 +2990,48 @@ void MacroAssembler::Push(JSValueType ty
 }
 
 void MacroAssembler::PushValue(const Address& addr) {
   MOZ_ASSERT(addr.base != getStackPointer());
   pushValue(addr);
   framePushed_ += sizeof(Value);
 }
 
-void MacroAssembler::PushEmptyRooted(VMFunction::RootType rootType) {
+void MacroAssembler::PushEmptyRooted(VMFunctionData::RootType rootType) {
   switch (rootType) {
-    case VMFunction::RootNone:
+    case VMFunctionData::RootNone:
       MOZ_CRASH("Handle must have root type");
-    case VMFunction::RootObject:
-    case VMFunction::RootString:
-    case VMFunction::RootFunction:
-    case VMFunction::RootCell:
+    case VMFunctionData::RootObject:
+    case VMFunctionData::RootString:
+    case VMFunctionData::RootFunction:
+    case VMFunctionData::RootCell:
       Push(ImmPtr(nullptr));
       break;
-    case VMFunction::RootValue:
+    case VMFunctionData::RootValue:
       Push(UndefinedValue());
       break;
-    case VMFunction::RootId:
+    case VMFunctionData::RootId:
       Push(ImmWord(JSID_BITS(JSID_VOID)));
       break;
   }
 }
 
-void MacroAssembler::popRooted(VMFunction::RootType rootType, Register cellReg,
-                               const ValueOperand& valueReg) {
+void MacroAssembler::popRooted(VMFunctionData::RootType rootType,
+                               Register cellReg, const ValueOperand& valueReg) {
   switch (rootType) {
-    case VMFunction::RootNone:
+    case VMFunctionData::RootNone:
       MOZ_CRASH("Handle must have root type");
-    case VMFunction::RootObject:
-    case VMFunction::RootString:
-    case VMFunction::RootFunction:
-    case VMFunction::RootCell:
-    case VMFunction::RootId:
+    case VMFunctionData::RootObject:
+    case VMFunctionData::RootString:
+    case VMFunctionData::RootFunction:
+    case VMFunctionData::RootCell:
+    case VMFunctionData::RootId:
       Pop(cellReg);
       break;
-    case VMFunction::RootValue:
+    case VMFunctionData::RootValue:
       Pop(valueReg);
       break;
   }
 }
 
 void MacroAssembler::adjustStack(int amount) {
   if (amount > 0) {
     freeStack(amount);
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -382,27 +382,27 @@ class MacroAssembler : public MacroAssem
   void Push(jsid id, Register scratchReg);
   void Push(const Address& addr);
   void Push(TypedOrValueRegister v);
   void Push(const ConstantOrRegister& v);
   void Push(const ValueOperand& val);
   void Push(const Value& val);
   void Push(JSValueType type, Register reg);
   void PushValue(const Address& addr);
-  void PushEmptyRooted(VMFunction::RootType rootType);
+  void PushEmptyRooted(VMFunctionData::RootType rootType);
   inline CodeOffset PushWithPatch(ImmWord word);
   inline CodeOffset PushWithPatch(ImmPtr imm);
 
   void Pop(const Operand op) DEFINED_ON(x86_shared);
   void Pop(Register reg) PER_SHARED_ARCH;
   void Pop(FloatRegister t) PER_SHARED_ARCH;
   void Pop(const ValueOperand& val) PER_SHARED_ARCH;
   void PopFlags() DEFINED_ON(x86_shared);
   void PopStackPtr() DEFINED_ON(arm, mips_shared, x86_shared);
-  void popRooted(VMFunction::RootType rootType, Register cellReg,
+  void popRooted(VMFunctionData::RootType rootType, Register cellReg,
                  const ValueOperand& valueReg);
 
   // Move the stack pointer based on the requested amount.
   void adjustStack(int amount);
   void freeStack(uint32_t amount);
 
   // Warning: This method does not update the framePushed() counter.
   void freeStack(Register amount);
--- a/js/src/jit/VMFunctionList-inl.h
+++ b/js/src/jit/VMFunctionList-inl.h
@@ -113,16 +113,17 @@ namespace jit {
   _(GetNonSyntacticGlobalThis, js::GetNonSyntacticGlobalThis)                  \
   _(GetOrCreateModuleMetaObject, js::GetOrCreateModuleMetaObject)              \
   _(GetPrototypeOf, js::jit::GetPrototypeOf)                                   \
   _(GetSparseElementHelper, js::GetSparseElementHelper)                        \
   _(GetValueProperty, js::GetValueProperty)                                    \
   _(GlobalNameConflictsCheckFromIon, js::jit::GlobalNameConflictsCheckFromIon) \
   _(GreaterThan, js::jit::GreaterThan)                                         \
   _(GreaterThanOrEqual, js::jit::GreaterThanOrEqual)                           \
+  _(HandleDebugTrap, js::jit::HandleDebugTrap)                                 \
   _(HomeObjectSuperBase, js::HomeObjectSuperBase)                              \
   _(ImplicitThisOperation, js::ImplicitThisOperation)                          \
   _(ImportMetaOperation, js::ImportMetaOperation)                              \
   _(InitElemGetterSetterOperation, js::InitElemGetterSetterOperation)          \
   _(InitElemOperation, js::InitElemOperation)                                  \
   _(InitElementArray, js::InitElementArray)                                    \
   _(InitFunctionEnvironmentObjects, js::jit::InitFunctionEnvironmentObjects)   \
   _(InitPropGetterSetterOperation, js::InitPropGetterSetterOperation)          \
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -62,22 +62,21 @@ struct VMFunctionDataHelper<R (*)(JSCont
     return BitMask<TypeToArgProperties, uint32_t, 2, Args...>::result;
   }
   static constexpr uint32_t argumentPassedInFloatRegs() {
     return BitMask<TypeToPassInFloatReg, uint32_t, 2, Args...>::result;
   }
   static constexpr uint64_t argumentRootTypes() {
     return BitMask<TypeToRootType, uint64_t, 3, Args...>::result;
   }
-  constexpr explicit VMFunctionDataHelper(
-      const char* name, PopValues extraValuesToPop = PopValues(0))
+  constexpr explicit VMFunctionDataHelper(const char* name)
       : VMFunctionData(name, explicitArgs(), argumentProperties(),
                        argumentPassedInFloatRegs(), argumentRootTypes(),
                        outParam(), outParamRootType(), returnType(),
-                       extraValuesToPop.numValues, NonTailCall) {}
+                       /* extraValuesToPop = */ 0, NonTailCall) {}
   constexpr explicit VMFunctionDataHelper(const char* name,
                                           MaybeTailCall expectTailCall,
                                           PopValues extraValuesToPop)
       : VMFunctionData(name, explicitArgs(), argumentProperties(),
                        argumentPassedInFloatRegs(), argumentRootTypes(),
                        outParam(), outParamRootType(), returnType(),
                        extraValuesToPop.numValues, expectTailCall) {}
 };
@@ -182,20 +181,16 @@ bool JitRuntime::generateVMWrappers(JSCo
   if (!generateVMWrappers<TailCallVMFunctionId>(
           cx, masm, tailCallFunctionWrapperOffsets_)) {
     return false;
   }
 
   return true;
 }
 
-// Statics are initialized to null.
-/* static */
-VMFunction* VMFunction::functions;
-
 AutoDetectInvalidation::AutoDetectInvalidation(JSContext* cx,
                                                MutableHandleValue rval)
     : cx_(cx),
       ionScript_(GetTopJitJSScript(cx)->ionScript()),
       rval_(rval),
       disabled_(false) {}
 
 bool InvokeFunction(JSContext* cx, HandleObject obj, bool constructing,
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -51,53 +51,51 @@ struct PopValues {
 
   explicit constexpr PopValues(uint8_t numValues) : numValues(numValues) {}
 };
 
 enum MaybeTailCall : bool { TailCall, NonTailCall };
 
 // [SMDOC] JIT-to-C++ Function Calls. (callVM)
 //
-// TODO(bug 1530937): update this comment after converting all VM functions.
-//
 // Sometimes it is easier to reuse C++ code by calling VM's functions. Calling a
 // function from the VM can be achieved with the use of callWithABI but this is
 // discouraged when the called functions might trigger exceptions and/or
 // garbage collections which are expecting to walk the stack. VMFunctions and
 // callVM are interfaces provided to handle the exception handling and register
 // the stack end (JITActivation) such that walking the stack is made possible.
 //
-// A VMFunction is a structure which contains the necessary information needed
+// VMFunctionData is a structure which contains the necessary information needed
 // for generating a trampoline function to make a call (with generateVMWrapper)
-// and to root the arguments of the function (in TraceJitExitFrame). VMFunctions
-// are created with the FunctionInfo template, which infers the fields of the
-// VMFunction from the function signature. The rooting and trampoline code is
-// therefore determined by the arguments of a function and their locations in
-// the signature of a function.
+// and to root the arguments of the function (in TraceJitExitFrame).
+// VMFunctionData is created with the VMFunctionDataHelper template, which
+// infers the VMFunctionData fields from the function signature. The rooting and
+// trampoline code is therefore determined by the arguments of a function and
+// their locations in the signature of a function.
 //
-// VMFunction all expect a JSContext* as first argument. This argument is
+// VM functions all expect a JSContext* as first argument. This argument is
 // implicitly provided by the trampoline code (in generateVMWrapper) and used
 // for creating new objects or reporting errors. If your function does not make
 // use of a JSContext* argument, then you might probably use a callWithABI
 // call.
 //
 // Functions described using the VMFunction system must conform to a simple
 // protocol: the return type must have a special "failure" value (for example,
 // false for bool, or nullptr for Objects). If the function is designed to
 // return a value that does not meet this requirement - such as
 // object-or-nullptr, or an integer, an optional, final outParam can be
 // specified. In this case, the return type must be boolean to indicate
 // failure.
 //
 // JIT Code usage:
 //
 // Different JIT compilers in SpiderMonkey have their own implementations of
-// callVM to consume VMFunctions. However, the general shape of them is that
-// arguments that don't include the JIT Context or trailing out-param are pushed
-// on to the stack from right to left (rightmost argument is pushed first).
+// callVM to call VM functions. However, the general shape of them is that
+// arguments (excluding the JSContext or trailing out-param) are pushed on to
+// the stack from right to left (rightmost argument is pushed first).
 //
 // Regardless of return value protocol being used (final outParam, or return
 // value) the generated trampolines ensure the return value ends up in
 // JSReturnOperand, ReturnReg or ReturnDoubleReg.
 //
 // Example:
 //
 // The details will differ slightly between the different compilers in
@@ -105,28 +103,29 @@ enum MaybeTailCall : bool { TailCall, No
 //
 // Suppose we have a function Foo:
 //
 //      bool Foo(JSContext* cx, HandleObject x, HandleId y,
 //               MutableHandleValue z);
 //
 // This function returns true on success, and z is the outparam return value.
 //
-// A VMFunction for this can be created using FunctionInfo. The typical pattern
-// used is:
+// A VM function wrapper for this can be created by adding an entry to
+// VM_FUNCTION_LIST in VMFunctionList-inl.h:
 //
-//      typedef bool (*FooFn)(JSContext*, HandleObject, HandleId,
-//                            MutableHandleValue);
-//      const VMFunction FooInfo = FunctionInfo<FooFn>(Foo, "Foo");
+//    _(Foo, js::Foo)
 //
 // In the compiler code the call would then be issued like this:
 //
 //      masm.Push(id);
 //      masm.Push(obj);
-//      if (!callVM(FooInfo)) {
+//
+//      using Fn = bool (*)(JSContext*, HandleObject, HandleId,
+//                          MutableHandleValue);
+//      if (!callVM<Fn, js::Foo>()) {
 //          return false;
 //      }
 //
 // After this, the result value is in the return value register.
 
 // Data for a VM function. All VMFunctionDatas are stored in a constexpr array.
 struct VMFunctionData {
 #if defined(JS_JITSPEW) || defined(JS_TRACE_LOGGING)
@@ -313,96 +312,17 @@ struct VMFunctionData {
         expectTailCall(expectTailCall) {
     // Check for valid failure/return type.
     MOZ_ASSERT_IF(outParam != Type_Void,
                   returnType == Type_Void || returnType == Type_Bool);
     MOZ_ASSERT(returnType == Type_Void || returnType == Type_Bool ||
                returnType == Type_Object);
   }
 
-  // Note: clang-tidy suggests using |= auto| here but that generates extra
-  // static initializers for old-style VMFunction definitions with Clang. We can
-  // do this after bug 1530937 converts all of them.
-  constexpr VMFunctionData(const VMFunctionData& o)
-      :
-#if defined(JS_JITSPEW) || defined(JS_TRACE_LOGGING)
-        name_(o.name_),
-#endif
-        argumentRootTypes(o.argumentRootTypes),
-        argumentProperties(o.argumentProperties),
-        argumentPassedInFloatRegs(o.argumentPassedInFloatRegs),
-        explicitArgs(o.explicitArgs),
-        outParamRootType(o.outParamRootType),
-        outParam(o.outParam),
-        returnType(o.returnType),
-        extraValuesToPop(o.extraValuesToPop),
-        expectTailCall(o.expectTailCall) {
-  }
-};
-
-// TODO(bug 1530937): remove VMFunction and FunctionInfo after converting all VM
-// functions to the new design.
-struct VMFunction : public VMFunctionData {
-  // Address of the C function.
-  void* wrapped;
-
-  // Global linked list of all VMFunctions.
-  static VMFunction* functions;
-  VMFunction* next;
-
-  constexpr VMFunction(void* wrapped, const char* name, uint32_t explicitArgs,
-                       uint32_t argumentProperties,
-                       uint32_t argumentPassedInFloatRegs,
-                       uint64_t argRootTypes, DataType outParam,
-                       RootType outParamRootType, DataType returnType,
-                       uint8_t extraValuesToPop = 0,
-                       MaybeTailCall expectTailCall = NonTailCall)
-      : VMFunctionData(name, explicitArgs, argumentProperties,
-                       argumentPassedInFloatRegs, argRootTypes, outParam,
-                       outParamRootType, returnType, extraValuesToPop,
-                       expectTailCall),
-        wrapped(wrapped),
-        next(nullptr) {}
-
-  VMFunction(const VMFunction& o)
-      : VMFunctionData(o), wrapped(o.wrapped), next(functions) {
-    // Add this to the global list of VMFunctions.
-    functions = this;
-  }
-
-  typedef const VMFunction* Lookup;
-
-  static HashNumber hash(const VMFunction* f) {
-    // The hash is based on the wrapped function, not the VMFunction*, to
-    // avoid generating duplicate wrapper code.
-    HashNumber hash = 0;
-    hash = mozilla::AddToHash(hash, f->wrapped);
-    hash = mozilla::AddToHash(hash, f->expectTailCall);
-    return hash;
-  }
-  static bool match(const VMFunction* f1, const VMFunction* f2) {
-    if (f1->wrapped != f2->wrapped ||
-        f1->expectTailCall != f2->expectTailCall) {
-      return false;
-    }
-
-    // If this starts failing, add extraValuesToPop to the if-statement and
-    // hash() method above.
-    MOZ_ASSERT(f1->extraValuesToPop == f2->extraValuesToPop);
-
-    MOZ_ASSERT(strcmp(f1->name_, f2->name_) == 0);
-    MOZ_ASSERT(f1->explicitArgs == f2->explicitArgs);
-    MOZ_ASSERT(f1->argumentProperties == f2->argumentProperties);
-    MOZ_ASSERT(f1->argumentPassedInFloatRegs == f2->argumentPassedInFloatRegs);
-    MOZ_ASSERT(f1->outParam == f2->outParam);
-    MOZ_ASSERT(f1->returnType == f2->returnType);
-    MOZ_ASSERT(f1->argumentRootTypes == f2->argumentRootTypes);
-    MOZ_ASSERT(f1->outParamRootType == f2->outParamRootType);
-    return true;
-  }
+  constexpr VMFunctionData(const VMFunctionData& o) = default;
 };
 
 template <class>
 struct TypeToDataType { /* Unexpected return type for a VMFunction. */
 };
 template <>
 struct TypeToDataType<void> {
   static const DataType result = Type_Void;
@@ -539,220 +459,222 @@ template <>
 struct TypeToDataType<HandleId> {
   static const DataType result = Type_Handle;
 };
 
 // Convert argument types to properties of the argument known by the jit.
 template <class T>
 struct TypeToArgProperties {
   static const uint32_t result =
-      (sizeof(T) <= sizeof(void*) ? VMFunction::Word : VMFunction::Double);
+      (sizeof(T) <= sizeof(void*) ? VMFunctionData::Word
+                                  : VMFunctionData::Double);
 };
 template <>
 struct TypeToArgProperties<const Value&> {
   static const uint32_t result =
-      TypeToArgProperties<Value>::result | VMFunction::ByRef;
+      TypeToArgProperties<Value>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<HandleObject> {
   static const uint32_t result =
-      TypeToArgProperties<JSObject*>::result | VMFunction::ByRef;
+      TypeToArgProperties<JSObject*>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<HandleString> {
   static const uint32_t result =
-      TypeToArgProperties<JSString*>::result | VMFunction::ByRef;
+      TypeToArgProperties<JSString*>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<HandlePropertyName> {
   static const uint32_t result =
-      TypeToArgProperties<PropertyName*>::result | VMFunction::ByRef;
+      TypeToArgProperties<PropertyName*>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<HandleFunction> {
   static const uint32_t result =
-      TypeToArgProperties<JSFunction*>::result | VMFunction::ByRef;
+      TypeToArgProperties<JSFunction*>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<Handle<NativeObject*> > {
   static const uint32_t result =
-      TypeToArgProperties<NativeObject*>::result | VMFunction::ByRef;
+      TypeToArgProperties<NativeObject*>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<Handle<InlineTypedObject*> > {
   static const uint32_t result =
-      TypeToArgProperties<InlineTypedObject*>::result | VMFunction::ByRef;
+      TypeToArgProperties<InlineTypedObject*>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<Handle<ArrayObject*> > {
   static const uint32_t result =
-      TypeToArgProperties<ArrayObject*>::result | VMFunction::ByRef;
+      TypeToArgProperties<ArrayObject*>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<Handle<AbstractGeneratorObject*> > {
   static const uint32_t result =
-      TypeToArgProperties<AbstractGeneratorObject*>::result | VMFunction::ByRef;
+      TypeToArgProperties<AbstractGeneratorObject*>::result |
+      VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<Handle<AsyncFunctionGeneratorObject*> > {
   static const uint32_t result =
       TypeToArgProperties<AsyncFunctionGeneratorObject*>::result |
-      VMFunction::ByRef;
+      VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<Handle<PlainObject*> > {
   static const uint32_t result =
-      TypeToArgProperties<PlainObject*>::result | VMFunction::ByRef;
+      TypeToArgProperties<PlainObject*>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<Handle<RegExpObject*> > {
   static const uint32_t result =
-      TypeToArgProperties<RegExpObject*>::result | VMFunction::ByRef;
+      TypeToArgProperties<RegExpObject*>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<Handle<WithScope*> > {
   static const uint32_t result =
-      TypeToArgProperties<WithScope*>::result | VMFunction::ByRef;
+      TypeToArgProperties<WithScope*>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<Handle<LexicalScope*> > {
   static const uint32_t result =
-      TypeToArgProperties<LexicalScope*>::result | VMFunction::ByRef;
+      TypeToArgProperties<LexicalScope*>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<Handle<Scope*> > {
   static const uint32_t result =
-      TypeToArgProperties<Scope*>::result | VMFunction::ByRef;
+      TypeToArgProperties<Scope*>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<HandleScript> {
   static const uint32_t result =
-      TypeToArgProperties<JSScript*>::result | VMFunction::ByRef;
+      TypeToArgProperties<JSScript*>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<HandleValue> {
   static const uint32_t result =
-      TypeToArgProperties<Value>::result | VMFunction::ByRef;
+      TypeToArgProperties<Value>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<MutableHandleValue> {
   static const uint32_t result =
-      TypeToArgProperties<Value>::result | VMFunction::ByRef;
+      TypeToArgProperties<Value>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<HandleId> {
   static const uint32_t result =
-      TypeToArgProperties<jsid>::result | VMFunction::ByRef;
+      TypeToArgProperties<jsid>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<HandleShape> {
   static const uint32_t result =
-      TypeToArgProperties<Shape*>::result | VMFunction::ByRef;
+      TypeToArgProperties<Shape*>::result | VMFunctionData::ByRef;
 };
 template <>
 struct TypeToArgProperties<HandleObjectGroup> {
   static const uint32_t result =
-      TypeToArgProperties<ObjectGroup*>::result | VMFunction::ByRef;
+      TypeToArgProperties<ObjectGroup*>::result | VMFunctionData::ByRef;
 };
 
 // Convert argument type to whether or not it should be passed in a float
 // register on platforms that have them, like x64.
 template <class T>
 struct TypeToPassInFloatReg {
   static const uint32_t result = 0;
 };
 template <>
 struct TypeToPassInFloatReg<double> {
   static const uint32_t result = 1;
 };
 
 // Convert argument types to root types used by the gc, see MarkJitExitFrame.
 template <class T>
 struct TypeToRootType {
-  static const uint32_t result = VMFunction::RootNone;
+  static const uint32_t result = VMFunctionData::RootNone;
 };
 template <>
 struct TypeToRootType<HandleObject> {
-  static const uint32_t result = VMFunction::RootObject;
+  static const uint32_t result = VMFunctionData::RootObject;
 };
 template <>
 struct TypeToRootType<HandleString> {
-  static const uint32_t result = VMFunction::RootString;
+  static const uint32_t result = VMFunctionData::RootString;
 };
 template <>
 struct TypeToRootType<HandlePropertyName> {
-  static const uint32_t result = VMFunction::RootString;
+  static const uint32_t result = VMFunctionData::RootString;
 };
 template <>
 struct TypeToRootType<HandleFunction> {
-  static const uint32_t result = VMFunction::RootFunction;
+  static const uint32_t result = VMFunctionData::RootFunction;
 };
 template <>
 struct TypeToRootType<HandleValue> {
-  static const uint32_t result = VMFunction::RootValue;
+  static const uint32_t result = VMFunctionData::RootValue;
 };
 template <>
 struct TypeToRootType<MutableHandleValue> {
-  static const uint32_t result = VMFunction::RootValue;
+  static const uint32_t result = VMFunctionData::RootValue;
 };
 template <>
 struct TypeToRootType<HandleId> {
-  static const uint32_t result = VMFunction::RootId;
+  static const uint32_t result = VMFunctionData::RootId;
 };
 template <>
 struct TypeToRootType<HandleShape> {
-  static const uint32_t result = VMFunction::RootCell;
+  static const uint32_t result = VMFunctionData::RootCell;
 };
 template <>
 struct TypeToRootType<HandleObjectGroup> {
-  static const uint32_t result = VMFunction::RootCell;
+  static const uint32_t result = VMFunctionData::RootCell;
 };
 template <>
 struct TypeToRootType<HandleScript> {
-  static const uint32_t result = VMFunction::RootCell;
+  static const uint32_t result = VMFunctionData::RootCell;
 };
 template <>
 struct TypeToRootType<Handle<NativeObject*> > {
-  static const uint32_t result = VMFunction::RootObject;
+  static const uint32_t result = VMFunctionData::RootObject;
 };
 template <>
 struct TypeToRootType<Handle<InlineTypedObject*> > {
-  static const uint32_t result = VMFunction::RootObject;
+  static const uint32_t result = VMFunctionData::RootObject;
 };
 template <>
 struct TypeToRootType<Handle<ArrayObject*> > {
-  static const uint32_t result = VMFunction::RootObject;
+  static const uint32_t result = VMFunctionData::RootObject;
 };
 template <>
 struct TypeToRootType<Handle<AbstractGeneratorObject*> > {
-  static const uint32_t result = VMFunction::RootObject;
+  static const uint32_t result = VMFunctionData::RootObject;
 };
 template <>
 struct TypeToRootType<Handle<AsyncFunctionGeneratorObject*> > {
-  static const uint32_t result = VMFunction::RootObject;
+  static const uint32_t result = VMFunctionData::RootObject;
 };
 template <>
 struct TypeToRootType<Handle<PlainObject*> > {
-  static const uint32_t result = VMFunction::RootObject;
+  static const uint32_t result = VMFunctionData::RootObject;
 };
 template <>
 struct TypeToRootType<Handle<RegExpObject*> > {
-  static const uint32_t result = VMFunction::RootObject;
+  static const uint32_t result = VMFunctionData::RootObject;
 };
 template <>
 struct TypeToRootType<Handle<LexicalScope*> > {
-  static const uint32_t result = VMFunction::RootCell;
+  static const uint32_t result = VMFunctionData::RootCell;
 };
 template <>
 struct TypeToRootType<Handle<WithScope*> > {
-  static const uint32_t result = VMFunction::RootCell;
+  static const uint32_t result = VMFunctionData::RootCell;
 };
 template <>
 struct TypeToRootType<Handle<Scope*> > {
-  static const uint32_t result = VMFunction::RootCell;
+  static const uint32_t result = VMFunctionData::RootCell;
 };
 template <class T>
 struct TypeToRootType<Handle<T> > {
   // Fail for Handle types that aren't specialized above.
 };
 
 template <class>
 struct OutParamToDataType {
@@ -792,29 +714,29 @@ struct OutParamToDataType<MutableHandleO
 };
 template <>
 struct OutParamToDataType<MutableHandleString> {
   static const DataType result = Type_Handle;
 };
 
 template <class>
 struct OutParamToRootType {
-  static const VMFunction::RootType result = VMFunction::RootNone;
+  static const VMFunctionData::RootType result = VMFunctionData::RootNone;
 };
 template <>
 struct OutParamToRootType<MutableHandleValue> {
-  static const VMFunction::RootType result = VMFunction::RootValue;
+  static const VMFunctionData::RootType result = VMFunctionData::RootValue;
 };
 template <>
 struct OutParamToRootType<MutableHandleObject> {
-  static const VMFunction::RootType result = VMFunction::RootObject;
+  static const VMFunctionData::RootType result = VMFunctionData::RootObject;
 };
 template <>
 struct OutParamToRootType<MutableHandleString> {
-  static const VMFunction::RootType result = VMFunction::RootString;
+  static const VMFunctionData::RootType result = VMFunctionData::RootString;
 };
 
 // Extract the last element of a list of types.
 template <typename... ArgTypes>
 struct LastArg;
 
 template <>
 struct LastArg<> {
@@ -857,62 +779,16 @@ struct BitMask<Each, ResultType, Shift, 
                     (8 * sizeof(ResultType) / Shift),
                 "not enough bits in the result type to store all bit masks");
 
   static constexpr ResultType result =
       ResultType(Each<HeadType>::result) |
       (BitMask<Each, ResultType, Shift, TailTypes...>::result << Shift);
 };
 
-// Extract VMFunction properties based on the signature of the function. The
-// properties are used to generate the logic for calling the VM function, and
-// also for marking the stack during GCs.
-template <typename... Args>
-struct FunctionInfo;
-
-template <class R, typename... Args>
-struct FunctionInfo<R (*)(JSContext*, Args...)> : public VMFunction {
-  using pf = R (*)(JSContext*, Args...);
-
-  static DataType returnType() { return TypeToDataType<R>::result; }
-  static DataType outParam() {
-    return OutParamToDataType<typename LastArg<Args...>::Type>::result;
-  }
-  static RootType outParamRootType() {
-    return OutParamToRootType<typename LastArg<Args...>::Type>::result;
-  }
-  static size_t NbArgs() { return LastArg<Args...>::nbArgs; }
-  static size_t explicitArgs() {
-    return NbArgs() - (outParam() != Type_Void ? 1 : 0);
-  }
-  static uint32_t argumentProperties() {
-    return BitMask<TypeToArgProperties, uint32_t, 2, Args...>::result;
-  }
-  static uint32_t argumentPassedInFloatRegs() {
-    return BitMask<TypeToPassInFloatReg, uint32_t, 2, Args...>::result;
-  }
-  static uint64_t argumentRootTypes() {
-    return BitMask<TypeToRootType, uint64_t, 3, Args...>::result;
-  }
-  explicit FunctionInfo(pf fun, const char* name,
-                        PopValues extraValuesToPop = PopValues(0))
-      : VMFunction(JS_FUNC_TO_DATA_PTR(void*, fun), name, explicitArgs(),
-                   argumentProperties(), argumentPassedInFloatRegs(),
-                   argumentRootTypes(), outParam(), outParamRootType(),
-                   returnType(), extraValuesToPop.numValues, NonTailCall) {
-  }
-  explicit FunctionInfo(pf fun, const char* name, MaybeTailCall expectTailCall,
-                        PopValues extraValuesToPop = PopValues(0))
-      : VMFunction(JS_FUNC_TO_DATA_PTR(void*, fun), name, explicitArgs(),
-                   argumentProperties(), argumentPassedInFloatRegs(),
-                   argumentRootTypes(), outParam(), outParamRootType(),
-                   returnType(), extraValuesToPop.numValues, expectTailCall) {
-  }
-};
-
 class AutoDetectInvalidation {
   JSContext* cx_;
   IonScript* ionScript_;
   MutableHandleValue rval_;
   bool disabled_;
 
   void setReturnOverride();
 
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -13,16 +13,17 @@
 #ifdef JS_ION_PERF
 #  include "jit/PerfSpewer.h"
 #endif
 #include "jit/VMFunctions.h"
 #include "vm/Realm.h"
 
 #include "jit/MacroAssembler-inl.h"
 #include "jit/SharedICHelpers-inl.h"
+#include "jit/VMFunctionList-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 static const FloatRegisterSet NonVolatileFloatRegs = FloatRegisterSet(
     (1ULL << FloatRegisters::d8) | (1ULL << FloatRegisters::d9) |
     (1ULL << FloatRegisters::d10) | (1ULL << FloatRegisters::d11) |
     (1ULL << FloatRegisters::d12) | (1ULL << FloatRegisters::d13) |
@@ -701,18 +702,16 @@ void JitRuntime::generateBailoutHandler(
   bailoutHandlerOffset_ = startTrampolineCode(masm);
 
   GenerateBailoutThunk(masm, NO_FRAME_SIZE_CLASS_ID, bailoutTail);
 }
 
 bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm,
                                    const VMFunctionData& f, void* nativeFun,
                                    uint32_t* wrapperOffset) {
-  MOZ_ASSERT(functionWrappers_);
-
   *wrapperOffset = startTrampolineCode(masm);
 
   AllocatableGeneralRegisterSet regs(Register::Codes::WrapperMask);
 
   static_assert(
       (Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0,
       "Wrapper register set must be a superset of Volatile register set.");
 
@@ -789,34 +788,34 @@ bool JitRuntime::generateVMWrapper(JSCon
   masm.setupUnalignedABICall(regs.getAny());
   masm.passABIArg(cxreg);
 
   size_t argDisp = 0;
 
   // Copy any arguments.
   for (uint32_t explicitArg = 0; explicitArg < f.explicitArgs; explicitArg++) {
     switch (f.argProperties(explicitArg)) {
-      case VMFunction::WordByValue:
+      case VMFunctionData::WordByValue:
         masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL);
         argDisp += sizeof(void*);
         break;
-      case VMFunction::DoubleByValue:
+      case VMFunctionData::DoubleByValue:
         // Values should be passed by reference, not by value, so we assert
         // that the argument is a double-precision float.
         MOZ_ASSERT(f.argPassedInFloatReg(explicitArg));
         masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::DOUBLE);
         argDisp += sizeof(double);
         break;
-      case VMFunction::WordByRef:
+      case VMFunctionData::WordByRef:
         masm.passABIArg(
             MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS),
             MoveOp::GENERAL);
         argDisp += sizeof(void*);
         break;
-      case VMFunction::DoubleByRef:
+      case VMFunctionData::DoubleByRef:
         masm.passABIArg(
             MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS),
             MoveOp::GENERAL);
         argDisp += 2 * sizeof(void*);
         break;
     }
   }
 
@@ -944,38 +943,36 @@ uint32_t JitRuntime::generatePreBarrier(
   masm.pop(temp3);
   masm.pop(temp2);
   masm.pop(temp1);
   masm.ret();
 
   return offset;
 }
 
-typedef bool (*HandleDebugTrapFn)(JSContext*, BaselineFrame*, uint8_t*, bool*);
-static const VMFunction HandleDebugTrapInfo =
-    FunctionInfo<HandleDebugTrapFn>(HandleDebugTrap, "HandleDebugTrap");
-
 JitCode* JitRuntime::generateDebugTrapHandler(JSContext* cx) {
   StackMacroAssembler masm;
 
   Register scratch1 = r0;
   Register scratch2 = r1;
 
   // Load BaselineFrame pointer in scratch1.
   masm.mov(r11, scratch1);
   masm.subPtr(Imm32(BaselineFrame::Size()), scratch1);
 
   // Enter a stub frame and call the HandleDebugTrap VM function. Ensure the
   // stub frame has a nullptr ICStub pointer, since this pointer is marked
   // during GC.
   masm.movePtr(ImmPtr(nullptr), ICStubReg);
   EmitBaselineEnterStubFrame(masm, scratch2);
 
-  TrampolinePtr code =
-      cx->runtime()->jitRuntime()->getVMWrapper(HandleDebugTrapInfo);
+  using Fn = bool (*)(JSContext*, BaselineFrame*, uint8_t*, bool*);
+  VMFunctionId id = VMFunctionToId<Fn, jit::HandleDebugTrap>::id;
+  TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(id);
+
   masm.push(lr);
   masm.push(scratch1);
   EmitBaselineCallVM(code, masm);
 
   EmitBaselineLeaveStubFrame(masm);
 
   // If the stub returns |true|, we have to perform a forced return (return
   // from the JS frame). If the stub returns |false|, just return from the
--- a/js/src/jit/arm64/Trampoline-arm64.cpp
+++ b/js/src/jit/arm64/Trampoline-arm64.cpp
@@ -11,16 +11,17 @@
 #ifdef JS_ION_PERF
 #  include "jit/PerfSpewer.h"
 #endif
 #include "jit/arm64/SharedICHelpers-arm64.h"
 #include "jit/VMFunctions.h"
 
 #include "jit/MacroAssembler-inl.h"
 #include "jit/SharedICHelpers-inl.h"
+#include "jit/VMFunctionList-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 /* This method generates a trampoline on ARM64 for a c++ function with
  * the following signature:
  *   bool blah(void* code, int argc, Value* argv,
  *             JSObject* scopeChain, Value* vp)
@@ -530,18 +531,16 @@ void JitRuntime::generateBailoutHandler(
   bailoutHandlerOffset_ = startTrampolineCode(masm);
 
   GenerateBailoutThunk(masm, bailoutTail);
 }
 
 bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm,
                                    const VMFunctionData& f, void* nativeFun,
                                    uint32_t* wrapperOffset) {
-  MOZ_ASSERT(functionWrappers_);
-
   *wrapperOffset = startTrampolineCode(masm);
 
   // Avoid conflicts with argument registers while discarding the result after
   // the function call.
   AllocatableGeneralRegisterSet regs(Register::Codes::WrapperMask);
 
   static_assert(
       (Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0,
@@ -624,32 +623,32 @@ bool JitRuntime::generateVMWrapper(JSCon
   masm.setupUnalignedABICall(regs.getAny());
   masm.passABIArg(reg_cx);
 
   size_t argDisp = 0;
 
   // Copy arguments.
   for (uint32_t explicitArg = 0; explicitArg < f.explicitArgs; explicitArg++) {
     switch (f.argProperties(explicitArg)) {
-      case VMFunction::WordByValue:
+      case VMFunctionData::WordByValue:
         masm.passABIArg(MoveOperand(argsBase, argDisp),
                         (f.argPassedInFloatReg(explicitArg) ? MoveOp::DOUBLE
                                                             : MoveOp::GENERAL));
         argDisp += sizeof(void*);
         break;
 
-      case VMFunction::WordByRef:
+      case VMFunctionData::WordByRef:
         masm.passABIArg(
             MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS),
             MoveOp::GENERAL);
         argDisp += sizeof(void*);
         break;
 
-      case VMFunction::DoubleByValue:
-      case VMFunction::DoubleByRef:
+      case VMFunctionData::DoubleByValue:
+      case VMFunctionData::DoubleByRef:
         MOZ_CRASH("NYI: AArch64 callVM should not be used with 128bit values.");
     }
   }
 
   // Copy the semi-implicit outparam, if any.
   // It is not a C++-abi outparam, which would get passed in the
   // outparam register, but a real parameter to the function, which
   // was stack-allocated above.
@@ -782,20 +781,16 @@ uint32_t JitRuntime::generatePreBarrier(
   masm.pop(temp3);
   masm.pop(temp2);
   masm.pop(temp1);
   masm.abiret();
 
   return offset;
 }
 
-typedef bool (*HandleDebugTrapFn)(JSContext*, BaselineFrame*, uint8_t*, bool*);
-static const VMFunction HandleDebugTrapInfo =
-    FunctionInfo<HandleDebugTrapFn>(HandleDebugTrap, "HandleDebugTrap");
-
 JitCode* JitRuntime::generateDebugTrapHandler(JSContext* cx) {
   StackMacroAssembler masm(cx);
 #ifndef JS_USE_LINK_REGISTER
   // The first value contains the return addres,
   // which we pull into ICTailCallReg for tail calls.
   masm.setFramePushed(sizeof(intptr_t));
 #endif
 
@@ -807,18 +802,20 @@ JitCode* JitRuntime::generateDebugTrapHa
            Operand(BaselineFrame::Size()));
 
   // Enter a stub frame and call the HandleDebugTrap VM function. Ensure the
   // stub frame has a nullptr ICStub pointer, since this pointer is marked
   // during GC.
   masm.movePtr(ImmPtr(nullptr), ICStubReg);
   EmitBaselineEnterStubFrame(masm, scratch2);
 
-  TrampolinePtr code =
-      cx->runtime()->jitRuntime()->getVMWrapper(HandleDebugTrapInfo);
+  using Fn = bool (*)(JSContext*, BaselineFrame*, uint8_t*, bool*);
+  VMFunctionId id = VMFunctionToId<Fn, jit::HandleDebugTrap>::id;
+  TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(id);
+
   masm.asVIXL().Push(vixl::lr, ARMRegister(scratch1, 64));
   EmitBaselineCallVM(code, masm);
 
   EmitBaselineLeaveStubFrame(masm);
 
   // If the stub returns |true|, we have to perform a forced return (return
   // from the JS frame). If the stub returns |false|, just return from the
   // trap stub so that execution continues at the current pc.
--- a/js/src/jit/x64/Trampoline-x64.cpp
+++ b/js/src/jit/x64/Trampoline-x64.cpp
@@ -12,16 +12,17 @@
 #  include "jit/PerfSpewer.h"
 #endif
 #include "jit/VMFunctions.h"
 #include "jit/x64/SharedICHelpers-x64.h"
 #include "vtune/VTuneWrapper.h"
 
 #include "jit/MacroAssembler-inl.h"
 #include "jit/SharedICHelpers-inl.h"
+#include "jit/VMFunctionList-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::IsPowerOfTwo;
 
 // All registers to save and restore. This includes the stack pointer, since we
 // use the ability to reference register values on the stack by index.
@@ -588,18 +589,16 @@ void JitRuntime::generateBailoutHandler(
   bailoutHandlerOffset_ = startTrampolineCode(masm);
 
   GenerateBailoutThunk(masm, NO_FRAME_SIZE_CLASS_ID, bailoutTail);
 }
 
 bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm,
                                    const VMFunctionData& f, void* nativeFun,
                                    uint32_t* wrapperOffset) {
-  MOZ_ASSERT(functionWrappers_);
-
   *wrapperOffset = startTrampolineCode(masm);
 
   // Avoid conflicts with argument registers while discarding the result after
   // the function call.
   AllocatableGeneralRegisterSet regs(Register::Codes::WrapperMask);
 
   static_assert(
       (Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0,
@@ -673,32 +672,32 @@ bool JitRuntime::generateVMWrapper(JSCon
   masm.setupUnalignedABICall(regs.getAny());
   masm.passABIArg(cxreg);
 
   size_t argDisp = 0;
 
   // Copy arguments.
   for (uint32_t explicitArg = 0; explicitArg < f.explicitArgs; explicitArg++) {
     switch (f.argProperties(explicitArg)) {
-      case VMFunction::WordByValue:
+      case VMFunctionData::WordByValue:
         if (f.argPassedInFloatReg(explicitArg)) {
           masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::DOUBLE);
         } else {
           masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL);
         }
         argDisp += sizeof(void*);
         break;
-      case VMFunction::WordByRef:
+      case VMFunctionData::WordByRef:
         masm.passABIArg(
             MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS),
             MoveOp::GENERAL);
         argDisp += sizeof(void*);
         break;
-      case VMFunction::DoubleByValue:
-      case VMFunction::DoubleByRef:
+      case VMFunctionData::DoubleByValue:
+      case VMFunctionData::DoubleByRef:
         MOZ_CRASH("NYI: x64 callVM should not be used with 128bits values.");
     }
   }
 
   // Copy the implicit outparam, if any.
   if (outReg != InvalidReg) {
     masm.passABIArg(outReg);
   }
@@ -816,20 +815,16 @@ uint32_t JitRuntime::generatePreBarrier(
   masm.pop(temp3);
   masm.pop(temp2);
   masm.pop(temp1);
   masm.ret();
 
   return offset;
 }
 
-typedef bool (*HandleDebugTrapFn)(JSContext*, BaselineFrame*, uint8_t*, bool*);
-static const VMFunction HandleDebugTrapInfo =
-    FunctionInfo<HandleDebugTrapFn>(HandleDebugTrap, "HandleDebugTrap");
-
 JitCode* JitRuntime::generateDebugTrapHandler(JSContext* cx) {
   StackMacroAssembler masm;
 #ifndef JS_USE_LINK_REGISTER
   // The first value contains the return addres,
   // which we pull into ICTailCallReg for tail calls.
   masm.setFramePushed(sizeof(intptr_t));
 #endif
 
@@ -845,18 +840,20 @@ JitCode* JitRuntime::generateDebugTrapHa
   masm.subPtr(Imm32(BaselineFrame::Size()), scratch2);
 
   // Enter a stub frame and call the HandleDebugTrap VM function. Ensure
   // the stub frame has a nullptr ICStub pointer, since this pointer is marked
   // during GC.
   masm.movePtr(ImmPtr(nullptr), ICStubReg);
   EmitBaselineEnterStubFrame(masm, scratch3);
 
-  TrampolinePtr code =
-      cx->runtime()->jitRuntime()->getVMWrapper(HandleDebugTrapInfo);
+  using Fn = bool (*)(JSContext*, BaselineFrame*, uint8_t*, bool*);
+  VMFunctionId id = VMFunctionToId<Fn, jit::HandleDebugTrap>::id;
+  TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(id);
+
   masm.push(scratch1);
   masm.push(scratch2);
   EmitBaselineCallVM(code, masm);
 
   EmitBaselineLeaveStubFrame(masm);
 
   // If the stub returns |true|, we have to perform a forced return
   // (return from the JS frame). If the stub returns |false|, just return
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -17,16 +17,17 @@
 #endif
 #include "jit/VMFunctions.h"
 #include "jit/x86/SharedICHelpers-x86.h"
 #include "vm/Realm.h"
 #include "vtune/VTuneWrapper.h"
 
 #include "jit/MacroAssembler-inl.h"
 #include "jit/SharedICHelpers-inl.h"
+#include "jit/VMFunctionList-inl.h"
 #include "vm/JSScript-inl.h"
 
 using mozilla::IsPowerOfTwo;
 
 using namespace js;
 using namespace js::jit;
 
 // All registers to save and restore. This includes the stack pointer, since we
@@ -605,18 +606,16 @@ void JitRuntime::generateBailoutHandler(
   bailoutHandlerOffset_ = startTrampolineCode(masm);
 
   GenerateBailoutThunk(masm, NO_FRAME_SIZE_CLASS_ID, bailoutTail);
 }
 
 bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm,
                                    const VMFunctionData& f, void* nativeFun,
                                    uint32_t* wrapperOffset) {
-  MOZ_ASSERT(functionWrappers_);
-
   *wrapperOffset = startTrampolineCode(masm);
 
   // Avoid conflicts with argument registers while discarding the result after
   // the function call.
   AllocatableGeneralRegisterSet regs(Register::Codes::WrapperMask);
 
   static_assert(
       (Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0,
@@ -683,35 +682,35 @@ bool JitRuntime::generateVMWrapper(JSCon
   masm.setupUnalignedABICall(regs.getAny());
   masm.passABIArg(cxreg);
 
   size_t argDisp = 0;
 
   // Copy arguments.
   for (uint32_t explicitArg = 0; explicitArg < f.explicitArgs; explicitArg++) {
     switch (f.argProperties(explicitArg)) {
-      case VMFunction::WordByValue:
+      case VMFunctionData::WordByValue:
         masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL);
         argDisp += sizeof(void*);
         break;
-      case VMFunction::DoubleByValue:
+      case VMFunctionData::DoubleByValue:
         // We don't pass doubles in float registers on x86, so no need
         // to check for argPassedInFloatReg.
         masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL);
         argDisp += sizeof(void*);
         masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL);
         argDisp += sizeof(void*);
         break;
-      case VMFunction::WordByRef:
+      case VMFunctionData::WordByRef:
         masm.passABIArg(
             MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS),
             MoveOp::GENERAL);
         argDisp += sizeof(void*);
         break;
-      case VMFunction::DoubleByRef:
+      case VMFunctionData::DoubleByRef:
         masm.passABIArg(
             MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS),
             MoveOp::GENERAL);
         argDisp += 2 * sizeof(void*);
         break;
     }
   }
 
@@ -835,20 +834,16 @@ uint32_t JitRuntime::generatePreBarrier(
   masm.pop(temp3);
   masm.pop(temp2);
   masm.pop(temp1);
   masm.ret();
 
   return offset;
 }
 
-typedef bool (*HandleDebugTrapFn)(JSContext*, BaselineFrame*, uint8_t*, bool*);
-static const VMFunction HandleDebugTrapInfo =
-    FunctionInfo<HandleDebugTrapFn>(HandleDebugTrap, "HandleDebugTrap");
-
 JitCode* JitRuntime::generateDebugTrapHandler(JSContext* cx) {
   StackMacroAssembler masm;
 #ifndef JS_USE_LINK_REGISTER
   // The first value contains the return addres,
   // which we pull into ICTailCallReg for tail calls.
   masm.setFramePushed(sizeof(intptr_t));
 #endif
 
@@ -864,18 +859,20 @@ JitCode* JitRuntime::generateDebugTrapHa
   masm.subPtr(Imm32(BaselineFrame::Size()), scratch2);
 
   // Enter a stub frame and call the HandleDebugTrap VM function. Ensure
   // the stub frame has a nullptr ICStub pointer, since this pointer is
   // marked during GC.
   masm.movePtr(ImmPtr(nullptr), ICStubReg);
   EmitBaselineEnterStubFrame(masm, scratch3);
 
-  TrampolinePtr code =
-      cx->runtime()->jitRuntime()->getVMWrapper(HandleDebugTrapInfo);
+  using Fn = bool (*)(JSContext*, BaselineFrame*, uint8_t*, bool*);
+  VMFunctionId id = VMFunctionToId<Fn, jit::HandleDebugTrap>::id;
+  TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(id);
+
   masm.push(scratch1);
   masm.push(scratch2);
   EmitBaselineCallVM(code, masm);
 
   EmitBaselineLeaveStubFrame(masm);
 
   // If the stub returns |true|, we have to perform a forced return
   // (return from the JS frame). If the stub returns |false|, just return