From: bmeurer Date: Mon, 15 Jun 2015 14:06:11 +0000 (-0700) Subject: [turbofan] Remove the TryLowerDirectJSCall hack from generic lowering. X-Git-Tag: upstream/4.7.83~2012 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6e5b9ffe4c4691570835607a99bc979f0e7cf3fc;p=platform%2Fupstream%2Fv8.git [turbofan] Remove the TryLowerDirectJSCall hack from generic lowering. The TryLowerDirectJSCall method tried to lower to a direct JavaScript function call depending on the type of the receiver, but only if the target is a cosntant JSFunction. Since this depends on types and is not required for correctness, it shouldn't be part of generic lowering anyway. So this functionality was moved to typed lowering instead, and we use proper types for the target instead. R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1182193005 Cr-Commit-Position: refs/heads/master@{#29028} --- diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc index 322654c..51b4f10 100644 --- a/src/compiler/js-generic-lowering.cc +++ b/src/compiler/js-generic-lowering.cc @@ -514,44 +514,7 @@ void JSGenericLowering::LowerJSCallConstruct(Node* node) { } -bool JSGenericLowering::TryLowerDirectJSCall(Node* node) { - // Lower to a direct call to a constant JSFunction if legal. - const CallFunctionParameters& p = CallFunctionParametersOf(node->op()); - 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()->internal_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; - - // Update to the function context. - NodeProperties::ReplaceContextInput( - node, jsgraph()->HeapConstant(Handle(function->context()))); - CallDescriptor::Flags flags = FlagsForNode(node); - if (is_strict(p.language_mode())) flags |= CallDescriptor::kSupportsTailCalls; - CallDescriptor* desc = - Linkage::GetJSCallDescriptor(zone(), false, 1 + arg_count, flags); - node->set_op(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()); diff --git a/src/compiler/js-generic-lowering.h b/src/compiler/js-generic-lowering.h index 89467db..9811ba8 100644 --- a/src/compiler/js-generic-lowering.h +++ b/src/compiler/js-generic-lowering.h @@ -41,9 +41,6 @@ class JSGenericLowering final : public Reducer { void ReplaceWithBuiltinCall(Node* node, Builtins::JavaScript id, int args); void ReplaceWithRuntimeCall(Node* node, Runtime::FunctionId f, int args = -1); - // Helper for optimization of JSCallFunction. - bool TryLowerDirectJSCall(Node* node); - Zone* zone() const; Isolate* isolate() const; JSGraph* jsgraph() const { return jsgraph_; } diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc index f3b8012..94fae66 100644 --- a/src/compiler/js-typed-lowering.cc +++ b/src/compiler/js-typed-lowering.cc @@ -1263,6 +1263,39 @@ Reduction JSTypedLowering::ReduceJSCreateBlockContext(Node* node) { } +Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) { + DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); + CallFunctionParameters const& p = CallFunctionParametersOf(node->op()); + int const arity = static_cast(p.arity() - 2); + Node* const function = NodeProperties::GetValueInput(node, 0); + Type* const function_type = NodeProperties::GetBounds(function).upper; + Node* const receiver = NodeProperties::GetValueInput(node, 1); + Type* const receiver_type = NodeProperties::GetBounds(receiver).upper; + Node* const effect = NodeProperties::GetEffectInput(node); + Node* const control = NodeProperties::GetControlInput(node); + + // Check that {function} is actually a JSFunction with the correct arity. + if (function_type->IsFunction() && + function_type->AsFunction()->Arity() == arity) { + // Check that the {receiver} doesn't need to be wrapped. + if (receiver_type->Is(Type::ReceiverOrUndefined())) { + Node* const context = graph()->NewNode( + simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), + function, effect, control); + NodeProperties::ReplaceContextInput(node, context); + CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState; + if (is_strict(p.language_mode())) { + flags |= CallDescriptor::kSupportsTailCalls; + } + node->set_op(common()->Call(Linkage::GetJSCallDescriptor( + graph()->zone(), false, 1 + arity, flags))); + return Changed(node); + } + } + return NoChange(); +} + + Reduction JSTypedLowering::ReduceJSForInDone(Node* node) { DCHECK_EQ(IrOpcode::kJSForInDone, node->opcode()); node->set_op(machine()->Word32Equal()); @@ -1631,6 +1664,8 @@ Reduction JSTypedLowering::Reduce(Node* node) { return ReduceJSCreateWithContext(node); case IrOpcode::kJSCreateBlockContext: return ReduceJSCreateBlockContext(node); + case IrOpcode::kJSCallFunction: + return ReduceJSCallFunction(node); case IrOpcode::kJSForInDone: return ReduceJSForInDone(node); case IrOpcode::kJSForInNext: diff --git a/src/compiler/js-typed-lowering.h b/src/compiler/js-typed-lowering.h index 260c900..63c1da9 100644 --- a/src/compiler/js-typed-lowering.h +++ b/src/compiler/js-typed-lowering.h @@ -61,6 +61,7 @@ class JSTypedLowering final : public AdvancedReducer { Reduction ReduceJSCreateLiteralObject(Node* node); Reduction ReduceJSCreateWithContext(Node* node); Reduction ReduceJSCreateBlockContext(Node* node); + Reduction ReduceJSCallFunction(Node* node); Reduction ReduceJSForInDone(Node* node); Reduction ReduceJSForInNext(Node* node); Reduction ReduceJSForInPrepare(Node* node); diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 0f6c4d1..aeacad5 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -26,6 +26,10 @@ namespace compiler { V(Float64) enum LazyCachedType { + kAnyFunc0, + kAnyFunc1, + kAnyFunc2, + kAnyFunc3, kNumberFunc0, kNumberFunc1, kNumberFunc2, @@ -78,6 +82,15 @@ class LazyTypeCache final : public ZoneObject { return CreateNative(Type::Number(), Type::UntaggedFloat64()); case kUint8Clamped: return Get(kUint8); + case kAnyFunc0: + return Type::Function(Type::Any(), zone()); + case kAnyFunc1: + return Type::Function(Type::Any(), Type::Any(), zone()); + case kAnyFunc2: + return Type::Function(Type::Any(), Type::Any(), Type::Any(), zone()); + case kAnyFunc3: + return Type::Function(Type::Any(), Type::Any(), Type::Any(), + Type::Any(), zone()); case kNumberFunc0: return Type::Function(Type::Number(), zone()); case kNumberFunc1: @@ -2393,6 +2406,23 @@ Type* Typer::Visitor::TypeConstant(Handle value) { return typer_->cache_->Get(kFloat64ArrayFunc); } } + int const arity = + JSFunction::cast(*value)->shared()->internal_formal_parameter_count(); + switch (arity) { + case 0: + return typer_->cache_->Get(kAnyFunc0); + case 1: + return typer_->cache_->Get(kAnyFunc1); + case 2: + return typer_->cache_->Get(kAnyFunc2); + case 3: + return typer_->cache_->Get(kAnyFunc3); + default: { + Type** const params = zone()->NewArray(arity); + std::fill(¶ms[0], ¶ms[arity], Type::Any(zone())); + return Type::Function(Type::Any(zone()), arity, params, zone()); + } + } } else if (value->IsJSTypedArray()) { switch (JSTypedArray::cast(*value)->type()) { #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ diff --git a/src/types.h b/src/types.h index 8f80624..228b6d0 100644 --- a/src/types.h +++ b/src/types.h @@ -233,6 +233,7 @@ namespace internal { V(Detectable, kDetectableReceiver | kNumber | kName) \ V(Object, kDetectableObject | kUndetectable) \ V(Receiver, kObject | kProxy) \ + V(ReceiverOrUndefined, kReceiver | kUndefined) \ V(StringOrReceiver, kString | kReceiver) \ V(Unique, kBoolean | kUniqueName | kNull | kUndefined | \ kReceiver) \ @@ -410,6 +411,14 @@ class TypeImpl : public Config::Base { function->InitParameter(2, param2); return function; } + static TypeHandle Function(TypeHandle result, int arity, TypeHandle* params, + Region* region) { + FunctionHandle function = Function(result, Any(region), arity, region); + for (int i = 0; i < arity; ++i) { + function->InitParameter(i, params[i]); + } + return function; + } static TypeHandle Union(TypeHandle type1, TypeHandle type2, Region* reg); static TypeHandle Intersect(TypeHandle type1, TypeHandle type2, Region* reg);