We should support CreateThis in the FTL
[WebKit-https.git] / Source / JavaScriptCore / runtime / RegExpConstructor.h
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2003-2018 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 "InternalFunction.h"
24 #include "RegExp.h"
25 #include "RegExpCachedResult.h"
26 #include "RegExpObject.h"
27
28 namespace JSC {
29
30 class RegExpPrototype;
31 class GetterSetter;
32
33 class RegExpConstructor final : public InternalFunction {
34 public:
35     typedef InternalFunction Base;
36     static const unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable;
37
38     template<typename CellType>
39     static IsoSubspace* subspaceFor(VM& vm)
40     {
41         return &vm.regExpConstructorSpace;
42     }
43
44     static RegExpConstructor* create(VM& vm, Structure* structure, RegExpPrototype* regExpPrototype, GetterSetter* species)
45     {
46         RegExpConstructor* constructor = new (NotNull, allocateCell<RegExpConstructor>(vm.heap)) RegExpConstructor(vm, structure, regExpPrototype);
47         constructor->finishCreation(vm, regExpPrototype, species);
48         return constructor;
49     }
50
51     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
52     {
53         return Structure::create(vm, globalObject, prototype, TypeInfo(InternalFunctionType, StructureFlags), info());
54     }
55
56     DECLARE_INFO;
57
58     MatchResult performMatch(VM&, RegExp*, JSString*, const String&, int startOffset, int** ovector);
59     MatchResult performMatch(VM&, RegExp*, JSString*, const String&, int startOffset);
60     void recordMatch(VM&, RegExp*, JSString*, const MatchResult&);
61
62     void setMultiline(bool multiline) { m_multiline = multiline; }
63     bool multiline() const { return m_multiline; }
64
65     JSValue getBackref(ExecState*, unsigned);
66     JSValue getLastParen(ExecState*);
67     JSValue getLeftContext(ExecState*);
68     JSValue getRightContext(ExecState*);
69
70     void setInput(ExecState* exec, JSString* string) { m_cachedResult.setInput(exec, this, string); }
71     JSString* input() { return m_cachedResult.input(); }
72
73     static void visitChildren(JSCell*, SlotVisitor&);
74
75     static ptrdiff_t offsetOfCachedResult() { return OBJECT_OFFSETOF(RegExpConstructor, m_cachedResult); }
76
77 protected:
78     void finishCreation(VM&, RegExpPrototype*, GetterSetter* species);
79
80 private:
81     RegExpConstructor(VM&, Structure*, RegExpPrototype*);
82     static void destroy(JSCell*);
83
84     RegExpCachedResult m_cachedResult;
85     bool m_multiline;
86     Vector<int> m_ovector;
87 };
88
89 JSObject* constructRegExp(ExecState*, JSGlobalObject*, const ArgList&, JSObject* callee = nullptr, JSValue newTarget = jsUndefined());
90
91 /* 
92    To facilitate result caching, exec(), test(), match(), search(), and replace() dipatch regular
93    expression matching through the performMatch function. We use cached results to calculate, 
94    e.g., RegExp.lastMatch and RegExp.leftParen.
95 */
96 ALWAYS_INLINE MatchResult RegExpConstructor::performMatch(VM& vm, RegExp* regExp, JSString* string, const String& input, int startOffset, int** ovector)
97 {
98     int position = regExp->match(vm, input, startOffset, m_ovector);
99
100     if (ovector)
101         *ovector = m_ovector.data();
102
103     if (position == -1)
104         return MatchResult::failed();
105
106     ASSERT(!m_ovector.isEmpty());
107     ASSERT(m_ovector[0] == position);
108     ASSERT(m_ovector[1] >= position);
109     size_t end = m_ovector[1];
110
111     m_cachedResult.record(vm, this, regExp, string, MatchResult(position, end));
112
113     return MatchResult(position, end);
114 }
115 ALWAYS_INLINE MatchResult RegExpConstructor::performMatch(VM& vm, RegExp* regExp, JSString* string, const String& input, int startOffset)
116 {
117     MatchResult result = regExp->match(vm, input, startOffset);
118     if (result)
119         m_cachedResult.record(vm, this, regExp, string, result);
120     return result;
121 }
122
123 ALWAYS_INLINE void RegExpConstructor::recordMatch(VM& vm, RegExp* regExp, JSString* string, const MatchResult& result)
124 {
125     ASSERT(result);
126     m_cachedResult.record(vm, this, regExp, string, result);
127 }
128
129 ALWAYS_INLINE bool isRegExp(VM& vm, ExecState* exec, JSValue value)
130 {
131     auto scope = DECLARE_THROW_SCOPE(vm);
132     if (!value.isObject())
133         return false;
134
135     JSObject* object = asObject(value);
136     JSValue matchValue = object->get(exec, vm.propertyNames->matchSymbol);
137     RETURN_IF_EXCEPTION(scope, false);
138     if (!matchValue.isUndefined())
139         return matchValue.toBoolean(exec);
140
141     return object->inherits<RegExpObject>(vm);
142 }
143
144 EncodedJSValue JSC_HOST_CALL esSpecRegExpCreate(ExecState*);
145
146 } // namespace JSC