mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
The main work here is serializing patterns, which are recursive. Unlike Types, Patterns are not uniqued (in the original AST they contain location info). Therefore, rather than using cross-referencing IDs, patterns are serialized as trailing records with an implied hierarchy. Each pattern record tells you what trailing records to expect. So, for example, the pattern ((x : Int, y : Int), _ : Int) will give you this serialization: 1. TuplePattern - 2 elements 2. TuplePatternElt 3. TuplePattern - 2 elements 4. TuplePatternElt 5. TypedPattern - Int 6. NamedPattern - x 7. TuplePatternElt 8. TypedPattern - Int 9. NamedPattern - y 10. TuplePatternElt 11. TypedPattern - Int 12. AnyPattern Functions contain two sets of patterns: "argument" patterns and "body" patterns, which are different in selector-style declarations. Currently we always serialize both of these, but it would be easy enough to add a flag in the FUNC_DECL record to skip one of them if they are the same. If the function is curried, each set will contain multiple patterns. These are simply read eagerly as trailing records from the function; as soon as a non-pattern record is encountered, we know all of the patterns have been read in. Swift SVN r5742
841 lines
26 KiB
C++
841 lines
26 KiB
C++
//===--- ModuleFile.cpp - Loading a serialized module -----------*- c++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ModuleFile.h"
|
|
#include "ModuleFormat.h"
|
|
#include "swift/AST/AST.h"
|
|
#include "swift/Serialization/BCReadingExtras.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
using namespace swift;
|
|
using namespace swift::serialization;
|
|
|
|
static ModuleStatus
|
|
validateControlBlock(llvm::BitstreamCursor &cursor,
|
|
llvm::SmallVectorImpl<uint64_t> &scratch) {
|
|
// The control block is malformed until we've at least read a major version
|
|
// number.
|
|
ModuleStatus result = ModuleStatus::Malformed;
|
|
|
|
auto next = cursor.advance();
|
|
while (next.Kind != llvm::BitstreamEntry::EndBlock) {
|
|
if (next.Kind == llvm::BitstreamEntry::Error)
|
|
return ModuleStatus::Malformed;
|
|
|
|
if (next.Kind == llvm::BitstreamEntry::SubBlock) {
|
|
// Unknown metadata sub-block, possibly for use by a future version of the
|
|
// module format.
|
|
if (cursor.SkipBlock())
|
|
return ModuleStatus::Malformed;
|
|
next = cursor.advance();
|
|
continue;
|
|
}
|
|
|
|
scratch.clear();
|
|
StringRef blobData;
|
|
unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
|
|
switch (kind) {
|
|
case control_block::METADATA: {
|
|
uint16_t versionMajor = scratch[0];
|
|
if (versionMajor > VERSION_MAJOR)
|
|
return ModuleStatus::FormatTooNew;
|
|
result = ModuleStatus::Valid;
|
|
break;
|
|
}
|
|
default:
|
|
// Unknown metadata record, possibly for use by a future version of the
|
|
// module format.
|
|
break;
|
|
}
|
|
|
|
next = cursor.advance();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
Pattern *ModuleFile::maybeReadPattern() {
|
|
using namespace decls_block;
|
|
|
|
SmallVector<uint64_t, 8> scratch;
|
|
|
|
auto next = DeclTypeCursor.advance();
|
|
if (next.Kind != llvm::BitstreamEntry::Record)
|
|
return nullptr;
|
|
|
|
unsigned kind = DeclTypeCursor.readRecord(next.ID, scratch);
|
|
switch (kind) {
|
|
case decls_block::PAREN_PATTERN: {
|
|
Pattern *subPattern = maybeReadPattern();
|
|
assert(subPattern);
|
|
|
|
auto result = new (ModuleContext->Ctx) ParenPattern(SourceLoc(),
|
|
subPattern,
|
|
SourceLoc());
|
|
result->setType(subPattern->getType());
|
|
return result;
|
|
}
|
|
case decls_block::TUPLE_PATTERN: {
|
|
TypeID tupleTypeID;
|
|
unsigned count;
|
|
|
|
TuplePatternLayout::readRecord(scratch, tupleTypeID, count);
|
|
|
|
SmallVector<TuplePatternElt, 8> elements;
|
|
for ( ; count > 0; --count) {
|
|
scratch.clear();
|
|
next = DeclTypeCursor.advance();
|
|
assert(next.Kind == llvm::BitstreamEntry::Record);
|
|
|
|
kind = DeclTypeCursor.readRecord(next.ID, scratch);
|
|
assert(kind == decls_block::TUPLE_PATTERN_ELT);
|
|
|
|
TypeID varargsTypeID;
|
|
TuplePatternEltLayout::readRecord(scratch, varargsTypeID);
|
|
|
|
Pattern *subPattern = maybeReadPattern();
|
|
assert(subPattern);
|
|
|
|
elements.push_back(TuplePatternElt(subPattern));
|
|
if (varargsTypeID) {
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
elements.back().setVarargBaseType(getType(varargsTypeID));
|
|
}
|
|
}
|
|
|
|
auto result = TuplePattern::create(ModuleContext->Ctx, SourceLoc(),
|
|
elements, SourceLoc());
|
|
{
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
result->setType(getType(tupleTypeID));
|
|
}
|
|
return result;
|
|
}
|
|
case decls_block::NAMED_PATTERN: {
|
|
|
|
DeclID varID;
|
|
NamedPatternLayout::readRecord(scratch, varID);
|
|
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
|
|
auto var = cast<VarDecl>(getDecl(varID));
|
|
auto result = new (ModuleContext->Ctx) NamedPattern(var);
|
|
result->setType(var->getType());
|
|
return result;
|
|
}
|
|
case decls_block::ANY_PATTERN: {
|
|
TypeID typeID;
|
|
|
|
AnyPatternLayout::readRecord(scratch, typeID);
|
|
auto result = new (ModuleContext->Ctx) AnyPattern(SourceLoc());
|
|
{
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
result->setType(getType(typeID));
|
|
}
|
|
return result;
|
|
}
|
|
case decls_block::TYPED_PATTERN: {
|
|
TypeID typeID;
|
|
|
|
TypedPatternLayout::readRecord(scratch, typeID);
|
|
Pattern *subPattern = maybeReadPattern();
|
|
assert(subPattern);
|
|
|
|
TypeLoc typeInfo = TypeLoc::withoutLoc(getType(typeID));
|
|
auto result = new (ModuleContext->Ctx) TypedPattern(subPattern, typeInfo);
|
|
{
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
result->setType(typeInfo.getType());
|
|
}
|
|
return result;
|
|
}
|
|
default:
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
Identifier ModuleFile::getIdentifier(IdentifierID IID) {
|
|
if (IID == 0)
|
|
return Identifier();
|
|
|
|
assert(IID <= Identifiers.size() && "invalid identifier ID");
|
|
auto identRecord = Identifiers[IID-1];
|
|
|
|
if (identRecord.Offset == 0)
|
|
return identRecord.Ident;
|
|
|
|
assert(!IdentifierData.empty() && "no identifier data in module");
|
|
|
|
StringRef rawStrPtr = IdentifierData.substr(identRecord.Offset);
|
|
size_t terminatorOffset = rawStrPtr.find('\0');
|
|
assert(terminatorOffset != StringRef::npos &&
|
|
"unterminated identifier string data");
|
|
|
|
return ModuleContext->Ctx.getIdentifier(rawStrPtr.slice(0, terminatorOffset));
|
|
}
|
|
|
|
DeclContext *ModuleFile::getDeclContext(DeclID DID) {
|
|
if (DID == 0)
|
|
return ModuleContext;
|
|
|
|
Decl *D = getDecl(DID);
|
|
|
|
if (auto ND = dyn_cast<NominalTypeDecl>(D))
|
|
return ND;
|
|
if (auto ED = dyn_cast<ExtensionDecl>(D))
|
|
return ED;
|
|
if (auto CD = dyn_cast<ConstructorDecl>(D))
|
|
return CD;
|
|
if (auto DD = dyn_cast<DestructorDecl>(D))
|
|
return DD;
|
|
if (auto FD = dyn_cast<FuncDecl>(D))
|
|
return FD->getBody();
|
|
|
|
llvm_unreachable("unknown DeclContext kind");
|
|
}
|
|
|
|
Decl *ModuleFile::getDecl(DeclID DID) {
|
|
if (DID == 0)
|
|
return nullptr;
|
|
|
|
assert(DID <= Decls.size() && "invalid decl ID");
|
|
auto &declOrOffset = Decls[DID-1];
|
|
|
|
if (declOrOffset.is<Decl *>())
|
|
return declOrOffset.get<Decl *>();
|
|
|
|
DeclTypeCursor.JumpToBit(declOrOffset.get<BitOffset>());
|
|
auto entry = DeclTypeCursor.advance();
|
|
|
|
if (entry.Kind != llvm::BitstreamEntry::Record) {
|
|
// We don't know how to serialize decls represented by sub-blocks.
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
ASTContext &ctx = ModuleContext->Ctx;
|
|
|
|
SmallVector<uint64_t, 64> scratch;
|
|
StringRef blobData;
|
|
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, &blobData);
|
|
|
|
switch (recordID) {
|
|
case decls_block::TYPE_ALIAS_DECL: {
|
|
IdentifierID nameID;
|
|
DeclID contextID;
|
|
TypeID underlyingTypeID;
|
|
bool isGeneric;
|
|
bool isImplicit;
|
|
ArrayRef<uint64_t> inheritedIDs;
|
|
|
|
decls_block::TypeAliasLayout::readRecord(scratch, nameID, contextID,
|
|
underlyingTypeID,
|
|
isGeneric, isImplicit,
|
|
inheritedIDs);
|
|
|
|
auto inherited =
|
|
MutableArrayRef<TypeLoc>(ctx.Allocate<TypeLoc>(inheritedIDs.size()),
|
|
inheritedIDs.size());
|
|
|
|
TypeLoc *nextInheritedType = inherited.data();
|
|
for (TypeID TID : inheritedIDs) {
|
|
auto type = getType(TID);
|
|
new (nextInheritedType) TypeLoc(TypeLoc::withoutLoc(type));
|
|
++nextInheritedType;
|
|
}
|
|
|
|
TypeLoc underlyingType = TypeLoc::withoutLoc(getType(underlyingTypeID));
|
|
auto alias = new (ctx) TypeAliasDecl(SourceLoc(),
|
|
getIdentifier(nameID),
|
|
SourceLoc(),
|
|
underlyingType,
|
|
getDeclContext(contextID),
|
|
inherited);
|
|
declOrOffset = alias;
|
|
|
|
if (isImplicit)
|
|
alias->setImplicit();
|
|
if (isGeneric)
|
|
alias->setGenericParameter();
|
|
break;
|
|
}
|
|
|
|
case decls_block::STRUCT_DECL: {
|
|
IdentifierID nameID;
|
|
DeclID contextID;
|
|
bool isImplicit;
|
|
ArrayRef<uint64_t> inheritedIDs;
|
|
|
|
decls_block::StructLayout::readRecord(scratch, nameID, contextID,
|
|
isImplicit, inheritedIDs);
|
|
|
|
auto inherited =
|
|
MutableArrayRef<TypeLoc>(ctx.Allocate<TypeLoc>(inheritedIDs.size()),
|
|
inheritedIDs.size());
|
|
|
|
TypeLoc *nextInheritedType = inherited.data();
|
|
for (TypeID TID : inheritedIDs) {
|
|
auto type = getType(TID);
|
|
new (nextInheritedType) TypeLoc(TypeLoc::withoutLoc(type));
|
|
++nextInheritedType;
|
|
}
|
|
|
|
ArrayRef<uint64_t> memberIDs;
|
|
|
|
auto entry = DeclTypeCursor.advance();
|
|
if (entry.Kind != llvm::BitstreamEntry::Record)
|
|
return {};
|
|
|
|
StringRef blobData;
|
|
SmallVector<uint64_t, 16> memberIDBuffer;
|
|
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, memberIDBuffer,
|
|
&blobData);
|
|
if (recordID != decls_block::DECL_CONTEXT) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
decls_block::DeclContextLayout::readRecord(memberIDBuffer, memberIDs);
|
|
|
|
auto theStruct = new (ctx) StructDecl(SourceLoc(), getIdentifier(nameID),
|
|
SourceLoc(), inherited,
|
|
/*generic params=*/nullptr,
|
|
getDeclContext(contextID));
|
|
declOrOffset = theStruct;
|
|
|
|
if (isImplicit)
|
|
theStruct->setImplicit();
|
|
|
|
if (!memberIDs.empty()) {
|
|
MutableArrayRef<Decl *> members(ctx.Allocate<Decl *>(memberIDs.size()),
|
|
memberIDs.size());
|
|
auto nextMember = members.begin();
|
|
for (auto rawID : memberIDBuffer) {
|
|
*nextMember = getDecl(rawID);
|
|
++nextMember;
|
|
}
|
|
|
|
theStruct->setMembers(members, SourceRange());
|
|
}
|
|
break;
|
|
}
|
|
|
|
case decls_block::CONSTRUCTOR_DECL: {
|
|
DeclID parentID;
|
|
bool isImplicit;
|
|
DeclID implicitThisID;
|
|
|
|
decls_block::ConstructorLayout::readRecord(scratch, parentID, isImplicit,
|
|
implicitThisID);
|
|
auto thisDecl = cast<VarDecl>(getDecl(implicitThisID));
|
|
auto parent = cast<NominalTypeDecl>(getDeclContext(parentID));
|
|
|
|
auto emptyArgs = TuplePattern::create(ctx, SourceLoc(), {}, SourceLoc());
|
|
auto ctor = new (ctx) ConstructorDecl(ctx.getIdentifier("constructor"),
|
|
SourceLoc(), emptyArgs, thisDecl,
|
|
/*generic params=*/nullptr,
|
|
parent);
|
|
declOrOffset = ctor;
|
|
|
|
// FIXME: Actually serialize the type instead of reconstructing it here.
|
|
ctor->setType(FunctionType::get(MetaTypeType::get(thisDecl->getType(),
|
|
ctx),
|
|
FunctionType::get(ctx.TheEmptyTupleType,
|
|
thisDecl->getType(),
|
|
ctx),
|
|
ctx));
|
|
|
|
if (isImplicit)
|
|
ctor->setImplicit();
|
|
break;
|
|
}
|
|
|
|
case decls_block::VAR_DECL: {
|
|
IdentifierID nameID;
|
|
DeclID contextID;
|
|
bool isImplicit, isNeverLValue;
|
|
TypeID typeID;
|
|
DeclID getterID, setterID;
|
|
DeclID overriddenID;
|
|
|
|
decls_block::VarLayout::readRecord(scratch, nameID, contextID, isImplicit,
|
|
isNeverLValue, typeID, getterID,
|
|
setterID, overriddenID);
|
|
|
|
auto var = new (ctx) VarDecl(SourceLoc(), getIdentifier(nameID),
|
|
getType(typeID), nullptr);
|
|
declOrOffset = var;
|
|
|
|
// Explicitly set the DeclContext /after/ creating the VarDecl.
|
|
// Sometimes the context has to reference this decl.
|
|
var->setDeclContext(getDeclContext(contextID));
|
|
|
|
var->setNeverUsedAsLValue(isNeverLValue);
|
|
if (isImplicit)
|
|
var->setImplicit();
|
|
|
|
if (getterID || setterID) {
|
|
var->setProperty(ctx, SourceLoc(),
|
|
cast_or_null<FuncDecl>(getDecl(getterID)),
|
|
cast_or_null<FuncDecl>(getDecl(setterID)),
|
|
SourceLoc());
|
|
}
|
|
|
|
var->setOverriddenDecl(cast_or_null<VarDecl>(getDecl(overriddenID)));
|
|
break;
|
|
}
|
|
|
|
case decls_block::FUNC_DECL: {
|
|
IdentifierID nameID;
|
|
DeclID contextID;
|
|
bool isImplicit, isNeverLValue;
|
|
TypeID signatureID;
|
|
bool isClassMethod;
|
|
DeclID associatedDeclID;
|
|
DeclID overriddenID;
|
|
|
|
decls_block::FuncLayout::readRecord(scratch, nameID, contextID, isImplicit,
|
|
isNeverLValue, signatureID,
|
|
isClassMethod, associatedDeclID,
|
|
overriddenID);
|
|
|
|
SmallVector<Pattern *, 16> patternBuf;
|
|
while (Pattern *pattern = maybeReadPattern())
|
|
patternBuf.push_back(pattern);
|
|
|
|
auto DC = getDeclContext(contextID);
|
|
auto signature = cast<FunctionType>(getType(signatureID).getPointer());
|
|
|
|
assert(!patternBuf.empty());
|
|
size_t patternCount = patternBuf.size() / 2;
|
|
assert(patternCount * 2 == patternBuf.size() &&
|
|
"two sets of patterns don't match up");
|
|
|
|
ArrayRef<Pattern *> patterns(patternBuf);
|
|
ArrayRef<Pattern *> argPatterns = patterns.slice(0, patternCount);
|
|
ArrayRef<Pattern *> bodyPatterns = patterns.slice(patternCount);
|
|
|
|
auto body = FuncExpr::create(ctx, SourceLoc(),
|
|
argPatterns, bodyPatterns,
|
|
TypeLoc::withoutLoc(signature->getResult()),
|
|
/*body=*/nullptr, DC);
|
|
|
|
auto fn = new (ctx) FuncDecl(SourceLoc(), SourceLoc(),
|
|
getIdentifier(nameID), SourceLoc(),
|
|
/*generic params=*/nullptr, signature,
|
|
body, DC);
|
|
declOrOffset = fn;
|
|
|
|
fn->setOverriddenDecl(cast_or_null<FuncDecl>(getDecl(overriddenID)));
|
|
|
|
fn->setNeverUsedAsLValue(isNeverLValue);
|
|
fn->setStatic(isClassMethod);
|
|
if (isImplicit)
|
|
fn->setImplicit();
|
|
|
|
if (Decl *associated = getDecl(associatedDeclID)) {
|
|
if (auto op = dyn_cast<OperatorDecl>(associated)) {
|
|
fn->setOperatorDecl(op);
|
|
} else {
|
|
bool isGetter = false;
|
|
|
|
if (auto subscript = dyn_cast<SubscriptDecl>(associated)) {
|
|
isGetter = (subscript->getGetter() == fn);
|
|
assert(isGetter || subscript->getSetter() == fn);
|
|
} else if (auto var = dyn_cast<VarDecl>(associated)) {
|
|
isGetter = (var->getGetter() == fn);
|
|
assert(isGetter || var->getSetter() == fn);
|
|
} else {
|
|
llvm_unreachable("unknown associated decl kind");
|
|
}
|
|
|
|
if (isGetter)
|
|
fn->makeGetter(associated);
|
|
else
|
|
fn->makeSetter(associated);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// We don't know how to deserialize this kind of decl.
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
return declOrOffset.get<Decl *>();
|
|
}
|
|
|
|
/// Translate from the Serialization calling convention enum values to the AST
|
|
/// strongly-typed enum.
|
|
///
|
|
/// The former is guaranteed to be stable, but may not reflect this version of
|
|
/// the AST.
|
|
static Optional<swift::AbstractCC> getActualCC(uint8_t cc) {
|
|
switch (cc) {
|
|
#define CASE(THE_CC) \
|
|
case static_cast<uint8_t>(serialization::AbstractCC::THE_CC): \
|
|
return swift::AbstractCC::THE_CC;
|
|
CASE(C)
|
|
CASE(ObjCMethod)
|
|
CASE(Freestanding)
|
|
CASE(Method)
|
|
#undef CASE
|
|
default:
|
|
return Nothing;
|
|
}
|
|
}
|
|
|
|
Type ModuleFile::getType(TypeID TID) {
|
|
if (TID == 0)
|
|
return Type();
|
|
|
|
assert(TID <= Types.size() && "invalid decl ID");
|
|
auto &typeOrOffset = Types[TID-1];
|
|
|
|
if (typeOrOffset.is<Type>())
|
|
return typeOrOffset.get<Type>();
|
|
|
|
DeclTypeCursor.JumpToBit(typeOrOffset.get<BitOffset>());
|
|
auto entry = DeclTypeCursor.advance();
|
|
|
|
if (entry.Kind != llvm::BitstreamEntry::Record) {
|
|
// We don't know how to serialize types represented by sub-blocks.
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
SmallVector<uint64_t, 64> scratch;
|
|
StringRef blobData;
|
|
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, &blobData);
|
|
|
|
switch (recordID) {
|
|
case decls_block::BUILTIN_TYPE: {
|
|
assert(!blobData.empty() && "missing name in BUILTIN_TYPE record");
|
|
|
|
SmallVector<ValueDecl *, 1> lookupResult;
|
|
ASTContext &ctx = ModuleContext->Ctx;
|
|
ctx.TheBuiltinModule->lookupValue({}, ctx.getIdentifier(blobData),
|
|
NLKind::QualifiedLookup, lookupResult);
|
|
if (lookupResult.empty()) {
|
|
// This builtin is not supported.
|
|
error();
|
|
return nullptr;
|
|
}
|
|
assert(lookupResult.size() == 1 && "multiple types for the same name");
|
|
typeOrOffset = cast<TypeDecl>(lookupResult.front())->getDeclaredType();
|
|
break;
|
|
}
|
|
|
|
case decls_block::NAME_ALIAS_TYPE: {
|
|
DeclID underlyingID;
|
|
decls_block::NameAliasTypeLayout::readRecord(scratch, underlyingID);
|
|
auto alias = dyn_cast_or_null<TypeAliasDecl>(getDecl(underlyingID));
|
|
if (!alias) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
typeOrOffset = alias->getDeclaredType();
|
|
break;
|
|
}
|
|
|
|
case decls_block::STRUCT_TYPE: {
|
|
DeclID structID;
|
|
TypeID parentID;
|
|
decls_block::StructTypeLayout::readRecord(scratch, structID, parentID);
|
|
typeOrOffset = StructType::get(cast<StructDecl>(getDecl(structID)),
|
|
getType(parentID), ModuleContext->Ctx);
|
|
break;
|
|
}
|
|
|
|
case decls_block::PAREN_TYPE: {
|
|
TypeID underlyingID;
|
|
decls_block::ParenTypeLayout::readRecord(scratch, underlyingID);
|
|
typeOrOffset = ParenType::get(ModuleContext->Ctx, getType(underlyingID));
|
|
break;
|
|
}
|
|
|
|
case decls_block::TUPLE_TYPE: {
|
|
// The tuple record itself is empty. Read all trailing elements.
|
|
SmallVector<TupleTypeElt, 8> elements;
|
|
while (true) {
|
|
auto entry = DeclTypeCursor.advance();
|
|
if (entry.Kind != llvm::BitstreamEntry::Record)
|
|
break;
|
|
|
|
scratch.clear();
|
|
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch,
|
|
&blobData);
|
|
if (recordID != decls_block::TUPLE_TYPE_ELT)
|
|
break;
|
|
|
|
IdentifierID nameID;
|
|
TypeID typeID;
|
|
TypeID varargBaseID;
|
|
decls_block::TupleTypeEltLayout::readRecord(scratch, nameID, typeID,
|
|
varargBaseID);
|
|
|
|
{
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
elements.push_back({getType(typeID), getIdentifier(nameID),
|
|
/*initializer=*/nullptr, getType(varargBaseID)});
|
|
}
|
|
}
|
|
|
|
typeOrOffset = TupleType::get(elements, ModuleContext->Ctx);
|
|
break;
|
|
}
|
|
|
|
case decls_block::IDENTIFIER_TYPE: {
|
|
TypeID mappedID;
|
|
decls_block::IdentifierTypeLayout::readRecord(scratch, mappedID);
|
|
// FIXME: Actually recreate the IdentifierType instead of just aliasing the
|
|
// underlying mapped type.
|
|
typeOrOffset = getType(mappedID);
|
|
break;
|
|
}
|
|
|
|
case decls_block::FUNCTION_TYPE: {
|
|
TypeID inputID;
|
|
TypeID resultID;
|
|
uint8_t rawCallingConvention;
|
|
bool autoClosure;
|
|
bool thin;
|
|
bool blockCompatible;
|
|
|
|
decls_block::FunctionTypeLayout::readRecord(scratch, inputID, resultID,
|
|
rawCallingConvention,
|
|
autoClosure, thin,
|
|
blockCompatible);
|
|
auto callingConvention = getActualCC(rawCallingConvention);
|
|
if (!callingConvention.hasValue()) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
typeOrOffset = FunctionType::get(getType(inputID), getType(resultID),
|
|
autoClosure, blockCompatible, thin,
|
|
callingConvention.getValue(),
|
|
ModuleContext->Ctx);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// We don't know how to deserialize this kind of type.
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
return typeOrOffset.get<Type>();
|
|
}
|
|
|
|
ModuleFile::ModuleFile(llvm::OwningPtr<llvm::MemoryBuffer> &&input)
|
|
: ModuleContext(nullptr),
|
|
InputFile(std::move(input)),
|
|
InputReader(reinterpret_cast<const uint8_t *>(InputFile->getBufferStart()),
|
|
reinterpret_cast<const uint8_t *>(InputFile->getBufferEnd())),
|
|
Status(ModuleStatus::Valid) {
|
|
llvm::BitstreamCursor cursor{InputReader};
|
|
|
|
for (unsigned char byte : SIGNATURE) {
|
|
if (cursor.AtEndOfStream() || cursor.Read(8) != byte)
|
|
return error();
|
|
}
|
|
|
|
// Future-proofing: make sure we validate the control block before we try to
|
|
// read any other blocks.
|
|
bool hasValidControlBlock = false;
|
|
SmallVector<uint64_t, 64> scratch;
|
|
|
|
auto topLevelEntry = cursor.advance();
|
|
while (topLevelEntry.Kind == llvm::BitstreamEntry::SubBlock) {
|
|
switch (topLevelEntry.ID) {
|
|
case llvm::bitc::BLOCKINFO_BLOCK_ID:
|
|
if (cursor.ReadBlockInfoBlock())
|
|
return error();
|
|
break;
|
|
|
|
case CONTROL_BLOCK_ID: {
|
|
cursor.EnterSubBlock(CONTROL_BLOCK_ID);
|
|
|
|
ModuleStatus err = validateControlBlock(cursor, scratch);
|
|
if (err != ModuleStatus::Valid)
|
|
return error(err);
|
|
|
|
hasValidControlBlock = true;
|
|
break;
|
|
}
|
|
|
|
case INPUT_BLOCK_ID: {
|
|
if (!hasValidControlBlock)
|
|
return error();
|
|
|
|
cursor.EnterSubBlock(INPUT_BLOCK_ID);
|
|
|
|
auto next = cursor.advance();
|
|
while (next.Kind == llvm::BitstreamEntry::Record) {
|
|
scratch.clear();
|
|
StringRef blobData;
|
|
unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
|
|
switch (kind) {
|
|
case input_block::SOURCE_FILE:
|
|
assert(scratch.empty());
|
|
SourcePaths.push_back(blobData);
|
|
break;
|
|
default:
|
|
// Unknown input kind, possibly for use by a future version of the
|
|
// module format.
|
|
// FIXME: Should we warn about this?
|
|
break;
|
|
}
|
|
|
|
next = cursor.advance();
|
|
}
|
|
|
|
if (next.Kind != llvm::BitstreamEntry::EndBlock)
|
|
return error();
|
|
|
|
break;
|
|
}
|
|
|
|
case DECLS_AND_TYPES_BLOCK_ID: {
|
|
if (!hasValidControlBlock)
|
|
return error();
|
|
|
|
// The decls-and-types block is lazily loaded. Save the cursor and load
|
|
// any abbrev records at the start of the block.
|
|
DeclTypeCursor = cursor;
|
|
DeclTypeCursor.EnterSubBlock(DECLS_AND_TYPES_BLOCK_ID);
|
|
if (DeclTypeCursor.advance().Kind == llvm::BitstreamEntry::Error)
|
|
return error();
|
|
|
|
// With the main cursor, skip over the block and continue.
|
|
if (cursor.SkipBlock())
|
|
return error();
|
|
break;
|
|
}
|
|
|
|
case IDENTIFIER_DATA_BLOCK_ID: {
|
|
if (!hasValidControlBlock)
|
|
return error();
|
|
|
|
cursor.EnterSubBlock(IDENTIFIER_DATA_BLOCK_ID);
|
|
|
|
auto next = cursor.advanceSkippingSubblocks();
|
|
while (next.Kind == llvm::BitstreamEntry::Record) {
|
|
scratch.clear();
|
|
StringRef blobData;
|
|
unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
|
|
|
|
switch (kind) {
|
|
case identifier_block::IDENTIFIER_DATA:
|
|
assert(scratch.empty());
|
|
IdentifierData = blobData;
|
|
break;
|
|
default:
|
|
// Unknown identifier data, which this version of the compiler won't
|
|
// use.
|
|
break;
|
|
}
|
|
|
|
next = cursor.advanceSkippingSubblocks();
|
|
}
|
|
|
|
if (next.Kind != llvm::BitstreamEntry::EndBlock)
|
|
return error();
|
|
|
|
break;
|
|
}
|
|
|
|
case INDEX_BLOCK_ID: {
|
|
if (!hasValidControlBlock)
|
|
return error();
|
|
|
|
cursor.EnterSubBlock(INDEX_BLOCK_ID);
|
|
|
|
auto next = cursor.advanceSkippingSubblocks();
|
|
while (next.Kind == llvm::BitstreamEntry::Record) {
|
|
scratch.clear();
|
|
StringRef blobData;
|
|
unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
|
|
|
|
switch (kind) {
|
|
case index_block::DECL_OFFSETS:
|
|
assert(blobData.empty());
|
|
Decls.assign(scratch.begin(), scratch.end());
|
|
break;
|
|
case index_block::TYPE_OFFSETS:
|
|
assert(blobData.empty());
|
|
Types.assign(scratch.begin(), scratch.end());
|
|
break;
|
|
case index_block::IDENTIFIER_OFFSETS:
|
|
assert(blobData.empty());
|
|
Identifiers.assign(scratch.begin(), scratch.end());
|
|
break;
|
|
case index_block::TOP_LEVEL_DECLS:
|
|
assert(blobData.empty());
|
|
RawTopLevelIDs.assign(scratch.begin(), scratch.end());
|
|
break;
|
|
default:
|
|
// Unknown index kind, which this version of the compiler won't use.
|
|
break;
|
|
}
|
|
|
|
next = cursor.advanceSkippingSubblocks();
|
|
}
|
|
|
|
if (next.Kind != llvm::BitstreamEntry::EndBlock)
|
|
return error();
|
|
|
|
break;
|
|
}
|
|
|
|
case FALL_BACK_TO_TRANSLATION_UNIT_ID:
|
|
// This is a bring-up hack and will eventually go away.
|
|
Status = ModuleStatus::FallBackToTranslationUnit;
|
|
break;
|
|
|
|
default:
|
|
// Unknown top-level block, possibly for use by a future version of the
|
|
// module format.
|
|
if (cursor.SkipBlock())
|
|
return error();
|
|
break;
|
|
}
|
|
|
|
topLevelEntry = cursor.advance(llvm::BitstreamCursor::AF_DontPopBlockAtEnd);
|
|
}
|
|
|
|
if (topLevelEntry.Kind != llvm::BitstreamEntry::EndBlock)
|
|
return error();
|
|
}
|
|
|
|
void ModuleFile::buildTopLevelDeclMap() {
|
|
// FIXME: be more lazy about deserialization by encoding this some other way.
|
|
for (DeclID ID : RawTopLevelIDs) {
|
|
auto value = cast<ValueDecl>(getDecl(ID));
|
|
TopLevelIDs[value->getName()] = ID;
|
|
}
|
|
|
|
RawTopLevelIDs.clear();
|
|
}
|
|
|
|
void ModuleFile::lookupValue(Identifier name,
|
|
SmallVectorImpl<ValueDecl*> &results) {
|
|
if (!RawTopLevelIDs.empty())
|
|
buildTopLevelDeclMap();
|
|
|
|
if (DeclID ID = TopLevelIDs.lookup(name))
|
|
results.push_back(cast<ValueDecl>(getDecl(ID)));
|
|
}
|