Commit graph

54 commits

Author SHA1 Message Date
Linus Groh
332946ab4f LibJS: Prepare ExecutionContext to store the current Realm Record
Also add VM::current_realm() to retrieve it, similar to all the other
getters (running_execution_context() et al.).
2021-09-12 11:10:20 +01:00
Linus Groh
15c33477e4 LibJS: Make prepare_for_ordinary_call() new_target parameter an Object*
This got changed in the spec at some point, replacing the assertion in
step 1 with "... and newTarget (an Object or undefined)" in the
parameter description.
Subsequently, there's now one step less, so the numbers all change.
2021-09-12 11:10:20 +01:00
Andreas Kling
0d2c3f62d3 LibJS: Use move semantics more when creating Reference objects
Turns a bunch of FlyString copies into moves.
2021-09-11 20:38:45 +02:00
Andreas Kling
b76456f0ed LibJS: Add a way to attach custom data to a JS::VM instance
This will be used by LibWeb to attach web engine specific stuff that
LibJS doesn't need to know about.
2021-09-09 02:18:31 +02:00
Linus Groh
6ffc8f389e LibJS: Use different stack space limit values for with and without ASAN
Instead of having a single limit here, which we had to increase once to
work with ASAN enabled, check whether HAS_ADDRESS_SANITIZER is defined
and use 32 KiB, and 16 KiB otherwise (which is what we used previously).

This idea is shamelessly stolen from V8:
https://github.com/v8/v8/blob/b2b44af/src/execution/isolate.cc#L1381-L1387
2021-09-05 22:17:09 +01:00
Linus Groh
9998a2c91e LibJS: Add ErrorType::CallStackSizeExceeded
I'm about to add another use of this, so let's add an ErrorType for it
instead of hardcoding the message for a third time.
2021-09-05 22:17:09 +01:00
davidot
def8b44c40 LibJS: Add support for public fields in classes 2021-09-01 13:39:14 +01:00
Robert Stefanic
e26cfd313e LibJS: Prevent stack overflow in flatten_into_array()
The check for stack space in VM from push_execution_context has been
moved to a method on VM called did_reach_stack_space_limit. This
allows us to check the stack size in other places besides
push_execution_context.

We can now verify that we have enough space on the stack before calling
flatten_into_array to ensure that we don't cause a stack overflow error
when calling the function with a large depth.
2021-08-15 11:24:30 +01:00
Timothy Flynn
66264f7c2a LibJS: Change ExecutionContext's arguments list to a MarkedValueList
The test262 tests under RegExp/property-escapes/generated will invoke
Reflect.apply with up to 10,000 arguments at a time. In LibJS, when the
call stack reached VM::call_internal, we transfer those arguments from
a MarkedValueList to the execution context's arguments Vector.

Because these types differ (MarkedValueList is a Vector<Value, 32>), the
arguments are copied rather than moved. By changing the arguments vector
to a MarkedValueList, we can properly move the passed arguments over.

This shaves about 2 seconds off the following test262 test (from 15sec):
  RegExp/property-escapes/generated/General_Category_-_Decimal_Number.js
2021-08-10 23:07:50 +02:00
Timothy Flynn
c6e9c6d6ab LibJS: Follow the spec more closely when determining the this value
Co-authored-by: davidot <david.tuin@gmail.com>
2021-07-20 23:45:28 +02:00
Andreas Kling
fd43d1e205 LibJS: Improve ResolveBinding + add GetIdentifierReference
ResolveBinding now matches the spec, while the non-conforming parts
are moved to GetIdentifierReference.

Implementing this properly requires variable bindings.
2021-07-02 22:22:21 +02:00
Andreas Kling
5ce9305c5f LibJS: Implement the PrepareForOrdinaryCall abstract operation
This is used by VM::call_internal() and VM::construct() which roughly
map to function objects' [[Call]] and [[Construct]] slots in the spec.

