Commit graph

1458 commits

Author SHA1 Message Date
Linus Groh
eaa85969c4 LibJS: Add Value::to_{index,length,integer_or_infinity} abstract operations
We should pay more attention to using the well-defined abstract
operations from the spec rather than making up our own, often slightly
different rules. This is another step in that direction.
2020-12-02 23:49:00 +01:00
Linus Groh
6de4f1fcb3 LibJS: Add generic InvalidLength error type
We have multiple array types now, so ArrayInvalidLength has been
replaced with a generic InvalidLength.

Also fixes a small issue in the Array constructor, it should throw
RangeError for invalid lengths, not TypeError.
2020-12-02 23:49:00 +01:00
Linus Groh
0b086c759a LibJS: Move TypedArray length getter to prototype 2020-12-02 14:39:53 +01:00
Linus Groh
ddaab598a7 LibJS: Add TypedArray.BYTES_PER_ELEMENT 2020-12-02 12:52:31 +01:00
Linus Groh
bb6bc70c5b LibJS: Add more tests for TypedArray 2020-12-02 12:52:31 +01:00
Linus Groh
3d05836a3e LibJS: Make TypedArray constructor (somewhat) spec-compliant
- Calling without 'new' is an error
- If the first argument is an object, we need a separate code path to
  initialize from TypedArray, ArrayBuffer, Iterable or Array-like
  object (marked TODO for now)
- Don't insert values into array if more than one argument is present
  (that's not part of the spec)
2020-12-02 12:52:31 +01:00
Linus Groh
1bff65c591 LibJS: Add ErrorType::ConstructorWithoutNew
...and use it in Proxy::call(), rather than having a specific error
type just for that.
2020-12-02 12:52:31 +01:00
Linus Groh
7fb299fe46 LibJS: Clean up TypedArray constructors and prototypes
The current implementation is not entirely correct yet. Two classes have
been added:
- TypedArrayConstructor, which the various typed array constructors now
  inherit from. Calling or constructing this class (from JS, that is)
  directly is not possible, we might want to move this abstract class
  functionality to NativeFunction at a later point.
- TypedArrayPrototype, which the various typed array prototypes now have
  as their own prototype. This will be the place where most of the
  functionality is being shared.

Relevant parts from the spec:

22.2.1 The %TypedArray% Intrinsic Object
The %TypedArray% intrinsic object:
- is a constructor function object that all of the TypedArray
  constructor objects inherit from.
- along with its corresponding prototype object, provides common
  properties that are inherited by all TypedArray constructors and their
  instances.

22.2.2 Properties of the %TypedArray% Intrinsic Object
The %TypedArray% intrinsic object:
- has a [[Prototype]] internal slot whose value is %Function.prototype%.

22.2.2.3 %TypedArray%.prototype
The initial value of %TypedArray%.prototype is the %TypedArray%
prototype object.

22.2.6 Properties of the TypedArray Constructors
Each TypedArray constructor:
- has a [[Prototype]] internal slot whose value is %TypedArray%.

22.2.6.2 TypedArray.prototype
The initial value of TypedArray.prototype is the corresponding
TypedArray prototype intrinsic object (22.2.7).

22.2.7 Properties of the TypedArray Prototype Objects
Each TypedArray prototype object:
- has a [[Prototype]] internal slot whose value is %TypedArray.prototype%.

22.2.7.2 TypedArray.prototype.constructor
The initial value of a TypedArray.prototype.constructor is the
corresponding %TypedArray% intrinsic object.
2020-12-02 12:52:31 +01:00
Andreas Kling
3565d3c60c LibJS: Add six typed arrays (signed and unsigned 8/16/32-bit)
This patch adds six of the standard type arrays and tries to share as
much code as possible:

- Uint8Array
- Uint16Array
- Uint32Array
- Int8Array
- Int16Array
- Int32Array
2020-12-01 21:05:25 +01:00
Andreas Kling
93feb7a81f LibJS: Have Uint8ClampedArray delegate OOB accesses to JS::Object
Uint8ClampedArray itself only cares about legitimate in-bounds accesses
since that's what where the specialization happens.
2020-12-01 17:12:04 +01:00
Andreas Kling
f2c7caf2db LibJS: Zero out memory in newly allocated Uint8ClampedArray objects 2020-12-01 17:06:48 +01:00
Linus Groh
48c19cdb06 LibJS: Remove ProxyPrototype
Proxy is an "exotic object" and doesn't have its own prototype. Use the
regular object prototype instead, but most stuff is happening on the
target object anyway. :^)
2020-12-01 09:54:37 +01:00
Linus Groh
ea08bf5812 LibJS: Fix crash in Lexer on EOF in unterminated template literal
Fixes #4252.
2020-11-30 11:36:42 +01:00
Andreas Kling
2d9d883274 LibJS: Add a basic implementation of String.prototype.substr() 2020-11-29 20:29:49 +01:00
Andreas Kling
2e4832c3da LibJS: Constructor function's "prototype" property should be writable
This matches other engines.
2020-11-29 19:49:27 +01:00
Andreas Kling
01c8765519 LibJS+LibWeb: Log JavaScript exceptions raised by web content
Instead of hiding JS exceptions raised on the web, we now print them to
the debug log. This will make it a bit easier to work out why some web
pages aren't working right. :^)
2020-11-29 16:50:32 +01:00
Linus Groh
3ac7fb9f6c LibJS: Disallow 'with' statement in strict mode 2020-11-28 20:33:41 +01:00
Andreas Kling
42b1b36eb4 LibJS: Run clang-format on WithScope.h 2020-11-28 17:36:38 +01:00
Andreas Kling
1fad95fec5 LibJS: Add a basic unit test for the "with" statement 2020-11-28 17:16:48 +01:00
Andreas Kling
9de6443ab7 LibJS: Add basic support for "with" statements
with statements evaluate an expression and put the result of it at the
"front" of the scope chain. This is implemented by creating a WithScope
object and placing it in front of the VM's current call frame's scope.
2020-11-28 17:16:48 +01:00
Andreas Kling
c3fe9b4df8 LibJS: Add a scope object abstraction
Both GlobalObject and LexicalEnvironment now inherit from ScopeObject,
and the VM's call frames point to a ScopeObject chain rather than just
a LexicalEnvironment chain.

