mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 15:29:45 +00:00
[dart2js] Do more native method inlining
Check if the call is typesafe instead of inlining only when type checks are disabled. Change-Id: Ie391bd7013941ffd3852fb8e2421e8827f41b6d0 Reviewed-on: https://dart-review.googlesource.com/c/89926 Commit-Queue: Stephen Adams <sra@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
parent
f353719b08
commit
1020a22290
|
@ -7,6 +7,7 @@ library dart2js.abstract_value_domain;
|
|||
import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue;
|
||||
import '../elements/entities.dart';
|
||||
import '../elements/names.dart';
|
||||
import '../elements/types.dart' show DartType;
|
||||
import '../serialization/serialization.dart';
|
||||
import '../universe/selector.dart';
|
||||
import '../universe/world_builder.dart';
|
||||
|
@ -477,6 +478,11 @@ abstract class AbstractValueDomain {
|
|||
AbstractBool needsNoSuchMethodHandling(
|
||||
AbstractValue receiver, Selector selector);
|
||||
|
||||
/// Returns the [AbstractValue] for the [parameterType] of a native
|
||||
/// method. May return `null`, for example, if [parameterType] is not modelled
|
||||
/// precisely by an [AbstractValue].
|
||||
AbstractValue getAbstractValueForNativeMethodParameterType(DartType type);
|
||||
|
||||
/// Returns an [AbstractBool] that describes if the set of runtime values of
|
||||
/// [subset] are known to all be in the set of runtime values of [superset].
|
||||
AbstractBool contains(AbstractValue superset, AbstractValue subset);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue;
|
||||
import '../elements/entities.dart';
|
||||
import '../elements/names.dart';
|
||||
import '../elements/types.dart' show DartType;
|
||||
import '../serialization/serialization.dart';
|
||||
import '../universe/selector.dart';
|
||||
import '../universe/world_builder.dart';
|
||||
|
@ -169,6 +170,10 @@ class TrivialAbstractValueDomain implements AbstractValueDomain {
|
|||
AbstractValue computeAbstractValueForConstant(ConstantValue value) =>
|
||||
const TrivialAbstractValue();
|
||||
|
||||
@override
|
||||
AbstractValue getAbstractValueForNativeMethodParameterType(DartType type) =>
|
||||
null;
|
||||
|
||||
@override
|
||||
AbstractBool containsAll(AbstractValue a) => AbstractBool.Maybe;
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import '../../common_elements.dart' show CommonElements;
|
|||
import '../../constants/values.dart';
|
||||
import '../../elements/entities.dart';
|
||||
import '../../elements/names.dart';
|
||||
import '../../elements/types.dart' show DartType, InterfaceType, DynamicType;
|
||||
import '../../serialization/serialization.dart';
|
||||
import '../../universe/class_hierarchy.dart';
|
||||
import '../../universe/selector.dart' show Selector;
|
||||
|
@ -774,6 +775,20 @@ class CommonMasks implements AbstractValueDomain {
|
|||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
AbstractValue getAbstractValueForNativeMethodParameterType(DartType type) {
|
||||
if (type is InterfaceType) {
|
||||
if (type.typeArguments.isNotEmpty) return null;
|
||||
// TODO(sra): Consider using a strengthened type check to avoid passing
|
||||
// `null` to primitive types since the native methods usually have
|
||||
// non-nullable primitive parameter types.
|
||||
return createNullableSubtype(type.element);
|
||||
}
|
||||
if (type is DynamicType) return dynamicType;
|
||||
// TODO(sra): Convert other [DartType]s to [AbstractValue]s
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String getCompactText(AbstractValue value) {
|
||||
return formatType(value);
|
||||
|
|
|
@ -14,7 +14,6 @@ import '../elements/entities.dart';
|
|||
import '../elements/types.dart';
|
||||
import '../inferrer/abstract_value_domain.dart';
|
||||
import '../inferrer/types.dart';
|
||||
//import '../js/js.dart' as js;
|
||||
import '../js_backend/allocator_analysis.dart' show JAllocatorAnalysis;
|
||||
import '../js_backend/backend.dart';
|
||||
import '../js_backend/native_data.dart' show NativeData;
|
||||
|
@ -755,50 +754,50 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
|||
|
||||
HInstruction tryInlineNativeMethod(
|
||||
HInvokeDynamicMethod node, FunctionEntity method) {
|
||||
// Enable direct calls to a native method only if we don't run in checked
|
||||
// mode, where the Dart version may have type annotations on parameters and
|
||||
// return type that it should check.
|
||||
// Also check that the parameters are not functions: it's the callee that
|
||||
// will translate them to JS functions.
|
||||
//
|
||||
// TODO(ngeoffray): There are some cases where we could still inline in
|
||||
// checked mode if we know the arguments have the right type. And we could
|
||||
// do the closure conversion as well as the return type annotation check.
|
||||
|
||||
// We can replace the call to the native class interceptor method (target)
|
||||
// if the target does no conversions or useful type checks.
|
||||
if (_options.disableInlining) return null;
|
||||
if (!node.isInterceptedCall) return null;
|
||||
|
||||
FunctionType type = _closedWorld.elementEnvironment.getFunctionType(method);
|
||||
if (type.namedParameters.isNotEmpty) return null;
|
||||
|
||||
// Return types on native methods don't need to be checked, since the
|
||||
// declaration has to be truthful.
|
||||
|
||||
// The call site might omit optional arguments. The inlined code must
|
||||
// preserve the number of arguments, so check only the actual arguments.
|
||||
|
||||
List<HInstruction> inputs = node.inputs.sublist(1);
|
||||
bool canInline = true;
|
||||
if (_options.parameterCheckPolicy.isEmitted && inputs.length > 1) {
|
||||
// TODO(sra): Check if [input] is guaranteed to pass the parameter
|
||||
// type check. Consider using a strengthened type check to avoid
|
||||
// passing `null` to primitive types since the native methods usually
|
||||
// have non-nullable primitive parameter types.
|
||||
canInline = false;
|
||||
} else {
|
||||
int inputPosition = 1; // Skip receiver.
|
||||
void checkParameterType(DartType type) {
|
||||
if (inputPosition++ < inputs.length && canInline) {
|
||||
if (type.unaliased.isFunctionType) {
|
||||
canInline = false;
|
||||
}
|
||||
}
|
||||
List<HInstruction> inputs = node.inputs;
|
||||
int inputPosition = 2; // Skip interceptor and receiver.
|
||||
|
||||
void checkParameterType(DartType parameterType) {
|
||||
if (!canInline) return;
|
||||
if (inputPosition >= inputs.length) return;
|
||||
HInstruction input = inputs[inputPosition++];
|
||||
if (parameterType.unaliased.isFunctionType) {
|
||||
// Must call the target since it contains a function conversion.
|
||||
canInline = false;
|
||||
return;
|
||||
}
|
||||
|
||||
type.parameterTypes.forEach(checkParameterType);
|
||||
type.optionalParameterTypes.forEach(checkParameterType);
|
||||
type.namedParameterTypes.forEach(checkParameterType);
|
||||
// If the target has no checks don't let a bad type stop us inlining.
|
||||
if (!_options.parameterCheckPolicy.isEmitted) return;
|
||||
|
||||
AbstractValue parameterAbstractValue = _abstractValueDomain
|
||||
.getAbstractValueForNativeMethodParameterType(parameterType);
|
||||
|
||||
if (parameterAbstractValue == null ||
|
||||
_abstractValueDomain
|
||||
.isIn(input.instructionType, parameterAbstractValue)
|
||||
.isPotentiallyFalse) {
|
||||
canInline = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
type.parameterTypes.forEach(checkParameterType);
|
||||
type.optionalParameterTypes.forEach(checkParameterType);
|
||||
assert(type.namedParameterTypes.isEmpty);
|
||||
|
||||
if (!canInline) return null;
|
||||
|
||||
// Strengthen instruction type from annotations to help optimize
|
||||
|
@ -809,7 +808,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
|||
HInvokeDynamicMethod result = new HInvokeDynamicMethod(
|
||||
node.selector,
|
||||
node.mask,
|
||||
inputs,
|
||||
inputs.sublist(1), // Drop interceptor.
|
||||
returnType,
|
||||
node.typeArguments,
|
||||
node.sourceInformation);
|
||||
|
|
Loading…
Reference in a new issue