Title: [199946] trunk
Revision
199946
Author
fpi...@apple.com
Date
2016-04-22 19:00:38 -0700 (Fri, 22 Apr 2016)

Log Message

Speed up bound functions a bit
https://bugs.webkit.org/show_bug.cgi?id=156889

Reviewed by Saam Barati.
Source/_javascript_Core:

        
Bound functions are hard to optimize because JSC doesn't have a good notion of non-JS code
that does JS-ey things like make JS calls. What I mean by "non-JS code" is code that did not
originate from JS source. A bound function does a highly polymorphic call to the target
stored in the JSBoundFunction. Prior to this change, we represented it as native code that
used the generic native->JS call API. That's not cheap.
        
We could model bound functions using a builtin, but it's not clear that this would be easy
to grok, since so much of the code would have to access special parts of the JSBoundFunction
type. Doing it that way might solve the performance problems but it would mean extra work to
arrange for the builtin to have speedy access to the call target, the bound this, and the
bound arguments. Also, optimizing bound functions that way would mean that bound function
performance would be gated on the performance of a bunch of other things in our system. For
example, we'd want this polymorphic call to be handled like the funnel that it is: if we're
compiling the bound function's outgoing call with no context then we should compile it as
fully polymorphic but we can let it assume basic sanity like that the callee is a real
function; but if we're compiling the call with any amount of calling context then we want to
use normal call IC's.
        
Since the builtin path wouldn't lead to a simpler patch and since I think that the VM will
benefit in the long run from using custom handling for bound functions, I kept the native
code and just added Intrinsic/thunk support.
        
This just adds an Intrinsic for bound function calls where the JSBoundFunction targets a
JSFunction instance and has no bound arguments (only bound this). This intrinsic is
currently only implemented as a thunk and not yet recognized by the DFG bytecode parser.

I needed to loosen some restrictions to do this. For one, I was really tired of our bad use
of ENABLE(JIT) conditionals, which made it so that any serious client of Intrinsics would
have to have #ifdefs. Really what should happen is that if the JIT is not enabled then we
just ignore intrinsics. Also, the code was previously assuming that having a native
constructor and knowing the Intrinsic for your native call were mutually exclusive. This
change makes it possible to have a native executable that has a custom function, custom
constructor, and an Intrinsic.
        
This is a >4x speed-up on bound function calls with no bound arguments.

In the future, we should teach the DFG Intrinsic handling to deal with bound functions and
we should teach the inliner (and ByteCodeParser::handleCall() in general) how to deal with
the function call inside the bound function. That would be super awesome.

* assembler/AbstractMacroAssembler.h:
(JSC::AbstractMacroAssembler::timesPtr):
(JSC::AbstractMacroAssembler::Address::withOffset):
(JSC::AbstractMacroAssembler::BaseIndex::BaseIndex):
(JSC::MacroAssemblerType>::Address::indexedBy):
* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::storeCell):
(JSC::AssemblyHelpers::loadCell):
(JSC::AssemblyHelpers::storeValue):
(JSC::AssemblyHelpers::emitSaveCalleeSaves):
(JSC::AssemblyHelpers::emitSaveThenMaterializeTagRegisters):
(JSC::AssemblyHelpers::emitRestoreCalleeSaves):
(JSC::AssemblyHelpers::emitRestoreSavedTagRegisters):
(JSC::AssemblyHelpers::copyCalleeSavesToVMCalleeSavesBuffer):
* jit/JITThunks.cpp:
(JSC::JITThunks::ctiNativeTailCall):
(JSC::JITThunks::ctiNativeTailCallWithoutSavedTags):
(JSC::JITThunks::ctiStub):
(JSC::JITThunks::hostFunctionStub):
(JSC::JITThunks::clearHostFunctionStubs):
* jit/JITThunks.h:
* jit/SpecializedThunkJIT.h:
(JSC::SpecializedThunkJIT::callDoubleToDoublePreservingReturn):
(JSC::SpecializedThunkJIT::tagReturnAsInt32):
(JSC::SpecializedThunkJIT::emitSaveThenMaterializeTagRegisters): Deleted.
(JSC::SpecializedThunkJIT::emitRestoreSavedTagRegisters): Deleted.
* jit/ThunkGenerators.cpp:
(JSC::virtualThunkFor):
(JSC::nativeForGenerator):
(JSC::nativeCallGenerator):
(JSC::nativeTailCallGenerator):
(JSC::nativeTailCallWithoutSavedTagsGenerator):
(JSC::nativeConstructGenerator):
(JSC::randomThunkGenerator):
(JSC::boundThisNoArgsFunctionCallGenerator):
* jit/ThunkGenerators.h:
* runtime/Executable.cpp:
(JSC::NativeExecutable::create):
(JSC::NativeExecutable::destroy):
(JSC::NativeExecutable::createStructure):
(JSC::NativeExecutable::finishCreation):
(JSC::NativeExecutable::NativeExecutable):
(JSC::ScriptExecutable::ScriptExecutable):
* runtime/Executable.h:
* runtime/FunctionPrototype.cpp:
(JSC::functionProtoFuncBind):
* runtime/IntlCollatorPrototype.cpp:
(JSC::IntlCollatorPrototypeGetterCompare):
* runtime/Intrinsic.h:
* runtime/JSBoundFunction.cpp:
(JSC::boundThisNoArgsFunctionCall):
(JSC::boundFunctionCall):
(JSC::boundThisNoArgsFunctionConstruct):
(JSC::boundFunctionConstruct):
(JSC::getBoundFunctionStructure):
(JSC::JSBoundFunction::create):
(JSC::JSBoundFunction::customHasInstance):
(JSC::JSBoundFunction::JSBoundFunction):
* runtime/JSBoundFunction.h:
(JSC::JSBoundFunction::targetFunction):
(JSC::JSBoundFunction::boundThis):
(JSC::JSBoundFunction::boundArgs):
(JSC::JSBoundFunction::createStructure):
(JSC::JSBoundFunction::offsetOfTargetFunction):
(JSC::JSBoundFunction::offsetOfBoundThis):
* runtime/JSFunction.cpp:
(JSC::JSFunction::lookUpOrCreateNativeExecutable):
(JSC::JSFunction::create):
* runtime/VM.cpp:
(JSC::thunkGeneratorForIntrinsic):
(JSC::VM::getHostFunction):
* runtime/VM.h:
(JSC::VM::getCTIStub):
(JSC::VM::exceptionOffset):

LayoutTests:


This microbenchmark speeds up by >4x with this change.

* js/regress/bound-function-call-expected.txt: Added.
* js/regress/bound-function-call.html: Added.
* js/regress/script-tests/bound-function-call.js: Added.
(foo):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (199945 => 199946)


--- trunk/LayoutTests/ChangeLog	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/LayoutTests/ChangeLog	2016-04-23 02:00:38 UTC (rev 199946)
@@ -1,3 +1,17 @@
+2016-04-22  Filip Pizlo  <fpi...@apple.com>
+
+        Speed up bound functions a bit
+        https://bugs.webkit.org/show_bug.cgi?id=156889
+
+        Reviewed by Saam Barati.
+
+        This microbenchmark speeds up by >4x with this change.
+
+        * js/regress/bound-function-call-expected.txt: Added.
+        * js/regress/bound-function-call.html: Added.
+        * js/regress/script-tests/bound-function-call.js: Added.
+        (foo):
+
 2016-04-22  Chris Dumez  <cdu...@apple.com>
 
         Cannot access the SQLTransaction.constructor.prototype

Added: trunk/LayoutTests/js/regress/bound-function-call-expected.txt (0 => 199946)


--- trunk/LayoutTests/js/regress/bound-function-call-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/bound-function-call-expected.txt	2016-04-23 02:00:38 UTC (rev 199946)
@@ -0,0 +1,10 @@
+JSRegress/bound-function-call
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/bound-function-call.html (0 => 199946)


--- trunk/LayoutTests/js/regress/bound-function-call.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/bound-function-call.html	2016-04-23 02:00:38 UTC (rev 199946)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/regress/script-tests/bound-function-call.js (0 => 199946)


--- trunk/LayoutTests/js/regress/script-tests/bound-function-call.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/bound-function-call.js	2016-04-23 02:00:38 UTC (rev 199946)
@@ -0,0 +1,16 @@
+function foo() {
+    return this.f;
+}
+
+var binding = foo.bind({f:42});
+
+(function() {
+    var n = 1000000;
+    var result = 0;
+    for (var i = 0; i < n; ++i) {
+        var myResult = binding();
+        result += myResult;
+    }
+    if (result != n * 42)
+        throw "Error: bad result: " + result;
+})();

Modified: trunk/Source/_javascript_Core/ChangeLog (199945 => 199946)


--- trunk/Source/_javascript_Core/ChangeLog	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-04-23 02:00:38 UTC (rev 199946)
@@ -1,3 +1,125 @@
+2016-04-22  Filip Pizlo  <fpi...@apple.com>
+
+        Speed up bound functions a bit
+        https://bugs.webkit.org/show_bug.cgi?id=156889
+
+        Reviewed by Saam Barati.
+        
+        Bound functions are hard to optimize because JSC doesn't have a good notion of non-JS code
+        that does JS-ey things like make JS calls. What I mean by "non-JS code" is code that did not
+        originate from JS source. A bound function does a highly polymorphic call to the target
+        stored in the JSBoundFunction. Prior to this change, we represented it as native code that
+        used the generic native->JS call API. That's not cheap.
+        
+        We could model bound functions using a builtin, but it's not clear that this would be easy
+        to grok, since so much of the code would have to access special parts of the JSBoundFunction
+        type. Doing it that way might solve the performance problems but it would mean extra work to
+        arrange for the builtin to have speedy access to the call target, the bound this, and the
+        bound arguments. Also, optimizing bound functions that way would mean that bound function
+        performance would be gated on the performance of a bunch of other things in our system. For
+        example, we'd want this polymorphic call to be handled like the funnel that it is: if we're
+        compiling the bound function's outgoing call with no context then we should compile it as
+        fully polymorphic but we can let it assume basic sanity like that the callee is a real
+        function; but if we're compiling the call with any amount of calling context then we want to
+        use normal call IC's.
+        
+        Since the builtin path wouldn't lead to a simpler patch and since I think that the VM will
+        benefit in the long run from using custom handling for bound functions, I kept the native
+        code and just added Intrinsic/thunk support.
+        
+        This just adds an Intrinsic for bound function calls where the JSBoundFunction targets a
+        JSFunction instance and has no bound arguments (only bound this). This intrinsic is
+        currently only implemented as a thunk and not yet recognized by the DFG bytecode parser.
+
+        I needed to loosen some restrictions to do this. For one, I was really tired of our bad use
+        of ENABLE(JIT) conditionals, which made it so that any serious client of Intrinsics would
+        have to have #ifdefs. Really what should happen is that if the JIT is not enabled then we
+        just ignore intrinsics. Also, the code was previously assuming that having a native
+        constructor and knowing the Intrinsic for your native call were mutually exclusive. This
+        change makes it possible to have a native executable that has a custom function, custom
+        constructor, and an Intrinsic.
+        
+        This is a >4x speed-up on bound function calls with no bound arguments.
+
+        In the future, we should teach the DFG Intrinsic handling to deal with bound functions and
+        we should teach the inliner (and ByteCodeParser::handleCall() in general) how to deal with
+        the function call inside the bound function. That would be super awesome.
+
+        * assembler/AbstractMacroAssembler.h:
+        (JSC::AbstractMacroAssembler::timesPtr):
+        (JSC::AbstractMacroAssembler::Address::withOffset):
+        (JSC::AbstractMacroAssembler::BaseIndex::BaseIndex):
+        (JSC::MacroAssemblerType>::Address::indexedBy):
+        * jit/AssemblyHelpers.h:
+        (JSC::AssemblyHelpers::storeCell):
+        (JSC::AssemblyHelpers::loadCell):
+        (JSC::AssemblyHelpers::storeValue):
+        (JSC::AssemblyHelpers::emitSaveCalleeSaves):
+        (JSC::AssemblyHelpers::emitSaveThenMaterializeTagRegisters):
+        (JSC::AssemblyHelpers::emitRestoreCalleeSaves):
+        (JSC::AssemblyHelpers::emitRestoreSavedTagRegisters):
+        (JSC::AssemblyHelpers::copyCalleeSavesToVMCalleeSavesBuffer):
+        * jit/JITThunks.cpp:
+        (JSC::JITThunks::ctiNativeTailCall):
+        (JSC::JITThunks::ctiNativeTailCallWithoutSavedTags):
+        (JSC::JITThunks::ctiStub):
+        (JSC::JITThunks::hostFunctionStub):
+        (JSC::JITThunks::clearHostFunctionStubs):
+        * jit/JITThunks.h:
+        * jit/SpecializedThunkJIT.h:
+        (JSC::SpecializedThunkJIT::callDoubleToDoublePreservingReturn):
+        (JSC::SpecializedThunkJIT::tagReturnAsInt32):
+        (JSC::SpecializedThunkJIT::emitSaveThenMaterializeTagRegisters): Deleted.
+        (JSC::SpecializedThunkJIT::emitRestoreSavedTagRegisters): Deleted.
+        * jit/ThunkGenerators.cpp:
+        (JSC::virtualThunkFor):
+        (JSC::nativeForGenerator):
+        (JSC::nativeCallGenerator):
+        (JSC::nativeTailCallGenerator):
+        (JSC::nativeTailCallWithoutSavedTagsGenerator):
+        (JSC::nativeConstructGenerator):
+        (JSC::randomThunkGenerator):
+        (JSC::boundThisNoArgsFunctionCallGenerator):
+        * jit/ThunkGenerators.h:
+        * runtime/Executable.cpp:
+        (JSC::NativeExecutable::create):
+        (JSC::NativeExecutable::destroy):
+        (JSC::NativeExecutable::createStructure):
+        (JSC::NativeExecutable::finishCreation):
+        (JSC::NativeExecutable::NativeExecutable):
+        (JSC::ScriptExecutable::ScriptExecutable):
+        * runtime/Executable.h:
+        * runtime/FunctionPrototype.cpp:
+        (JSC::functionProtoFuncBind):
+        * runtime/IntlCollatorPrototype.cpp:
+        (JSC::IntlCollatorPrototypeGetterCompare):
+        * runtime/Intrinsic.h:
+        * runtime/JSBoundFunction.cpp:
+        (JSC::boundThisNoArgsFunctionCall):
+        (JSC::boundFunctionCall):
+        (JSC::boundThisNoArgsFunctionConstruct):
+        (JSC::boundFunctionConstruct):
+        (JSC::getBoundFunctionStructure):
+        (JSC::JSBoundFunction::create):
+        (JSC::JSBoundFunction::customHasInstance):
+        (JSC::JSBoundFunction::JSBoundFunction):
+        * runtime/JSBoundFunction.h:
+        (JSC::JSBoundFunction::targetFunction):
+        (JSC::JSBoundFunction::boundThis):
+        (JSC::JSBoundFunction::boundArgs):
+        (JSC::JSBoundFunction::createStructure):
+        (JSC::JSBoundFunction::offsetOfTargetFunction):
+        (JSC::JSBoundFunction::offsetOfBoundThis):
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::lookUpOrCreateNativeExecutable):
+        (JSC::JSFunction::create):
+        * runtime/VM.cpp:
+        (JSC::thunkGeneratorForIntrinsic):
+        (JSC::VM::getHostFunction):
+        * runtime/VM.h:
+        (JSC::VM::getCTIStub):
+        (JSC::VM::exceptionOffset):
+
 2016-04-22  Joonghun Park  <jh718.p...@samsung.com>
 
         [JSC] Fix build break since r199866

Modified: trunk/Source/_javascript_Core/assembler/AbstractMacroAssembler.h (199945 => 199946)


--- trunk/Source/_javascript_Core/assembler/AbstractMacroAssembler.h	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/assembler/AbstractMacroAssembler.h	2016-04-23 02:00:38 UTC (rev 199946)
@@ -143,7 +143,9 @@
             return TimesFour;
         return TimesEight;
     }
-
+    
+    struct BaseIndex;
+    
     // Address:
     //
     // Describes a simple base-offset address.
@@ -159,6 +161,8 @@
             return Address(base, offset + additionalOffset);
         }
         
+        BaseIndex indexedBy(RegisterID index, Scale) const;
+        
         RegisterID base;
         int32_t offset;
     };
@@ -216,7 +220,7 @@
             , offset(offset)
         {
         }
-
+        
         RegisterID base;
         RegisterID index;
         Scale scale;
@@ -1144,6 +1148,15 @@
     friend class LinkBuffer;
 }; // class AbstractMacroAssembler
 
+template <class AssemblerType, class MacroAssemblerType>
+inline typename AbstractMacroAssembler<AssemblerType, MacroAssemblerType>::BaseIndex
+AbstractMacroAssembler<AssemblerType, MacroAssemblerType>::Address::indexedBy(
+    typename AbstractMacroAssembler<AssemblerType, MacroAssemblerType>::RegisterID index,
+    typename AbstractMacroAssembler<AssemblerType, MacroAssemblerType>::Scale scale) const
+{
+    return BaseIndex(base, index, scale, offset);
+}
+
 } // namespace JSC
 
 #endif // ENABLE(ASSEMBLER)

Modified: trunk/Source/_javascript_Core/jit/AssemblyHelpers.h (199945 => 199946)


--- trunk/Source/_javascript_Core/jit/AssemblyHelpers.h	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/jit/AssemblyHelpers.h	2016-04-23 02:00:38 UTC (rev 199946)
@@ -85,6 +85,15 @@
 #endif
     }
     
+    void loadCell(Address address, GPRReg gpr)
+    {
+#if USE(JSVALUE64)
+        load64(address, gpr);
+#else
+        load32(address.withOffset(PayloadOffset), gpr);
+#endif
+    }
+    
     void storeValue(JSValueRegs regs, Address address)
     {
 #if USE(JSVALUE64)
@@ -274,11 +283,36 @@
         emitSaveCalleeSavesFor(codeBlock());
     }
 
+    void emitSaveThenMaterializeTagRegisters()
+    {
+#if USE(JSVALUE64)
+#if CPU(ARM64)
+        pushPair(GPRInfo::tagTypeNumberRegister, GPRInfo::tagMaskRegister);
+#else
+        push(GPRInfo::tagTypeNumberRegister);
+        push(GPRInfo::tagMaskRegister);
+#endif
+        emitMaterializeTagCheckRegisters();
+#endif
+    }
+    
     void emitRestoreCalleeSaves()
     {
         emitRestoreCalleeSavesFor(codeBlock());
     }
 
+    void emitRestoreSavedTagRegisters()
+    {
+#if USE(JSVALUE64)
+#if CPU(ARM64)
+        popPair(GPRInfo::tagTypeNumberRegister, GPRInfo::tagMaskRegister);
+#else
+        pop(GPRInfo::tagMaskRegister);
+        pop(GPRInfo::tagTypeNumberRegister);
+#endif
+#endif
+    }
+
     void copyCalleeSavesToVMCalleeSavesBuffer(const TempRegisterSet& usedRegisters = { RegisterSet::stubUnavailableRegisters() })
     {
 #if NUMBER_OF_CALLEE_SAVES_REGISTERS > 0

Modified: trunk/Source/_javascript_Core/jit/JITThunks.cpp (199945 => 199946)


--- trunk/Source/_javascript_Core/jit/JITThunks.cpp	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/jit/JITThunks.cpp	2016-04-23 02:00:38 UTC (rev 199946)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2013, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 2015-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -64,6 +64,12 @@
     return ctiStub(vm, nativeTailCallGenerator).code();
 }
 
+MacroAssemblerCodePtr JITThunks::ctiNativeTailCallWithoutSavedTags(VM* vm)
+{
+    ASSERT(vm->canUseJIT());
+    return ctiStub(vm, nativeTailCallWithoutSavedTagsGenerator).code();
+}
+
 MacroAssemblerCodeRef JITThunks::ctiStub(VM* vm, ThunkGenerator generator)
 {
     LockHolder locker(m_lock);
@@ -84,27 +90,15 @@
 
 NativeExecutable* JITThunks::hostFunctionStub(VM* vm, NativeFunction function, NativeFunction constructor, const String& name)
 {
-    ASSERT(!isCompilationThread());
-
-    if (NativeExecutable* nativeExecutable = m_hostFunctionStubMap->get(std::make_tuple(function, constructor, name)))
-        return nativeExecutable;
-
-    NativeExecutable* nativeExecutable = NativeExecutable::create(
-        *vm,
-        adoptRef(new NativeJITCode(JIT::compileCTINativeCall(vm, function), JITCode::HostCallThunk)),
-        function,
-        adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct(vm)), JITCode::HostCallThunk)),
-        constructor, NoIntrinsic, name);
-    weakAdd(*m_hostFunctionStubMap, std::make_tuple(function, constructor, name), Weak<NativeExecutable>(nativeExecutable, this));
-    return nativeExecutable;
+    return hostFunctionStub(vm, function, constructor, nullptr, NoIntrinsic, name);
 }
 
-NativeExecutable* JITThunks::hostFunctionStub(VM* vm, NativeFunction function, ThunkGenerator generator, Intrinsic intrinsic, const String& name)
+NativeExecutable* JITThunks::hostFunctionStub(VM* vm, NativeFunction function, NativeFunction constructor, ThunkGenerator generator, Intrinsic intrinsic, const String& name)
 {
     ASSERT(!isCompilationThread());    
     ASSERT(vm->canUseJIT());
 
-    if (NativeExecutable* nativeExecutable = m_hostFunctionStubMap->get(std::make_tuple(function, &callHostFunctionAsConstructor, name)))
+    if (NativeExecutable* nativeExecutable = m_hostFunctionStubMap->get(std::make_tuple(function, constructor, name)))
         return nativeExecutable;
 
     RefPtr<JITCode> forCall;
@@ -116,11 +110,16 @@
     
     RefPtr<JITCode> forConstruct = adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct(vm)), JITCode::HostCallThunk));
     
-    NativeExecutable* nativeExecutable = NativeExecutable::create(*vm, forCall, function, forConstruct, callHostFunctionAsConstructor, intrinsic, name);
-    weakAdd(*m_hostFunctionStubMap, std::make_tuple(function, &callHostFunctionAsConstructor, name), Weak<NativeExecutable>(nativeExecutable, this));
+    NativeExecutable* nativeExecutable = NativeExecutable::create(*vm, forCall, function, forConstruct, constructor, intrinsic, name);
+    weakAdd(*m_hostFunctionStubMap, std::make_tuple(function, constructor, name), Weak<NativeExecutable>(nativeExecutable, this));
     return nativeExecutable;
 }
 
+NativeExecutable* JITThunks::hostFunctionStub(VM* vm, NativeFunction function, ThunkGenerator generator, Intrinsic intrinsic, const String& name)
+{
+    return hostFunctionStub(vm, function, callHostFunctionAsConstructor, generator, intrinsic, name);
+}
+
 void JITThunks::clearHostFunctionStubs()
 {
     m_hostFunctionStubMap = nullptr;

Modified: trunk/Source/_javascript_Core/jit/JITThunks.h (199945 => 199946)


--- trunk/Source/_javascript_Core/jit/JITThunks.h	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/jit/JITThunks.h	2016-04-23 02:00:38 UTC (rev 199946)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -55,10 +55,12 @@
     MacroAssemblerCodePtr ctiNativeCall(VM*);
     MacroAssemblerCodePtr ctiNativeConstruct(VM*);
     MacroAssemblerCodePtr ctiNativeTailCall(VM*);    
+    MacroAssemblerCodePtr ctiNativeTailCallWithoutSavedTags(VM*);    
 
     MacroAssemblerCodeRef ctiStub(VM*, ThunkGenerator);
 
     NativeExecutable* hostFunctionStub(VM*, NativeFunction, NativeFunction constructor, const String& name);
+    NativeExecutable* hostFunctionStub(VM*, NativeFunction, NativeFunction constructor, ThunkGenerator, Intrinsic, const String& name);
     NativeExecutable* hostFunctionStub(VM*, NativeFunction, ThunkGenerator, Intrinsic, const String& name);
 
     void clearHostFunctionStubs();

Modified: trunk/Source/_javascript_Core/jit/SpecializedThunkJIT.h (199945 => 199946)


--- trunk/Source/_javascript_Core/jit/SpecializedThunkJIT.h	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/jit/SpecializedThunkJIT.h	2016-04-23 02:00:38 UTC (rev 199946)
@@ -193,31 +193,6 @@
         }
 
     private:
-        void emitSaveThenMaterializeTagRegisters()
-        {
-#if USE(JSVALUE64)
-#if CPU(ARM64)
-            pushPair(tagTypeNumberRegister, tagMaskRegister);
-#else
-            push(tagTypeNumberRegister);
-            push(tagMaskRegister);
-#endif
-            emitMaterializeTagCheckRegisters();
-#endif
-        }
-
-        void emitRestoreSavedTagRegisters()
-        {
-#if USE(JSVALUE64)
-#if CPU(ARM64)
-            popPair(tagTypeNumberRegister, tagMaskRegister);
-#else
-            pop(tagMaskRegister);
-            pop(tagTypeNumberRegister);
-#endif
-#endif
-        }
-        
         void tagReturnAsInt32()
         {
 #if USE(JSVALUE64)

Modified: trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp (199945 => 199946)


--- trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp	2016-04-23 02:00:38 UTC (rev 199946)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010, 2012, 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2012, 2013, 2014, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,6 +31,7 @@
 #include "JITOperations.h"
 #include "JSArray.h"
 #include "JSArrayIterator.h"
+#include "JSBoundFunction.h"
 #include "JSStack.h"
 #include "MathCommon.h"
 #include "MaxFrameExtentForSlowPathCall.h"
@@ -227,7 +228,7 @@
         callLinkInfo.callMode() == CallMode::Regular ? "call" : callLinkInfo.callMode() == CallMode::Tail ? "tail call" : "construct"));
 }
 
