Commit dc3c8481 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Introduce a Function type and optimize based on it.

This inserts a new bit set type Function, which is used to represent
JSFunctions, and uses that type in typed lowering to optimize calls
to use the CallFunction builtin directly. Also allows for better typing
of the typeof operator, which can infern "function" for JSFunctions
properly.

R=jarin@chromium.org

Review URL: https://codereview.chromium.org/1410343016

Cr-Commit-Position: refs/heads/master@{#31827}
parent 4ab1b05d
......@@ -298,6 +298,13 @@ Callable CodeFactory::Call(Isolate* isolate) {
}
// static
Callable CodeFactory::CallFunction(Isolate* isolate) {
return Callable(isolate->builtins()->CallFunction(),
CallTrampolineDescriptor(isolate));
}
// static
Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate) {
return Callable(isolate->builtins()->InterpreterPushArgsAndCall(),
......
......@@ -97,6 +97,7 @@ class CodeFactory final {
static Callable ArgumentAdaptor(Isolate* isolate);
static Callable Call(Isolate* isolate);
static Callable CallFunction(Isolate* isolate);
static Callable InterpreterPushArgsAndCall(Isolate* isolate);
static Callable InterpreterPushArgsAndConstruct(Isolate* isolate);
......
......@@ -1633,6 +1633,29 @@ Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
return Changed(node);
}
// Check if {target} is a JSFunction.
if (target_type->Is(Type::Function())) {
// Remove the eager bailout frame state.
NodeProperties::RemoveFrameStateInput(node, 1);
// Compute flags for the call.
CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
if (p.tail_call_mode() == TailCallMode::kAllow) {
flags |= CallDescriptor::kSupportsTailCalls;
}
// Patch {node} to an indirect call via the CallFunction builtin.
Callable callable = CodeFactory::CallFunction(isolate());
node->InsertInput(graph()->zone(), 0,
jsgraph()->HeapConstant(callable.code()));
node->InsertInput(graph()->zone(), 2, jsgraph()->Int32Constant(arity));
NodeProperties::ChangeOp(
node, common()->Call(Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
flags)));
return Changed(node);
}
return NoChange();
}
......
......@@ -1161,6 +1161,8 @@ Type* Typer::Visitor::JSTypeOfTyper(Type* type, Typer* t) {
return Type::Constant(f->undefined_string(), t->zone());
} else if (type->Is(Type::Null())) {
return Type::Constant(f->object_string(), t->zone());
} else if (type->Is(Type::Function())) {
return Type::Constant(f->function_string(), t->zone());
} else if (type->IsConstant()) {
return Type::Constant(
Object::TypeOf(t->isolate(), type->AsConstant()->Value()), t->zone());
......
......@@ -173,7 +173,7 @@ TypeImpl<Config>::BitsetType::Lub(TypeImpl* type) {
if (type->IsRange()) return type->AsRange()->Lub();
if (type->IsContext()) return kInternal & kTaggedPointer;
if (type->IsArray()) return kOtherObject;
if (type->IsFunction()) return kOtherObject; // TODO(rossberg): kFunction
if (type->IsFunction()) return kFunction;
UNREACHABLE();
return kNone;
}
......@@ -247,7 +247,8 @@ TypeImpl<Config>::BitsetType::Lub(i::Map* map) {
if (map->is_undetectable()) return kUndetectable;
return kOtherObject;
case JS_FUNCTION_TYPE:
return kOtherObject; // TODO(rossberg): there should be a Function type.
if (map->is_undetectable()) return kUndetectable;
return kFunction;
case JS_REGEXP_TYPE:
return kOtherObject; // TODO(rossberg): there should be a RegExp type.
case JS_PROXY_TYPE:
......
......@@ -159,8 +159,8 @@ namespace internal {
// clang-format off
#define MASK_BITSET_TYPE_LIST(V) \
V(Representation, 0xfff00000u) \
V(Semantic, 0x000ffffeu)
V(Representation, 0xff800000u) \
V(Semantic, 0x007ffffeu)
#define REPRESENTATION(k) ((k) & BitsetType::kRepresentation)
#define SEMANTIC(k) ((k) & BitsetType::kSemantic)
......@@ -205,7 +205,8 @@ namespace internal {
V(Undetectable, 1u << 16 | REPRESENTATION(kTaggedPointer)) \
V(OtherObject, 1u << 17 | REPRESENTATION(kTaggedPointer)) \
V(Proxy, 1u << 18 | REPRESENTATION(kTaggedPointer)) \
V(Internal, 1u << 19 | REPRESENTATION(kTagged | kUntagged)) \
V(Function, 1u << 19 | REPRESENTATION(kTaggedPointer)) \
V(Internal, 1u << 20 | REPRESENTATION(kTagged | kUntagged)) \
\
V(Signed31, kUnsigned30 | kNegative31) \
V(Signed32, kSigned31 | kOtherUnsigned31 | kOtherSigned32) \
......@@ -226,11 +227,10 @@ namespace internal {
V(NumberOrUndefined, kNumber | kUndefined) \
V(PlainPrimitive, kNumberOrString | kBoolean | kNullOrUndefined) \
V(Primitive, kSymbol | kSimd | kPlainPrimitive) \
V(DetectableReceiver, kOtherObject | kProxy) \
V(DetectableReceiver, kFunction | kOtherObject | kProxy) \
V(Detectable, kDetectableReceiver | kNumber | kName) \
V(Object, kOtherObject | kUndetectable) \
V(Object, kFunction | kOtherObject | kUndetectable) \
V(Receiver, kObject | kProxy) \
V(ReceiverOrUndefined, kReceiver | kUndefined) \
V(StringOrReceiver, kString | kReceiver) \
V(Unique, kBoolean | kUniqueName | kNull | kUndefined | \
kReceiver) \
......
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