1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2003-2019 Apple Inc. All Rights Reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21#pragma once
22
23#include "JSObject.h"
24#include "RegExp.h"
25#include "ThrowScope.h"
26#include "TypeError.h"
27
28namespace JSC {
29
30class RegExpObject final : public JSNonFinalObject {
31public:
32 using Base = JSNonFinalObject;
33 static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames;
34
35 static constexpr uintptr_t lastIndexIsNotWritableFlag = 1;
36
37 static RegExpObject* create(VM& vm, Structure* structure, RegExp* regExp)
38 {
39 RegExpObject* object = new (NotNull, allocateCell<RegExpObject>(vm.heap)) RegExpObject(vm, structure, regExp);
40 object->finishCreation(vm);
41 return object;
42 }
43
44 static RegExpObject* create(VM& vm, Structure* structure, RegExp* regExp, JSValue lastIndex)
45 {
46 auto* object = create(vm, structure, regExp);
47 object->m_lastIndex.set(vm, object, lastIndex);
48 return object;
49 }
50
51 void setRegExp(VM& vm, RegExp* regExp)
52 {
53 uintptr_t result = (m_regExpAndLastIndexIsNotWritableFlag & lastIndexIsNotWritableFlag) | bitwise_cast<uintptr_t>(regExp);
54 m_regExpAndLastIndexIsNotWritableFlag = result;
55 vm.heap.writeBarrier(this, regExp);
56 }
57
58 RegExp* regExp() const
59 {
60 return bitwise_cast<RegExp*>(m_regExpAndLastIndexIsNotWritableFlag & (~lastIndexIsNotWritableFlag));
61 }
62
63 bool setLastIndex(JSGlobalObject* globalObject, size_t lastIndex)
64 {
65 VM& vm = getVM(globalObject);
66 auto scope = DECLARE_THROW_SCOPE(vm);
67
68 if (LIKELY(lastIndexIsWritable())) {
69 m_lastIndex.setWithoutWriteBarrier(jsNumber(lastIndex));
70 return true;
71 }
72 throwTypeError(globalObject, scope, ReadonlyPropertyWriteError);
73 return false;
74 }
75 bool setLastIndex(JSGlobalObject* globalObject, JSValue lastIndex, bool shouldThrow)
76 {
77 VM& vm = getVM(globalObject);
78 auto scope = DECLARE_THROW_SCOPE(vm);
79
80 if (LIKELY(lastIndexIsWritable())) {
81 m_lastIndex.set(vm, this, lastIndex);
82 return true;
83 }
84 return typeError(globalObject, scope, shouldThrow, ReadonlyPropertyWriteError);
85 }
86 JSValue getLastIndex() const
87 {
88 return m_lastIndex.get();
89 }
90
91 bool test(JSGlobalObject* globalObject, JSString* string) { return !!match(globalObject, string); }
92 bool testInline(JSGlobalObject* globalObject, JSString* string) { return !!matchInline(globalObject, string); }
93 JSValue exec(JSGlobalObject*, JSString*);
94 JSValue execInline(JSGlobalObject*, JSString*);
95 MatchResult match(JSGlobalObject*, JSString*);
96 JSValue matchGlobal(JSGlobalObject*, JSString*);
97
98 static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
99 static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
100
101 DECLARE_EXPORT_INFO;
102
103 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
104 {
105 return Structure::create(vm, globalObject, prototype, TypeInfo(RegExpObjectType, StructureFlags), info());
106 }
107
108 static ptrdiff_t offsetOfRegExpAndLastIndexIsNotWritableFlag()
109 {
110 return OBJECT_OFFSETOF(RegExpObject, m_regExpAndLastIndexIsNotWritableFlag);
111 }
112
113 static ptrdiff_t offsetOfLastIndex()
114 {
115 return OBJECT_OFFSETOF(RegExpObject, m_lastIndex);
116 }
117
118 static size_t allocationSize(Checked<size_t> inlineCapacity)
119 {
120 ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
121 return sizeof(RegExpObject);
122 }
123
124protected:
125 JS_EXPORT_PRIVATE RegExpObject(VM&, Structure*, RegExp*);
126 JS_EXPORT_PRIVATE void finishCreation(VM&);
127
128 static void visitChildren(JSCell*, SlotVisitor&);
129
130 bool lastIndexIsWritable() const
131 {
132 return !(m_regExpAndLastIndexIsNotWritableFlag & lastIndexIsNotWritableFlag);
133 }
134
135 void setLastIndexIsNotWritable()
136 {
137 m_regExpAndLastIndexIsNotWritableFlag = (m_regExpAndLastIndexIsNotWritableFlag | lastIndexIsNotWritableFlag);
138 }
139
140 JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
141 JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
142 JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
143 JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
144 JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
145
146private:
147 MatchResult matchInline(JSGlobalObject*, JSString*);
148
149 uintptr_t m_regExpAndLastIndexIsNotWritableFlag { 0 };
150 WriteBarrier<Unknown> m_lastIndex;
151};
152
153} // namespace JSC
154