-enum ThunkEntryType { EnterViaCall, EnterViaJump };
+enum ThunkEntryType { EnterViaCall, EnterViaJumpWithSavedTags, EnterViaJumpWithoutSavedTags };
 
 static MacroAssemblerCodeRef nativeForGenerator(VM* vm, CodeSpecializationKind kind, ThunkEntryType entryType = EnterViaCall)
 {
@@ -238,10 +239,12 @@
     
     JSInterfaceJIT jit(vm);
 
-    if (entryType == EnterViaCall)
+    switch (entryType) {
+    case EnterViaCall:
         jit.emitFunctionPrologue();
+        break;
+    case EnterViaJumpWithSavedTags:
 #if USE(JSVALUE64)
-    else if (entryType == EnterViaJump) {
         // We're coming from a specialized thunk that has saved the prior tag registers' contents.
         // Restore them now.
 #if CPU(ARM64)
@@ -250,8 +253,12 @@
         jit.pop(JSInterfaceJIT::tagMaskRegister);
         jit.pop(JSInterfaceJIT::tagTypeNumberRegister);
 #endif
+#endif
+        break;
+    case EnterViaJumpWithoutSavedTags:
+        jit.move(JSInterfaceJIT::framePointerRegister, JSInterfaceJIT::stackPointerRegister);
+        break;
     }
-#endif
 
     jit.emitPutToCallFrameHeader(0, JSStack::CodeBlock);
     jit.storePtr(JSInterfaceJIT::callFrameRegister, &vm->topCallFrame);
@@ -374,7 +381,7 @@
     jit.jumpToExceptionHandler();
 
     LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
-    return FINALIZE_CODE(patchBuffer, ("native %s%s trampoline", entryType == EnterViaJump ? "Tail " : "", toCString(kind).data()));
+    return FINALIZE_CODE(patchBuffer, ("native %s%s trampoline", entryType == EnterViaJumpWithSavedTags ? "Tail With Saved Tags " : entryType == EnterViaJumpWithoutSavedTags ? "Tail Without Saved Tags " : "", toCString(kind).data()));
 }
 
 MacroAssemblerCodeRef nativeCallGenerator(VM* vm)
@@ -384,9 +391,14 @@
 
 MacroAssemblerCodeRef nativeTailCallGenerator(VM* vm)
 {
-    return nativeForGenerator(vm, CodeForCall, EnterViaJump);
+    return nativeForGenerator(vm, CodeForCall, EnterViaJumpWithSavedTags);
 }
 
+MacroAssemblerCodeRef nativeTailCallWithoutSavedTagsGenerator(VM* vm)
+{
+    return nativeForGenerator(vm, CodeForCall, EnterViaJumpWithoutSavedTags);
+}
+
 MacroAssemblerCodeRef nativeConstructGenerator(VM* vm)
 {
     return nativeForGenerator(vm, CodeForConstruct);
@@ -1079,6 +1091,97 @@
 #endif
 }
 
+MacroAssemblerCodeRef boundThisNoArgsFunctionCallGenerator(VM* vm)
+{
+    CCallHelpers jit(vm);
+    
+    jit.emitFunctionPrologue();
+    
+    // Set up our call frame.
+    jit.storePtr(CCallHelpers::TrustedImmPtr(nullptr), CCallHelpers::addressFor(JSStack::CodeBlock));
+    jit.store32(CCallHelpers::TrustedImm32(0), CCallHelpers::tagFor(JSStack::ArgumentCount));
+
+    unsigned extraStackNeeded = 0;
+    if (unsigned stackMisalignment = sizeof(CallerFrameAndPC) % stackAlignmentBytes())
+        extraStackNeeded = stackAlignmentBytes() - stackMisalignment;
+    
+    // We need to forward all of the arguments that we were passed. We aren't allowed to do a tail
+    // call here as far as I can tell. At least not so long as the generic path doesn't do a tail
+    // call, since that would be way too weird.
+    
+    // The formula for the number of stack bytes needed given some number of parameters (including
+    // this) is:
+    //
+    //     stackAlign((numParams + CallFrameHeaderSize) * sizeof(Register) - sizeof(CallerFrameAndPC))
+    //
+    // Probably we want to write this as:
+    //
+    //     stackAlign((numParams + (CallFrameHeaderSize - CallerFrameAndPCSize)) * sizeof(Register))
+    //
+    // That's really all there is to this. We have all the registers we need to do it.
+    
+    jit.load32(CCallHelpers::payloadFor(JSStack::ArgumentCount), GPRInfo::regT1);
+    jit.add32(CCallHelpers::TrustedImm32(JSStack::CallFrameHeaderSize - JSStack::CallerFrameAndPCSize), GPRInfo::regT1, GPRInfo::regT2);
+    jit.lshift32(CCallHelpers::TrustedImm32(3), GPRInfo::regT2);
+    jit.add32(CCallHelpers::TrustedImm32(stackAlignmentBytes() - 1), GPRInfo::regT2);
+    jit.and32(CCallHelpers::TrustedImm32(-stackAlignmentBytes()), GPRInfo::regT2);
+    
+    if (extraStackNeeded)
+        jit.add32(CCallHelpers::TrustedImm32(extraStackNeeded), GPRInfo::regT2);
+    
+    // At this point regT1 has the actual argument count and regT2 has the amount of stack we will
+    // need.
+    
+    jit.subPtr(GPRInfo::regT2, CCallHelpers::stackPointerRegister);
+
+    // Do basic callee frame setup, including 'this'.
+    
+    jit.loadCell(CCallHelpers::addressFor(JSStack::Callee), GPRInfo::regT3);
+
+    jit.store32(GPRInfo::regT1, CCallHelpers::calleeFramePayloadSlot(JSStack::ArgumentCount));
+    
+    JSValueRegs valueRegs = JSValueRegs::withTwoAvailableRegs(GPRInfo::regT0, GPRInfo::regT2);
+    jit.loadValue(CCallHelpers::Address(GPRInfo::regT3, JSBoundFunction::offsetOfBoundThis()), valueRegs);
+    jit.storeValue(valueRegs, CCallHelpers::calleeArgumentSlot(0));
+
+    jit.loadPtr(CCallHelpers::Address(GPRInfo::regT3, JSBoundFunction::offsetOfTargetFunction()), GPRInfo::regT3);
+    jit.storeCell(GPRInfo::regT3, CCallHelpers::calleeFrameSlot(JSStack::Callee));
+    
+    // OK, now we can start copying. This is a simple matter of copying parameters from the caller's
+    // frame to the callee's frame. Note that we know that regT1 (the argument count) must be at
+    // least 1.
+    jit.sub32(CCallHelpers::TrustedImm32(1), GPRInfo::regT1);
+    CCallHelpers::Jump done = jit.branchTest32(CCallHelpers::Zero, GPRInfo::regT1);
+    
+    CCallHelpers::Label loop = jit.label();
+    jit.sub32(CCallHelpers::TrustedImm32(1), GPRInfo::regT1);
+    jit.loadValue(CCallHelpers::addressFor(virtualRegisterForArgument(1)).indexedBy(GPRInfo::regT1, CCallHelpers::TimesEight), valueRegs);
+    jit.storeValue(valueRegs, CCallHelpers::calleeArgumentSlot(1).indexedBy(GPRInfo::regT1, CCallHelpers::TimesEight));
+    jit.branchTest32(CCallHelpers::NonZero, GPRInfo::regT1).linkTo(loop, &jit);
+    
+    done.link(&jit);
+    
+    jit.loadPtr(
+        CCallHelpers::Address(GPRInfo::regT3, JSFunction::offsetOfExecutable()),
+        GPRInfo::regT0);
+    jit.loadPtr(
+        CCallHelpers::Address(
+            GPRInfo::regT0, ExecutableBase::offsetOfJITCodeWithArityCheckFor(CodeForCall)),
+        GPRInfo::regT0);
+    CCallHelpers::Jump noCode = jit.branchTestPtr(CCallHelpers::Zero, GPRInfo::regT0);
+    
+    emitPointerValidation(jit, GPRInfo::regT0);
+    jit.call(GPRInfo::regT0);
+    
+    jit.emitFunctionEpilogue();
+    jit.ret();
+    
+    LinkBuffer linkBuffer(*vm, jit, GLOBAL_THUNK_ID);
+    linkBuffer.link(noCode, CodeLocationLabel(vm->jitStubs->ctiNativeTailCallWithoutSavedTags(vm)));
+    return FINALIZE_CODE(
+        linkBuffer, ("Specialized thunk for bound function calls with no arguments"));
 }
 
+} // namespace JSC
+
 #endif // ENABLE(JIT)

Modified: trunk/Source/_javascript_Core/jit/ThunkGenerators.h (199945 => 199946)


