Commit 6e5b9ffe authored by bmeurer's avatar bmeurer Committed by Commit bot

[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}
parent 3938956b
......@@ -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<int>(p.arity() - 2);
// Check the function is a constant and is really a JSFunction.
HeapObjectMatcher<Object> function_const(node->InputAt(0));
if (!function_const.HasValue()) return false; // not a constant.
Handle<Object> func = function_const.Value().handle();
if (!func->IsJSFunction()) return false; // not a function.
Handle<JSFunction> function = Handle<JSFunction>::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<Context>(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<int>(p.arity() - 2);
CallFunctionStub stub(isolate(), arg_count, p.flags());
......
......@@ -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_; }
......
......@@ -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<int>(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:
......
......@@ -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);
......
......@@ -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<Object> 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<Type*>(arity);
std::fill(&params[0], &params[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) \
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment