}
+Immediate::Immediate(Label *internal_offset) {
+ x_ = reinterpret_cast<int32_t>(internal_offset);
+ rmode_ = RelocInfo::INTERNAL_REFERENCE;
+}
+
+
Immediate::Immediate(Handle<Object> handle) {
// Verify all Objects referred by code are NOT in new space.
Object* obj = *handle;
void Assembler::emit(const Immediate& x) {
+ if (x.rmode_ == RelocInfo::INTERNAL_REFERENCE) {
+ Label* label = reinterpret_cast<Label*>(x.x_);
+ emit_code_relative_offset(label);
+ return;
+ }
if (x.rmode_ != RelocInfo::NONE) RecordRelocInfo(x.rmode_);
emit(x.x_);
}
+void Assembler::emit_code_relative_offset(Label* label) {
+ if (label->is_bound()) {
+ int32_t pos;
+ pos = label->pos() + Code::kHeaderSize - kHeapObjectTag;
+ emit(pos);
+ } else {
+ emit_disp(label, Displacement::CODE_RELATIVE);
+ }
+}
+
+
void Assembler::emit_w(const Immediate& x) {
ASSERT(x.rmode_ == RelocInfo::NONE);
uint16_t value = static_cast<uint16_t>(x.x_);
}
-void Assembler::push(Label* label, RelocInfo::Mode reloc_mode) {
- ASSERT_NOT_NULL(label);
- EnsureSpace ensure_space(this);
- last_pc_ = pc_;
- // If reloc_mode == NONE, the label is stored as buffer relative.
- ASSERT(reloc_mode == RelocInfo::NONE);
- if (label->is_bound()) {
- // Index of position relative to Code Object-pointer.
- int rel_pos = label->pos() + Code::kHeaderSize - kHeapObjectTag;
- if (rel_pos >= 0 && rel_pos < 256) {
- EMIT(0x6a);
- EMIT(rel_pos);
- } else {
- EMIT(0x68);
- emit(rel_pos);
- }
- } else {
- EMIT(0x68);
- emit_disp(label, Displacement::CODE_RELATIVE);
- }
-}
-
-
void Assembler::pop(Register dst) {
ASSERT(reloc_info_writer.last_pc() != NULL);
if (FLAG_push_pop_elimination && (reloc_info_writer.last_pc() <= last_pc_)) {
inline explicit Immediate(Handle<Object> handle);
inline explicit Immediate(Smi* value);
+ static Immediate CodeRelativeOffset(Label* label) {
+ return Immediate(label);
+ }
+
bool is_zero() const { return x_ == 0 && rmode_ == RelocInfo::NONE; }
bool is_int8() const {
return -128 <= x_ && x_ < 128 && rmode_ == RelocInfo::NONE;
}
private:
+ inline explicit Immediate(Label* value);
+
int x_;
RelocInfo::Mode rmode_;
private:
- // Code buffer:
- // The buffer into which code and relocation info are generated.
- byte* buffer_;
- int buffer_size_;
- // True if the assembler owns the buffer, false if buffer is external.
- bool own_buffer_;
-
- // code generation
- byte* pc_; // the program counter; moves forward
- RelocInfoWriter reloc_info_writer;
-
- // push-pop elimination
- byte* last_pc_;
-
- // source position information
- int last_position_;
- int last_statement_position_;
-
byte* addr_at(int pos) { return buffer_ + pos; }
byte byte_at(int pos) { return buffer_[pos]; }
uint32_t long_at(int pos) {
inline void emit(const Immediate& x);
inline void emit_w(const Immediate& x);
+ // Emit the code-object-relative offset of the label's position
+ inline void emit_code_relative_offset(Label* label);
+
// instruction generation
void emit_arith_b(int op1, int op2, Register dst, int imm8);
friend class CodePatcher;
friend class EnsureSpace;
+
+ // Code buffer:
+ // The buffer into which code and relocation info are generated.
+ byte* buffer_;
+ int buffer_size_;
+ // True if the assembler owns the buffer, false if buffer is external.
+ bool own_buffer_;
+
+ // code generation
+ byte* pc_; // the program counter; moves forward
+ RelocInfoWriter reloc_info_writer;
+
+ // push-pop elimination
+ byte* last_pc_;
+
+ // source position information
+ int last_position_;
+ int last_statement_position_;
};
#include "simulator-ia32.h"
#endif
+#include "debug.h"
+#include "v8threads.h"
+
namespace v8 { namespace internal {
}
+static Object* RuntimePreempt() {
+ // Clear the preempt request flag.
+ StackGuard::Continue(PREEMPT);
+
+ ContextSwitcher::PreemptionReceived();
+
+ {
+ v8::Unlocker unlocker;
+ Thread::YieldCPU();
+ }
+
+ return Heap::undefined_value();
+}
+
+
+Object* Execution::DebugBreakHelper() {
+ // Just continue if breaks are disabled.
+ if (Debug::disable_break()) {
+ return Heap::undefined_value();
+ }
+
+ // Don't break in system functions. If the current function is
+ // either in the builtins object of some context or is in the debug
+ // context just return with the debug break stack guard active.
+ JavaScriptFrameIterator it;
+ JavaScriptFrame* frame = it.frame();
+ Object* fun = frame->function();
+ if (fun->IsJSFunction()) {
+ GlobalObject* global = JSFunction::cast(fun)->context()->global();
+ if (global->IsJSBuiltinsObject() || Debug::IsDebugGlobal(global)) {
+ return Heap::undefined_value();
+ }
+ }
+
+ // Clear the debug request flag.
+ StackGuard::Continue(DEBUGBREAK);
+
+ HandleScope scope;
+ // Enter the debugger. Just continue if we fail to enter the debugger.
+ EnterDebugger debugger;
+ if (debugger.FailedToEnter()) {
+ return Heap::undefined_value();
+ }
+
+ // Notify the debug event listeners.
+ Debugger::OnDebugBreak(Factory::undefined_value());
+
+ // Return to continue execution.
+ return Heap::undefined_value();
+}
+
+
+Object* Execution::HandleStackGuardInterrupt() {
+ if (StackGuard::IsDebugBreak()) DebugBreakHelper();
+ if (StackGuard::IsPreempted()) RuntimePreempt();
+ if (StackGuard::IsInterrupted()) {
+ // interrupt
+ StackGuard::Continue(INTERRUPT);
+ return Top::StackOverflow();
+ }
+ return Heap::undefined_value();
+}
+
// --- G C E x t e n s i o n ---
const char* GCExtension::kSource = "native function gc();";
Handle<Object> pos,
Handle<Object> is_global);
+ static Object* DebugBreakHelper();
+
+ // If the stack guard is triggered, but it is not an actual
+ // stack overflow, then handle the interruption accordingly.
+ static Object* HandleStackGuardInterrupt();
+
// Get a function delegate (or undefined) for the given non-function
// object. Used for support calling objects as functions.
static Handle<Object> GetFunctionDelegate(Handle<Object> object);
return AtomExec(regexp, subject, index);
case JSRegExp::IRREGEXP: {
Handle<Object> result = IrregexpExec(regexp, subject, index);
- if (!result.is_null()) {
+ if (!result.is_null() || Top::has_pending_exception()) {
return result;
}
// We couldn't handle the regexp using Irregexp, so fall back
return AtomExecGlobal(regexp, subject);
case JSRegExp::IRREGEXP: {
Handle<Object> result = IrregexpExecGlobal(regexp, subject);
- if (!result.is_null()) {
+ if (!result.is_null() || Top::has_pending_exception()) {
return result;
}
- // We couldn't handle the regexp using Irregexp, so fall back
- // on JSCRE.
- // Reset the JSRegExp to use JSCRE.
+ // Empty handle as result but no exception thrown means that
+ // the regexp contains features not yet handled by the irregexp
+ // compiler.
+ // We have to fall back on JSCRE. Reset the JSRegExp to use JSCRE.
JscrePrepare(regexp,
Handle<String>(regexp->Pattern()),
regexp->GetFlags());
// Irregexp implementation.
+// Retrieves a compiled version of the regexp for either ASCII or non-ASCII
+// strings. If the compiled version doesn't already exist, it is compiled
+// from the source pattern.
+// Irregexp is not feature complete yet. If there is something in the
+// regexp that the compiler cannot currently handle, an empty
+// handle is returned, but no exception is thrown.
static Handle<FixedArray> GetCompiledIrregexp(Handle<JSRegExp> re,
bool is_ascii) {
ASSERT(re->DataAt(JSRegExp::kIrregexpDataIndex)->IsFixedArray());
bool is_ascii = flatshape.IsAsciiRepresentation();
int char_size_shift = is_ascii ? 0 : 1;
+ RegExpMacroAssemblerIA32::Result res;
+
if (flatshape.IsExternal()) {
const byte* address;
if (is_ascii) {
ExternalTwoByteString* ext = ExternalTwoByteString::cast(*subject);
address = reinterpret_cast<const byte*>(ext->resource()->data());
}
- rc = RegExpMacroAssemblerIA32::Execute(
+ res = RegExpMacroAssemblerIA32::Execute(
*code,
&address,
start_offset << char_size_shift,
is_ascii ? SeqAsciiString::cast(*subject)->GetCharsAddress()
: SeqTwoByteString::cast(*subject)->GetCharsAddress();
int byte_offset = char_address - reinterpret_cast<Address>(*subject);
- rc = RegExpMacroAssemblerIA32::Execute(
+ res = RegExpMacroAssemblerIA32::Execute(
*code,
subject.location(),
byte_offset + (start_offset << char_size_shift),
previous_index == 0);
}
+ if (res == RegExpMacroAssemblerIA32::EXCEPTION) {
+ ASSERT(Top::has_pending_exception());
+ return Handle<Object>::null();
+ }
+ rc = (res == RegExpMacroAssemblerIA32::SUCCESS);
+
if (rc) {
// Capture values are relative to start_offset only.
for (int i = 0; i < offsets_vector_length; i++) {
start_label_.Unuse();
success_label_.Unuse();
exit_label_.Unuse();
+ check_preempt_label_.Unuse();
}
void RegExpMacroAssemblerIA32::Backtrack() {
- __ pop(ecx);
- __ add(Operand(ecx), Immediate(self_));
- __ jmp(Operand(ecx));
+ SafeReturn();
}
constant_buffer.at<char>(i) = static_cast<char>(str[i]);
}
} else {
+ ASSERT(mode_ == UC16);
memcpy(constant_buffer.location(),
str.start(),
str.length() * sizeof(uc16));
__ pop(esi);
__ sub(edi, Operand(esi));
} else {
- // store state
+ ASSERT(mode_ == UC16);
__ push(esi);
__ push(edi);
__ push(ecx);
- // align stack
- int frameAlignment = OS::ActivationFrameAlignment();
- if (frameAlignment != 0) {
- __ mov(ebx, esp);
- __ sub(Operand(esp), Immediate(5 * kPointerSize)); // args + esp.
- ASSERT(IsPowerOf2(frameAlignment));
- __ and_(esp, -frameAlignment);
- __ mov(Operand(esp, 4 * kPointerSize), ebx);
- } else {
- __ sub(Operand(esp), Immediate(4 * kPointerSize));
- }
+ const int four_arguments = 4;
+ FrameAlign(four_arguments);
// Put arguments on stack.
__ mov(Operand(esp, 3 * kPointerSize), ecx);
__ mov(ebx, Operand(ebp, kInputEndOffset));
__ mov(eax, Operand(ebp, kInputBuffer));
__ mov(Operand(esp, 0 * kPointerSize), eax);
Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16);
- __ mov(Operand(eax),
- Immediate(reinterpret_cast<int32_t>(function_address)));
- __ call(Operand(eax));
- if (frameAlignment != 0) {
- __ mov(esp, Operand(esp, 4 * kPointerSize));
- } else {
- __ add(Operand(esp), Immediate(4 * sizeof(int32_t)));
- }
+ CallCFunction(function_address, four_arguments);
__ pop(ecx);
__ pop(edi);
__ pop(esi);
+
__ or_(eax, Operand(eax));
BranchOrBacktrack(zero, on_no_match);
__ add(edi, Operand(ecx));
// Exit code:
- // Success
- __ bind(&success_label_);
- if (num_saved_registers_ > 0) {
- // copy captures to output
- __ mov(ebx, Operand(ebp, kRegisterOutput));
- __ mov(ecx, Operand(ebp, kInputEndOffset));
- __ sub(ecx, Operand(ebp, kInputStartOffset));
- for (int i = 0; i < num_saved_registers_; i++) {
- __ mov(eax, register_location(i));
- __ add(eax, Operand(ecx)); // Convert to index from start, not end.
- if (char_size() > 1) {
- ASSERT(char_size() == 2);
- __ sar(eax, 1); // Convert to character index, not byte.
+ if (success_label_.is_linked()) {
+ // Success
+ __ bind(&success_label_);
+ if (num_saved_registers_ > 0) {
+ // copy captures to output
+ __ mov(ebx, Operand(ebp, kRegisterOutput));
+ __ mov(ecx, Operand(ebp, kInputEndOffset));
+ __ sub(ecx, Operand(ebp, kInputStartOffset));
+ for (int i = 0; i < num_saved_registers_; i++) {
+ __ mov(eax, register_location(i));
+ __ add(eax, Operand(ecx)); // Convert to index from start, not end.
+ if (mode_ == UC16) {
+ __ sar(eax, 1); // Convert byte index to character index.
+ }
+ __ mov(Operand(ebx, i * kPointerSize), eax);
}
- __ mov(Operand(ebx, i * kPointerSize), eax);
}
+ __ mov(eax, Immediate(1));
}
- __ mov(eax, Immediate(1));
-
// Exit and return eax
__ bind(&exit_label_);
__ leave();
__ pop(esi);
__ ret(0);
+ // Preempt-code
+ if (check_preempt_label_.is_linked()) {
+ __ bind(&check_preempt_label_);
+ // TODO(lrn): call C function to check the stack guard and return current
+ // stack state (0 = ok, positive = out of stack, negative = preempt).
+ // Then dispatch to an action depending on state, and loop.
+ __ push(edi);
+
+ Label retry;
+ Label stack_overflow;
+
+ __ bind(&retry);
+ int num_arguments = 2;
+ FrameAlign(num_arguments);
+ __ mov(Operand(esp, 1 * kPointerSize), Immediate(self_));
+ __ lea(eax, Operand(esp, -kPointerSize));
+ __ mov(Operand(esp, 0 * kPointerSize), eax);
+ CallCFunction(FUNCTION_ADDR(&CheckStackGuardState), num_arguments);
+
+ ExternalReference stack_guard_limit =
+ ExternalReference::address_of_stack_guard_limit();
+
+ __ or_(eax, Operand(eax));
+ __ j(not_equal, &stack_overflow);
+
+ __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
+ __ j(below_equal, &retry);
+
+ __ pop(edi);
+ // String might have moved: Recompute esi from scratch.
+ __ mov(esi, Operand(esp, kInputBuffer));
+ __ mov(esi, Operand(esi, 0));
+ __ add(esi, Operand(esp, kInputEndOffset));
+ SafeReturn();
+
+ __ bind(&stack_overflow);
+ // Exit with result -1 to signal thrown exception.
+ __ mov(eax, -1);
+ __ jmp(&exit_label_);
+ }
+
CodeDesc code_desc;
masm_->GetCode(&code_desc);
Handle<Code> code = Factory::NewCode(code_desc,
void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) {
- // CheckStackLimit(); // Not ready yet.
- __ push(label, RelocInfo::NONE);
+ __ push(Immediate::CodeRelativeOffset(label));
+ CheckStackLimit();
}
}
+int RegExpMacroAssemblerIA32::CheckStackGuardState(Address return_address,
+ Code* re_code) {
+ if (StackGuard::IsStackOverflow()) {
+ Top::StackOverflow();
+ return 1;
+ }
+
+ // If not real stack overflow the stack guard was used to interrupt
+ // execution for another purpose.
+
+ // Prepare for possible GC.
+ Handle<Code> code_handle(re_code);
+#ifdef DEBUG
+ CHECK(re_code->instruction_start() <= return_address);
+ CHECK(return_address <=
+ re_code->instruction_start() + re_code->instruction_size());
+#endif
+
+ Object* result = Execution::HandleStackGuardInterrupt();
+
+ if (*code_handle != re_code) { // Return address no longer valid
+ int delta = *code_handle - re_code;
+ *reinterpret_cast<int32_t*>(return_address) += delta;
+ }
+
+ if (result->IsException()) {
+ return 1;
+ }
+ return 0;
+}
+
+
Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
ASSERT(register_index < (1<<30));
if (num_registers_ <= register_index) {
}
+void RegExpMacroAssemblerIA32::SafeCall(Label* to) {
+ Label return_to;
+ __ push(Immediate::CodeRelativeOffset(&return_to));
+ __ jmp(to);
+ __ bind(&return_to);
+}
+
+
+void RegExpMacroAssemblerIA32::SafeReturn() {
+ __ pop(ecx);
+ __ add(Operand(ecx), Immediate(self_));
+ __ jmp(Operand(ecx));
+}
+
+
void RegExpMacroAssemblerIA32::CheckStackLimit() {
if (FLAG_check_stack) {
// Check for preemption first.
Label no_preempt;
- Label retry_preempt;
// Check for preemption.
ExternalReference stack_guard_limit =
ExternalReference::address_of_stack_guard_limit();
__ cmp(esp, Operand::StaticVariable(stack_guard_limit));
__ j(above, &no_preempt, taken);
- __ push(edi); // Current position.
- __ push(edx); // Current character.
- // Restore original edi, esi.
- __ mov(edi, Operand(ebp, kBackup_edi));
- __ mov(esi, Operand(ebp, kBackup_esi));
-
- __ bind(&retry_preempt);
- // simulate stack for Runtime call.
- __ push(eax);
- __ push(Immediate(Smi::FromInt(0))); // Dummy receiver
- __ CallRuntime(Runtime::kStackGuard, 1);
- __ pop(eax);
- __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
- __ j(below_equal, &retry_preempt);
-
- __ pop(edx);
- __ pop(edi);
- __ mov(esi, Operand(ebp, kInputBuffer));
- __ mov(esi, Operand(esi, 0));
- __ add(esi, Operand(ebp, kInputEndOffset));
+ SafeCall(&check_preempt_label_);
__ bind(&no_preempt);
}
}
+void RegExpMacroAssemblerIA32::FrameAlign(int num_arguments) {
+ int frameAlignment = OS::ActivationFrameAlignment();
+ if (frameAlignment != 0) {
+ // Make stack end at alignment and make room for num_arguments words
+ // and the original value of esp.
+ __ mov(ebx, esp);
+ __ sub(Operand(esp), Immediate((num_arguments + 1) * kPointerSize));
+ ASSERT(IsPowerOf2(frameAlignment));
+ __ and_(esp, -frameAlignment);
+ __ mov(Operand(esp, num_arguments * kPointerSize), ebx);
+ } else {
+ __ sub(Operand(esp), Immediate(num_arguments * kPointerSize));
+ }
+}
+
+
+void RegExpMacroAssemblerIA32::CallCFunction(Address function_address,
+ int num_arguments) {
+ __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(function_address)));
+ __ call(Operand(eax));
+ if (OS::ActivationFrameAlignment() != 0) {
+ __ mov(esp, Operand(esp, num_arguments * kPointerSize));
+ } else {
+ __ add(Operand(esp), Immediate(num_arguments * sizeof(int32_t)));
+ }
+}
+
+
void RegExpMacroAssemblerIA32::LoadCurrentCharacterUnchecked(int cp_offset) {
if (mode_ == ASCII) {
__ movzx_b(current_character(), Operand(esi, edi, times_1, cp_offset));
- return;
+ } else {
+ ASSERT(mode_ == UC16);
+ __ movzx_w(current_character(),
+ Operand(esi, edi, times_1, cp_offset * sizeof(uc16)));
}
- ASSERT(mode_ == UC16);
- __ movzx_w(current_character(),
- Operand(esi, edi, times_1, cp_offset * sizeof(uc16)));
}
class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
public:
// Type of input string to generate code for.
- enum Mode {ASCII = 1, UC16 = 2};
+ enum Mode { ASCII = 1, UC16 = 2 };
+ enum Result { EXCEPTION = -1, FAILURE = 0, SUCCESS = 1 };
RegExpMacroAssemblerIA32(Mode mode, int registers_to_save);
virtual ~RegExpMacroAssemblerIA32();
virtual void WriteStackPointerToRegister(int reg);
template <typename T>
- static inline bool Execute(Code* code,
- T** input,
- int start_offset,
- int end_offset,
- int* output,
- bool at_start) {
- typedef bool (*matcher)(T**, int, int, int*, int);
+ static inline Result Execute(Code* code,
+ T** input,
+ int start_offset,
+ int end_offset,
+ int* output,
+ bool at_start) {
+ typedef int (*matcher)(T**, int, int, int*, int);
matcher matcher_func = FUNCTION_CAST<matcher>(code->entry());
int at_start_val = at_start ? 1 : 0;
- return matcher_func(input, start_offset, end_offset, output, at_start_val);
+ int result = matcher_func(input,
+ start_offset,
+ end_offset,
+ output,
+ at_start_val);
+ return (result < 0) ? EXCEPTION : (result ? SUCCESS : FAILURE);
}
private:
int byte_offset2,
size_t byte_length);
+ // Called from RegExp if the stack-guard is triggered.
+ // If the code object is relocated, the return address is fixed before
+ // returning.
+ static int CheckStackGuardState(Address return_address, Code* re_code);
+
// The ebp-relative location of a regexp register.
Operand register_location(int register_index);
// (and checks if we have hit the stack limit too).
void CheckStackLimit();
+ // Call and return internally in the generated code in a way that
+ // is GC-safe (i.e., doesn't leave absolute code addresses on the stack)
+ void SafeCall(Label* to);
+ void SafeReturn();
+
+ // Before calling a C-function from generated code, align arguments on stack.
+ // After aligning the frame, arguments must be stored in esp[0], esp[4],
+ // etc., not pushed. The argument count assumes all arguments are word sized.
+ void FrameAlign(int num_arguments);
+ // Calls a C function and cleans up the space for arguments allocated
+ // by FrameAlign. The called function is not allowed to trigger a garbage
+ // collection, since that might move the code and invalidate the return
+ // address
+ void CallCFunction(Address function_address, int num_arguments);
+
MacroAssembler* masm_;
// Constant buffer provider. Allocates external storage for storing
// constants.
Label start_label_;
Label success_label_;
Label exit_label_;
+ Label check_preempt_label_;
// Handle used to represent the generated code object itself.
Handle<Object> self_;
};
}
-static Object* RuntimePreempt(Arguments args) {
- // Clear the preempt request flag.
- StackGuard::Continue(PREEMPT);
-
- ContextSwitcher::PreemptionReceived();
-
- {
- v8::Unlocker unlocker;
- Thread::YieldCPU();
- }
-
- return Heap::undefined_value();
-}
-
-
-static Object* DebugBreakHelper() {
- // Just continue if breaks are disabled.
- if (Debug::disable_break()) {
- return Heap::undefined_value();
- }
-
- // Don't break in system functions. If the current function is
- // either in the builtins object of some context or is in the debug
- // context just return with the debug break stack guard active.
- JavaScriptFrameIterator it;
- JavaScriptFrame* frame = it.frame();
- Object* fun = frame->function();
- if (fun->IsJSFunction()) {
- GlobalObject* global = JSFunction::cast(fun)->context()->global();
- if (global->IsJSBuiltinsObject() || Debug::IsDebugGlobal(global)) {
- return Heap::undefined_value();
- }
- }
-
- // Clear the debug request flag.
- StackGuard::Continue(DEBUGBREAK);
-
- HandleScope scope;
- // Enter the debugger. Just continue if we fail to enter the debugger.
- EnterDebugger debugger;
- if (debugger.FailedToEnter()) {
- return Heap::undefined_value();
- }
-
- // Notify the debug event listeners.
- Debugger::OnDebugBreak(Factory::undefined_value());
-
- // Return to continue execution.
- return Heap::undefined_value();
-}
-
-
static Object* Runtime_DebugBreak(Arguments args) {
ASSERT(args.length() == 0);
- return DebugBreakHelper();
+ return Execution::DebugBreakHelper();
}
// First check if this is a real stack overflow.
if (StackGuard::IsStackOverflow()) return Runtime_StackOverflow(args);
- // If not real stack overflow the stack guard was used to interrupt
- // execution for another purpose.
- if (StackGuard::IsDebugBreak()) DebugBreakHelper();
- if (StackGuard::IsPreempted()) RuntimePreempt(args);
- if (StackGuard::IsInterrupted()) {
- // interrupt
- StackGuard::Continue(INTERRUPT);
- return Top::StackOverflow();
- }
- return Heap::undefined_value();
+ return Execution::HandleStackGuardInterrupt();
}
#ifndef ARM // IA32 only tests.
+class ContextInitializer {
+ public:
+ ContextInitializer() : env_(), scope_(), stack_guard_() {
+ env_ = v8::Context::New();
+ env_->Enter();
+ }
+ ~ContextInitializer() {
+ env_->Exit();
+ env_.Dispose();
+ }
+ private:
+ v8::Persistent<v8::Context> env_;
+ v8::HandleScope scope_;
+ v8::internal::StackGuard stack_guard_;
+};
+
+
TEST(MacroAssemblerIA32Success) {
V8::Initialize(NULL);
-
- // regexp-macro-assembler-ia32 needs a handle scope to allocate
- // byte-arrays for constants.
- v8::HandleScope scope;
+ ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 4);
int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
int end_offset = start_offset + seq_input->length();
- bool success = RegExpMacroAssemblerIA32::Execute(*code,
- seq_input.location(),
- start_offset,
- end_offset,
- captures,
- true);
+ RegExpMacroAssemblerIA32::Result result =
+ RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ captures,
+ true);
- CHECK(success);
+ CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(-1, captures[0]);
CHECK_EQ(-1, captures[1]);
CHECK_EQ(-1, captures[2]);
TEST(MacroAssemblerIA32Simple) {
V8::Initialize(NULL);
-
- // regexp-macro-assembler-ia32 needs a handle scope to allocate
- // byte-arrays for constants.
- v8::HandleScope scope;
+ ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 4);
int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
int end_offset = start_offset + seq_input->length();
- bool success = RegExpMacroAssemblerIA32::Execute(*code,
- seq_input.location(),
- start_offset,
- end_offset,
- captures,
- true);
+ RegExpMacroAssemblerIA32::Result result =
+ RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ captures,
+ true);
- CHECK(success);
+ CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(0, captures[0]);
CHECK_EQ(3, captures[1]);
CHECK_EQ(-1, captures[2]);
start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
end_offset = start_offset + seq_input->length();
- success = RegExpMacroAssemblerIA32::Execute(*code,
- seq_input.location(),
- start_offset,
- end_offset,
- captures,
- true);
+ result = RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ captures,
+ true);
- CHECK(!success);
+ CHECK_EQ(RegExpMacroAssemblerIA32::FAILURE, result);
}
TEST(MacroAssemblerIA32SimpleUC16) {
V8::Initialize(NULL);
-
- // regexp-macro-assembler-ia32 needs a handle scope to allocate
- // byte-arrays for constants.
- v8::HandleScope scope;
+ ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::UC16, 4);
int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
int end_offset = start_offset + seq_input->length() * sizeof(uc16);
- bool success = RegExpMacroAssemblerIA32::Execute(*code,
- seq_input.location(),
- start_offset,
- end_offset,
- captures,
- true);
+ RegExpMacroAssemblerIA32::Result result =
+ RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ captures,
+ true);
- CHECK(success);
+ CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(0, captures[0]);
CHECK_EQ(3, captures[1]);
CHECK_EQ(-1, captures[2]);
start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
end_offset = start_offset + seq_input->length() * sizeof(uc16);
- success = RegExpMacroAssemblerIA32::Execute(*code,
- seq_input.location(),
- start_offset,
- end_offset,
- captures,
- true);
+ result = RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ captures,
+ true);
- CHECK(!success);
+ CHECK_EQ(RegExpMacroAssemblerIA32::FAILURE, result);
}
TEST(MacroAssemblerIA32Backtrack) {
V8::Initialize(NULL);
-
- // regexp-macro-assembler-ia32 needs a handle scope to allocate
- // byte-arrays for constants.
- v8::HandleScope scope;
+ ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 0);
int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
int end_offset = start_offset + seq_input->length();
- bool success = RegExpMacroAssemblerIA32::Execute(*code,
- seq_input.location(),
- start_offset,
- end_offset,
- NULL,
- true);
+ RegExpMacroAssemblerIA32::Result result =
+ RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ NULL,
+ true);
- CHECK(!success);
+ CHECK_EQ(RegExpMacroAssemblerIA32::FAILURE, result);
}
TEST(MacroAssemblerIA32BackReference) {
V8::Initialize(NULL);
-
- // regexp-macro-assembler-ia32 needs a handle scope to allocate
- // byte-arrays for constants.
- v8::HandleScope scope;
+ ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 3);
int end_offset = start_offset + seq_input->length();
int output[3];
- bool success = RegExpMacroAssemblerIA32::Execute(*code,
- seq_input.location(),
- start_offset,
- end_offset,
- output,
- true);
-
- CHECK(success);
+ RegExpMacroAssemblerIA32::Result result =
+ RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ output,
+ true);
+
+ CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(0, output[0]);
CHECK_EQ(2, output[1]);
CHECK_EQ(6, output[2]);
TEST(MacroAssemblerIA32AtStart) {
V8::Initialize(NULL);
-
- // regexp-macro-assembler-ia32 needs a handle scope to allocate
- // byte-arrays for constants.
- v8::HandleScope scope;
+ ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 0);
int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
int end_offset = start_offset + seq_input->length();
- bool success = RegExpMacroAssemblerIA32::Execute(*code,
- seq_input.location(),
- start_offset,
- end_offset,
- NULL,
- true);
+ RegExpMacroAssemblerIA32::Result result =
+ RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ NULL,
+ true);
- CHECK(success);
+ CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
start_offset += 3;
- success = RegExpMacroAssemblerIA32::Execute(*code,
+ result = RegExpMacroAssemblerIA32::Execute(*code,
seq_input.location(),
start_offset,
end_offset,
NULL,
false);
- CHECK(success);
+ CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
}
TEST(MacroAssemblerIA32BackRefNoCase) {
V8::Initialize(NULL);
-
- // regexp-macro-assembler-ia32 needs a handle scope to allocate
- // byte-arrays for constants.
- v8::HandleScope scope;
+ ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 4);
int end_offset = start_offset + seq_input->length();
int output[4];
- bool success = RegExpMacroAssemblerIA32::Execute(*code,
- seq_input.location(),
- start_offset,
- end_offset,
- output,
- true);
-
- CHECK(success);
+ RegExpMacroAssemblerIA32::Result result =
+ RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ output,
+ true);
+
+ CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(0, output[0]);
CHECK_EQ(12, output[1]);
CHECK_EQ(0, output[2]);
TEST(MacroAssemblerIA32Registers) {
V8::Initialize(NULL);
-
- // regexp-macro-assembler-ia32 needs a handle scope to allocate
- // byte-arrays for constants.
- v8::HandleScope scope;
+ ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 5);
int end_offset = start_offset + seq_input->length();
int output[5];
- bool success = RegExpMacroAssemblerIA32::Execute(*code,
- seq_input.location(),
- start_offset,
- end_offset,
- output,
- true);
-
- CHECK(success);
+ RegExpMacroAssemblerIA32::Result result =
+ RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ output,
+ true);
+
+ CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(0, output[0]);
CHECK_EQ(3, output[1]);
CHECK_EQ(6, output[2]);
CHECK_EQ(9, output[4]);
}
+
+TEST(MacroAssemblerIA32StackOverflow) {
+ V8::Initialize(NULL);
+ ContextInitializer initializer;
+
+ RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 0);
+
+ Label loop;
+ m.Bind(&loop);
+ m.PushBacktrack(&loop);
+ m.GoTo(&loop);
+
+ Handle<String> source =
+ Factory::NewStringFromAscii(CStrVector("<stack overflow test>"));
+ Handle<Object> code_object = m.GetCode(source);
+ Handle<Code> code = Handle<Code>::cast(code_object);
+
+ // String long enough for test (content doesn't matter).
+ Handle<String> input =
+ Factory::NewStringFromAscii(CStrVector("dummy"));
+ Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
+ Address start_adr = seq_input->GetCharsAddress();
+ int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
+ int end_offset = start_offset + seq_input->length();
+
+ RegExpMacroAssemblerIA32::Result result =
+ RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ NULL,
+ true);
+
+ CHECK_EQ(RegExpMacroAssemblerIA32::EXCEPTION, result);
+ CHECK(Top::has_pending_exception());
+ Top::clear_pending_exception();
+}
+
+
#endif // !defined ARM
TEST(AddInverseToTable) {