Always update raw pointers when handling interrupts inside RegExp code.
R=mstarzinger@chromium.org BUG=chromium:469480 LOG=N Review URL: https://codereview.chromium.org/1034173002 Cr-Commit-Position: refs/heads/master@{#27615}
This commit is contained in:
parent
146598f44a
commit
c67cb287a9
@ -1040,102 +1040,22 @@ static T& frame_entry(Address re_frame, int frame_offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static T* frame_entry_address(Address re_frame, int frame_offset) {
|
||||||
|
return reinterpret_cast<T*>(re_frame + frame_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
|
int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
|
||||||
Code* re_code,
|
Code* re_code,
|
||||||
Address re_frame) {
|
Address re_frame) {
|
||||||
Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
|
return NativeRegExpMacroAssembler::CheckStackGuardState(
|
||||||
StackLimitCheck check(isolate);
|
frame_entry<Isolate*>(re_frame, kIsolate),
|
||||||
if (check.JsHasOverflowed()) {
|
frame_entry<int>(re_frame, kStartIndex),
|
||||||
isolate->StackOverflow();
|
frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
|
||||||
return EXCEPTION;
|
frame_entry_address<String*>(re_frame, kInputString),
|
||||||
}
|
frame_entry_address<const byte*>(re_frame, kInputStart),
|
||||||
|
frame_entry_address<const byte*>(re_frame, kInputEnd));
|
||||||
// If not real stack overflow the stack guard was used to interrupt
|
|
||||||
// execution for another purpose.
|
|
||||||
|
|
||||||
// If this is a direct call from JavaScript retry the RegExp forcing the call
|
|
||||||
// through the runtime system. Currently the direct call cannot handle a GC.
|
|
||||||
if (frame_entry<int>(re_frame, kDirectCall) == 1) {
|
|
||||||
return RETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare for possible GC.
|
|
||||||
HandleScope handles(isolate);
|
|
||||||
Handle<Code> code_handle(re_code);
|
|
||||||
|
|
||||||
Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
|
|
||||||
|
|
||||||
// Current string.
|
|
||||||
bool is_one_byte = subject->IsOneByteRepresentationUnderneath();
|
|
||||||
|
|
||||||
DCHECK(re_code->instruction_start() <= *return_address);
|
|
||||||
DCHECK(*return_address <=
|
|
||||||
re_code->instruction_start() + re_code->instruction_size());
|
|
||||||
|
|
||||||
Object* result = isolate->stack_guard()->HandleInterrupts();
|
|
||||||
|
|
||||||
if (*code_handle != re_code) { // Return address no longer valid
|
|
||||||
int delta = code_handle->address() - re_code->address();
|
|
||||||
// Overwrite the return address on the stack.
|
|
||||||
*return_address += delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result->IsException()) {
|
|
||||||
return EXCEPTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<String> subject_tmp = subject;
|
|
||||||
int slice_offset = 0;
|
|
||||||
|
|
||||||
// Extract the underlying string and the slice offset.
|
|
||||||
if (StringShape(*subject_tmp).IsCons()) {
|
|
||||||
subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
|
|
||||||
} else if (StringShape(*subject_tmp).IsSliced()) {
|
|
||||||
SlicedString* slice = SlicedString::cast(*subject_tmp);
|
|
||||||
subject_tmp = Handle<String>(slice->parent());
|
|
||||||
slice_offset = slice->offset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// String might have changed.
|
|
||||||
if (subject_tmp->IsOneByteRepresentation() != is_one_byte) {
|
|
||||||
// If we changed between an Latin1 and an UC16 string, the specialized
|
|
||||||
// code cannot be used, and we need to restart regexp matching from
|
|
||||||
// scratch (including, potentially, compiling a new version of the code).
|
|
||||||
return RETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, the content of the string might have moved. It must still
|
|
||||||
// be a sequential or external string with the same content.
|
|
||||||
// Update the start and end pointers in the stack frame to the current
|
|
||||||
// location (whether it has actually moved or not).
|
|
||||||
DCHECK(StringShape(*subject_tmp).IsSequential() ||
|
|
||||||
StringShape(*subject_tmp).IsExternal());
|
|
||||||
|
|
||||||
// The original start address of the characters to match.
|
|
||||||
const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
|
|
||||||
|
|
||||||
// Find the current start address of the same character at the current string
|
|
||||||
// position.
|
|
||||||
int start_index = frame_entry<int>(re_frame, kStartIndex);
|
|
||||||
const byte* new_address = StringCharacterPosition(*subject_tmp,
|
|
||||||
start_index + slice_offset);
|
|
||||||
|
|
||||||
if (start_address != new_address) {
|
|
||||||
// If there is a difference, update the object pointer and start and end
|
|
||||||
// addresses in the RegExp stack frame to match the new value.
|
|
||||||
const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
|
|
||||||
int byte_length = static_cast<int>(end_address - start_address);
|
|
||||||
frame_entry<const String*>(re_frame, kInputString) = *subject;
|
|
||||||
frame_entry<const byte*>(re_frame, kInputStart) = new_address;
|
|
||||||
frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
|
|
||||||
} else if (frame_entry<const String*>(re_frame, kInputString) != *subject) {
|
|
||||||
// Subject string might have been a ConsString that underwent
|
|
||||||
// short-circuiting during GC. That will not change start_address but
|
|
||||||
// will change pointer inside the subject handle.
|
|
||||||
frame_entry<const String*>(re_frame, kInputString) = *subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1285,104 +1285,19 @@ static T& frame_entry(Address re_frame, int frame_offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int RegExpMacroAssemblerARM64::CheckStackGuardState(Address* return_address,
|
template <typename T>
|
||||||
Code* re_code,
|
static T* frame_entry_address(Address re_frame, int frame_offset) {
|
||||||
Address re_frame,
|
return reinterpret_cast<T*>(re_frame + frame_offset);
|
||||||
int start_offset,
|
}
|
||||||
const byte** input_start,
|
|
||||||
const byte** input_end) {
|
|
||||||
Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
|
|
||||||
StackLimitCheck check(isolate);
|
|
||||||
if (check.JsHasOverflowed()) {
|
|
||||||
isolate->StackOverflow();
|
|
||||||
return EXCEPTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not real stack overflow the stack guard was used to interrupt
|
|
||||||
// execution for another purpose.
|
|
||||||
|
|
||||||
// If this is a direct call from JavaScript retry the RegExp forcing the call
|
int RegExpMacroAssemblerARM64::CheckStackGuardState(
|
||||||
// through the runtime system. Currently the direct call cannot handle a GC.
|
Address* return_address, Code* re_code, Address re_frame, int start_index,
|
||||||
if (frame_entry<int>(re_frame, kDirectCall) == 1) {
|
const byte** input_start, const byte** input_end) {
|
||||||
return RETRY;
|
return NativeRegExpMacroAssembler::CheckStackGuardState(
|
||||||
}
|
frame_entry<Isolate*>(re_frame, kIsolate), start_index,
|
||||||
|
frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
|
||||||
// Prepare for possible GC.
|
frame_entry_address<String*>(re_frame, kInput), input_start, input_end);
|
||||||
HandleScope handles(isolate);
|
|
||||||
Handle<Code> code_handle(re_code);
|
|
||||||
|
|
||||||
Handle<String> subject(frame_entry<String*>(re_frame, kInput));
|
|
||||||
|
|
||||||
// Current string.
|
|
||||||
bool is_one_byte = subject->IsOneByteRepresentationUnderneath();
|
|
||||||
|
|
||||||
DCHECK(re_code->instruction_start() <= *return_address);
|
|
||||||
DCHECK(*return_address <=
|
|
||||||
re_code->instruction_start() + re_code->instruction_size());
|
|
||||||
|
|
||||||
Object* result = isolate->stack_guard()->HandleInterrupts();
|
|
||||||
|
|
||||||
if (*code_handle != re_code) { // Return address no longer valid
|
|
||||||
int delta = code_handle->address() - re_code->address();
|
|
||||||
// Overwrite the return address on the stack.
|
|
||||||
*return_address += delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result->IsException()) {
|
|
||||||
return EXCEPTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<String> subject_tmp = subject;
|
|
||||||
int slice_offset = 0;
|
|
||||||
|
|
||||||
// Extract the underlying string and the slice offset.
|
|
||||||
if (StringShape(*subject_tmp).IsCons()) {
|
|
||||||
subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
|
|
||||||
} else if (StringShape(*subject_tmp).IsSliced()) {
|
|
||||||
SlicedString* slice = SlicedString::cast(*subject_tmp);
|
|
||||||
subject_tmp = Handle<String>(slice->parent());
|
|
||||||
slice_offset = slice->offset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// String might have changed.
|
|
||||||
if (subject_tmp->IsOneByteRepresentation() != is_one_byte) {
|
|
||||||
// If we changed between an Latin1 and an UC16 string, the specialized
|
|
||||||
// code cannot be used, and we need to restart regexp matching from
|
|
||||||
// scratch (including, potentially, compiling a new version of the code).
|
|
||||||
return RETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, the content of the string might have moved. It must still
|
|
||||||
// be a sequential or external string with the same content.
|
|
||||||
// Update the start and end pointers in the stack frame to the current
|
|
||||||
// location (whether it has actually moved or not).
|
|
||||||
DCHECK(StringShape(*subject_tmp).IsSequential() ||
|
|
||||||
StringShape(*subject_tmp).IsExternal());
|
|
||||||
|
|
||||||
// The original start address of the characters to match.
|
|
||||||
const byte* start_address = *input_start;
|
|
||||||
|
|
||||||
// Find the current start address of the same character at the current string
|
|
||||||
// position.
|
|
||||||
const byte* new_address = StringCharacterPosition(*subject_tmp,
|
|
||||||
start_offset + slice_offset);
|
|
||||||
|
|
||||||
if (start_address != new_address) {
|
|
||||||
// If there is a difference, update the object pointer and start and end
|
|
||||||
// addresses in the RegExp stack frame to match the new value.
|
|
||||||
const byte* end_address = *input_end;
|
|
||||||
int byte_length = static_cast<int>(end_address - start_address);
|
|
||||||
frame_entry<const String*>(re_frame, kInput) = *subject;
|
|
||||||
*input_start = new_address;
|
|
||||||
*input_end = new_address + byte_length;
|
|
||||||
} else if (frame_entry<const String*>(re_frame, kInput) != *subject) {
|
|
||||||
// Subject string might have been a ConsString that underwent
|
|
||||||
// short-circuiting during GC. That will not change start_address but
|
|
||||||
// will change pointer inside the subject handle.
|
|
||||||
frame_entry<const String*>(re_frame, kInput) = *subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1072,102 +1072,22 @@ static T& frame_entry(Address re_frame, int frame_offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static T* frame_entry_address(Address re_frame, int frame_offset) {
|
||||||
|
return reinterpret_cast<T*>(re_frame + frame_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
|
int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
|
||||||
Code* re_code,
|
Code* re_code,
|
||||||
Address re_frame) {
|
Address re_frame) {
|
||||||
Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
|
return NativeRegExpMacroAssembler::CheckStackGuardState(
|
||||||
StackLimitCheck check(isolate);
|
frame_entry<Isolate*>(re_frame, kIsolate),
|
||||||
if (check.JsHasOverflowed()) {
|
frame_entry<int>(re_frame, kStartIndex),
|
||||||
isolate->StackOverflow();
|
frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
|
||||||
return EXCEPTION;
|
frame_entry_address<String*>(re_frame, kInputString),
|
||||||
}
|
frame_entry_address<const byte*>(re_frame, kInputStart),
|
||||||
|
frame_entry_address<const byte*>(re_frame, kInputEnd));
|
||||||
// If not real stack overflow the stack guard was used to interrupt
|
|
||||||
// execution for another purpose.
|
|
||||||
|
|
||||||
// If this is a direct call from JavaScript retry the RegExp forcing the call
|
|
||||||
// through the runtime system. Currently the direct call cannot handle a GC.
|
|
||||||
if (frame_entry<int>(re_frame, kDirectCall) == 1) {
|
|
||||||
return RETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare for possible GC.
|
|
||||||
HandleScope handles(isolate);
|
|
||||||
Handle<Code> code_handle(re_code);
|
|
||||||
|
|
||||||
Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
|
|
||||||
|
|
||||||
// Current string.
|
|
||||||
bool is_one_byte = subject->IsOneByteRepresentationUnderneath();
|
|
||||||
|
|
||||||
DCHECK(re_code->instruction_start() <= *return_address);
|
|
||||||
DCHECK(*return_address <=
|
|
||||||
re_code->instruction_start() + re_code->instruction_size());
|
|
||||||
|
|
||||||
Object* result = isolate->stack_guard()->HandleInterrupts();
|
|
||||||
|
|
||||||
if (*code_handle != re_code) { // Return address no longer valid
|
|
||||||
int delta = code_handle->address() - re_code->address();
|
|
||||||
// Overwrite the return address on the stack.
|
|
||||||
*return_address += delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result->IsException()) {
|
|
||||||
return EXCEPTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<String> subject_tmp = subject;
|
|
||||||
int slice_offset = 0;
|
|
||||||
|
|
||||||
// Extract the underlying string and the slice offset.
|
|
||||||
if (StringShape(*subject_tmp).IsCons()) {
|
|
||||||
subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
|
|
||||||
} else if (StringShape(*subject_tmp).IsSliced()) {
|
|
||||||
SlicedString* slice = SlicedString::cast(*subject_tmp);
|
|
||||||
subject_tmp = Handle<String>(slice->parent());
|
|
||||||
slice_offset = slice->offset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// String might have changed.
|
|
||||||
if (subject_tmp->IsOneByteRepresentation() != is_one_byte) {
|
|
||||||
// If we changed between an LATIN1 and an UC16 string, the specialized
|
|
||||||
// code cannot be used, and we need to restart regexp matching from
|
|
||||||
// scratch (including, potentially, compiling a new version of the code).
|
|
||||||
return RETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, the content of the string might have moved. It must still
|
|
||||||
// be a sequential or external string with the same content.
|
|
||||||
// Update the start and end pointers in the stack frame to the current
|
|
||||||
// location (whether it has actually moved or not).
|
|
||||||
DCHECK(StringShape(*subject_tmp).IsSequential() ||
|
|
||||||
StringShape(*subject_tmp).IsExternal());
|
|
||||||
|
|
||||||
// The original start address of the characters to match.
|
|
||||||
const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
|
|
||||||
|
|
||||||
// Find the current start address of the same character at the current string
|
|
||||||
// position.
|
|
||||||
int start_index = frame_entry<int>(re_frame, kStartIndex);
|
|
||||||
const byte* new_address = StringCharacterPosition(*subject_tmp,
|
|
||||||
start_index + slice_offset);
|
|
||||||
|
|
||||||
if (start_address != new_address) {
|
|
||||||
// If there is a difference, update the object pointer and start and end
|
|
||||||
// addresses in the RegExp stack frame to match the new value.
|
|
||||||
const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
|
|
||||||
int byte_length = static_cast<int>(end_address - start_address);
|
|
||||||
frame_entry<const String*>(re_frame, kInputString) = *subject;
|
|
||||||
frame_entry<const byte*>(re_frame, kInputStart) = new_address;
|
|
||||||
frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
|
|
||||||
} else if (frame_entry<const String*>(re_frame, kInputString) != *subject) {
|
|
||||||
// Subject string might have been a ConsString that underwent
|
|
||||||
// short-circuiting during GC. That will not change start_address but
|
|
||||||
// will change pointer inside the subject handle.
|
|
||||||
frame_entry<const String*>(re_frame, kInputString) = *subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -833,6 +833,12 @@ Object* Isolate::StackOverflow() {
|
|||||||
Throw(*exception, nullptr);
|
Throw(*exception, nullptr);
|
||||||
|
|
||||||
CaptureAndSetSimpleStackTrace(exception, factory()->undefined_value());
|
CaptureAndSetSimpleStackTrace(exception, factory()->undefined_value());
|
||||||
|
#ifdef VERIFY_HEAP
|
||||||
|
if (FLAG_verify_heap && FLAG_stress_compaction) {
|
||||||
|
heap()->CollectAllAvailableGarbage("trigger compaction");
|
||||||
|
}
|
||||||
|
#endif // VERIFY_HEAP
|
||||||
|
|
||||||
return heap()->exception();
|
return heap()->exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1100,101 +1100,22 @@ static T& frame_entry(Address re_frame, int frame_offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static T* frame_entry_address(Address re_frame, int frame_offset) {
|
||||||
|
return reinterpret_cast<T*>(re_frame + frame_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address,
|
int RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address,
|
||||||
Code* re_code,
|
Code* re_code,
|
||||||
Address re_frame) {
|
Address re_frame) {
|
||||||
Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
|
return NativeRegExpMacroAssembler::CheckStackGuardState(
|
||||||
StackLimitCheck check(isolate);
|
frame_entry<Isolate*>(re_frame, kIsolate),
|
||||||
if (check.JsHasOverflowed()) {
|
frame_entry<int>(re_frame, kStartIndex),
|
||||||
isolate->StackOverflow();
|
frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
|
||||||
return EXCEPTION;
|
frame_entry_address<String*>(re_frame, kInputString),
|
||||||
}
|
frame_entry_address<const byte*>(re_frame, kInputStart),
|
||||||
|
frame_entry_address<const byte*>(re_frame, kInputEnd));
|
||||||
// If not real stack overflow the stack guard was used to interrupt
|
|
||||||
// execution for another purpose.
|
|
||||||
|
|
||||||
// If this is a direct call from JavaScript retry the RegExp forcing the call
|
|
||||||
// through the runtime system. Currently the direct call cannot handle a GC.
|
|
||||||
if (frame_entry<int>(re_frame, kDirectCall) == 1) {
|
|
||||||
return RETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare for possible GC.
|
|
||||||
HandleScope handles(isolate);
|
|
||||||
Handle<Code> code_handle(re_code);
|
|
||||||
|
|
||||||
Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
|
|
||||||
// Current string.
|
|
||||||
bool is_one_byte = subject->IsOneByteRepresentationUnderneath();
|
|
||||||
|
|
||||||
DCHECK(re_code->instruction_start() <= *return_address);
|
|
||||||
DCHECK(*return_address <=
|
|
||||||
re_code->instruction_start() + re_code->instruction_size());
|
|
||||||
|
|
||||||
Object* result = isolate->stack_guard()->HandleInterrupts();
|
|
||||||
|
|
||||||
if (*code_handle != re_code) { // Return address no longer valid.
|
|
||||||
int delta = code_handle->address() - re_code->address();
|
|
||||||
// Overwrite the return address on the stack.
|
|
||||||
*return_address += delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result->IsException()) {
|
|
||||||
return EXCEPTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<String> subject_tmp = subject;
|
|
||||||
int slice_offset = 0;
|
|
||||||
|
|
||||||
// Extract the underlying string and the slice offset.
|
|
||||||
if (StringShape(*subject_tmp).IsCons()) {
|
|
||||||
subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
|
|
||||||
} else if (StringShape(*subject_tmp).IsSliced()) {
|
|
||||||
SlicedString* slice = SlicedString::cast(*subject_tmp);
|
|
||||||
subject_tmp = Handle<String>(slice->parent());
|
|
||||||
slice_offset = slice->offset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// String might have changed.
|
|
||||||
if (subject_tmp->IsOneByteRepresentation() != is_one_byte) {
|
|
||||||
// If we changed between an Latin1 and an UC16 string, the specialized
|
|
||||||
// code cannot be used, and we need to restart regexp matching from
|
|
||||||
// scratch (including, potentially, compiling a new version of the code).
|
|
||||||
return RETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, the content of the string might have moved. It must still
|
|
||||||
// be a sequential or external string with the same content.
|
|
||||||
// Update the start and end pointers in the stack frame to the current
|
|
||||||
// location (whether it has actually moved or not).
|
|
||||||
DCHECK(StringShape(*subject_tmp).IsSequential() ||
|
|
||||||
StringShape(*subject_tmp).IsExternal());
|
|
||||||
|
|
||||||
// The original start address of the characters to match.
|
|
||||||
const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
|
|
||||||
|
|
||||||
// Find the current start address of the same character at the current string
|
|
||||||
// position.
|
|
||||||
int start_index = frame_entry<int>(re_frame, kStartIndex);
|
|
||||||
const byte* new_address = StringCharacterPosition(*subject_tmp,
|
|
||||||
start_index + slice_offset);
|
|
||||||
|
|
||||||
if (start_address != new_address) {
|
|
||||||
// If there is a difference, update the object pointer and start and end
|
|
||||||
// addresses in the RegExp stack frame to match the new value.
|
|
||||||
const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
|
|
||||||
int byte_length = static_cast<int>(end_address - start_address);
|
|
||||||
frame_entry<const String*>(re_frame, kInputString) = *subject;
|
|
||||||
frame_entry<const byte*>(re_frame, kInputStart) = new_address;
|
|
||||||
frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
|
|
||||||
} else if (frame_entry<const String*>(re_frame, kInputString) != *subject) {
|
|
||||||
// Subject string might have been a ConsString that underwent
|
|
||||||
// short-circuiting during GC. That will not change start_address but
|
|
||||||
// will change pointer inside the subject handle.
|
|
||||||
frame_entry<const String*>(re_frame, kInputString) = *subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1146,101 +1146,22 @@ static T& frame_entry(Address re_frame, int frame_offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int64_t RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address,
|
template <typename T>
|
||||||
|
static T* frame_entry_address(Address re_frame, int frame_offset) {
|
||||||
|
return reinterpret_cast<T*>(re_frame + frame_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int64 RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address,
|
||||||
Code* re_code,
|
Code* re_code,
|
||||||
Address re_frame) {
|
Address re_frame) {
|
||||||
Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
|
return NativeRegExpMacroAssembler::CheckStackGuardState(
|
||||||
StackLimitCheck check(isolate);
|
frame_entry<Isolate*>(re_frame, kIsolate),
|
||||||
if (check.JsHasOverflowed()) {
|
frame_entry<int>(re_frame, kStartIndex),
|
||||||
isolate->StackOverflow();
|
frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
|
||||||
return EXCEPTION;
|
frame_entry_address<String*>(re_frame, kInputString),
|
||||||
}
|
frame_entry_address<const byte*>(re_frame, kInputStart),
|
||||||
|
frame_entry_address<const byte*>(re_frame, kInputEnd));
|
||||||
// If not real stack overflow the stack guard was used to interrupt
|
|
||||||
// execution for another purpose.
|
|
||||||
|
|
||||||
// If this is a direct call from JavaScript retry the RegExp forcing the call
|
|
||||||
// through the runtime system. Currently the direct call cannot handle a GC.
|
|
||||||
if (frame_entry<int>(re_frame, kDirectCall) == 1) {
|
|
||||||
return RETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare for possible GC.
|
|
||||||
HandleScope handles(isolate);
|
|
||||||
Handle<Code> code_handle(re_code);
|
|
||||||
|
|
||||||
Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
|
|
||||||
// Current string.
|
|
||||||
bool is_one_byte = subject->IsOneByteRepresentationUnderneath();
|
|
||||||
|
|
||||||
DCHECK(re_code->instruction_start() <= *return_address);
|
|
||||||
DCHECK(*return_address <=
|
|
||||||
re_code->instruction_start() + re_code->instruction_size());
|
|
||||||
|
|
||||||
Object* result = isolate->stack_guard()->HandleInterrupts();
|
|
||||||
|
|
||||||
if (*code_handle != re_code) { // Return address no longer valid.
|
|
||||||
int delta = code_handle->address() - re_code->address();
|
|
||||||
// Overwrite the return address on the stack.
|
|
||||||
*return_address += delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result->IsException()) {
|
|
||||||
return EXCEPTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<String> subject_tmp = subject;
|
|
||||||
int slice_offset = 0;
|
|
||||||
|
|
||||||
// Extract the underlying string and the slice offset.
|
|
||||||
if (StringShape(*subject_tmp).IsCons()) {
|
|
||||||
subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
|
|
||||||
} else if (StringShape(*subject_tmp).IsSliced()) {
|
|
||||||
SlicedString* slice = SlicedString::cast(*subject_tmp);
|
|
||||||
subject_tmp = Handle<String>(slice->parent());
|
|
||||||
slice_offset = slice->offset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// String might have changed.
|
|
||||||
if (subject_tmp->IsOneByteRepresentation() != is_one_byte) {
|
|
||||||
// If we changed between an Latin1 and an UC16 string, the specialized
|
|
||||||
// code cannot be used, and we need to restart regexp matching from
|
|
||||||
// scratch (including, potentially, compiling a new version of the code).
|
|
||||||
return RETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, the content of the string might have moved. It must still
|
|
||||||
// be a sequential or external string with the same content.
|
|
||||||
// Update the start and end pointers in the stack frame to the current
|
|
||||||
// location (whether it has actually moved or not).
|
|
||||||
DCHECK(StringShape(*subject_tmp).IsSequential() ||
|
|
||||||
StringShape(*subject_tmp).IsExternal());
|
|
||||||
|
|
||||||
// The original start address of the characters to match.
|
|
||||||
const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
|
|
||||||
|
|
||||||
// Find the current start address of the same character at the current string
|
|
||||||
// position.
|
|
||||||
int start_index = frame_entry<int>(re_frame, kStartIndex);
|
|
||||||
const byte* new_address = StringCharacterPosition(*subject_tmp,
|
|
||||||
start_index + slice_offset);
|
|
||||||
|
|
||||||
if (start_address != new_address) {
|
|
||||||
// If there is a difference, update the object pointer and start and end
|
|
||||||
// addresses in the RegExp stack frame to match the new value.
|
|
||||||
const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
|
|
||||||
int byte_length = static_cast<int>(end_address - start_address);
|
|
||||||
frame_entry<const String*>(re_frame, kInputString) = *subject;
|
|
||||||
frame_entry<const byte*>(re_frame, kInputStart) = new_address;
|
|
||||||
frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
|
|
||||||
} else if (frame_entry<const String*>(re_frame, kInputString) != *subject) {
|
|
||||||
// Subject string might have been a ConsString that underwent
|
|
||||||
// short-circuiting during GC. That will not change start_address but
|
|
||||||
// will change pointer inside the subject handle.
|
|
||||||
frame_entry<const String*>(re_frame, kInputString) = *subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1104,102 +1104,22 @@ static T& frame_entry(Address re_frame, int frame_offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static T* frame_entry_address(Address re_frame, int frame_offset) {
|
||||||
|
return reinterpret_cast<T*>(re_frame + frame_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int RegExpMacroAssemblerPPC::CheckStackGuardState(Address* return_address,
|
int RegExpMacroAssemblerPPC::CheckStackGuardState(Address* return_address,
|
||||||
Code* re_code,
|
Code* re_code,
|
||||||
Address re_frame) {
|
Address re_frame) {
|
||||||
Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
|
return NativeRegExpMacroAssembler::CheckStackGuardState(
|
||||||
StackLimitCheck check(isolate);
|
frame_entry<Isolate*>(re_frame, kIsolate),
|
||||||
if (check.JsHasOverflowed()) {
|
frame_entry<int>(re_frame, kStartIndex),
|
||||||
isolate->StackOverflow();
|
frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
|
||||||
return EXCEPTION;
|
frame_entry_address<String*>(re_frame, kInputString),
|
||||||
}
|
frame_entry_address<const byte*>(re_frame, kInputStart),
|
||||||
|
frame_entry_address<const byte*>(re_frame, kInputEnd));
|
||||||
// If not real stack overflow the stack guard was used to interrupt
|
|
||||||
// execution for another purpose.
|
|
||||||
|
|
||||||
// If this is a direct call from JavaScript retry the RegExp forcing the call
|
|
||||||
// through the runtime system. Currently the direct call cannot handle a GC.
|
|
||||||
if (frame_entry<int>(re_frame, kDirectCall) == 1) {
|
|
||||||
return RETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare for possible GC.
|
|
||||||
HandleScope handles(isolate);
|
|
||||||
Handle<Code> code_handle(re_code);
|
|
||||||
|
|
||||||
Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
|
|
||||||
|
|
||||||
// Current string.
|
|
||||||
bool is_one_byte = subject->IsOneByteRepresentationUnderneath();
|
|
||||||
|
|
||||||
DCHECK(re_code->instruction_start() <= *return_address);
|
|
||||||
DCHECK(*return_address <=
|
|
||||||
re_code->instruction_start() + re_code->instruction_size());
|
|
||||||
|
|
||||||
Object* result = isolate->stack_guard()->HandleInterrupts();
|
|
||||||
|
|
||||||
if (*code_handle != re_code) { // Return address no longer valid
|
|
||||||
intptr_t delta = code_handle->address() - re_code->address();
|
|
||||||
// Overwrite the return address on the stack.
|
|
||||||
*return_address += delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result->IsException()) {
|
|
||||||
return EXCEPTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<String> subject_tmp = subject;
|
|
||||||
int slice_offset = 0;
|
|
||||||
|
|
||||||
// Extract the underlying string and the slice offset.
|
|
||||||
if (StringShape(*subject_tmp).IsCons()) {
|
|
||||||
subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
|
|
||||||
} else if (StringShape(*subject_tmp).IsSliced()) {
|
|
||||||
SlicedString* slice = SlicedString::cast(*subject_tmp);
|
|
||||||
subject_tmp = Handle<String>(slice->parent());
|
|
||||||
slice_offset = slice->offset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// String might have changed.
|
|
||||||
if (subject_tmp->IsOneByteRepresentation() != is_one_byte) {
|
|
||||||
// If we changed between an Latin1 and an UC16 string, the specialized
|
|
||||||
// code cannot be used, and we need to restart regexp matching from
|
|
||||||
// scratch (including, potentially, compiling a new version of the code).
|
|
||||||
return RETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, the content of the string might have moved. It must still
|
|
||||||
// be a sequential or external string with the same content.
|
|
||||||
// Update the start and end pointers in the stack frame to the current
|
|
||||||
// location (whether it has actually moved or not).
|
|
||||||
DCHECK(StringShape(*subject_tmp).IsSequential() ||
|
|
||||||
StringShape(*subject_tmp).IsExternal());
|
|
||||||
|
|
||||||
// The original start address of the characters to match.
|
|
||||||
const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
|
|
||||||
|
|
||||||
// Find the current start address of the same character at the current string
|
|
||||||
// position.
|
|
||||||
int start_index = frame_entry<intptr_t>(re_frame, kStartIndex);
|
|
||||||
const byte* new_address =
|
|
||||||
StringCharacterPosition(*subject_tmp, start_index + slice_offset);
|
|
||||||
|
|
||||||
if (start_address != new_address) {
|
|
||||||
// If there is a difference, update the object pointer and start and end
|
|
||||||
// addresses in the RegExp stack frame to match the new value.
|
|
||||||
const byte* end_address = frame_entry<const byte*>(re_frame, kInputEnd);
|
|
||||||
int byte_length = static_cast<int>(end_address - start_address);
|
|
||||||
frame_entry<const String*>(re_frame, kInputString) = *subject;
|
|
||||||
frame_entry<const byte*>(re_frame, kInputStart) = new_address;
|
|
||||||
frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
|
|
||||||
} else if (frame_entry<const String*>(re_frame, kInputString) != *subject) {
|
|
||||||
// Subject string might have been a ConsString that underwent
|
|
||||||
// short-circuiting during GC. That will not change start_address but
|
|
||||||
// will change pointer inside the subject handle.
|
|
||||||
frame_entry<const String*>(re_frame, kInputString) = *subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,30 +42,82 @@ bool NativeRegExpMacroAssembler::CanReadUnaligned() {
|
|||||||
const byte* NativeRegExpMacroAssembler::StringCharacterPosition(
|
const byte* NativeRegExpMacroAssembler::StringCharacterPosition(
|
||||||
String* subject,
|
String* subject,
|
||||||
int start_index) {
|
int start_index) {
|
||||||
// Not just flat, but ultra flat.
|
if (subject->IsConsString()) {
|
||||||
DCHECK(subject->IsExternalString() || subject->IsSeqString());
|
subject = ConsString::cast(subject)->first();
|
||||||
|
} else if (subject->IsSlicedString()) {
|
||||||
|
start_index += SlicedString::cast(subject)->offset();
|
||||||
|
subject = SlicedString::cast(subject)->parent();
|
||||||
|
}
|
||||||
DCHECK(start_index >= 0);
|
DCHECK(start_index >= 0);
|
||||||
DCHECK(start_index <= subject->length());
|
DCHECK(start_index <= subject->length());
|
||||||
if (subject->IsOneByteRepresentation()) {
|
if (subject->IsSeqOneByteString()) {
|
||||||
const byte* address;
|
return reinterpret_cast<const byte*>(
|
||||||
if (StringShape(subject).IsExternal()) {
|
SeqOneByteString::cast(subject)->GetChars() + start_index);
|
||||||
const uint8_t* data = ExternalOneByteString::cast(subject)->GetChars();
|
} else if (subject->IsSeqTwoByteString()) {
|
||||||
address = reinterpret_cast<const byte*>(data);
|
return reinterpret_cast<const byte*>(
|
||||||
|
SeqTwoByteString::cast(subject)->GetChars() + start_index);
|
||||||
|
} else if (subject->IsExternalOneByteString()) {
|
||||||
|
return reinterpret_cast<const byte*>(
|
||||||
|
ExternalOneByteString::cast(subject)->GetChars() + start_index);
|
||||||
} else {
|
} else {
|
||||||
DCHECK(subject->IsSeqOneByteString());
|
return reinterpret_cast<const byte*>(
|
||||||
const uint8_t* data = SeqOneByteString::cast(subject)->GetChars();
|
ExternalTwoByteString::cast(subject)->GetChars() + start_index);
|
||||||
address = reinterpret_cast<const byte*>(data);
|
|
||||||
}
|
}
|
||||||
return address + start_index;
|
}
|
||||||
}
|
|
||||||
const uc16* data;
|
|
||||||
if (StringShape(subject).IsExternal()) {
|
int NativeRegExpMacroAssembler::CheckStackGuardState(
|
||||||
data = ExternalTwoByteString::cast(subject)->GetChars();
|
Isolate* isolate, int start_index, bool is_direct_call,
|
||||||
|
Address* return_address, Code* re_code, String** subject,
|
||||||
|
const byte** input_start, const byte** input_end) {
|
||||||
|
DCHECK(re_code->instruction_start() <= *return_address);
|
||||||
|
DCHECK(*return_address <= re_code->instruction_end());
|
||||||
|
int return_value = 0;
|
||||||
|
// Prepare for possible GC.
|
||||||
|
HandleScope handles(isolate);
|
||||||
|
Handle<Code> code_handle(re_code);
|
||||||
|
Handle<String> subject_handle(*subject);
|
||||||
|
bool is_one_byte = subject_handle->IsOneByteRepresentationUnderneath();
|
||||||
|
|
||||||
|
StackLimitCheck check(isolate);
|
||||||
|
if (check.JsHasOverflowed()) {
|
||||||
|
isolate->StackOverflow();
|
||||||
|
return_value = EXCEPTION;
|
||||||
|
} else if (is_direct_call) {
|
||||||
|
// If not real stack overflow the stack guard was used to interrupt
|
||||||
|
// execution for another purpose. If this is a direct call from JavaScript
|
||||||
|
// retry the RegExp forcing the call through the runtime system.
|
||||||
|
// Currently the direct call cannot handle a GC.
|
||||||
|
return_value = RETRY;
|
||||||
} else {
|
} else {
|
||||||
DCHECK(subject->IsSeqTwoByteString());
|
Object* result = isolate->stack_guard()->HandleInterrupts();
|
||||||
data = SeqTwoByteString::cast(subject)->GetChars();
|
if (result->IsException()) return_value = EXCEPTION;
|
||||||
}
|
}
|
||||||
return reinterpret_cast<const byte*>(data + start_index);
|
|
||||||
|
DisallowHeapAllocation no_gc;
|
||||||
|
|
||||||
|
if (*code_handle != re_code) { // Return address no longer valid
|
||||||
|
intptr_t delta = code_handle->address() - re_code->address();
|
||||||
|
// Overwrite the return address on the stack.
|
||||||
|
*return_address += delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we continue, we need to update the subject string addresses.
|
||||||
|
if (return_value == 0) {
|
||||||
|
// String encoding might have changed.
|
||||||
|
if (subject_handle->IsOneByteRepresentationUnderneath() != is_one_byte) {
|
||||||
|
// If we changed between an LATIN1 and an UC16 string, the specialized
|
||||||
|
// code cannot be used, and we need to restart regexp matching from
|
||||||
|
// scratch (including, potentially, compiling a new version of the code).
|
||||||
|
return_value = RETRY;
|
||||||
|
} else {
|
||||||
|
*subject = *subject_handle;
|
||||||
|
intptr_t byte_length = *input_end - *input_start;
|
||||||
|
*input_start = StringCharacterPosition(*subject, start_index);
|
||||||
|
*input_end = *input_start + byte_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -215,6 +215,12 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
|
|||||||
|
|
||||||
static const byte* StringCharacterPosition(String* subject, int start_index);
|
static const byte* StringCharacterPosition(String* subject, int start_index);
|
||||||
|
|
||||||
|
static int CheckStackGuardState(Isolate* isolate, int start_index,
|
||||||
|
bool is_direct_call, Address* return_address,
|
||||||
|
Code* re_code, String** subject,
|
||||||
|
const byte** input_start,
|
||||||
|
const byte** input_end);
|
||||||
|
|
||||||
// Byte map of one byte characters with a 0xff if the character is a word
|
// Byte map of one byte characters with a 0xff if the character is a word
|
||||||
// character (digit, letter or underscore) and 0x00 otherwise.
|
// character (digit, letter or underscore) and 0x00 otherwise.
|
||||||
// Used by generated RegExp code.
|
// Used by generated RegExp code.
|
||||||
|
@ -1176,102 +1176,22 @@ static T& frame_entry(Address re_frame, int frame_offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static T* frame_entry_address(Address re_frame, int frame_offset) {
|
||||||
|
return reinterpret_cast<T*>(re_frame + frame_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address,
|
int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address,
|
||||||
Code* re_code,
|
Code* re_code,
|
||||||
Address re_frame) {
|
Address re_frame) {
|
||||||
Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
|
return NativeRegExpMacroAssembler::CheckStackGuardState(
|
||||||
StackLimitCheck check(isolate);
|
frame_entry<Isolate*>(re_frame, kIsolate),
|
||||||
if (check.JsHasOverflowed()) {
|
frame_entry<int>(re_frame, kStartIndex),
|
||||||
isolate->StackOverflow();
|
frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
|
||||||
return EXCEPTION;
|
frame_entry_address<String*>(re_frame, kInputString),
|
||||||
}
|
frame_entry_address<const byte*>(re_frame, kInputStart),
|
||||||
|
frame_entry_address<const byte*>(re_frame, kInputEnd));
|
||||||
// If not real stack overflow the stack guard was used to interrupt
|
|
||||||
// execution for another purpose.
|
|
||||||
|
|
||||||
// If this is a direct call from JavaScript retry the RegExp forcing the call
|
|
||||||
// through the runtime system. Currently the direct call cannot handle a GC.
|
|
||||||
if (frame_entry<int>(re_frame, kDirectCall) == 1) {
|
|
||||||
return RETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare for possible GC.
|
|
||||||
HandleScope handles(isolate);
|
|
||||||
Handle<Code> code_handle(re_code);
|
|
||||||
|
|
||||||
Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
|
|
||||||
|
|
||||||
// Current string.
|
|
||||||
bool is_one_byte = subject->IsOneByteRepresentationUnderneath();
|
|
||||||
|
|
||||||
DCHECK(re_code->instruction_start() <= *return_address);
|
|
||||||
DCHECK(*return_address <=
|
|
||||||
re_code->instruction_start() + re_code->instruction_size());
|
|
||||||
|
|
||||||
Object* result = isolate->stack_guard()->HandleInterrupts();
|
|
||||||
|
|
||||||
if (*code_handle != re_code) { // Return address no longer valid
|
|
||||||
intptr_t delta = code_handle->address() - re_code->address();
|
|
||||||
// Overwrite the return address on the stack.
|
|
||||||
*return_address += delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result->IsException()) {
|
|
||||||
return EXCEPTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<String> subject_tmp = subject;
|
|
||||||
int slice_offset = 0;
|
|
||||||
|
|
||||||
// Extract the underlying string and the slice offset.
|
|
||||||
if (StringShape(*subject_tmp).IsCons()) {
|
|
||||||
subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
|
|
||||||
} else if (StringShape(*subject_tmp).IsSliced()) {
|
|
||||||
SlicedString* slice = SlicedString::cast(*subject_tmp);
|
|
||||||
subject_tmp = Handle<String>(slice->parent());
|
|
||||||
slice_offset = slice->offset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// String might have changed.
|
|
||||||
if (subject_tmp->IsOneByteRepresentation() != is_one_byte) {
|
|
||||||
// If we changed between an Latin1 and an UC16 string, the specialized
|
|
||||||
// code cannot be used, and we need to restart regexp matching from
|
|
||||||
// scratch (including, potentially, compiling a new version of the code).
|
|
||||||
return RETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, the content of the string might have moved. It must still
|
|
||||||
// be a sequential or external string with the same content.
|
|
||||||
// Update the start and end pointers in the stack frame to the current
|
|
||||||
// location (whether it has actually moved or not).
|
|
||||||
DCHECK(StringShape(*subject_tmp).IsSequential() ||
|
|
||||||
StringShape(*subject_tmp).IsExternal());
|
|
||||||
|
|
||||||
// The original start address of the characters to match.
|
|
||||||
const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
|
|
||||||
|
|
||||||
// Find the current start address of the same character at the current string
|
|
||||||
// position.
|
|
||||||
int start_index = frame_entry<int>(re_frame, kStartIndex);
|
|
||||||
const byte* new_address = StringCharacterPosition(*subject_tmp,
|
|
||||||
start_index + slice_offset);
|
|
||||||
|
|
||||||
if (start_address != new_address) {
|
|
||||||
// If there is a difference, update the object pointer and start and end
|
|
||||||
// addresses in the RegExp stack frame to match the new value.
|
|
||||||
const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
|
|
||||||
int byte_length = static_cast<int>(end_address - start_address);
|
|
||||||
frame_entry<const String*>(re_frame, kInputString) = *subject;
|
|
||||||
frame_entry<const byte*>(re_frame, kInputStart) = new_address;
|
|
||||||
frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
|
|
||||||
} else if (frame_entry<const String*>(re_frame, kInputString) != *subject) {
|
|
||||||
// Subject string might have been a ConsString that underwent
|
|
||||||
// short-circuiting during GC. That will not change start_address but
|
|
||||||
// will change pointer inside the subject handle.
|
|
||||||
frame_entry<const String*>(re_frame, kInputString) = *subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1071,102 +1071,22 @@ static T& frame_entry(Address re_frame, int frame_offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static T* frame_entry_address(Address re_frame, int frame_offset) {
|
||||||
|
return reinterpret_cast<T*>(re_frame + frame_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int RegExpMacroAssemblerX87::CheckStackGuardState(Address* return_address,
|
int RegExpMacroAssemblerX87::CheckStackGuardState(Address* return_address,
|
||||||
Code* re_code,
|
Code* re_code,
|
||||||
Address re_frame) {
|
Address re_frame) {
|
||||||
Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
|
return NativeRegExpMacroAssembler::CheckStackGuardState(
|
||||||
StackLimitCheck check(isolate);
|
frame_entry<Isolate*>(re_frame, kIsolate),
|
||||||
if (check.JsHasOverflowed()) {
|
frame_entry<int>(re_frame, kStartIndex),
|
||||||
isolate->StackOverflow();
|
frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
|
||||||
return EXCEPTION;
|
frame_entry_address<String*>(re_frame, kInputString),
|
||||||
}
|
frame_entry_address<const byte*>(re_frame, kInputStart),
|
||||||
|
frame_entry_address<const byte*>(re_frame, kInputEnd));
|
||||||
// If not real stack overflow the stack guard was used to interrupt
|
|
||||||
// execution for another purpose.
|
|
||||||
|
|
||||||
// If this is a direct call from JavaScript retry the RegExp forcing the call
|
|
||||||
// through the runtime system. Currently the direct call cannot handle a GC.
|
|
||||||
if (frame_entry<int>(re_frame, kDirectCall) == 1) {
|
|
||||||
return RETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare for possible GC.
|
|
||||||
HandleScope handles(isolate);
|
|
||||||
Handle<Code> code_handle(re_code);
|
|
||||||
|
|
||||||
Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
|
|
||||||
|
|
||||||
// Current string.
|
|
||||||
bool is_one_byte = subject->IsOneByteRepresentationUnderneath();
|
|
||||||
|
|
||||||
DCHECK(re_code->instruction_start() <= *return_address);
|
|
||||||
DCHECK(*return_address <=
|
|
||||||
re_code->instruction_start() + re_code->instruction_size());
|
|
||||||
|
|
||||||
Object* result = isolate->stack_guard()->HandleInterrupts();
|
|
||||||
|
|
||||||
if (*code_handle != re_code) { // Return address no longer valid
|
|
||||||
int delta = code_handle->address() - re_code->address();
|
|
||||||
// Overwrite the return address on the stack.
|
|
||||||
*return_address += delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result->IsException()) {
|
|
||||||
return EXCEPTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<String> subject_tmp = subject;
|
|
||||||
int slice_offset = 0;
|
|
||||||
|
|
||||||
// Extract the underlying string and the slice offset.
|
|
||||||
if (StringShape(*subject_tmp).IsCons()) {
|
|
||||||
subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
|
|
||||||
} else if (StringShape(*subject_tmp).IsSliced()) {
|
|
||||||
SlicedString* slice = SlicedString::cast(*subject_tmp);
|
|
||||||
subject_tmp = Handle<String>(slice->parent());
|
|
||||||
slice_offset = slice->offset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// String might have changed.
|
|
||||||
if (subject_tmp->IsOneByteRepresentation() != is_one_byte) {
|
|
||||||
// If we changed between an LATIN1 and an UC16 string, the specialized
|
|
||||||
// code cannot be used, and we need to restart regexp matching from
|
|
||||||
// scratch (including, potentially, compiling a new version of the code).
|
|
||||||
return RETRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, the content of the string might have moved. It must still
|
|
||||||
// be a sequential or external string with the same content.
|
|
||||||
// Update the start and end pointers in the stack frame to the current
|
|
||||||
// location (whether it has actually moved or not).
|
|
||||||
DCHECK(StringShape(*subject_tmp).IsSequential() ||
|
|
||||||
StringShape(*subject_tmp).IsExternal());
|
|
||||||
|
|
||||||
// The original start address of the characters to match.
|
|
||||||
const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
|
|
||||||
|
|
||||||
// Find the current start address of the same character at the current string
|
|
||||||
// position.
|
|
||||||
int start_index = frame_entry<int>(re_frame, kStartIndex);
|
|
||||||
const byte* new_address = StringCharacterPosition(*subject_tmp,
|
|
||||||
start_index + slice_offset);
|
|
||||||
|
|
||||||
if (start_address != new_address) {
|
|
||||||
// If there is a difference, update the object pointer and start and end
|
|
||||||
// addresses in the RegExp stack frame to match the new value.
|
|
||||||
const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
|
|
||||||
int byte_length = static_cast<int>(end_address - start_address);
|
|
||||||
frame_entry<const String*>(re_frame, kInputString) = *subject;
|
|
||||||
frame_entry<const byte*>(re_frame, kInputStart) = new_address;
|
|
||||||
frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
|
|
||||||
} else if (frame_entry<const String*>(re_frame, kInputString) != *subject) {
|
|
||||||
// Subject string might have been a ConsString that underwent
|
|
||||||
// short-circuiting during GC. That will not change start_address but
|
|
||||||
// will change pointer inside the subject handle.
|
|
||||||
frame_entry<const String*>(re_frame, kInputString) = *subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
13
test/mjsunit/regress/regress-crbug-469480.js
Normal file
13
test/mjsunit/regress/regress-crbug-469480.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// Flags: --allow-natives-syntax --stress-compaction --verify-heap
|
||||||
|
// Flags: --stack-size=100
|
||||||
|
|
||||||
|
// Load the debug context to fill up code space.
|
||||||
|
%GetDebugContext();
|
||||||
|
%GetDebugContext();
|
||||||
|
|
||||||
|
// Recurse and run regexp code.
|
||||||
|
assertThrows(function f() { f(/./.test("a")); }, RangeError);
|
Loading…
Reference in New Issue
Block a user