// Returns true if we found enough information to terminate optimization. static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, size_t depth, bool& needsVarInjectionChecks, ResolveOp& op) { if (JSActivation* activation = jsDynamicCast<JSActivation*>(scope)) { if (ident == exec->propertyNames().arguments) { // We know the property will be at this activation scope, but we don't know how to cache it. op = ResolveOp(Dynamic, 0, 0, 0, 0); return true; } SymbolTableEntry entry = activation->symbolTable()->get(ident.impl()); if (entry.isReadOnly() && getOrPut == Put) { // We know the property will be at this activation scope, but we don't know how to cache it. op = ResolveOp(Dynamic, 0, 0, 0, 0); return true; } if (!entry.isNull()) { op = ResolveOp(makeType(ClosureVar, needsVarInjectionChecks), depth, activation->structure(), 0, entry.getIndex()); return true; } if (activation->symbolTable()->usesNonStrictEval()) needsVarInjectionChecks = true; return false; } if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(scope)) { SymbolTableEntry entry = globalObject->symbolTable()->get(ident.impl()); if (!entry.isNull()) { if (getOrPut == Put && entry.isReadOnly()) { // We know the property will be at global scope, but we don't know how to cache it. op = ResolveOp(Dynamic, 0, 0, 0, 0); return true; } op = ResolveOp( makeType(GlobalVar, needsVarInjectionChecks), depth, 0, entry.watchpointSet(), reinterpret_cast<uintptr_t>(globalObject->registerAt(entry.getIndex()).slot())); return true; } PropertySlot slot(globalObject); if (!globalObject->getOwnPropertySlot(globalObject, exec, ident, slot) || !slot.isCacheableValue() || !globalObject->structure()->propertyAccessesAreCacheable() || (globalObject->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto() && getOrPut == Put)) { // We know the property will be at global scope, but we don't know how to cache it. ASSERT(!scope->next()); op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, 0, 0, 0); return true; } op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, globalObject->structure(), 0, slot.cachedOffset()); return true; } op = ResolveOp(Dynamic, 0, 0, 0, 0); return true; }
Type Type::substitute(const std::vector<Type>& types, const std::vector<Type>& replacements) const { NodeManagerScope nms(d_nodeManager); vector<TypeNode> typesNodes, replacementsNodes; for(vector<Type>::const_iterator i = types.begin(), iend = types.end(); i != iend; ++i) { typesNodes.push_back(*(*i).d_typeNode); } for(vector<Type>::const_iterator i = replacements.begin(), iend = replacements.end(); i != iend; ++i) { replacementsNodes.push_back(*(*i).d_typeNode); } return makeType(d_typeNode->substitute(typesNodes.begin(), typesNodes.end(), replacementsNodes.begin(), replacementsNodes.end())); }
/** * @brief ComponentsMaker::makeField * @return */ OptionalEntity ComponentsMaker::makeField(const Tokens &tokens) { Q_ASSERT(!tokens.isEmpty() && tokens[int(FieldGroupNames::Typename)]->isSingle() && !tokens[int(FieldGroupNames::Typename)]->token().isEmpty() && tokens[int(FieldGroupNames::Name)]->isSingle() && !tokens[int(FieldGroupNames::Name)]->token().isEmpty()); Q_ASSERT(checkCommonState()); // Make field with lhs keywords auto newField = std::make_shared<entity::Field>(); newField->setName(tokens[int(FieldGroupNames::Name)]->token()); if (!tokens[int(FieldGroupNames::LhsKeywords)]->token().isEmpty()) { auto keyword = utility::fieldKeywordFromString(tokens[int(FieldGroupNames::LhsKeywords)]->token()); Q_ASSERT(keyword != entity::FieldKeyword::Invalid); newField->addKeyword(keyword); } // Make type Tokens typeTokens(int(TypeGroups::GroupsCount)); std::copy(std::begin(tokens) + int(FieldGroupNames::ConstStatus), std::begin(tokens) + int(FieldGroupNames::Name), // do not include name std::begin(typeTokens) + int(TypeGroups::ConstStatus)); // add first group offset auto optionalType = makeType(typeTokens); if (!optionalType.errorMessage.isEmpty()) return {optionalType.errorMessage, nullptr}; Q_ASSERT(optionalType.resultEntity); newField->setTypeId(optionalType.resultEntity->id()); return {"", newField}; }
SortType SortConstructorType::instantiate(const std::vector<Type>& params) const { NodeManagerScope nms(d_nodeManager); vector<TypeNode> paramsNodes; for(vector<Type>::const_iterator i = params.begin(), iend = params.end(); i != iend; ++i) { paramsNodes.push_back(*getTypeNode(*i)); } return SortType(makeType(d_nodeManager->mkSort(*d_typeNode, paramsNodes))); }
vector<Type> SExprType::getTypes() const { NodeManagerScope nms(d_nodeManager); vector<Type> types; vector<TypeNode> typeNodes = d_typeNode->getSExprTypes(); vector<TypeNode>::iterator it = typeNodes.begin(); vector<TypeNode>::iterator it_end = typeNodes.end(); for(; it != it_end; ++ it) { types.push_back(makeType(*it)); } return types; }
std::vector<Type> DatatypeType::getParamTypes() const { NodeManagerScope nms(d_nodeManager); vector<Type> params; vector<TypeNode> paramNodes = d_typeNode->getParamTypes(); vector<TypeNode>::iterator it = paramNodes.begin(); vector<TypeNode>::iterator it_end = paramNodes.end(); for(; it != it_end; ++it) { params.push_back(makeType(*it)); } return params; }
std::vector<Type> ConstructorType::getArgTypes() const { NodeManagerScope nms(d_nodeManager); vector<Type> args; vector<TypeNode> argNodes = d_typeNode->getArgTypes(); vector<TypeNode>::iterator it = argNodes.begin(); vector<TypeNode>::iterator it_end = argNodes.end(); for(; it != it_end; ++ it) { args.push_back(makeType(*it)); } return args; }
/** * @brief SignatureMaker::makeTypeOrExt * @param type * @return */ QString SignatureMaker::makeTypeOrExtType(const Entity::SharedType &type) const { if (!type) return ""; if (type->hashType() == Entity::ExtendedType::staticHashType()) // Return extended type which may be alias (with optioanl *, &, const) return makeExtType(std::static_pointer_cast<Entity::ExtendedType>(type)); else // Or return name (with namespaces) of type, class, enum or union return makeType(type); }
DatatypeType DatatypeType::instantiate(const std::vector<Type>& params) const { NodeManagerScope nms(d_nodeManager); TypeNode cons = d_nodeManager->mkTypeConst( getDatatype() ); vector<TypeNode> paramsNodes; paramsNodes.push_back( cons ); for(vector<Type>::const_iterator i = params.begin(), iend = params.end(); i != iend; ++i) { paramsNodes.push_back(*getTypeNode(*i)); } return DatatypeType(makeType(d_nodeManager->mkTypeNode(kind::PARAMETRIC_DATATYPE, paramsNodes))); }
std::shared_ptr<TypeInfo> DwarfVariableFinder::getType(const DWARFDie &die) { if (!die.isValid()) { assert(0); return std::make_shared<TypeInfo>("", ~0u); } auto die_offset = die.getOffset(); if(typeDict.count(die_offset)) { return typeDict[die_offset]; } auto result = makeType(die); typeDict[die_offset] = result; return result; }
Type ArrayType::getIndexType() const { return makeType(d_typeNode->getArrayIndexType()); }
DatatypeType ConstructorType::getRangeType() const { return DatatypeType(makeType(d_typeNode->getConstructorRangeType())); }
/** * @brief ComponentsMaker::makeMethod * @param tokens * @return */ OptionalEntity ComponentsMaker::makeMethod(const Tokens &tokens) { Q_ASSERT(!tokens.isEmpty() && tokens[int(MethodsGroupsNames::ReturnType)]->isMulti() && tokens[int(MethodsGroupsNames::Name)]->isSingle()); Q_ASSERT(checkCommonState()); entity::SharedMethod newMethod = std::make_shared<entity::ClassMethod>(); // Add Lhs auto lhsToken = tokens[int(MethodsGroupsNames::LhsKeywords)]; Q_ASSERT(!lhsToken->isEmpty() && lhsToken->isSingle()); for (auto &&w : lhsToken->token().split(QChar::Space, QString::SkipEmptyParts)) { entity::LhsIdentificator id = utility::methodLhsIdFromString(w); Q_ASSERT(id != entity::LhsIdentificator::None); newMethod->addLhsIdentificator(id); } // Add return type auto returnTypeToken = tokens[int(MethodsGroupsNames::ReturnType)]; Q_ASSERT(returnTypeToken->isMulti() && !returnTypeToken->isEmpty()); auto returnType = makeType(returnTypeToken->tokens()); if (!returnType.errorMessage.isEmpty()) return {returnType.errorMessage, nullptr}; newMethod->setReturnTypeId(returnType.resultEntity->id()); // Add name newMethod->setName(tokens[int(MethodsGroupsNames::Name)]->token()); // Add arguments auto argumentsToken = tokens[int(MethodsGroupsNames::Arguments)]; Q_ASSERT(argumentsToken->isEmpty() || argumentsToken->isMulti()); if (argumentsToken->isMulti()) { auto argumentsTokens = argumentsToken->tokens(); for (auto &&argumentToken : argumentsTokens) { Q_ASSERT(argumentToken->isMulti()); auto argSubTokens = argumentToken->tokens(); Q_ASSERT(argSubTokens.size() == int(Argument::GroupsCount)); Q_ASSERT(argSubTokens[int(Argument::Name)]->isSingle()); auto name = argSubTokens[int(Argument::Name)]->token(); Q_ASSERT(argSubTokens[int(Argument::Type)]->isMulti()); auto type = makeType(argSubTokens[int(Argument::Type)]->tokens()); if (!type.errorMessage.isEmpty()) return {tr("Wrong type of argument: %1. Error: %2.").arg( QString::number(argumentsTokens.indexOf(argumentToken)), type.errorMessage ), nullptr}; Q_ASSERT(type.resultEntity); newMethod->addParameter(name, type.resultEntity->id()); } } // Const auto constArgument = tokens[int(MethodsGroupsNames::Const)]; Q_ASSERT(!constArgument->isEmpty() && constArgument->isSingle()); const QString &token = constArgument->token(); if (!token.isEmpty()) { if (token == "const") newMethod->setConstStatus(true); else return {tr("Wrong const status token: %1.").arg(constArgument->token()), nullptr}; } // Rhs auto rhsArgument = tokens[int(MethodsGroupsNames::RhsKeywords)]; Q_ASSERT(!rhsArgument->isEmpty() && rhsArgument->isSingle()); const QString &rhsToken = rhsArgument->token(); if (!rhsToken.isEmpty()) { entity::RhsIdentificator rhsId = utility::methodRhsIdFromString(rhsToken); if (rhsId != entity::RhsIdentificator::None) newMethod->setRhsIdentificator(rhsId); else return {tr("Wrong rhs keyword: %1").arg(rhsToken), nullptr}; } return {"", newMethod}; }
// Returns true if we found enough information to terminate optimization. static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, size_t depth, bool& needsVarInjectionChecks, ResolveOp& op, InitializationMode initializationMode) { if (scope->isJSLexicalEnvironment()) { JSLexicalEnvironment* lexicalEnvironment = jsCast<JSLexicalEnvironment*>(scope); if (ident == exec->propertyNames().arguments) { // We know the property will be at this lexical environment scope, but we don't know how to cache it. op = ResolveOp(Dynamic, 0, 0, 0, 0, 0); return true; } SymbolTable* symbolTable = lexicalEnvironment->symbolTable(); { ConcurrentJSLocker locker(symbolTable->m_lock); auto iter = symbolTable->find(locker, ident.impl()); if (iter != symbolTable->end(locker)) { SymbolTableEntry& entry = iter->value; ASSERT(!entry.isNull()); if (entry.isReadOnly() && getOrPut == Put) { // We know the property will be at this lexical environment scope, but we don't know how to cache it. op = ResolveOp(Dynamic, 0, 0, 0, 0, 0); return true; } op = ResolveOp(makeType(ClosureVar, needsVarInjectionChecks), depth, 0, lexicalEnvironment, entry.watchpointSet(), entry.scopeOffset().offset()); return true; } } if (scope->type() == ModuleEnvironmentType) { JSModuleEnvironment* moduleEnvironment = jsCast<JSModuleEnvironment*>(scope); AbstractModuleRecord* moduleRecord = moduleEnvironment->moduleRecord(); AbstractModuleRecord::Resolution resolution = moduleRecord->resolveImport(exec, ident); if (resolution.type == AbstractModuleRecord::Resolution::Type::Resolved) { AbstractModuleRecord* importedRecord = resolution.moduleRecord; JSModuleEnvironment* importedEnvironment = importedRecord->moduleEnvironment(); SymbolTable* symbolTable = importedEnvironment->symbolTable(); ConcurrentJSLocker locker(symbolTable->m_lock); auto iter = symbolTable->find(locker, resolution.localName.impl()); ASSERT(iter != symbolTable->end(locker)); SymbolTableEntry& entry = iter->value; ASSERT(!entry.isNull()); op = ResolveOp(makeType(ModuleVar, needsVarInjectionChecks), depth, 0, importedEnvironment, entry.watchpointSet(), entry.scopeOffset().offset(), resolution.localName.impl()); return true; } } if (symbolTable->usesNonStrictEval()) needsVarInjectionChecks = true; return false; } if (scope->isGlobalLexicalEnvironment()) { JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(scope); SymbolTable* symbolTable = globalLexicalEnvironment->symbolTable(); ConcurrentJSLocker locker(symbolTable->m_lock); auto iter = symbolTable->find(locker, ident.impl()); if (iter != symbolTable->end(locker)) { SymbolTableEntry& entry = iter->value; ASSERT(!entry.isNull()); if (getOrPut == Put && entry.isReadOnly() && !isInitialization(initializationMode)) { // We know the property will be at global lexical environment, but we don't know how to cache it. op = ResolveOp(Dynamic, 0, 0, 0, 0, 0); return true; } // We can force const Initialization to always go down the fast path. It is provably impossible to construct // a program that needs a var injection check here. You can convince yourself of this as follows: // Any other let/const/class would be a duplicate of this in the global scope, so we would never get here in that situation. // Also, if we had an eval in the global scope that defined a const, it would also be a duplicate of this const, and so it would // also throw an error. Therefore, we're *the only* thing that can assign to this "const" slot for the first (and only) time. Also, // we will never have a Dynamic ResolveType here because if we were inside a "with" statement, that would mean the "const" definition // isn't a global, it would be a local to the "with" block. // We still need to make the slow path correct for when we need to fire a watchpoint. ResolveType resolveType = initializationMode == InitializationMode::ConstInitialization ? GlobalLexicalVar : makeType(GlobalLexicalVar, needsVarInjectionChecks); op = ResolveOp( resolveType, depth, 0, 0, entry.watchpointSet(), reinterpret_cast<uintptr_t>(globalLexicalEnvironment->variableAt(entry.scopeOffset()).slot())); return true; } return false; } if (scope->isGlobalObject()) { JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(scope); { SymbolTable* symbolTable = globalObject->symbolTable(); ConcurrentJSLocker locker(symbolTable->m_lock); auto iter = symbolTable->find(locker, ident.impl()); if (iter != symbolTable->end(locker)) { SymbolTableEntry& entry = iter->value; ASSERT(!entry.isNull()); if (getOrPut == Put && entry.isReadOnly()) { // We know the property will be at global scope, but we don't know how to cache it. op = ResolveOp(Dynamic, 0, 0, 0, 0, 0); return true; } op = ResolveOp( makeType(GlobalVar, needsVarInjectionChecks), depth, 0, 0, entry.watchpointSet(), reinterpret_cast<uintptr_t>(globalObject->variableAt(entry.scopeOffset()).slot())); return true; } } PropertySlot slot(globalObject, PropertySlot::InternalMethodType::VMInquiry); bool hasOwnProperty = globalObject->getOwnPropertySlot(globalObject, exec, ident, slot); if (!hasOwnProperty) { op = ResolveOp(makeType(UnresolvedProperty, needsVarInjectionChecks), 0, 0, 0, 0, 0); return true; } if (!slot.isCacheableValue() || !globalObject->structure()->propertyAccessesAreCacheable() || (globalObject->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto() && getOrPut == Put)) { // We know the property will be at global scope, but we don't know how to cache it. ASSERT(!scope->next()); op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), 0, 0, 0, 0, 0); return true; } WatchpointState state = globalObject->structure()->ensurePropertyReplacementWatchpointSet(exec->vm(), slot.cachedOffset())->state(); if (state == IsWatched && getOrPut == Put) { // The field exists, but because the replacement watchpoint is still intact. This is // kind of dangerous. We have two options: // 1) Invalidate the watchpoint set. That would work, but it's possible that this code // path never executes - in which case this would be unwise. // 2) Have the invalidation happen at run-time. All we have to do is leave the code // uncached. The only downside is slightly more work when this does execute. // We go with option (2) here because it seems less evil. op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, 0, 0, 0, 0); } else op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, globalObject->structure(), 0, 0, slot.cachedOffset()); return true; } op = ResolveOp(Dynamic, 0, 0, 0, 0, 0); return true; }
// Returns true if we found enough information to terminate optimization. static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, size_t depth, bool& needsVarInjectionChecks, ResolveOp& op) { if (JSActivation* activation = jsDynamicCast<JSActivation*>(scope)) { if (ident == exec->propertyNames().arguments) { // We know the property will be at this activation scope, but we don't know how to cache it. op = ResolveOp(Dynamic, 0, 0, 0, 0, 0); return true; } SymbolTableEntry entry = activation->symbolTable()->get(ident.impl()); if (entry.isReadOnly() && getOrPut == Put) { // We know the property will be at this activation scope, but we don't know how to cache it. op = ResolveOp(Dynamic, 0, 0, 0, 0, 0); return true; } if (!entry.isNull()) { op = ResolveOp(makeType(ClosureVar, needsVarInjectionChecks), depth, 0, activation, entry.watchpointSet(), entry.getIndex()); return true; } if (activation->symbolTable()->usesNonStrictEval()) needsVarInjectionChecks = true; return false; } if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(scope)) { SymbolTableEntry entry = globalObject->symbolTable()->get(ident.impl()); if (!entry.isNull()) { if (getOrPut == Put && entry.isReadOnly()) { // We know the property will be at global scope, but we don't know how to cache it. op = ResolveOp(Dynamic, 0, 0, 0, 0, 0); return true; } op = ResolveOp( makeType(GlobalVar, needsVarInjectionChecks), depth, 0, 0, entry.watchpointSet(), reinterpret_cast<uintptr_t>(globalObject->registerAt(entry.getIndex()).slot())); return true; } PropertySlot slot(globalObject); if (!globalObject->getOwnPropertySlot(globalObject, exec, ident, slot) || !slot.isCacheableValue() || !globalObject->structure()->propertyAccessesAreCacheable() || (globalObject->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto() && getOrPut == Put)) { // We know the property will be at global scope, but we don't know how to cache it. ASSERT(!scope->next()); op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, 0, 0, 0, 0); return true; } WatchpointState state = globalObject->structure()->ensurePropertyReplacementWatchpointSet(exec->vm(), slot.cachedOffset())->state(); if (state == IsWatched && getOrPut == Put) { // The field exists, but because the replacement watchpoint is still intact. This is // kind of dangerous. We have two options: // 1) Invalidate the watchpoint set. That would work, but it's possible that this code // path never executes - in which case this would be unwise. // 2) Have the invalidation happen at run-time. All we have to do is leave the code // uncached. The only downside is slightly more work when this does execute. // We go with option (2) here because it seems less evil. op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, 0, 0, 0, 0); } else op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, globalObject->structure(), 0, 0, slot.cachedOffset()); return true; } op = ResolveOp(Dynamic, 0, 0, 0, 0, 0); return true; }
Type ArrayType::getConstituentType() const { return makeType(d_typeNode->getArrayConstituentType()); }
Type SetType::getElementType() const { return makeType(d_typeNode->getSetElementType()); }
std::shared_ptr<TypeInfo> DwarfVariableFinder::makeType(const DWARFDie &die) { if (!die.isValid()) { return std::make_shared<TypeInfo>("", ~0u); } auto opSize = die.find(dwarf::DW_AT_byte_size); unsigned size = 1; if(opSize.hasValue()) { size = opSize.getValue().getAsUnsignedConstant().getValue(); } std::string type_encoding = ""; raw_string_ostream SS(type_encoding); switch (die.getTag()) { case dwarf::DW_TAG_base_type: { auto opForm = die.find(dwarf::DW_AT_encoding); auto opEnc = opForm->getAsUnsignedConstant(); assert(opEnc < HANDLE_DW_ATE_SIZE); SS << HANDLE_DW_ATE[*opEnc]; opForm = die.find(dwarf::DW_AT_name); opForm->dump(SS); return std::make_shared<TypeInfo>(SS.str(), size); } case dwarf::DW_TAG_reference_type: case dwarf::DW_TAG_rvalue_reference_type: case dwarf::DW_TAG_pointer_type: { auto baseType = getType(die.getAttributeValueAsReferencedDie(dwarf::DW_AT_type)); SS << "*" << baseType->getName(); return std::make_shared<TypeInfo>(SS.str(), size); } case dwarf::DW_TAG_array_type: { auto baseType = getType(die.getAttributeValueAsReferencedDie(dwarf::DW_AT_type)); SS << baseType->getName(); size *= baseType->getSize(); for (auto childDie = die.getFirstChild(); childDie && childDie.getTag(); childDie = childDie.getSibling()) { std::shared_ptr<TypeInfo> rangeInfo = makeType(childDie); SS << "["; SS << rangeInfo->getName(); SS << "]"; size *= rangeInfo->getSize(); } return std::make_shared<TypeInfo>(SS.str(), size); } case dwarf::DW_TAG_subrange_type: { uint64_t count = 0; auto opCount = die.find(dwarf::DW_AT_count); if(opCount.hasValue()) { count = opCount.getValue().getAsUnsignedConstant().getValue(); } else { opCount = die.find(dwarf::DW_AT_upper_bound); assert(opCount.hasValue()); count = opCount.getValue().getAsUnsignedConstant().getValue() +1; } return std::make_shared<TypeInfo>(std::to_string(count), count); } case dwarf::DW_TAG_typedef: { return getType(die.getAttributeValueAsReferencedDie(dwarf::DW_AT_type)); } case dwarf::DW_TAG_structure_type: case dwarf::DW_TAG_class_type: case dwarf::DW_TAG_union_type: { SS << "struct" << dwarf::toString(die.find(dwarf::DW_AT_name), "None"); auto structType = std::make_shared<TypeInfo>(SS.str(), size); // Add subentries for various pieces of the struct. for (auto childDie = die.getFirstChild(); childDie && childDie.getTag(); childDie = childDie.getSibling()) { if (childDie.getTag() != dwarf::DW_TAG_inheritance && childDie.getTag() != dwarf::DW_TAG_member) { continue; } uint64_t dataMemOffset = dwarf::toUnsigned(childDie.find(dwarf::DW_AT_data_member_location), ~0U); structType->getFields().emplace_back(makeType(childDie), dataMemOffset); } return structType; } case dwarf::DW_TAG_inheritance: case dwarf::DW_TAG_member: { return getType(die.getAttributeValueAsReferencedDie(dwarf::DW_AT_type)); } default: { auto tagString = TagString(die.getTag()); if (tagString.empty()) { llvm::errs() << format("DW_TAG_Unknown_%x", die.getTag()); } die.dump(llvm::errs(), 10); return std::make_shared<TypeInfo>("", ~0u); } } }
Type Type::substitute(const Type& type, const Type& replacement) const { NodeManagerScope nms(d_nodeManager); return makeType(d_typeNode->substitute(*type.d_typeNode, *replacement.d_typeNode)); }
Type FunctionType::getRangeType() const { NodeManagerScope nms(d_nodeManager); PrettyCheckArgument(isNull() || isFunction(), this); return makeType(d_typeNode->getRangeType()); }
BooleanType TesterType::getRangeType() const { return BooleanType(makeType(d_nodeManager->booleanType())); }
bindError("non null pointer type expected", nonNullTypeErr); bindError("non positive inj expression expected", nonPosInjErr); bindError("unexpected object", objectErr); bindError("positive inj expression expected", posInjErr); bindError("out of range", rangeErr); bindError("cannot report error", reportErr); bindError("subsumed form", subsumedFormErr); bindError("too few elements", tooFewElemsErr); bindError("too many elements", tooManyElemsErr); bindError("expression has unexpected type", typeErr); bindError("type exe expression expected", typeExeErr); bindError("type mut expression expected", typeMutErr); bindError("type obj expression expected", typeObjErr); bindError("type size too large", typeSizeErr); bindError("type type obj expression expected", typeTypeObjErr); bindError("version does not match", versionErr); bindError("zero inj expression expected", zeroInjErr); // Make external types. These must be defined here, and not in a prelude file, // because Orson code can't get the alignment or size of a C type. The garbage // collector must explicitly mark the types to which names are not bound. voidExternal = makeType(void); fileExternal = makeType(FILE); labelExternal = makeType(sigjmp_buf); // Bind secret names to externals. We can mention these in the prelude. bindSecret("File", makePrefix(typeHook, fileExternal), fileExternal); bindSecret("Label", makePrefix(typeHook, labelExternal), labelExternal); }
Type SelectorType::getRangeType() const { return makeType((*d_typeNode)[1]); }
DatatypeType TesterType::getDomain() const { return DatatypeType(makeType((*d_typeNode)[0])); }
static bool runStatement(ASTNode* node, MemoryStack* stack, Scope* scope, RuntimeError* error) { switch (node->nodeType) { case AST_STATEMENT_TYPE_DEFINITION: { if (getTypeDefinition(scope, node->typeDefinition.identifier, false)) { *error = RuntimeError{ RET_TYPE_ALREADY_DEFINED, node->typeDefinition.identifier, node->typeDefinition.lineNumber }; return false; } else { TypeDefinition* typeDef = scopePushToList(scope, stack, &scope->types); typeDef->identifier = node->typeDefinition.identifier; typeDef->members = {}; ListIterator<ASTNode> iterator = makeIterator(&node->typeDefinition.definitions); int currOffsetInBytes = 0; while (hasNext(&iterator)) { ASTNode* node = getNext(&iterator); StructMember* member = scopePushToList(scope, stack, &typeDef->members); member->identifier = node->variableDeclaration.identifier; member->type = makeType(scope, node->variableDeclaration.typeIdentifier); member->offsetInBytes = currOffsetInBytes; currOffsetInBytes += member->type.definition->totalSizeInBytes; } typeDef->totalSizeInBytes = currOffsetInBytes; return true; } } break; case AST_STATEMENT_VARIABLE_DECLARATION: { if (getVariable(scope, node->variableDeclaration.identifier, false)) { *error = RuntimeError{ RET_VARIABLE_ALREADY_DEFINED, node->variableDeclaration.identifier, node->variableDeclaration.lineNumber }; return false; } else { Variable* var = defineAVariable( node->variableDeclaration.identifier, makeType(scope, node->variableDeclaration.typeIdentifier), stack, scope); if (node->variableDeclaration.expression) return runExpression(node->variableDeclaration.expression, stack, scope, error, &var->value); else return true; // TODO: set default value } } break; case AST_STATEMENT_FUNCTION_DEFINITION: { Function func; func.type = FT_INTERNAL; func.identifier.name = node->functionDefinition.identifier; func.identifier.arguments = {}; bool stillWorking = true; if (!node->functionDefinition.returnType) func.returnType = Type{ nullptr, 0 }; else { func.returnType = makeType(scope, node->functionDefinition.returnType); if (!func.returnType.definition) { *error = RuntimeError{ RET_UNDEFINED_TYPE, node->functionDefinition.returnType->typeIdentifier.name, node->functionDefinition.lineNumber }; stillWorking = false; } } ListIterator<ASTNode> args = makeIterator(&node->functionDefinition.arguments); while (stillWorking && hasNext(&args)) { ASTNode* arg = getNext(&args); Argument* argument = scopePushToList(scope, stack, &func.identifier.arguments); argument->identifier = arg->variableDeclaration.identifier; argument->type = makeType(scope, arg->variableDeclaration.typeIdentifier); if (!argument->type.definition) { *error = RuntimeError{ RET_UNDEFINED_TYPE, arg->variableDeclaration.typeIdentifier->typeIdentifier.name, arg->variableDeclaration.lineNumber }; stillWorking = false; } } func.body = node->functionDefinition.body; Function* hasFunc = getFunction(scope, func.identifier, false); if (hasFunc) { *error = RuntimeError{ RET_FUNCTION_ALREADY_DEFINED, node->functionDefinition.identifier, node->functionDefinition.lineNumber }; stillWorking = false; } else { *scopePushToList(scope, stack, &scope->functions) = func; } return stillWorking; } break; case AST_STATEMENT_IF: { Scope ifScope = makeScope(scope); Value conditionResult = pushValue(&ifScope, stack, Type{ getTypeDefinition(scope, makeSlice("s32")), false }); bool stillWorking = runExpression(node->ifStatement.condition, stack, scope, error, &conditionResult); if (stillWorking) { if (*(int*)conditionResult.memory != 0) { stillWorking = runStatement(node->ifStatement.ifCase, stack, &ifScope, error); } else if (node->ifStatement.elseCase != nullptr) { stillWorking = runStatement(node->ifStatement.elseCase, stack, &ifScope, error); } } scopeFreeMemory(&ifScope, stack); return stillWorking; } break; case AST_STATEMENT_WHILE: { Scope whileScope = makeScope(scope); Value conditionResult = pushValue(&whileScope, stack, Type{ getTypeDefinition(scope, makeSlice("s32")), false }); bool stillWorking = runExpression(node->whileStatement.condition, stack, scope, error, &conditionResult); if (stillWorking) { while (*(int*)conditionResult.memory != 0) { if (!(stillWorking = runStatement(node->whileStatement.body, stack, &whileScope, error))) break; if (!(stillWorking = runExpression(node->whileStatement.condition, stack, scope, error, &conditionResult))) break; } } scopeFreeMemory(&whileScope, stack); return stillWorking; } break; case AST_STATEMENT_ASSIGNMENT: { Value value; if (getValue(scope, node->assignment.lValue, error, &value)) { return runExpression(node->assignment.expression, stack, scope, error, &value); } else return false; } break; case AST_STATEMENTS_BLOCK: { Scope blockScope = makeScope(scope); bool result = runStatements(&node->statementsBlock.statements, stack, &blockScope, error); scopeFreeMemory(&blockScope, stack); return result; } break; case AST_FUNCTION_CALL: { return runFunctionCall(node, stack, scope, error, nullptr); } break; default: { assert(!"this is not a statement!"); return false; } break; } }