blob: 2ce5cfb12af41ba5d7426d6d08abf42ccdfd8dd9 [file] [log] [blame]
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.orga74f0da2008-12-03 16:05:52 +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
ager@chromium.orga74f0da2008-12-03 16:05:52 +000028#include "v8.h"
29#include "ast.h"
30#include "assembler.h"
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000031#include "regexp-stack.h"
ager@chromium.orga74f0da2008-12-03 16:05:52 +000032#include "regexp-macro-assembler.h"
ager@chromium.orgc4c92722009-11-18 14:12:51 +000033#include "simulator.h"
ager@chromium.orga74f0da2008-12-03 16:05:52 +000034
kasperl@chromium.org71affb52009-05-26 05:44:31 +000035namespace v8 {
36namespace internal {
ager@chromium.orga74f0da2008-12-03 16:05:52 +000037
mmassi@chromium.org7028c052012-06-13 11:51:58 +000038RegExpMacroAssembler::RegExpMacroAssembler(Zone* zone)
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +000039 : slow_safe_compiler_(false),
mmassi@chromium.org7028c052012-06-13 11:51:58 +000040 global_mode_(NOT_GLOBAL),
41 zone_(zone) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +000042}
43
44
45RegExpMacroAssembler::~RegExpMacroAssembler() {
46}
47
48
ager@chromium.org18ad94b2009-09-02 08:22:29 +000049bool RegExpMacroAssembler::CanReadUnaligned() {
50#ifdef V8_HOST_CAN_READ_UNALIGNED
51 return true;
52#else
53 return false;
54#endif
55}
56
57
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000058#ifndef V8_INTERPRETED_REGEXP // Avoid unused code, e.g., on ARM.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000059
mmassi@chromium.org7028c052012-06-13 11:51:58 +000060NativeRegExpMacroAssembler::NativeRegExpMacroAssembler(Zone* zone)
61 : RegExpMacroAssembler(zone) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000062}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000063
64
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000065NativeRegExpMacroAssembler::~NativeRegExpMacroAssembler() {
66}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000067
ager@chromium.org18ad94b2009-09-02 08:22:29 +000068
69bool NativeRegExpMacroAssembler::CanReadUnaligned() {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000070 return FLAG_enable_unaligned_accesses && !slow_safe();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000071}
72
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000073const byte* NativeRegExpMacroAssembler::StringCharacterPosition(
74 String* subject,
75 int start_index) {
76 // Not just flat, but ultra flat.
77 ASSERT(subject->IsExternalString() || subject->IsSeqString());
78 ASSERT(start_index >= 0);
79 ASSERT(start_index <= subject->length());
80 if (subject->IsAsciiRepresentation()) {
81 const byte* address;
82 if (StringShape(subject).IsExternal()) {
erikcorry0ad885c2011-11-21 13:51:57 +000083 const char* data = ExternalAsciiString::cast(subject)->GetChars();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000084 address = reinterpret_cast<const byte*>(data);
85 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000086 ASSERT(subject->IsSeqOneByteString());
87 char* data = SeqOneByteString::cast(subject)->GetChars();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000088 address = reinterpret_cast<const byte*>(data);
ager@chromium.orga74f0da2008-12-03 16:05:52 +000089 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000090 return address + start_index;
ager@chromium.orga74f0da2008-12-03 16:05:52 +000091 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000092 const uc16* data;
93 if (StringShape(subject).IsExternal()) {
erikcorry0ad885c2011-11-21 13:51:57 +000094 data = ExternalTwoByteString::cast(subject)->GetChars();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000095 } else {
96 ASSERT(subject->IsSeqTwoByteString());
97 data = SeqTwoByteString::cast(subject)->GetChars();
98 }
99 return reinterpret_cast<const byte*>(data + start_index);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000100}
101
ager@chromium.org32912102009-01-16 10:38:43 +0000102
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000103NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Match(
104 Handle<Code> regexp_code,
105 Handle<String> subject,
106 int* offsets_vector,
107 int offsets_vector_length,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000108 int previous_index,
109 Isolate* isolate) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000110
111 ASSERT(subject->IsFlat());
112 ASSERT(previous_index >= 0);
113 ASSERT(previous_index <= subject->length());
114
115 // No allocations before calling the regexp, but we can't use
116 // AssertNoAllocation, since regexps might be preempted, and another thread
117 // might do allocation anyway.
118
119 String* subject_ptr = *subject;
120 // Character offsets into string.
121 int start_offset = previous_index;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000122 int char_length = subject_ptr->length() - start_offset;
123 int slice_offset = 0;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000124
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000125 // The string has been flattened, so if it is a cons string it contains the
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126 // full string in the first part.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000127 if (StringShape(subject_ptr).IsCons()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000128 ASSERT_EQ(0, ConsString::cast(subject_ptr)->second()->length());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000129 subject_ptr = ConsString::cast(subject_ptr)->first();
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000130 } else if (StringShape(subject_ptr).IsSliced()) {
131 SlicedString* slice = SlicedString::cast(subject_ptr);
132 subject_ptr = slice->parent();
133 slice_offset = slice->offset();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000134 }
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000135 // Ensure that an underlying string has the same ASCII-ness.
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000136 bool is_ascii = subject_ptr->IsAsciiRepresentation();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000137 ASSERT(subject_ptr->IsExternalString() || subject_ptr->IsSeqString());
138 // String is now either Sequential or External
139 int char_size_shift = is_ascii ? 0 : 1;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000140
141 const byte* input_start =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000142 StringCharacterPosition(subject_ptr, start_offset + slice_offset);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000143 int byte_length = char_length << char_size_shift;
144 const byte* input_end = input_start + byte_length;
145 Result res = Execute(*regexp_code,
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000146 *subject,
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000147 start_offset,
148 input_start,
149 input_end,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000150 offsets_vector,
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000151 offsets_vector_length,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000152 isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000153 return res;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000154}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000155
156
157NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Execute(
158 Code* code,
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000159 String* input, // This needs to be the unpacked (sliced, cons) string.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000160 int start_offset,
161 const byte* input_start,
162 const byte* input_end,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000163 int* output,
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000164 int output_size,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000165 Isolate* isolate) {
166 ASSERT(isolate == Isolate::Current());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000167 // Ensure that the minimum stack has been allocated.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000168 RegExpStackScope stack_scope(isolate);
169 Address stack_base = stack_scope.stack()->stack_base();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000170
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000171 int direct_call = 0;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000172 int result = CALL_GENERATED_REGEXP_CODE(code->entry(),
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000173 input,
174 start_offset,
175 input_start,
176 input_end,
177 output,
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000178 output_size,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000179 stack_base,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000180 direct_call,
181 isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000182 ASSERT(result >= RETRY);
183
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000184 if (result == EXCEPTION && !isolate->has_pending_exception()) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000185 // We detected a stack overflow (on the backtrack stack) in RegExp code,
186 // but haven't created the exception yet.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000187 isolate->StackOverflow();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000188 }
189 return static_cast<Result>(result);
190}
191
192
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000193const byte NativeRegExpMacroAssembler::word_character_map[] = {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000194 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
195 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
196 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
197 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
198
199 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
200 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
201 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, // '0' - '7'
202 0xffu, 0xffu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, // '8' - '9'
203
204 0x00u, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, // 'A' - 'G'
205 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, // 'H' - 'O'
206 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, // 'P' - 'W'
207 0xffu, 0xffu, 0xffu, 0x00u, 0x00u, 0x00u, 0x00u, 0xffu, // 'X' - 'Z', '_'
208
209 0x00u, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, // 'a' - 'g'
210 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, // 'h' - 'o'
211 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, // 'p' - 'w'
212 0xffu, 0xffu, 0xffu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, // 'x' - 'z'
213};
214
215
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000216int NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16(
217 Address byte_offset1,
218 Address byte_offset2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000219 size_t byte_length,
220 Isolate* isolate) {
221 ASSERT(isolate == Isolate::Current());
222 unibrow::Mapping<unibrow::Ecma262Canonicalize>* canonicalize =
223 isolate->regexp_macro_assembler_canonicalize();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000224 // This function is not allowed to cause a garbage collection.
225 // A GC might move the calling generated code and invalidate the
226 // return address on the stack.
227 ASSERT(byte_length % 2 == 0);
228 uc16* substring1 = reinterpret_cast<uc16*>(byte_offset1);
229 uc16* substring2 = reinterpret_cast<uc16*>(byte_offset2);
230 size_t length = byte_length >> 1;
231
232 for (size_t i = 0; i < length; i++) {
233 unibrow::uchar c1 = substring1[i];
234 unibrow::uchar c2 = substring2[i];
235 if (c1 != c2) {
236 unibrow::uchar s1[1] = { c1 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000237 canonicalize->get(c1, '\0', s1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000238 if (s1[0] != c2) {
239 unibrow::uchar s2[1] = { c2 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000240 canonicalize->get(c2, '\0', s2);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000241 if (s1[0] != s2[0]) {
242 return 0;
243 }
244 }
245 }
246 }
247 return 1;
248}
249
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000250
251Address NativeRegExpMacroAssembler::GrowStack(Address stack_pointer,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000252 Address* stack_base,
253 Isolate* isolate) {
254 ASSERT(isolate == Isolate::Current());
255 RegExpStack* regexp_stack = isolate->regexp_stack();
256 size_t size = regexp_stack->stack_capacity();
257 Address old_stack_base = regexp_stack->stack_base();
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000258 ASSERT(old_stack_base == *stack_base);
259 ASSERT(stack_pointer <= old_stack_base);
260 ASSERT(static_cast<size_t>(old_stack_base - stack_pointer) <= size);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000261 Address new_stack_base = regexp_stack->EnsureCapacity(size * 2);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000262 if (new_stack_base == NULL) {
263 return NULL;
264 }
265 *stack_base = new_stack_base;
266 intptr_t stack_content_size = old_stack_base - stack_pointer;
267 return new_stack_base - stack_content_size;
268}
269
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000270#endif // V8_INTERPRETED_REGEXP
271
ager@chromium.org32912102009-01-16 10:38:43 +0000272} } // namespace v8::internal