// 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/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)';
}
