Commit b4fd72b3 authored by lrn@chromium.org's avatar lrn@chromium.org

Change native RegExp call code to properly set C++ structures and

to handle exceptions on return from RegExp.

BUG=1108
TEST=

Review URL: http://codereview.chromium.org/6489001

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6794 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 54e74230
...@@ -3299,105 +3299,13 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) { ...@@ -3299,105 +3299,13 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
// r0 holds the exception. __ Throw(r0);
// Adjust this code if not the case.
STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
// Drop the sp to the top of the handler.
__ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
__ ldr(sp, MemOperand(r3));
// Restore the next handler and frame pointer, discard handler state.
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
__ pop(r2);
__ str(r2, MemOperand(r3));
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
__ ldm(ia_w, sp, r3.bit() | fp.bit()); // r3: discarded state.
// Before returning we restore the context from the frame pointer if
// not NULL. The frame pointer is NULL in the exception handler of a
// JS entry frame.
__ cmp(fp, Operand(0, RelocInfo::NONE));
// Set cp to NULL if fp is NULL.
__ mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq);
// Restore cp otherwise.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
#ifdef DEBUG
if (FLAG_debug_code) {
__ mov(lr, Operand(pc));
}
#endif
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
__ pop(pc);
} }
void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm, void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm,
UncatchableExceptionType type) { UncatchableExceptionType type) {
// Adjust this code if not the case. __ ThrowUncatchable(type, r0);
STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
// Drop sp to the top stack handler.
__ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
__ ldr(sp, MemOperand(r3));
// Unwind the handlers until the ENTRY handler is found.
Label loop, done;
__ bind(&loop);
// Load the type of the current stack handler.
const int kStateOffset = StackHandlerConstants::kStateOffset;
__ ldr(r2, MemOperand(sp, kStateOffset));
__ cmp(r2, Operand(StackHandler::ENTRY));
__ b(eq, &done);
// Fetch the next handler in the list.
const int kNextOffset = StackHandlerConstants::kNextOffset;
__ ldr(sp, MemOperand(sp, kNextOffset));
__ jmp(&loop);
__ bind(&done);
// Set the top handler address to next handler past the current ENTRY handler.
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
__ pop(r2);
__ str(r2, MemOperand(r3));
if (type == OUT_OF_MEMORY) {
// Set external caught exception to false.
ExternalReference external_caught(Top::k_external_caught_exception_address);
__ mov(r0, Operand(false, RelocInfo::NONE));
__ mov(r2, Operand(external_caught));
__ str(r0, MemOperand(r2));
// Set pending exception and r0 to out of memory exception.
Failure* out_of_memory = Failure::OutOfMemoryException();
__ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
__ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address)));
__ str(r0, MemOperand(r2));
}
// Stack layout at this point. See also StackHandlerConstants.
// sp -> state (ENTRY)
// fp
// lr
// Discard handler state (r2 is not used) and restore frame pointer.
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
__ ldm(ia_w, sp, r2.bit() | fp.bit()); // r2: discarded state.
// Before returning we restore the context from the frame pointer if
// not NULL. The frame pointer is NULL in the exception handler of a
// JS entry frame.
__ cmp(fp, Operand(0, RelocInfo::NONE));
// Set cp to NULL if fp is NULL.
__ mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq);
// Restore cp otherwise.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
#ifdef DEBUG
if (FLAG_debug_code) {
__ mov(lr, Operand(pc));
}
#endif
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
__ pop(pc);
} }
...@@ -3484,7 +3392,9 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, ...@@ -3484,7 +3392,9 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
// r0:r1: result // r0:r1: result
// sp: stack pointer // sp: stack pointer
// fp: frame pointer // fp: frame pointer
__ LeaveExitFrame(save_doubles_); // Callee-saved register r4 still holds argc.
__ LeaveExitFrame(save_doubles_, r4);
__ mov(pc, lr);
// check if we should retry or throw exception // check if we should retry or throw exception
Label retry; Label retry;
...@@ -4263,24 +4173,27 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { ...@@ -4263,24 +4173,27 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ IncrementCounter(&Counters::regexp_entry_native, 1, r0, r2); __ IncrementCounter(&Counters::regexp_entry_native, 1, r0, r2);
static const int kRegExpExecuteArguments = 7; static const int kRegExpExecuteArguments = 7;
__ push(lr); static const int kParameterRegisters = 4;
__ PrepareCallCFunction(kRegExpExecuteArguments, r0); __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters);
// Stack pointer now points to cell where return address is to be written.
// Arguments are before that on the stack or in registers.
// Argument 7 (sp[8]): Indicate that this is a direct call from JavaScript. // Argument 7 (sp[12]): Indicate that this is a direct call from JavaScript.
__ mov(r0, Operand(1)); __ mov(r0, Operand(1));
__ str(r0, MemOperand(sp, 2 * kPointerSize)); __ str(r0, MemOperand(sp, 3 * kPointerSize));
// Argument 6 (sp[4]): Start (high end) of backtracking stack memory area. // Argument 6 (sp[8]): Start (high end) of backtracking stack memory area.
__ mov(r0, Operand(address_of_regexp_stack_memory_address)); __ mov(r0, Operand(address_of_regexp_stack_memory_address));
__ ldr(r0, MemOperand(r0, 0)); __ ldr(r0, MemOperand(r0, 0));
__ mov(r2, Operand(address_of_regexp_stack_memory_size)); __ mov(r2, Operand(address_of_regexp_stack_memory_size));
__ ldr(r2, MemOperand(r2, 0)); __ ldr(r2, MemOperand(r2, 0));
__ add(r0, r0, Operand(r2)); __ add(r0, r0, Operand(r2));
__ str(r0, MemOperand(sp, 1 * kPointerSize)); __ str(r0, MemOperand(sp, 2 * kPointerSize));
// Argument 5 (sp[0]): static offsets vector buffer. // Argument 5 (sp[4]): static offsets vector buffer.
__ mov(r0, Operand(ExternalReference::address_of_static_offsets_vector())); __ mov(r0, Operand(ExternalReference::address_of_static_offsets_vector()));
__ str(r0, MemOperand(sp, 0 * kPointerSize)); __ str(r0, MemOperand(sp, 1 * kPointerSize));
// For arguments 4 and 3 get string length, calculate start of string data and // For arguments 4 and 3 get string length, calculate start of string data and
// calculate the shift of the index (0 for ASCII and 1 for two byte). // calculate the shift of the index (0 for ASCII and 1 for two byte).
...@@ -4302,8 +4215,10 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { ...@@ -4302,8 +4215,10 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Locate the code entry and call it. // Locate the code entry and call it.
__ add(r7, r7, Operand(Code::kHeaderSize - kHeapObjectTag)); __ add(r7, r7, Operand(Code::kHeaderSize - kHeapObjectTag));
__ CallCFunction(r7, kRegExpExecuteArguments); DirectCEntryStub stub;
__ pop(lr); stub.GenerateCall(masm, r7);
__ LeaveExitFrame(false, no_reg);
// r0: result // r0: result
// subject: subject string (callee saved) // subject: subject string (callee saved)
...@@ -4312,6 +4227,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { ...@@ -4312,6 +4227,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Check the result. // Check the result.
Label success; Label success;
__ cmp(r0, Operand(NativeRegExpMacroAssembler::SUCCESS)); __ cmp(r0, Operand(NativeRegExpMacroAssembler::SUCCESS));
__ b(eq, &success); __ b(eq, &success);
Label failure; Label failure;
...@@ -4324,12 +4240,26 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { ...@@ -4324,12 +4240,26 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// stack overflow (on the backtrack stack) was detected in RegExp code but // stack overflow (on the backtrack stack) was detected in RegExp code but
// haven't created the exception yet. Handle that in the runtime system. // haven't created the exception yet. Handle that in the runtime system.
// TODO(592): Rerunning the RegExp to get the stack overflow exception. // TODO(592): Rerunning the RegExp to get the stack overflow exception.
__ mov(r0, Operand(ExternalReference::the_hole_value_location())); __ mov(r1, Operand(ExternalReference::the_hole_value_location()));
__ ldr(r0, MemOperand(r0, 0));
__ mov(r1, Operand(ExternalReference(Top::k_pending_exception_address)));
__ ldr(r1, MemOperand(r1, 0)); __ ldr(r1, MemOperand(r1, 0));
__ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address)));
__ ldr(r0, MemOperand(r2, 0));
__ cmp(r0, r1); __ cmp(r0, r1);
__ b(eq, &runtime); __ b(eq, &runtime);
__ str(r1, MemOperand(r2, 0)); // Clear pending exception.
// Check if the exception is a termination. If so, throw as uncatchable.
__ LoadRoot(ip, Heap::kTerminationExceptionRootIndex);
__ cmp(r0, ip);
Label termination_exception;
__ b(eq, &termination_exception);
__ Throw(r0); // Expects thrown value in r0.
__ bind(&termination_exception);
__ ThrowUncatchable(TERMINATION, r0); // Expects thrown value in r0.
__ bind(&failure); __ bind(&failure);
// For failure and exception return null. // For failure and exception return null.
__ mov(r0, Operand(Factory::null_value())); __ mov(r0, Operand(Factory::null_value()));
...@@ -5953,14 +5883,24 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm, ...@@ -5953,14 +5883,24 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
ApiFunction *function) { ApiFunction *function) {
__ mov(lr, Operand(reinterpret_cast<intptr_t>(GetCode().location()), __ mov(lr, Operand(reinterpret_cast<intptr_t>(GetCode().location()),
RelocInfo::CODE_TARGET)); RelocInfo::CODE_TARGET));
// Push return address (accessible to GC through exit frame pc).
__ mov(r2, __ mov(r2,
Operand(ExternalReference(function, ExternalReference::DIRECT_CALL))); Operand(ExternalReference(function, ExternalReference::DIRECT_CALL)));
// Push return address (accessible to GC through exit frame pc).
__ str(pc, MemOperand(sp, 0)); __ str(pc, MemOperand(sp, 0));
__ Jump(r2); // Call the api function. __ Jump(r2); // Call the api function.
} }
void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
Register target) {
__ mov(lr, Operand(reinterpret_cast<intptr_t>(GetCode().location()),
RelocInfo::CODE_TARGET));
// Push return address (accessible to GC through exit frame pc).
__ str(pc, MemOperand(sp, 0));
__ Jump(target); // Call the C++ function.
}
void GenerateFastPixelArrayLoad(MacroAssembler* masm, void GenerateFastPixelArrayLoad(MacroAssembler* masm,
Register receiver, Register receiver,
Register key, Register key,
......
...@@ -581,6 +581,7 @@ class DirectCEntryStub: public CodeStub { ...@@ -581,6 +581,7 @@ class DirectCEntryStub: public CodeStub {
DirectCEntryStub() {} DirectCEntryStub() {}
void Generate(MacroAssembler* masm); void Generate(MacroAssembler* masm);
void GenerateCall(MacroAssembler* masm, ApiFunction *function); void GenerateCall(MacroAssembler* masm, ApiFunction *function);
void GenerateCall(MacroAssembler* masm, Register target);
private: private:
Major MajorKey() { return DirectCEntry; } Major MajorKey() { return DirectCEntry; }
......
...@@ -714,7 +714,8 @@ int MacroAssembler::ActivationFrameAlignment() { ...@@ -714,7 +714,8 @@ int MacroAssembler::ActivationFrameAlignment() {
} }
void MacroAssembler::LeaveExitFrame(bool save_doubles) { void MacroAssembler::LeaveExitFrame(bool save_doubles,
Register argument_count) {
// Optionally restore all double registers. // Optionally restore all double registers.
if (save_doubles) { if (save_doubles) {
for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) { for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) {
...@@ -736,12 +737,12 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles) { ...@@ -736,12 +737,12 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles) {
str(r3, MemOperand(ip)); str(r3, MemOperand(ip));
#endif #endif
// Tear down the exit frame, pop the arguments, and return. Callee-saved // Tear down the exit frame, pop the arguments, and return.
// register r4 still holds argc.
mov(sp, Operand(fp)); mov(sp, Operand(fp));
ldm(ia_w, sp, fp.bit() | lr.bit()); ldm(ia_w, sp, fp.bit() | lr.bit());
add(sp, sp, Operand(r4, LSL, kPointerSizeLog2)); if (argument_count.is_valid()) {
mov(pc, lr); add(sp, sp, Operand(argument_count, LSL, kPointerSizeLog2));
}
} }
...@@ -1005,6 +1006,117 @@ void MacroAssembler::PopTryHandler() { ...@@ -1005,6 +1006,117 @@ void MacroAssembler::PopTryHandler() {
} }
void MacroAssembler::Throw(Register value) {
// r0 is expected to hold the exception.
if (!value.is(r0)) {
mov(r0, value);
}
// Adjust this code if not the case.
STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
// Drop the sp to the top of the handler.
mov(r3, Operand(ExternalReference(Top::k_handler_address)));
ldr(sp, MemOperand(r3));
// Restore the next handler and frame pointer, discard handler state.
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(r2);
str(r2, MemOperand(r3));
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
ldm(ia_w, sp, r3.bit() | fp.bit()); // r3: discarded state.
// Before returning we restore the context from the frame pointer if
// not NULL. The frame pointer is NULL in the exception handler of a
// JS entry frame.
cmp(fp, Operand(0, RelocInfo::NONE));
// Set cp to NULL if fp is NULL.
mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq);
// Restore cp otherwise.
ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
#ifdef DEBUG
if (FLAG_debug_code) {
mov(lr, Operand(pc));
}
#endif
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
pop(pc);
}
void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
Register value) {
// Adjust this code if not the case.
STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
// r0 is expected to hold the exception.
if (!value.is(r0)) {
mov(r0, value);
}
// Drop sp to the top stack handler.
mov(r3, Operand(ExternalReference(Top::k_handler_address)));
ldr(sp, MemOperand(r3));
// Unwind the handlers until the ENTRY handler is found.
Label loop, done;
bind(&loop);
// Load the type of the current stack handler.
const int kStateOffset = StackHandlerConstants::kStateOffset;
ldr(r2, MemOperand(sp, kStateOffset));
cmp(r2, Operand(StackHandler::ENTRY));
b(eq, &done);
// Fetch the next handler in the list.
const int kNextOffset = StackHandlerConstants::kNextOffset;
ldr(sp, MemOperand(sp, kNextOffset));
jmp(&loop);
bind(&done);
// Set the top handler address to next handler past the current ENTRY handler.
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(r2);
str(r2, MemOperand(r3));
if (type == OUT_OF_MEMORY) {
// Set external caught exception to false.
ExternalReference external_caught(Top::k_external_caught_exception_address);
mov(r0, Operand(false, RelocInfo::NONE));
mov(r2, Operand(external_caught));
str(r0, MemOperand(r2));
// Set pending exception and r0 to out of memory exception.
Failure* out_of_memory = Failure::OutOfMemoryException();
mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
mov(r2, Operand(ExternalReference(Top::k_pending_exception_address)));
str(r0, MemOperand(r2));
}
// Stack layout at this point. See also StackHandlerConstants.
// sp -> state (ENTRY)
// fp
// lr
// Discard handler state (r2 is not used) and restore frame pointer.
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize);
ldm(ia_w, sp, r2.bit() | fp.bit()); // r2: discarded state.
// Before returning we restore the context from the frame pointer if
// not NULL. The frame pointer is NULL in the exception handler of a
// JS entry frame.
cmp(fp, Operand(0, RelocInfo::NONE));
// Set cp to NULL if fp is NULL.
mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq);
// Restore cp otherwise.
ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
#ifdef DEBUG
if (FLAG_debug_code) {
mov(lr, Operand(pc));
}
#endif
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
pop(pc);
}
void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
Register scratch, Register scratch,
Label* miss) { Label* miss) {
...@@ -1554,9 +1666,10 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn( ...@@ -1554,9 +1666,10 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
cmp(r4, r5); cmp(r4, r5);
b(ne, &promote_scheduled_exception); b(ne, &promote_scheduled_exception);
// LeaveExitFrame expects unwind space to be in r4. // LeaveExitFrame expects unwind space to be in a register.
mov(r4, Operand(stack_space)); mov(r4, Operand(stack_space));
LeaveExitFrame(false); LeaveExitFrame(false, r4);
mov(pc, lr);
bind(&promote_scheduled_exception); bind(&promote_scheduled_exception);
MaybeObject* result = TryTailCallExternalReference( MaybeObject* result = TryTailCallExternalReference(
......
...@@ -297,7 +297,9 @@ class MacroAssembler: public Assembler { ...@@ -297,7 +297,9 @@ class MacroAssembler: public Assembler {
void EnterExitFrame(bool save_doubles, int stack_space = 0); void EnterExitFrame(bool save_doubles, int stack_space = 0);
// Leave the current exit frame. Expects the return value in r0. // Leave the current exit frame. Expects the return value in r0.
void LeaveExitFrame(bool save_doubles); // Expect the number of values, pushed prior to the exit frame, to
// remove in a register (or no_reg, if there is nothing to remove).
void LeaveExitFrame(bool save_doubles, Register argument_count);
// Get the actual activation frame alignment for target environment. // Get the actual activation frame alignment for target environment.
static int ActivationFrameAlignment(); static int ActivationFrameAlignment();
...@@ -371,6 +373,13 @@ class MacroAssembler: public Assembler { ...@@ -371,6 +373,13 @@ class MacroAssembler: public Assembler {
// Must preserve the result register. // Must preserve the result register.
void PopTryHandler(); void PopTryHandler();
// Passes thrown value (in r0) to the handler of top of the try handler chain.
void Throw(Register value);
// Propagates an uncatchable exception to the top of the current JS stack's
// handler chain.
void ThrowUncatchable(UncatchableExceptionType type, Register value);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Inline caching support // Inline caching support
......
...@@ -57,48 +57,57 @@ namespace internal { ...@@ -57,48 +57,57 @@ namespace internal {
* - r13/sp : points to tip of C stack. * - r13/sp : points to tip of C stack.
* *
* The remaining registers are free for computations. * The remaining registers are free for computations.
*
* Each call to a public method should retain this convention. * Each call to a public method should retain this convention.
*
* The stack will have the following structure: * The stack will have the following structure:
* - direct_call (if 1, direct call from JavaScript code, if 0 call * - fp[48] direct_call (if 1, direct call from JavaScript code,
* through the runtime system) * if 0, call through the runtime system).
* - stack_area_base (High end of the memory area to use as * - fp[44] stack_area_base (High end of the memory area to use as
* backtracking stack) * backtracking stack).
* - int* capture_array (int[num_saved_registers_], for output). * - fp[40] int* capture_array (int[num_saved_registers_], for output).
* --- sp when called --- * - fp[36] secondary link/return address used by native call.
* - link address * --- sp when called ---
* - backup of registers r4..r11 * - fp[32] return address (lr).
* - end of input (Address of end of string) * - fp[28] old frame pointer (r11).
* - start of input (Address of first character in string) * - fp[0..24] backup of registers r4..r10.
* - start index (character index of start) * --- frame pointer ----
* --- frame pointer ---- * - fp[-4] end of input (Address of end of string).
* - void* input_string (location of a handle containing the string) * - fp[-8] start of input (Address of first character in string).
* - Offset of location before start of input (effectively character * - fp[-12] start index (character index of start).
* position -1). Used to initialize capture registers to a non-position. * - fp[-16] void* input_string (location of a handle containing the string).
* - At start (if 1, we are starting at the start of the * - fp[-20] Offset of location before start of input (effectively character
* string, otherwise 0) * position -1). Used to initialize capture registers to a
* - register 0 (Only positions must be stored in the first * non-position.
* - register 1 num_saved_registers_ registers) * - fp[-24] At start (if 1, we are starting at the start of the
* - ... * string, otherwise 0)
* - register num_registers-1 * - fp[-28] register 0 (Only positions must be stored in the first
* --- sp --- * - register 1 num_saved_registers_ registers)
* - ...
* - register num_registers-1
* --- sp ---
* *
* The first num_saved_registers_ registers are initialized to point to * The first num_saved_registers_ registers are initialized to point to
* "character -1" in the string (i.e., char_size() bytes before the first * "character -1" in the string (i.e., char_size() bytes before the first
* character of the string). The remaining registers start out as garbage. * character of the string). The remaining registers start out as garbage.
* *
* The data up to the return address must be placed there by the calling * The data up to the return address must be placed there by the calling
* code, by calling the code entry as cast to a function with the signature: * code and the remaining arguments are passed in registers, e.g. by calling the
* code entry as cast to a function with the signature:
* int (*match)(String* input_string, * int (*match)(String* input_string,
* int start_index, * int start_index,
* Address start, * Address start,
* Address end, * Address end,
* Address secondary_return_address, // Only used by native call.
* int* capture_output_array, * int* capture_output_array,
* bool at_start,
* byte* stack_area_base, * byte* stack_area_base,
* bool direct_call) * bool direct_call = false)
* The call is performed by NativeRegExpMacroAssembler::Execute() * The call is performed by NativeRegExpMacroAssembler::Execute()
* (in regexp-macro-assembler.cc). * (in regexp-macro-assembler.cc) via the CALL_GENERATED_REGEXP_CODE macro
* in arm/simulator-arm.h.
* When calling as a non-direct call (i.e., from C++ code), the return address
* area is overwritten with the LR register by the RegExp code. When doing a
* direct call from generated code, the return address is placed there by
* the calling code, as in a normal exit frame.
*/ */
#define __ ACCESS_MASM(masm_) #define __ ACCESS_MASM(masm_)
...@@ -598,16 +607,17 @@ Handle<Object> RegExpMacroAssemblerARM::GetCode(Handle<String> source) { ...@@ -598,16 +607,17 @@ Handle<Object> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
// Entry code: // Entry code:
__ bind(&entry_label_); __ bind(&entry_label_);
// Push Link register.
// Push arguments // Push arguments
// Save callee-save registers. // Save callee-save registers.
// Start new stack frame. // Start new stack frame.
// Store link register in existing stack-cell.
// Order here should correspond to order of offset constants in header file. // Order here should correspond to order of offset constants in header file.
RegList registers_to_retain = r4.bit() | r5.bit() | r6.bit() | RegList registers_to_retain = r4.bit() | r5.bit() | r6.bit() |
r7.bit() | r8.bit() | r9.bit() | r10.bit() | fp.bit(); r7.bit() | r8.bit() | r9.bit() | r10.bit() | fp.bit();
RegList argument_registers = r0.bit() | r1.bit() | r2.bit() | r3.bit(); RegList argument_registers = r0.bit() | r1.bit() | r2.bit() | r3.bit();
__ stm(db_w, sp, argument_registers | registers_to_retain | lr.bit()); __ stm(db_w, sp, argument_registers | registers_to_retain | lr.bit());
// Set frame pointer just above the arguments. // Set frame pointer in space for it if this is not a direct call
// from generated code.
__ add(frame_pointer(), sp, Operand(4 * kPointerSize)); __ add(frame_pointer(), sp, Operand(4 * kPointerSize));
__ push(r0); // Make room for "position - 1" constant (value is irrelevant). __ push(r0); // Make room for "position - 1" constant (value is irrelevant).
__ push(r0); // Make room for "at start" constant (value is irrelevant). __ push(r0); // Make room for "at start" constant (value is irrelevant).
...@@ -764,10 +774,9 @@ Handle<Object> RegExpMacroAssemblerARM::GetCode(Handle<String> source) { ...@@ -764,10 +774,9 @@ Handle<Object> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
if (stack_overflow_label_.is_linked()) { if (stack_overflow_label_.is_linked()) {
SafeCallTarget(&stack_overflow_label_); SafeCallTarget(&stack_overflow_label_);
// Reached if the backtrack-stack limit has been hit. // Reached if the backtrack-stack limit has been hit.
Label grow_failed; Label grow_failed;
// Call GrowStack(backtrack_stackpointer()) // Call GrowStack(backtrack_stackpointer(), &stack_base)
static const int num_arguments = 2; static const int num_arguments = 2;
__ PrepareCallCFunction(num_arguments, r0); __ PrepareCallCFunction(num_arguments, r0);
__ mov(r0, backtrack_stackpointer()); __ mov(r0, backtrack_stackpointer());
......
...@@ -122,8 +122,9 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler { ...@@ -122,8 +122,9 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler {
static const int kStoredRegisters = kFramePointer; static const int kStoredRegisters = kFramePointer;
// Return address (stored from link register, read into pc on return). // Return address (stored from link register, read into pc on return).
static const int kReturnAddress = kStoredRegisters + 8 * kPointerSize; static const int kReturnAddress = kStoredRegisters + 8 * kPointerSize;
static const int kSecondaryReturnAddress = kReturnAddress + kPointerSize;
// Stack parameters placed by caller. // Stack parameters placed by caller.
static const int kRegisterOutput = kReturnAddress + kPointerSize; static const int kRegisterOutput = kSecondaryReturnAddress + kPointerSize;
static const int kStackHighEnd = kRegisterOutput + kPointerSize; static const int kStackHighEnd = kRegisterOutput + kPointerSize;
static const int kDirectCall = kStackHighEnd + kPointerSize; static const int kDirectCall = kStackHighEnd + kPointerSize;
......
...@@ -51,7 +51,7 @@ namespace internal { ...@@ -51,7 +51,7 @@ namespace internal {
// Call the generated regexp code directly. The entry function pointer should // Call the generated regexp code directly. The entry function pointer should
// expect seven int/pointer sized arguments and return an int. // expect seven int/pointer sized arguments and return an int.
#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \ #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
(entry(p0, p1, p2, p3, p4, p5, p6)) (entry(p0, p1, p2, p3, NULL, p4, p5, p6))
#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
(reinterpret_cast<TryCatch*>(try_catch_address)) (reinterpret_cast<TryCatch*>(try_catch_address))
...@@ -363,7 +363,7 @@ class Simulator { ...@@ -363,7 +363,7 @@ class Simulator {
#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \ #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
Simulator::current()->Call( \ Simulator::current()->Call( \
FUNCTION_ADDR(entry), 7, p0, p1, p2, p3, p4, p5, p6) FUNCTION_ADDR(entry), 8, p0, p1, p2, p3, NULL, p4, p5, p6)
#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
try_catch_address == \ try_catch_address == \
......
...@@ -86,9 +86,6 @@ namespace internal { ...@@ -86,9 +86,6 @@ namespace internal {
CODE_STUB_LIST_ALL_PLATFORMS(V) \ CODE_STUB_LIST_ALL_PLATFORMS(V) \
CODE_STUB_LIST_ARM(V) CODE_STUB_LIST_ARM(V)
// Types of uncatchable exceptions.
enum UncatchableExceptionType { OUT_OF_MEMORY, TERMINATION };
// Mode to overwrite BinaryExpression values. // Mode to overwrite BinaryExpression values.
enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT }; enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
enum UnaryOverwriteMode { UNARY_OVERWRITE, UNARY_NO_OVERWRITE }; enum UnaryOverwriteMode { UNARY_OVERWRITE, UNARY_NO_OVERWRITE };
......
...@@ -3887,7 +3887,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { ...@@ -3887,7 +3887,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ IncrementCounter(&Counters::regexp_entry_native, 1); __ IncrementCounter(&Counters::regexp_entry_native, 1);
static const int kRegExpExecuteArguments = 7; static const int kRegExpExecuteArguments = 7;
__ PrepareCallCFunction(kRegExpExecuteArguments, ecx); __ EnterApiExitFrame(kRegExpExecuteArguments);
// Argument 7: Indicate that this is a direct call from JavaScript. // Argument 7: Indicate that this is a direct call from JavaScript.
__ mov(Operand(esp, 6 * kPointerSize), Immediate(1)); __ mov(Operand(esp, 6 * kPointerSize), Immediate(1));
...@@ -3932,7 +3932,10 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { ...@@ -3932,7 +3932,10 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Locate the code entry and call it. // Locate the code entry and call it.
__ add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag)); __ add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag));
__ CallCFunction(edx, kRegExpExecuteArguments); __ call(Operand(edx));
// Drop arguments and come back to JS mode.
__ LeaveApiExitFrame();
// Check the result. // Check the result.
Label success; Label success;
...@@ -3949,12 +3952,30 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { ...@@ -3949,12 +3952,30 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// haven't created the exception yet. Handle that in the runtime system. // haven't created the exception yet. Handle that in the runtime system.
// TODO(592): Rerunning the RegExp to get the stack overflow exception. // TODO(592): Rerunning the RegExp to get the stack overflow exception.
ExternalReference pending_exception(Top::k_pending_exception_address); ExternalReference pending_exception(Top::k_pending_exception_address);
__ mov(eax, __ mov(edx,
Operand::StaticVariable(ExternalReference::the_hole_value_location())); Operand::StaticVariable(ExternalReference::the_hole_value_location()));
__ cmp(eax, Operand::StaticVariable(pending_exception)); __ mov(eax, Operand::StaticVariable(pending_exception));
__ cmp(edx, Operand(eax));
__ j(equal, &runtime); __ j(equal, &runtime);
// For exception, throw the exception again.
// Clear the pending exception variable.
__ mov(Operand::StaticVariable(pending_exception), edx);
// Special handling of termination exceptions which are uncatchable
// by javascript code.
__ cmp(eax, Factory::termination_exception());
Label throw_termination_exception;
__ j(equal, &throw_termination_exception);
// Handle normal exception by following handler chain.
__ Throw(eax);
__ bind(&throw_termination_exception);
__ ThrowUncatchable(TERMINATION, eax);
__ bind(&failure); __ bind(&failure);
// For failure and exception return null. // For failure to match, return null.
__ mov(Operand(eax), Factory::null_value()); __ mov(Operand(eax), Factory::null_value());
__ ret(4 * kPointerSize); __ ret(4 * kPointerSize);
...@@ -4628,34 +4649,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { ...@@ -4628,34 +4649,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
// eax holds the exception. __ Throw(eax);
// Adjust this code if not the case.
STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
// Drop the sp to the top of the handler.
ExternalReference handler_address(Top::k_handler_address);
__ mov(esp, Operand::StaticVariable(handler_address));
// Restore next handler and frame pointer, discard handler state.
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
__ pop(Operand::StaticVariable(handler_address));
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize);
__ pop(ebp);
__ pop(edx); // Remove state.
// Before returning we restore the context from the frame pointer if
// not NULL. The frame pointer is NULL in the exception handler of
// a JS entry frame.
__ Set(esi, Immediate(0)); // Tentatively set context pointer to NULL.
NearLabel skip;
__ cmp(ebp, 0);
__ j(equal, &skip, not_taken);
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ bind(&skip);
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
__ ret(0);
} }
...@@ -4778,52 +4772,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, ...@@ -4778,52 +4772,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm, void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm,
UncatchableExceptionType type) { UncatchableExceptionType type) {
// Adjust this code if not the case. __ ThrowUncatchable(type, eax);
STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
// Drop sp to the top stack handler.
ExternalReference handler_address(Top::k_handler_address);
__ mov(esp, Operand::StaticVariable(handler_address));
// Unwind the handlers until the ENTRY handler is found.
NearLabel loop, done;
__ bind(&loop);
// Load the type of the current stack handler.
const int kStateOffset = StackHandlerConstants::kStateOffset;
__ cmp(Operand(esp, kStateOffset), Immediate(StackHandler::ENTRY));
__ j(equal, &done);
// Fetch the next handler in the list.
const int kNextOffset = StackHandlerConstants::kNextOffset;
__ mov(esp, Operand(esp, kNextOffset));
__ jmp(&loop);
__ bind(&done);
// Set the top handler address to next handler past the current ENTRY handler.
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
__ pop(Operand::StaticVariable(handler_address));
if (type == OUT_OF_MEMORY) {
// Set external caught exception to false.
ExternalReference external_caught(Top::k_external_caught_exception_address);
__ mov(eax, false);
__ mov(Operand::StaticVariable(external_caught), eax);
// Set pending exception and eax to out of memory exception.
ExternalReference pending_exception(Top::k_pending_exception_address);
__ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
__ mov(Operand::StaticVariable(pending_exception), eax);
}
// Clear the context pointer.
__ Set(esi, Immediate(0));
// Restore fp from handler and discard handler state.
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize);
__ pop(ebp);
__ pop(edx); // State.
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
__ ret(0);
} }
......
...@@ -448,6 +448,97 @@ void MacroAssembler::PopTryHandler() { ...@@ -448,6 +448,97 @@ void MacroAssembler::PopTryHandler() {
} }
void MacroAssembler::Throw(Register value) {
// Adjust this code if not the case.
STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
// eax must hold the exception.
if (!value.is(eax)) {
mov(eax, value);
}
// Drop the sp to the top of the handler.
ExternalReference handler_address(Top::k_handler_address);
mov(esp, Operand::StaticVariable(handler_address));
// Restore next handler and frame pointer, discard handler state.
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(Operand::StaticVariable(handler_address));
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize);
pop(ebp);
pop(edx); // Remove state.
// Before returning we restore the context from the frame pointer if
// not NULL. The frame pointer is NULL in the exception handler of
// a JS entry frame.
Set(esi, Immediate(0)); // Tentatively set context pointer to NULL.
NearLabel skip;
cmp(ebp, 0);
j(equal, &skip, not_taken);
mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
bind(&skip);
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
ret(0);
}
void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
Register value) {
// Adjust this code if not the case.
STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
// eax must hold the exception.
if (!value.is(eax)) {
mov(eax, value);
}
// Drop sp to the top stack handler.
ExternalReference handler_address(Top::k_handler_address);
mov(esp, Operand::StaticVariable(handler_address));
// Unwind the handlers until the ENTRY handler is found.
NearLabel loop, done;
bind(&loop);
// Load the type of the current stack handler.
const int kStateOffset = StackHandlerConstants::kStateOffset;
cmp(Operand(esp, kStateOffset), Immediate(StackHandler::ENTRY));
j(equal, &done);
// Fetch the next handler in the list.
const int kNextOffset = StackHandlerConstants::kNextOffset;
mov(esp, Operand(esp, kNextOffset));
jmp(&loop);
bind(&done);
// Set the top handler address to next handler past the current ENTRY handler.
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(Operand::StaticVariable(handler_address));
if (type == OUT_OF_MEMORY) {
// Set external caught exception to false.
ExternalReference external_caught(Top::k_external_caught_exception_address);
mov(eax, false);
mov(Operand::StaticVariable(external_caught), eax);
// Set pending exception and eax to out of memory exception.
ExternalReference pending_exception(Top::k_pending_exception_address);
mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
mov(Operand::StaticVariable(pending_exception), eax);
}
// Clear the context pointer.
Set(esi, Immediate(0));
// Restore fp from handler and discard handler state.
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize);
pop(ebp);
pop(edx); // State.
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
ret(0);
}
void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
Register scratch, Register scratch,
Label* miss) { Label* miss) {
......
...@@ -304,6 +304,11 @@ class MacroAssembler: public Assembler { ...@@ -304,6 +304,11 @@ class MacroAssembler: public Assembler {
// Unlink the stack handler on top of the stack from the try handler chain. // Unlink the stack handler on top of the stack from the try handler chain.
void PopTryHandler(); void PopTryHandler();
// Activate the top handler in the try hander chain.
void Throw(Register value);
void ThrowUncatchable(UncatchableExceptionType type, Register value);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Inline caching support // Inline caching support
......
...@@ -50,6 +50,13 @@ enum HandlerType { ...@@ -50,6 +50,13 @@ enum HandlerType {
}; };
// Types of uncatchable exceptions.
enum UncatchableExceptionType {
OUT_OF_MEMORY,
TERMINATION
};
// Invalid depth in prototype chain. // Invalid depth in prototype chain.
const int kInvalidProtoDepth = -1; const int kInvalidProtoDepth = -1;
......
This diff is collapsed.
...@@ -1542,6 +1542,96 @@ void MacroAssembler::PopTryHandler() { ...@@ -1542,6 +1542,96 @@ void MacroAssembler::PopTryHandler() {
} }
void MacroAssembler::Throw(Register value) {
// Check that stack should contain next handler, frame pointer, state and
// return address in that order.
STATIC_ASSERT(StackHandlerConstants::kFPOffset + kPointerSize ==
StackHandlerConstants::kStateOffset);
STATIC_ASSERT(StackHandlerConstants::kStateOffset + kPointerSize ==
StackHandlerConstants::kPCOffset);
// Keep thrown value in rax.
if (!value.is(rax)) {
movq(rax, value);
}
ExternalReference handler_address(Top::k_handler_address);
movq(kScratchRegister, handler_address);
movq(rsp, Operand(kScratchRegister, 0));
// get next in chain
pop(rcx);
movq(Operand(kScratchRegister, 0), rcx);
pop(rbp); // pop frame pointer
pop(rdx); // remove state
// Before returning we restore the context from the frame pointer if not NULL.
// The frame pointer is NULL in the exception handler of a JS entry frame.
Set(rsi, 0); // Tentatively set context pointer to NULL
NearLabel skip;
cmpq(rbp, Immediate(0));
j(equal, &skip);
movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
bind(&skip);
ret(0);
}
void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
Register value) {
// Keep thrown value in rax.
if (!value.is(rax)) {
movq(rax, value);
}
// Fetch top stack handler.
ExternalReference handler_address(Top::k_handler_address);
movq(kScratchRegister, handler_address);
movq(rsp, Operand(kScratchRegister, 0));
// Unwind the handlers until the ENTRY handler is found.
NearLabel loop, done;
bind(&loop);
// Load the type of the current stack handler.
const int kStateOffset = StackHandlerConstants::kStateOffset;
cmpq(Operand(rsp, kStateOffset), Immediate(StackHandler::ENTRY));
j(equal, &done);
// Fetch the next handler in the list.
const int kNextOffset = StackHandlerConstants::kNextOffset;
movq(rsp, Operand(rsp, kNextOffset));
jmp(&loop);
bind(&done);
// Set the top handler address to next handler past the current ENTRY handler.
movq(kScratchRegister, handler_address);
pop(Operand(kScratchRegister, 0));
if (type == OUT_OF_MEMORY) {
// Set external caught exception to false.
ExternalReference external_caught(Top::k_external_caught_exception_address);
movq(rax, Immediate(false));
store_rax(external_caught);
// Set pending exception and rax to out of memory exception.
ExternalReference pending_exception(Top::k_pending_exception_address);
movq(rax, Failure::OutOfMemoryException(), RelocInfo::NONE);
store_rax(pending_exception);
}
// Clear the context pointer.
Set(rsi, 0);
// Restore registers from handler.
STATIC_ASSERT(StackHandlerConstants::kNextOffset + kPointerSize ==
StackHandlerConstants::kFPOffset);
pop(rbp); // FP
STATIC_ASSERT(StackHandlerConstants::kFPOffset + kPointerSize ==
StackHandlerConstants::kStateOffset);
pop(rdx); // State
STATIC_ASSERT(StackHandlerConstants::kStateOffset + kPointerSize ==
StackHandlerConstants::kPCOffset);
ret(0);
}
void MacroAssembler::Ret() { void MacroAssembler::Ret() {
ret(0); ret(0);
} }
......
...@@ -680,6 +680,13 @@ class MacroAssembler: public Assembler { ...@@ -680,6 +680,13 @@ class MacroAssembler: public Assembler {
// Unlink the stack handler on top of the stack from the try handler chain. // Unlink the stack handler on top of the stack from the try handler chain.
void PopTryHandler(); void PopTryHandler();
// Activate the top handler in the try hander chain and pass the
// thrown value.
void Throw(Register value);
// Propagate an uncatchable exception out of the current JS stack.
void ThrowUncatchable(UncatchableExceptionType type, Register value);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Inline caching support // Inline caching support
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment