blob: 4b2c3f235c32731dad087b0f9e855f654c5b6397 [file] [log] [blame]
mjs@apple.com52b67602008-09-22 03:15:52 +00001/*
mark.lam@apple.com6b810292021-11-11 17:31:37 +00002 * Copyright (C) 2008-2021 Apple Inc. All Rights Reserved.
mjs@apple.com52b67602008-09-22 03:15:52 +00003 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 */
19
ryanhaddad@apple.com22104f52016-09-28 17:08:17 +000020#pragma once
mjs@apple.com52b67602008-09-22 03:15:52 +000021
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +000022#include "ButterflyInlines.h"
fpizlo@apple.com9a175952016-09-28 21:55:53 +000023#include "GCDeferralContextInlines.h"
mjs@apple.com52b67602008-09-22 03:15:52 +000024#include "JSArray.h"
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +000025#include "JSCInlines.h"
barraclough@apple.com0a0af1a2012-03-23 19:57:28 +000026#include "JSGlobalObject.h"
commit-queue@webkit.orgf78337d2019-11-12 22:09:37 +000027#include "ObjectConstructor.h"
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +000028#include "RegExpInlines.h"
barraclough@apple.com0a0af1a2012-03-23 19:57:28 +000029#include "RegExpObject.h"
mjs@apple.com52b67602008-09-22 03:15:52 +000030
31namespace JSC {
32
ysuzuki@apple.come5fb32b2022-04-22 05:41:35 +000033static constexpr PropertyOffset RegExpMatchesArrayIndexPropertyOffset = firstOutOfLineOffset;
34static constexpr PropertyOffset RegExpMatchesArrayInputPropertyOffset = firstOutOfLineOffset + 1;
35static constexpr PropertyOffset RegExpMatchesArrayGroupsPropertyOffset = firstOutOfLineOffset + 2;
36static constexpr PropertyOffset RegExpMatchesArrayIndicesPropertyOffset = firstOutOfLineOffset + 3;
37static constexpr PropertyOffset RegExpMatchesIndicesGroupsPropertyOffset = firstOutOfLineOffset;
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +000038
mark.lam@apple.com21476402017-04-27 19:24:07 +000039ALWAYS_INLINE JSArray* tryCreateUninitializedRegExpMatchesArray(ObjectInitializationScope& scope, GCDeferralContext* deferralContext, Structure* structure, unsigned initialLength)
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +000040{
mark.lam@apple.com21476402017-04-27 19:24:07 +000041 VM& vm = scope.vm();
fpizlo@apple.combc16ddb2016-09-06 01:02:22 +000042 unsigned vectorLength = initialLength;
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +000043 if (vectorLength > MAX_STORAGE_VECTOR_LENGTH)
ross.kirsling@sony.com2abe6c62020-05-11 02:36:05 +000044 return nullptr;
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +000045
keith_miller@apple.com66c57652018-06-18 23:53:27 +000046 const bool hasIndexingHeader = true;
47 Butterfly* butterfly = Butterfly::tryCreateUninitialized(vm, nullptr, 0, structure->outOfLineCapacity(), hasIndexingHeader, vectorLength * sizeof(EncodedJSValue), deferralContext);
48 if (UNLIKELY(!butterfly))
fpizlo@apple.combc16ddb2016-09-06 01:02:22 +000049 return nullptr;
keith_miller@apple.com66c57652018-06-18 23:53:27 +000050
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +000051 butterfly->setVectorLength(vectorLength);
52 butterfly->setPublicLength(initialLength);
mark.lam@apple.com21476402017-04-27 19:24:07 +000053
keith_miller@apple.com66c57652018-06-18 23:53:27 +000054 for (unsigned i = initialLength; i < vectorLength; ++i)
keith_miller@apple.comc02f5d32018-05-22 18:04:31 +000055 butterfly->contiguous().atUnsafe(i).clear();
mark.lam@apple.com21476402017-04-27 19:24:07 +000056
57 JSArray* result = JSArray::createWithButterfly(vm, deferralContext, structure, butterfly);
keith_miller@apple.com66c57652018-06-18 23:53:27 +000058
mark.lam@apple.com35ad20b2020-07-22 01:40:59 +000059 scope.notifyAllocated(result);
mark.lam@apple.com21476402017-04-27 19:24:07 +000060 return result;
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +000061}
62
63ALWAYS_INLINE JSArray* createRegExpMatchesArray(
64 VM& vm, JSGlobalObject* globalObject, JSString* input, const String& inputValue,
65 RegExp* regExp, unsigned startOffset, MatchResult& result)
66{
mark.lam@apple.com4b9b5c62020-06-04 21:07:42 +000067 if constexpr (validateDFGDoesGC)
mark.lam@apple.com6b810292021-11-11 17:31:37 +000068 vm.verifyCanGC();
mark.lam@apple.com8eafba52019-02-22 02:02:32 +000069
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +000070 Vector<int, 32> subpatternResults;
ysuzuki@apple.comf99e5d82020-04-08 20:01:39 +000071 int position = regExp->matchInline(globalObject, vm, inputValue, startOffset, subpatternResults);
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +000072 if (position == -1) {
73 result = MatchResult::failed();
74 return nullptr;
75 }
76
77 result.start = position;
78 result.end = subpatternResults[1];
79
80 JSArray* array;
msaboff@apple.comdd96c362021-02-18 19:14:34 +000081 JSArray* indicesArray = nullptr;
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +000082
83 // FIXME: This should handle array allocation errors gracefully.
84 // https://bugs.webkit.org/show_bug.cgi?id=155144
85
msaboff@apple.com8e26fe22017-09-07 23:13:38 +000086 unsigned numSubpatterns = regExp->numSubpatterns();
87 bool hasNamedCaptures = regExp->hasNamedCaptures();
msaboff@apple.comdd96c362021-02-18 19:14:34 +000088 bool createIndices = regExp->hasIndices();
commit-queue@webkit.orgf78337d2019-11-12 22:09:37 +000089 JSObject* groups = hasNamedCaptures ? constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure()) : nullptr;
msaboff@apple.comdd96c362021-02-18 19:14:34 +000090 Structure* matchStructure = createIndices ? globalObject->regExpMatchesArrayWithIndicesStructure() : globalObject->regExpMatchesArrayStructure();
91
92 JSObject* indicesGroups = createIndices && hasNamedCaptures ? constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure()) : nullptr;
msaboff@apple.com8e26fe22017-09-07 23:13:38 +000093
fpizlo@apple.combc16ddb2016-09-06 01:02:22 +000094 auto setProperties = [&] () {
95 array->putDirect(vm, RegExpMatchesArrayIndexPropertyOffset, jsNumber(result.start));
96 array->putDirect(vm, RegExpMatchesArrayInputPropertyOffset, input);
commit-queue@webkit.orgf78337d2019-11-12 22:09:37 +000097 array->putDirect(vm, RegExpMatchesArrayGroupsPropertyOffset, hasNamedCaptures ? groups : jsUndefined());
keith_miller@apple.com66c57652018-06-18 23:53:27 +000098
99 ASSERT(!array->butterfly()->indexingHeader()->preCapacity(matchStructure));
100 auto capacity = matchStructure->outOfLineCapacity();
101 auto size = matchStructure->outOfLineSize();
sbarati@apple.com64b84492019-11-04 23:57:34 +0000102 gcSafeZeroMemory(static_cast<JSValue*>(array->butterfly()->base(0, capacity)), (capacity - size) * sizeof(JSValue));
msaboff@apple.comdd96c362021-02-18 19:14:34 +0000103
104 if (createIndices) {
105 array->putDirect(vm, RegExpMatchesArrayIndicesPropertyOffset, indicesArray);
106
107 Structure* indicesStructure = globalObject->regExpMatchesIndicesArrayStructure();
108
msaboff@apple.com51fb24b2021-02-19 20:50:48 +0000109 indicesArray->putDirect(vm, RegExpMatchesIndicesGroupsPropertyOffset, indicesGroups ? indicesGroups : jsUndefined());
msaboff@apple.comdd96c362021-02-18 19:14:34 +0000110
111 ASSERT(!indicesArray->butterfly()->indexingHeader()->preCapacity(indicesStructure));
112 auto indicesCapacity = indicesStructure->outOfLineCapacity();
113 auto indicesSize = indicesStructure->outOfLineSize();
114 gcSafeZeroMemory(static_cast<JSValue*>(indicesArray->butterfly()->base(0, indicesCapacity)), (indicesCapacity - indicesSize) * sizeof(JSValue));
115 }
116 };
117
118 auto createIndexArray = [&] (GCDeferralContext& deferralContext, int start, int end) {
119 ObjectInitializationScope scope(vm);
120
121 JSArray* result = JSArray::tryCreateUninitializedRestricted(scope, &deferralContext, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), 2);
122 result->initializeIndexWithoutBarrier(scope, 0, jsNumber(start));
123 result->initializeIndexWithoutBarrier(scope, 1, jsNumber(end));
124
125 return result;
fpizlo@apple.combc16ddb2016-09-06 01:02:22 +0000126 };
msaboff@apple.com8e26fe22017-09-07 23:13:38 +0000127
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +0000128 if (UNLIKELY(globalObject->isHavingABadTime())) {
mark.lam@apple.com6b810292021-11-11 17:31:37 +0000129 GCDeferralContext deferralContext(vm);
msaboff@apple.comdd96c362021-02-18 19:14:34 +0000130 ObjectInitializationScope matchesArrayScope(vm);
131 ObjectInitializationScope indicesArrayScope(vm);
132 array = JSArray::tryCreateUninitializedRestricted(matchesArrayScope, &deferralContext, matchStructure, numSubpatterns + 1);
133
134 if (createIndices)
135 indicesArray = JSArray::tryCreateUninitializedRestricted(indicesArrayScope, &deferralContext, globalObject->regExpMatchesIndicesArrayStructure(), numSubpatterns + 1);
keith_miller@apple.com66c57652018-06-18 23:53:27 +0000136
mark.lam@apple.comc2e98e82017-03-23 20:31:18 +0000137 // FIXME: we should probably throw an out of memory error here, but
138 // when making this change we should check that all clients of this
139 // function will correctly handle an exception being thrown from here.
140 // https://bugs.webkit.org/show_bug.cgi?id=169786
141 RELEASE_ASSERT(array);
142
fpizlo@apple.combc16ddb2016-09-06 01:02:22 +0000143 setProperties();
144
msaboff@apple.comdd96c362021-02-18 19:14:34 +0000145 array->initializeIndexWithoutBarrier(matchesArrayScope, 0, jsSubstringOfResolved(vm, &deferralContext, input, result.start, result.end - result.start));
146
fpizlo@apple.combc16ddb2016-09-06 01:02:22 +0000147 for (unsigned i = 1; i <= numSubpatterns; ++i) {
148 int start = subpatternResults[2 * i];
fpizlo@apple.com9a175952016-09-28 21:55:53 +0000149 JSValue value;
fpizlo@apple.combc16ddb2016-09-06 01:02:22 +0000150 if (start >= 0)
ysuzuki@apple.comcb663b32019-03-01 03:13:31 +0000151 value = jsSubstringOfResolved(vm, &deferralContext, input, start, subpatternResults[2 * i + 1] - start);
fpizlo@apple.com9a175952016-09-28 21:55:53 +0000152 else
153 value = jsUndefined();
msaboff@apple.comdd96c362021-02-18 19:14:34 +0000154 array->initializeIndexWithoutBarrier(matchesArrayScope, i, value);
155 }
156
157 if (createIndices) {
158 for (unsigned i = 0; i <= numSubpatterns; ++i) {
159 int start = subpatternResults[2 * i];
160 JSValue value;
161 if (start >= 0)
162 indicesArray->initializeIndexWithoutBarrier(indicesArrayScope, i, createIndexArray(deferralContext, start, subpatternResults[2 * i + 1]));
163 else
164 indicesArray->initializeIndexWithoutBarrier(indicesArrayScope, i, jsUndefined());
165 }
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +0000166 }
167 } else {
mark.lam@apple.com6b810292021-11-11 17:31:37 +0000168 GCDeferralContext deferralContext(vm);
msaboff@apple.comdd96c362021-02-18 19:14:34 +0000169 ObjectInitializationScope matchesArrayScope(vm);
170 ObjectInitializationScope indicesArrayScope(vm);
171 array = tryCreateUninitializedRegExpMatchesArray(matchesArrayScope, &deferralContext, matchStructure, numSubpatterns + 1);
172
173 if (createIndices)
174 indicesArray = tryCreateUninitializedRegExpMatchesArray(indicesArrayScope, &deferralContext, globalObject->regExpMatchesIndicesArrayStructure(), numSubpatterns + 1);
keith_miller@apple.com66c57652018-06-18 23:53:27 +0000175
176 // FIXME: we should probably throw an out of memory error here, but
177 // when making this change we should check that all clients of this
178 // function will correctly handle an exception being thrown from here.
179 // https://bugs.webkit.org/show_bug.cgi?id=169786
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +0000180 RELEASE_ASSERT(array);
181
fpizlo@apple.combc16ddb2016-09-06 01:02:22 +0000182 setProperties();
183
msaboff@apple.comdd96c362021-02-18 19:14:34 +0000184 array->initializeIndexWithoutBarrier(matchesArrayScope, 0, jsSubstringOfResolved(vm, &deferralContext, input, result.start, result.end - result.start), ArrayWithContiguous);
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +0000185
fpizlo@apple.combc16ddb2016-09-06 01:02:22 +0000186 for (unsigned i = 1; i <= numSubpatterns; ++i) {
187 int start = subpatternResults[2 * i];
fpizlo@apple.com9a175952016-09-28 21:55:53 +0000188 JSValue value;
fpizlo@apple.combc16ddb2016-09-06 01:02:22 +0000189 if (start >= 0)
ysuzuki@apple.comcb663b32019-03-01 03:13:31 +0000190 value = jsSubstringOfResolved(vm, &deferralContext, input, start, subpatternResults[2 * i + 1] - start);
fpizlo@apple.com9a175952016-09-28 21:55:53 +0000191 else
192 value = jsUndefined();
msaboff@apple.comdd96c362021-02-18 19:14:34 +0000193 array->initializeIndexWithoutBarrier(matchesArrayScope, i, value, ArrayWithContiguous);
194 }
195
196 if (createIndices) {
197 for (unsigned i = 0; i <= numSubpatterns; ++i) {
198 int start = subpatternResults[2 * i];
199 JSValue value;
200 if (start >= 0)
201 indicesArray->initializeIndexWithoutBarrier(indicesArrayScope, i, createIndexArray(deferralContext, start, subpatternResults[2 * i + 1]));
202 else
203 indicesArray->initializeIndexWithoutBarrier(indicesArrayScope, i, jsUndefined());
204 }
keith_miller@apple.com66c57652018-06-18 23:53:27 +0000205 }
206 }
207
208 // Now the object is safe to scan by GC.
209
msaboff@apple.comdd96c362021-02-18 19:14:34 +0000210 // We initialize the groups and indices objects late as they could allocate, which with the current API could cause
keith_miller@apple.com66c57652018-06-18 23:53:27 +0000211 // allocations.
commit-queue@webkit.orgf78337d2019-11-12 22:09:37 +0000212 if (hasNamedCaptures) {
keith_miller@apple.com66c57652018-06-18 23:53:27 +0000213 for (unsigned i = 1; i <= numSubpatterns; ++i) {
214 String groupName = regExp->getCaptureGroupName(i);
msaboff@apple.comdd96c362021-02-18 19:14:34 +0000215 if (!groupName.isEmpty()) {
mark.lam@apple.com5ba07792019-08-27 22:14:52 +0000216 groups->putDirect(vm, Identifier::fromString(vm, groupName), array->getIndexQuickly(i));
msaboff@apple.comdd96c362021-02-18 19:14:34 +0000217 if (createIndices)
218 indicesGroups->putDirect(vm, Identifier::fromString(vm, groupName), indicesArray->getIndexQuickly(i));
219 }
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +0000220 }
221 }
msaboff@apple.comdd96c362021-02-18 19:14:34 +0000222
fpizlo@apple.com6ea42db2016-03-08 21:15:07 +0000223 return array;
224}
225
ysuzuki@apple.com52e98bb2019-10-22 09:24:48 +0000226inline JSArray* createRegExpMatchesArray(JSGlobalObject* globalObject, JSString* string, RegExp* regExp, unsigned startOffset)
fpizlo@apple.com68cf74d2016-03-08 00:34:44 +0000227{
ysuzuki@apple.com52e98bb2019-10-22 09:24:48 +0000228 VM& vm = getVM(globalObject);
ysuzuki@apple.com782a6d32019-09-28 03:40:23 +0000229 auto scope = DECLARE_THROW_SCOPE(vm);
230
fpizlo@apple.com68cf74d2016-03-08 00:34:44 +0000231 MatchResult ignoredResult;
ysuzuki@apple.com52e98bb2019-10-22 09:24:48 +0000232 String input = string->value(globalObject);
ysuzuki@apple.com782a6d32019-09-28 03:40:23 +0000233 RETURN_IF_EXCEPTION(scope, { });
234
ysuzuki@apple.com7c2addb2022-04-11 04:57:33 +0000235 RELEASE_AND_RETURN(scope, createRegExpMatchesArray(vm, globalObject, string, WTFMove(input), regExp, startOffset, ignoredResult));
fpizlo@apple.com68cf74d2016-03-08 00:34:44 +0000236}
237JSArray* createEmptyRegExpMatchesArray(JSGlobalObject*, JSString*, RegExp*);
fpizlo@apple.com7518ba22016-03-06 20:11:09 +0000238Structure* createRegExpMatchesArrayStructure(VM&, JSGlobalObject*);
msaboff@apple.comdd96c362021-02-18 19:14:34 +0000239Structure* createRegExpMatchesArrayWithIndicesStructure(VM&, JSGlobalObject*);
240Structure* createRegExpMatchesIndicesArrayStructure(VM&, JSGlobalObject*);
fpizlo@apple.com7518ba22016-03-06 20:11:09 +0000241Structure* createRegExpMatchesArraySlowPutStructure(VM&, JSGlobalObject*);
msaboff@apple.comdd96c362021-02-18 19:14:34 +0000242Structure* createRegExpMatchesArrayWithIndicesSlowPutStructure(VM&, JSGlobalObject*);
243Structure* createRegExpMatchesIndicesArraySlowPutStructure(VM&, JSGlobalObject*);
akling@apple.com24400d22014-05-23 22:13:50 +0000244
ryanhaddad@apple.com22104f52016-09-28 17:08:17 +0000245} // namespace JSC