Reorganizing this code revealed something weird: NativeFunction gets
its strictness by checking VM::in_strict_mode(). In other words,
it inherits the strict flag from the caller context. This is quite
weird, but many test-js tests rely on it, so let's preserve it until
we can think of something nicer.
2021-07-02 21:44:08 +02:00
Andreas Kling
44221756ab LibJS: Drop "Record" suffix from all the *Environment record classes
"Records" in the spec are basically C++ classes, so let's drop this
mouthful of a suffix.
2021-07-01 12:28:57 +02:00
Andreas Kling
9eed7444de LibJS: Implement the CreateUnmappedArgumentsObject abstract operation 2021-06-28 02:00:46 +02:00
Andreas Kling
1bd52ce789 LibJS: Stop qualifying AK::Function
Now that JS function objects are JS::FunctionObject, we can stop
qualifying AK::Function and just say "Function" everywhere. Nice. :^)
2021-06-27 22:40:49 +02:00
Andreas Kling
ba9d5c4d54 LibJS: Rename Function => FunctionObject 2021-06-27 22:36:04 +02:00
Andreas Kling
bce7fdba81 LibJS: Bring Reference records a bit closer to the ECMAScript spec
Our Reference class now has the same fields as the spec:

- Base (a non-nullish value, an environment record, or `unresolvable`)
- Referenced Name (the name of the binding)
- Strict (whether the reference originated in strict mode code)
- ThisValue (if non-empty, the reference represents a `super` keyword)

The main difference from before is that we now resolve the environment
record that a reference interacts with. Previously we simply resolved
to either "local variable" or "global variable".

The associated abstract operations are still largely non-conforming,
since we don't yet implement proper variable bindings. But this patch
should at least fix a handful of test262 cases. :^)

There's one minor regression: some TypeError message strings get
a little worse due to doing a RequireObjectCoercible earlier in the
evaluation of MemberExpression.
2021-06-25 16:58:36 +02:00
Andreas Kling
6e1932e8b2 LibJS: Evaluate this in terms of ResolveThisBinding 2021-06-25 16:58:36 +02:00
Andreas Kling
07acdc7be2 LibJS: Rename VM::get_reference() => resolve_binding()
This function maps to the ResolveBinding operation from the spec,
so let's rename it to match.
2021-06-25 16:58:36 +02:00
Andreas Kling
6215a9c2cb LibJS: Rename ExecutionContext::callee => function
This matches what ECMAScript calls it. Also make it a JS::Function*
instead of a generic Value, since it will always either be a function
object or null.
2021-06-24 19:28:00 +02:00
Andreas Kling
c2ad599783 LibJS: Rename CallFrame => ExecutionContext
This struct represents what the ECMAScript specification calls an
"execution context" so let's use the same terminology. :^)
2021-06-24 19:28:00 +02:00
Andreas Kling
cf34313fad LibJS: Remove no-longer-needed environment record shape
We had a cached shape for environment records to make instantiating
them fast. Now that environment records don't inherit from JS::Object,
we can just get rid of this. :^)
2021-06-23 13:08:40 +02:00
Andreas Kling
1d20380859 LibJS: Split the per-call-frame environment into lexical and variable
To better follow the spec, we need to distinguish between the current
execution context's lexical environment and variable environment.

This patch moves us to having two record pointers, although both of
them point at the same environment records for now.
2021-06-22 18:44:53 +02:00
Andreas Kling
aabd82d508 LibJS: Bring function environment records closer to the spec
This patch adds FunctionEnvironmentRecord as a subclass of the existing
DeclarativeEnvironmentRecord. Things that are specific to function
environment records move into there, simplifying the base.

Most of the abstract operations related to function environment records
are rewritten to match the spec exactly. I also had to implement
GetThisEnvironment() and GetSuperConstructor() to keep tests working
after the changes, so that's nice as well. :^)
2021-06-22 18:44:53 +02:00
Andreas Kling
08510a0c80 LibJS: Rename VM::current_scope() => current_environment_record()
And rename some related functions that wrapped this as well.
2021-06-21 23:49:50 +02:00
Andreas Kling
6c6dbcfc36 LibJS: Rename Environment Records so they match the spec :^)
This patch makes the following name changes:

