// 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.

library js_backend.interceptor_data;

import '../common/names.dart' show Identifiers;
import '../common_elements.dart'
    show CommonElements, KCommonElements, KElementEnvironment;
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/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(
      DataSource source,
      NativeData nativeData,
      CommonElements commonElements) = InterceptorDataImpl.readFromDataSource;

  /// Serializes this [InterceptorData] to [sink].
  void writeToDataSink(DataSink 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 =
      new Map<String, Set<MemberEntity>>();

  final Map<String, Set<ClassEntity>> _interceptedClassesCache =
      new Map<String, Set<ClassEntity>>();

  final Set<ClassEntity> _noClasses = new Set<ClassEntity>();

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

  factory InterceptorDataImpl.readFromDataSource(
      DataSource 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 new InterceptorDataImpl(
        nativeData,
        commonElements,
        interceptedMembers,
        interceptedClasses,
        classesMixedIntoInterceptedClasses);
  }

  @override
  void writeToDataSink(DataSink 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 = new Set<ClassEntity>();
      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 = new Set<ClassEntity>();
          result.add(subclass);
        }
      });
    }
    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 (!type.treatAsRaw) return false;
    if (type.isFutureOr) 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 =
      <String, Set<MemberEntity>>{};

  /// Set of classes whose methods are intercepted.
  final Set<ClassEntity> _interceptedClasses = new Set<ClassEntity>();

  /// 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 =
      new Set<ClassEntity>();

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

  @override
  InterceptorData close() {
    return new 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] ??= new Set<MemberEntity>();
      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] ??= new Set<MemberEntity>();
        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;
  }

  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;

  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.putIfAbsent(
        key, () => new OneShotInterceptor(key, selector));
    interceptor.classes.addAll(classes);
    registerSpecializedGetInterceptor(classes, namer);
    return namer.nameForGetOneShotInterceptor(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] ??= new 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)';
}
