Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored branch instructions with renaming ILoop into IWhile #232

Merged
merged 3 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/main/resources/manuals/funcs/IsInTailPosition.ir
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def IsInTailPosition(
// Let _body_ be the |FunctionBody|, |ConciseBody|, or |AsyncConciseBody| that most closely contains _call_.
%0 = false
%1 = call
loop[repeat] (&& (! %0) (! (= %1 absent))) {
while (&& (! %0) (! (= %1 absent))) {
%0 = (|| (|| (|| %0 (? %1: "FunctionBody")) (? %1: "ConciseBody")) (? %1: "AsyncConciseBody"))
if (! %0) %1 = %1.parent else {}
}
Expand Down
10 changes: 5 additions & 5 deletions src/main/resources/manuals/rule.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@
"Create an own accessor property named _P_ of object _O_ whose [[Get]], [[Set]], [[Enumerable]], and [[Configurable]] attributes are set to the value of the corresponding field in _Desc_ if _Desc_ has that field, or to the attribute's <emu-xref href=\"#table-object-property-attributes\">default value</emu-xref> otherwise.": "{ let ap = (new PropertyDescriptor()) if (= Desc.Get absent) ap.Get = undefined else ap.Get = Desc.Get if (= Desc.Set absent) ap.Set = undefined else ap.Set = Desc.Set if (= Desc.Enumerable absent) ap.Enumerable = false else ap.Enumerable = Desc.Enumerable if (= Desc.Configurable absent) ap.Configurable = false else ap.Configurable = Desc.Configurable O.SubMap[P] = ap }",
"Create an own data property named _P_ of object _O_ whose [[Value]], [[Writable]], [[Enumerable]], and [[Configurable]] attributes are set to the value of the corresponding field in _Desc_ if _Desc_ has that field, or to the attribute's <emu-xref href=\"#table-object-property-attributes\">default value</emu-xref> otherwise.": "{ let dp = (new PropertyDescriptor()) if (= Desc.Value absent) dp.Value = undefined else dp.Value = Desc.Value if (= Desc.Writable absent) dp.Writable = false else dp.Writable = Desc.Writable if (= Desc.Enumerable absent) dp.Enumerable = false else dp.Enumerable = Desc.Enumerable if (= Desc.Configurable absent) dp.Configurable = false else dp.Configurable = Desc.Configurable O.SubMap[P] = dp }",
"Create any host-defined global object properties on _globalObj_.": "nop",
"For each field of _Desc_, set the corresponding attribute of the property named _P_ of object _O_ to the value of the field.": "{ let fields = (keys Desc) let idx = 0 loop[repeat] (< idx fields.length) { let f = fields[idx] O.SubMap[P][f] = Desc[f] idx = (+ idx 1) } }",
"For each property of the Global Object specified in clause <emu-xref href=\"#sec-global-object\"></emu-xref>, do\n 1. Let _name_ be the String value of the property name.\n 1. Let _desc_ be the fully populated data Property Descriptor for the property, containing the specified attributes for the property. For properties listed in <emu-xref href=\"#sec-function-properties-of-the-global-object\"></emu-xref>, <emu-xref href=\"#sec-constructor-properties-of-the-global-object\"></emu-xref>, or <emu-xref href=\"#sec-other-properties-of-the-global-object\"></emu-xref> the value of the [[Value]] attribute is the corresponding intrinsic object from _realmRec_.\n 1. Perform ? DefinePropertyOrThrow(_global_, _name_, _desc_).": "{ let keys = (keys @GLOBAL.SubMap) let idx = 0 loop[repeat] (< idx keys.length) { let name = keys[idx] global.SubMap[name] = @GLOBAL.SubMap[name] idx = (+ idx 1) } global.SubMap.globalThis = (new PropertyDescriptor(\"Value\" -> global, \"Writable\" -> true, \"Enumerable\" -> false, \"Configurable\" -> true)) }",
"For each field of _Desc_, set the corresponding attribute of the property named _P_ of object _O_ to the value of the field.": "{ let fields = (keys Desc) let idx = 0 while (< idx fields.length) { let f = fields[idx] O.SubMap[P][f] = Desc[f] idx = (+ idx 1) } }",
"For each property of the Global Object specified in clause <emu-xref href=\"#sec-global-object\"></emu-xref>, do\n 1. Let _name_ be the String value of the property name.\n 1. Let _desc_ be the fully populated data Property Descriptor for the property, containing the specified attributes for the property. For properties listed in <emu-xref href=\"#sec-function-properties-of-the-global-object\"></emu-xref>, <emu-xref href=\"#sec-constructor-properties-of-the-global-object\"></emu-xref>, or <emu-xref href=\"#sec-other-properties-of-the-global-object\"></emu-xref> the value of the [[Value]] attribute is the corresponding intrinsic object from _realmRec_.\n 1. Perform ? DefinePropertyOrThrow(_global_, _name_, _desc_).": "{ let keys = (keys @GLOBAL.SubMap) let idx = 0 while (< idx keys.length) { let name = keys[idx] global.SubMap[name] = @GLOBAL.SubMap[name] idx = (+ idx 1) } global.SubMap.globalThis = (new PropertyDescriptor(\"Value\" -> global, \"Writable\" -> true, \"Enumerable\" -> false, \"Configurable\" -> true)) }",
"If the host is a web browser, then\n 1. Perform ? HostEnsureCanAddPrivateElement(_O_).": "nop",
"If _Desc_ does not have any fields, return *true*.": "{ let descKeys = (keys Desc) if (= descKeys.length 0) return true else {} }",
"If _O_ does not have an own property with key _P_, return *undefined*.": "if (= O.SubMap[P] absent) return undefined else {}",
Expand All @@ -59,17 +59,17 @@
"Let _args_ be the List of arguments that was passed to this function by [[Call]] or [[Construct]].": "let args = ArgumentsList",
"Let _asyncContext_ be a copy of _runningContext_.": "let asyncContext = (copy runningContext)",
"Let _contained_ be the result of _child_ Contains _symbol_.": "{ sdo-call result = child->Contains(symbol) let contained = result }",
"Let _ec_ be the topmost execution context on the execution context stack whose ScriptOrModule component is not *null*.": "{ let ec = absent let idx = 0 loop[repeat] (&& (< idx @EXECUTION_STACK.length) (= ec absent)) { if (! (= @EXECUTION_STACK[idx].ScriptOrModule null) ) ec = @EXECUTION_STACK[idx] else {} idx = (+ idx 1) } }",
"Let _ec_ be the topmost execution context on the execution context stack whose ScriptOrModule component is not *null*.": "{ let ec = absent let idx = 0 while (&& (< idx @EXECUTION_STACK.length) (= ec absent)) { if (! (= @EXECUTION_STACK[idx].ScriptOrModule null) ) ec = @EXECUTION_STACK[idx] else {} idx = (+ idx 1) } }",
"Let _func_ be a new built-in function object that, when called, performs the action described by _behaviour_ using the provided arguments as the values of the corresponding parameters specified by _behaviour_. The new function object has internal slots whose names are the elements of _internalSlotsList_, and an [[InitialName]] internal slot.": "{ let func = (new BuiltinFunctionObject()) func.Code = behaviour }",
"Let _instantiatedVarNames_ be a copy of the List _parameterBindings_.": "let instantiatedVarNames = (copy parameterBindings)",
"Let _internalSlotsList_ be a List containing the names of all the internal slots that <emu-xref href=\"#sec-built-in-function-objects\"></emu-xref> requires for the built-in function object that is about to be created.": "let internalSlotsList = (new [\"Prototype\", \"Extensible\", \"Realm\", \"InitialName\"])",
"Let _newLenDesc_ be a copy of _Desc_.": "let newLenDesc = (copy Desc)",
"Let _nextPending_ be the PendingJob record at the front of _nextQueue_. Remove that record from _nextQueue_.": "let nextPending = (pop < @JOB_QUEUE)",
"Let _nextQueue_ be a non-empty Job Queue chosen in an implementation-defined manner.": "let nextQueue = @JOB_QUEUE",
"Let _obj_ be a newly created object with an internal slot for each name in _internalSlotsList_.": "{ let obj = (new Object()) let idx = 0 loop[repeat] (< idx internalSlotsList.length) { obj[internalSlotsList[idx]] = undefined idx = (+ idx 1) } }",
"Let _obj_ be a newly created object with an internal slot for each name in _internalSlotsList_.": "{ let obj = (new Object()) let idx = 0 while (< idx internalSlotsList.length) { obj[internalSlotsList[idx]] = undefined idx = (+ idx 1) } }",
"Let _opText_ be the sequence of Unicode code points associated with _assignmentOpText_ in the following table:\n <figure>\n <!-- emu-format ignore -->\n <table class=\"lightweight-table\">\n <tbody><tr><th> _assignmentOpText_ </th><th> _opText_ </th></tr>\n <tr><td> `**=` </td><td> `**` </td></tr>\n <tr><td> `*=` </td><td> `*` </td></tr>\n <tr><td> `/=` </td><td> `/` </td></tr>\n <tr><td> `%=` </td><td> `%` </td></tr>\n <tr><td> `+=` </td><td> `+` </td></tr>\n <tr><td> `-=` </td><td> `-` </td></tr>\n <tr><td> `<<=` </td><td> `<<` </td></tr>\n <tr><td> `>>=` </td><td> `>>` </td></tr>\n <tr><td> `>>>=` </td><td> `>>>` </td></tr>\n <tr><td> `&=` </td><td> `&` </td></tr>\n <tr><td> `^=` </td><td> `^` </td></tr>\n <tr><td> `|=` </td><td> `|` </td></tr>\n </tbody></table>\n </figure>": "{ if (= assignmentOpText \"**=\") let opText = \"**\" else {} if (= assignmentOpText \"*=\") let opText = \"*\" else {} if (= assignmentOpText \"/=\") let opText = \"/\" else {} if (= assignmentOpText \"%=\") let opText = \"%\" else {} if (= assignmentOpText \"+=\") let opText = \"+\" else {} if (= assignmentOpText \"-=\") let opText = \"-\" else {} if (= assignmentOpText \"<<=\") let opText = \"<<\" else {} if (= assignmentOpText \">>=\") let opText = \">>\" else {} if (= assignmentOpText \">>>=\") let opText = \">>>\" else {} if (= assignmentOpText \"&=\") let opText = \"&\" else {} if (= assignmentOpText \"^=\") let opText = \"^\" else {} if (= assignmentOpText \"|=\") let opText = \"|\" else {} }",
"Let _operation_ be the abstract operation associated with _opText_ and Type(_lnum_) in the following table:\n <figure>\n <!-- emu-format ignore -->\n <table class=\"lightweight-table\">\n <tbody><tr><th> _opText_ </th><th> Type(_lnum_) </th><th> _operation_ </th></tr>\n <tr><td> `**` </td><td> Number </td><td> Number::exponentiate </td></tr>\n <tr><td> `*` </td><td> Number </td><td> Number::multiply </td></tr>\n <tr><td> `*` </td><td> BigInt </td><td> BigInt::multiply </td></tr>\n <tr><td> `/` </td><td> Number </td><td> Number::divide </td></tr>\n <tr><td> `%` </td><td> Number </td><td> Number::remainder </td></tr>\n <tr><td> `+` </td><td> Number </td><td> Number::add </td></tr>\n <tr><td> `+` </td><td> BigInt </td><td> BigInt::add </td></tr>\n <tr><td> `-` </td><td> Number </td><td> Number::subtract </td></tr>\n <tr><td> `-` </td><td> BigInt </td><td> BigInt::subtract </td></tr>\n <tr><td> `<<` </td><td> Number </td><td> Number::leftShift </td></tr>\n <tr><td> `<<` </td><td> BigInt </td><td> BigInt::leftShift </td></tr>\n <tr><td> `>>` </td><td> Number </td><td> Number::signedRightShift </td></tr>\n <tr><td> `>>` </td><td> BigInt </td><td> BigInt::signedRightShift </td></tr>\n <tr><td> `>>>` </td><td> Number </td><td> Number::unsignedRightShift </td></tr>\n <tr><td> `&` </td><td> Number </td><td> Number::bitwiseAND </td></tr>\n <tr><td> `&` </td><td> BigInt </td><td> BigInt::bitwiseAND </td></tr>\n <tr><td> `^` </td><td> Number </td><td> Number::bitwiseXOR </td></tr>\n <tr><td> `^` </td><td> BigInt </td><td> BigInt::bitwiseXOR </td></tr>\n <tr><td> `|` </td><td> Number </td><td> Number::bitwiseOR </td></tr>\n <tr><td> `|` </td><td> BigInt </td><td> BigInt::bitwiseOR </td></tr>\n </tbody></table>\n </figure>": "if (? lnum: \"Number\") { if (= opText \"**\") let operation = clo<Number::exponentiate> else {} if (= opText \"*\") let operation = clo<Number::multiply> else {} if (= opText \"/\") let operation = clo<Number::divide> else {} if (= opText \"%\") let operation = clo<Number::remainder> else {} if (= opText \"+\") let operation = clo<Number::add> else {} if (= opText \"-\") let operation = clo<Number::subtract> else {} if (= opText \"<<\") let operation = clo<Number::leftShift> else {} if (= opText \">>\") let operation = clo<Number::signedRightShift> else {} if (= opText \">>>\") let operation = clo<Number::unsignedRightShift> else {} if (= opText \"&\") let operation = clo<Number::bitwiseAND> else {} if (= opText \"^\") let operation = clo<Number::bitwiseXOR> else {} if (= opText \"|\") let operation = clo<Number::bitwiseOR> else {} } else if (? lnum: \"BigInt\") { if (= opText \"*\") let operation = clo<BigInt::multiply> else {} if (= opText \"+\") let operation = clo<BigInt::add> else {} if (= opText \"-\") let operation = clo<BigInt::subtract> else {} if (= opText \"<<\") let operation = clo<BigInt::leftShift> else {} if (= opText \">>\") let operation = clo<BigInt::signedRightShift> else {} if (= opText \"&\") let operation = clo<BigInt::bitwiseAND> else {} if (= opText \"^\") let operation = clo<BigInt::bitwiseXOR> else {} if (= opText \"|\") let operation = clo<BigInt::bitwiseOR> else {} } else { }",
"Let _privateName_ be the Private Name in _names_ whose [[Description]] is _privateIdentifier_.": "{ let idx = 0 loop[repeat] (< idx names.length) { let elem = names[idx] if (= elem.Description privateIdentifier) let privateName = elem else {} idx = (+ idx 1) } }",
"Let _privateName_ be the Private Name in _names_ whose [[Description]] is _privateIdentifier_.": "{ let idx = 0 while (< idx names.length) { let elem = names[idx] if (= elem.Description privateIdentifier) let privateName = elem else {} idx = (+ idx 1) } }",
"Let _realmRec_ be a new Realm Record.": "let realmRec = @REALM",
"Let _result_ be the Completion Record that is <emu-meta effects=\"user-code\">the result of evaluating</emu-meta> _F_ in a manner that conforms to the specification of _F_. If _thisArgument_ is ~uninitialized~, the *this* value is uninitialized; otherwise, _thisArgument_ provides the *this* value. _argumentsList_ provides the named parameters. _newTarget_ provides the NewTarget value.": "if (= thisArgument ~uninitialized~) call result = F.Code(undefined, argumentsList, newTarget) else call result = F.Code(thisArgument, argumentsList, undefined)",
"Let _sourceText_ be the source code of a script.": "let sourceText = @SOURCE_TEXT",
Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/esmeta/cfg/Node.scala
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ case class Branch(
var elseNode: Option[Node] = None,
) extends NodeWithInst {
def isLoop: Boolean = kind match
case BranchKind.If => false
case _ => true
case BranchKind.If => false
case BranchKind.While => true
}
enum BranchKind extends CFGElem:
case If
case Loop(str: String)
case While
4 changes: 2 additions & 2 deletions src/main/scala/esmeta/cfg/util/Stringifier.scala
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class Stringifier(detail: Boolean, location: Boolean) {
given branchKindRule: Rule[BranchKind] = (app, kind) =>
import BranchKind.*
app >> (kind match {
case If => "if"
case Loop(str) => s"loop[$str]"
case If => "if"
case While => "while"
})
}
35 changes: 24 additions & 11 deletions src/main/scala/esmeta/cfgbuilder/CFGBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,28 @@ class CFGBuilder(
case (branch: Branch, true) => branch.thenNode = Some(to)
case (branch: Branch, false) => branch.elseNode = Some(to)

// aux branch case
def auxBranch(inst: Inst): Unit =
inst match
case branch: BranchInst =>
branch match
case IIf(cond, thenInst, elseInst) =>
val branch = Branch(nextNId, BranchKind.If, cond)
connect(branch.setInst(inst))
val thenPrev = {
prev = List((branch, true)); aux(thenInst); prev
}
val elsePrev = {
prev = List((branch, false)); aux(elseInst); prev
}
prev = thenPrev ++ elsePrev
case IWhile(cond, body) =>
val branch = Branch(nextNId, BranchKind.While, cond)
connect(branch.setInst(inst), isLoopPred = true)
prev = List((branch, true)); aux(body); connect(branch)
prev = List((branch, false))
case _ => throw Exception("impossible match")

// aux
def aux(inst: Inst): Unit = inst match {
case normal: NormalInst =>
Expand All @@ -59,17 +81,8 @@ class CFGBuilder(
block.insts += normal
prev = List((block, true))
case ISeq(insts) => for { i <- insts } aux(i)
case inst @ IIf(cond, thenInst, elseInst) =>
val branch = Branch(nextNId, BranchKind.If, cond)
connect(branch.setInst(inst))
val thenPrev = { prev = List((branch, true)); aux(thenInst); prev }
val elsePrev = { prev = List((branch, false)); aux(elseInst); prev }
prev = thenPrev ++ elsePrev
case inst @ ILoop(kind, cond, body) =>
val branch = Branch(nextNId, BranchKind.Loop(kind), cond)
connect(branch.setInst(inst), isLoopPred = true)
prev = List((branch, true)); aux(body); connect(branch)
prev = List((branch, false))
case branch: BranchInst =>
auxBranch(inst)
case callInst: CallInst =>
val call = Call(nextNId, callInst)
connect(call)
Expand Down
27 changes: 9 additions & 18 deletions src/main/scala/esmeta/compiler/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,7 @@ class Compiler(
case Param(name, _, Variadic) =>
List(
ILet(Name(name), EList(Nil)),
ILoop(
"args",
IWhile(
lessThan(EMath(BigDecimal(remaining, UNLIMITED)), argsLen),
IPush(EPop(ENAME_ARGS_LIST, true), toERef(Name(name)), false),
),
Expand Down Expand Up @@ -231,8 +230,7 @@ class Compiler(
IAssign(i, zero),
)
fb.addInst(
ILoop(
"foreach",
IWhile(
lessThan(iExpr, toStrERef(list, "length")),
fb.newScope {
fb.addInst(ILet(compile(x), toERef(list, iExpr)))
Expand All @@ -249,8 +247,7 @@ class Compiler(
IAssign(i, toStrERef(list, "length")),
)
fb.addInst(
ILoop(
"foreach",
IWhile(
lessThan(zero, iExpr),
fb.newScope {
fb.addInst(IAssign(i, sub(iExpr, one)))
Expand All @@ -264,8 +261,7 @@ class Compiler(
val (i, iExpr) = compileWithExpr(x)
fb.addInst(ILet(i, compile(fb, start)))
fb.addInst(
ILoop(
"foreach-int",
IWhile(
if (ascending) not(lessThan(compile(fb, end), iExpr))
else not(lessThan(iExpr, compile(fb, end))),
fb.newScope {
Expand All @@ -284,8 +280,7 @@ class Compiler(
IAssign(list, EKeys(toStrERef(compile(fb, obj), "SubMap"), intSorted)),
if (ascending) IAssign(i, zero)
else IAssign(i, toStrERef(list, "length")),
ILoop(
"repeat",
IWhile(
if (ascending) lessThan(iExpr, toStrERef(list, "length"))
else lessThan(zero, iExpr),
fb.newScope {
Expand All @@ -312,8 +307,7 @@ class Compiler(
IAssign(length, toStrERef(list, "length")),
)
fb.addInst(
ILoop(
"foreach-node",
IWhile(
lessThan(iExpr, lengthExpr),
fb.newScope {
fb.addInst(ILet(compile(x), toERef(list, iExpr)))
Expand All @@ -337,8 +331,7 @@ class Compiler(
fb.addInst(IPush(compile(fb, expr), ERef(compile(fb, ref)), true))
case RepeatStep(cond, body) =>
fb.addInst(
ILoop(
"repeat",
IWhile(
cond.fold(EBool(true))(compile(fb, _)),
compileWithScope(fb, body),
),
Expand Down Expand Up @@ -565,8 +558,7 @@ class Compiler(
IAssign(list, EList(Nil)),
)
fb.addInst(
ILoop(
"int-list",
IWhile(
if (asc) lessThan(iExpr, if (tInc) inc(tExpr) else tExpr)
else lessThan(if (fInc) dec(fExpr) else fExpr, iExpr),
fb.newScope {
Expand Down Expand Up @@ -922,8 +914,7 @@ class Compiler(
IAssign(l, list),
IAssign(i, zero),
IAssign(b, F),
ILoop(
"contains",
IWhile(
and(not(bExpr), lessThan(iExpr, toStrERef(l, "length"))),
fb.newScope {
fb.addInst(
Expand Down
Loading
Loading