Skip to content

Commit d6e0ca3

Browse files
[PlaygroundTransform] Add experimental feature PlaygroundExtendedCallbacks to pass more info in callbacks (#67215)
* Add experimental feature `PlaygroundExtendedCallbacks` which passes more information in `-playground` callbacks Adds the experimental feature `PlaygroundExtendedCallbacks` which (when `-playground` is also passed) causes the playground transform to use alternate forms of the result-value, scope-entry, and scope-exit callbacks that include the module name and file path of the source file. The previous callbacks included integers for the module number and file number, but this was cumbersome to use because it required the caller to create source symbols with magical names formed from the module name and file path that the playground transform knew how to look up. The extended callbacks in the experimental feature instead pass these strings as string literals. This is an experimental feature because of the need to measure the performance impact, and because of the need to provide an option to control which set of callbacks to use so that existing clients of the playground transform can opt into it when ready. It's also likely that we'll want to pass more information in the extended callbacks, such as an indication of the kind of result is being logged (e.g. a loop iteration variable vs a return statement vs a variable assignment). So this should be considered the first of a series of experimental improvements that will then be pitched as an actual, non-experimental v2.0 of the playground transform callback API. Because of the nature of how the playground transform is used, it's much easier to iterate on the functionality in the form of an experimental feature rather than using only desktop debug builds of the Swift compiler. Changes: - define a new experimental feature called `PlaygroundExtendedCallbacks` - modify the playground transform step in sema to pass the module name and file name literals when the experimental feature is set - add a unit test for the extended callbacks There is no change in behaviour when `PlaygroundExtendedCallbacks` is not enabled. rdar://109911742 Co-authored-by: Brent Shank <[email protected]>
1 parent c86ac86 commit d6e0ca3

File tree

5 files changed

+110
-8
lines changed

5 files changed

+110
-8
lines changed

include/swift/Basic/Features.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,10 @@ EXPERIMENTAL_FEATURE(StrictConcurrency, true)
220220
/// Defer Sendable checking to SIL diagnostic phase.
221221
EXPERIMENTAL_FEATURE(DeferredSendableChecking, false)
222222

223+
/// Enable extended callbacks (with additional parameters) to be used when the
224+
/// "playground transform" is enabled.
225+
EXPERIMENTAL_FEATURE(PlaygroundExtendedCallbacks, true)
226+
223227
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
224228
#undef EXPERIMENTAL_FEATURE
225229
#undef UPCOMING_FEATURE

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3480,6 +3480,10 @@ static bool usesFeatureDeferredSendableChecking(Decl *decl) {
34803480
return false;
34813481
}
34823482

3483+
static bool usesFeaturePlaygroundExtendedCallbacks(Decl *decl) {
3484+
return false;
3485+
}
3486+
34833487
/// Suppress the printing of a particular feature.
34843488
static void suppressingFeature(PrintOptions &options, Feature feature,
34853489
llvm::function_ref<void()> action) {

lib/Sema/PlaygroundTransform.cpp

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -41,13 +41,18 @@ class Instrumenter : InstrumenterBase {
4141
std::mt19937_64 &RNG;
4242
unsigned &TmpNameIndex;
4343
bool HighPerformance;
44+
bool ExtendedCallbacks;
4445

4546
DeclNameRef DebugPrintName;
4647
DeclNameRef PrintName;
4748
DeclNameRef PostPrintName;
49+
DeclNameRef PostPrintExtendedName;
4850
DeclNameRef LogWithIDName;
51+
DeclNameRef LogWithIDExtendedName;
4952
DeclNameRef LogScopeExitName;
53+
DeclNameRef LogScopeExitExtendedName;
5054
DeclNameRef LogScopeEntryName;
55+
DeclNameRef LogScopeEntryExtendedName;
5156
DeclNameRef SendDataName;
5257

5358
struct BracePair {
@@ -126,12 +131,17 @@ class Instrumenter : InstrumenterBase {
126131
unsigned &TmpNameIndex)
127132
: InstrumenterBase(C, DC), RNG(RNG), TmpNameIndex(TmpNameIndex),
128133
HighPerformance(HP),
134+
ExtendedCallbacks(C.LangOpts.hasFeature(Feature::PlaygroundExtendedCallbacks)),
129135
DebugPrintName(C.getIdentifier("__builtin_debugPrint")),
130136
PrintName(C.getIdentifier("__builtin_print")),
131137
PostPrintName(C.getIdentifier("__builtin_postPrint")),
138+
PostPrintExtendedName(C.getIdentifier("__builtin_postPrint_extended")),
132139
LogWithIDName(C.getIdentifier("__builtin_log_with_id")),
140+
LogWithIDExtendedName(C.getIdentifier("__builtin_log_with_id_extended")),
133141
LogScopeExitName(C.getIdentifier("__builtin_log_scope_exit")),
142+
LogScopeExitExtendedName(C.getIdentifier("__builtin_log_scope_exit_extended")),
134143
LogScopeEntryName(C.getIdentifier("__builtin_log_scope_entry")),
144+
LogScopeEntryExtendedName(C.getIdentifier("__builtin_log_scope_entry_extended")),
135145
SendDataName(C.getIdentifier("__builtin_send_data")) { }
136146

137147
Stmt *transformStmt(Stmt *S) {
@@ -736,7 +746,7 @@ class Instrumenter : InstrumenterBase {
736746
}
737747

738748
Added<Stmt *> logPostPrint(SourceRange SR) {
739-
return buildLoggerCallWithArgs(PostPrintName, {}, SR);
749+
return buildLoggerCallWithArgs(ExtendedCallbacks ? PostPrintExtendedName : PostPrintName, {}, SR);
740750
}
741751

742752
std::pair<PatternBindingDecl *, VarDecl *>
@@ -776,15 +786,15 @@ class Instrumenter : InstrumenterBase {
776786
const unsigned id_num = Distribution(RNG);
777787
Expr *IDExpr = IntegerLiteralExpr::createFromUnsigned(Context, id_num, SourceLoc());
778788

779-
return buildLoggerCallWithArgs(LogWithIDName, { *E, NameExpr, IDExpr }, SR);
789+
return buildLoggerCallWithArgs(ExtendedCallbacks ? LogWithIDExtendedName : LogWithIDName, { *E, NameExpr, IDExpr }, SR);
780790
}
781791

782792
Added<Stmt *> buildScopeEntry(SourceRange SR) {
783-
return buildLoggerCallWithArgs(LogScopeEntryName, {}, SR);
793+
return buildLoggerCallWithArgs(ExtendedCallbacks ? LogScopeEntryExtendedName : LogScopeEntryName, {}, SR);
784794
}
785795

786796
Added<Stmt *> buildScopeExit(SourceRange SR) {
787-
return buildLoggerCallWithArgs(LogScopeExitName, {}, SR);
797+
return buildLoggerCallWithArgs(ExtendedCallbacks ? LogScopeExitExtendedName : LogScopeExitName, {}, SR);
788798
}
789799

790800
Added<Stmt *> buildLoggerCallWithArgs(DeclNameRef LoggerName,
@@ -813,14 +823,28 @@ class Instrumenter : InstrumenterBase {
813823

814824
llvm::SmallVector<Expr *, 6> ArgsWithSourceRange(Args.begin(), Args.end());
815825

816-
ArgsWithSourceRange.append(
817-
{StartLine, EndLine, StartColumn, EndColumn, ModuleExpr, FileExpr});
818-
819826
UnresolvedDeclRefExpr *LoggerRef = new (Context)
820827
UnresolvedDeclRefExpr(LoggerName, DeclRefKind::Ordinary,
821828
DeclNameLoc(SR.End));
822829
LoggerRef->setImplicit(true);
823830

831+
if (ExtendedCallbacks) {
832+
StringRef filePath = Context.SourceMgr.getDisplayNameForLoc(SR.Start);
833+
834+
Expr *FilePathExpr = new (Context) StringLiteralExpr(
835+
Context.AllocateCopy(filePath), SourceRange(), /*implicit=*/true);
836+
837+
std::string moduleName = std::string(TypeCheckDC->getParentModule()->getName());
838+
Expr *ModuleNameExpr = new (Context) StringLiteralExpr(
839+
Context.AllocateCopy(moduleName), SourceRange(), /*implicit=*/true);
840+
841+
ArgsWithSourceRange.append(
842+
{StartLine, EndLine, StartColumn, EndColumn, ModuleNameExpr, FilePathExpr});
843+
} else {
844+
ArgsWithSourceRange.append(
845+
{StartLine, EndLine, StartColumn, EndColumn, ModuleExpr, FileExpr});
846+
}
847+
824848
auto *ArgList =
825849
ArgumentList::forImplicitUnlabeled(Context, ArgsWithSourceRange);
826850
ApplyExpr *LoggerCall =

test/PlaygroundTransform/Inputs/PlaygroundsRuntime.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ struct ModuleFileIdentifier {
2323
class LogRecord {
2424
let text : String
2525

26+
init(api : String, object : Any, name : String, id : Int, range : SourceRange, moduleName : String, filePath : String) {
27+
var object_description : String = ""
28+
print(object, terminator: "", to: &object_description)
29+
text = range.text + " " + api + "[" + name + "='" + object_description + "'" + " module: " + moduleName + ". file: " + filePath + "]"
30+
}
2631
init(api : String, object : Any, name : String, id : Int, range : SourceRange, moduleFileId : ModuleFileIdentifier) {
2732
var object_description : String = ""
2833
print(object, terminator: "", to: &object_description)
@@ -38,6 +43,9 @@ class LogRecord {
3843
print(object, terminator: "", to: &object_description)
3944
text = moduleFileId.text + " " + range.text + " " + api + "['" + object_description + "']"
4045
}
46+
init(api : String, range : SourceRange, moduleName : String, filePath: String) {
47+
text = range.text + " " + api + " " + " module: " + moduleName + ". file: " + filePath
48+
}
4149
init(api: String, range : SourceRange, moduleFileId : ModuleFileIdentifier) {
4250
text = moduleFileId.text + " " + range.text + " " + api
4351
}
@@ -53,21 +61,37 @@ public func __builtin_log_with_id<T>(_ object : T, _ name : String, _ id : Int,
5361
return LogRecord(api:"__builtin_log", object:object, name:name, id:id, range:SourceRange(sl:sl, el:el, sc:sc, ec:ec), moduleFileId:moduleFileId)
5462
}
5563

64+
public func __builtin_log_with_id_extended<T>(_ object: T, _ name: String, _ id: Int, _ sl: Int, _ el: Int, _ sc: Int, _ ec: Int, _ moduleName: String, _ filePath: String) -> AnyObject? {
65+
return LogRecord(api:"__builtin_log_with_id_extended", object:object, name:name, id:id, range:SourceRange(sl:sl, el:el, sc:sc, ec:ec), moduleName:moduleName, filePath:filePath)
66+
}
67+
5668
public func __builtin_log_scope_entry(_ sl : Int, _ el : Int, _ sc : Int, _ ec: Int, _ moduleId : Int, _ fileId : Int) -> AnyObject? {
5769
let moduleFileId = ModuleFileIdentifier(moduleId:moduleId, fileId:fileId)
5870
return LogRecord(api:"__builtin_log_scope_entry", range:SourceRange(sl:sl, el:el, sc:sc, ec:ec), moduleFileId:moduleFileId)
5971
}
6072

73+
public func __builtin_log_scope_entry_extended(_ sl : Int, _ el : Int, _ sc : Int, _ ec: Int, _ moduleName: String, _ filePath: String) -> AnyObject? {
74+
return LogRecord(api:"__builtin_log_scope_entry_extended", range:SourceRange(sl:sl, el:el, sc:sc, ec:ec), moduleName:moduleName, filePath:filePath)
75+
}
76+
6177
public func __builtin_log_scope_exit(_ sl : Int, _ el : Int, _ sc : Int, _ ec: Int, _ moduleId : Int, _ fileId : Int) -> AnyObject? {
6278
let moduleFileId = ModuleFileIdentifier(moduleId:moduleId, fileId:fileId)
6379
return LogRecord(api:"__builtin_log_scope_exit", range:SourceRange(sl:sl, el:el, sc:sc, ec:ec), moduleFileId:moduleFileId)
6480
}
6581

82+
public func __builtin_log_scope_exit_extended(_ sl : Int, _ el : Int, _ sc : Int, _ ec: Int, _ moduleName: String, _ filePath: String) -> AnyObject? {
83+
return LogRecord(api:"__builtin_log_scope_exit_extended", range:SourceRange(sl:sl, el:el, sc:sc, ec:ec), moduleName:moduleName, filePath:filePath)
84+
}
85+
6686
public func __builtin_postPrint(_ sl : Int, _ el : Int, _ sc : Int, _ ec: Int, _ moduleId : Int, _ fileId : Int) -> AnyObject? {
6787
let moduleFileId = ModuleFileIdentifier(moduleId:moduleId, fileId:fileId)
6888
return LogRecord(api:"__builtin_postPrint", range:SourceRange(sl:sl, el:el, sc:sc, ec:ec), moduleFileId:moduleFileId)
6989
}
7090

91+
public func __builtin_postPrint_extended(_ sl : Int, _ el : Int, _ sc : Int, _ ec: Int, _ moduleName: String, _ filePath: String) -> AnyObject? {
92+
return LogRecord(api:"__builtin_postPrint_extended", range:SourceRange(sl:sl, el:el, sc:sc, ec:ec), moduleName:moduleName, filePath:filePath)
93+
}
94+
7195
public func __builtin_send_data(_ object:AnyObject?) {
7296
print((object as! LogRecord).text)
7397
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: cp %s %t/main.swift
3+
// RUN: %target-build-swift -whole-module-optimization -module-name PlaygroundSupport -emit-module-path %t/PlaygroundSupport.swiftmodule -parse-as-library -c -o %t/PlaygroundSupport.o %S/Inputs/SilentPCMacroRuntime.swift %S/Inputs/PlaygroundsRuntime.swift
4+
// RUN: %target-build-swift -Xfrontend -playground -Xfrontend -playground-high-performance -enable-experimental-feature PlaygroundExtendedCallbacks -o %t/main -I=%t %t/PlaygroundSupport.o %t/main.swift
5+
// RUN: %target-codesign %t/main
6+
// RUN: %target-run %t/main | %FileCheck %s
7+
// RUN: %target-build-swift -Xfrontend -pc-macro -Xfrontend -playground -Xfrontend -playground-high-performance -enable-experimental-feature PlaygroundExtendedCallbacks -o %t/main2 -I=%t %t/PlaygroundSupport.o %t/main.swift
8+
// RUN: %target-codesign %t/main2
9+
// RUN: %target-run %t/main2 | %FileCheck %s
10+
// REQUIRES: executable_test
11+
12+
import PlaygroundSupport
13+
14+
var a = true
15+
if (a) {
16+
5
17+
} else {
18+
7
19+
}
20+
21+
for i in 0..<3 {
22+
i
23+
}
24+
// CHECK: [{{.*}}] __builtin_log_with_id_extended[a='true' module: main{{.*}}. file: {{.*/main[\d]?.swift}}]
25+
// CHECK-NEXT: [{{.*}}] __builtin_log_with_id_extended[='5' module: main{{.*}}. file: {{.*/main[\d]?.swift}}]
26+
// CHECK-NEXT: [{{.*}}] __builtin_log_with_id_extended[='0' module: main{{.*}}. file: {{.*/main[\d]?.swift}}]
27+
// CHECK-NEXT: [{{.*}}] __builtin_log_with_id_extended[='1' module: main{{.*}}. file: {{.*/main[\d]?.swift}}]
28+
// CHECK-NEXT: [{{.*}}] __builtin_log_with_id_extended[='2' module: main{{.*}}. file: {{.*/main[\d]?.swift}}]
29+
30+
var b = true
31+
for i in 0..<3 {
32+
i
33+
continue
34+
}
35+
// CHECK-NEXT: [{{.*}}] __builtin_log_with_id_extended[b='true' module: main{{.*}}. file: {{.*/main[\d]?.swift}}]
36+
// CHECK-NEXT: [{{.*}}] __builtin_log_with_id_extended[='0' module: main{{.*}}. file: {{.*/main[\d]?.swift}}]
37+
// CHECK-NEXT: [{{.*}}] __builtin_log_with_id_extended[='1' module: main{{.*}}. file: {{.*/main[\d]?.swift}}]
38+
// CHECK-NEXT: [{{.*}}] __builtin_log_with_id_extended[='2' module: main{{.*}}. file: {{.*/main[\d]?.swift}}]
39+
40+
var c = true
41+
for i in 0..<3 {
42+
i
43+
break
44+
}
45+
// CHECK-NEXT: [{{.*}}] __builtin_log_with_id_extended[c='true' module: main{{.*}}. file: {{.*/main[\d]?.swift}}]
46+
// CHECK-NEXT: [{{.*}}] __builtin_log_with_id_extended[='0' module: main{{.*}}. file: {{.*/main[\d]?.swift}}]

0 commit comments

Comments
 (0)