// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// @dart = 2.10

library js_backend.interceptor_data;

import '../common/elements.dart'
    show CommonElements, KCommonElements, KElementEnvironment;
import '../common/names.dart' show Identifiers;
import '../elements/entities.dart';
import '../elements/types.dart';
import '../inferrer/abstract_value_domain.dart';
import '../js/js.dart' as jsAst;
import '../serialization/serialization.dart';
import '../universe/class_set.dart';
import '../universe/selector.dart';
import '../world.dart' show JClosedWorld;
import 'namer.dart' show ModularNamer, suffixForGetInterceptor;
import 'native_data.dart';

abstract class InterceptorData {
  /// Deserializes a [InterceptorData] object from [source].
  factory InterceptorData.readFromDataSource(
      DataSourceReader source,
      NativeData nativeData,
      CommonElements commonElements) = InterceptorDataImpl.readFromDataSource;

  /// Serializes this [InterceptorData] to [sink].
  void writeToDataSink(DataSinkWriter sink);

  /// Returns `true` if [cls] is an intercepted class.
  bool isInterceptedClass(ClassEntity element);

  bool isInterceptedMethod(MemberEntity element);
  bool fieldHasInterceptedGetter(FieldEntity element);
  bool fieldHasInterceptedSetter(FieldEntity element);
  bool isInterceptedName(String name);
  bool isInterceptedSelector(Selector selector);

  /// Returns `true` iff [selector] matches an element defined in a class mixed
  /// into an intercepted class.
  ///
  /// These selectors are not eligible for the 'dummy explicit receiver'
  /// optimization.
  bool isInterceptedMixinSelector(
      Selector selector, AbstractValue mask, JClosedWorld closedWorld);

  /// Set of classes whose methods are intercepted.
  Iterable<ClassEntity> get interceptedClasses;
  bool isMixedIntoInterceptedClass(ClassEntity element);

  /// Returns a set of interceptor classes that contain a member named [name]
  ///
  /// Returns an empty set if there is no class. Do not modify the returned set.
  Set<ClassEntity> getInterceptedClassesOn(
      String name, JClosedWorld closedWorld);

  /// Whether the compiler can use the native `instanceof` check to test for
  /// instances of [type]. This is true for types that are not used as mixins or
  /// interfaces.
  bool mayGenerateInstanceofCheck(DartType type, JClosedWorld closedWorld);
}

abstract class InterceptorDataBuilder {
  void addInterceptors(ClassEntity cls);
  void addInterceptorsForNativeClassMembers(ClassEntity cls);
  InterceptorData close();
}

class InterceptorDataImpl implements InterceptorData {
  /// Tag used for identifying serialized [InterceptorData] objects in a
  /// debugging data stream.
  static const String tag = 'interceptor-data';

  final NativeBasicData _nativeData;
  final CommonElements _commonElements;

  /// The members of instantiated interceptor classes: maps a member name to the
  /// list of members that have that name. This map is used by the codegen to
  /// know whether a send must be intercepted or not.
  final Map<String, Set<MemberEntity>> interceptedMembers;

  @override
  final Set<ClassEntity> interceptedClasses;

  /// Set of classes used as mixins on intercepted (native and primitive)
  /// classes. Methods on these classes might also be mixed in to regular Dart
  /// (unintercepted) classes.
  final Set<ClassEntity> classesMixedIntoInterceptedClasses;

  /// The members of mixin classes that are mixed into an instantiated
  /// interceptor class.  This is a cached subset of [_interceptedElements].
  ///
  /// Mixin methods are not specialized for the class they are mixed into.
  /// Methods mixed into intercepted classes thus always make use of the
  /// explicit receiver argument, even when mixed into non-interceptor classes.
  ///
  /// These members must be invoked with a correct explicit receiver even when
  /// the receiver is not an intercepted class.
  final Map<String, Set<MemberEntity>> _interceptedMixinElements = {};

  final Map<String, Set<ClassEntity>> _interceptedClassesCache = {};

  final Set<ClassEntity> _noClasses = {};

  InterceptorDataImpl(
      this._nativeData,
      this._commonElements,
      this.interceptedMembers,
      this.interceptedClasses,
      this.classesMixedIntoInterceptedClasses);

  factory InterceptorDataImpl.readFromDataSource(DataSourceReader source,
      NativeData nativeData, CommonElements commonElements) {
    source.begin(tag);
    int interceptedMembersCount = source.readInt();
    Map<String, Set<MemberEntity>> interceptedMembers = {};
    for (int i = 0; i < interceptedMembersCount; i++) {
      String name = source.readString();
      Set<MemberEntity> members = source.readMembers().toSet();
      interceptedMembers[name] = members;
    }
    Set<ClassEntity> interceptedClasses = source.readClasses().toSet();
    Set<ClassEntity> classesMixedIntoInterceptedClasses =
        source.readClasses().toSet();
    source.end(tag);
    return InterceptorDataImpl(nativeData, commonElements, interceptedMembers,
        interceptedClasses, classesMixedIntoInterceptedClasses);
  }

  @override
  void writeToDataSink(DataSinkWriter sink) {
    sink.begin(tag);
    sink.writeInt(interceptedMembers.length);
    interceptedMembers.forEach((String name, Set<MemberEntity> members) {
      sink.writeString(name);
      sink.writeMembers(members);
    });
    sink.writeClasses(interceptedClasses);
    sink.writeClasses(classesMixedIntoInterceptedClasses);
    sink.end(tag);
  }

  @override
  bool isInterceptedMethod(MemberEntity element) {
    if (!element.isInstanceMember) return false;
    // TODO(johnniwinther): Avoid this hack.
    if (element is ConstructorBodyEntity) {
      return _nativeData.isNativeOrExtendsNative(element.enclosingClass);
    }
    return interceptedMembers[element.name] != null;
  }

  @override
  bool fieldHasInterceptedGetter(FieldEntity element) {
    return interceptedMembers[element.name] != null;
  }

  @override
  bool fieldHasInterceptedSetter(FieldEntity element) {
    return interceptedMembers[element.name] != null;
  }

  @override
  bool isInterceptedName(String name) {
    return interceptedMembers[name] != null;
  }

  @override
  bool isInterceptedSelector(Selector selector) {
    return interceptedMembers[selector.name] != null;
  }

  @override
  bool isInterceptedMixinSelector(
      Selector selector, AbstractValue mask, JClosedWorld closedWorld) {
    Set<MemberEntity> elements =
        _interceptedMixinElements.putIfAbsent(selector.name, () {
      Set<MemberEntity> elements = interceptedMembers[selector.name];
      if (elements == null) return null;
      return elements
          .where((element) => classesMixedIntoInterceptedClasses
              .contains(element.enclosingClass))
          .toSet();
    });

    if (elements == null) return false;
    if (elements.isEmpty) return false;
    return elements.any((element) {
      return selector.applies(element) &&
          (mask == null ||
              closedWorld.abstractValueDomain
                  .isTargetingMember(mask, element, selector.memberName)
                  .isPotentiallyTrue);
    });
  }

  /// True if the given class is an internal class used for type inference
  /// and never exists at runtime.
  bool _isCompileTimeOnlyClass(ClassEntity class_) {
    return class_ == _commonElements.jsPositiveIntClass ||
        class_ == _commonElements.jsUInt32Class ||
        class_ == _commonElements.jsUInt31Class ||
        class_ == _commonElements.jsFixedArrayClass ||
        class_ == _commonElements.jsUnmodifiableArrayClass ||
        class_ == _commonElements.jsMutableArrayClass ||
        class_ == _commonElements.jsExtendableArrayClass;
  }

  /// Returns a set of interceptor classes that contain a member named [name]
  ///
  /// Returns an empty set if there is no class. Do not modify the returned set.
  @override
  Set<ClassEntity> getInterceptedClassesOn(
      String name, JClosedWorld closedWorld) {
    Set<MemberEntity> intercepted = interceptedMembers[name];
    if (intercepted == null) return _noClasses;
    return _interceptedClassesCache.putIfAbsent(name, () {
      // Populate the cache by running through all the elements and
      // determine if the given selector applies to them.
      Set<ClassEntity> result = {};
      for (MemberEntity element in intercepted) {
        ClassEntity classElement = element.enclosingClass;
        if (_isCompileTimeOnlyClass(classElement)) continue;
        if (_nativeData.isNativeOrExtendsNative(classElement) ||
            interceptedClasses.contains(classElement)) {
          result.add(classElement);
        }
        if (classesMixedIntoInterceptedClasses.contains(classElement)) {
          Set<ClassEntity> nativeSubclasses =
              nativeSubclassesOfMixin(classElement, closedWorld);
          if (nativeSubclasses != null) result.addAll(nativeSubclasses);
        }
      }
      return result;
    });
  }

  Set<ClassEntity> nativeSubclassesOfMixin(
      ClassEntity mixin, JClosedWorld closedWorld) {
    Iterable<ClassEntity> uses = closedWorld.mixinUsesOf(mixin);
    Set<ClassEntity> result = null;
    for (ClassEntity use in uses) {
      closedWorld.classHierarchy.forEachStrictSubclassOf(use,
          (ClassEntity subclass) {
        if (_nativeData.isNativeOrExtendsNative(subclass)) {
          if (result == null) result = {};
          result.add(subclass);
        }
        return IterationStep.CONTINUE;
      });
    }
    return result;
  }

  @override
  bool isInterceptedClass(ClassEntity element) {
    if (element == null) return false;
    if (_nativeData.isNativeOrExtendsNative(element)) return true;
    if (interceptedClasses.contains(element)) return true;
    if (classesMixedIntoInterceptedClasses.contains(element)) return true;
    return false;
  }

  @override
  bool isMixedIntoInterceptedClass(ClassEntity element) =>
      classesMixedIntoInterceptedClasses.contains(element);

  @override
  bool mayGenerateInstanceofCheck(DartType type, JClosedWorld closedWorld) {
    // We can use an instanceof check for raw types that have no subclass that
    // is mixed-in or in an implements clause.

    if (!closedWorld.dartTypes.treatAsRawType(type)) return false;
    if (type is FutureOrType) return false;
    InterfaceType interfaceType = type;
    ClassEntity classElement = interfaceType.element;
    if (isInterceptedClass(classElement)) return false;
    return closedWorld.classHierarchy.hasOnlySubclasses(classElement);
  }
}

class InterceptorDataBuilderImpl implements InterceptorDataBuilder {
  final NativeBasicData _nativeData;
  final KElementEnvironment _elementEnvironment;
  final KCommonElements _commonElements;

  /// The members of instantiated interceptor classes: maps a member name to the
  /// list of members that have that name. This map is used by the codegen to
  /// know whether a send must be intercepted or not.
  final Map<String, Set<MemberEntity>> _interceptedElements = {};

  /// Set of classes whose methods are intercepted.
  final Set<ClassEntity> _interceptedClasses = {};

  /// Set of classes used as mixins on intercepted (native and primitive)
  /// classes. Methods on these classes might also be mixed in to regular Dart
  /// (unintercepted) classes.
  final Set<ClassEntity> _classesMixedIntoInterceptedClasses = {};

  InterceptorDataBuilderImpl(
      this._nativeData, this._elementEnvironment, this._commonElements);

  @override
  InterceptorData close() {
    return InterceptorDataImpl(
        _nativeData,
        _commonElements,
        _interceptedElements,
        _interceptedClasses,
        _classesMixedIntoInterceptedClasses);
  }

