Bug 1416592 - Deduplicate VMFunction wrapper code. r=nbp
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 15 Nov 2017 09:50:27 +0100
changeset 391961 3aa5eb7e2ed90b56d28f2618ed1339da085028b2
parent 391960 7613f8e20ad525e183b9e5a237cb5725fbe3f630
child 391962 365135d6f7cc33d21fe75518be52331c348b3138
push id32909
push usercbrindusan@mozilla.com
push dateWed, 15 Nov 2017 22:25:14 +0000
treeherdermozilla-central@f41930a869a8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs1416592
milestone59.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 1416592 - Deduplicate VMFunction wrapper code. r=nbp
js/src/jit/CodeGenerator.cpp
js/src/jit/Ion.cpp
js/src/jit/JitCompartment.h
js/src/jit/VMFunctions.h
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -6303,17 +6303,17 @@ CodeGenerator::visitInitElem(LInitElem* 
     pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
 
     callVM(InitElemInfo, lir);
 }
 
 typedef bool (*InitElemGetterSetterFn)(JSContext*, jsbytecode*, HandleObject, HandleValue,
                                        HandleObject);
 static const VMFunction InitElemGetterSetterInfo =
-    FunctionInfo<InitElemGetterSetterFn>(InitGetterSetterOperation, "InitGetterSetterOperation");
+    FunctionInfo<InitElemGetterSetterFn>(InitGetterSetterOperation, "InitElemGetterSetterOperation");
 
 void
 CodeGenerator::visitInitElemGetterSetter(LInitElemGetterSetter* lir)
 {
     Register obj = ToRegister(lir->object());
     Register value = ToRegister(lir->value());
 
     pushArg(value);
@@ -6337,17 +6337,17 @@ CodeGenerator::visitMutateProto(LMutateP
     pushArg(objReg);
 
     callVM(MutatePrototypeInfo, lir);
 }
 
 typedef bool(*InitPropGetterSetterFn)(JSContext*, jsbytecode*, HandleObject, HandlePropertyName,
                                       HandleObject);
 static const VMFunction InitPropGetterSetterInfo =
-    FunctionInfo<InitPropGetterSetterFn>(InitGetterSetterOperation, "InitGetterSetterOperation");
+    FunctionInfo<InitPropGetterSetterFn>(InitGetterSetterOperation, "InitPropGetterSetterOperation");
 
 void
 CodeGenerator::visitInitPropGetterSetter(LInitPropGetterSetter* lir)
 {
     Register obj = ToRegister(lir->object());
     Register value = ToRegister(lir->value());
 
     pushArg(value);
@@ -10394,37 +10394,37 @@ CodeGenerator::visitCallSetProperty(LCal
     pushArg(ImmGCPtr(ins->mir()->name()));
     pushArg(objReg);
 
     callVM(SetPropertyInfo, ins);
 }
 
 typedef bool (*DeletePropertyFn)(JSContext*, HandleValue, HandlePropertyName, bool*);
 static const VMFunction DeletePropertyStrictInfo =
-    FunctionInfo<DeletePropertyFn>(DeletePropertyJit<true>, "DeletePropertyStrictJit");
+    FunctionInfo<DeletePropertyFn>(DeletePropertyJit<true>, "DeletePropertyStrict");
 static const VMFunction DeletePropertyNonStrictInfo =
-    FunctionInfo<DeletePropertyFn>(DeletePropertyJit<false>, "DeletePropertyNonStrictJit");
+    FunctionInfo<DeletePropertyFn>(DeletePropertyJit<false>, "DeletePropertyNonStrict");
 
 void
 CodeGenerator::visitCallDeleteProperty(LCallDeleteProperty* lir)
 {
     pushArg(ImmGCPtr(lir->mir()->name()));
     pushArg(ToValue(lir, LCallDeleteProperty::Value));
 
     if (lir->mir()->strict())
         callVM(DeletePropertyStrictInfo, lir);
     else
         callVM(DeletePropertyNonStrictInfo, lir);
 }
 
 typedef bool (*DeleteElementFn)(JSContext*, HandleValue, HandleValue, bool*);
 static const VMFunction DeleteElementStrictInfo =
-    FunctionInfo<DeleteElementFn>(DeleteElementJit<true>, "DeleteElementStrictJit");
+    FunctionInfo<DeleteElementFn>(DeleteElementJit<true>, "DeleteElementStrict");
 static const VMFunction DeleteElementNonStrictInfo =
-    FunctionInfo<DeleteElementFn>(DeleteElementJit<false>, "DeleteElementNonStrictJit");
+    FunctionInfo<DeleteElementFn>(DeleteElementJit<false>, "DeleteElementNonStrict");
 
 void
 CodeGenerator::visitCallDeleteElement(LCallDeleteElement* lir)
 {
     pushArg(ToValue(lir, LCallDeleteElement::Index));
     pushArg(ToValue(lir, LCallDeleteElement::Value));
 
     if (lir->mir()->strict())
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -335,16 +335,20 @@ JitRuntime::initialize(JSContext* cx, Au
     freeStub_ = generateFreeStub(cx);
     if (!freeStub_)
         return false;
 
     {
         JitSpew(JitSpew_Codegen, "# Emitting VM function wrappers");
         MacroAssembler masm;
         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");
             if (!generateVMWrapper(cx, masm, *fun))
                 return false;
         }
 
         Linker linker(masm);
         AutoFlushICache afc("VMWrappers");
         functionWrapperCode_ = linker.newCode<NoGC>(cx, OTHER_CODE);
--- a/js/src/jit/JitCompartment.h
+++ b/js/src/jit/JitCompartment.h
@@ -135,17 +135,17 @@ class JitRuntime
     ExclusiveAccessLockWriteOnceData<JitCode*> baselineDebugModeOSRHandler_;
     ExclusiveAccessLockWriteOnceData<void*> baselineDebugModeOSRHandlerNoFrameRegPopAddr_;
 
     // Code for all VMFunction wrappers.
     ExclusiveAccessLockWriteOnceData<JitCode*> functionWrapperCode_;
 
     // Map VMFunction addresses to the offset of the wrapper in
     // functionWrapperCode_.
-    using VMWrapperMap = HashMap<const VMFunction*, uint32_t>;
+    using VMWrapperMap = HashMap<const VMFunction*, uint32_t, VMFunction>;
     ExclusiveAccessLockWriteOnceData<VMWrapperMap*> functionWrappers_;
 
     // If true, the signal handler to interrupt Ion code should not attempt to
     // patch backedges, as some thread is busy modifying data structures.
     mozilla::Atomic<bool> preventBackedgePatching_;
 
     // Global table of jitcode native address => bytecode address mappings.
     UnprotectedData<JitcodeGlobalTable*> jitcodeGlobalTable_;
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -3,16 +3,17 @@
  * 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/. */
 
 #ifndef jit_VMFunctions_h
 #define jit_VMFunctions_h
 
 #include "mozilla/Attributes.h"
+#include "mozilla/HashFunctions.h"
 
 #include "jspubtd.h"
 
 #include "jit/CompileInfo.h"
 #include "jit/JitFrames.h"
 #include "vm/Interpreter.h"
 
 namespace js {
@@ -266,16 +267,48 @@ struct VMFunction
                       returnType == Type_Void ||
                       returnType == Type_Bool);
         MOZ_ASSERT(returnType == Type_Void ||
                    returnType == Type_Bool ||
                    returnType == Type_Object);
         addToFunctions();
     }
 
+    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;
+    }
+
   private:
     // Add this to the global list of VMFunctions.
     void addToFunctions();
 };
 
 template <class> struct TypeToDataType { /* Unexpected return type for a VMFunction. */ };
 template <> struct TypeToDataType<void> { static const DataType result = Type_Void; };
 template <> struct TypeToDataType<bool> { static const DataType result = Type_Bool; };