--- trunk/Source/_javascript_Core/jit/ThunkGenerators.h	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/jit/ThunkGenerators.h	2016-04-23 02:00:38 UTC (rev 199946)
@@ -46,6 +46,7 @@
 MacroAssemblerCodeRef nativeCallGenerator(VM*);
 MacroAssemblerCodeRef nativeConstructGenerator(VM*);
 MacroAssemblerCodeRef nativeTailCallGenerator(VM*);
+MacroAssemblerCodeRef nativeTailCallWithoutSavedTagsGenerator(VM*);
 MacroAssemblerCodeRef arityFixupGenerator(VM*);
 MacroAssemblerCodeRef unreachableGenerator(VM*);
 
@@ -65,6 +66,8 @@
 MacroAssemblerCodeRef randomThunkGenerator(VM*);
 MacroAssemblerCodeRef truncThunkGenerator(VM*);
 
+MacroAssemblerCodeRef boundThisNoArgsFunctionCallGenerator(VM* vm);
+
 }
 #endif // ENABLE(JIT)
 

Modified: trunk/Source/_javascript_Core/runtime/Executable.cpp (199945 => 199946)


--- trunk/Source/_javascript_Core/runtime/Executable.cpp	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/runtime/Executable.cpp	2016-04-23 02:00:38 UTC (rev 199946)
@@ -103,11 +103,41 @@
 
 const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, CREATE_METHOD_TABLE(NativeExecutable) };
 
+NativeExecutable* NativeExecutable::create(VM& vm, PassRefPtr<JITCode> callThunk, NativeFunction function, PassRefPtr<JITCode> constructThunk, NativeFunction constructor, Intrinsic intrinsic, const String& name)
+{
+    NativeExecutable* executable;
+    executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor, intrinsic);
+    executable->finishCreation(vm, callThunk, constructThunk, name);
+    return executable;
+}
+
 void NativeExecutable::destroy(JSCell* cell)
 {
     static_cast<NativeExecutable*>(cell)->NativeExecutable::~NativeExecutable();
 }
 
+Structure* NativeExecutable::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+{
+    return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info());
+}
+
+void NativeExecutable::finishCreation(VM& vm, PassRefPtr<JITCode> callThunk, PassRefPtr<JITCode> constructThunk, const String& name)
+{
+    Base::finishCreation(vm);
+    m_jitCodeForCall = callThunk;
+    m_jitCodeForConstruct = constructThunk;
+    m_jitCodeForCallWithArityCheck = m_jitCodeForCall->addressForCall(MustCheckArity);
+    m_jitCodeForConstructWithArityCheck = m_jitCodeForConstruct->addressForCall(MustCheckArity);
+    m_name = name;
+}
+
+NativeExecutable::NativeExecutable(VM& vm, NativeFunction function, NativeFunction constructor, Intrinsic intrinsic)
+    : ExecutableBase(vm, vm.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST, intrinsic)
+    , m_function(function)
+    , m_constructor(constructor)
+{
+}
+
 const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, CREATE_METHOD_TABLE(ScriptExecutable) };
 
 ScriptExecutable::ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext, DerivedContextType derivedContextType, bool isInArrowFunctionContext, EvalContextType evalContextType, Intrinsic intrinsic)

Modified: trunk/Source/_javascript_Core/runtime/Executable.h (199945 => 199946)


--- trunk/Source/_javascript_Core/runtime/Executable.h	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/runtime/Executable.h	2016-04-23 02:00:38 UTC (rev 199946)
@@ -258,13 +258,7 @@
     typedef ExecutableBase Base;
     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 
-    static NativeExecutable* create(VM& vm, PassRefPtr<JITCode> callThunk, NativeFunction function, PassRefPtr<JITCode> constructThunk, NativeFunction constructor, Intrinsic intrinsic, const String& name)
-    {
-        NativeExecutable* executable;
-        executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor, intrinsic);
-        executable->finishCreation(vm, callThunk, constructThunk, name);
-        return executable;
-    }
+    static NativeExecutable* create(VM& vm, PassRefPtr<JITCode> callThunk, NativeFunction function, PassRefPtr<JITCode> constructThunk, NativeFunction constructor, Intrinsic intrinsic, const String& name);
 
     static void destroy(JSCell*);
 
@@ -289,7 +283,7 @@
         return OBJECT_OFFSETOF(NativeExecutable, m_constructor);
     }
 
-    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); }
+    static Structure* createStructure(VM&, JSGlobalObject*, JSValue proto);
         
     DECLARE_INFO;
 
@@ -298,23 +292,12 @@
     const String& name() const { return m_name; }
 
 protected:
-    void finishCreation(VM& vm, PassRefPtr<JITCode> callThunk, PassRefPtr<JITCode> constructThunk, const String& name)
-    {
-        Base::finishCreation(vm);
-        m_jitCodeForCall = callThunk;
-        m_jitCodeForConstruct = constructThunk;
-        m_name = name;
-    }
+    void finishCreation(VM&, PassRefPtr<JITCode> callThunk, PassRefPtr<JITCode> constructThunk, const String& name);
 
 private:
     friend class ExecutableBase;
 
-    NativeExecutable(VM& vm, NativeFunction function, NativeFunction constructor, Intrinsic intrinsic)
-        : ExecutableBase(vm, vm.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST, intrinsic)
-        , m_function(function)
-        , m_constructor(constructor)
-    {
-    }
+    NativeExecutable(VM&, NativeFunction function, NativeFunction constructor, Intrinsic);
 
     NativeFunction m_function;
     NativeFunction m_constructor;

Modified: trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp (199945 => 199946)


--- trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp	2016-04-23 02:00:38 UTC (rev 199946)
@@ -141,13 +141,17 @@
 
     // Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order.
     size_t numBoundArgs = exec->argumentCount() > 1 ? exec->argumentCount() - 1 : 0;
-    JSArray* boundArgs = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), numBoundArgs);
-    if (!boundArgs)
-        return JSValue::encode(throwOutOfMemoryError(exec));
+    JSArray* boundArgs;
+    if (numBoundArgs) {
+        boundArgs = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), numBoundArgs);
+        if (!boundArgs)
+            return JSValue::encode(throwOutOfMemoryError(exec));
+        
+        for (size_t i = 0; i < numBoundArgs; ++i)
+            boundArgs->initializeIndex(vm, i, exec->argument(i + 1));
+    } else
+        boundArgs = nullptr;
 
-    for (size_t i = 0; i < numBoundArgs; ++i)
-        boundArgs->initializeIndex(vm, i, exec->argument(i + 1));
-
     // If the [[Class]] internal property of Target is "Function", then ...
     // Else set the length own property of F to 0.
     unsigned length = 0;

Modified: trunk/Source/_javascript_Core/runtime/IntlCollatorPrototype.cpp (199945 => 199946)


--- trunk/Source/_javascript_Core/runtime/IntlCollatorPrototype.cpp	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/runtime/IntlCollatorPrototype.cpp	2016-04-23 02:00:38 UTC (rev 199946)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2015 Andy VanWagoner (thetalecraf...@gmail.com)
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -124,12 +125,9 @@
         // a. Let F be a new built-in function object as defined in 11.3.4.
         // b. The value of F’s length property is 2.
         JSFunction* targetObject = JSFunction::create(vm, globalObject, 2, ASCIILiteral("compare"), IntlCollatorFuncCompare, NoIntrinsic);