- ScopeObject => EnvironmentRecord
- LexicalEnvironment => DeclarativeEnvironmentRecord
- WithScope => ObjectEnvironmentRecord
2021-06-21 23:49:50 +02:00
Andreas Kling
0d2aba07aa LibJS: Add VM::dump_scope_chain()
This is a handy helper that dumps the current scope chain, starting at
the innermost scope.
2021-06-21 20:58:55 +02:00
Idan Horowitz
de9fa6622a LibJS: Add the FinalizationRegistry built-in object
As well as the needed functionality in VM to enqueue and run cleanup
jobs for the FinalizationRegistry instances.
2021-06-15 23:59:21 +01:00
Idan Horowitz
2100b46d02 LibJS: Implement the IteratorClose abstract op and use it where needed 2021-06-15 12:15:12 +01:00
Idan Horowitz
6913f06b6f LibJS: Store and maintain an "execution generation" counter
This counter is increased each time a synchronous execution sequence
completes, and will allow us to emulate the abstract operations
AddToKeptObjects & ClearKeptObjects efficiently.
2021-06-12 18:39:23 +01:00
Andreas Kling
93a07ba962 LibJS: Remove GlobalObject& argument from VM::construct()
We can just get the global object from the constructor function.
2021-06-10 23:17:29 +02:00
Gunnar Beutner
319a60043b LibJS: Let the bytecode interpreter set the VM's last value 2021-06-10 21:47:25 +02:00
Idan Horowitz
064ed8279e LibJS: Support deleting local variables with operator delete
To make this cleaner i also moved the logic into Reference::delete_.
2021-06-08 15:31:46 +01:00
Andreas Kling
d24f4462c7 LibJS: Add VM::dump_backtrace()
This is just a simple helper that dumps the current VM call stack
to the debug console. I find myself rewriting this function over and
over, so let's just have it in the tree.
2021-06-07 10:22:25 +02:00
Andreas Kling
f290048662 LibJS: Pass unwinding target labels a bit more efficiently
Use const reference or move semantics when passing these labels.
2021-06-06 11:45:52 +02:00
Ali Mohammad Pur
7a00d6d9c8 LibJS: Implement destructuring assignments and function parameters 2021-05-29 23:02:23 +04:30
Linus Groh
b9d3df70e0 LibJS: Increase free stack space required for function calls to 32 kiB
The previous 16 kiB weren't sufficient with ASAN enabled and would
trigger stack overflow failures.
2021-05-17 18:03:10 +01:00
Ali Mohammad Pur
b1b0db946e LibJS: Default-initialize the current_node pointer member in CallFrame
Some parts of the code depend on this being nullptr without actually
initializing it, leading to odd random crashes.
e.g. `VM::call_internal`.
2021-05-17 09:41:26 +02:00
Linus Groh
62c7608a25 LibJS+LibWeb: Move exception logging and remove should_log_exceptions
LibWeb is now responsible for logging unhandled exceptions itself,
which means set_should_log_exceptions() is no longer used and can be
removed. It turned out to be not the best option for web page exception
logging, as we would have no indication regarding whether the exception
was later handled of not.
2021-04-24 20:11:04 +02:00
Linus Groh
08373090ae LibJS: Add VM::on_call_stack_emptied callback
Instead of having to run queued promise jobs in LibWeb in various
places, this allows us to consolidate that into one function - this is
very close to how the spec describes it as well ("at some future point
in time, when there is no running execution context and the execution
context stack is empty, the implementation must [...]").

Eventually this will also be used to log unhandled exceptions, and
possibly other actions that require JS execution to have ended.
2021-04-24 20:11:04 +02:00
Linus Groh
ebdeed087c Everywhere: Use linusg@serenityos.org for my copyright headers 2021-04-22 22:51:19 +02:00
Brian Gianforcaro
1682f0b760 Everything: Move to SPDX license identifiers in all files.
SPDX License Identifiers are a more compact / standardized
way of representing file license information.

See: https://spdx.dev/resources/use/#identifiers

This was done with the `ambr` search and replace tool.

 ambr --no-parent-ignore --key-from-file --rep-from-file key.txt rep.txt *
2021-04-22 11:22:27 +02:00
Linus Groh
8d490aba76 LibJS: Implement console.assert() 2021-04-18 18:28:17 +02:00
Linus Groh
45133d8ada LibJS: Unset m_unwind_until_label in stop_unwind()
I don't see a reason to keep this intact, that might only surprise us
down the line...
2021-04-13 15:40:52 +02:00
Linus Groh
4ee965f916 LibJS: Add set_exception() and change throw_exception() to take a reference
Sometimes we just want to set m_exception to some value we stored
previously, without really "throwing" it again - that's what
set_exception() does now. Since we have clear_exception(), it does take
a reference, i.e. you don't set_exception(nullptr). For consistency I
updated throw_exception() to do the same.
2021-04-13 15:40:52 +02:00
Linus Groh
da177c6517 LibJS: Make Errors fully spec compliant
The previous handling of the name and message properties specifically
was breaking websites that created their own error types and relied on
the error prototype working correctly - not assuming an JS::Error this
object, that is.

The way it works now, and it is supposed to work, is:

- Error.prototype.name and Error.prototype.message just have initial
  string values and are no longer getters/setters
- When constructing an error with a message, we create a regular
  property on the newly created object, so a lookup of the message
  property will either get it from the object directly or go though the
  prototype chain
- Internal m_name/m_message properties are no longer needed and removed

This makes printing errors slightly more complicated, as we can no
longer rely on the (safe) internal properties, and cannot trust a
property lookup either - get_without_side_effects() is used to solve
this, it's not perfect but something we can revisit later.

I did some refactoring along the way, there was some really old stuff in
there - accessing vm.call_frame().arguments[0] is not something we (have
to) do anymore :^)

