LibJS: Cache commonly used FlyStrings in the VM

Roughly 7% of test-js runtime was spent creating FlyStrings from string
literals. This patch frontloads that work and caches all the commonly
used names in LibJS on a CommonPropertyNames struct that hangs off VM.
This commit is contained in:
Andreas Kling 2020-10-13 23:49:19 +02:00
parent 9f6c5f68b6
commit 7b863330dc
Notes: sideshowbarker 2024-07-19 01:54:41 +09:00
45 changed files with 651 additions and 392 deletions

View file

@ -698,6 +698,7 @@ Value ClassMethod::execute(Interpreter& interpreter, GlobalObject& global_object
Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const
{
auto& vm = interpreter.vm();
Value class_constructor_value = m_constructor->execute(interpreter, global_object);
if (interpreter.exception())
return {};
@ -720,22 +721,22 @@ Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
Object* super_constructor_prototype = nullptr;
if (!super_constructor.is_null()) {
super_constructor_prototype = &super_constructor.as_object().get("prototype").as_object();
super_constructor_prototype = &super_constructor.as_object().get(vm.names.prototype).as_object();
if (interpreter.exception())
return {};
}
prototype->set_prototype(super_constructor_prototype);
prototype->define_property("constructor", class_constructor, 0);
prototype->define_property(vm.names.constructor, class_constructor, 0);
if (interpreter.exception())
return {};
class_constructor->define_property("prototype", prototype, 0);
class_constructor->define_property(vm.names.prototype, prototype, 0);
if (interpreter.exception())
return {};
class_constructor->set_prototype(super_constructor.is_null() ? global_object.function_prototype() : &super_constructor.as_object());
}
auto class_prototype = class_constructor->get("prototype");
auto class_prototype = class_constructor->get(vm.names.prototype);
if (interpreter.exception())
return {};
@ -1756,21 +1757,22 @@ void TaggedTemplateLiteral::dump(int indent) const
Value TaggedTemplateLiteral::execute(Interpreter& interpreter, GlobalObject& global_object) const
{
auto& vm = interpreter.vm();
auto tag = m_tag->execute(interpreter, global_object);
if (interpreter.exception())
if (vm.exception())
return {};
if (!tag.is_function()) {
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotAFunction, tag.to_string_without_side_effects());
vm.throw_exception<TypeError>(global_object, ErrorType::NotAFunction, tag.to_string_without_side_effects());
return {};
}
auto& tag_function = tag.as_function();
auto& expressions = m_template_literal->expressions();
auto* strings = Array::create(global_object);
MarkedValueList arguments(interpreter.heap());
MarkedValueList arguments(vm.heap());
arguments.append(strings);
for (size_t i = 0; i < expressions.size(); ++i) {
auto value = expressions[i].execute(interpreter, global_object);
if (interpreter.exception())
if (vm.exception())
return {};
// tag`${foo}` -> "", foo, "" -> tag(["", ""], foo)
// tag`foo${bar}baz${qux}` -> "foo", bar, "baz", qux, "" -> tag(["foo", "baz", ""], bar, qux)
@ -1784,12 +1786,12 @@ Value TaggedTemplateLiteral::execute(Interpreter& interpreter, GlobalObject& glo
auto* raw_strings = Array::create(global_object);
for (auto& raw_string : m_template_literal->raw_strings()) {
auto value = raw_string.execute(interpreter, global_object);
if (interpreter.exception())
if (vm.exception())
return {};
raw_strings->indexed_properties().append(value);
}
strings->define_property("raw", raw_strings, 0);
return interpreter.vm().call(tag_function, js_undefined(), move(arguments));
strings->define_property(vm.names.raw, raw_strings, 0);
return vm.call(tag_function, js_undefined(), move(arguments));
}
void TryStatement::dump(int indent) const

View file

@ -69,7 +69,8 @@ Value Interpreter::run(GlobalObject& global_object, const Program& program)
CallFrame global_call_frame;
global_call_frame.this_value = &global_object;
global_call_frame.function_name = "(global execution context)";
static FlyString global_execution_context_name = "(global execution context)";
global_call_frame.function_name = global_execution_context_name;
global_call_frame.environment = heap().allocate<LexicalEnvironment>(global_object, LexicalEnvironment::EnvironmentRecordType::Global);
global_call_frame.environment->bind_this_value(global_object, &global_object);
global_call_frame.is_strict_mode = program.is_strict_mode();

View file

@ -40,7 +40,8 @@ Array* Array::create(GlobalObject& global_object)
Array::Array(Object& prototype)
: Object(prototype)
{
define_native_property("length", length_getter, length_setter, Attribute::Writable);
auto& vm = this->vm();
define_native_property(vm.names.length, length_getter, length_setter, Attribute::Writable);
}
Array::~Array()

View file

@ -37,7 +37,7 @@
namespace JS {
ArrayConstructor::ArrayConstructor(GlobalObject& global_object)
: NativeFunction("Array", *global_object.function_prototype())
: NativeFunction(vm().names.Array, *global_object.function_prototype())
{
}
@ -47,15 +47,16 @@ ArrayConstructor::~ArrayConstructor()
void ArrayConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property("prototype", global_object.array_prototype(), 0);
define_property("length", Value(1), Attribute::Configurable);
define_property(vm.names.prototype, global_object.array_prototype(), 0);
define_property(vm.names.length, Value(1), Attribute::Configurable);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function("from", from, 1, attr);
define_native_function("isArray", is_array, 1, attr);
define_native_function("of", of, 0, attr);
define_native_function(vm.names.from, from, 1, attr);
define_native_function(vm.names.isArray, is_array, 1, attr);
define_native_function(vm.names.of, of, 0, attr);
}
Value ArrayConstructor::call()

View file

@ -40,9 +40,10 @@ ArrayIteratorPrototype::ArrayIteratorPrototype(GlobalObject& global_object)
void ArrayIteratorPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
define_native_function("next", next, 0, Attribute::Configurable | Attribute::Writable);
define_native_function(vm.names.next, next, 0, Attribute::Configurable | Attribute::Writable);
define_property(global_object.vm().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "Array Iterator"), Attribute::Configurable);
}

View file

@ -46,40 +46,41 @@ ArrayPrototype::ArrayPrototype(GlobalObject& global_object)
void ArrayPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function("filter", filter, 1, attr);
define_native_function("forEach", for_each, 1, attr);
define_native_function("map", map, 1, attr);
define_native_function("pop", pop, 0, attr);
define_native_function("push", push, 1, attr);
define_native_function("shift", shift, 0, attr);
define_native_function("toString", to_string, 0, attr);
define_native_function("toLocaleString", to_locale_string, 0, attr);
define_native_function("unshift", unshift, 1, attr);
define_native_function("join", join, 1, attr);
define_native_function("concat", concat, 1, attr);
define_native_function("slice", slice, 2, attr);
define_native_function("indexOf", index_of, 1, attr);
define_native_function("reduce", reduce, 1, attr);
define_native_function("reduceRight", reduce_right, 1, attr);
define_native_function("reverse", reverse, 0, attr);
define_native_function("lastIndexOf", last_index_of, 1, attr);
define_native_function("includes", includes, 1, attr);
define_native_function("find", find, 1, attr);
define_native_function("findIndex", find_index, 1, attr);
define_native_function("some", some, 1, attr);
define_native_function("every", every, 1, attr);
define_native_function("splice", splice, 2, attr);
define_native_function("fill", fill, 1, attr);
define_native_function("values", values, 0, attr);
define_property("length", Value(0), Attribute::Configurable);
define_native_function(vm.names.filter, filter, 1, attr);
define_native_function(vm.names.forEach, for_each, 1, attr);
define_native_function(vm.names.map, map, 1, attr);
define_native_function(vm.names.pop, pop, 0, attr);
define_native_function(vm.names.push, push, 1, attr);
define_native_function(vm.names.shift, shift, 0, attr);
define_native_function(vm.names.toString, to_string, 0, attr);
define_native_function(vm.names.toLocaleString, to_locale_string, 0, attr);
define_native_function(vm.names.unshift, unshift, 1, attr);
define_native_function(vm.names.join, join, 1, attr);
define_native_function(vm.names.concat, concat, 1, attr);
define_native_function(vm.names.slice, slice, 2, attr);
define_native_function(vm.names.indexOf, index_of, 1, attr);
define_native_function(vm.names.reduce, reduce, 1, attr);
define_native_function(vm.names.reduceRight, reduce_right, 1, attr);
define_native_function(vm.names.reverse, reverse, 0, attr);
define_native_function(vm.names.lastIndexOf, last_index_of, 1, attr);
define_native_function(vm.names.includes, includes, 1, attr);
define_native_function(vm.names.find, find, 1, attr);
define_native_function(vm.names.findIndex, find_index, 1, attr);
define_native_function(vm.names.some, some, 1, attr);
define_native_function(vm.names.every, every, 1, attr);
define_native_function(vm.names.splice, splice, 2, attr);
define_native_function(vm.names.fill, fill, 1, attr);
define_native_function(vm.names.values, values, 0, attr);
define_property(vm.names.length, Value(0), Attribute::Configurable);
// Use define_property here instead of define_native_function so that
// Object.is(Array.prototype[Symbol.iterator], Array.prototype.values)
// evaluates to true
define_property(global_object.vm().well_known_symbol_iterator(), get("values"), attr);
define_property(vm.well_known_symbol_iterator(), get(vm.names.values), attr);
}
ArrayPrototype::~ArrayPrototype()
@ -103,7 +104,7 @@ static Function* callback_from_args(GlobalObject& global_object, const String& n
static size_t get_length(VM& vm, Object& object)
{
auto length_property = object.get("length");
auto length_property = object.get(vm.names.length);
if (vm.exception())
return 0;
return length_property.to_size_t(object.global_object());
@ -208,7 +209,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::push)
return {};
}
auto new_length_value = Value((i32)new_length);
this_object->put("length", new_length_value);
this_object->put(vm.names.length, new_length_value);
if (vm.exception())
return {};
return new_length_value;
@ -237,7 +238,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::pop)
}
auto length = get_length(vm, *this_object);
if (length == 0) {
this_object->put("length", Value(0));
this_object->put(vm.names.length, Value(0));
return js_undefined();
}
auto index = length - 1;
@ -247,7 +248,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::pop)
this_object->delete_property(index);
if (vm.exception())
return {};
this_object->put("length", Value((i32)index));
this_object->put(vm.names.length, Value((i32)index));
if (vm.exception())
return {};
return element;
@ -271,7 +272,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::to_string)
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
auto join_function = this_object->get("join");
auto join_function = this_object->get(vm.names.join);
if (vm.exception())
return {};
if (!join_function.is_function())
@ -789,7 +790,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::splice)
return {};
}
this_object->put("length", Value((i32)new_length));
this_object->put(vm.names.length, Value((i32)new_length));
if (vm.exception())
return {};

View file

@ -35,19 +35,20 @@
namespace JS {
BigIntConstructor::BigIntConstructor(GlobalObject& global_object)
: NativeFunction("BigInt", *global_object.function_prototype())
: NativeFunction(vm().names.BigInt, *global_object.function_prototype())
{
}
void BigIntConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property("prototype", global_object.bigint_prototype(), 0);
define_property("length", Value(1), Attribute::Configurable);
define_property(vm.names.prototype, global_object.bigint_prototype(), 0);
define_property(vm.names.length, Value(1), Attribute::Configurable);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function("asIntN", as_int_n, 2, attr);
define_native_function("asUintN", as_uint_n, 2, attr);
define_native_function(vm.names.asIntN, as_int_n, 2, attr);
define_native_function(vm.names.asUintN, as_uint_n, 2, attr);
}
BigIntConstructor::~BigIntConstructor()

View file

@ -39,13 +39,14 @@ BigIntPrototype::BigIntPrototype(GlobalObject& global_object)
void BigIntPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function("toString", to_string, 0, attr);
define_native_function("toLocaleString", to_locale_string, 0, attr);
define_native_function("valueOf", value_of, 0, attr);
define_native_function(vm.names.toString, to_string, 0, attr);
define_native_function(vm.names.toLocaleString, to_locale_string, 0, attr);
define_native_function(vm.names.valueOf, value_of, 0, attr);
define_property(global_object.vm().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "BigInt"), Attribute::Configurable);
define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), "BigInt"), Attribute::Configurable);
}
BigIntPrototype::~BigIntPrototype()

View file

@ -33,15 +33,16 @@
namespace JS {
BooleanConstructor::BooleanConstructor(GlobalObject& global_object)
: NativeFunction("Boolean", *global_object.function_prototype())
: NativeFunction(vm().names.Boolean, *global_object.function_prototype())
{
}
void BooleanConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property("prototype", Value(global_object.boolean_prototype()), 0);
define_property("length", Value(1), Attribute::Configurable);
define_property(vm.names.prototype, Value(global_object.boolean_prototype()), 0);
define_property(vm.names.length, Value(1), Attribute::Configurable);
}
BooleanConstructor::~BooleanConstructor()

View file

@ -38,9 +38,10 @@ BooleanPrototype::BooleanPrototype(GlobalObject& global_object)
void BooleanPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
BooleanObject::initialize(global_object);
define_native_function("toString", to_string, 0, Attribute::Writable | Attribute::Configurable);
define_native_function("valueOf", value_of, 0, Attribute::Writable | Attribute::Configurable);
define_native_function(vm.names.toString, to_string, 0, Attribute::Writable | Attribute::Configurable);
define_native_function(vm.names.valueOf, value_of, 0, Attribute::Writable | Attribute::Configurable);
}
BooleanPrototype::~BooleanPrototype()

View file

@ -40,8 +40,9 @@ BoundFunction::BoundFunction(GlobalObject& global_object, Function& target_funct
void BoundFunction::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Function::initialize(global_object);
define_property("length", Value(m_length), Attribute::Configurable);
define_property(vm.names.length, Value(m_length), Attribute::Configurable);
}
BoundFunction::~BoundFunction()

View file

@ -0,0 +1,209 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <AK/FlyString.h>
#include <LibJS/Forward.h>
namespace JS {
#define ENUMERATE_STANDARD_PROPERTY_NAMES(P) \
P(BigInt) \
P(Boolean) \
P(E) \
P(EPSILON) \
P(Infinity) \
P(JSON) \
P(LN10) \
P(LN2) \
P(LOG10E) \
P(LOG2E) \
P(MAX_SAFE_INTEGER) \
P(MIN_SAFE_INTEGER) \
P(Math) \
P(NEGATIVE_INFINITY) \
P(NaN) \
P(Number) \
P(PI) \
P(POSITIVE_INFINITY) \
P(Proxy) \
P(Reflect) \
P(RegExp) \
P(SQRT1_2) \
P(SQRT2) \
P(String) \
P(Symbol) \
P(UTC) \
P(abs) \
P(acosh) \
P(apply) \
P(asIntN) \
P(asUintN) \
P(asinh) \
P(atanh) \
P(bind) \
P(call) \
P(cbrt) \
P(ceil) \
P(charAt) \
P(charCodeAt) \
P(clz32) \
P(concat) \
P(console) \
P(construct) \
P(constructor) \
P(cos) \
P(defineProperty) \
P(deleteProperty) \
P(description) \
P(done) \
P(entries) \
P(every) \
P(exp) \
P(expm1) \
P(fill) \
P(filter) \
P(find) \
P(findIndex) \
P(floor) \
P(forEach) \
P(from) \
P(fromCharCode) \
P(gc) \
P(get) \
P(getDate) \
P(getDay) \
P(getFullYear) \
P(getHours) \
P(getMilliseconds) \
P(getMinutes) \
P(getMonth) \
P(getOwnPropertyDescriptor) \
P(getOwnPropertyNames) \
P(getPrototypeOf) \
P(getSeconds) \
P(getTime) \
P(getUTCDate) \
P(getUTCDay) \
P(getUTCFullYear) \
P(getUTCHours) \
P(getUTCMilliseconds) \
P(getUTCMinutes) \
P(getUTCMonth) \
P(getUTCSeconds) \
P(globalThis) \
P(has) \
P(hasOwnProperty) \
P(includes) \
P(indexOf) \
P(is) \
P(isArray) \
P(isExtensible) \
P(isFinite) \
P(isInteger) \
P(isNaN) \
P(isSafeInteger) \
P(join) \
P(keyFor) \
P(keys) \
P(lastIndexOf) \
P(length) \
P(log1p) \
P(map) \
P(max) \
P(message) \
P(min) \
P(name) \
P(now) \
P(of) \
P(ownKeys) \
P(padEnd) \
P(padStart) \
P(parse) \
P(parseFloat) \
P(pop) \
P(pow) \
P(preventExtensions) \
P(prototype) \
P(push) \
P(random) \
P(raw) \
P(reduce) \
P(reduceRight) \
P(repeat) \
P(reverse) \
P(round) \
P(set) \
P(setPrototypeOf) \
P(shift) \
P(sign) \
P(sin) \
P(slice) \
P(some) \
P(splice) \
P(sqrt) \
P(startsWith) \
P(substring) \
P(tan) \
P(toDateString) \
P(toISOString) \
P(toJSON) \
P(toLocaleDateString) \
P(toLocaleString) \
P(toLocaleTimeString) \
P(toLowerCase) \
P(toString) \
P(toTimeString) \
P(toUpperCase) \
P(trim) \
P(trimEnd) \
P(trimStart) \
P(trunc) \
P(undefined) \
P(unshift) \
P(value) \
P(valueOf) \
P(enumerable) \
P(configurable) \
P(writable) \
P(next) \
P(values)
struct CommonPropertyNames {
FlyString for_ { "for" };
#define __ENUMERATE(x) FlyString x { #x };
ENUMERATE_STANDARD_PROPERTY_NAMES(__ENUMERATE)
#undef __ENUMERATE
#define __JS_ENUMERATE(x, a, b, c) FlyString x { #x };
JS_ENUMERATE_BUILTIN_TYPES
#undef __JS_ENUMERATE
#define __JS_ENUMERATE(x, a) FlyString x { #x };
JS_ENUMERATE_WELL_KNOWN_SYMBOLS
#undef __JS_ENUMERATE
};
}

View file

@ -138,19 +138,20 @@ static Value parse_simplified_iso8601(const String& iso_8601)
}
DateConstructor::DateConstructor(GlobalObject& global_object)
: NativeFunction("Date", *global_object.function_prototype())
: NativeFunction(vm().names.Date, *global_object.function_prototype())
{
}
void DateConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property("prototype", global_object.date_prototype(), 0);
define_property("length", Value(7), Attribute::Configurable);
define_property(vm.names.prototype, global_object.date_prototype(), 0);
define_property(vm.names.length, Value(7), Attribute::Configurable);
define_native_function("now", now, 0, Attribute::Writable | Attribute::Configurable);
define_native_function("parse", parse, 1, Attribute::Writable | Attribute::Configurable);
define_native_function("UTC", utc, 1, Attribute::Writable | Attribute::Configurable);
define_native_function(vm.names.now, now, 0, Attribute::Writable | Attribute::Configurable);
define_native_function(vm.names.parse, parse, 1, Attribute::Writable | Attribute::Configurable);
define_native_function(vm.names.UTC, utc, 1, Attribute::Writable | Attribute::Configurable);
}
DateConstructor::~DateConstructor()

View file

@ -54,35 +54,36 @@ DatePrototype::DatePrototype(GlobalObject& global_object)
void DatePrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function("getDate", get_date, 0, attr);
define_native_function("getDay", get_day, 0, attr);
define_native_function("getFullYear", get_full_year, 0, attr);
define_native_function("getHours", get_hours, 0, attr);
define_native_function("getMilliseconds", get_milliseconds, 0, attr);
define_native_function("getMinutes", get_minutes, 0, attr);
define_native_function("getMonth", get_month, 0, attr);
define_native_function("getSeconds", get_seconds, 0, attr);
define_native_function("getTime", get_time, 0, attr);
define_native_function("getUTCDate", get_utc_date, 0, attr);
define_native_function("getUTCDay", get_utc_day, 0, attr);
define_native_function("getUTCFullYear", get_utc_full_year, 0, attr);
define_native_function("getUTCHours", get_utc_hours, 0, attr);
define_native_function("getUTCMilliseconds", get_utc_milliseconds, 0, attr);
define_native_function("getUTCMinutes", get_utc_minutes, 0, attr);
define_native_function("getUTCMonth", get_utc_month, 0, attr);
define_native_function("getUTCSeconds", get_utc_seconds, 0, attr);
define_native_function("toDateString", to_date_string, 0, attr);
define_native_function("toISOString", to_iso_string, 0, attr);
define_native_function("toLocaleDateString", to_locale_date_string, 0, attr);
define_native_function("toLocaleString", to_locale_string, 0, attr);
define_native_function("toLocaleTimeString", to_locale_time_string, 0, attr);
define_native_function("toTimeString", to_time_string, 0, attr);
define_native_function("toString", to_string, 0, attr);
define_native_function(vm.names.getDate, get_date, 0, attr);
define_native_function(vm.names.getDay, get_day, 0, attr);
define_native_function(vm.names.getFullYear, get_full_year, 0, attr);
define_native_function(vm.names.getHours, get_hours, 0, attr);
define_native_function(vm.names.getMilliseconds, get_milliseconds, 0, attr);
define_native_function(vm.names.getMinutes, get_minutes, 0, attr);
define_native_function(vm.names.getMonth, get_month, 0, attr);
define_native_function(vm.names.getSeconds, get_seconds, 0, attr);
define_native_function(vm.names.getTime, get_time, 0, attr);
define_native_function(vm.names.getUTCDate, get_utc_date, 0, attr);
define_native_function(vm.names.getUTCDay, get_utc_day, 0, attr);
define_native_function(vm.names.getUTCFullYear, get_utc_full_year, 0, attr);
define_native_function(vm.names.getUTCHours, get_utc_hours, 0, attr);
define_native_function(vm.names.getUTCMilliseconds, get_utc_milliseconds, 0, attr);
define_native_function(vm.names.getUTCMinutes, get_utc_minutes, 0, attr);
define_native_function(vm.names.getUTCMonth, get_utc_month, 0, attr);
define_native_function(vm.names.getUTCSeconds, get_utc_seconds, 0, attr);
define_native_function(vm.names.toDateString, to_date_string, 0, attr);
define_native_function(vm.names.toISOString, to_iso_string, 0, attr);
define_native_function(vm.names.toLocaleDateString, to_locale_date_string, 0, attr);
define_native_function(vm.names.toLocaleString, to_locale_string, 0, attr);
define_native_function(vm.names.toLocaleTimeString, to_locale_time_string, 0, attr);
define_native_function(vm.names.toTimeString, to_time_string, 0, attr);
define_native_function(vm.names.toString, to_string, 0, attr);
// Aliases.
define_native_function("valueOf", get_time, 0, attr);
define_native_function(vm.names.valueOf, get_time, 0, attr);
// toJSON() isn't quite an alias for toISOString():
// - it returns null instead of throwing RangeError
// - its .length is 1, not 0

View file