This gives us much more flexibility to implement things like "with",
and also unifies some of the code paths that previously required
special handling of the global object.

There's a bunch of more cleanup that can be done in the wake of this
change, and there might be some oversights in the handling of the
"super" keyword, but this generally seems like a good architectural
improvement. :^)
2020-11-28 17:16:48 +01:00
Andreas Kling
e1bbc7c075 LibJS: Make JS::Value constructors take const cell pointers
Taking non-const cell pointers is asking for trouble, since passing e.g
a "const Object*" to Value(Object*) will actually call Value(bool),
which is most likely not what you want.
2020-11-28 17:16:48 +01:00
Andreas Kling
d617120499 LibJS: Parse "with" statements :^) 2020-11-28 17:16:48 +01:00
Andreas Kling
98f2da9834 LibJS: Rename Cell::visit_children() => Cell::visit_edges()
The GC heap is really a graph of cells, so "children" didn't quite feel
appropriate here.
2020-11-28 17:16:48 +01:00
Andreas Kling
97a05ac9ac LibJS: Allow Shape without a global object
It would be nice to be able to cache some shapes globally in the VM,
but then they can't be tied to a specific global object. So let's just
get rid of the requirement that shapes are tied to a global object.
2020-11-28 17:16:48 +01:00
Linus Groh
149b54e26f LibJS: Remove quotes from RegExpCompileError message
They look a bit out of place, especially for multi-line error messages.
2020-11-28 16:46:25 +01:00
Linus Groh
7dd77020ae LibJS: Use enumerator macros to define RegExp.prototype flag getters 2020-11-28 01:20:11 +01:00
Linus Groh
8a9a7f1677 LibJS: Make RegExp.prototype.source spec-compliant
Basically:
- And edge case for this object being RegExp.prototype.source
- Return "(?:)" for empty pattern
- Escape some things properly
2020-11-28 01:20:11 +01:00
Linus Groh
b6e5442d55 LibJS: Make RegExp.prototype.toString() spec-compliant
It should use the 'source' and 'flags' properties of the object, and
therefore work with non-RegExp objects as well.
2020-11-28 01:20:11 +01:00
Linus Groh
ee66eaa1b0 LibJS: Make RegExp.prototype.flags spec-compliant
This should be using the individual flag boolean properties rather than
the [[OriginalFlags]] internal slot.
Use an enumerator macro here for brevity, this will be useful for other
things as well. :^)
2020-11-28 01:20:11 +01:00
Linus Groh
5cb45e4feb LibJS: Make RegExp() constructor spec-compliant
- Default values should depend on arguments being undefined, not being
  missing
- "(?:)" for empty pattern happens in RegExp.prototype.source, not the
  constructor