Fixes #6245.
2021-04-12 09:38:57 +02:00
Linus Groh
f418115f1b LibJS: Add initial support for Promises
Almost a year after first working on this, it's finally done: an
implementation of Promises for LibJS! :^)

The core functionality is working and closely following the spec [1].
I mostly took the pseudo code and transformed it into C++ - if you read
and understand it, you will know how the spec implements Promises; and
if you read the spec first, the code will look very familiar.

Implemented functions are:

- Promise() constructor
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.resolve()
- Promise.reject()

For the tests I added a new function to test-js's global object,
runQueuedPromiseJobs(), which calls vm.run_queued_promise_jobs().
By design, queued jobs normally only run after the script was fully
executed, making it improssible to test handlers in individual test()
calls by default [2].

Subsequent commits include integrations into LibWeb and js(1) -
pretty-printing, running queued promise jobs when necessary.

This has an unusual amount of dbgln() statements, all hidden behind the
PROMISE_DEBUG flag - I'm leaving them in for now as they've been very
useful while debugging this, things can get quite complex with so many
asynchronously executed functions.

I've not extensively explored use of these APIs for promise-based
functionality in LibWeb (fetch(), Notification.requestPermission()
etc.), but we'll get there in due time.

[1]: https://tc39.es/ecma262/#sec-promise-objects
[2]: https://tc39.es/ecma262/#sec-jobs-and-job-queues
2021-04-02 10:47:40 +02:00
Andreas Kling
1fb50d823d LibJS: Always inline Cell::vm() and Cell::heap() 2021-03-21 21:39:39 +01:00
Andreas Kling
1603623772 LibJS: Move AST node stack from VM to Interpreter 2021-03-21 16:02:11 +01:00
Andreas Kling
8062fc711c LibJS: Add arguments.callee to our hack arguments object
arguments.callee refers to the currently executing function.
2021-03-15 21:20:33 +01:00