Sync to upstream/release/606

This commit is contained in:
Vyacheslav Egorov 2023-12-08 17:42:54 +02:00
parent 557e77a676
commit 69728e87cf
123 changed files with 768 additions and 323 deletions

View File

@ -150,7 +150,7 @@ private:
*/ */
ScopePtr childScope(AstNode* node, const ScopePtr& parent); ScopePtr childScope(AstNode* node, const ScopePtr& parent);
std::optional<TypeId> lookup(Scope* scope, DefId def); std::optional<TypeId> lookup(Scope* scope, DefId def, bool prototype = true);
/** /**
* Adds a new constraint with no dependencies to a given scope. * Adds a new constraint with no dependencies to a given scope.

View File

@ -74,8 +74,15 @@ private:
struct DfgScope struct DfgScope
{ {
enum ScopeType
{
Linear,
Loop,
Function,
};
DfgScope* parent; DfgScope* parent;
bool isLoopScope; ScopeType scopeType;
using Bindings = DenseHashMap<Symbol, const Def*>; using Bindings = DenseHashMap<Symbol, const Def*>;
using Props = DenseHashMap<const Def*, std::unordered_map<std::string, const Def*>>; using Props = DenseHashMap<const Def*, std::unordered_map<std::string, const Def*>>;
@ -117,7 +124,17 @@ private:
std::vector<std::unique_ptr<DfgScope>> scopes; std::vector<std::unique_ptr<DfgScope>> scopes;
DfgScope* childScope(DfgScope* scope, bool isLoopScope = false); struct FunctionCapture
{
std::vector<DefId> captureDefs;
std::vector<DefId> allVersions;
size_t versionOffset = 0;
};
DenseHashMap<Symbol, FunctionCapture> captures{Symbol{}};
void resolveCaptures();
DfgScope* childScope(DfgScope* scope, DfgScope::ScopeType scopeType = DfgScope::Linear);
void join(DfgScope* p, DfgScope* a, DfgScope* b); void join(DfgScope* p, DfgScope* a, DfgScope* b);
void joinBindings(DfgScope::Bindings& p, const DfgScope::Bindings& a, const DfgScope::Bindings& b); void joinBindings(DfgScope::Bindings& p, const DfgScope::Bindings& a, const DfgScope::Bindings& b);
@ -167,11 +184,11 @@ private:
DataFlowResult visitExpr(DfgScope* scope, AstExprError* error); DataFlowResult visitExpr(DfgScope* scope, AstExprError* error);
void visitLValue(DfgScope* scope, AstExpr* e, DefId incomingDef, bool isCompoundAssignment = false); void visitLValue(DfgScope* scope, AstExpr* e, DefId incomingDef, bool isCompoundAssignment = false);
void visitLValue(DfgScope* scope, AstExprLocal* l, DefId incomingDef, bool isCompoundAssignment); DefId visitLValue(DfgScope* scope, AstExprLocal* l, DefId incomingDef, bool isCompoundAssignment);
void visitLValue(DfgScope* scope, AstExprGlobal* g, DefId incomingDef, bool isCompoundAssignment); DefId visitLValue(DfgScope* scope, AstExprGlobal* g, DefId incomingDef, bool isCompoundAssignment);
void visitLValue(DfgScope* scope, AstExprIndexName* i, DefId incomingDef); DefId visitLValue(DfgScope* scope, AstExprIndexName* i, DefId incomingDef);
void visitLValue(DfgScope* scope, AstExprIndexExpr* i, DefId incomingDef); DefId visitLValue(DfgScope* scope, AstExprIndexExpr* i, DefId incomingDef);
void visitLValue(DfgScope* scope, AstExprError* e, DefId incomingDef); DefId visitLValue(DfgScope* scope, AstExprError* e, DefId incomingDef);
void visitType(DfgScope* scope, AstType* t); void visitType(DfgScope* scope, AstType* t);
void visitType(DfgScope* scope, AstTypeReference* r); void visitType(DfgScope* scope, AstTypeReference* r);

View File

@ -73,6 +73,7 @@ const T* get(DefId def)
} }
bool containsSubscriptedDefinition(DefId def); bool containsSubscriptedDefinition(DefId def);
void collectOperands(DefId def, std::vector<DefId>* operands);
struct DefArena struct DefArena
{ {

View File

@ -205,7 +205,7 @@ ScopePtr ConstraintGenerator::childScope(AstNode* node, const ScopePtr& parent)
return scope; return scope;
} }
std::optional<TypeId> ConstraintGenerator::lookup(Scope* scope, DefId def) std::optional<TypeId> ConstraintGenerator::lookup(Scope* scope, DefId def, bool prototype)
{ {
if (get<Cell>(def)) if (get<Cell>(def))
return scope->lookup(def); return scope->lookup(def);
@ -213,22 +213,24 @@ std::optional<TypeId> ConstraintGenerator::lookup(Scope* scope, DefId def)
{ {
if (auto found = scope->lookup(def)) if (auto found = scope->lookup(def))
return *found; return *found;
else if (!prototype)
return std::nullopt;
TypeId res = builtinTypes->neverType; TypeId res = builtinTypes->neverType;
for (DefId operand : phi->operands) for (DefId operand : phi->operands)
{ {
// `scope->lookup(operand)` may return nothing because it could be a phi node of globals, but one of // `scope->lookup(operand)` may return nothing because we only bind a type to that operand
// the operand of that global has never been assigned a type, and so it should be an error. // once we've seen that particular `DefId`. In this case, we need to prototype those types
// e.g. // and use those at a later time.
// ``` std::optional<TypeId> ty = lookup(scope, operand, /*prototype*/false);
// if foo() then if (!ty)
// g = 5 {
// end ty = arena->addType(BlockedType{});
// -- `g` here is a phi node of the assignment to `g`, or the original revision of `g` before the branch. rootScope->lvalueTypes[operand] = *ty;
// ``` }
TypeId ty = scope->lookup(operand).value_or(builtinTypes->errorRecoveryType());
res = simplifyUnion(builtinTypes, arena, res, ty).result; res = simplifyUnion(builtinTypes, arena, res, *ty).result;
} }
scope->lvalueTypes[def] = res; scope->lvalueTypes[def] = res;
@ -861,7 +863,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatFunction* f
DenseHashSet<Constraint*> excludeList{nullptr}; DenseHashSet<Constraint*> excludeList{nullptr};
DefId def = dfg->getDef(function->name); DefId def = dfg->getDef(function->name);
std::optional<TypeId> existingFunctionTy = scope->lookup(def); std::optional<TypeId> existingFunctionTy = lookup(scope.get(), def);
if (AstExprLocal* localName = function->name->as<AstExprLocal>()) if (AstExprLocal* localName = function->name->as<AstExprLocal>())
{ {
@ -1724,16 +1726,14 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprGlobal* globa
/* prepopulateGlobalScope() has already added all global functions to the environment by this point, so any /* prepopulateGlobalScope() has already added all global functions to the environment by this point, so any
* global that is not already in-scope is definitely an unknown symbol. * global that is not already in-scope is definitely an unknown symbol.
*/ */
if (auto ty = lookup(scope.get(), def)) if (auto ty = lookup(scope.get(), def, /*prototype=*/false))
return Inference{*ty, refinementArena.proposition(key, builtinTypes->truthyType)};
else if (auto ty = scope->lookup(global->name))
{ {
rootScope->lvalueTypes[def] = *ty; rootScope->lvalueTypes[def] = *ty;
return Inference{*ty, refinementArena.proposition(key, builtinTypes->truthyType)}; return Inference{*ty, refinementArena.proposition(key, builtinTypes->truthyType)};
} }
else else
{ {
reportError(global->location, UnknownSymbol{global->name.value}); reportError(global->location, UnknownSymbol{global->name.value, UnknownSymbol::Binding});
return Inference{builtinTypes->errorRecoveryType()}; return Inference{builtinTypes->errorRecoveryType()};
} }
} }
@ -3110,6 +3110,16 @@ struct GlobalPrepopulator : AstVisitor
return true; return true;
} }
bool visit(AstType*) override
{
return true;
}
bool visit(class AstTypePack* node) override
{
return true;
}
}; };
void ConstraintGenerator::prepopulateGlobalScope(const ScopePtr& globalScope, AstStatBlock* program) void ConstraintGenerator::prepopulateGlobalScope(const ScopePtr& globalScope, AstStatBlock* program)

