Skip to content

Access markers for class properties (other than materializeForSet). #8771

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/SILGen/SILGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
/// \brief The current context where formal evaluation cleanups are managed.
FormalEvaluationContext FormalEvalContext;

/// \brief Values to end dynamic access enforcement on. A hack for
/// materializeForSet.
SmallVectorImpl<SILValue> *ValuesToEndAccessForMaterializeForSet = nullptr;

/// VarLoc - representation of an emitted local variable or constant. There
/// are three scenarios here:
///
Expand Down
118 changes: 73 additions & 45 deletions lib/SILGen/SILGenLValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,65 @@ namespace {
}
};

class EndAccessPseudoComponent : public WritebackPseudoComponent {
public:
EndAccessPseudoComponent(const LValueTypeData &typeData)
: WritebackPseudoComponent(typeData) {}

private:
void writeback(SILGenFunction &SGF, SILLocation loc,
ManagedValue base,
MaterializedLValue materialized,
bool isFinal) override {
assert(base.isLValue());
SGF.B.createEndAccess(loc, base.getValue(), /*abort*/ false);
}

void print(raw_ostream &OS) const override {
OS << "EndAccessPseudoComponent";
}
};
} // end anonymous namespace

static SILValue enterAccessScope(SILGenFunction &SGF, SILLocation loc,
SILValue addr, LValueTypeData typeData,
AccessKind accessKind,
SILAccessEnforcement enforcement) {
auto silAccessKind = [&] {
switch (accessKind) {
case AccessKind::Read:
return SILAccessKind::Read;
case AccessKind::Write:
case AccessKind::ReadWrite:
return SILAccessKind::Modify;
}
}();

// Hack for materializeForSet emission, where we can't safely
// push a begin/end access.
if (!SGF.InWritebackScope) {
assert(SGF.ValuesToEndAccessForMaterializeForSet);
if (enforcement == SILAccessEnforcement::Dynamic) {
// FIXME: begin access.
SGF.ValuesToEndAccessForMaterializeForSet->push_back(addr);
}
return addr;
}

// Enter the access.
addr = SGF.B.createBeginAccess(loc, addr, silAccessKind, enforcement);

// Push a writeback to end it.
auto accessedMV = ManagedValue::forLValue(addr);
std::unique_ptr<LogicalPathComponent>
component(new EndAccessPseudoComponent(typeData));
pushWriteback(SGF, loc, std::move(component), accessedMV,
MaterializedLValue());

return addr;
}

namespace {
class RefElementComponent : public PhysicalPathComponent {
VarDecl *Field;
SILType SubstFieldType;
Expand All @@ -399,9 +458,16 @@ namespace {
// Borrow the ref element addr using formal access. If we need the ref
// element addr, we will load it in this expression.
base = base.formalAccessBorrow(SGF, loc);
auto Res = SGF.B.createRefElementAddr(loc, base.getUnmanagedValue(),
Field, SubstFieldType);
return ManagedValue::forLValue(Res);
SILValue result =
SGF.B.createRefElementAddr(loc, base.getUnmanagedValue(),
Field, SubstFieldType);

if (auto enforcement = SGF.getDynamicEnforcement(Field)) {
result = enterAccessScope(SGF, loc, result, getTypeData(),
accessKind, *enforcement);
}

return ManagedValue::forLValue(result);
}

void print(raw_ostream &OS) const override {
Expand Down Expand Up @@ -517,25 +583,6 @@ namespace {
}
};

class EndAccessPseudoComponent : public WritebackPseudoComponent {
public:
EndAccessPseudoComponent(const LValueTypeData &typeData)
: WritebackPseudoComponent(typeData) {}

private:
void writeback(SILGenFunction &SGF, SILLocation loc,
ManagedValue base,
MaterializedLValue materialized,
bool isFinal) override {
assert(base.isLValue());
SGF.B.createEndAccess(loc, base.getValue(), /*abort*/ false);
}

void print(raw_ostream &OS) const override {
OS << "EndAccessPseudoComponent";
}
};

/// A physical path component which returns a literal address.
class ValueComponent : public PhysicalPathComponent {
ManagedValue Value;
Expand All @@ -560,30 +607,11 @@ namespace {
if (!Enforcement)
return Value;

assert(Value.isLValue() && "nonlvalue has enforcement?");
auto silAccessKind = [&] {
switch (accessKind) {
case AccessKind::Read:
return SILAccessKind::Read;
case AccessKind::Write:
case AccessKind::ReadWrite:
return SILAccessKind::Modify;
}
}();

// Enter the access.
auto accessedValue =
SGF.B.createBeginAccess(loc, Value.getValue(),
silAccessKind, *Enforcement);
auto accessedMV = ManagedValue::forLValue(accessedValue);

// Push a writeback to end it.
std::unique_ptr<LogicalPathComponent>
component(new EndAccessPseudoComponent(getTypeData()));
pushWriteback(SGF, loc, std::move(component), accessedMV,
MaterializedLValue());
SILValue addr = Value.getLValueAddress();
addr = enterAccessScope(SGF, loc, addr, getTypeData(),
accessKind, *Enforcement);

return ManagedValue::forLValue(accessedValue);
return ManagedValue::forLValue(addr);
}

bool isRValue() const override {
Expand Down
19 changes: 16 additions & 3 deletions lib/SILGen/SILGenMaterializeForSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,8 @@ struct MaterializeForSetEmitter {
void emit(SILGenFunction &gen);

SILValue emitUsingStorage(SILGenFunction &gen, SILLocation loc,
ManagedValue self, RValue &&indices);
ManagedValue self, RValue &&indices,
SILValue callbackBuffer, SILFunction *&callback);

SILValue emitUsingAddressor(SILGenFunction &gen, SILLocation loc,
ManagedValue self, RValue &&indices,
Expand Down Expand Up @@ -559,7 +560,8 @@ void MaterializeForSetEmitter::emit(SILGenFunction &gen) {
llvm_unreachable("materializeForSet should never engage in behavior init");

case AccessStrategy::Storage:
address = emitUsingStorage(gen, loc, self, std::move(indicesRV));
address = emitUsingStorage(gen, loc, self, std::move(indicesRV),
callbackBuffer, callbackFn);
break;

case AccessStrategy::Addressor:
Expand Down Expand Up @@ -730,11 +732,22 @@ SILFunction *MaterializeForSetEmitter::createCallback(SILFunction &F,
SILValue MaterializeForSetEmitter::emitUsingStorage(SILGenFunction &gen,
SILLocation loc,
ManagedValue self,
RValue &&indices) {
RValue &&indices,
SILValue callbackBuffer,
SILFunction *&callback) {
LValue lvalue = buildLValue(gen, loc, self, std::move(indices),
AccessKind::ReadWrite);

SmallVector<SILValue, 4> valuesToEndAccessOf;
gen.ValuesToEndAccessForMaterializeForSet = &valuesToEndAccessOf;

ManagedValue address =
gen.emitAddressOfLValue(loc, std::move(lvalue), AccessKind::ReadWrite);

if (!valuesToEndAccessOf.empty()) {
// FIXME: build callback to end access.
}

return address.getUnmanagedValue();
}

Expand Down
20 changes: 20 additions & 0 deletions test/SILGen/access_marker_gen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,23 @@ public struct HasTwoStoredProperties {
f = g
}
}

class C {
final var x: Int = 0
}

func testClassInstanceProperties(c: C) {
let y = c.x
c.x = y
}
// CHECK-LABEL: sil hidden @_T017access_marker_gen27testClassInstancePropertiesyAA1CC1c_tF :
// CHECK: [[C:%.*]] = begin_borrow %0 : $C
// CHECK-NEXT: [[CX:%.*]] = ref_element_addr [[C]] : $C, #C.x
// CHECK-NEXT: [[ACCESS:%.*]] = begin_access [read] [dynamic] [[CX]] : $*Int
// CHECK-NEXT: [[Y:%.*]] = load [trivial] [[ACCESS]]
// CHECK-NEXT: end_access [[ACCESS]]
// CHECK: [[C:%.*]] = begin_borrow %0 : $C
// CHECK-NEXT: [[CX:%.*]] = ref_element_addr [[C]] : $C, #C.x
// CHECK-NEXT: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[CX]] : $*Int
// CHECK-NEXT: assign [[Y]] to [[ACCESS]]
// CHECK-NEXT: end_access [[ACCESS]]