  @override
  void addInterceptorsForNativeClassMembers(ClassEntity cls) {
    _elementEnvironment.forEachClassMember(cls,
        (ClassEntity cls, MemberEntity member) {
      if (member.name == Identifiers.call) return;
      // All methods on [Object] are shadowed by [Interceptor].
      if (cls == _commonElements.objectClass) return;
      Set<MemberEntity> set = _interceptedElements[member.name] ??= {};
      set.add(member);
    });

    // Walk superclass chain to find mixins.
    _elementEnvironment.forEachMixin(cls, (ClassEntity mixin) {
      _classesMixedIntoInterceptedClasses.add(mixin);
    });
  }

  @override
  void addInterceptors(ClassEntity cls) {
    if (_interceptedClasses.add(cls)) {
      _elementEnvironment.forEachClassMember(cls,
          (ClassEntity cls, MemberEntity member) {
        // All methods on [Object] are shadowed by [Interceptor].
        if (cls == _commonElements.objectClass) return;
        Set<MemberEntity> set = _interceptedElements[member.name] ??= {};
        set.add(member);
      });
    }
    _interceptedClasses.add(_commonElements.jsInterceptorClass);
  }
}

class OneShotInterceptorData {
  final InterceptorData _interceptorData;
  final CommonElements _commonElements;
  final NativeData _nativeData;

  OneShotInterceptorData(
      this._interceptorData, this._commonElements, this._nativeData);

  Iterable<OneShotInterceptor> get oneShotInterceptors {
    List<OneShotInterceptor> interceptors = [];
    for (var map in _oneShotInterceptors.values) {
      interceptors.addAll(map.values);
    }
    return interceptors;
  }

  final Map<Selector, Map<String, OneShotInterceptor>> _oneShotInterceptors =
      {};

  /// A set of specialized versions of the [getInterceptorMethod].
  ///
  /// Since [getInterceptorMethod] is a hot method at runtime, we're always
  /// specializing it based on the incoming type. The keys in the map are the
  /// names of these specialized versions. Note that the generic version that
  /// contains all possible type checks is also stored in this map.
  Iterable<SpecializedGetInterceptor> get specializedGetInterceptors =>
      _specializedGetInterceptors.values;

  final Map<String, SpecializedGetInterceptor> _specializedGetInterceptors = {};

  jsAst.Name registerOneShotInterceptor(
      Selector selector, ModularNamer namer, JClosedWorld closedWorld) {
    selector = selector.toNormalized();
    Set<ClassEntity> classes =
        _interceptorData.getInterceptedClassesOn(selector.name, closedWorld);
    String key = suffixForGetInterceptor(_commonElements, _nativeData, classes);
    Map<String, OneShotInterceptor> interceptors =
        _oneShotInterceptors[selector] ??= {};
    OneShotInterceptor interceptor =
        interceptors[key] ??= OneShotInterceptor(key, selector);
    interceptor.classes.addAll(classes);
    registerSpecializedGetInterceptor(classes, namer);
    return namer.nameForOneShotInterceptor(selector, classes);
  }

  void registerSpecializedGetInterceptor(
      Set<ClassEntity> classes, ModularNamer namer) {
    if (classes.contains(_commonElements.jsInterceptorClass)) {
      // We can't use a specialized [getInterceptorMethod], so we make
      // sure we emit the one with all checks.
      classes = _interceptorData.interceptedClasses;
    }
    String key = suffixForGetInterceptor(_commonElements, _nativeData, classes);
    SpecializedGetInterceptor interceptor =
        _specializedGetInterceptors[key] ??= SpecializedGetInterceptor(key);
    interceptor.classes.addAll(classes);
  }
}

class OneShotInterceptor {
  final Selector selector;
  final String key;
  final Set<ClassEntity> classes = {};

  OneShotInterceptor(this.key, this.selector);

  @override
  String toString() =>
      'OneShotInterceptor(selector=$selector,key=$key,classes=$classes)';
}

class SpecializedGetInterceptor {
  final String key;
  final Set<ClassEntity> classes = {};

  SpecializedGetInterceptor(this.key);

  @override
  String toString() => 'SpecializedGetInterceptor(key=$key,classes=$classes)';
}
