blob: 2a63070cba064fee936eaa0584da1d8945f3e0b5 [file] [log] [blame]
// Copyright (c) 2013, 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 universe.side_effects;
import '../elements/entities.dart';
import '../serialization/serialization.dart';
class SideEffects {
/// Tag used for identifying serialized [SideEffects] objects in a debugging
/// data stream.
static const String tag = 'side-effects';
// Changes flags.
static const int FLAG_CHANGES_INDEX = 0;
static const int FLAG_CHANGES_INSTANCE_PROPERTY = FLAG_CHANGES_INDEX + 1;
static const int FLAG_CHANGES_STATIC_PROPERTY =
FLAG_CHANGES_INSTANCE_PROPERTY + 1;
static const int FLAG_CHANGES_COUNT = FLAG_CHANGES_STATIC_PROPERTY + 1;
// Depends flags (one for each changes flag).
static const int FLAG_DEPENDS_ON_INDEX_STORE = FLAG_CHANGES_COUNT;
static const int FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE =
FLAG_DEPENDS_ON_INDEX_STORE + 1;
static const int FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE =
FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE + 1;
static const int FLAG_DEPENDS_ON_COUNT =
FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE + 1;
int _flags = 0;
SideEffects() {
setAllSideEffects();
setDependsOnSomething();
}
SideEffects.empty() {
clearAllDependencies();
clearAllSideEffects();
}
SideEffects.fromFlags(this._flags);
/// Deserializes a [SideEffects] object from [source].
factory SideEffects.readFromDataSource(DataSource source) {
source.begin(tag);
int flags = source.readInt();
source.end(tag);
return new SideEffects.fromFlags(flags);
}
/// Serializes this [SideEffects] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeInt(_flags);
sink.end(tag);
}
@override
bool operator ==(other) => _flags == other._flags;
@override
int get hashCode => throw new UnsupportedError('SideEffects.hashCode');
bool _getFlag(int position) {
return (_flags & (1 << position)) != 0;
}
bool _setFlag(int position) {
int before = _flags;
_flags |= (1 << position);
return before != _flags;
}
bool _clearFlag(int position) {
int before = _flags;
_flags &= ~(1 << position);
return before != _flags;
}
int getChangesFlags() {
return _flags & ((1 << FLAG_CHANGES_COUNT) - 1);
}
int getDependsOnFlags() {
return (_flags & ((1 << FLAG_DEPENDS_ON_COUNT) - 1)) >> FLAG_CHANGES_COUNT;
}
bool hasSideEffects() => getChangesFlags() != 0;
bool dependsOnSomething() => getDependsOnFlags() != 0;
bool setAllSideEffects() {
int before = _flags;
_flags |= ((1 << FLAG_CHANGES_COUNT) - 1);
return before != _flags;
}
bool clearAllSideEffects() {
int before = _flags;
_flags &= ~((1 << FLAG_CHANGES_COUNT) - 1);
return before != _flags;
}
bool setDependsOnSomething() {
int before = _flags;
int count = FLAG_DEPENDS_ON_COUNT - FLAG_CHANGES_COUNT;
_flags |= (((1 << count) - 1) << FLAG_CHANGES_COUNT);
return before != _flags;
}
bool clearAllDependencies() {
int before = _flags;
int count = FLAG_DEPENDS_ON_COUNT - FLAG_CHANGES_COUNT;
_flags &= ~(((1 << count) - 1) << FLAG_CHANGES_COUNT);
return before != _flags;
}
bool dependsOnStaticPropertyStore() {
return _getFlag(FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE);
}
bool setDependsOnStaticPropertyStore() {
return _setFlag(FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE);
}
bool clearDependsOnStaticPropertyStore() {
return _clearFlag(FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE);
}
bool setChangesStaticProperty() {
return _setFlag(FLAG_CHANGES_STATIC_PROPERTY);
}
bool clearChangesStaticProperty() {
return _clearFlag(FLAG_CHANGES_STATIC_PROPERTY);
}
bool changesStaticProperty() => _getFlag(FLAG_CHANGES_STATIC_PROPERTY);
bool dependsOnIndexStore() => _getFlag(FLAG_DEPENDS_ON_INDEX_STORE);
bool setDependsOnIndexStore() {
return _setFlag(FLAG_DEPENDS_ON_INDEX_STORE);
}
bool clearDependsOnIndexStore() {
return _clearFlag(FLAG_DEPENDS_ON_INDEX_STORE);
}
bool setChangesIndex() {
return _setFlag(FLAG_CHANGES_INDEX);
}
bool clearChangesIndex() {
return _clearFlag(FLAG_CHANGES_INDEX);
}
bool changesIndex() => _getFlag(FLAG_CHANGES_INDEX);
bool dependsOnInstancePropertyStore() {
return _getFlag(FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE);
}
bool setDependsOnInstancePropertyStore() {
return _setFlag(FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE);
}
bool clearDependsOnInstancePropertyStore() {
return _setFlag(FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE);
}
bool setChangesInstanceProperty() {
return _setFlag(FLAG_CHANGES_INSTANCE_PROPERTY);
}
bool clearChangesInstanceProperty() {
return _clearFlag(FLAG_CHANGES_INSTANCE_PROPERTY);
}
bool changesInstanceProperty() => _getFlag(FLAG_CHANGES_INSTANCE_PROPERTY);
static int computeDependsOnFlags(int flags) => flags << FLAG_CHANGES_COUNT;
bool dependsOn(int dependsFlags) {
return (_flags & dependsFlags) != 0;
}
bool add(SideEffects other) {
int before = _flags;
_flags |= other._flags;
return before != _flags;
}
void setTo(SideEffects other) {
_flags = other._flags;
}
bool contains(SideEffects other) {
return (_flags | other._flags) == _flags;
}
int get flags => _flags;
@override
String toString() {
StringBuffer buffer = new StringBuffer();
buffer.write('SideEffects(reads');
if (!dependsOnSomething()) {
buffer.write(' nothing');
} else if (dependsOnIndexStore() &&
dependsOnInstancePropertyStore() &&
dependsOnStaticPropertyStore()) {
buffer.write(' anything');
} else {
String comma = '';
if (dependsOnIndexStore()) {
buffer.write(' index');
comma = ',';
}
if (dependsOnInstancePropertyStore()) {
buffer.write('$comma field');
comma = ',';
}
if (dependsOnStaticPropertyStore()) {
buffer.write('$comma static');
}
}
buffer.write('; writes');
if (!hasSideEffects()) {
buffer.write(' nothing');
} else if (changesIndex() &&
changesInstanceProperty() &&
changesStaticProperty()) {
buffer.write(' anything');
} else {
String comma = '';
if (changesIndex()) {
buffer.write(' index');
comma = ',';
}
if (changesInstanceProperty()) {
buffer.write('$comma field');
comma = ',';
}
if (changesStaticProperty()) {
buffer.write('$comma static');
}
}
buffer.write(')');
return buffer.toString();
}
}
class SideEffectsBuilder {
final MemberEntity _member;
final SideEffects _sideEffects = new SideEffects.empty();
final bool _free;
Set<SideEffectsBuilder> _depending;
SideEffectsBuilder(this._member) : _free = false;
SideEffectsBuilder.free(this._member) : _free = true;
void setChangesInstanceProperty() {
if (_free) return;
_sideEffects.setChangesInstanceProperty();
}
void setDependsOnInstancePropertyStore() {
if (_free) return;
_sideEffects.setDependsOnInstancePropertyStore();
}
void setChangesStaticProperty() {
if (_free) return;
_sideEffects.setChangesStaticProperty();
}
void setDependsOnStaticPropertyStore() {
if (_free) return;
_sideEffects.setDependsOnStaticPropertyStore();
}
void setAllSideEffectsAndDependsOnSomething() {
if (_free) return;
_sideEffects.setAllSideEffects();
_sideEffects.setDependsOnSomething();
}
void setAllSideEffects() {
if (_free) return;
_sideEffects.setAllSideEffects();
}
void addInput(SideEffectsBuilder input) {
if (_free) return;
(input._depending ??= new Set<SideEffectsBuilder>()).add(this);
}
bool add(SideEffects input) {
if (_free) return false;
return _sideEffects.add(input);
}
SideEffects get sideEffects => _sideEffects;
Iterable<SideEffectsBuilder> get depending =>
_depending != null ? _depending : const <SideEffectsBuilder>[];
MemberEntity get member => _member;
@override
String toString() {
StringBuffer sb = new StringBuffer();
sb.write('SideEffectsBuilder(member=$member,');
sb.write('free=$_free,');
sb.write('sideEffects=$sideEffects,');
sb.write('depending=${depending.map((s) => s.member).join(',')},');
return sb.toString();
}
}