diff --git a/src/compiler/arm/linkage-arm.cc b/src/compiler/arm/linkage-arm.cc index 9a65ccc109..2c644d680c 100644 --- a/src/compiler/arm/linkage-arm.cc +++ b/src/compiler/arm/linkage-arm.cc @@ -35,8 +35,9 @@ struct ArmLinkageHelperTraits { typedef LinkageHelper LH; -CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) { - return LH::GetJSCallDescriptor(zone, parameter_count); +CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone, + CallDescriptor::Flags flags) { + return LH::GetJSCallDescriptor(zone, parameter_count, flags); } diff --git a/src/compiler/arm64/linkage-arm64.cc b/src/compiler/arm64/linkage-arm64.cc index c50736c8a5..bfa79da82c 100644 --- a/src/compiler/arm64/linkage-arm64.cc +++ b/src/compiler/arm64/linkage-arm64.cc @@ -35,8 +35,9 @@ struct Arm64LinkageHelperTraits { typedef LinkageHelper LH; -CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) { - return LH::GetJSCallDescriptor(zone, parameter_count); +CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone, + CallDescriptor::Flags flags) { + return LH::GetJSCallDescriptor(zone, parameter_count, flags); } diff --git a/src/compiler/ia32/linkage-ia32.cc b/src/compiler/ia32/linkage-ia32.cc index 8d85a9d185..2d10f6f1fb 100644 --- a/src/compiler/ia32/linkage-ia32.cc +++ b/src/compiler/ia32/linkage-ia32.cc @@ -30,8 +30,9 @@ struct IA32LinkageHelperTraits { typedef LinkageHelper LH; -CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) { - return LH::GetJSCallDescriptor(zone, parameter_count); +CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone, + CallDescriptor::Flags flags) { + return LH::GetJSCallDescriptor(zone, parameter_count, flags); } diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc index 11979ec6ed..90d4d5efc8 100644 --- a/src/compiler/js-generic-lowering.cc +++ b/src/compiler/js-generic-lowering.cc @@ -9,6 +9,7 @@ #include "src/compiler/js-generic-lowering.h" #include "src/compiler/machine-operator.h" #include "src/compiler/node-aux-data-inl.h" +#include "src/compiler/node-matchers.h" #include "src/compiler/node-properties-inl.h" #include "src/unique.h" @@ -405,9 +406,51 @@ void JSGenericLowering::LowerJSCallConstruct(Node* node) { } -void JSGenericLowering::LowerJSCallFunction(Node* node) { +bool JSGenericLowering::TryLowerDirectJSCall(Node* node) { + // Lower to a direct call to a constant JSFunction if legal. const CallFunctionParameters& p = CallFunctionParametersOf(node->op()); - CallFunctionStub stub(isolate(), static_cast(p.arity() - 2), p.flags()); + int arg_count = static_cast(p.arity() - 2); + + // Check the function is a constant and is really a JSFunction. + HeapObjectMatcher function_const(node->InputAt(0)); + if (!function_const.HasValue()) return false; // not a constant. + Handle func = function_const.Value().handle(); + if (!func->IsJSFunction()) return false; // not a function. + Handle function = Handle::cast(func); + if (arg_count != function->shared()->formal_parameter_count()) return false; + + // Check the receiver doesn't need to be wrapped. + Node* receiver = node->InputAt(1); + if (!NodeProperties::IsTyped(receiver)) return false; + Type* ok_receiver = Type::Union(Type::Undefined(), Type::Receiver(), zone()); + if (!NodeProperties::GetBounds(receiver).upper->Is(ok_receiver)) return false; + + int index = NodeProperties::FirstContextIndex(node); + + // TODO(titzer): total hack to share function context constants. + // Remove this when the JSGraph canonicalizes heap constants. + Node* context = node->InputAt(index); + HeapObjectMatcher context_const(context); + if (!context_const.HasValue() || + *(context_const.Value().handle()) != function->context()) { + context = jsgraph()->HeapConstant(Handle(function->context())); + } + node->ReplaceInput(index, context); + CallDescriptor* desc = linkage()->GetJSCallDescriptor( + 1 + arg_count, jsgraph()->zone(), FlagsForNode(node)); + PatchOperator(node, common()->Call(desc)); + return true; +} + + +void JSGenericLowering::LowerJSCallFunction(Node* node) { + // Fast case: call function directly. + if (TryLowerDirectJSCall(node)) return; + + // General case: CallFunctionStub. + const CallFunctionParameters& p = CallFunctionParametersOf(node->op()); + int arg_count = static_cast(p.arity() - 2); + CallFunctionStub stub(isolate(), arg_count, p.flags()); CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor(); CallDescriptor* desc = linkage()->GetStubCallDescriptor( d, static_cast(p.arity() - 1), FlagsForNode(node)); diff --git a/src/compiler/js-generic-lowering.h b/src/compiler/js-generic-lowering.h index d01d395194..63d8e93ca4 100644 --- a/src/compiler/js-generic-lowering.h +++ b/src/compiler/js-generic-lowering.h @@ -66,6 +66,8 @@ class JSGenericLowering : public Reducer { CompilationInfo* info_; JSGraph* jsgraph_; Linkage* linkage_; + + bool TryLowerDirectJSCall(Node* node); }; } // namespace compiler diff --git a/src/compiler/linkage-impl.h b/src/compiler/linkage-impl.h index 807d626be2..c964eee068 100644 --- a/src/compiler/linkage-impl.h +++ b/src/compiler/linkage-impl.h @@ -28,8 +28,8 @@ class LinkageHelper { } // TODO(turbofan): cache call descriptors for JSFunction calls. - static CallDescriptor* GetJSCallDescriptor(Zone* zone, - int js_parameter_count) { + static CallDescriptor* GetJSCallDescriptor(Zone* zone, int js_parameter_count, + CallDescriptor::Flags flags) { const size_t return_count = 1; const size_t context_count = 1; const size_t parameter_count = js_parameter_count + context_count; @@ -56,16 +56,17 @@ class LinkageHelper { // The target for JS function calls is the JSFunction object. MachineType target_type = kMachAnyTagged; LinkageLocation target_loc = regloc(LinkageTraits::JSCallFunctionReg()); - return new (zone) CallDescriptor(CallDescriptor::kCallJSFunction, // kind - target_type, // target MachineType - target_loc, // target location - types.Build(), // machine_sig - locations.Build(), // location_sig - js_parameter_count, // js_parameter_count - Operator::kNoProperties, // properties - kNoCalleeSaved, // callee-saved - CallDescriptor::kNeedsFrameState, // flags - "js-call"); + return new (zone) CallDescriptor( // -- + CallDescriptor::kCallJSFunction, // kind + target_type, // target MachineType + target_loc, // target location + types.Build(), // machine_sig + locations.Build(), // location_sig + js_parameter_count, // js_parameter_count + Operator::kNoProperties, // properties + kNoCalleeSaved, // callee-saved + flags, // flags + "js-call"); } @@ -116,16 +117,17 @@ class LinkageHelper { // The target for runtime calls is a code object. MachineType target_type = kMachAnyTagged; LinkageLocation target_loc = LinkageLocation::AnyRegister(); - return new (zone) CallDescriptor(CallDescriptor::kCallCodeObject, // kind - target_type, // target MachineType - target_loc, // target location - types.Build(), // machine_sig - locations.Build(), // location_sig - js_parameter_count, // js_parameter_count - properties, // properties - kNoCalleeSaved, // callee-saved - flags, // flags - function->name); // debug name + return new (zone) CallDescriptor( // -- + CallDescriptor::kCallCodeObject, // kind + target_type, // target MachineType + target_loc, // target location + types.Build(), // machine_sig + locations.Build(), // location_sig + js_parameter_count, // js_parameter_count + properties, // properties + kNoCalleeSaved, // callee-saved + flags, // flags + function->name); // debug name } @@ -169,16 +171,17 @@ class LinkageHelper { // The target for stub calls is a code object. MachineType target_type = kMachAnyTagged; LinkageLocation target_loc = LinkageLocation::AnyRegister(); - return new (zone) CallDescriptor(CallDescriptor::kCallCodeObject, // kind - target_type, // target MachineType - target_loc, // target location - types.Build(), // machine_sig - locations.Build(), // location_sig - js_parameter_count, // js_parameter_count - Operator::kNoProperties, // properties - kNoCalleeSaved, // callee-saved registers - flags, // flags - descriptor.DebugName(zone->isolate())); + return new (zone) CallDescriptor( // -- + CallDescriptor::kCallCodeObject, // kind + target_type, // target MachineType + target_loc, // target location + types.Build(), // machine_sig + locations.Build(), // location_sig + js_parameter_count, // js_parameter_count + Operator::kNoProperties, // properties + kNoCalleeSaved, // callee-saved registers + flags, // flags + descriptor.DebugName(zone->isolate())); } static CallDescriptor* GetSimplifiedCDescriptor(Zone* zone, @@ -201,15 +204,16 @@ class LinkageHelper { // The target for C calls is always an address (i.e. machine pointer). MachineType target_type = kMachPtr; LinkageLocation target_loc = LinkageLocation::AnyRegister(); - return new (zone) CallDescriptor(CallDescriptor::kCallAddress, // kind - target_type, // target MachineType - target_loc, // target location - msig, // machine_sig - locations.Build(), // location_sig - 0, // js_parameter_count - Operator::kNoProperties, // properties - LinkageTraits::CCalleeSaveRegisters(), - CallDescriptor::kNoFlags, "c-call"); + return new (zone) CallDescriptor( // -- + CallDescriptor::kCallAddress, // kind + target_type, // target MachineType + target_loc, // target location + msig, // machine_sig + locations.Build(), // location_sig + 0, // js_parameter_count + Operator::kNoProperties, // properties + LinkageTraits::CCalleeSaveRegisters(), CallDescriptor::kNoFlags, + "c-call"); } static LinkageLocation regloc(Register reg) { diff --git a/src/compiler/linkage.cc b/src/compiler/linkage.cc index b5863010f6..87aa81b6d1 100644 --- a/src/compiler/linkage.cc +++ b/src/compiler/linkage.cc @@ -42,13 +42,15 @@ CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) { if (info->function() != NULL) { // If we already have the function literal, use the number of parameters // plus the receiver. - return GetJSCallDescriptor(1 + info->function()->parameter_count(), zone); + return GetJSCallDescriptor(1 + info->function()->parameter_count(), zone, + CallDescriptor::kNoFlags); } if (!info->closure().is_null()) { // If we are compiling a JS function, use a JS call descriptor, // plus the receiver. SharedFunctionInfo* shared = info->closure()->shared(); - return GetJSCallDescriptor(1 + shared->formal_parameter_count(), zone); + return GetJSCallDescriptor(1 + shared->formal_parameter_count(), zone, + CallDescriptor::kNoFlags); } if (info->code_stub() != NULL) { // Use the code stub interface descriptor. @@ -88,8 +90,9 @@ FrameOffset Linkage::GetFrameOffset(int spill_slot, Frame* frame, } -CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count) const { - return GetJSCallDescriptor(parameter_count, zone_); +CallDescriptor* Linkage::GetJSCallDescriptor( + int parameter_count, CallDescriptor::Flags flags) const { + return GetJSCallDescriptor(parameter_count, zone_, flags); } diff --git a/src/compiler/linkage.h b/src/compiler/linkage.h index d11fa12468..60a21425ee 100644 --- a/src/compiler/linkage.h +++ b/src/compiler/linkage.h @@ -174,8 +174,10 @@ class Linkage : public ZoneObject { // The call descriptor for this compilation unit describes the locations // of incoming parameters and the outgoing return value(s). CallDescriptor* GetIncomingDescriptor() const { return incoming_; } - CallDescriptor* GetJSCallDescriptor(int parameter_count) const; - static CallDescriptor* GetJSCallDescriptor(int parameter_count, Zone* zone); + CallDescriptor* GetJSCallDescriptor(int parameter_count, + CallDescriptor::Flags flags) const; + static CallDescriptor* GetJSCallDescriptor(int parameter_count, Zone* zone, + CallDescriptor::Flags flags); CallDescriptor* GetRuntimeCallDescriptor( Runtime::FunctionId function, int parameter_count, Operator::Properties properties) const; diff --git a/src/compiler/mips/linkage-mips.cc b/src/compiler/mips/linkage-mips.cc index 91fe9c3d5f..d4ec1902e1 100644 --- a/src/compiler/mips/linkage-mips.cc +++ b/src/compiler/mips/linkage-mips.cc @@ -35,8 +35,9 @@ struct MipsLinkageHelperTraits { typedef LinkageHelper LH; -CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) { - return LH::GetJSCallDescriptor(zone, parameter_count); +CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone, + CallDescriptor::Flags flags) { + return LH::GetJSCallDescriptor(zone, parameter_count, flags); } diff --git a/src/compiler/raw-machine-assembler.cc b/src/compiler/raw-machine-assembler.cc index 1d8b187b0f..a8b658f963 100644 --- a/src/compiler/raw-machine-assembler.cc +++ b/src/compiler/raw-machine-assembler.cc @@ -99,7 +99,8 @@ Node* RawMachineAssembler::CallFunctionStub0(Node* function, Node* receiver, Node* RawMachineAssembler::CallJS0(Node* function, Node* receiver, Node* context, Node* frame_state) { - CallDescriptor* descriptor = Linkage::GetJSCallDescriptor(1, zone()); + CallDescriptor* descriptor = + Linkage::GetJSCallDescriptor(1, zone(), CallDescriptor::kNeedsFrameState); Node* call = graph()->NewNode(common()->Call(descriptor), function, receiver, context, frame_state); schedule()->AddNode(CurrentBlock(), call); diff --git a/src/compiler/x64/linkage-x64.cc b/src/compiler/x64/linkage-x64.cc index 0638591354..7bf2c78579 100644 --- a/src/compiler/x64/linkage-x64.cc +++ b/src/compiler/x64/linkage-x64.cc @@ -49,8 +49,9 @@ struct X64LinkageHelperTraits { typedef LinkageHelper LH; -CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) { - return LH::GetJSCallDescriptor(zone, parameter_count); +CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone, + CallDescriptor::Flags flags) { + return LH::GetJSCallDescriptor(zone, parameter_count, flags); } diff --git a/test/cctest/compiler/test-linkage.cc b/test/cctest/compiler/test-linkage.cc index 267d464f89..0d5ee8f754 100644 --- a/test/cctest/compiler/test-linkage.cc +++ b/test/cctest/compiler/test-linkage.cc @@ -90,7 +90,8 @@ TEST(TestLinkageJSCall) { Linkage linkage(info.zone(), &info); for (int i = 0; i < 32; i++) { - CallDescriptor* descriptor = linkage.GetJSCallDescriptor(i); + CallDescriptor* descriptor = + linkage.GetJSCallDescriptor(i, CallDescriptor::kNoFlags); CHECK_NE(NULL, descriptor); CHECK_EQ(i, descriptor->JSParameterCount()); CHECK_EQ(1, descriptor->ReturnCount());