2020-11-28 01:20:11 +01:00
AnotherTest
210a3db44d LibJS: Implement `RegExpPrototype::exec()'
This implements *only* the builtin exec() function.
2020-11-27 21:32:41 +01:00
AnotherTest
8ba273a2f3 LibJS: Hook up Regex<ECMA262> to RegExpObject and implement `test()'
This makes RegExpObject compile and store a Regex<ECMA262>, adds
all flag-related properties, and implements `RegExpPrototype.test()`
(complete with 'lastIndex' support) :^)
It should be noted that this only implements `test()' using the builtin
`exec()'.
2020-11-27 21:32:41 +01:00
AnotherTest
3200ff5f4f LibJS+js: Rename RegExp.{content => pattern}
The spec talks about it as 'pattern', so let's use that instead.
2020-11-27 21:32:41 +01:00
Linus Groh
922d0759b0 LibJS: Fix possible OOB read during Lexer construction
The Lexer constructor calls consume() once, which initializes m_position
to be > 0 and sets m_character. consume() calls is_line_terminator(),
which wasn't accounting for this state.
2020-11-25 22:43:30 +01:00
Linus Groh
f6f0d3cbae LibJS: Support receiver in ProxyObject::get/put()
If a receiver is given, e.g. via Reflect.get/set(), forward it to the
target object's get()/put() or use it as last argument of the trap
function. The default value is the Proxy object itself.
2020-11-24 21:35:03 +01:00
Linus Groh
48369194d2 LibJS: Forward receiver value to native property getters/setters
There's no reason why only (user-defined) accessors would have set the
receiver as this value for their getters/setters, this is an oversight.
2020-11-22 19:00:19 +01:00
Linus Groh
c52739ea4b LibJS: Make call_native_property_{g,s}etter() take a NativeProperty&
Passing in a plain Value and expecting it to be a native property is
error prone, let's use a more narrow type and pass a NativeProperty
reference directly.
2020-11-22 19:00:19 +01:00
Luke
bbc0487ced LibJS: Fix build with VM_DEBUG defined 2020-11-22 11:35:13 +01:00
Linus Groh
5a307836c1 LibJS: Handle symbol PropertyName in primitive assignment error
We can't just to_string() the PropertyName, it might be a symbol.
Instead to_value() it and then use to_string_without_side_effects() as
usual.

Fixes #4062.
2020-11-12 11:40:29 +01:00
Linus Groh
e77202fe0f LibJS/Tests: Use canParseSource() for toEval()
We can now enable the "new.target is syntax error outside of function"
test :^)
2020-11-12 10:14:57 +01:00
Linus Groh
8694d804c7 LibJS: Run prettier on test-common.js 2020-11-12 10:14:57 +01:00
Linus Groh
1b0c862f3a LibJS: Throw TypeError when calling class constructor without 'new' 2020-11-12 10:14:00 +01:00
Linus Groh
b07c7f589f LibJS: Refactor ScriptFunction::call() a bit
- Get VM reference once
- Less nesting
- Better variable names
2020-11-12 10:14:00 +01:00
Luke
bb22b04d44 LibWeb+LibJS: Add [LegacyNullToEmptyString] attribute
If specified, to_string() returns an empty string instead of "null" for
null values.
2020-11-11 12:15:05 +01:00
Andreas Kling
1745e503aa LibJS: Use a HashTable to identify potential cell pointers in GC scan
Previously we would iterate over all the live HeapBlocks in order to
learn if an arbitrary pointer-sized value was a pointer into a live
HeapBlock. This was quite time-consuming.

Instead of that, just put all the live HeapBlock*'s in a HashTable
and identify pointers by doing a bit-masked lookup into the table.
2020-11-10 20:28:53 +01:00
Linus Groh
a02b9983f9 LibJS: Throw RuntimeError when reaching the end of the stack
This prevents stack overflows when calling infinite/deep recursive
functions, e.g.:

    const f = () => f(); f();
    JSON.stringify({}, () => ({ foo: "bar" }));
    new Proxy({}, { get: (_, __, p) => p.foo }).foo;

The VM caches a StackInfo object to not slow down function calls
considerably. VM::push_call_frame() will throw an exception if
necessary (plain Error with "RuntimeError" as its .name).
2020-11-08 16:51:54 +01:00
Linus Groh
9c3ead8f91 LibJS+AK: Move cross-platform stack bounds code from JS::Heap to AK::StackInfo
This will be useful for other things than the Heap, maybe even outside
of LibJS.
2020-11-08 16:51:54 +01:00
Andreas Kling
43ff2ea8d8 LibJS: Use regular stack for VM call frames instead of Vector storage
Keeping the VM call frames in a Vector could cause them to move around
underneath us due to Vector resizing. Avoid this issue by allocating
CallFrame objects on the stack and having the VM simply keep a list
of pointers to each CallFrame, instead of the CallFrames themselves.

Fixes #3830.
Fixes #3951.
2020-11-07 13:58:28 +01:00
Luke
f5aad71c15 LibJS: Remove unused variable m_has_property_table in Shape 2020-11-07 10:09:55 +01:00