View File

@ -116,7 +116,7 @@ bool DfgScope::canUpdateDefinition(Symbol symbol) const
{ {
if (current->bindings.find(symbol)) if (current->bindings.find(symbol))
return true; return true;
else if (current->isLoopScope) else if (current->scopeType == DfgScope::Loop)
return false; return false;
} }
@ -129,7 +129,7 @@ bool DfgScope::canUpdateDefinition(DefId def, const std::string& key) const
{ {
if (auto props = current->props.find(def)) if (auto props = current->props.find(def))
return true; return true;
else if (current->isLoopScope) else if (current->scopeType == DfgScope::Loop)
return false; return false;
} }
@ -144,6 +144,7 @@ DataFlowGraph DataFlowGraphBuilder::build(AstStatBlock* block, NotNull<InternalE
builder.handle = handle; builder.handle = handle;
builder.moduleScope = builder.childScope(nullptr); // nullptr is the root DFG scope. builder.moduleScope = builder.childScope(nullptr); // nullptr is the root DFG scope.
builder.visitBlockWithoutChildScope(builder.moduleScope, block); builder.visitBlockWithoutChildScope(builder.moduleScope, block);
builder.resolveCaptures();
if (FFlag::DebugLuauFreezeArena) if (FFlag::DebugLuauFreezeArena)
{ {
@ -154,9 +155,27 @@ DataFlowGraph DataFlowGraphBuilder::build(AstStatBlock* block, NotNull<InternalE
return std::move(builder.graph); return std::move(builder.graph);
} }
DfgScope* DataFlowGraphBuilder::childScope(DfgScope* scope, bool isLoopScope) void DataFlowGraphBuilder::resolveCaptures()
{ {
return scopes.emplace_back(new DfgScope{scope, isLoopScope}).get(); for (const auto& [_, capture] : captures)
{
std::vector<DefId> operands;
for (size_t i = capture.versionOffset; i < capture.allVersions.size(); ++i)
collectOperands(capture.allVersions[i], &operands);
for (DefId captureDef : capture.captureDefs)
{
Phi* phi = const_cast<Phi*>(get<Phi>(captureDef));
LUAU_ASSERT(phi);
LUAU_ASSERT(phi->operands.empty());
phi->operands = operands;
}
}
}
DfgScope* DataFlowGraphBuilder::childScope(DfgScope* scope, DfgScope::ScopeType scopeType)
{
return scopes.emplace_back(new DfgScope{scope, scopeType}).get();
} }
void DataFlowGraphBuilder::join(DfgScope* p, DfgScope* a, DfgScope* b) void DataFlowGraphBuilder::join(DfgScope* p, DfgScope* a, DfgScope* b)
@ -227,24 +246,44 @@ void DataFlowGraphBuilder::joinProps(DfgScope::Props& p, const DfgScope::Props&
DefId DataFlowGraphBuilder::lookup(DfgScope* scope, Symbol symbol) DefId DataFlowGraphBuilder::lookup(DfgScope* scope, Symbol symbol)
{ {
if (auto found = scope->lookup(symbol)) for (DfgScope* current = scope; current; current = current->parent)
return *found;
else
{ {
DefId result = defArena->freshCell(); if (auto found = current->bindings.find(symbol))
if (symbol.local) return NotNull{*found};
scope->bindings[symbol] = result; else if (current->scopeType == DfgScope::Function)
else {
moduleScope->bindings[symbol] = result; FunctionCapture& capture = captures[symbol];
return result; DefId captureDef = defArena->phi({});
capture.captureDefs.push_back(captureDef);
scope->bindings[symbol] = captureDef;
return NotNull{captureDef};
}
} }
DefId result = defArena->freshCell();
scope->bindings[symbol] = result;
captures[symbol].allVersions.push_back(result);
return result;
} }
DefId DataFlowGraphBuilder::lookup(DfgScope* scope, DefId def, const std::string& key) DefId DataFlowGraphBuilder::lookup(DfgScope* scope, DefId def, const std::string& key)
{ {
if (auto found = scope->lookup(def, key)) for (DfgScope* current = scope; current; current = current->parent)
return *found; {
else if (auto phi = get<Phi>(def)) if (auto props = current->props.find(def))
{
if (auto it = props->find(key); it != props->end())
return NotNull{it->second};
}
else if (auto phi = get<Phi>(def); phi && phi->operands.empty()) // Unresolved phi nodes
{
DefId result = defArena->freshCell();
scope->props[def][key] = result;
return result;
}
}
if (auto phi = get<Phi>(def))
{ {
std::vector<DefId> defs; std::vector<DefId> defs;
for (DefId operand : phi->operands) for (DefId operand : phi->operands)
@ -361,7 +400,7 @@ ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatIf* i)
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatWhile* w) ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatWhile* w)
{ {
// TODO(controlflow): entry point has a back edge from exit point // TODO(controlflow): entry point has a back edge from exit point
DfgScope* whileScope = childScope(scope, /*isLoopScope=*/true); DfgScope* whileScope = childScope(scope, DfgScope::Loop);
visitExpr(whileScope, w->condition); visitExpr(whileScope, w->condition);
visit(whileScope, w->body); visit(whileScope, w->body);
@ -373,7 +412,7 @@ ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatWhile* w)
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatRepeat* r) ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatRepeat* r)
{ {
// TODO(controlflow): entry point has a back edge from exit point // TODO(controlflow): entry point has a back edge from exit point
DfgScope* repeatScope = childScope(scope, /*isLoopScope=*/true); DfgScope* repeatScope = childScope(scope, DfgScope::Loop);
visitBlockWithoutChildScope(repeatScope, r->body); visitBlockWithoutChildScope(repeatScope, r->body);
visitExpr(repeatScope, r->condition); visitExpr(repeatScope, r->condition);
@ -429,6 +468,7 @@ ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatLocal* l)
DefId def = defArena->freshCell(subscripted); DefId def = defArena->freshCell(subscripted);
graph.localDefs[local] = def; graph.localDefs[local] = def;
scope->bindings[local] = def; scope->bindings[local] = def;
captures[local].allVersions.push_back(def);
} }
return ControlFlow::None; return ControlFlow::None;
@ -436,7 +476,7 @@ ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatLocal* l)
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatFor* f) ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatFor* f)
{ {
DfgScope* forScope = childScope(scope, /*isLoopScope=*/true); DfgScope* forScope = childScope(scope, DfgScope::Loop);
visitExpr(scope, f->from); visitExpr(scope, f->from);
visitExpr(scope, f->to); visitExpr(scope, f->to);
@ -449,6 +489,7 @@ ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatFor* f)
DefId def = defArena->freshCell(); DefId def = defArena->freshCell();
graph.localDefs[f->var] = def; graph.localDefs[f->var] = def;
scope->bindings[f->var] = def; scope->bindings[f->var] = def;
captures[f->var].allVersions.push_back(def);
// TODO(controlflow): entry point has a back edge from exit point // TODO(controlflow): entry point has a back edge from exit point
visit(forScope, f->body); visit(forScope, f->body);
@ -460,7 +501,7 @@ ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatFor* f)
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatForIn* f) ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatForIn* f)
{ {
DfgScope* forScope = childScope(scope, /*isLoopScope=*/true); DfgScope* forScope = childScope(scope, DfgScope::Loop);
for (AstLocal* local : f->vars) for (AstLocal* local : f->vars)
{ {
@ -470,6 +511,7 @@ ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatForIn* f)
DefId def = defArena->freshCell(); DefId def = defArena->freshCell();
graph.localDefs[local] = def; graph.localDefs[local] = def;
forScope->bindings[local] = def; forScope->bindings[local] = def;
captures[local].allVersions.push_back(def);
} }
// TODO(controlflow): entry point has a back edge from exit point // TODO(controlflow): entry point has a back edge from exit point
@ -527,10 +569,21 @@ ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatFunction* f)
// //
// which is evidence that references to variables must be a phi node of all possible definitions, // which is evidence that references to variables must be a phi node of all possible definitions,
// but for bug compatibility, we'll assume the same thing here. // but for bug compatibility, we'll assume the same thing here.
DefId prototype = defArena->freshCell(); visitLValue(scope, f->name, defArena->freshCell());
visitLValue(scope, f->name, prototype);
visitExpr(scope, f->func); visitExpr(scope, f->func);
if (auto local = f->name->as<AstExprLocal>())
{
// local f
// function f()
// if cond() then
// f() -- should reference only the function version and other future version, and nothing prior
// end
// end
FunctionCapture& capture = captures[local->local];
capture.versionOffset = capture.allVersions.size() - 1;
}
return ControlFlow::None; return ControlFlow::None;
} }
@ -539,6 +592,7 @@ ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatLocalFunction* l
DefId def = defArena->freshCell(); DefId def = defArena->freshCell();
graph.localDefs[l->name] = def; graph.localDefs[l->name] = def;
scope->bindings[l->name] = def; scope->bindings[l->name] = def;
captures[l->name].allVersions.push_back(def);
visitExpr(scope, l->func); visitExpr(scope, l->func);
return ControlFlow::None; return ControlFlow::None;
@ -559,6 +613,7 @@ ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatDeclareGlobal* d
DefId def = defArena->freshCell(); DefId def = defArena->freshCell();
graph.declaredDefs[d] = def; graph.declaredDefs[d] = def;
scope->bindings[d->name] = def; scope->bindings[d->name] = def;
captures[d->name].allVersions.push_back(def);
visitType(scope, d->type); visitType(scope, d->type);
@ -570,6 +625,7 @@ ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatDeclareFunction*
DefId def = defArena->freshCell(); DefId def = defArena->freshCell();
graph.declaredDefs[d] = def; graph.declaredDefs[d] = def;
scope->bindings[d->name] = def; scope->bindings[d->name] = def;
captures[d->name].allVersions.push_back(def);
DfgScope* unreachable = childScope(scope); DfgScope* unreachable = childScope(scope);
visitGenerics(unreachable, d->generics); visitGenerics(unreachable, d->generics);
@ -669,14 +725,9 @@ DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprGroup* gr
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprLocal* l) DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprLocal* l)
{ {
// DfgScope::lookup is intentional here: we want to be able to ice. DefId def = lookup(scope, l->local);
if (auto def = scope->lookup(l->local)) const RefinementKey* key = keyArena->leaf(def);
{ return {def, key};
const RefinementKey* key = keyArena->leaf(*def);
return {*def, key};
}
handle->ice("DFG: AstExprLocal came before its declaration?");
} }
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprGlobal* g) DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprGlobal* g)
@ -723,7 +774,7 @@ DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprIndexExpr
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprFunction* f) DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprFunction* f)
{ {
DfgScope* signatureScope = childScope(scope); DfgScope* signatureScope = childScope(scope, DfgScope::Function);
if (AstLocal* self = f->self) if (AstLocal* self = f->self)
{ {
@ -733,6 +784,7 @@ DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprFunction*
DefId def = defArena->freshCell(); DefId def = defArena->freshCell();
graph.localDefs[self] = def; graph.localDefs[self] = def;
signatureScope->bindings[self] = def; signatureScope->bindings[self] = def;
captures[self].allVersions.push_back(def);
} }
for (AstLocal* param : f->args) for (AstLocal* param : f->args)
@ -743,6 +795,7 @@ DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprFunction*
DefId def = defArena->freshCell(); DefId def = defArena->freshCell();
graph.localDefs[param] = def; graph.localDefs[param] = def;
signatureScope->bindings[param] = def; signatureScope->bindings[param] = def;
captures[param].allVersions.push_back(def);
} }
if (f->varargAnnotation) if (f->varargAnnotation)
@ -827,41 +880,46 @@ DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprError* er
void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExpr* e, DefId incomingDef, bool isCompoundAssignment) void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExpr* e, DefId incomingDef, bool isCompoundAssignment)
{ {
if (auto l = e->as<AstExprLocal>()) auto go = [&]() {
return visitLValue(scope, l, incomingDef, isCompoundAssignment); if (auto l = e->as<AstExprLocal>())
else if (auto g = e->as<AstExprGlobal>()) return visitLValue(scope, l, incomingDef, isCompoundAssignment);
return visitLValue(scope, g, incomingDef, isCompoundAssignment); else if (auto g = e->as<AstExprGlobal>())
else if (auto i = e->as<AstExprIndexName>()) return visitLValue(scope, g, incomingDef, isCompoundAssignment);
return visitLValue(scope, i, incomingDef); else if (auto i = e->as<AstExprIndexName>())
else if (auto i = e->as<AstExprIndexExpr>()) return visitLValue(scope, i, incomingDef);
return visitLValue(scope, i, incomingDef); else if (auto i = e->as<AstExprIndexExpr>())
else if (auto error = e->as<AstExprError>()) return visitLValue(scope, i, incomingDef);
return visitLValue(scope, error, incomingDef); else if (auto error = e->as<AstExprError>())
else return visitLValue(scope, error, incomingDef);
handle->ice("Unknown AstExpr in DataFlowGraphBuilder::visitLValue"); else
handle->ice("Unknown AstExpr in DataFlowGraphBuilder::visitLValue");
};
graph.astDefs[e] = go();
} }
void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprLocal* l, DefId incomingDef, bool isCompoundAssignment) DefId DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprLocal* l, DefId incomingDef, bool isCompoundAssignment)
{ {
// We need to keep the previous def around for a compound assignment. // We need to keep the previous def around for a compound assignment.
if (isCompoundAssignment) if (isCompoundAssignment)
{ {
if (auto def = scope->lookup(l->local)) DefId def = lookup(scope, l->local);
graph.compoundAssignDefs[l] = *def; graph.compoundAssignDefs[l] = def;
} }
// In order to avoid alias tracking, we need to clip the reference to the parent def. // In order to avoid alias tracking, we need to clip the reference to the parent def.
if (scope->canUpdateDefinition(l->local)) if (scope->canUpdateDefinition(l->local))
{ {
DefId updated = defArena->freshCell(containsSubscriptedDefinition(incomingDef)); DefId updated = defArena->freshCell(containsSubscriptedDefinition(incomingDef));
graph.astDefs[l] = updated;
scope->bindings[l->local] = updated; scope->bindings[l->local] = updated;
captures[l->local].allVersions.push_back(updated);
return updated;
} }
else else
visitExpr(scope, static_cast<AstExpr*>(l)); return visitExpr(scope, static_cast<AstExpr*>(l)).def;
} }
void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprGlobal* g, DefId incomingDef, bool isCompoundAssignment) DefId DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprGlobal* g, DefId incomingDef, bool isCompoundAssignment)
{ {
// We need to keep the previous def around for a compound assignment. // We need to keep the previous def around for a compound assignment.
if (isCompoundAssignment) if (isCompoundAssignment)
@ -874,28 +932,29 @@ void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprGlobal* g, DefId
if (scope->canUpdateDefinition(g->name)) if (scope->canUpdateDefinition(g->name))
{ {
DefId updated = defArena->freshCell(containsSubscriptedDefinition(incomingDef)); DefId updated = defArena->freshCell(containsSubscriptedDefinition(incomingDef));
graph.astDefs[g] = updated;
scope->bindings[g->name] = updated; scope->bindings[g->name] = updated;
captures[g->name].allVersions.push_back(updated);
return updated;
} }
else else
visitExpr(scope, static_cast<AstExpr*>(g)); return visitExpr(scope, static_cast<AstExpr*>(g)).def;
} }
void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprIndexName* i, DefId incomingDef) DefId DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprIndexName* i, DefId incomingDef)
{ {
DefId parentDef = visitExpr(scope, i->expr).def; DefId parentDef = visitExpr(scope, i->expr).def;
if (scope->canUpdateDefinition(parentDef, i->index.value)) if (scope->canUpdateDefinition(parentDef, i->index.value))
{ {
DefId updated = defArena->freshCell(containsSubscriptedDefinition(incomingDef)); DefId updated = defArena->freshCell(containsSubscriptedDefinition(incomingDef));
graph.astDefs[i] = updated;
scope->props[parentDef][i->index.value] = updated; scope->props[parentDef][i->index.value] = updated;
return updated;
} }
else else
visitExpr(scope, static_cast<AstExpr*>(i)); return visitExpr(scope, static_cast<AstExpr*>(i)).def;
} }
void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprIndexExpr* i, DefId incomingDef) DefId DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprIndexExpr* i, DefId incomingDef)
{ {
DefId parentDef = visitExpr(scope, i->expr).def; DefId parentDef = visitExpr(scope, i->expr).def;
visitExpr(scope, i->index); visitExpr(scope, i->index);
@ -905,20 +964,19 @@ void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprIndexExpr* i, Def
if (scope->canUpdateDefinition(parentDef, string->value.data)) if (scope->canUpdateDefinition(parentDef, string->value.data))
{ {
DefId updated = defArena->freshCell(containsSubscriptedDefinition(incomingDef)); DefId updated = defArena->freshCell(containsSubscriptedDefinition(incomingDef));
graph.astDefs[i] = updated;
scope->props[parentDef][string->value.data] = updated; scope->props[parentDef][string->value.data] = updated;
return updated;
} }
else else
visitExpr(scope, static_cast<AstExpr*>(i)); return visitExpr(scope, static_cast<AstExpr*>(i)).def;
} }
else
graph.astDefs[i] = defArena->freshCell(); return defArena->freshCell(/*subscripted=*/true);
} }
void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprError* error, DefId incomingDef) DefId DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprError* error, DefId incomingDef)
{ {
DefId def = visitExpr(scope, error).def; return visitExpr(scope, error).def;
graph.astDefs[error] = def;
} }
void DataFlowGraphBuilder::visitType(DfgScope* scope, AstType* t) void DataFlowGraphBuilder::visitType(DfgScope* scope, AstType* t)

