From 23b1d97b0d757cf6427d86a736b811f13698fd92 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 15 Mar 2020 15:25:43 +0100 Subject: [PATCH] LibJS: Add ObjectPrototype and implement hasOwnProperty() All Objects will now have ObjectPrototype as their prototype, unless overridden. --- Base/home/anon/js/hasOwnProperty.js | 2 ++ Libraries/LibJS/Interpreter.cpp | 3 ++ Libraries/LibJS/Interpreter.h | 2 ++ Libraries/LibJS/Makefile | 1 + Libraries/LibJS/Object.cpp | 8 +++++ Libraries/LibJS/Object.h | 2 ++ Libraries/LibJS/ObjectPrototype.cpp | 54 +++++++++++++++++++++++++++++ Libraries/LibJS/ObjectPrototype.h | 42 ++++++++++++++++++++++ 8 files changed, 114 insertions(+) create mode 100644 Base/home/anon/js/hasOwnProperty.js create mode 100644 Libraries/LibJS/ObjectPrototype.cpp create mode 100644 Libraries/LibJS/ObjectPrototype.h diff --git a/Base/home/anon/js/hasOwnProperty.js b/Base/home/anon/js/hasOwnProperty.js new file mode 100644 index 0000000000..26456344ab --- /dev/null +++ b/Base/home/anon/js/hasOwnProperty.js @@ -0,0 +1,2 @@ +var x = "foobar"; +print(x.hasOwnProperty("length")); diff --git a/Libraries/LibJS/Interpreter.cpp b/Libraries/LibJS/Interpreter.cpp index c7ceb8eba3..1f5c6d1e1c 100644 --- a/Libraries/LibJS/Interpreter.cpp +++ b/Libraries/LibJS/Interpreter.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ Interpreter::Interpreter() : m_heap(*this) { m_global_object = heap().allocate(); + m_object_prototype = heap().allocate(); m_string_prototype = heap().allocate(); } @@ -140,6 +142,7 @@ void Interpreter::gather_roots(Badge, HashTable& roots) { roots.set(m_global_object); roots.set(m_string_prototype); + roots.set(m_object_prototype); for (auto& scope : m_scope_stack) { for (auto& it : scope.variables) { diff --git a/Libraries/LibJS/Interpreter.h b/Libraries/LibJS/Interpreter.h index ca6ad60409..abad03da81 100644 --- a/Libraries/LibJS/Interpreter.h +++ b/Libraries/LibJS/Interpreter.h @@ -89,6 +89,7 @@ public: } Object* string_prototype() { return m_string_prototype; } + Object* object_prototype() { return m_object_prototype; } private: Heap m_heap; @@ -98,6 +99,7 @@ private: Object* m_global_object { nullptr }; Object* m_string_prototype { nullptr }; + Object* m_object_prototype { nullptr }; }; } diff --git a/Libraries/LibJS/Makefile b/Libraries/LibJS/Makefile index f32336e837..f067594753 100644 --- a/Libraries/LibJS/Makefile +++ b/Libraries/LibJS/Makefile @@ -9,6 +9,7 @@ OBJS = \ Lexer.o \ NativeFunction.o \ Object.o \ + ObjectPrototype.o \ Parser.o \ PrimitiveString.o \ ScriptFunction.o \ diff --git a/Libraries/LibJS/Object.cpp b/Libraries/LibJS/Object.cpp index 8fdd3721b2..5669e77930 100644 --- a/Libraries/LibJS/Object.cpp +++ b/Libraries/LibJS/Object.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -34,6 +35,7 @@ namespace JS { Object::Object() { + set_prototype(interpreter().object_prototype()); } Object::~Object() @@ -44,6 +46,7 @@ Value Object::get(String property_name) const { const Object* object = this; while (object) { + dbg() << "Object::get() trying '" << property_name << "' in " << object->class_name(); auto value = object->m_properties.get(property_name); if (value.has_value()) return value.value(); @@ -71,4 +74,9 @@ void Object::visit_children(Cell::Visitor& visitor) visitor.visit(it.value); } +bool Object::has_own_property(const String& property_name) const +{ + return m_properties.get(property_name).has_value(); +} + } diff --git a/Libraries/LibJS/Object.h b/Libraries/LibJS/Object.h index e3b8f1e4f9..293e843f01 100644 --- a/Libraries/LibJS/Object.h +++ b/Libraries/LibJS/Object.h @@ -54,6 +54,8 @@ public: const Object* prototype() const { return m_prototype; } void set_prototype(Object* prototype) { m_prototype = prototype; } + bool has_own_property(const String& property_name) const; + private: HashMap m_properties; Object* m_prototype { nullptr }; diff --git a/Libraries/LibJS/ObjectPrototype.cpp b/Libraries/LibJS/ObjectPrototype.cpp new file mode 100644 index 0000000000..1833d50c29 --- /dev/null +++ b/Libraries/LibJS/ObjectPrototype.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020, Andreas Kling + * 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. + */ + +#include +#include +#include +#include +#include +#include + +namespace JS { + +ObjectPrototype::ObjectPrototype() +{ + set_prototype(nullptr); + + put_native_function("hasOwnProperty", [](Interpreter& interpreter, Vector arguments) -> Value { + dbg() << "hasOwnProperty"; + if (arguments.is_empty()) + return js_undefined(); + Value this_value = interpreter.this_value(); + ASSERT(this_value.is_object()); + return Value(this_value.as_object()->has_own_property(arguments[0].to_string())); + }); +} + +ObjectPrototype::~ObjectPrototype() +{ +} + +} diff --git a/Libraries/LibJS/ObjectPrototype.h b/Libraries/LibJS/ObjectPrototype.h new file mode 100644 index 0000000000..9833c0f9bd --- /dev/null +++ b/Libraries/LibJS/ObjectPrototype.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020, Andreas Kling + * 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 + +namespace JS { + +class ObjectPrototype final : public Object { +public: + ObjectPrototype(); + virtual ~ObjectPrototype() override; + +private: + virtual const char* class_name() const override { return "ObjectPrototype"; } +}; + +}