When there is no `catch` parameter to bind the error, we don't need
to allocate an environment, since there's nothing to add to it.
This avoids one environment allocation every time we catch like this:
try {
...
} catch {
...
}
This was a remnant from the AST/BC hybrid interpreter times. We've had
a VERIFY in here for weeks now that would catch anything depending on
this behavior, and nothing has hit it, so let's remove the unnecessary
code (but leave the VERIFY) :^)
Our implementation of environment.CreateImmutableBinding(name, true)
in this AO was not correctly initializing const variables in strict
mode. This would mean that constant declarations in for loop bodies
would not throw if they were modified.
To fix this, add a new parameter to CreateVariable to set strict mode.
Also remove the vm.is_strict mode check here, as it doesn't look like
anywhere in the spec will change strict mode depending on whether the
script itself is running in script mode or not.
This fixes two of our test-js tests, no change to test262.
Instead of running a big switch statement on the opcode when checking
how long an instruction is, we now simply store that in a member
variable at construction time for instant access.
This yields a 10.2% speed-up on Kraken/ai-astar :^)
Instead of trying to keep a live reference to the bytecode interpreter's
current instruction stream iterator, we now simply copy the current
iterator whenever pushing to the ExecutionContext stack.
This fixes a stack-use-after-return issue reported by ASAN.
This works by adding source start/end offset to every bytecode
instruction. In the future we can make this more efficient by keeping
a map of bytecode ranges to source ranges in the Executable instead,
but let's just get traces working first.
Co-Authored-By: Andrew Kaster <akaster@serenityos.org>
This is not we're supposed to do according to https://tc39.es/ecma262/#sec-runtime-semantics-propertydefinitionevaluation
Furthermore, this was observable by ToPrimitive looking up toString and
valueOf and potentially calling them if they exist. The big ticket
issue however is that for objects without toString and valueOf, such as
null-proto objects, this would unexpectedly throw.
If we're inside of a `with` statement scope, we have to take care to
extract the correct `this` value for use in calls when calling a method
on the binding object via an Identifier instead of a MemberExpression.
This makes Vue.js work way better in the bytecode VM. :^)
Also, 1 new pass on test262.
Because "this" value cannot be changed during function execution it is
safe to compute it once and then use for future access.
This optimization makes ai-astar.js run 8% faster.
This fixes an issue where returning inside a `try` block and then
calling a function inside `finally` would clobber the saved return
value from the `try` block.
Note that we didn't need to change the base of register allocation,
since it was already 1 too high.
With this fixed, https://microsoft.com/edge loads in bytecode mode. :^)
Thanks to Luke for reducing the issue!
These passes have not been shown to actually optimize any JS, and tests
have become very flaky with optimizations enabled. Until some measurable
benefit is shown, remove the optimization passes to reduce overhead of
maintaining bytecode operations and to reduce CI churn. The framework
for optimizations will live on in git history, and can be restored once
proven useful.
GetByValue now shares code with GetById to elide the synthetic wrapper
objects for primitive values in strict mode.
Fixes 2 test-js tests in bytecode mode. :^)
This is just something I spotted looking around the code, previously
the PassPipelineExecutable was passed by value to
generate_cfg_for_block, which generated the CFG then just dropped it on
the floor. Making this a reference results in the CFG actually getting
generated.
Similar to the scoped continue and break, the only two differences
between these functions is the scope that is scanned for a matching
label, and the specific handling of a continue/break boundary.
Rather than splitting the Iterator type and its AOs into two files,
let's combine them into one file to match every other JS runtime object
that we have.
If an exception was thrown while evaluating the argument of an `await`
expression, we should jump to the continuation block instead of eagerly
rejecting the caller async function.
This restores the behavior prior to the addition of the separate `Await`
instruction in d66eb4e3.
If the exception from the `try` block has already been caught by
`catch`, we need to clear the saved exception before entering `finally`
so that ContinuePendingUnwind will not re-throw it.
9 new passes on test262 :^)
CreateVariable is not needed for locals because they are not stored in
environment and created binding will not be used. Also if all variables
in loop initialization sections are local then CreateLexicalEnvironment
and LeaveLexicalEnvironment can also be ommitted.
The RegExpLiteral AST node already has the parsed regex::Parser::Result
so let's plumb that over to the bytecode executable instead of reparsing
the regex every time NewRegExp is executed.
~12% speed-up on language/literals/regexp/S7.8.5_A2.1_T2.js in test262.
This optimization was no longer helpful after the bug fix for missing
invalidation on global delete was introduced in 331f6a9e6, since we
now have to check bindings for presence in the global environment every
time anyway.
Since the bytecode VM now has fast GetGlobal in most cases, let's not
even worry about this and just remove the unhelpful "optimization".
In fact, removing this is actually an *optimization*, since we avoid
a redundant has_binding() check on every global variable access. :^)
Using mmap was quite punishing on inputs with lots of basic blocks,
such as test262 tests with eval() in a loop that goes 64k times..
~27% speed-up on language/literals/regexp/S7.8.5_A2.1_T2.js but
presumably everything everywhere will benefit from this. :^)
Using a special instruction to access global variables allows skipping
the environment chain traversal for them and going directly to the
module/global environment. Currently, this instruction only caches the
offset for bindings that belong to the global object environment.
However, there is also an opportunity to cache the offset in the global
declarative record.
This change results in a 57% increase in speed for
imaging-gaussian-blur.js in Kraken.
Since we can't rely on shape identity (i.e its pointer address) for
unique shapes, give them a serial number that increments whenever a
mutation occurs.
Inline caches can then compare this serial number against what they
have seen before.
When building an object from an object expression, we don't want to
go through the full property setting machinery. This patch adds a new
PropertyKind::DirectKeyValue for PutById which guarantees that the
property becomes an own property.
This fixes an issue where setting the "__proto__" property in object
expressions wasn't working right.
12 new passes on test262. :^)
The instructions GetById and GetByIdWithThis now remember the last-seen
Shape, and if we see the same object again, we reuse the property offset
from last time without doing a new lookup.
This allows us to use Object::get_direct(), bypassing the entire lookup
machinery and saving lots of time.
~23% speed-up on Kraken/ai-astar.js :^)