@ -51,7 +51,7 @@ Error::~Error()
return global_object.heap().allocate<ClassName>(global_object, message, *global_object.snake_name##_prototype()); \
} \
ClassName::ClassName(const String& message, Object& prototype) \
: Error(#ClassName, message, prototype) \
: Error(vm().names.ClassName, message, prototype) \
{ \
} \
ClassName::~ClassName() { }

View file

@ -31,15 +31,16 @@
namespace JS {
ErrorConstructor::ErrorConstructor(GlobalObject& global_object)
: NativeFunction("Error", *global_object.function_prototype())
: NativeFunction(vm().names.Error, *global_object.function_prototype())
{
}
void ErrorConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property("prototype", global_object.error_prototype(), 0);
define_property("length", Value(1), Attribute::Configurable);
define_property(vm.names.prototype, global_object.error_prototype(), 0);
define_property(vm.names.length, Value(1), Attribute::Configurable);
}
ErrorConstructor::~ErrorConstructor()
@ -60,7 +61,7 @@ Value ErrorConstructor::construct(Function&)
if (vm.exception())
return {};
}
return Error::create(global_object(), "Error", message);
return Error::create(global_object(), vm.names.Error, message);
}
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
@ -70,9 +71,10 @@ Value ErrorConstructor::construct(Function&)
} \
void ConstructorName::initialize(GlobalObject& global_object) \
{ \
auto& vm = this->vm(); \
NativeFunction::initialize(global_object); \
define_property("prototype", global_object.snake_name##_prototype(), 0); \
define_property("length", Value(1), Attribute::Configurable); \
define_property(vm.names.prototype, global_object.snake_name##_prototype(), 0); \
define_property(vm.names.length, Value(1), Attribute::Configurable); \
} \
ConstructorName::~ConstructorName() { } \
Value ConstructorName::call() \

View file

@ -41,11 +41,12 @@ ErrorPrototype::ErrorPrototype(GlobalObject& global_object)
void ErrorPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_property("name", name_getter, name_setter, attr);
define_native_property("message", message_getter, nullptr, attr);
define_native_function("toString", to_string, 0, attr);
define_native_property(vm.names.name, name_getter, name_setter, attr);
define_native_property(vm.names.message, message_getter, nullptr, attr);
define_native_function(vm.names.toString, to_string, 0, attr);
}
ErrorPrototype::~ErrorPrototype()
@ -100,7 +101,7 @@ JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::to_string)
auto& this_object = vm.this_value(global_object).as_object();
String name = "Error";
auto name_property = this_object.get("name");
auto name_property = this_object.get(vm.names.name);
if (vm.exception())
return {};
if (!name_property.is_empty() && !name_property.is_undefined()) {
@ -110,7 +111,7 @@ JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::to_string)
}
String message = "";
auto message_property = this_object.get("message");
auto message_property = this_object.get(vm.names.message);
if (vm.exception())
return {};
if (!message_property.is_empty() && !message_property.is_undefined()) {

View file

@ -35,7 +35,7 @@ Exception::Exception(Value value)
{
auto& call_stack = vm().call_stack();
for (ssize_t i = call_stack.size() - 1; i >= 0; --i) {
auto function_name = call_stack[i].function_name;
String function_name = call_stack[i].function_name;
if (function_name.is_empty())
function_name = "<anonymous>";
m_trace.append(function_name);

View file

@ -49,15 +49,16 @@ Function::~Function()
BoundFunction* Function::bind(Value bound_this_value, Vector<Value> arguments)
{
auto& vm = this->vm();
Function& target_function = is_bound_function() ? static_cast<BoundFunction&>(*this).target_function() : *this;
auto bound_this_object = [bound_this_value, this]() -> Value {
auto bound_this_object = [&vm, bound_this_value, this]() -> Value {
if (!m_bound_this.is_empty())
return m_bound_this;
switch (bound_this_value.type()) {
case Value::Type::Undefined:
case Value::Type::Null:
if (vm().in_strict_mode())
if (vm.in_strict_mode())
return bound_this_value;
return &global_object();
default:
@ -66,15 +67,15 @@ BoundFunction* Function::bind(Value bound_this_value, Vector<Value> arguments)
}();
i32 computed_length = 0;
auto length_property = get("length");
if (vm().exception())
auto length_property = get(vm.names.length);
if (vm.exception())
return nullptr;
if (length_property.is_number())
computed_length = max(0, length_property.as_i32() - static_cast<i32>(arguments.size()));
Object* constructor_prototype = nullptr;
auto prototype_property = target_function.get("prototype");
if (vm().exception())
auto prototype_property = target_function.get(vm.names.prototype);
if (vm.exception())
return nullptr;
if (prototype_property.is_object())
constructor_prototype = &prototype_property.as_object();

View file

@ -36,15 +36,16 @@
namespace JS {
FunctionConstructor::FunctionConstructor(GlobalObject& global_object)
: NativeFunction("Function", *global_object.function_prototype())
: NativeFunction(vm().names.Function, *global_object.function_prototype())
{
}
void FunctionConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property("prototype", global_object.function_prototype(), 0);
define_property("length", Value(1), Attribute::Configurable);
define_property(vm.names.prototype, global_object.function_prototype(), 0);
define_property(vm.names.length, Value(1), Attribute::Configurable);
}
FunctionConstructor::~FunctionConstructor()

View file

@ -45,15 +45,16 @@ FunctionPrototype::FunctionPrototype(GlobalObject& global_object)
void FunctionPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function("apply", apply, 2, attr);
define_native_function("bind", bind, 1, attr);
define_native_function("call", call, 1, attr);
define_native_function("toString", to_string, 0, attr);
define_native_function(global_object.vm().well_known_symbol_has_instance(), symbol_has_instance, 1, 0);
define_property("length", Value(0), Attribute::Configurable);
define_property("name", js_string(heap(), ""), Attribute::Configurable);
define_native_function(vm.names.apply, apply, 2, attr);
define_native_function(vm.names.bind, bind, 1, attr);
define_native_function(vm.names.call, call, 1, attr);
define_native_function(vm.names.toString, to_string, 0, attr);
define_native_function(vm.well_known_symbol_has_instance(), symbol_has_instance, 1, 0);
define_property(vm.names.length, Value(0), Attribute::Configurable);
define_property(vm.names.name, js_string(heap(), ""), Attribute::Configurable);
}
FunctionPrototype::~FunctionPrototype()
@ -78,7 +79,7 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::apply)
vm.throw_exception<TypeError>(global_object, ErrorType::FunctionArgsNotObject);
return {};
}
auto length_property = arg_array.as_object().get("length");
auto length_property = arg_array.as_object().get(vm.names.length);
if (vm.exception())
return {};
auto length = length_property.to_size_t(global_object);

View file

@ -75,6 +75,8 @@ GlobalObject::GlobalObject()
void GlobalObject::initialize()
{
auto& vm = this->vm();
ensure_shape_is_unique();
// These are done first since other prototypes depend on their presence.
@ -98,36 +100,36 @@ void GlobalObject::initialize()
#undef __JS_ENUMERATE
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function("gc", gc, 0, attr);
define_native_function("isNaN", is_nan, 1, attr);
define_native_function("isFinite", is_finite, 1, attr);
define_native_function("parseFloat", parse_float, 1, attr);
define_native_function(vm.names.gc, gc, 0, attr);
define_native_function(vm.names.isNaN, is_nan, 1, attr);
define_native_function(vm.names.isFinite, is_finite, 1, attr);
define_native_function(vm.names.parseFloat, parse_float, 1, attr);
define_property("NaN", js_nan(), 0);
define_property("Infinity", js_infinity(), 0);
define_property("undefined", js_undefined(), 0);
define_property(vm.names.NaN, js_nan(), 0);
define_property(vm.names.Infinity, js_infinity(), 0);
define_property(vm.names.undefined, js_undefined(), 0);
define_property("globalThis", this, attr);
define_property("console", heap().allocate<ConsoleObject>(*this, *this), attr);
define_property("Math", heap().allocate<MathObject>(*this, *this), attr);
define_property("JSON", heap().allocate<JSONObject>(*this, *this), attr);
define_property("Reflect", heap().allocate<ReflectObject>(*this, *this), attr);
define_property(vm.names.globalThis, this, attr);
define_property(vm.names.console, heap().allocate<ConsoleObject>(*this, *this), attr);
define_property(vm.names.Math, heap().allocate<MathObject>(*this, *this), attr);
define_property(vm.names.JSON, heap().allocate<JSONObject>(*this, *this), attr);
define_property(vm.names.Reflect, heap().allocate<ReflectObject>(*this, *this), attr);
add_constructor("Array", m_array_constructor, *m_array_prototype);
add_constructor("BigInt", m_bigint_constructor, *m_bigint_prototype);
add_constructor("Boolean", m_boolean_constructor, *m_boolean_prototype);
add_constructor("Date", m_date_constructor, *m_date_prototype);
add_constructor("Error", m_error_constructor, *m_error_prototype);
add_constructor("Function", m_function_constructor, *m_function_prototype);
add_constructor("Number", m_number_constructor, *m_number_prototype);
add_constructor("Object", m_object_constructor, *m_object_prototype);
add_constructor("Proxy", m_proxy_constructor, *m_proxy_prototype);
add_constructor("RegExp", m_regexp_constructor, *m_regexp_prototype);
add_constructor("String", m_string_constructor, *m_string_prototype);
add_constructor("Symbol", m_symbol_constructor, *m_symbol_prototype);
add_constructor(vm.names.Array, m_array_constructor, *m_array_prototype);
add_constructor(vm.names.BigInt, m_bigint_constructor, *m_bigint_prototype);
add_constructor(vm.names.Boolean, m_boolean_constructor, *m_boolean_prototype);
add_constructor(vm.names.Date, m_date_constructor, *m_date_prototype);
add_constructor(vm.names.Error, m_error_constructor, *m_error_prototype);
add_constructor(vm.names.Function, m_function_constructor, *m_function_prototype);
add_constructor(vm.names.Number, m_number_constructor, *m_number_prototype);
add_constructor(vm.names.Object, m_object_constructor, *m_object_prototype);
add_constructor(vm.names.Proxy, m_proxy_constructor, *m_proxy_prototype);
add_constructor(vm.names.RegExp, m_regexp_constructor, *m_regexp_prototype);
add_constructor(vm.names.String, m_string_constructor, *m_string_prototype);
add_constructor(vm.names.Symbol, m_symbol_constructor, *m_symbol_prototype);
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
add_constructor(#ClassName, m_##snake_name##_constructor, *m_##snake_name##_prototype);
add_constructor(vm.names.ClassName, m_##snake_name##_constructor, *m_##snake_name##_prototype);
JS_ENUMERATE_ERROR_SUBCLASSES
#undef __JS_ENUMERATE
}

View file

@ -87,12 +87,13 @@ private:
template<typename ConstructorType>
inline void GlobalObject::add_constructor(const FlyString& property_name, ConstructorType*& constructor, Object& prototype)
{
auto& vm = this->vm();
constructor = heap().allocate<ConstructorType>(*this, *this);
constructor->define_property("name", js_string(heap(), property_name), Attribute::Configurable);
if (vm().exception())
constructor->define_property(vm.names.name, js_string(heap(), property_name), Attribute::Configurable);
if (vm.exception())
return;
prototype.define_property("constructor", constructor, Attribute::Writable | Attribute::Configurable);
if (vm().exception())
prototype.define_property(vm.names.constructor, constructor, Attribute::Writable | Attribute::Configurable);
if (vm.exception())
return;
define_property(property_name, constructor, Attribute::Writable | Attribute::Configurable);
}

View file

@ -62,7 +62,7 @@ Object* iterator_next(Object& iterator, Value value)
{
auto& vm = iterator.vm();
auto& global_object = iterator.global_object();
auto next_method = iterator.get("next");
auto next_method = iterator.get(vm.names.next);
if (vm.exception())
return {};
@ -95,9 +95,10 @@ void iterator_close(Object& iterator)
Value create_iterator_result_object(GlobalObject& global_object, Value value, bool done)
{
auto& vm = global_object.vm();
auto* object = Object::create_empty(global_object);
object->define_property("value", value);
object->define_property("done", Value(done));
object->define_property(vm.names.value, value);
object->define_property(vm.names.done, Value(done));
return object;
}
@ -114,14 +115,14 @@ void get_iterator_values(GlobalObject& global_object, Value value, AK::Function<
if (!next_object)
return;
auto done_property = next_object->get("done");
auto done_property = next_object->get(vm.names.done);
if (vm.exception())
return;
if (!done_property.is_empty() && done_property.to_boolean())
return;
auto next_value = next_object->get("value");
auto next_value = next_object->get(vm.names.value);
if (vm.exception())
return;

View file

@ -154,7 +154,7 @@ String JSONObject::serialize_json_property(GlobalObject& global_object, Stringif
if (vm.exception())
return {};
if (value.is_object()) {
auto to_json = value.as_object().get("toJSON");
auto to_json = value.as_object().get(vm.names.toJSON);
if (vm.exception())
return {};
if (to_json.is_function()) {

View file

@ -40,41 +40,42 @@ MathObject::MathObject(GlobalObject& global_object)
void MathObject::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function("abs", abs, 1, attr);
define_native_function("random", random, 0, attr);
define_native_function("sqrt", sqrt, 1, attr);
define_native_function("floor", floor, 1, attr);
define_native_function("ceil", ceil, 1, attr);
define_native_function("round", round, 1, attr);
define_native_function("max", max, 2, attr);
define_native_function("min", min, 2, attr);
define_native_function("trunc", trunc, 1, attr);
define_native_function("sin", sin, 1, attr);
define_native_function("cos", cos, 1, attr);
define_native_function("tan", tan, 1, attr);
define_native_function("pow", pow, 2, attr);
define_native_function("exp", exp, 1, attr);
define_native_function("expm1", expm1, 1, attr);
define_native_function("sign", sign, 1, attr);
define_native_function("clz32", clz32, 1, attr);
define_native_function("acosh", acosh, 1, attr);
define_native_function("asinh", asinh, 1, attr);
define_native_function("atanh", atanh, 1, attr);
define_native_function("log1p", log1p, 1, attr);
define_native_function("cbrt", cbrt, 1, attr);
define_native_function(vm.names.abs, abs, 1, attr);
define_native_function(vm.names.random, random, 0, attr);
define_native_function(vm.names.sqrt, sqrt, 1, attr);
define_native_function(vm.names.floor, floor, 1, attr);
define_native_function(vm.names.ceil, ceil, 1, attr);
define_native_function(vm.names.round, round, 1, attr);
define_native_function(vm.names.max, max, 2, attr);
define_native_function(vm.names.min, min, 2, attr);
define_native_function(vm.names.trunc, trunc, 1, attr);
define_native_function(vm.names.sin, sin, 1, attr);
define_native_function(vm.names.cos, cos, 1, attr);
define_native_function(vm.names.tan, tan, 1, attr);
define_native_function(vm.names.pow, pow, 2, attr);
define_native_function(vm.names.exp, exp, 1, attr);
define_native_function(vm.names.expm1, expm1, 1, attr);
define_native_function(vm.names.sign, sign, 1, attr);
define_native_function(vm.names.clz32, clz32, 1, attr);
define_native_function(vm.names.acosh, acosh, 1, attr);
define_native_function(vm.names.asinh, asinh, 1, attr);
define_native_function(vm.names.atanh, atanh, 1, attr);
define_native_function(vm.names.log1p, log1p, 1, attr);
define_native_function(vm.names.cbrt, cbrt, 1, attr);
define_property("E", Value(M_E), 0);
define_property("LN2", Value(M_LN2), 0);
define_property("LN10", Value(M_LN10), 0);
define_property("LOG2E", Value(log2(M_E)), 0);
define_property("LOG10E", Value(log10(M_E)), 0);
define_property("PI", Value(M_PI), 0);
define_property("SQRT1_2", Value(M_SQRT1_2), 0);
define_property("SQRT2", Value(M_SQRT2), 0);
define_property(vm.names.E, Value(M_E), 0);
define_property(vm.names.LN2, Value(M_LN2), 0);
define_property(vm.names.LN10, Value(M_LN10), 0);
define_property(vm.names.LOG2E, Value(log2(M_E)), 0);
define_property(vm.names.LOG10E, Value(log10(M_E)), 0);
define_property(vm.names.PI, Value(M_PI), 0);
define_property(vm.names.SQRT1_2, Value(M_SQRT1_2), 0);
define_property(vm.names.SQRT2, Value(M_SQRT2), 0);
define_property(global_object.vm().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "Math"), Attribute::Configurable);
define_property(vm.well_known_symbol_to_string_tag(), js_string(vm.heap(), "Math"), Attribute::Configurable);
}
MathObject::~MathObject()

View file

@ -30,34 +30,36 @@
#include <LibJS/Runtime/NumberObject.h>
#include <math.h>
#define EPSILON pow(2, -52)
#define MAX_SAFE_INTEGER pow(2, 53) - 1
#define MIN_SAFE_INTEGER -(pow(2, 53) - 1)
// FIXME: constexpr these?
#define EPSILON_VALUE pow(2, -52)
#define MAX_SAFE_INTEGER_VALUE pow(2, 53) - 1
#define MIN_SAFE_INTEGER_VALUE -(pow(2, 53) - 1)
namespace JS {
NumberConstructor::NumberConstructor(GlobalObject& global_object)
: NativeFunction("Number", *global_object.function_prototype())
: NativeFunction(vm().names.Number, *global_object.function_prototype())
{
}
void NumberConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function("isFinite", is_finite, 1, attr);
define_native_function("isInteger", is_integer, 1, attr);
define_native_function("isNaN", is_nan, 1, attr);
define_native_function("isSafeInteger", is_safe_integer, 1, attr);
define_property("parseFloat", global_object.get("parseFloat"));
define_property("prototype", global_object.number_prototype(), 0);
define_property("length", Value(1), Attribute::Configurable);
define_property("EPSILON", Value(EPSILON), 0);
define_property("MAX_SAFE_INTEGER", Value(MAX_SAFE_INTEGER), 0);
define_property("MIN_SAFE_INTEGER", Value(MIN_SAFE_INTEGER), 0);
define_property("NEGATIVE_INFINITY", js_negative_infinity(), 0);
define_property("POSITIVE_INFINITY", js_infinity(), 0);
define_property("NaN", js_nan(), 0);
define_native_function(vm.names.isFinite, is_finite, 1, attr);
define_native_function(vm.names.isInteger, is_integer, 1, attr);
define_native_function(vm.names.isNaN, is_nan, 1, attr);
define_native_function(vm.names.isSafeInteger, is_safe_integer, 1, attr);
define_property(vm.names.parseFloat, global_object.get(vm.names.parseFloat));
define_property(vm.names.prototype, global_object.number_prototype(), 0);
define_property(vm.names.length, Value(1), Attribute::Configurable);
define_property(vm.names.EPSILON, Value(EPSILON_VALUE), 0);
define_property(vm.names.MAX_SAFE_INTEGER, Value(MAX_SAFE_INTEGER_VALUE), 0);
define_property(vm.names.MIN_SAFE_INTEGER, Value(MIN_SAFE_INTEGER_VALUE), 0);
define_property(vm.names.NEGATIVE_INFINITY, js_negative_infinity(), 0);
define_property(vm.names.POSITIVE_INFINITY, js_infinity(), 0);
define_property(vm.names.NaN, js_nan(), 0);
}
NumberConstructor::~NumberConstructor()
@ -102,7 +104,7 @@ JS_DEFINE_NATIVE_FUNCTION(NumberConstructor::is_safe_integer)
if (!vm.argument(0).is_number())
return Value(false);
auto value = vm.argument(0).as_double();
return Value((int64_t)value == value && value >= MIN_SAFE_INTEGER && value <= MAX_SAFE_INTEGER);
return Value((int64_t)value == value && value >= MIN_SAFE_INTEGER_VALUE && value <= MAX_SAFE_INTEGER_VALUE);
}
}

View file

@ -44,36 +44,36 @@ namespace JS {
PropertyDescriptor PropertyDescriptor::from_dictionary(VM& vm, const Object& object)
{
PropertyAttributes attributes;
if (object.has_property("configurable")) {
if (object.has_property(vm.names.configurable)) {
attributes.set_has_configurable();
if (object.get("configurable").value_or(Value(false)).to_boolean())
if (object.get(vm.names.configurable).value_or(Value(false)).to_boolean())
attributes.set_configurable();
if (vm.exception())
return {};
}
if (object.has_property("enumerable")) {
if (object.has_property(vm.names.enumerable)) {
attributes.set_has_enumerable();
if (object.get("enumerable").value_or(Value(false)).to_boolean())
if (object.get(vm.names.enumerable).value_or(Value(false)).to_boolean())
attributes.set_enumerable();
if (vm.exception())
return {};
}
if (object.has_property("writable")) {
if (object.has_property(vm.names.writable)) {
attributes.set_has_writable();
if (object.get("writable").value_or(Value(false)).to_boolean())
if (object.get(vm.names.writable).value_or(Value(false)).to_boolean())
attributes.set_writable();
if (vm.exception())
return {};
}
PropertyDescriptor descriptor { attributes, object.get("value"), nullptr, nullptr };
PropertyDescriptor descriptor { attributes, object.get(vm.names.value), nullptr, nullptr };
if (vm.exception())
return {};
auto getter = object.get("get");
auto getter = object.get(vm.names.get);
if (vm.exception())
return {};
if (getter.is_function())
descriptor.getter = &getter.as_function();
auto setter = object.get("set");
auto setter = object.get(vm.names.set);
if (vm.exception())
return {};
if (setter.is_function())
@ -295,34 +295,35 @@ Optional<PropertyDescriptor> Object::get_own_property_descriptor(const PropertyN
Value Object::get_own_property_descriptor_object(const PropertyName& property_name) const
{
auto& vm = this->vm();
auto descriptor_opt = get_own_property_descriptor(property_name);
if (!descriptor_opt.has_value())
return js_undefined();
auto descriptor = descriptor_opt.value();
auto* descriptor_object = Object::create_empty(global_object());
descriptor_object->define_property("enumerable", Value(descriptor.attributes.is_enumerable()));
if (vm().exception())
descriptor_object->define_property(vm.names.enumerable, Value(descriptor.attributes.is_enumerable()));
if (vm.exception())
return {};
descriptor_object->define_property("configurable", Value(descriptor.attributes.is_configurable()));
if (vm().exception())
descriptor_object->define_property(vm.names.configurable, Value(descriptor.attributes.is_configurable()));
if (vm.exception())
return {};
if (descriptor.is_data_descriptor()) {
descriptor_object->define_property("value", descriptor.value.value_or(js_undefined()));
if (vm().exception())
descriptor_object->define_property(vm.names.value, descriptor.value.value_or(js_undefined()));
if (vm.exception())
return {};
descriptor_object->define_property("writable", Value(descriptor.attributes.is_writable()));
if (vm().exception())
descriptor_object->define_property(vm.names.writable, Value(descriptor.attributes.is_writable()));
if (vm.exception())
return {};
} else if (descriptor.is_accessor_descriptor()) {
if (descriptor.getter) {
descriptor_object->define_property("get", Value(descriptor.getter));
if (vm().exception())
descriptor_object->define_property(vm.names.get, Value(descriptor.getter));
if (vm.exception())
return {};
}
if (descriptor.setter) {
descriptor_object->define_property("set", Value(descriptor.setter));
if (vm().exception())
descriptor_object->define_property(vm.names.set, Value(descriptor.setter));
if (vm.exception())
return {};
}
}
@ -337,35 +338,36 @@ void Object::set_shape(Shape& new_shape)
bool Object::define_property(const StringOrSymbol& property_name, const Object& descriptor, bool throw_exceptions)
{
bool is_accessor_property = descriptor.has_property("get") || descriptor.has_property("set");
auto& vm = this->vm();
bool is_accessor_property = descriptor.has_property(vm.names.get) || descriptor.has_property(vm.names.set);
PropertyAttributes attributes;
if (descriptor.has_property("configurable")) {
if (descriptor.has_property(vm.names.configurable)) {
attributes.set_has_configurable();
if (descriptor.get("configurable").value_or(Value(false)).to_boolean())
if (descriptor.get(vm.names.configurable).value_or(Value(false)).to_boolean())
attributes.set_configurable();
if (vm().exception())
if (vm.exception())
return false;
}
if (descriptor.has_property("enumerable")) {
if (descriptor.has_property(vm.names.enumerable)) {
attributes.set_has_enumerable();
if (descriptor.get("enumerable").value_or(Value(false)).to_boolean())
if (descriptor.get(vm.names.enumerable).value_or(Value(false)).to_boolean())
attributes.set_enumerable();
if (vm().exception())
if (vm.exception())
return false;
}
if (is_accessor_property) {
if (descriptor.has_property("value") || descriptor.has_property("writable")) {
if (descriptor.has_property(vm.names.value) || descriptor.has_property(vm.names.writable)) {
if (throw_exceptions)
vm().throw_exception<TypeError>(global_object(), ErrorType::AccessorValueOrWritable);
vm.throw_exception<TypeError>(global_object(), ErrorType::AccessorValueOrWritable);
return false;
}
auto getter = descriptor.get("get").value_or(js_undefined());
if (vm().exception())
auto getter = descriptor.get(vm.names.get).value_or(js_undefined());
if (vm.exception())
return {};
auto setter = descriptor.get("set").value_or(js_undefined());
if (vm().exception())
auto setter = descriptor.get(vm.names.set).value_or(js_undefined());
if (vm.exception())
return {};
Function* getter_function { nullptr };
@ -374,14 +376,14 @@ bool Object::define_property(const StringOrSymbol& property_name, const Object&
if (getter.is_function()) {
getter_function = &getter.as_function();
} else if (!getter.is_undefined()) {
vm().throw_exception<TypeError>(global_object(), ErrorType::AccessorBadField, "get");
vm.throw_exception<TypeError>(global_object(), ErrorType::AccessorBadField, "get");
return false;
}
if (setter.is_function()) {
setter_function = &setter.as_function();
} else if (!setter.is_undefined()) {
vm().throw_exception<TypeError>(global_object(), ErrorType::AccessorBadField, "set");
vm.throw_exception<TypeError>(global_object(), ErrorType::AccessorBadField, "set");
return false;
}
@ -391,20 +393,20 @@ bool Object::define_property(const StringOrSymbol& property_name, const Object&
<< "setter=" << setter.to_string_without_side_effects() << "}";
#endif
return define_property(property_name, Accessor::create(vm(), getter_function, setter_function), attributes, throw_exceptions);
return define_property(property_name, Accessor::create(vm, getter_function, setter_function), attributes, throw_exceptions);
}
auto value = descriptor.get("value");
if (vm().exception())
auto value = descriptor.get(vm.names.value);
if (vm.exception())
return {};
if (descriptor.has_property("writable")) {
if (descriptor.has_property(vm.names.writable)) {
attributes.set_has_writable();
if (descriptor.get("writable").value_or(Value(false)).to_boolean())
if (descriptor.get(vm.names.writable).value_or(Value(false)).to_boolean())
attributes.set_writable();
if (vm().exception())
if (vm.exception())
return false;
}
if (vm().exception())
if (vm.exception())
return {};
#ifdef OBJECT_DEBUG
@ -462,6 +464,14 @@ bool Object::put_own_property(Object& this_object, const StringOrSymbol& propert
{
ASSERT(!(mode == PutOwnPropertyMode::Put && value.is_accessor()));
if (value.is_accessor()) {
auto& accessor = value.as_accessor();
if (accessor.getter())
attributes.set_has_getter();
if (accessor.setter())
attributes.set_has_setter();
}
auto metadata = shape().lookup(property_name);
bool new_property = !metadata.has_value();
@ -474,14 +484,6 @@ bool Object::put_own_property(Object& this_object, const StringOrSymbol& propert
return false;
}
if (value.is_accessor()) {
auto& accessor = value.as_accessor();
if (accessor.getter())
attributes.set_has_getter();
if (accessor.setter())
attributes.set_has_setter();
}
if (new_property) {
if (!m_shape->is_unique() && shape().property_count() > 100) {
// If you add more than 100 properties to an object, let's stop doing
@ -752,6 +754,7 @@ bool Object::put(const PropertyName& property_name, Value value, Value receiver)
bool Object::define_native_function(const StringOrSymbol& property_name, AK::Function<Value(VM&, GlobalObject&)> native_function, i32 length, PropertyAttributes attribute)
{
auto& vm = this->vm();
String function_name;
if (property_name.is_string()) {
function_name = property_name.as_string();
@ -759,11 +762,11 @@ bool Object::define_native_function(const StringOrSymbol& property_name, AK::Fun
function_name = String::formatted("[{}]", property_name.as_symbol()->description());
}
auto* function = NativeFunction::create(global_object(), function_name, move(native_function));
function->define_property_without_transition("length", Value(length), Attribute::Configurable);
if (vm().exception())
function->define_property_without_transition(vm.names.length, Value(length), Attribute::Configurable);
if (vm.exception())
return {};
function->define_property_without_transition("name", js_string(heap(), function_name), Attribute::Configurable);
if (vm().exception())
function->define_property_without_transition(vm.names.name, js_string(vm.heap(), function_name), Attribute::Configurable);
if (vm.exception())
return {};
return define_property(property_name, function, attribute);
}
@ -846,7 +849,7 @@ Value Object::to_primitive(Value::PreferredType preferred_type) const
Value Object::to_string() const
{
auto& vm = this->vm();
auto to_string_property = get("toString");
auto to_string_property = get(vm.names.toString);
if (to_string_property.is_function()) {
auto& to_string_function = to_string_property.as_function();
auto to_string_result = vm.call(to_string_function, const_cast<Object*>(this));
@ -859,7 +862,7 @@ Value Object::to_string() const
return {};
return string;
}
return js_string(heap(), String::formatted("[object {}]", class_name()));
return js_string(vm, String::formatted("[object {}]", class_name()));
}
Value Object::invoke(const StringOrSymbol& property_name, Optional<MarkedValueList> arguments)

View file

@ -35,28 +35,29 @@
namespace JS {
ObjectConstructor::ObjectConstructor(GlobalObject& global_object)
: NativeFunction("Object", *global_object.function_prototype())
: NativeFunction(vm().names.Object, *global_object.function_prototype())
{
}
void ObjectConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property("prototype", global_object.object_prototype(), 0);
define_property("length", Value(1), Attribute::Configurable);
define_property(vm.names.prototype, global_object.object_prototype(), 0);
define_property(vm.names.length, Value(1), Attribute::Configurable);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function("defineProperty", define_property_, 3, attr);
define_native_function("is", is, 2, attr);
define_native_function("getOwnPropertyDescriptor", get_own_property_descriptor, 2, attr);
define_native_function("getOwnPropertyNames", get_own_property_names, 1, attr);
define_native_function("getPrototypeOf", get_prototype_of, 1, attr);
define_native_function("setPrototypeOf", set_prototype_of, 2, attr);
define_native_function("isExtensible", is_extensible, 1, attr);
define_native_function("preventExtensions", prevent_extensions, 1, attr);
define_native_function("keys", keys, 1, attr);
define_native_function("values", values, 1, attr);
define_native_function("entries", entries, 1, attr);
define_native_function(vm.names.defineProperty, define_property_, 3, attr);
define_native_function(vm.names.is, is, 2, attr);
define_native_function(vm.names.getOwnPropertyDescriptor, get_own_property_descriptor, 2, attr);
define_native_function(vm.names.getOwnPropertyNames, get_own_property_names, 1, attr);
define_native_function(vm.names.getPrototypeOf, get_prototype_of, 1, attr);
define_native_function(vm.names.setPrototypeOf, set_prototype_of, 2, attr);
define_native_function(vm.names.isExtensible, is_extensible, 1, attr);
define_native_function(vm.names.preventExtensions, prevent_extensions, 1, attr);
define_native_function(vm.names.keys, keys, 1, attr);
define_native_function(vm.names.values, values, 1, attr);
define_native_function(vm.names.entries, entries, 1, attr);
}
ObjectConstructor::~ObjectConstructor()

View file

@ -40,14 +40,15 @@ ObjectPrototype::ObjectPrototype(GlobalObject& global_object)
void ObjectPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
// This must be called after the constructor has returned, so that the below code
// can find the ObjectPrototype through normal paths.
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function("hasOwnProperty", has_own_property, 1, attr);
define_native_function("toString", to_string, 0, attr);
define_native_function("toLocaleString", to_locale_string, 0, attr);
define_native_function("valueOf", value_of, 0, attr);
define_native_function(vm.names.hasOwnProperty, has_own_property, 1, attr);
define_native_function(vm.names.toString, to_string, 0, attr);
define_native_function(vm.names.toLocaleString, to_locale_string, 0, attr);
define_native_function(vm.names.valueOf, value_of, 0, attr);
}
ObjectPrototype::~ObjectPrototype()

View file

@ -33,15 +33,16 @@
namespace JS {
ProxyConstructor::ProxyConstructor(GlobalObject& global_object)
: NativeFunction("Proxy", *global_object.function_prototype())
: NativeFunction(vm().names.Proxy, *global_object.function_prototype())
{
}
void ProxyConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property("prototype", global_object.proxy_prototype(), 0);
define_property("length", Value(2), Attribute::Configurable);
define_property(vm.names.prototype, global_object.proxy_prototype(), 0);
define_property(vm.names.length, Value(2), Attribute::Configurable);
}
ProxyConstructor::~ProxyConstructor()

View file

@ -79,7 +79,7 @@ Object* ProxyObject::prototype()
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return nullptr;
}
auto trap = m_handler.get("getPrototypeOf");
auto trap = m_handler.get(vm().names.getPrototypeOf);
if (vm().exception())
return nullptr;
if (trap.is_empty() || trap.is_nullish())
@ -128,7 +128,7 @@ bool ProxyObject::set_prototype(Object* object)
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return false;
}
auto trap = m_handler.get("setPrototypeOf");
auto trap = m_handler.get(vm().names.setPrototypeOf);
if (vm().exception())
return false;
if (trap.is_empty() || trap.is_nullish())
@ -159,7 +159,7 @@ bool ProxyObject::is_extensible() const
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return false;
}
auto trap = m_handler.get("isExtensible");
auto trap = m_handler.get(vm().names.isExtensible);
if (vm().exception())
return false;
if (trap.is_empty() || trap.is_nullish())
@ -186,7 +186,7 @@ bool ProxyObject::prevent_extensions()
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return false;
}
auto trap = m_handler.get("preventExtensions");
auto trap = m_handler.get(vm().names.preventExtensions);
if (vm().exception())
return false;
if (trap.is_empty() || trap.is_nullish())
@ -213,7 +213,7 @@ Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(const Prop
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return {};
}
auto trap = m_handler.get("getOwnPropertyDescriptor");
auto trap = m_handler.get(vm().names.getOwnPropertyDescriptor);
if (vm().exception())
return {};
if (trap.is_empty() || trap.is_nullish())
@ -268,7 +268,7 @@ bool ProxyObject::define_property(const StringOrSymbol& property_name, const Obj
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return false;
}
auto trap = m_handler.get("defineProperty");
auto trap = m_handler.get(vm().names.defineProperty);
if (vm().exception())
return false;
if (trap.is_empty() || trap.is_nullish())
@ -285,7 +285,7 @@ bool ProxyObject::define_property(const StringOrSymbol& property_name, const Obj
if (vm().exception())
return false;
bool setting_config_false = false;
if (descriptor.has_property("configurable") && !descriptor.get("configurable").to_boolean())
if (descriptor.has_property(vm().names.configurable) && !descriptor.get(vm().names.configurable).to_boolean())
setting_config_false = true;
if (vm().exception())
return false;
@ -319,7 +319,7 @@ bool ProxyObject::has_property(const PropertyName& name) const
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return false;
}
auto trap = m_handler.get("has");
auto trap = m_handler.get(vm().names.has);
if (vm().exception())
return false;
if (trap.is_empty() || trap.is_nullish())
@ -357,7 +357,7 @@ Value ProxyObject::get(const PropertyName& name, Value) const
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return {};
}
auto trap = m_handler.get("get");
auto trap = m_handler.get(vm().names.get);
if (vm().exception())
return {};
if (trap.is_empty() || trap.is_nullish())
@ -388,32 +388,33 @@ Value ProxyObject::get(const PropertyName& name, Value) const
bool ProxyObject::put(const PropertyName& name, Value value, Value)
{
auto& vm = this->vm();
if (m_is_revoked) {
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return false;
}
auto trap = m_handler.get("set");
if (vm().exception())
auto trap = m_handler.get(vm.names.set);
if (vm.exception())
return false;
if (trap.is_empty() || trap.is_nullish())
return m_target.put(name, value);
if (!trap.is_function()) {
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "set");
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "set");
return false;
}
auto trap_result = vm().call(trap.as_function(), Value(&m_handler), Value(&m_target), js_string(vm(), name.to_string()), value, Value(const_cast<ProxyObject*>(this))).to_boolean();
if (vm().exception() || !trap_result)
auto trap_result = vm.call(trap.as_function(), Value(&m_handler), Value(&m_target), js_string(vm, name.to_string()), value, Value(const_cast<ProxyObject*>(this))).to_boolean();
if (vm.exception() || !trap_result)
return false;
auto target_desc = m_target.get_own_property_descriptor(name);
if (vm().exception())
if (vm.exception())
return false;
if (target_desc.has_value() && !target_desc.value().attributes.is_configurable()) {
if (target_desc.value().is_data_descriptor() && !target_desc.value().attributes.is_writable() && !same_value(value, target_desc.value().value)) {
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxySetImmutableDataProperty);
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxySetImmutableDataProperty);
return false;
}
if (target_desc.value().is_accessor_descriptor() && !target_desc.value().setter) {
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxySetNonConfigurableAccessor);
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxySetNonConfigurableAccessor);
}
}
return true;
@ -421,32 +422,33 @@ bool ProxyObject::put(const PropertyName& name, Value value, Value)
Value ProxyObject::delete_property(const PropertyName& name)
{
auto& vm = this->vm();
if (m_is_revoked) {
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return {};
}
auto trap = m_handler.get("deleteProperty");
if (vm().exception())
auto trap = m_handler.get(vm.names.deleteProperty);
if (vm.exception())
return {};
if (trap.is_empty() || trap.is_nullish())
return m_target.delete_property(name);
if (!trap.is_function()) {
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "deleteProperty");
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "deleteProperty");
return {};
}
auto trap_result = vm().call(trap.as_function(), Value(&m_handler), Value(&m_target), js_string(vm(), name.to_string())).to_boolean();
if (vm().exception())
auto trap_result = vm.call(trap.as_function(), Value(&m_handler), Value(&m_target), js_string(vm, name.to_string())).to_boolean();
if (vm.exception())
return {};
if (!trap_result)
return Value(false);
auto target_desc = m_target.get_own_property_descriptor(name);
if (vm().exception())
if (vm.exception())
return {};
if (!target_desc.has_value())
return Value(true);
if (!target_desc.value().attributes.is_configurable()) {
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyDeleteNonConfigurable);
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyDeleteNonConfigurable);
return {};
}
return Value(true);
@ -461,21 +463,22 @@ void ProxyObject::visit_children(Cell::Visitor& visitor)
Value ProxyObject::call()
{
auto& vm = this->vm();
if (!is_function()) {
vm().throw_exception<TypeError>(global_object(), ErrorType::NotAFunction, Value(this).to_string_without_side_effects());
vm.throw_exception<TypeError>(global_object(), ErrorType::NotAFunction, Value(this).to_string_without_side_effects());
return {};
}
if (m_is_revoked) {
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return {};
}
auto trap = m_handler.get("apply");
if (vm().exception())
auto trap = m_handler.get(vm.names.apply);
if (vm.exception())
return {};
if (trap.is_empty() || trap.is_nullish())
return static_cast<Function&>(m_target).call();
if (!trap.is_function()) {
vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "apply");
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "apply");
return {};
}
MarkedValueList arguments(heap());
@ -483,12 +486,12 @@ Value ProxyObject::call()
arguments.append(Value(&m_handler));
// FIXME: Pass global object
auto arguments_array = Array::create(global_object());
vm().for_each_argument([&](auto& argument) {
vm.for_each_argument([&](auto& argument) {
arguments_array->indexed_properties().append(argument);
});
arguments.append(arguments_array);
return vm().call(trap.as_function(), Value(&m_handler), move(arguments));
return vm.call(trap.as_function(), Value(&m_handler), move(arguments));
}
Value ProxyObject::construct(Function& new_target)
@ -502,7 +505,7 @@ Value ProxyObject::construct(Function& new_target)
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return {};
}
auto trap = m_handler.get("construct");
auto trap = m_handler.get(vm.names.construct);
if (vm.exception())
return {};
if (trap.is_empty() || trap.is_nullish())

View file

@ -63,7 +63,7 @@ static void prepare_arguments_list(GlobalObject& global_object, Value value, Mar
return;
}
auto& arguments_list = value.as_object();
auto length_property = arguments_list.get("length");
auto length_property = arguments_list.get(vm.names.length);
if (vm.exception())
return;
auto length = length_property.to_size_t(global_object);
@ -84,21 +84,22 @@ ReflectObject::ReflectObject(GlobalObject& global_object)
void ReflectObject::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function("apply", apply, 3, attr);
define_native_function("construct", construct, 2, attr);
define_native_function("defineProperty", define_property, 3, attr);
define_native_function("deleteProperty", delete_property, 2, attr);
define_native_function("get", get, 2, attr);
define_native_function("getOwnPropertyDescriptor", get_own_property_descriptor, 2, attr);
define_native_function("getPrototypeOf", get_prototype_of, 1, attr);
define_native_function("has", has, 2, attr);
define_native_function("isExtensible", is_extensible, 1, attr);
define_native_function("ownKeys", own_keys, 1, attr);
define_native_function("preventExtensions", prevent_extensions, 1, attr);
define_native_function("set", set, 3, attr);
define_native_function("setPrototypeOf", set_prototype_of, 2, attr);
define_native_function(vm.names.apply, apply, 3, attr);
define_native_function(vm.names.construct, construct, 2, attr);
define_native_function(vm.names.defineProperty, define_property, 3, attr);
define_native_function(vm.names.deleteProperty, delete_property, 2, attr);
define_native_function(vm.names.get, get, 2, attr);
define_native_function(vm.names.getOwnPropertyDescriptor, get_own_property_descriptor, 2, attr);
define_native_function(vm.names.getPrototypeOf, get_prototype_of, 1, attr);
define_native_function(vm.names.has, has, 2, attr);
define_native_function(vm.names.isExtensible, is_extensible, 1, attr);
define_native_function(vm.names.ownKeys, own_keys, 1, attr);
define_native_function(vm.names.preventExtensions, prevent_extensions, 1, attr);
define_native_function(vm.names.set, set, 3, attr);
define_native_function(vm.names.setPrototypeOf, set_prototype_of, 2, attr);
}
ReflectObject::~ReflectObject()

View file

@ -32,15 +32,16 @@
namespace JS {
RegExpConstructor::RegExpConstructor(GlobalObject& global_object)
: NativeFunction("RegExp", *global_object.function_prototype())
: NativeFunction(vm().names.RegExp, *global_object.function_prototype())
{
}
void RegExpConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property("prototype", global_object.regexp_prototype(), 0);
define_property("length", Value(2), Attribute::Configurable);
define_property(vm.names.prototype, global_object.regexp_prototype(), 0);
define_property(vm.names.length, Value(2), Attribute::Configurable);
}
RegExpConstructor::~RegExpConstructor()

View file

@ -66,14 +66,15 @@ ScriptFunction::ScriptFunction(GlobalObject& global_object, const FlyString& nam
void ScriptFunction::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Function::initialize(global_object);
if (!m_is_arrow_function) {
Object* prototype = Object::create_empty(global_object);
prototype->define_property_without_transition("constructor", this, Attribute::Writable | Attribute::Configurable);
define_property("prototype", prototype, 0);
prototype->define_property_without_transition(vm.names.constructor, this, Attribute::Writable | Attribute::Configurable);
define_property(vm.names.prototype, prototype, 0);
}
define_native_property("length", length_getter, nullptr, Attribute::Configurable);
define_native_property("name", name_getter, nullptr, Attribute::Configurable);
define_native_property(vm.names.length, length_getter, nullptr, Attribute::Configurable);
define_native_property(vm.names.name, name_getter, nullptr, Attribute::Configurable);
}
ScriptFunction::~ScriptFunction()

View file

@ -35,19 +35,20 @@
namespace JS {
StringConstructor::StringConstructor(GlobalObject& global_object)
: NativeFunction("String", *global_object.function_prototype())
: NativeFunction(vm().names.String, *global_object.function_prototype())
{
}
void StringConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property("prototype", global_object.string_prototype(), 0);
define_property("length", Value(1), Attribute::Configurable);
define_property(vm.names.prototype, global_object.string_prototype(), 0);
define_property(vm.names.length, Value(1), Attribute::Configurable);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function("raw", raw, 1, attr);
define_native_function("fromCharCode", from_char_code, 1, attr);
define_native_function(vm.names.raw, raw, 1, attr);
define_native_function(vm.names.fromCharCode, from_char_code, 1, attr);
}
StringConstructor::~StringConstructor()
@ -84,7 +85,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringConstructor::raw)
if (vm.exception())
return {};
auto raw = template_object->get("raw");
auto raw = template_object->get(vm.names.raw);
if (vm.exception())
return {};
if (raw.is_empty() || raw.is_nullish()) {

View file

@ -40,10 +40,10 @@ StringIteratorPrototype::StringIteratorPrototype(GlobalObject& global_object)
void StringIteratorPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
define_native_function("next", next, 0, Attribute::Configurable | Attribute::Writable);
define_property(global_object.vm().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "String Iterator"), Attribute::Configurable);
define_native_function(vm.names.next, next, 0, Attribute::Configurable | Attribute::Writable);
define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), "String Iterator"), Attribute::Configurable);
}
StringIteratorPrototype::~StringIteratorPrototype()

View file

@ -66,29 +66,30 @@ StringPrototype::StringPrototype(GlobalObject& global_object)
void StringPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
StringObject::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_property("length", length_getter, nullptr, 0);
define_native_function("charAt", char_at, 1, attr);
define_native_function("charCodeAt", char_code_at, 1, attr);
define_native_function("repeat", repeat, 1, attr);
define_native_function("startsWith", starts_with, 1, attr);
define_native_function("indexOf", index_of, 1, attr);
define_native_function("toLowerCase", to_lowercase, 0, attr);
define_native_function("toUpperCase", to_uppercase, 0, attr);
define_native_function("toString", to_string, 0, attr);
define_native_function("padStart", pad_start, 1, attr);
define_native_function("padEnd", pad_end, 1, attr);
define_native_function("trim", trim, 0, attr);
define_native_function("trimStart", trim_start, 0, attr);
define_native_function("trimEnd", trim_end, 0, attr);
define_native_function("concat", concat, 1, attr);
define_native_function("substring", substring, 2, attr);
define_native_function("includes", includes, 1, attr);
define_native_function("slice", slice, 2, attr);
define_native_function("lastIndexOf", last_index_of, 1, attr);
define_native_function(global_object.vm().well_known_symbol_iterator(), symbol_iterator, 0, attr);
define_native_property(vm.names.length, length_getter, nullptr, 0);
define_native_function(vm.names.charAt, char_at, 1, attr);
define_native_function(vm.names.charCodeAt, char_code_at, 1, attr);
define_native_function(vm.names.repeat, repeat, 1, attr);
define_native_function(vm.names.startsWith, starts_with, 1, attr);
define_native_function(vm.names.indexOf, index_of, 1, attr);
define_native_function(vm.names.toLowerCase, to_lowercase, 0, attr);
define_native_function(vm.names.toUpperCase, to_uppercase, 0, attr);
define_native_function(vm.names.toString, to_string, 0, attr);
define_native_function(vm.names.padStart, pad_start, 1, attr);
define_native_function(vm.names.padEnd, pad_end, 1, attr);
define_native_function(vm.names.trim, trim, 0, attr);
define_native_function(vm.names.trimStart, trim_start, 0, attr);
define_native_function(vm.names.trimEnd, trim_end, 0, attr);
define_native_function(vm.names.concat, concat, 1, attr);
define_native_function(vm.names.substring, substring, 2, attr);
define_native_function(vm.names.includes, includes, 1, attr);
define_native_function(vm.names.slice, slice, 2, attr);
define_native_function(vm.names.lastIndexOf, last_index_of, 1, attr);
define_native_function(vm.well_known_symbol_iterator(), symbol_iterator, 0, attr);
}
StringPrototype::~StringPrototype()

View file

@ -32,21 +32,22 @@
namespace JS {
SymbolConstructor::SymbolConstructor(GlobalObject& global_object)
: NativeFunction("Symbol", *global_object.function_prototype())
: NativeFunction(vm().names.Symbol, *global_object.function_prototype())
{
}
void SymbolConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property("prototype", global_object.symbol_prototype(), 0);
define_property("length", Value(0), Attribute::Configurable);
define_property(vm.names.prototype, global_object.symbol_prototype(), 0);
define_property(vm.names.length, Value(0), Attribute::Configurable);
define_native_function("for", for_, 1, Attribute::Writable | Attribute::Configurable);
define_native_function("keyFor", key_for, 1, Attribute::Writable | Attribute::Configurable);
define_native_function(vm.names.for_, for_, 1, Attribute::Writable | Attribute::Configurable);
define_native_function(vm.names.keyFor, key_for, 1, Attribute::Writable | Attribute::Configurable);
#define __JS_ENUMERATE(SymbolName, snake_name) \
define_property(#SymbolName, global_object.vm().well_known_symbol_##snake_name(), 0);
define_property(vm.names.SymbolName, vm.well_known_symbol_##snake_name(), 0);
JS_ENUMERATE_WELL_KNOWN_SYMBOLS
#undef __JS_ENUMERATE
}

View file

@ -45,10 +45,11 @@ SymbolPrototype::SymbolPrototype(GlobalObject& global_object)
void SymbolPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
define_native_property("description", description_getter, nullptr, Attribute::Configurable);
define_native_function("toString", to_string, 0, Attribute::Writable | Attribute::Configurable);
define_native_function("valueOf", value_of, 0, Attribute::Writable | Attribute::Configurable);
define_native_property(vm.names.description, description_getter, nullptr, Attribute::Configurable);
define_native_function(vm.names.toString, to_string, 0, Attribute::Writable | Attribute::Configurable);
define_native_function(vm.names.valueOf, value_of, 0, Attribute::Writable | Attribute::Configurable);
define_property(global_object.vm().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "Symbol"), Attribute::Configurable);
}

View file

@ -40,7 +40,8 @@ Uint8ClampedArray::Uint8ClampedArray(u32 length, Object& prototype)
: Object(prototype)
, m_length(length)
{
define_native_property("length", length_getter, nullptr);
auto& vm = this->vm();
define_native_property(vm.names.length, length_getter, nullptr);
m_data = new u8[m_length];
}

View file

@ -207,7 +207,7 @@ Value VM::construct(Function& function, Function& new_target, Optional<MarkedVal
current_environment()->bind_this_value(global_object, new_object);
if (exception())
return {};
auto prototype = new_target.get("prototype");
auto prototype = new_target.get(names.prototype);
if (exception())
return {};
if (prototype.is_object()) {
@ -230,7 +230,7 @@ Value VM::construct(Function& function, Function& new_target, Optional<MarkedVal
// set the prototype on objects created by constructors that return an object (i.e. NativeFunction subclasses).
if (function.constructor_kind() == Function::ConstructorKind::Base && new_target.constructor_kind() == Function::ConstructorKind::Derived && result.is_object()) {
current_environment()->replace_this_binding(result);
auto prototype = new_target.get("prototype");
auto prototype = new_target.get(names.prototype);
if (exception())
return {};
if (prototype.is_object()) {

View file

@ -30,6 +30,7 @@
#include <AK/HashMap.h>
#include <AK/RefCounted.h>
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/CommonPropertyNames.h>
#include <LibJS/Runtime/ErrorTypes.h>
#include <LibJS/Runtime/Exception.h>
#include <LibJS/Runtime/MarkedValueList.h>
@ -223,6 +224,8 @@ public:
return call(function, this_value);
}
CommonPropertyNames names;
private:
VM();

View file

@ -738,7 +738,7 @@ Value ordinary_has_instance(GlobalObject& global_object, Value lhs, Value rhs)
return Value(false);
Object* lhs_object = &lhs.as_object();
auto rhs_prototype = rhs_function.get("prototype");
auto rhs_prototype = rhs_function.get(vm.names.prototype);
if (vm.exception())
return {};
@ -1013,8 +1013,9 @@ TriState abstract_relation(GlobalObject& global_object, bool left_first, Value l
size_t length_of_array_like(GlobalObject& global_object, Value value)
{
ASSERT(value.is_object());
auto result = value.as_object().get("length");
if (global_object.vm().exception())
auto& vm = global_object.vm();
auto result = value.as_object().get(vm.names.length);
if (vm.exception())
return 0;
return result.to_size_t(global_object);
}

View file

@ -154,8 +154,10 @@ TestRunnerGlobalObject::~TestRunnerGlobalObject()
void TestRunnerGlobalObject::initialize()
{
JS::GlobalObject::initialize();
define_property("global", this, JS::Attribute::Enumerable);
define_native_function("isStrictMode", is_strict_mode);
static FlyString global_property_name { "global" };
static FlyString is_strict_mode_property_name { "isStrictMode" };
define_property(global_property_name, this, JS::Attribute::Enumerable);
define_native_function(is_strict_mode_property_name, is_strict_mode);
}
JS_DEFINE_NATIVE_FUNCTION(TestRunnerGlobalObject::is_strict_mode)