}
-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());
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_; }
}
+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());
return ReduceJSCreateWithContext(node);
case IrOpcode::kJSCreateBlockContext:
return ReduceJSCreateBlockContext(node);
+ case IrOpcode::kJSCallFunction:
+ return ReduceJSCallFunction(node);
case IrOpcode::kJSForInDone:
return ReduceJSForInDone(node);
case IrOpcode::kJSForInNext:
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);
V(Float64)
enum LazyCachedType {
+ kAnyFunc0,
+ kAnyFunc1,
+ kAnyFunc2,
+ kAnyFunc3,
kNumberFunc0,
kNumberFunc1,
kNumberFunc2,
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:
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(¶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) \
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) \
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);