Skip to content

[embedded] Add a simple Swift runtime, written in embedded Swift #68735

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 7 commits into from
Sep 26, 2023
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
34 changes: 34 additions & 0 deletions lib/SILOptimizer/UtilityPasses/Link.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "swift/SILOptimizer/PassManager/Passes.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "swift/SIL/SILModule.h"
#include "swift/Serialization/SerializedSILLoader.h"

using namespace swift;

Expand All @@ -35,8 +36,41 @@ class SILLinker : public SILModuleTransform {
for (auto &Fn : M)
if (M.linkFunction(&Fn, LinkMode))
invalidateAnalysis(&Fn, SILAnalysis::InvalidationKind::Everything);

// In embedded Swift, the stdlib contains all the runtime functions needed
// (swift_retain, etc.). Link them in so they can be referenced in IRGen.
if (M.getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
linkEmbeddedRuntimeFromStdlib();
}
}

void linkEmbeddedRuntimeFromStdlib() {
#define FUNCTION(ID, NAME, CC, AVAILABILITY, RETURNS, ARGS, ATTRS, EFFECT) \
linkEmbeddedRuntimeFunctionByName(#NAME);

#define RETURNS(...)
#define ARGS(...)
#define NO_ARGS
#define ATTRS(...)
#define NO_ATTRS
#define EFFECT(...)

#include "swift/Runtime/RuntimeFunctions.def"
}

void linkEmbeddedRuntimeFunctionByName(StringRef name) {
SILModule &M = *getModule();

// Bail if runtime function is already loaded.
if (M.lookUpFunction(name)) return;

SILFunction *Fn =
M.getSILLoader()->lookupSILFunction(name, SILLinkage::PublicExternal);
if (!Fn) return;

if (M.linkFunction(Fn, LinkMode))
invalidateAnalysis(Fn, SILAnalysis::InvalidationKind::Everything);
}
};
} // end anonymous namespace

Expand Down
1 change: 1 addition & 0 deletions stdlib/public/SwiftShims/swift/shims/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
set(sources
AssertionReporting.h
CoreFoundationShims.h
EmbeddedShims.h
FoundationShims.h
GlobalObjects.h
HeapObject.h
Expand Down
49 changes: 49 additions & 0 deletions stdlib/public/SwiftShims/swift/shims/EmbeddedShims.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//===--- EmbeddedShims.h - shims for embedded Swift -------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Shims for embedded Swift.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_STDLIB_SHIMS_EMBEDDEDSHIMS_H
#define SWIFT_STDLIB_SHIMS_EMBEDDEDSHIMS_H

#include "SwiftStddef.h"
#include "Visibility.h"

#if __has_feature(nullability)
#pragma clang assume_nonnull begin
#endif

#ifdef __cplusplus
extern "C" {
#endif

#define SWIFT_CC __attribute__((swiftcall))
#define SWIFT_CONTEXT __attribute__((swift_context))

typedef void SWIFT_CC (*HeapObjectDestroyer)(SWIFT_CONTEXT void *object);

static inline void _swift_runtime_invoke_heap_object_destroy(
const void *destroy, void *self) {
((HeapObjectDestroyer)destroy)(self);
}

#ifdef __cplusplus
} // extern "C"
#endif

#if __has_feature(nullability)
#pragma clang assume_nonnull end
#endif

#endif // SWIFT_STDLIB_SHIMS_EMBEDDEDSHIMS_H
1 change: 1 addition & 0 deletions stdlib/public/SwiftShims/swift/shims/LibcShims.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ __swift_size_t _swift_stdlib_fwrite_stdout(const void *ptr, __swift_size_t size,

// General utilities <stdlib.h>
// Memory management functions
extern int posix_memalign(void **memptr, __swift_size_t alignment, __swift_size_t size);
static inline void _swift_stdlib_free(void *_Nullable ptr) {
extern void free(void *_Nullable);
free(ptr);
Expand Down
1 change: 1 addition & 0 deletions stdlib/public/SwiftShims/swift/shims/module.modulemap
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module SwiftShims {
header "AssertionReporting.h"
header "CoreFoundationShims.h"
header "EmbeddedShims.h"
header "FoundationShims.h"
header "GlobalObjects.h"
header "HeapObject.h"
Expand Down
6 changes: 5 additions & 1 deletion stdlib/public/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,10 @@ if(SWIFT_STDLIB_ENABLE_VECTOR_TYPES)
list(APPEND SWIFTLIB_GYB_SOURCES SIMDConcreteOperations.swift.gyb SIMDVectorTypes.swift.gyb)
endif()

list(APPEND SWIFTLIB_EMBEDDED_SOURCES EmbeddedStubs.swift)
list(APPEND SWIFTLIB_EMBEDDED_SOURCES
EmbeddedRuntime.swift
EmbeddedStubs.swift
)

set(GROUP_INFO_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/GroupInfo.json)
set(swift_core_link_flags "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}")
Expand Down Expand Up @@ -427,6 +430,7 @@ if(SWIFT_SHOULD_BUILD_EMBEDDED_STDLIB)
MODULE_DIR "${CMAKE_BINARY_DIR}/lib/swift/embedded"
SDK "embedded"
ARCHITECTURE "${arch}"
FILE_DEPENDS ${swiftCore_common_dependencies}
INSTALL_IN_COMPONENT "never_install"
)
add_dependencies(embedded-stdlib embedded-stdlib-${triple})
Expand Down
132 changes: 132 additions & 0 deletions stdlib/public/core/EmbeddedRuntime.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
//===----------------------------------------------------------------------===//
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super cool that you can just put this into the stdlib!

//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import SwiftShims

public struct ClassMetadata {
var superclassMetadata: UnsafeMutablePointer<ClassMetadata>?

// There is no way to express the actual calling convention on the heap desroy
// function (swiftcc with 'self') currently, so let's use UnsafeRawPointer
// and a helper function in C (_swift_runtime_invoke_heap_object_destroy).
var destroy: UnsafeRawPointer
}

public struct HeapObject {
var metadata: UnsafeMutablePointer<ClassMetadata>

// TODO: This is just an initial support for strong refcounting only. We need
// to think about supporting (or banning) weak and/or unowned references.
var refcount: Int

static let immortalRefCount = -1
}

func alignedAlloc(size: Int, alignment: Int) -> UnsafeMutableRawPointer? {
let alignment = max(alignment, MemoryLayout<UnsafeRawPointer>.size)
var r: UnsafeMutableRawPointer? = nil
_ = posix_memalign(&r, alignment, size)
return r
}

@_cdecl("swift_slowAlloc")
public func swift_slowAlloc(_ size: Int, _ alignMask: Int) -> UnsafeMutableRawPointer? {
let alignment: Int
if alignMask == -1 {
alignment = _swift_MinAllocationAlignment
} else {
alignment = alignMask + 1
}
return alignedAlloc(size: size, alignment: alignment)
}

@_cdecl("swift_slowDealloc")
public func swift_slowDealloc(_ ptr: UnsafeMutableRawPointer?, _ size: Int, _ alignMask: Int) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you going to add the DO_NOT_FREE_BIT here, too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it should go here...? I thought swift_slowDealloc is not used on refcounted objects, and only used to implement things like UnsafePointer.deallocate(). This matches how swift_slowDealloc is implemented in the main runtime (no checking of anything, just a direct call to free).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry, I meant to add this comment for swift_deallocClassInstance

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aha, then yes -- let me do that as a follow-up in https://github.com/apple/swift/pull/68754/files, I'll rebase it on top of this Swift runtime.

free(ptr)
}

@_silgen_name("swift_allocObject")
public func swift_allocObject(metadata: UnsafeMutablePointer<ClassMetadata>, requiredSize: Int, requiredAlignmentMask: Int) -> UnsafeMutablePointer<HeapObject> {
let p = swift_slowAlloc(requiredSize, requiredAlignmentMask)!
let object = p.assumingMemoryBound(to: HeapObject.self)
object.pointee.metadata = metadata
object.pointee.refcount = 1
return object
}

@_silgen_name("swift_deallocClassInstance")
public func swift_deallocClassInstance(object: UnsafeMutablePointer<HeapObject>, allocatedSize: Int, allocatedAlignMask: Int) {
free(object)
}

@_silgen_name("swift_initStackObject")
public func swift_initStackObject(metadata: UnsafeMutablePointer<ClassMetadata>, object: UnsafeMutablePointer<HeapObject>) -> UnsafeMutablePointer<HeapObject> {
object.pointee.metadata = metadata

// TODO/FIXME: Making all stack promoted objects immortal is not correct.
object.pointee.refcount = HeapObject.immortalRefCount
return object
}

// TODO/FIXME: Refcounting and swift_once is not thread-safe, the following only works in single-threaded environments.

@_silgen_name("swift_isUniquelyReferenced_nonNull_native")
public func swift_isUniquelyReferenced_nonNull_native(object: UnsafeMutablePointer<HeapObject>) -> Bool {
// TODO/FIXME: Refcounting is not thread-safe, the following only works in single-threaded environments.
return object.pointee.refcount == 1
}

@_silgen_name("swift_retain")
public func swift_retain(object: Builtin.RawPointer) -> Builtin.RawPointer {
if Int(Builtin.ptrtoint_Word(object)) == 0 { return object }
let o = UnsafeMutablePointer<HeapObject>(object)
// TODO/FIXME: Refcounting is not thread-safe, the following only works in single-threaded environments.
if o.pointee.refcount == HeapObject.immortalRefCount { return o._rawValue }
o.pointee.refcount += 1
return o._rawValue
}

@_silgen_name("swift_release")
public func swift_release(object: Builtin.RawPointer) {
if Int(Builtin.ptrtoint_Word(object)) == 0 { return }
let o = UnsafeMutablePointer<HeapObject>(object)
// TODO/FIXME: Refcounting is not thread-safe, the following only works in single-threaded environments.
if o.pointee.refcount == HeapObject.immortalRefCount { return }
o.pointee.refcount -= 1
if o.pointee.refcount == 0 {
_swift_runtime_invoke_heap_object_destroy(o.pointee.metadata.pointee.destroy, o)
}
}

@_silgen_name("swift_beginAccess")
public func swift_beginAccess(pointer: UnsafeMutableRawPointer, buffer: UnsafeMutableRawPointer, flags: UInt, pc: UnsafeMutableRawPointer) {
// TODO: Add actual exclusivity checking.
}

@_silgen_name("swift_endAccess")
public func swift_endAccess(buffer: UnsafeMutableRawPointer) {
// TODO: Add actual exclusivity checking.
}

@_silgen_name("swift_once")
public func swift_once(predicate: UnsafeMutablePointer<Int>, fn: (@convention(c) (UnsafeMutableRawPointer)->()), context: UnsafeMutableRawPointer) {
// TODO/FIXME: The following only works in single-threaded environments.
if predicate.pointee == 0 {
predicate.pointee = 1
fn(context)
}
}

@_silgen_name("swift_deletedMethodError")
public func swift_deletedMethodError() -> Never {
Builtin.int_trap()
}
1 change: 1 addition & 0 deletions stdlib/public/core/GroupInfo.json
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@
"Duration.swift",
"DurationProtocol.swift",
"Instant.swift",
"EmbeddedRuntime.swift",
"EmbeddedStubs.swift"
],
"Result": [
Expand Down
80 changes: 0 additions & 80 deletions test/embedded/Inputs/tiny-runtime-dummy-refcounting.c

This file was deleted.

Loading