View File

@ -19,17 +19,13 @@ bool containsSubscriptedDefinition(DefId def)
return false; return false;
} }
DefId DefArena::freshCell(bool subscripted) void collectOperands(DefId def, std::vector<DefId>* operands)
{ {
return NotNull{allocator.allocate(Def{Cell{subscripted}})}; LUAU_ASSERT(operands);
} if (std::find(operands->begin(), operands->end(), def) != operands->end())
static void collectOperands(DefId def, std::vector<DefId>& operands)
{
if (std::find(operands.begin(), operands.end(), def) != operands.end())
return; return;
else if (get<Cell>(def)) else if (get<Cell>(def))
operands.push_back(def); operands->push_back(def);
else if (auto phi = get<Phi>(def)) else if (auto phi = get<Phi>(def))
{ {
for (const Def* operand : phi->operands) for (const Def* operand : phi->operands)
@ -37,6 +33,11 @@ static void collectOperands(DefId def, std::vector<DefId>& operands)
} }
} }
DefId DefArena::freshCell(bool subscripted)
{
return NotNull{allocator.allocate(Def{Cell{subscripted}})};
}
DefId DefArena::phi(DefId a, DefId b) DefId DefArena::phi(DefId a, DefId b)
{ {
return phi({a, b}); return phi({a, b});
@ -46,7 +47,7 @@ DefId DefArena::phi(const std::vector<DefId>& defs)
{ {
std::vector<DefId> operands; std::vector<DefId> operands;
for (DefId operand : defs) for (DefId operand : defs)
collectOperands(operand, operands); collectOperands(operand, &operands);
// There's no need to allocate a Phi node for a singleton set. // There's no need to allocate a Phi node for a singleton set.
if (operands.size() == 1) if (operands.size() == 1)

View File

@ -32,11 +32,9 @@ LUAU_FASTINT(LuauTypeInferRecursionLimit)
LUAU_FASTINT(LuauTarjanChildLimit) LUAU_FASTINT(LuauTarjanChildLimit)
LUAU_FASTFLAG(LuauInferInNoCheckMode) LUAU_FASTFLAG(LuauInferInNoCheckMode)
LUAU_FASTFLAGVARIABLE(LuauKnowsTheDataModel3, false) LUAU_FASTFLAGVARIABLE(LuauKnowsTheDataModel3, false)
LUAU_FASTINTVARIABLE(LuauAutocompleteCheckTimeoutMs, 100) // TODO: Remove with FFlagLuauTypecheckLimitControls
LUAU_FASTFLAGVARIABLE(DebugLuauDeferredConstraintResolution, false) LUAU_FASTFLAGVARIABLE(DebugLuauDeferredConstraintResolution, false)
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJson, false) LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJson, false)
LUAU_FASTFLAGVARIABLE(DebugLuauReadWriteProperties, false) LUAU_FASTFLAGVARIABLE(DebugLuauReadWriteProperties, false)
LUAU_FASTFLAGVARIABLE(LuauTypecheckLimitControls, false)
LUAU_FASTFLAGVARIABLE(CorrectEarlyReturnInMarkDirty, false) LUAU_FASTFLAGVARIABLE(CorrectEarlyReturnInMarkDirty, false)
LUAU_FASTFLAGVARIABLE(LuauDefinitionFileSetModuleName, false) LUAU_FASTFLAGVARIABLE(LuauDefinitionFileSetModuleName, false)
@ -902,82 +900,41 @@ void Frontend::checkBuildQueueItem(BuildQueueItem& item)
TypeCheckLimits typeCheckLimits; TypeCheckLimits typeCheckLimits;
if (FFlag::LuauTypecheckLimitControls) if (item.options.moduleTimeLimitSec)
typeCheckLimits.finishTime = TimeTrace::getClock() + *item.options.moduleTimeLimitSec;
else
typeCheckLimits.finishTime = std::nullopt;
// TODO: This is a dirty ad hoc solution for autocomplete timeouts
// We are trying to dynamically adjust our existing limits to lower total typechecking time under the limit
// so that we'll have type information for the whole file at lower quality instead of a full abort in the middle
if (item.options.applyInternalLimitScaling)
{ {
if (item.options.moduleTimeLimitSec) if (FInt::LuauTarjanChildLimit > 0)
typeCheckLimits.finishTime = TimeTrace::getClock() + *item.options.moduleTimeLimitSec; typeCheckLimits.instantiationChildLimit = std::max(1, int(FInt::LuauTarjanChildLimit * sourceNode.autocompleteLimitsMult));
else else
typeCheckLimits.finishTime = std::nullopt; typeCheckLimits.instantiationChildLimit = std::nullopt;
// TODO: This is a dirty ad hoc solution for autocomplete timeouts if (FInt::LuauTypeInferIterationLimit > 0)
// We are trying to dynamically adjust our existing limits to lower total typechecking time under the limit typeCheckLimits.unifierIterationLimit = std::max(1, int(FInt::LuauTypeInferIterationLimit * sourceNode.autocompleteLimitsMult));
// so that we'll have type information for the whole file at lower quality instead of a full abort in the middle else
if (item.options.applyInternalLimitScaling) typeCheckLimits.unifierIterationLimit = std::nullopt;
{
if (FInt::LuauTarjanChildLimit > 0)
typeCheckLimits.instantiationChildLimit = std::max(1, int(FInt::LuauTarjanChildLimit * sourceNode.autocompleteLimitsMult));
else
typeCheckLimits.instantiationChildLimit = std::nullopt;
if (FInt::LuauTypeInferIterationLimit > 0)
typeCheckLimits.unifierIterationLimit = std::max(1, int(FInt::LuauTypeInferIterationLimit * sourceNode.autocompleteLimitsMult));
else
typeCheckLimits.unifierIterationLimit = std::nullopt;
}
typeCheckLimits.cancellationToken = item.options.cancellationToken;
} }
typeCheckLimits.cancellationToken = item.options.cancellationToken;
if (item.options.forAutocomplete) if (item.options.forAutocomplete)
{ {
double autocompleteTimeLimit = FInt::LuauAutocompleteCheckTimeoutMs / 1000.0;
if (!FFlag::LuauTypecheckLimitControls)
{
// The autocomplete typecheck is always in strict mode with DM awareness
// to provide better type information for IDE features
if (autocompleteTimeLimit != 0.0)
typeCheckLimits.finishTime = TimeTrace::getClock() + autocompleteTimeLimit;
else
typeCheckLimits.finishTime = std::nullopt;
// TODO: This is a dirty ad hoc solution for autocomplete timeouts
// We are trying to dynamically adjust our existing limits to lower total typechecking time under the limit
// so that we'll have type information for the whole file at lower quality instead of a full abort in the middle
if (FInt::LuauTarjanChildLimit > 0)
typeCheckLimits.instantiationChildLimit = std::max(1, int(FInt::LuauTarjanChildLimit * sourceNode.autocompleteLimitsMult));
else
typeCheckLimits.instantiationChildLimit = std::nullopt;
if (FInt::LuauTypeInferIterationLimit > 0)
typeCheckLimits.unifierIterationLimit = std::max(1, int(FInt::LuauTypeInferIterationLimit * sourceNode.autocompleteLimitsMult));
else
typeCheckLimits.unifierIterationLimit = std::nullopt;
typeCheckLimits.cancellationToken = item.options.cancellationToken;
}
// The autocomplete typecheck is always in strict mode with DM awareness to provide better type information for IDE features // The autocomplete typecheck is always in strict mode with DM awareness to provide better type information for IDE features
ModulePtr moduleForAutocomplete = check(sourceModule, Mode::Strict, requireCycles, environmentScope, /*forAutocomplete*/ true, ModulePtr moduleForAutocomplete = check(sourceModule, Mode::Strict, requireCycles, environmentScope, /*forAutocomplete*/ true,
/*recordJsonLog*/ false, typeCheckLimits); /*recordJsonLog*/ false, typeCheckLimits);
double duration = getTimestamp() - timestamp; double duration = getTimestamp() - timestamp;
if (FFlag::LuauTypecheckLimitControls) moduleForAutocomplete->checkDurationSec = duration;
{
moduleForAutocomplete->checkDurationSec = duration;
if (item.options.moduleTimeLimitSec && item.options.applyInternalLimitScaling) if (item.options.moduleTimeLimitSec && item.options.applyInternalLimitScaling)
applyInternalLimitScaling(sourceNode, moduleForAutocomplete, *item.options.moduleTimeLimitSec); applyInternalLimitScaling(sourceNode, moduleForAutocomplete, *item.options.moduleTimeLimitSec);
}
else
{
if (moduleForAutocomplete->timeout)
sourceNode.autocompleteLimitsMult = sourceNode.autocompleteLimitsMult / 2.0;
else if (duration < autocompleteTimeLimit / 2.0)
sourceNode.autocompleteLimitsMult = std::min(sourceNode.autocompleteLimitsMult * 2.0, 1.0);
}
item.stats.timeCheck += duration; item.stats.timeCheck += duration;
item.stats.filesStrict += 1; item.stats.filesStrict += 1;
@ -986,29 +943,16 @@ void Frontend::checkBuildQueueItem(BuildQueueItem& item)
return; return;
} }
if (!FFlag::LuauTypecheckLimitControls)
{
typeCheckLimits.cancellationToken = item.options.cancellationToken;
}
ModulePtr module = check(sourceModule, mode, requireCycles, environmentScope, /*forAutocomplete*/ false, item.recordJsonLog, typeCheckLimits); ModulePtr module = check(sourceModule, mode, requireCycles, environmentScope, /*forAutocomplete*/ false, item.recordJsonLog, typeCheckLimits);
if (FFlag::LuauTypecheckLimitControls) double duration = getTimestamp() - timestamp;
{
double duration = getTimestamp() - timestamp;
module->checkDurationSec = duration; module->checkDurationSec = duration;
if (item.options.moduleTimeLimitSec && item.options.applyInternalLimitScaling) if (item.options.moduleTimeLimitSec && item.options.applyInternalLimitScaling)
applyInternalLimitScaling(sourceNode, module, *item.options.moduleTimeLimitSec); applyInternalLimitScaling(sourceNode, module, *item.options.moduleTimeLimitSec);
item.stats.timeCheck += duration;
}
else
{
item.stats.timeCheck += getTimestamp() - timestamp;
}
item.stats.timeCheck += duration;
item.stats.filesStrict += mode == Mode::Strict; item.stats.filesStrict += mode == Mode::Strict;
item.stats.filesNonstrict += mode == Mode::Nonstrict; item.stats.filesNonstrict += mode == Mode::Nonstrict;

View File

@ -124,7 +124,7 @@ static bool analyzeFile(const char* name, const unsigned nestingLimit, std::vect
{ {
Luau::BytecodeBuilder bcb; Luau::BytecodeBuilder bcb;
compileOrThrow(bcb, source.value(), copts()); compileOrThrow(bcb, *source, copts());
const std::string& bytecode = bcb.getBytecode(); const std::string& bytecode = bcb.getBytecode();

View File

@ -42,8 +42,18 @@
LUAU_FASTFLAGVARIABLE(DebugCodegenNoOpt, false) LUAU_FASTFLAGVARIABLE(DebugCodegenNoOpt, false)
LUAU_FASTFLAGVARIABLE(DebugCodegenOptSize, false) LUAU_FASTFLAGVARIABLE(DebugCodegenOptSize, false)
LUAU_FASTFLAGVARIABLE(DebugCodegenSkipNumbering, false) LUAU_FASTFLAGVARIABLE(DebugCodegenSkipNumbering, false)
// Per-module IR instruction count limit
LUAU_FASTINTVARIABLE(CodegenHeuristicsInstructionLimit, 1'048'576) // 1 M LUAU_FASTINTVARIABLE(CodegenHeuristicsInstructionLimit, 1'048'576) // 1 M
LUAU_FASTINTVARIABLE(CodegenHeuristicsBlockLimit, 65'536) // 64 K
// Per-function IR block limit
// Current value is based on some member variables being limited to 16 bits
// Because block check is made before optimization passes and optimization can generate new blocks, limit is lowered 2x
// The limit will probably be adjusted in the future to avoid performance issues with analysis that's more complex than O(n)
LUAU_FASTINTVARIABLE(CodegenHeuristicsBlockLimit, 32'768) // 32 K
// Per-function IR instruction limit
// Current value is based on some member variables being limited to 16 bits
LUAU_FASTINTVARIABLE(CodegenHeuristicsBlockInstructionLimit, 65'536) // 64 K LUAU_FASTINTVARIABLE(CodegenHeuristicsBlockInstructionLimit, 65'536) // 64 K
namespace Luau namespace Luau
@ -104,11 +114,18 @@ static void logPerfFunction(Proto* p, uintptr_t addr, unsigned size)
} }
template<typename AssemblyBuilder> template<typename AssemblyBuilder>
static std::optional<NativeProto> createNativeFunction(AssemblyBuilder& build, ModuleHelpers& helpers, Proto* proto) static std::optional<NativeProto> createNativeFunction(AssemblyBuilder& build, ModuleHelpers& helpers, Proto* proto, uint32_t& totalIrInstCount)
{ {
IrBuilder ir; IrBuilder ir;
ir.buildFunctionIr(proto); ir.buildFunctionIr(proto);
unsigned instCount = unsigned(ir.function.instructions.size());
if (totalIrInstCount + instCount >= unsigned(FInt::CodegenHeuristicsInstructionLimit.value))
return std::nullopt;
totalIrInstCount += instCount;
if (!lowerFunction(ir, build, helpers, proto, {}, /* stats */ nullptr)) if (!lowerFunction(ir, build, helpers, proto, {}, /* stats */ nullptr))
return std::nullopt; return std::nullopt;
@ -291,9 +308,13 @@ CodeGenCompilationResult compile(lua_State* L, int idx, unsigned int flags, Comp
std::vector<NativeProto> results; std::vector<NativeProto> results;
results.reserve(protos.size()); results.reserve(protos.size());
uint32_t totalIrInstCount = 0;
for (Proto* p : protos) for (Proto* p : protos)
if (std::optional<NativeProto> np = createNativeFunction(build, helpers, p)) {
if (std::optional<NativeProto> np = createNativeFunction(build, helpers, p, totalIrInstCount))
results.push_back(*np); results.push_back(*np);
}
// Very large modules might result in overflowing a jump offset; in this case we currently abandon the entire module // Very large modules might result in overflowing a jump offset; in this case we currently abandon the entire module
if (!build.finalize()) if (!build.finalize())

View File

@ -253,11 +253,6 @@ inline bool lowerIr(A64::AssemblyBuilderA64& build, IrBuilder& ir, const std::ve
template<typename AssemblyBuilder> template<typename AssemblyBuilder>
inline bool lowerFunction(IrBuilder& ir, AssemblyBuilder& build, ModuleHelpers& helpers, Proto* proto, AssemblyOptions options, LoweringStats* stats) inline bool lowerFunction(IrBuilder& ir, AssemblyBuilder& build, ModuleHelpers& helpers, Proto* proto, AssemblyOptions options, LoweringStats* stats)
{ {
helpers.bytecodeInstructionCount += unsigned(ir.function.instructions.size());
if (helpers.bytecodeInstructionCount >= unsigned(FInt::CodegenHeuristicsInstructionLimit.value))
return false;
killUnusedBlocks(ir.function); killUnusedBlocks(ir.function);
unsigned preOptBlockCount = 0; unsigned preOptBlockCount = 0;
@ -268,9 +263,7 @@ inline bool lowerFunction(IrBuilder& ir, AssemblyBuilder& build, ModuleHelpers&
preOptBlockCount += (block.kind != IrBlockKind::Dead); preOptBlockCount += (block.kind != IrBlockKind::Dead);
unsigned blockInstructions = block.finish - block.start; unsigned blockInstructions = block.finish - block.start;
maxBlockInstructions = std::max(maxBlockInstructions, blockInstructions); maxBlockInstructions = std::max(maxBlockInstructions, blockInstructions);
}; }
helpers.preOptBlockCount += preOptBlockCount;
// we update stats before checking the heuristic so that even if we bail out // we update stats before checking the heuristic so that even if we bail out
// our stats include information about the limit that was exceeded. // our stats include information about the limit that was exceeded.
@ -280,9 +273,7 @@ inline bool lowerFunction(IrBuilder& ir, AssemblyBuilder& build, ModuleHelpers&
stats->maxBlockInstructions = maxBlockInstructions; stats->maxBlockInstructions = maxBlockInstructions;
} }
// we use helpers.blocksPreOpt instead of stats.blocksPreOpt since if (preOptBlockCount >= unsigned(FInt::CodegenHeuristicsBlockLimit.value))
// stats can be null across some code paths.
if (helpers.preOptBlockCount >= unsigned(FInt::CodegenHeuristicsBlockLimit.value))
return false; return false;
if (maxBlockInstructions >= unsigned(FInt::CodegenHeuristicsBlockInstructionLimit.value)) if (maxBlockInstructions >= unsigned(FInt::CodegenHeuristicsBlockInstructionLimit.value))

View File

@ -31,9 +31,6 @@ struct ModuleHelpers
// A64 // A64
Label continueCall; // x0: closure Label continueCall; // x0: closure
unsigned bytecodeInstructionCount = 0;
unsigned preOptBlockCount = 0;
}; };
} // namespace CodeGen } // namespace CodeGen

View File

@ -66,7 +66,8 @@ end
-- and 'false' otherwise. -- and 'false' otherwise.
-- --
-- Example usage: -- Example usage:
-- local bench = script and require(script.Parent.bench_support) or require("bench_support") -- local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
-- local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
-- function testFunc() -- function testFunc()
-- ... -- ...
-- end -- end

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,5 +1,6 @@
--!nonstrict --!nonstrict
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
local stretchTreeDepth = 18 -- about 16Mb local stretchTreeDepth = 18 -- about 16Mb
local longLivedTreeDepth = 16 -- about 4Mb local longLivedTreeDepth = 16 -- about 4Mb

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()
local count = 1 local count = 1

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()
local count = 1 local count = 1

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()
local count = 1 local count = 1

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()
local t = {} local t = {}

View File

@ -21,7 +21,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] ]]
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -22,7 +22,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
]] ]]
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
bench.runCode(function() bench.runCode(function()
for j=1,1e6 do for j=1,1e6 do

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()
local t = table.create(250001, 0) local t = table.create(250001, 0)

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()
local t = table.create(5000001, 0) local t = table.create(5000001, 0)

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()
local t = table.create(250001, 0) local t = table.create(250001, 0)

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
local arr_months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"} local arr_months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
bench.runCode(function() bench.runCode(function()
for j=1,1e6 do for j=1,1e6 do

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
bench.runCode(function() bench.runCode(function()
local src = string.rep("abcdefghijklmnopqrstuvwxyz", 100) local src = string.rep("abcdefghijklmnopqrstuvwxyz", 100)

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
bench.runCode(function() bench.runCode(function()
for outer=1,28,3 do for outer=1,28,3 do

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,5 +1,6 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
local RANKS = "12345678" local RANKS = "12345678"
local FILES = "abcdefgh" local FILES = "abcdefgh"

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
local function mmul(matrix1, matrix2) local function mmul(matrix1, matrix2)
local shapeRows = #matrix1 local shapeRows = #matrix1

View File

@ -1,5 +1,6 @@
--!strict --!strict
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
local samples = 100_000 local samples = 100_000

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
function test() function test()

View File

@ -23,7 +23,8 @@ SOFTWARE.
]] ]]
-- http://www.bagley.org/~doug/shootout/ -- http://www.bagley.org/~doug/shootout/
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../../bench_support")
function test() function test()

View File

@ -25,7 +25,8 @@ SOFTWARE.
-- http://benchmarksgame.alioth.debian.org/ -- http://benchmarksgame.alioth.debian.org/
-- contributed by Mike Pall -- contributed by Mike Pall
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../../bench_support")
function test() function test()

View File

@ -25,7 +25,8 @@ SOFTWARE.
-- http://benchmarksgame.alioth.debian.org/ -- http://benchmarksgame.alioth.debian.org/
-- contributed by Mike Pall -- contributed by Mike Pall
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../../bench_support")
function test() function test()

View File

@ -21,7 +21,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] ]]
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../../bench_support")
function test() function test()

View File

@ -21,7 +21,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] ]]
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../../bench_support")
function test() function test()

View File

@ -21,7 +21,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] ]]
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../../bench_support")
function test() function test()

View File

@ -1,4 +1,5 @@
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../../bench_support")
function test() function test()

View File

@ -23,7 +23,8 @@ SOFTWARE.
]] ]]
-- Julia sets via interval cell-mapping (quadtree version) -- Julia sets via interval cell-mapping (quadtree version)
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../../bench_support")
function test() function test()

View File

@ -21,7 +21,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] ]]
local bench = script and require(script.Parent.bench_support) or require("bench_support") local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../../bench_support")
function test() function test()

Some files were not shown because too many files have changed in this diff Show More