1 | /* |
2 | * Copyright (C) 1999-2001 Harri Porten ([email protected]) |
3 | * Copyright (C) 2001 Peter Kelly ([email protected]) |
4 | * Copyright (C) 2003-2019 Apple Inc. All rights reserved. |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Library General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Library General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Library General Public License |
17 | * along with this library; see the file COPYING.LIB. If not, write to |
18 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 | * Boston, MA 02110-1301, USA. |
20 | * |
21 | */ |
22 | |
23 | #pragma once |
24 | |
25 | #include "JSCast.h" |
26 | |
27 | #include "CallFrame.h" |
28 | #include "JSGlobalObject.h" |
29 | #include "NullGetterFunction.h" |
30 | #include "NullSetterFunction.h" |
31 | #include "Structure.h" |
32 | |
33 | namespace JSC { |
34 | |
35 | class JSObject; |
36 | |
37 | // This is an internal value object which stores getter and setter functions |
38 | // for a property. Instances of this class have the property that once a getter |
39 | // or setter is set to a non-null value, then they cannot be changed. This means |
40 | // that if a property holding a GetterSetter reference is constant-inferred and |
41 | // that constant is observed to have a non-null setter (or getter) then we can |
42 | // constant fold that setter (or getter). |
43 | class GetterSetter final : public JSCell { |
44 | friend class JIT; |
45 | using Base = JSCell; |
46 | private: |
47 | GetterSetter(VM& vm, JSGlobalObject* globalObject, JSObject* getter, JSObject* setter) |
48 | : Base(vm, vm.getterSetterStructure.get()) |
49 | { |
50 | WTF::storeStoreFence(); |
51 | m_getter.set(vm, this, getter ? getter : globalObject->nullGetterFunction()); |
52 | m_setter.set(vm, this, setter ? setter : globalObject->nullSetterFunction()); |
53 | } |
54 | |
55 | public: |
56 | |
57 | static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | StructureIsImmortal; |
58 | |
59 | template<typename CellType, SubspaceAccess> |
60 | static IsoSubspace* subspaceFor(VM& vm) |
61 | { |
62 | return &vm.getterSetterSpace; |
63 | } |
64 | |
65 | static GetterSetter* create(VM& vm, JSGlobalObject* globalObject, JSObject* getter, JSObject* setter) |
66 | { |
67 | GetterSetter* getterSetter = new (NotNull, allocateCell<GetterSetter>(vm.heap)) GetterSetter(vm, globalObject, getter, setter); |
68 | getterSetter->finishCreation(vm); |
69 | return getterSetter; |
70 | } |
71 | |
72 | static GetterSetter* create(VM& vm, JSGlobalObject* globalObject, JSValue getter, JSValue setter) |
73 | { |
74 | ASSERT(getter.isUndefined() || getter.isObject()); |
75 | ASSERT(setter.isUndefined() || setter.isObject()); |
76 | JSObject* getterObject { nullptr }; |
77 | JSObject* setterObject { nullptr }; |
78 | if (getter.isObject()) |
79 | getterObject = asObject(getter); |
80 | if (setter.isObject()) |
81 | setterObject = asObject(setter); |
82 | return create(vm, globalObject, getterObject, setterObject); |
83 | } |
84 | |
85 | static void visitChildren(JSCell*, SlotVisitor&); |
86 | |
87 | JSObject* getter() const { return m_getter.get(); } |
88 | |
89 | JSObject* getterConcurrently() const |
90 | { |
91 | JSObject* result = getter(); |
92 | WTF::loadLoadFence(); |
93 | return result; |
94 | } |
95 | |
96 | bool isGetterNull() const { return !!jsDynamicCast<NullGetterFunction*>(m_getter.get()->vm(), m_getter.get()); } |
97 | bool isSetterNull() const { return !!jsDynamicCast<NullSetterFunction*>(m_setter.get()->vm(), m_setter.get()); } |
98 | |
99 | JSObject* setter() const { return m_setter.get(); } |
100 | |
101 | JSObject* setterConcurrently() const |
102 | { |
103 | JSObject* result = setter(); |
104 | WTF::loadLoadFence(); |
105 | return result; |
106 | } |
107 | |
108 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) |
109 | { |
110 | return Structure::create(vm, globalObject, prototype, TypeInfo(GetterSetterType), info()); |
111 | } |
112 | |
113 | static ptrdiff_t offsetOfGetter() |
114 | { |
115 | return OBJECT_OFFSETOF(GetterSetter, m_getter); |
116 | } |
117 | |
118 | static ptrdiff_t offsetOfSetter() |
119 | { |
120 | return OBJECT_OFFSETOF(GetterSetter, m_setter); |
121 | } |
122 | |
123 | DECLARE_EXPORT_INFO; |
124 | |
125 | static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&) { RELEASE_ASSERT_NOT_REACHED(); return false; } |
126 | static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&) { RELEASE_ASSERT_NOT_REACHED(); return false; } |
127 | static bool putByIndex(JSCell*, JSGlobalObject*, unsigned, JSValue, bool) { RELEASE_ASSERT_NOT_REACHED(); return false; } |
128 | static bool setPrototype(JSObject*, JSGlobalObject*, JSValue, bool) { RELEASE_ASSERT_NOT_REACHED(); return false; } |
129 | static bool defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool) { RELEASE_ASSERT_NOT_REACHED(); return false; } |
130 | static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName) { RELEASE_ASSERT_NOT_REACHED(); return false; } |
131 | |
132 | private: |
133 | WriteBarrier<JSObject> m_getter; |
134 | WriteBarrier<JSObject> m_setter; |
135 | }; |
136 | |
137 | JSValue callGetter(JSGlobalObject*, JSValue base, JSValue getterSetter); |
138 | JS_EXPORT_PRIVATE bool callSetter(JSGlobalObject*, JSValue base, JSValue getterSetter, JSValue, ECMAMode); |
139 | |
140 | } // namespace JSC |
141 | |