Sync to upstream/release/581 (#958)
* Definition files can now ascribe indexers to class types. (https://github.com/Roblox/luau/pull/949) * Remove --compile support from the REPL. You can just use luau-compile instead. * When an exception is thrown during parallel typechecking (usually an ICE), we now gracefully stop typechecking and drain active workers before rethrowing the exception. New solver * Include more source location information when we hit an internal compiler error * Improve the logic that simplifies intersections of tables JIT * Save testable type annotations to bytecode * Improve block placement for linearized blocks * Add support for lea reg, [rip+offset] for labels * Unify X64 and A64 codegen for RETURN * Outline interrupt handlers for X64 * Remove global rArgN in favor of build.abi * Change A64 INTERRUPT lowering to match X64 --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
This commit is contained in:
parent
bc0722471f
commit
d458d240cd
|
@ -174,10 +174,10 @@ struct ConstraintSolver
|
|||
bool blockOnPendingTypes(TypePackId target, NotNull<const Constraint> constraint);
|
||||
|
||||
void unblock(NotNull<const Constraint> progressed);
|
||||
void unblock(TypeId progressed);
|
||||
void unblock(TypePackId progressed);
|
||||
void unblock(const std::vector<TypeId>& types);
|
||||
void unblock(const std::vector<TypePackId>& packs);
|
||||
void unblock(TypeId progressed, Location location);
|
||||
void unblock(TypePackId progressed, Location location);
|
||||
void unblock(const std::vector<TypeId>& types, Location location);
|
||||
void unblock(const std::vector<TypePackId>& packs, Location location);
|
||||
|
||||
/**
|
||||
* @returns true if the TypeId is in a blocked state.
|
||||
|
|
|
@ -539,8 +539,8 @@ bool ConstraintSolver::tryDispatch(const GeneralizationConstraint& c, NotNull<co
|
|||
asMutable(c.generalizedType)->ty.emplace<BoundType>(builtinTypes->errorRecoveryType());
|
||||
}
|
||||
|
||||
unblock(c.generalizedType);
|
||||
unblock(c.sourceType);
|
||||
unblock(c.generalizedType, constraint->location);
|
||||
unblock(c.sourceType, constraint->location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -564,7 +564,7 @@ bool ConstraintSolver::tryDispatch(const InstantiationConstraint& c, NotNull<con
|
|||
reportError(UnificationTooComplex{}, constraint->location);
|
||||
|
||||
asMutable(c.subType)->ty.emplace<BoundType>(errorRecoveryType());
|
||||
unblock(c.subType);
|
||||
unblock(c.subType, constraint->location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -574,7 +574,7 @@ bool ConstraintSolver::tryDispatch(const InstantiationConstraint& c, NotNull<con
|
|||
InstantiationQueuer queuer{constraint->scope, constraint->location, this};
|
||||
queuer.traverse(c.subType);
|
||||
|
||||
unblock(c.subType);
|
||||
unblock(c.subType, constraint->location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -597,7 +597,7 @@ bool ConstraintSolver::tryDispatch(const UnaryConstraint& c, NotNull<const Const
|
|||
{
|
||||
asMutable(c.resultType)->ty.emplace<BoundType>(builtinTypes->booleanType);
|
||||
|
||||
unblock(c.resultType);
|
||||
unblock(c.resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
case AstExprUnary::Len:
|
||||
|
@ -605,7 +605,7 @@ bool ConstraintSolver::tryDispatch(const UnaryConstraint& c, NotNull<const Const
|
|||
// __len must return a number.
|
||||
asMutable(c.resultType)->ty.emplace<BoundType>(builtinTypes->numberType);
|
||||
|
||||
unblock(c.resultType);
|
||||
unblock(c.resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
case AstExprUnary::Minus:
|
||||
|
@ -635,7 +635,7 @@ bool ConstraintSolver::tryDispatch(const UnaryConstraint& c, NotNull<const Const
|
|||
asMutable(c.resultType)->ty.emplace<BoundType>(builtinTypes->errorRecoveryType());
|
||||
}
|
||||
|
||||
unblock(c.resultType);
|
||||
unblock(c.resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -684,7 +684,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
|
|||
if (isBlocked(leftType) || (hasTypeInIntersection<FreeType>(leftType) && !isLogical))
|
||||
{
|
||||
asMutable(resultType)->ty.emplace<BoundType>(errorRecoveryType());
|
||||
unblock(resultType);
|
||||
unblock(resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -697,7 +697,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
|
|||
{
|
||||
// TODO: Boolean singleton false? The result is _always_ boolean false.
|
||||
asMutable(resultType)->ty.emplace<BoundType>(builtinTypes->booleanType);
|
||||
unblock(resultType);
|
||||
unblock(resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -760,7 +760,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
|
|||
}
|
||||
|
||||
asMutable(resultType)->ty.emplace<BoundType>(mmResult);
|
||||
unblock(resultType);
|
||||
unblock(resultType, constraint->location);
|
||||
|
||||
(*c.astOriginalCallTypes)[c.astFragment] = *mm;
|
||||
(*c.astOverloadResolvedTypes)[c.astFragment] = *instantiatedMm;
|
||||
|
@ -790,14 +790,14 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
|
|||
{
|
||||
unify(leftType, rightType, constraint->scope);
|
||||
asMutable(resultType)->ty.emplace<BoundType>(anyPresent ? builtinTypes->anyType : leftType);
|
||||
unblock(resultType);
|
||||
unblock(resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
else if (get<NeverType>(leftType) || get<NeverType>(rightType))
|
||||
{
|
||||
unify(leftType, rightType, constraint->scope);
|
||||
asMutable(resultType)->ty.emplace<BoundType>(builtinTypes->neverType);
|
||||
unblock(resultType);
|
||||
unblock(resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -814,14 +814,14 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
|
|||
{
|
||||
unify(leftType, rightType, constraint->scope);
|
||||
asMutable(resultType)->ty.emplace<BoundType>(anyPresent ? builtinTypes->anyType : leftType);
|
||||
unblock(resultType);
|
||||
unblock(resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
else if (get<NeverType>(leftType) || get<NeverType>(rightType))
|
||||
{
|
||||
unify(leftType, rightType, constraint->scope);
|
||||
asMutable(resultType)->ty.emplace<BoundType>(builtinTypes->neverType);
|
||||
unblock(resultType);
|
||||
unblock(resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -840,14 +840,14 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
|
|||
if (lt && rt && (lt->isExactlyNumber() || get<AnyType>(lt->tops)) && rt->isExactlyNumber())
|
||||
{
|
||||
asMutable(resultType)->ty.emplace<BoundType>(builtinTypes->booleanType);
|
||||
unblock(resultType);
|
||||
unblock(resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (lt && rt && (lt->isSubtypeOfString() || get<AnyType>(lt->tops)) && rt->isSubtypeOfString())
|
||||
{
|
||||
asMutable(resultType)->ty.emplace<BoundType>(builtinTypes->booleanType);
|
||||
unblock(resultType);
|
||||
unblock(resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -855,7 +855,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
|
|||
if (get<NeverType>(leftType) || get<NeverType>(rightType))
|
||||
{
|
||||
asMutable(resultType)->ty.emplace<BoundType>(builtinTypes->booleanType);
|
||||
unblock(resultType);
|
||||
unblock(resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -867,7 +867,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
|
|||
case AstExprBinary::Op::CompareEq:
|
||||
case AstExprBinary::Op::CompareNe:
|
||||
asMutable(resultType)->ty.emplace<BoundType>(builtinTypes->booleanType);
|
||||
unblock(resultType);
|
||||
unblock(resultType, constraint->location);
|
||||
return true;
|
||||
// And evalutes to a boolean if the LHS is falsey, and the RHS type if LHS is
|
||||
// truthy.
|
||||
|
@ -876,7 +876,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
|
|||
TypeId leftFilteredTy = simplifyIntersection(builtinTypes, arena, leftType, builtinTypes->falsyType).result;
|
||||
|
||||
asMutable(resultType)->ty.emplace<BoundType>(simplifyUnion(builtinTypes, arena, rightType, leftFilteredTy).result);
|
||||
unblock(resultType);
|
||||
unblock(resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
// Or evaluates to the LHS type if the LHS is truthy, and the RHS type if
|
||||
|
@ -886,7 +886,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
|
|||
TypeId leftFilteredTy = simplifyIntersection(builtinTypes, arena, leftType, builtinTypes->truthyType).result;
|
||||
|
||||
asMutable(resultType)->ty.emplace<BoundType>(simplifyUnion(builtinTypes, arena, rightType, leftFilteredTy).result);
|
||||
unblock(resultType);
|
||||
unblock(resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
|
@ -898,7 +898,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
|
|||
unify(leftType, errorRecoveryType(), constraint->scope);
|
||||
unify(rightType, errorRecoveryType(), constraint->scope);
|
||||
asMutable(resultType)->ty.emplace<BoundType>(errorRecoveryType());
|
||||
unblock(resultType);
|
||||
unblock(resultType, constraint->location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1065,14 +1065,14 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
|
|||
const PendingExpansionType* petv = get<PendingExpansionType>(follow(c.target));
|
||||
if (!petv)
|
||||
{
|
||||
unblock(c.target);
|
||||
unblock(c.target, constraint->location);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto bindResult = [this, &c](TypeId result) {
|
||||
auto bindResult = [this, &c, constraint](TypeId result) {
|
||||
LUAU_ASSERT(get<PendingExpansionType>(c.target));
|
||||
asMutable(c.target)->ty.emplace<BoundType>(result);
|
||||
unblock(c.target);
|
||||
unblock(c.target, constraint->location);
|
||||
};
|
||||
|
||||
std::optional<TypeFun> tf = (petv->prefix) ? constraint->scope->lookupImportedType(petv->prefix->value, petv->name.value)
|
||||
|
@ -1400,9 +1400,9 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
|
|||
const auto [changedTypes, changedPacks] = bestOverloadLog->getChanges();
|
||||
bestOverloadLog->commit();
|
||||
|
||||
unblock(changedTypes);
|
||||
unblock(changedPacks);
|
||||
unblock(c.result);
|
||||
unblock(changedTypes, constraint->location);
|
||||
unblock(changedPacks, constraint->location);
|
||||
unblock(c.result, constraint->location);
|
||||
|
||||
InstantiationQueuer queuer{constraint->scope, constraint->location, this};
|
||||
queuer.traverse(fn);
|
||||
|
@ -1421,7 +1421,7 @@ bool ConstraintSolver::tryDispatch(const PrimitiveTypeConstraint& c, NotNull<con
|
|||
|
||||
TypeId bindTo = maybeSingleton(expectedType) ? c.singletonType : c.multitonType;
|
||||
asMutable(c.resultType)->ty.emplace<BoundType>(bindTo);
|
||||
unblock(c.resultType);
|
||||
unblock(c.resultType, constraint->location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1440,7 +1440,7 @@ bool ConstraintSolver::tryDispatch(const HasPropConstraint& c, NotNull<const Con
|
|||
TableType& ttv = asMutable(subjectType)->ty.emplace<TableType>(TableState::Free, TypeLevel{}, constraint->scope);
|
||||
ttv.props[c.prop] = Property{c.resultType};
|
||||
asMutable(c.resultType)->ty.emplace<FreeType>(constraint->scope);
|
||||
unblock(c.resultType);
|
||||
unblock(c.resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1454,7 +1454,7 @@ bool ConstraintSolver::tryDispatch(const HasPropConstraint& c, NotNull<const Con
|
|||
}
|
||||
|
||||
asMutable(c.resultType)->ty.emplace<BoundType>(result.value_or(builtinTypes->anyType));
|
||||
unblock(c.resultType);
|
||||
unblock(c.resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1568,7 +1568,7 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull<const Con
|
|||
if (!isBlocked(c.propType))
|
||||
unify(c.propType, *existingPropType, constraint->scope);
|
||||
bind(c.resultType, c.subjectType);
|
||||
unblock(c.resultType);
|
||||
unblock(c.resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1593,8 +1593,8 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull<const Con
|
|||
bind(subjectType, ty);
|
||||
if (follow(c.resultType) != follow(ty))
|
||||
bind(c.resultType, ty);
|
||||
unblock(subjectType);
|
||||
unblock(c.resultType);
|
||||
unblock(subjectType, constraint->location);
|
||||
unblock(c.resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
else if (auto ttv = getMutable<TableType>(subjectType))
|
||||
|
@ -1605,7 +1605,7 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull<const Con
|
|||
|
||||
ttv->props[c.path[0]] = Property{c.propType};
|
||||
bind(c.resultType, c.subjectType);
|
||||
unblock(c.resultType);
|
||||
unblock(c.resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
else if (ttv->state == TableState::Unsealed)
|
||||
|
@ -1614,14 +1614,14 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull<const Con
|
|||
|
||||
updateTheTableType(builtinTypes, NotNull{arena}, subjectType, c.path, c.propType);
|
||||
bind(c.resultType, c.subjectType);
|
||||
unblock(subjectType);
|
||||
unblock(c.resultType);
|
||||
unblock(subjectType, constraint->location);
|
||||
unblock(c.resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bind(c.resultType, subjectType);
|
||||
unblock(c.resultType);
|
||||
unblock(c.resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1630,7 +1630,7 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull<const Con
|
|||
// Other kinds of types don't change shape when properties are assigned
|
||||
// to them. (if they allow properties at all!)
|
||||
bind(c.resultType, subjectType);
|
||||
unblock(c.resultType);
|
||||
unblock(c.resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1649,8 +1649,8 @@ bool ConstraintSolver::tryDispatch(const SetIndexerConstraint& c, NotNull<const
|
|||
|
||||
asMutable(c.resultType)->ty.emplace<BoundType>(subjectType);
|
||||
asMutable(c.propType)->ty.emplace<FreeType>(scope);
|
||||
unblock(c.propType);
|
||||
unblock(c.resultType);
|
||||
unblock(c.propType, constraint->location);
|
||||
unblock(c.resultType, constraint->location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1662,8 +1662,8 @@ bool ConstraintSolver::tryDispatch(const SetIndexerConstraint& c, NotNull<const
|
|||
unify(c.indexType, tt->indexer->indexType, constraint->scope);
|
||||
asMutable(c.propType)->ty.emplace<BoundType>(tt->indexer->indexResultType);
|
||||
asMutable(c.resultType)->ty.emplace<BoundType>(subjectType);
|
||||
unblock(c.propType);
|
||||
unblock(c.resultType);
|
||||
unblock(c.propType, constraint->location);
|
||||
unblock(c.resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
else if (tt->state == TableState::Free || tt->state == TableState::Unsealed)
|
||||
|
@ -1675,8 +1675,8 @@ bool ConstraintSolver::tryDispatch(const SetIndexerConstraint& c, NotNull<const
|
|||
mtt->indexer = TableIndexer{promotedIndexTy, c.propType};
|
||||
asMutable(c.propType)->ty.emplace<FreeType>(tt->scope);
|
||||
asMutable(c.resultType)->ty.emplace<BoundType>(subjectType);
|
||||
unblock(c.propType);
|
||||
unblock(c.resultType);
|
||||
unblock(c.propType, constraint->location);
|
||||
unblock(c.resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
// Do not augment sealed or generic tables that lack indexers
|
||||
|
@ -1684,8 +1684,8 @@ bool ConstraintSolver::tryDispatch(const SetIndexerConstraint& c, NotNull<const
|
|||
|
||||
asMutable(c.propType)->ty.emplace<BoundType>(builtinTypes->errorRecoveryType());
|
||||
asMutable(c.resultType)->ty.emplace<BoundType>(builtinTypes->errorRecoveryType());
|
||||
unblock(c.propType);
|
||||
unblock(c.resultType);
|
||||
unblock(c.propType, constraint->location);
|
||||
unblock(c.resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1704,7 +1704,7 @@ bool ConstraintSolver::tryDispatch(const SingletonOrTopTypeConstraint& c, NotNul
|
|||
else
|
||||
*asMutable(c.resultType) = BoundType{builtinTypes->anyType};
|
||||
|
||||
unblock(c.resultType);
|
||||
unblock(c.resultType, constraint->location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1720,7 +1720,7 @@ bool ConstraintSolver::tryDispatch(const UnpackConstraint& c, NotNull<const Cons
|
|||
if (isBlocked(resultPack))
|
||||
{
|
||||
asMutable(resultPack)->ty.emplace<BoundTypePack>(sourcePack);
|
||||
unblock(resultPack);
|
||||
unblock(resultPack, constraint->location);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1745,7 +1745,7 @@ bool ConstraintSolver::tryDispatch(const UnpackConstraint& c, NotNull<const Cons
|
|||
}
|
||||
else
|
||||
asMutable(*destIter)->ty.emplace<BoundType>(srcTy);
|
||||
unblock(*destIter);
|
||||
unblock(*destIter, constraint->location);
|
||||
}
|
||||
else
|
||||
unify(*destIter, srcTy, constraint->scope);
|
||||
|
@ -1763,7 +1763,7 @@ bool ConstraintSolver::tryDispatch(const UnpackConstraint& c, NotNull<const Cons
|
|||
if (isBlocked(*destIter))
|
||||
{
|
||||
asMutable(*destIter)->ty.emplace<BoundType>(builtinTypes->errorRecoveryType());
|
||||
unblock(*destIter);
|
||||
unblock(*destIter, constraint->location);
|
||||
}
|
||||
|
||||
++destIter;
|
||||
|
@ -1852,7 +1852,7 @@ bool ConstraintSolver::tryDispatch(const RefineConstraint& c, NotNull<const Cons
|
|||
if (c.mode == RefineConstraint::Intersection && isNegatedAny(c.discriminant))
|
||||
{
|
||||
asMutable(c.resultType)->ty.emplace<BoundType>(c.type);
|
||||
unblock(c.resultType);
|
||||
unblock(c.resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1880,7 +1880,7 @@ bool ConstraintSolver::tryDispatch(const RefineConstraint& c, NotNull<const Cons
|
|||
else
|
||||
asMutable(c.resultType)->ty.emplace<BoundType>(c.discriminant);
|
||||
|
||||
unblock(c.resultType);
|
||||
unblock(c.resultType, constraint->location);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1892,7 +1892,7 @@ bool ConstraintSolver::tryDispatch(const RefineConstraint& c, NotNull<const Cons
|
|||
|
||||
asMutable(c.resultType)->ty.emplace<BoundType>(result);
|
||||
|
||||
unblock(c.resultType);
|
||||
unblock(c.resultType, constraint->location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1904,10 +1904,10 @@ bool ConstraintSolver::tryDispatch(const ReduceConstraint& c, NotNull<const Cons
|
|||
reduceFamilies(ty, constraint->location, NotNull{arena}, builtinTypes, constraint->scope, normalizer, nullptr, force);
|
||||
|
||||
for (TypeId r : result.reducedTypes)
|
||||
unblock(r);
|
||||
unblock(r, constraint->location);
|
||||
|
||||
for (TypePackId r : result.reducedPacks)
|
||||
unblock(r);
|
||||
unblock(r, constraint->location);
|
||||
|
||||
if (force)
|
||||
return true;
|
||||
|
@ -1928,10 +1928,10 @@ bool ConstraintSolver::tryDispatch(const ReducePackConstraint& c, NotNull<const
|
|||
reduceFamilies(tp, constraint->location, NotNull{arena}, builtinTypes, constraint->scope, normalizer, nullptr, force);
|
||||
|
||||
for (TypeId r : result.reducedTypes)
|
||||
unblock(r);
|
||||
unblock(r, constraint->location);
|
||||
|
||||
for (TypePackId r : result.reducedPacks)
|
||||
unblock(r);
|
||||
unblock(r, constraint->location);
|
||||
|
||||
if (force)
|
||||
return true;
|
||||
|
@ -2374,8 +2374,8 @@ bool ConstraintSolver::tryUnify(NotNull<const Constraint> constraint, TID subTy,
|
|||
|
||||
u.log.commit();
|
||||
|
||||
unblock(changedTypes);
|
||||
unblock(changedPacks);
|
||||
unblock(changedTypes, constraint->location);
|
||||
unblock(changedPacks, constraint->location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -2509,7 +2509,7 @@ void ConstraintSolver::unblock(NotNull<const Constraint> progressed)
|
|||
return unblock_(progressed.get());
|
||||
}
|
||||
|
||||
void ConstraintSolver::unblock(TypeId ty)
|
||||
void ConstraintSolver::unblock(TypeId ty, Location location)
|
||||
{
|
||||
DenseHashSet<TypeId> seen{nullptr};
|
||||
|
||||
|
@ -2517,7 +2517,7 @@ void ConstraintSolver::unblock(TypeId ty)
|
|||
while (true)
|
||||
{
|
||||
if (seen.find(progressed))
|
||||
iceReporter.ice("ConstraintSolver::unblock encountered a self-bound type!");
|
||||
iceReporter.ice("ConstraintSolver::unblock encountered a self-bound type!", location);
|
||||
seen.insert(progressed);
|
||||
|
||||
if (logger)
|
||||
|
@ -2532,7 +2532,7 @@ void ConstraintSolver::unblock(TypeId ty)
|
|||
}
|
||||
}
|
||||
|
||||
void ConstraintSolver::unblock(TypePackId progressed)
|
||||
void ConstraintSolver::unblock(TypePackId progressed, Location)
|
||||
{
|
||||
if (logger)
|
||||
logger->popBlock(progressed);
|
||||
|
@ -2540,16 +2540,16 @@ void ConstraintSolver::unblock(TypePackId progressed)
|
|||
return unblock_(progressed);
|
||||
}
|
||||
|
||||
void ConstraintSolver::unblock(const std::vector<TypeId>& types)
|
||||
void ConstraintSolver::unblock(const std::vector<TypeId>& types, Location location)
|
||||
{
|
||||
for (TypeId t : types)
|
||||
unblock(t);
|
||||
unblock(t, location);
|
||||
}
|
||||
|
||||
void ConstraintSolver::unblock(const std::vector<TypePackId>& packs)
|
||||
void ConstraintSolver::unblock(const std::vector<TypePackId>& packs, Location location)
|
||||
{
|
||||
for (TypePackId t : packs)
|
||||
unblock(t);
|
||||
unblock(t, location);
|
||||
}
|
||||
|
||||
bool ConstraintSolver::isBlocked(TypeId ty)
|
||||
|
@ -2586,8 +2586,8 @@ ErrorVec ConstraintSolver::unify(TypeId subType, TypeId superType, NotNull<Scope
|
|||
|
||||
u.log.commit();
|
||||
|
||||
unblock(changedTypes);
|
||||
unblock(changedPacks);
|
||||
unblock(changedTypes, Location{});
|
||||
unblock(changedPacks, Location{});
|
||||
|
||||
return std::move(u.errors);
|
||||
}
|
||||
|
@ -2604,8 +2604,8 @@ ErrorVec ConstraintSolver::unify(TypePackId subPack, TypePackId superPack, NotNu
|
|||
|
||||
u.log.commit();
|
||||
|
||||
unblock(changedTypes);
|
||||
unblock(changedPacks);
|
||||
unblock(changedTypes, Location{});
|
||||
unblock(changedPacks, Location{});
|
||||
|
||||
return std::move(u.errors);
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ LUAU_FASTINTVARIABLE(LuauAutocompleteCheckTimeoutMs, 100)
|
|||
LUAU_FASTFLAGVARIABLE(DebugLuauDeferredConstraintResolution, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJson, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauReadWriteProperties, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFixBuildQueueExceptionUnwrap, false)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -596,6 +597,7 @@ std::vector<ModuleName> Frontend::checkQueuedModules(std::optional<FrontendOptio
|
|||
sendCycleItemTask();
|
||||
|
||||
std::vector<size_t> nextItems;
|
||||
std::optional<size_t> itemWithException;
|
||||
|
||||
while (remaining != 0)
|
||||
{
|
||||
|
@ -603,17 +605,25 @@ std::vector<ModuleName> Frontend::checkQueuedModules(std::optional<FrontendOptio
|
|||
std::unique_lock guard(mtx);
|
||||
|
||||
// If nothing is ready yet, wait
|
||||
if (readyQueueItems.empty())
|
||||
{
|
||||
cv.wait(guard, [&readyQueueItems] {
|
||||
return !readyQueueItems.empty();
|
||||
});
|
||||
}
|
||||
cv.wait(guard, [&readyQueueItems] {
|
||||
return !readyQueueItems.empty();
|
||||
});
|
||||
|
||||
// Handle checked items
|
||||
for (size_t i : readyQueueItems)
|
||||
{
|
||||
const BuildQueueItem& item = buildQueueItems[i];
|
||||
|
||||
if (FFlag::LuauFixBuildQueueExceptionUnwrap)
|
||||
{
|
||||
// If exception was thrown, stop adding new items and wait for processing items to complete
|
||||
if (item.exception)
|
||||
itemWithException = i;
|
||||
|
||||
if (itemWithException)
|
||||
break;
|
||||
}
|
||||
|
||||
recordItemResult(item);
|
||||
|
||||
// Notify items that were waiting for this dependency
|
||||
|
@ -648,7 +658,16 @@ std::vector<ModuleName> Frontend::checkQueuedModules(std::optional<FrontendOptio
|
|||
|
||||
// If we aren't done, but don't have anything processing, we hit a cycle
|
||||
if (remaining != 0 && processing == 0)
|
||||
{
|
||||
// We might have stopped because of a pending exception
|
||||
if (FFlag::LuauFixBuildQueueExceptionUnwrap && itemWithException)
|
||||
{
|
||||
recordItemResult(buildQueueItems[*itemWithException]);
|
||||
break;
|
||||
}
|
||||
|
||||
sendCycleItemTask();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ModuleName> checkedModules;
|
||||
|
@ -1104,6 +1123,8 @@ ModulePtr check(const SourceModule& sourceModule, const std::vector<RequireCycle
|
|||
result->name = sourceModule.name;
|
||||
result->humanReadableName = sourceModule.humanReadableName;
|
||||
|
||||
iceHandler->moduleName = sourceModule.name;
|
||||
|
||||
std::unique_ptr<DcrLogger> logger;
|
||||
if (recordJsonLog)
|
||||
{
|
||||
|
@ -1189,9 +1210,19 @@ ModulePtr Frontend::check(const SourceModule& sourceModule, Mode mode, std::vect
|
|||
prepareModuleScope(name, scope, forAutocomplete);
|
||||
};
|
||||
|
||||
return Luau::check(sourceModule, requireCycles, builtinTypes, NotNull{&iceHandler},
|
||||
NotNull{forAutocomplete ? &moduleResolverForAutocomplete : &moduleResolver}, NotNull{fileResolver},
|
||||
environmentScope ? *environmentScope : globals.globalScope, prepareModuleScopeWrap, options, recordJsonLog);
|
||||
try
|
||||
{
|
||||
return Luau::check(sourceModule, requireCycles, builtinTypes, NotNull{&iceHandler},
|
||||
NotNull{forAutocomplete ? &moduleResolverForAutocomplete : &moduleResolver}, NotNull{fileResolver},
|
||||
environmentScope ? *environmentScope : globals.globalScope, prepareModuleScopeWrap, options, recordJsonLog);
|
||||
}
|
||||
catch (const InternalCompilerError& err)
|
||||
{
|
||||
InternalCompilerError augmented = err.location.has_value()
|
||||
? InternalCompilerError{err.message, sourceModule.humanReadableName, *err.location}
|
||||
: InternalCompilerError{err.message, sourceModule.humanReadableName};
|
||||
throw augmented;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -2117,15 +2117,15 @@ std::optional<TypeId> Normalizer::intersectionOfTables(TypeId here, TypeId there
|
|||
TypeId hmtable = nullptr;
|
||||
if (const MetatableType* hmtv = get<MetatableType>(here))
|
||||
{
|
||||
htable = hmtv->table;
|
||||
hmtable = hmtv->metatable;
|
||||
htable = follow(hmtv->table);
|
||||
hmtable = follow(hmtv->metatable);
|
||||
}
|
||||
TypeId ttable = there;
|
||||
TypeId tmtable = nullptr;
|
||||
if (const MetatableType* tmtv = get<MetatableType>(there))
|
||||
{
|
||||
ttable = tmtv->table;
|
||||
tmtable = tmtv->metatable;
|
||||
ttable = follow(tmtv->table);
|
||||
tmtable = follow(tmtv->metatable);
|
||||
}
|
||||
|
||||
const TableType* httv = get<TableType>(htable);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "Luau/ToString.h"
|
||||
#include "Luau/TypeArena.h"
|
||||
#include "Luau/Normalize.h" // TypeIds
|
||||
#include <algorithm>
|
||||
|
||||
LUAU_FASTINT(LuauTypeReductionRecursionLimit)
|
||||
|
||||
|
@ -236,6 +237,17 @@ Relation relateTables(TypeId left, TypeId right)
|
|||
NotNull<const TableType> leftTable{get<TableType>(left)};
|
||||
NotNull<const TableType> rightTable{get<TableType>(right)};
|
||||
LUAU_ASSERT(1 == rightTable->props.size());
|
||||
// Disjoint props have nothing in common
|
||||
// t1 with props p1's cannot appear in t2 and t2 with props p2's cannot appear in t1
|
||||
bool foundPropFromLeftInRight = std::any_of(begin(leftTable->props), end(leftTable->props), [&](auto prop) {
|
||||
return rightTable->props.find(prop.first) != end(rightTable->props);
|
||||
});
|
||||
bool foundPropFromRightInLeft = std::any_of(begin(rightTable->props), end(rightTable->props), [&](auto prop) {
|
||||
return leftTable->props.find(prop.first) != end(leftTable->props);
|
||||
});
|
||||
|
||||
if (!(foundPropFromLeftInRight || foundPropFromRightInLeft) && leftTable->props.size() >= 1 && rightTable->props.size() >= 1)
|
||||
return Relation::Disjoint;
|
||||
|
||||
const auto [propName, rightProp] = *begin(rightTable->props);
|
||||
|
||||
|
|
|
@ -111,11 +111,14 @@ static TypeId shallowClone(TypeId ty, TypeArena& dest, const TxnLog* log, bool a
|
|||
else if constexpr (std::is_same_v<T, GenericType>)
|
||||
return dest.addType(a);
|
||||
else if constexpr (std::is_same_v<T, BlockedType>)
|
||||
return ty;
|
||||
return dest.addType(a);
|
||||
else if constexpr (std::is_same_v<T, PrimitiveType>)
|
||||
return ty;
|
||||
else if constexpr (std::is_same_v<T, PendingExpansionType>)
|
||||
return ty;
|
||||
{
|
||||
PendingExpansionType clone = PendingExpansionType{a.prefix, a.name, a.typeArguments, a.packArguments};
|
||||
return dest.addType(std::move(clone));
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, AnyType>)
|
||||
return ty;
|
||||
else if constexpr (std::is_same_v<T, ErrorType>)
|
||||
|
|
293
CLI/Repl.cpp
293
CLI/Repl.cpp
|
@ -6,7 +6,6 @@
|
|||
|
||||
#include "Luau/CodeGen.h"
|
||||
#include "Luau/Compiler.h"
|
||||
#include "Luau/BytecodeBuilder.h"
|
||||
#include "Luau/Parser.h"
|
||||
#include "Luau/TimeTrace.h"
|
||||
|
||||
|
@ -40,27 +39,6 @@
|
|||
|
||||
LUAU_FASTFLAG(DebugLuauTimeTracing)
|
||||
|
||||
enum class CliMode
|
||||
{
|
||||
Unknown,
|
||||
Repl,
|
||||
Compile,
|
||||
RunSourceFiles
|
||||
};
|
||||
|
||||
enum class CompileFormat
|
||||
{
|
||||
Text,
|
||||
Binary,
|
||||
Remarks,
|
||||
Codegen, // Prints annotated native code including IR and assembly
|
||||
CodegenAsm, // Prints annotated native code assembly
|
||||
CodegenIr, // Prints annotated native code IR
|
||||
CodegenVerbose, // Prints annotated native code including IR, assembly and outlined code
|
||||
CodegenNull,
|
||||
Null
|
||||
};
|
||||
|
||||
constexpr int MaxTraversalLimit = 50;
|
||||
|
||||
static bool codegen = false;
|
||||
|
@ -668,178 +646,11 @@ static bool runFile(const char* name, lua_State* GL, bool repl)
|
|||
return status == 0;
|
||||
}
|
||||
|
||||
static void report(const char* name, const Luau::Location& location, const char* type, const char* message)
|
||||
{
|
||||
fprintf(stderr, "%s(%d,%d): %s: %s\n", name, location.begin.line + 1, location.begin.column + 1, type, message);
|
||||
}
|
||||
|
||||
static void reportError(const char* name, const Luau::ParseError& error)
|
||||
{
|
||||
report(name, error.getLocation(), "SyntaxError", error.what());
|
||||
}
|
||||
|
||||
static void reportError(const char* name, const Luau::CompileError& error)
|
||||
{
|
||||
report(name, error.getLocation(), "CompileError", error.what());
|
||||
}
|
||||
|
||||
static std::string getCodegenAssembly(const char* name, const std::string& bytecode, Luau::CodeGen::AssemblyOptions options)
|
||||
{
|
||||
std::unique_ptr<lua_State, void (*)(lua_State*)> globalState(luaL_newstate(), lua_close);
|
||||
lua_State* L = globalState.get();
|
||||
|
||||
if (luau_load(L, name, bytecode.data(), bytecode.size(), 0) == 0)
|
||||
return Luau::CodeGen::getAssembly(L, -1, options);
|
||||
|
||||
fprintf(stderr, "Error loading bytecode %s\n", name);
|
||||
return "";
|
||||
}
|
||||
|
||||
static void annotateInstruction(void* context, std::string& text, int fid, int instpos)
|
||||
{
|
||||
Luau::BytecodeBuilder& bcb = *(Luau::BytecodeBuilder*)context;
|
||||
|
||||
bcb.annotateInstruction(text, fid, instpos);
|
||||
}
|
||||
|
||||
struct CompileStats
|
||||
{
|
||||
size_t lines;
|
||||
size_t bytecode;
|
||||
size_t codegen;
|
||||
|
||||
double readTime;
|
||||
double miscTime;
|
||||
double parseTime;
|
||||
double compileTime;
|
||||
double codegenTime;
|
||||
};
|
||||
|
||||
static double recordDeltaTime(double& timer)
|
||||
{
|
||||
double now = Luau::TimeTrace::getClock();
|
||||
double delta = now - timer;
|
||||
timer = now;
|
||||
return delta;
|
||||
}
|
||||
|
||||
static bool compileFile(const char* name, CompileFormat format, CompileStats& stats)
|
||||
{
|
||||
double currts = Luau::TimeTrace::getClock();
|
||||
|
||||
std::optional<std::string> source = readFile(name);
|
||||
if (!source)
|
||||
{
|
||||
fprintf(stderr, "Error opening %s\n", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
stats.readTime += recordDeltaTime(currts);
|
||||
|
||||
// NOTE: Normally, you should use Luau::compile or luau_compile (see lua_require as an example)
|
||||
// This function is much more complicated because it supports many output human-readable formats through internal interfaces
|
||||
|
||||
try
|
||||
{
|
||||
Luau::BytecodeBuilder bcb;
|
||||
|
||||
Luau::CodeGen::AssemblyOptions options;
|
||||
options.outputBinary = format == CompileFormat::CodegenNull;
|
||||
|
||||
if (!options.outputBinary)
|
||||
{
|
||||
options.includeAssembly = format != CompileFormat::CodegenIr;
|
||||
options.includeIr = format != CompileFormat::CodegenAsm;
|
||||
options.includeOutlinedCode = format == CompileFormat::CodegenVerbose;
|
||||
}
|
||||
|
||||
options.annotator = annotateInstruction;
|
||||
options.annotatorContext = &bcb;
|
||||
|
||||
if (format == CompileFormat::Text)
|
||||
{
|
||||
bcb.setDumpFlags(Luau::BytecodeBuilder::Dump_Code | Luau::BytecodeBuilder::Dump_Source | Luau::BytecodeBuilder::Dump_Locals |
|
||||
Luau::BytecodeBuilder::Dump_Remarks);
|
||||
bcb.setDumpSource(*source);
|
||||
}
|
||||
else if (format == CompileFormat::Remarks)
|
||||
{
|
||||
bcb.setDumpFlags(Luau::BytecodeBuilder::Dump_Source | Luau::BytecodeBuilder::Dump_Remarks);
|
||||
bcb.setDumpSource(*source);
|
||||
}
|
||||
else if (format == CompileFormat::Codegen || format == CompileFormat::CodegenAsm || format == CompileFormat::CodegenIr ||
|
||||
format == CompileFormat::CodegenVerbose)
|
||||
{
|
||||
bcb.setDumpFlags(Luau::BytecodeBuilder::Dump_Code | Luau::BytecodeBuilder::Dump_Source | Luau::BytecodeBuilder::Dump_Locals |
|
||||
Luau::BytecodeBuilder::Dump_Remarks);
|
||||
bcb.setDumpSource(*source);
|
||||
}
|
||||
|
||||
stats.miscTime += recordDeltaTime(currts);
|
||||
|
||||
Luau::Allocator allocator;
|
||||
Luau::AstNameTable names(allocator);
|
||||
Luau::ParseResult result = Luau::Parser::parse(source->c_str(), source->size(), names, allocator);
|
||||
|
||||
if (!result.errors.empty())
|
||||
throw Luau::ParseErrors(result.errors);
|
||||
|
||||
stats.lines += result.lines;
|
||||
stats.parseTime += recordDeltaTime(currts);
|
||||
|
||||
Luau::compileOrThrow(bcb, result, names, copts());
|
||||
stats.bytecode += bcb.getBytecode().size();
|
||||
stats.compileTime += recordDeltaTime(currts);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case CompileFormat::Text:
|
||||
printf("%s", bcb.dumpEverything().c_str());
|
||||
break;
|
||||
case CompileFormat::Remarks:
|
||||
printf("%s", bcb.dumpSourceRemarks().c_str());
|
||||
break;
|
||||
case CompileFormat::Binary:
|
||||
fwrite(bcb.getBytecode().data(), 1, bcb.getBytecode().size(), stdout);
|
||||
break;
|
||||
case CompileFormat::Codegen:
|
||||
case CompileFormat::CodegenAsm:
|
||||
case CompileFormat::CodegenIr:
|
||||
case CompileFormat::CodegenVerbose:
|
||||
printf("%s", getCodegenAssembly(name, bcb.getBytecode(), options).c_str());
|
||||
break;
|
||||
case CompileFormat::CodegenNull:
|
||||
stats.codegen += getCodegenAssembly(name, bcb.getBytecode(), options).size();
|
||||
stats.codegenTime += recordDeltaTime(currts);
|
||||
break;
|
||||
case CompileFormat::Null:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Luau::ParseErrors& e)
|
||||
{
|
||||
for (auto& error : e.getErrors())
|
||||
reportError(name, error);
|
||||
return false;
|
||||
}
|
||||
catch (Luau::CompileError& e)
|
||||
{
|
||||
reportError(name, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void displayHelp(const char* argv0)
|
||||
{
|
||||
printf("Usage: %s [--mode] [options] [file list]\n", argv0);
|
||||
printf("Usage: %s [options] [file list]\n", argv0);
|
||||
printf("\n");
|
||||
printf("When mode and file list are omitted, an interactive REPL is started instead.\n");
|
||||
printf("\n");
|
||||
printf("Available modes:\n");
|
||||
printf(" omitted: compile and run input files one by one\n");
|
||||
printf(" --compile[=format]: compile input files and output resulting bytecode/assembly (binary, text, remarks, codegen)\n");
|
||||
printf("When file list is omitted, an interactive REPL is started instead.\n");
|
||||
printf("\n");
|
||||
printf("Available options:\n");
|
||||
printf(" --coverage: collect code coverage while running the code and output results to coverage.out\n");
|
||||
|
@ -864,67 +675,12 @@ int replMain(int argc, char** argv)
|
|||
|
||||
setLuauFlagsDefault();
|
||||
|
||||
CliMode mode = CliMode::Unknown;
|
||||
CompileFormat compileFormat{};
|
||||
int profile = 0;
|
||||
bool coverage = false;
|
||||
bool interactive = false;
|
||||
bool codegenPerf = false;
|
||||
|
||||
// Set the mode if the user has explicitly specified one.
|
||||
int argStart = 1;
|
||||
if (argc >= 2 && strncmp(argv[1], "--compile", strlen("--compile")) == 0)
|
||||
{
|
||||
argStart++;
|
||||
mode = CliMode::Compile;
|
||||
if (strcmp(argv[1], "--compile") == 0)
|
||||
{
|
||||
compileFormat = CompileFormat::Text;
|
||||
}
|
||||
else if (strcmp(argv[1], "--compile=binary") == 0)
|
||||
{
|
||||
compileFormat = CompileFormat::Binary;
|
||||
}
|
||||
else if (strcmp(argv[1], "--compile=text") == 0)
|
||||
{
|
||||
compileFormat = CompileFormat::Text;
|
||||
}
|
||||
else if (strcmp(argv[1], "--compile=remarks") == 0)
|
||||
{
|
||||
compileFormat = CompileFormat::Remarks;
|
||||
}
|
||||
else if (strcmp(argv[1], "--compile=codegen") == 0)
|
||||
{
|
||||
compileFormat = CompileFormat::Codegen;
|
||||
}
|
||||
else if (strcmp(argv[1], "--compile=codegenasm") == 0)
|
||||
{
|
||||
compileFormat = CompileFormat::CodegenAsm;
|
||||
}
|
||||
else if (strcmp(argv[1], "--compile=codegenir") == 0)
|
||||
{
|
||||
compileFormat = CompileFormat::CodegenIr;
|
||||
}
|
||||
else if (strcmp(argv[1], "--compile=codegenverbose") == 0)
|
||||
{
|
||||
compileFormat = CompileFormat::CodegenVerbose;
|
||||
}
|
||||
else if (strcmp(argv[1], "--compile=codegennull") == 0)
|
||||
{
|
||||
compileFormat = CompileFormat::CodegenNull;
|
||||
}
|
||||
else if (strcmp(argv[1], "--compile=null") == 0)
|
||||
{
|
||||
compileFormat = CompileFormat::Null;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error: Unrecognized value for '--compile' specified.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = argStart; i < argc; i++)
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
|
||||
{
|
||||
|
@ -1026,50 +782,20 @@ int replMain(int argc, char** argv)
|
|||
#endif
|
||||
}
|
||||
|
||||
const std::vector<std::string> files = getSourceFiles(argc, argv);
|
||||
if (mode == CliMode::Unknown)
|
||||
{
|
||||
mode = files.empty() ? CliMode::Repl : CliMode::RunSourceFiles;
|
||||
}
|
||||
|
||||
if (mode != CliMode::Compile && codegen && !Luau::CodeGen::isSupported())
|
||||
if (codegen && !Luau::CodeGen::isSupported())
|
||||
{
|
||||
fprintf(stderr, "Cannot enable --codegen, native code generation is not supported in current configuration\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case CliMode::Compile:
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (compileFormat == CompileFormat::Binary)
|
||||
_setmode(_fileno(stdout), _O_BINARY);
|
||||
#endif
|
||||
const std::vector<std::string> files = getSourceFiles(argc, argv);
|
||||
|
||||
CompileStats stats = {};
|
||||
int failed = 0;
|
||||
|
||||
for (const std::string& path : files)
|
||||
failed += !compileFile(path.c_str(), compileFormat, stats);
|
||||
|
||||
if (compileFormat == CompileFormat::Null)
|
||||
printf("Compiled %d KLOC into %d KB bytecode (read %.2fs, parse %.2fs, compile %.2fs)\n", int(stats.lines / 1000),
|
||||
int(stats.bytecode / 1024), stats.readTime, stats.parseTime, stats.compileTime);
|
||||
else if (compileFormat == CompileFormat::CodegenNull)
|
||||
printf("Compiled %d KLOC into %d KB bytecode => %d KB native code (%.2fx) (read %.2fs, parse %.2fs, compile %.2fs, codegen %.2fs)\n",
|
||||
int(stats.lines / 1000), int(stats.bytecode / 1024), int(stats.codegen / 1024),
|
||||
stats.bytecode == 0 ? 0.0 : double(stats.codegen) / double(stats.bytecode), stats.readTime, stats.parseTime, stats.compileTime,
|
||||
stats.codegenTime);
|
||||
|
||||
return failed ? 1 : 0;
|
||||
}
|
||||
case CliMode::Repl:
|
||||
if (files.empty())
|
||||
{
|
||||
runRepl();
|
||||
return 0;
|
||||
}
|
||||
case CliMode::RunSourceFiles:
|
||||
else
|
||||
{
|
||||
std::unique_ptr<lua_State, void (*)(lua_State*)> globalState(luaL_newstate(), lua_close);
|
||||
lua_State* L = globalState.get();
|
||||
|
@ -1101,9 +827,4 @@ int replMain(int argc, char** argv)
|
|||
|
||||
return failed ? 1 : 0;
|
||||
}
|
||||
case CliMode::Unknown:
|
||||
default:
|
||||
LUAU_ASSERT(!"Unhandled cli mode.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,6 +98,8 @@ public:
|
|||
void call(Label& label);
|
||||
void call(OperandX64 op);
|
||||
|
||||
void lea(RegisterX64 lhs, Label& label);
|
||||
|
||||
void int3();
|
||||
void ud2();
|
||||
|
||||
|
@ -243,6 +245,7 @@ private:
|
|||
LUAU_NOINLINE void log(const char* opcode, OperandX64 op1, OperandX64 op2, OperandX64 op3, OperandX64 op4);
|
||||
LUAU_NOINLINE void log(Label label);
|
||||
LUAU_NOINLINE void log(const char* opcode, Label label);
|
||||
LUAU_NOINLINE void log(const char* opcode, RegisterX64 reg, Label label);
|
||||
void log(OperandX64 op);
|
||||
|
||||
const char* getSizeName(SizeX64 size) const;
|
||||
|
|
|
@ -801,6 +801,8 @@ struct IrBlock
|
|||
uint32_t start = ~0u;
|
||||
uint32_t finish = ~0u;
|
||||
|
||||
uint32_t sortkey = ~0u;
|
||||
|
||||
Label label;
|
||||
};
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ std::string toString(const IrFunction& function, bool includeUseInfo);
|
|||
std::string dump(const IrFunction& function);
|
||||
|
||||
std::string toDot(const IrFunction& function, bool includeInst);
|
||||
std::string toDotCfg(const IrFunction& function);
|
||||
std::string toDotDjGraph(const IrFunction& function);
|
||||
|
||||
std::string dumpDot(const IrFunction& function, bool includeInst);
|
||||
|
||||
|
|
|
@ -463,6 +463,20 @@ void AssemblyBuilderX64::call(OperandX64 op)
|
|||
commit();
|
||||
}
|
||||
|
||||
void AssemblyBuilderX64::lea(RegisterX64 lhs, Label& label)
|
||||
{
|
||||
LUAU_ASSERT(lhs.size == SizeX64::qword);
|
||||
|
||||
placeBinaryRegAndRegMem(lhs, OperandX64(SizeX64::qword, noreg, 1, rip, 0), 0x8d, 0x8d);
|
||||
|
||||
codePos -= 4;
|
||||
placeLabel(label);
|
||||
commit();
|
||||
|
||||
if (logText)
|
||||
log("lea", lhs, label);
|
||||
}
|
||||
|
||||
void AssemblyBuilderX64::int3()
|
||||
{
|
||||
if (logText)
|
||||
|
@ -1415,7 +1429,7 @@ void AssemblyBuilderX64::commit()
|
|||
{
|
||||
LUAU_ASSERT(codePos <= codeEnd);
|
||||
|
||||
if (codeEnd - codePos < kMaxInstructionLength)
|
||||
if (unsigned(codeEnd - codePos) < kMaxInstructionLength)
|
||||
extend();
|
||||
}
|
||||
|
||||
|
@ -1501,6 +1515,14 @@ void AssemblyBuilderX64::log(const char* opcode, Label label)
|
|||
logAppend(" %-12s.L%d\n", opcode, label.id);
|
||||
}
|
||||
|
||||
void AssemblyBuilderX64::log(const char* opcode, RegisterX64 reg, Label label)
|
||||
{
|
||||
logAppend(" %-12s", opcode);
|
||||
log(reg);
|
||||
text.append(",");
|
||||
logAppend(".L%d\n", label.id);
|
||||
}
|
||||
|
||||
void AssemblyBuilderX64::log(OperandX64 op)
|
||||
{
|
||||
switch (op.cat)
|
||||
|
|
|
@ -56,8 +56,10 @@ static void makePagesExecutable(uint8_t* mem, size_t size)
|
|||
|
||||
static void flushInstructionCache(uint8_t* mem, size_t size)
|
||||
{
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
|
||||
if (FlushInstructionCache(GetCurrentProcess(), mem, size) == 0)
|
||||
LUAU_ASSERT(!"Failed to flush instruction cache");
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static uint8_t* allocatePages(size_t size)
|
||||
|
|
|
@ -125,7 +125,7 @@ static bool lowerImpl(AssemblyBuilder& build, IrLowering& lowering, IrFunction&
|
|||
return (a.kind == IrBlockKind::Fallback) < (b.kind == IrBlockKind::Fallback);
|
||||
|
||||
// Try to order by instruction order
|
||||
return a.start < b.start;
|
||||
return a.sortkey < b.sortkey;
|
||||
});
|
||||
|
||||
// For each IR instruction that begins a bytecode instruction, which bytecode instruction is it?
|
||||
|
@ -234,6 +234,8 @@ static bool lowerImpl(AssemblyBuilder& build, IrLowering& lowering, IrFunction&
|
|||
build.setLabel(abandoned.label);
|
||||
}
|
||||
|
||||
lowering.finishFunction();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -244,7 +246,15 @@ static bool lowerImpl(AssemblyBuilder& build, IrLowering& lowering, IrFunction&
|
|||
build.logAppend("#\n");
|
||||
}
|
||||
|
||||
if (outputEnabled && !options.includeOutlinedCode && seenFallback)
|
||||
if (!seenFallback)
|
||||
{
|
||||
textSize = build.text.length();
|
||||
codeSize = build.getCodeSize();
|
||||
}
|
||||
|
||||
lowering.finishFunction();
|
||||
|
||||
if (outputEnabled && !options.includeOutlinedCode && textSize < build.text.size())
|
||||
{
|
||||
build.text.resize(textSize);
|
||||
|
||||
|
@ -594,6 +604,12 @@ std::string getAssembly(lua_State* L, int idx, AssemblyOptions options)
|
|||
X64::assembleHelpers(build, helpers);
|
||||
#endif
|
||||
|
||||
if (!options.includeOutlinedCode && options.includeAssembly)
|
||||
{
|
||||
build.text.clear();
|
||||
build.logAppend("; skipping %u bytes of outlined helpers\n", unsigned(build.getCodeSize() * sizeof(build.code[0])));
|
||||
}
|
||||
|
||||
for (Proto* p : protos)
|
||||
if (p)
|
||||
if (std::optional<NativeProto> np = assembleFunction(build, data, helpers, p, options))
|
||||
|
|
|
@ -288,27 +288,27 @@ void assembleHelpers(AssemblyBuilderA64& build, ModuleHelpers& helpers)
|
|||
{
|
||||
if (build.logText)
|
||||
build.logAppend("; exitContinueVm\n");
|
||||
helpers.exitContinueVm = build.setLabel();
|
||||
build.setLabel(helpers.exitContinueVm);
|
||||
emitExit(build, /* continueInVm */ true);
|
||||
|
||||
if (build.logText)
|
||||
build.logAppend("; exitNoContinueVm\n");
|
||||
helpers.exitNoContinueVm = build.setLabel();
|
||||
build.setLabel(helpers.exitNoContinueVm);
|
||||
emitExit(build, /* continueInVm */ false);
|
||||
|
||||
if (build.logText)
|
||||
build.logAppend("; reentry\n");
|
||||
helpers.reentry = build.setLabel();
|
||||
build.setLabel(helpers.reentry);
|
||||
emitReentry(build, helpers);
|
||||
|
||||
if (build.logText)
|
||||
build. |