-        JSArray* boundArgs = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), 0);
-        if (!boundArgs)
-            return JSValue::encode(throwOutOfMemoryError(state));
 
         // c. Let bc be BoundFunctionCreate(F, «this value»).
-        boundCompare = JSBoundFunction::create(vm, state, globalObject, targetObject, collator, boundArgs, 2, ASCIILiteral("compare"));
+        boundCompare = JSBoundFunction::create(vm, state, globalObject, targetObject, collator, nullptr, 2, ASCIILiteral("compare"));
         if (vm.exception())
             return JSValue::encode(JSValue());
         // d. Set collator.[[boundCompare]] to bc.

Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.h (199945 => 199946)


--- trunk/Source/_javascript_Core/runtime/Intrinsic.h	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.h	2016-04-23 02:00:38 UTC (rev 199946)
@@ -61,6 +61,7 @@
     IsArrayConstructorIntrinsic,
     IsJSArrayIntrinsic,
     IsRegExpObjectIntrinsic,
+    BoundThisNoArgsFunctionCallIntrinsic,
 
     // Getter intrinsics.
     TypedArrayLengthIntrinsic,

Modified: trunk/Source/_javascript_Core/runtime/JSBoundFunction.cpp (199945 => 199946)


--- trunk/Source/_javascript_Core/runtime/JSBoundFunction.cpp	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/runtime/JSBoundFunction.cpp	2016-04-23 02:00:38 UTC (rev 199946)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -34,16 +34,37 @@
 
 const ClassInfo JSBoundFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(JSBoundFunction) };
 
+EncodedJSValue JSC_HOST_CALL boundThisNoArgsFunctionCall(ExecState* exec)
+{
+    JSBoundFunction* boundFunction = jsCast<JSBoundFunction*>(exec->callee());
+
+    MarkedArgumentBuffer args;
+    for (unsigned i = 0; i < exec->argumentCount(); ++i)
+        args.append(exec->uncheckedArgument(i));
+
+    JSFunction* targetFunction = jsCast<JSFunction*>(boundFunction->targetFunction());
+    ExecutableBase* executable = targetFunction->executable();
+    if (executable->hasJITCodeForCall()) {
+        // Force the executable to cache its arity entrypoint.
+        executable->entrypointFor(CodeForCall, MustCheckArity);
+    }
+    CallData callData;
+    CallType callType = getCallData(targetFunction, callData);
+    ASSERT(callType != CallType::None);
+    return JSValue::encode(call(exec, targetFunction, callType, callData, boundFunction->boundThis(), args));
+}
+
 EncodedJSValue JSC_HOST_CALL boundFunctionCall(ExecState* exec)
 {
     JSBoundFunction* boundFunction = jsCast<JSBoundFunction*>(exec->callee());
 
-    ASSERT(isJSArray(boundFunction->boundArgs())); // Currently this is true!
-    JSArray* boundArgs = asArray(boundFunction->boundArgs());
+    JSArray* boundArgs = boundFunction->boundArgs();
 
     MarkedArgumentBuffer args;
-    for (unsigned i = 0; i < boundArgs->length(); ++i)
-        args.append(boundArgs->getIndexQuickly(i));
+    if (boundArgs) {
+        for (unsigned i = 0; i < boundArgs->length(); ++i)
+            args.append(boundArgs->getIndexQuickly(i));
+    }
     for (unsigned i = 0; i < exec->argumentCount(); ++i)
         args.append(exec->uncheckedArgument(i));
 
@@ -54,16 +75,32 @@
     return JSValue::encode(call(exec, targetFunction, callType, callData, boundFunction->boundThis(), args));
 }
 
+EncodedJSValue JSC_HOST_CALL boundThisNoArgsFunctionConstruct(ExecState* exec)
+{
+    JSBoundFunction* boundFunction = jsCast<JSBoundFunction*>(exec->callee());
+
+    MarkedArgumentBuffer args;
+    for (unsigned i = 0; i < exec->argumentCount(); ++i)
+        args.append(exec->uncheckedArgument(i));
+
+    JSFunction* targetFunction = jsCast<JSFunction*>(boundFunction->targetFunction());
+    ConstructData constructData;
+    ConstructType constructType = getConstructData(targetFunction, constructData);
+    ASSERT(constructType != ConstructType::None);
+    return JSValue::encode(construct(exec, targetFunction, constructType, constructData, args));
+}
+
 EncodedJSValue JSC_HOST_CALL boundFunctionConstruct(ExecState* exec)
 {
     JSBoundFunction* boundFunction = jsCast<JSBoundFunction*>(exec->callee());
 
-    ASSERT(isJSArray(boundFunction->boundArgs())); // Currently this is true!
-    JSArray* boundArgs = asArray(boundFunction->boundArgs());
+    JSArray* boundArgs = boundFunction->boundArgs();
 
     MarkedArgumentBuffer args;
-    for (unsigned i = 0; i < boundArgs->length(); ++i)
-        args.append(boundArgs->getIndexQuickly(i));
+    if (boundArgs) {
+        for (unsigned i = 0; i < boundArgs->length(); ++i)
+            args.append(boundArgs->getIndexQuickly(i));
+    }
     for (unsigned i = 0; i < exec->argumentCount(); ++i)
         args.append(exec->uncheckedArgument(i));
 
@@ -119,12 +156,19 @@
     return result;
 }
 
-JSBoundFunction* JSBoundFunction::create(VM& vm, ExecState* exec, JSGlobalObject* globalObject, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs, int length, const String& name)
+JSBoundFunction* JSBoundFunction::create(VM& vm, ExecState* exec, JSGlobalObject* globalObject, JSObject* targetFunction, JSValue boundThis, JSArray* boundArgs, int length, const String& name)
 {
     ConstructData constructData;
     ConstructType constructType = JSC::getConstructData(targetFunction, constructData);
     bool canConstruct = constructType != ConstructType::None;
-    NativeExecutable* executable = vm.getHostFunction(boundFunctionCall, canConstruct ? boundFunctionConstruct : callHostFunctionAsConstructor, name);
+    
+    bool slowCase = boundArgs || !getJSFunction(targetFunction);
+    
+    NativeExecutable* executable = vm.getHostFunction(
+        slowCase ? boundFunctionCall : boundThisNoArgsFunctionCall,
+        slowCase ? NoIntrinsic : BoundThisNoArgsFunctionCallIntrinsic,
+        canConstruct ? (slowCase ? boundFunctionConstruct : boundThisNoArgsFunctionConstruct) : callHostFunctionAsConstructor,
+        name);
     Structure* structure = getBoundFunctionStructure(vm, exec, globalObject, targetFunction);
     if (UNLIKELY(vm.exception()))
         return nullptr;
@@ -139,11 +183,11 @@
     return jsCast<JSBoundFunction*>(object)->m_targetFunction->hasInstance(exec, value);
 }
 
