blob: 02b53e00dba293e1cf34a4809af686c1bf6cc216 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "execution.h"
31#include "factory.h"
32#include "jsregexp.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000033#include "platform.h"
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000034#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include "top.h"
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000036#include "compilation-cache.h"
37
38// Including pcre.h undefines DEBUG to avoid getting debug output from
39// the JSCRE implementation. Make sure to redefine it in debug mode
40// after having included the header file.
41#ifdef DEBUG
42#include "third_party/jscre/pcre.h"
43#define DEBUG
44#else
45#include "third_party/jscre/pcre.h"
46#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047
48namespace v8 { namespace internal {
49
50
51#define CAPTURE_INDEX 0
52#define INTERNAL_INDEX 1
53
54static Failure* malloc_failure;
55
56static void* JSREMalloc(size_t size) {
57 Object* obj = Heap::AllocateByteArray(size);
58
59 // If allocation failed, return a NULL pointer to JSRE, and jsRegExpCompile
60 // will return NULL to the caller, performs GC there.
61 // Also pass failure information to the caller.
62 if (obj->IsFailure()) {
63 malloc_failure = Failure::cast(obj);
64 return NULL;
65 }
66
67 // Note: object is unrooted, the caller of jsRegExpCompile must
68 // create a handle for the return value before doing heap allocation.
69 return reinterpret_cast<void*>(ByteArray::cast(obj)->GetDataStartAddress());
70}
71
72
73static void JSREFree(void* p) {
74 USE(p); // Do nothing, memory is garbage collected.
75}
76
77
78String* RegExpImpl::last_ascii_string_ = NULL;
79String* RegExpImpl::two_byte_cached_string_ = NULL;
80
81
82void RegExpImpl::NewSpaceCollectionPrologue() {
83 // The two byte string is always in the old space. The Ascii string may be
84 // in either place. If it is in the old space we don't need to do anything.
85 if (Heap::InNewSpace(last_ascii_string_)) {
86 // Invalidate the cache.
87 last_ascii_string_ = NULL;
88 two_byte_cached_string_ = NULL;
89 }
90}
91
92
93void RegExpImpl::OldSpaceCollectionPrologue() {
94 last_ascii_string_ = NULL;
95 two_byte_cached_string_ = NULL;
96}
97
98
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000099Handle<Object> RegExpImpl::CreateRegExpLiteral(Handle<JSFunction> constructor,
100 Handle<String> pattern,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101 Handle<String> flags,
102 bool* has_pending_exception) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000103 // Ensure that the constructor function has been loaded.
104 if (!constructor->IsLoaded()) {
105 LoadLazy(constructor, has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000106 if (*has_pending_exception) return Handle<Object>(Failure::Exception());
107 }
108 // Call the construct code with 2 arguments.
109 Object** argv[2] = { Handle<Object>::cast(pattern).location(),
110 Handle<Object>::cast(flags).location() };
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000111 return Execution::New(constructor, 2, argv, has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112}
113
114
115// Converts a source string to a 16 bit flat string or a SlicedString containing
116// a 16 bit flat string).
117Handle<String> RegExpImpl::CachedStringToTwoByte(Handle<String> subject) {
118 if (*subject == last_ascii_string_) {
119 ASSERT(two_byte_cached_string_ != NULL);
120 return Handle<String>(String::cast(two_byte_cached_string_));
121 }
122 Handle<String> two_byte_string = StringToTwoByte(subject);
123 last_ascii_string_ = *subject;
124 two_byte_cached_string_ = *two_byte_string;
125 return two_byte_string;
126}
127
128
129// Converts a source string to a 16 bit flat string or a SlicedString containing
130// a 16 bit flat string).
131Handle<String> RegExpImpl::StringToTwoByte(Handle<String> pattern) {
132 if (!pattern->IsFlat()) {
133 FlattenString(pattern);
134 }
135 Handle<String> flat_string(pattern->IsConsString() ?
136 String::cast(ConsString::cast(*pattern)->first()) :
137 *pattern);
138 ASSERT(!flat_string->IsConsString());
139 ASSERT(flat_string->IsSeqString() || flat_string->IsSlicedString() ||
140 flat_string->IsExternalString());
ager@chromium.org7c537e22008-10-16 08:43:32 +0000141 if (!flat_string->IsAsciiRepresentation()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000142 return flat_string;
143 }
144
145 Handle<String> two_byte_string =
146 Factory::NewRawTwoByteString(flat_string->length(), TENURED);
147 static StringInputBuffer convert_to_two_byte_buffer;
148 convert_to_two_byte_buffer.Reset(*flat_string);
149 for (int i = 0; convert_to_two_byte_buffer.has_more(); i++) {
150 two_byte_string->Set(i, convert_to_two_byte_buffer.GetNext());
151 }
152 return two_byte_string;
153}
154
155
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000156static JSRegExp::Flags RegExpFlagsFromString(Handle<String> str) {
157 int flags = JSRegExp::NONE;
158 for (int i = 0; i < str->length(); i++) {
159 switch (str->Get(i)) {
160 case 'i':
161 flags |= JSRegExp::IGNORE_CASE;
162 break;
163 case 'g':
164 flags |= JSRegExp::GLOBAL;
165 break;
166 case 'm':
167 flags |= JSRegExp::MULTILINE;
168 break;
169 }
170 }
171 return JSRegExp::Flags(flags);
172}
173
174
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000175unibrow::Predicate<unibrow::RegExpSpecialChar, 128> is_reg_exp_special_char;
176
177
178Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
179 Handle<String> pattern,
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000180 Handle<String> flag_str) {
181 JSRegExp::Flags flags = RegExpFlagsFromString(flag_str);
182 Handle<FixedArray> cached = CompilationCache::LookupRegExp(pattern, flags);
183 bool in_cache = !cached.is_null();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000184 Handle<Object> result;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000185 if (in_cache) {
186 re->set_data(*cached);
187 result = re;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000188 } else {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000189 bool is_atom = !flags.is_ignore_case();
190 for (int i = 0; is_atom && i < pattern->length(); i++) {
191 if (is_reg_exp_special_char.get(pattern->Get(i)))
192 is_atom = false;
193 }
194 if (is_atom) {
195 result = AtomCompile(re, pattern, flags);
196 } else {
197 result = JsreCompile(re, pattern, flags);
198 }
199 Object* data = re->data();
200 if (data->IsFixedArray()) {
201 // If compilation succeeded then the data is set on the regexp
202 // and we can store it in the cache.
203 Handle<FixedArray> data(FixedArray::cast(re->data()));
204 CompilationCache::PutRegExp(pattern, flags, data);
205 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000206 }
207
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000208 LOG(RegExpCompileEvent(re, in_cache));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000209 return result;
210}
211
212
213Handle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp,
214 Handle<String> subject,
215 Handle<Object> index) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000216 switch (regexp->TypeTag()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000217 case JSRegExp::JSCRE:
218 return JsreExec(regexp, subject, index);
219 case JSRegExp::ATOM:
220 return AtomExec(regexp, subject, index);
221 default:
222 UNREACHABLE();
223 return Handle<Object>();
224 }
225}
226
227
228Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp,
229 Handle<String> subject) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000230 switch (regexp->TypeTag()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000231 case JSRegExp::JSCRE:
232 return JsreExecGlobal(regexp, subject);
233 case JSRegExp::ATOM:
234 return AtomExecGlobal(regexp, subject);
235 default:
236 UNREACHABLE();
237 return Handle<Object>();
238 }
239}
240
241
242Handle<Object> RegExpImpl::AtomCompile(Handle<JSRegExp> re,
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000243 Handle<String> pattern,
244 JSRegExp::Flags flags) {
245 Factory::SetRegExpData(re, JSRegExp::ATOM, pattern, flags, pattern);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000246 return re;
247}
248
249
250Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re,
251 Handle<String> subject,
252 Handle<Object> index) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000253 Handle<String> needle(String::cast(re->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000254
255 uint32_t start_index;
256 if (!Array::IndexFromObject(*index, &start_index)) {
257 return Handle<Smi>(Smi::FromInt(-1));
258 }
259
260 LOG(RegExpExecEvent(re, start_index, subject));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000261 int value = Runtime::StringMatch(subject, needle, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000262 if (value == -1) return Factory::null_value();
ager@chromium.org7c537e22008-10-16 08:43:32 +0000263
264 Handle<FixedArray> array = Factory::NewFixedArray(2);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000265 array->set(0,
266 Smi::FromInt(value),
267 SKIP_WRITE_BARRIER);
268 array->set(1,
269 Smi::FromInt(value + needle->length()),
270 SKIP_WRITE_BARRIER);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000271 return Factory::NewJSArrayWithElements(array);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000272}
273
274
275Handle<Object> RegExpImpl::AtomExecGlobal(Handle<JSRegExp> re,
276 Handle<String> subject) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000277 Handle<String> needle(String::cast(re->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000278 Handle<JSArray> result = Factory::NewJSArray(1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000279 int index = 0;
280 int match_count = 0;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000281 int subject_length = subject->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000282 int needle_length = needle->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +0000283 while (true) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000284 LOG(RegExpExecEvent(re, index, subject));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000285 int value = -1;
286 if (index + needle_length <= subject_length) {
287 value = Runtime::StringMatch(subject, needle, index);
288 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000289 if (value == -1) break;
290 HandleScope scope;
291 int end = value + needle_length;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000292
293 Handle<FixedArray> array = Factory::NewFixedArray(2);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000294 array->set(0,
295 Smi::FromInt(value),
296 SKIP_WRITE_BARRIER);
297 array->set(1,
298 Smi::FromInt(end),
299 SKIP_WRITE_BARRIER);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000300 Handle<JSArray> pair = Factory::NewJSArrayWithElements(array);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000301 SetElement(result, match_count, pair);
302 match_count++;
303 index = end;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000304 if (needle_length == 0) index++;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000305 }
306 return result;
307}
308
309
ager@chromium.org236ad962008-09-25 09:45:57 +0000310Handle<Object> RegExpImpl::JsreCompile(Handle<JSRegExp> re,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000311 Handle<String> pattern,
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000312 JSRegExp::Flags flags) {
313 JSRegExpIgnoreCaseOption case_option = flags.is_ignore_case()
314 ? JSRegExpIgnoreCase
315 : JSRegExpDoNotIgnoreCase;
316 JSRegExpMultilineOption multiline_option = flags.is_multiline()
317 ? JSRegExpMultiline
318 : JSRegExpSingleLine;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000319
320 Handle<String> two_byte_pattern = StringToTwoByte(pattern);
321
322 unsigned number_of_captures;
323 const char* error_message = NULL;
324
ager@chromium.org7c537e22008-10-16 08:43:32 +0000325 JscreRegExp* code = NULL;
326 FlattenString(pattern);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327
ager@chromium.org7c537e22008-10-16 08:43:32 +0000328 bool first_time = true;
329
330 while (true) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000331 malloc_failure = Failure::Exception();
332 code = jsRegExpCompile(two_byte_pattern->GetTwoByteData(),
333 pattern->length(), case_option,
334 multiline_option, &number_of_captures,
335 &error_message, &JSREMalloc, &JSREFree);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000336 if (code == NULL) {
337 if (first_time && malloc_failure->IsRetryAfterGC()) {
338 first_time = false;
339 if (!Heap::CollectGarbage(malloc_failure->requested(),
340 malloc_failure->allocation_space())) {
341 // TODO(1181417): Fix this.
342 V8::FatalProcessOutOfMemory("RegExpImpl::JsreCompile");
343 }
344 continue;
345 }
346 if (malloc_failure->IsRetryAfterGC() ||
347 malloc_failure->IsOutOfMemoryFailure()) {
348 // TODO(1181417): Fix this.
349 V8::FatalProcessOutOfMemory("RegExpImpl::JsreCompile");
350 } else {
351 // Throw an exception.
352 Handle<JSArray> array = Factory::NewJSArray(2);
353 SetElement(array, 0, pattern);
354 SetElement(array, 1, Factory::NewStringFromUtf8(CStrVector(
355 (error_message == NULL) ? "Unknown regexp error" : error_message)));
356 Handle<Object> regexp_err =
357 Factory::NewSyntaxError("malformed_regexp", array);
358 return Handle<Object>(Top::Throw(*regexp_err));
359 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000361
362 ASSERT(code != NULL);
363 // Convert the return address to a ByteArray pointer.
364 Handle<ByteArray> internal(
365 ByteArray::FromDataStartAddress(reinterpret_cast<Address>(code)));
366
367 Handle<FixedArray> value = Factory::NewFixedArray(2);
368 value->set(CAPTURE_INDEX, Smi::FromInt(number_of_captures));
369 value->set(INTERNAL_INDEX, *internal);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000370 Factory::SetRegExpData(re, JSRegExp::JSCRE, pattern, flags, value);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000371
372 return re;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000373 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000374}
375
376
ager@chromium.org236ad962008-09-25 09:45:57 +0000377Handle<Object> RegExpImpl::JsreExecOnce(Handle<JSRegExp> regexp,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000378 int num_captures,
379 Handle<String> subject,
380 int previous_index,
381 const uc16* two_byte_subject,
382 int* offsets_vector,
383 int offsets_vector_length) {
384 int rc;
385 {
386 AssertNoAllocation a;
387 ByteArray* internal = JsreInternal(regexp);
ager@chromium.org236ad962008-09-25 09:45:57 +0000388 const JscreRegExp* js_regexp =
389 reinterpret_cast<JscreRegExp*>(internal->GetDataStartAddress());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000390
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000391 LOG(RegExpExecEvent(regexp, previous_index, subject));
392
ager@chromium.org236ad962008-09-25 09:45:57 +0000393 rc = jsRegExpExecute(js_regexp,
394 two_byte_subject,
395 subject->length(),
396 previous_index,
397 offsets_vector,
398 offsets_vector_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 }
400
401 // The KJS JavaScript engine returns null (ie, a failed match) when
402 // JSRE's internal match limit is exceeded. We duplicate that behavior here.
403 if (rc == JSRegExpErrorNoMatch
404 || rc == JSRegExpErrorHitLimit) {
405 return Factory::null_value();
406 }
407
408 // Other JSRE errors:
409 if (rc < 0) {
410 // Throw an exception.
411 Handle<Object> code(Smi::FromInt(rc));
412 Handle<Object> args[2] = { Factory::LookupAsciiSymbol("jsre_exec"), code };
413 Handle<Object> regexp_err(
414 Factory::NewTypeError("jsre_error", HandleVector(args, 2)));
415 return Handle<Object>(Top::Throw(*regexp_err));
416 }
417
ager@chromium.org7c537e22008-10-16 08:43:32 +0000418 Handle<FixedArray> array = Factory::NewFixedArray(2 * (num_captures+1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000419 // The captures come in (start, end+1) pairs.
420 for (int i = 0; i < 2 * (num_captures+1); i += 2) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000421 array->set(i,
422 Smi::FromInt(offsets_vector[i]),
423 SKIP_WRITE_BARRIER);
424 array->set(i+1,
425 Smi::FromInt(offsets_vector[i+1]),
426 SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000427 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000428 return Factory::NewJSArrayWithElements(array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429}
430
431
432class OffsetsVector {
433 public:
434 inline OffsetsVector(int num_captures) {
435 offsets_vector_length_ = (num_captures + 1) * 3;
436 if (offsets_vector_length_ > kStaticOffsetsVectorSize) {
437 vector_ = NewArray<int>(offsets_vector_length_);
438 } else {
439 vector_ = static_offsets_vector_;
440 }
441 }
442
443
444 inline ~OffsetsVector() {
445 if (offsets_vector_length_ > kStaticOffsetsVectorSize) {
446 DeleteArray(vector_);
447 vector_ = NULL;
448 }
449 }
450
451
452 inline int* vector() {
453 return vector_;
454 }
455
456
457 inline int length() {
458 return offsets_vector_length_;
459 }
460
461 private:
462 int* vector_;
463 int offsets_vector_length_;
464 static const int kStaticOffsetsVectorSize = 30;
465 static int static_offsets_vector_[kStaticOffsetsVectorSize];
466};
467
468
469int OffsetsVector::static_offsets_vector_[
470 OffsetsVector::kStaticOffsetsVectorSize];
471
472
ager@chromium.org236ad962008-09-25 09:45:57 +0000473Handle<Object> RegExpImpl::JsreExec(Handle<JSRegExp> regexp,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000474 Handle<String> subject,
475 Handle<Object> index) {
476 // Prepare space for the return values.
477 int num_captures = JsreCapture(regexp);
478
479 OffsetsVector offsets(num_captures);
480
481 int previous_index = static_cast<int>(DoubleToInteger(index->Number()));
482
483 Handle<String> subject16 = CachedStringToTwoByte(subject);
484
485 Handle<Object> result(JsreExecOnce(regexp, num_captures, subject,
486 previous_index,
487 subject16->GetTwoByteData(),
488 offsets.vector(), offsets.length()));
489
490 return result;
491}
492
493
ager@chromium.org236ad962008-09-25 09:45:57 +0000494Handle<Object> RegExpImpl::JsreExecGlobal(Handle<JSRegExp> regexp,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000495 Handle<String> subject) {
496 // Prepare space for the return values.
497 int num_captures = JsreCapture(regexp);
498
499 OffsetsVector offsets(num_captures);
500
501 int previous_index = 0;
502
ager@chromium.org7c537e22008-10-16 08:43:32 +0000503 Handle<JSArray> result = Factory::NewJSArray(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000504 int i = 0;
505 Handle<Object> matches;
506
507 Handle<String> subject16 = CachedStringToTwoByte(subject);
508
509 do {
510 if (previous_index > subject->length() || previous_index < 0) {
511 // Per ECMA-262 15.10.6.2, if the previous index is greater than the
512 // string length, there is no match.
513 matches = Factory::null_value();
514 } else {
515 matches = JsreExecOnce(regexp, num_captures, subject, previous_index,
516 subject16->GetTwoByteData(),
517 offsets.vector(), offsets.length());
518
519 if (matches->IsJSArray()) {
520 SetElement(result, i, matches);
521 i++;
522 previous_index = offsets.vector()[1];
523 if (offsets.vector()[0] == offsets.vector()[1]) {
524 previous_index++;
525 }
526 }
527 }
528 } while (matches->IsJSArray());
529
530 // If we exited the loop with an exception, throw it.
531 if (matches->IsNull()) { // Exited loop normally.
532 return result;
533 } else { // Exited loop with the exception in matches.
534 return matches;
535 }
536}
537
538
ager@chromium.org236ad962008-09-25 09:45:57 +0000539int RegExpImpl::JsreCapture(Handle<JSRegExp> re) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000540 FixedArray* value = FixedArray::cast(re->DataAt(JSRegExp::kJscreDataIndex));
541 return Smi::cast(value->get(CAPTURE_INDEX))->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000542}
543
544
ager@chromium.org236ad962008-09-25 09:45:57 +0000545ByteArray* RegExpImpl::JsreInternal(Handle<JSRegExp> re) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000546 FixedArray* value = FixedArray::cast(re->DataAt(JSRegExp::kJscreDataIndex));
547 return ByteArray::cast(value->get(INTERNAL_INDEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548}
549
550}} // namespace v8::internal