-JSBoundFunction::JSBoundFunction(VM& vm, JSGlobalObject* globalObject, Structure* structure, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs)
+JSBoundFunction::JSBoundFunction(VM& vm, JSGlobalObject* globalObject, Structure* structure, JSObject* targetFunction, JSValue boundThis, JSArray* boundArgs)
     : Base(vm, globalObject, structure)
     , m_targetFunction(vm, this, targetFunction)
     , m_boundThis(vm, this, boundThis)
-    , m_boundArgs(vm, this, boundArgs)
+    , m_boundArgs(vm, this, boundArgs, WriteBarrier<JSArray>::MayBeNull)
 {
 }
 

Modified: trunk/Source/_javascript_Core/runtime/JSBoundFunction.h (199945 => 199946)


--- trunk/Source/_javascript_Core/runtime/JSBoundFunction.h	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/runtime/JSBoundFunction.h	2016-04-23 02:00:38 UTC (rev 199946)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -30,7 +30,9 @@
 
 namespace JSC {
 
+EncodedJSValue JSC_HOST_CALL boundThisNoArgsFunctionCall(ExecState*);
 EncodedJSValue JSC_HOST_CALL boundFunctionCall(ExecState*);
+EncodedJSValue JSC_HOST_CALL boundThisNoArgsFunctionConstruct(ExecState*);
 EncodedJSValue JSC_HOST_CALL boundFunctionConstruct(ExecState*);
 EncodedJSValue JSC_HOST_CALL isBoundFunction(ExecState*);
 EncodedJSValue JSC_HOST_CALL hasInstanceBoundFunction(ExecState*);
@@ -40,19 +42,22 @@
     typedef JSFunction Base;
     const static unsigned StructureFlags = ~ImplementsDefaultHasInstance & Base::StructureFlags;
 
-    static JSBoundFunction* create(VM&, ExecState*, JSGlobalObject*, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs, int, const String& name);
+    static JSBoundFunction* create(VM&, ExecState*, JSGlobalObject*, JSObject* targetFunction, JSValue boundThis, JSArray* boundArgs, int, const String& name);
     
     static bool customHasInstance(JSObject*, ExecState*, JSValue);
 
     JSObject* targetFunction() { return m_targetFunction.get(); }
     JSValue boundThis() { return m_boundThis.get(); }
-    JSValue boundArgs() { return m_boundArgs.get(); }
+    JSArray* boundArgs() { return m_boundArgs.get(); }
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
         ASSERT(globalObject);
         return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info()); 
     }
+    
+    static ptrdiff_t offsetOfTargetFunction() { return OBJECT_OFFSETOF(JSBoundFunction, m_targetFunction); }
+    static ptrdiff_t offsetOfBoundThis() { return OBJECT_OFFSETOF(JSBoundFunction, m_boundThis); }
 
     DECLARE_INFO;
 
@@ -60,13 +65,13 @@
     static void visitChildren(JSCell*, SlotVisitor&);
 
 private:
-    JSBoundFunction(VM&, JSGlobalObject*, Structure*, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs);
+    JSBoundFunction(VM&, JSGlobalObject*, Structure*, JSObject* targetFunction, JSValue boundThis, JSArray* boundArgs);
     
     void finishCreation(VM&, NativeExecutable*, int length, const String& name);
 
     WriteBarrier<JSObject> m_targetFunction;
     WriteBarrier<Unknown> m_boundThis;
-    WriteBarrier<Unknown> m_boundArgs;
+    WriteBarrier<JSArray> m_boundArgs;
 };
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (199945 => 199946)


--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2016-04-23 02:00:38 UTC (rev 199946)
@@ -84,15 +84,7 @@
 
 NativeExecutable* JSFunction::lookUpOrCreateNativeExecutable(VM& vm, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor, const String& name)
 {
-#if !ENABLE(JIT)
-    UNUSED_PARAM(intrinsic);
-#else
-    if (intrinsic != NoIntrinsic && vm.canUseJIT()) {
-        ASSERT(nativeConstructor == callHostFunctionAsConstructor);
-        return vm.getHostFunction(nativeFunction, intrinsic, name);
-    }
-#endif
-    return vm.getHostFunction(nativeFunction, nativeConstructor, name);
+    return vm.getHostFunction(nativeFunction, intrinsic, nativeConstructor, name);
 }
 
 JSFunction* JSFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor)

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (199945 => 199946)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2016-04-23 02:00:38 UTC (rev 199946)
@@ -495,33 +495,34 @@
         return imulThunkGenerator;
     case RandomIntrinsic:
         return randomThunkGenerator;
+    case BoundThisNoArgsFunctionCallIntrinsic:
+        return boundThisNoArgsFunctionCallGenerator;
     default:
-        return 0;
+        return nullptr;
     }
 }
 
+#endif // !ENABLE(JIT)
+
 NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor, const String& name)
 {
-    return jitStubs->hostFunctionStub(this, function, constructor, name);
+    return getHostFunction(function, NoIntrinsic, constructor, name);
 }
-NativeExecutable* VM::getHostFunction(NativeFunction function, Intrinsic intrinsic, const String& name)
-{
-    ASSERT(canUseJIT());
-    return jitStubs->hostFunctionStub(this, function, intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0, intrinsic, name);
-}
 
-#else // !ENABLE(JIT)
-
-NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor, const String& name)
+NativeExecutable* VM::getHostFunction(NativeFunction function, Intrinsic intrinsic, NativeFunction constructor, const String& name)
 {
+    if (canUseJIT()) {
+        return jitStubs->hostFunctionStub(
+            this, function, constructor,
+            intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0,
+            intrinsic, name);
+    }
     return NativeExecutable::create(*this,
         adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_call_trampoline), JITCode::HostCallThunk)), function,
         adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_construct_trampoline), JITCode::HostCallThunk)), constructor,
         NoIntrinsic, name);
 }
 
-#endif // !ENABLE(JIT)
-
 VM::ClientData::~ClientData()
 {
 }

Modified: trunk/Source/_javascript_Core/runtime/VM.h (199945 => 199946)


--- trunk/Source/_javascript_Core/runtime/VM.h	2016-04-23 01:14:02 UTC (rev 199945)
+++ trunk/Source/_javascript_Core/runtime/VM.h	2016-04-23 02:00:38 UTC (rev 199946)
@@ -399,7 +399,6 @@
     {
         return jitStubs->ctiStub(this, generator);
     }
-    NativeExecutable* getHostFunction(NativeFunction, Intrinsic, const String& name);
     
     std::unique_ptr<RegisterAtOffsetList> allCalleeSaveRegisterOffsets;
     
@@ -411,6 +410,7 @@
     std::unique_ptr<FTL::Thunks> ftlThunks;
 #endif
     NativeExecutable* getHostFunction(NativeFunction, NativeFunction constructor, const String& name);
+    NativeExecutable* getHostFunction(NativeFunction, Intrinsic intrinsic, NativeFunction constructor, const String& name);
 
     static ptrdiff_t exceptionOffset()
     {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to