summaryrefslogtreecommitdiff
path: root/deps/v8/src/x64/code-stubs-x64.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/x64/code-stubs-x64.cc')
-rw-r--r--deps/v8/src/x64/code-stubs-x64.cc323
1 files changed, 180 insertions, 143 deletions
diff --git a/deps/v8/src/x64/code-stubs-x64.cc b/deps/v8/src/x64/code-stubs-x64.cc
index b0cadda6d3..0cfe665ced 100644
--- a/deps/v8/src/x64/code-stubs-x64.cc
+++ b/deps/v8/src/x64/code-stubs-x64.cc
@@ -2268,46 +2268,46 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// rcx: RegExp data (FixedArray)
// rdx: Number of capture registers
// Check that the second argument is a string.
- __ movq(rax, Operand(rsp, kSubjectOffset));
- __ JumpIfSmi(rax, &runtime);
- Condition is_string = masm->IsObjectStringType(rax, rbx, rbx);
+ __ movq(rdi, Operand(rsp, kSubjectOffset));
+ __ JumpIfSmi(rdi, &runtime);
+ Condition is_string = masm->IsObjectStringType(rdi, rbx, rbx);
__ j(NegateCondition(is_string), &runtime);
- // rax: Subject string.
- // rcx: RegExp data (FixedArray).
+ // rdi: Subject string.
+ // rax: RegExp data (FixedArray).
// rdx: Number of capture registers.
// Check that the third argument is a positive smi less than the string
// length. A negative value will be greater (unsigned comparison).
__ movq(rbx, Operand(rsp, kPreviousIndexOffset));
__ JumpIfNotSmi(rbx, &runtime);
- __ SmiCompare(rbx, FieldOperand(rax, String::kLengthOffset));
+ __ SmiCompare(rbx, FieldOperand(rdi, String::kLengthOffset));
__ j(above_equal, &runtime);
- // rcx: RegExp data (FixedArray)
+ // rax: RegExp data (FixedArray)
// rdx: Number of capture registers
// Check that the fourth object is a JSArray object.
- __ movq(rax, Operand(rsp, kLastMatchInfoOffset));
- __ JumpIfSmi(rax, &runtime);
- __ CmpObjectType(rax, JS_ARRAY_TYPE, kScratchRegister);
+ __ movq(rdi, Operand(rsp, kLastMatchInfoOffset));
+ __ JumpIfSmi(rdi, &runtime);
+ __ CmpObjectType(rdi, JS_ARRAY_TYPE, kScratchRegister);
__ j(not_equal, &runtime);
// Check that the JSArray is in fast case.
- __ movq(rbx, FieldOperand(rax, JSArray::kElementsOffset));
- __ movq(rax, FieldOperand(rbx, HeapObject::kMapOffset));
- __ Cmp(rax, Factory::fixed_array_map());
+ __ movq(rbx, FieldOperand(rdi, JSArray::kElementsOffset));
+ __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
+ __ Cmp(rdi, Factory::fixed_array_map());
__ j(not_equal, &runtime);
// Check that the last match info has space for the capture registers and the
// additional information. Ensure no overflow in add.
STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset);
- __ SmiToInteger32(rax, FieldOperand(rbx, FixedArray::kLengthOffset));
+ __ SmiToInteger32(rdi, FieldOperand(rbx, FixedArray::kLengthOffset));
__ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead));
- __ cmpl(rdx, rax);
+ __ cmpl(rdx, rdi);
__ j(greater, &runtime);
- // rcx: RegExp data (FixedArray)
+ // rax: RegExp data (FixedArray)
// Check the representation and encoding of the subject string.
NearLabel seq_ascii_string, seq_two_byte_string, check_code;
- __ movq(rax, Operand(rsp, kSubjectOffset));
- __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
+ __ movq(rdi, Operand(rsp, kSubjectOffset));
+ __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset));
__ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
// First check for flat two byte string.
__ andb(rbx, Immediate(
@@ -2328,13 +2328,13 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ testb(rbx, Immediate(kIsNotStringMask | kExternalStringTag));
__ j(not_zero, &runtime);
// String is a cons string.
- __ movq(rdx, FieldOperand(rax, ConsString::kSecondOffset));
+ __ movq(rdx, FieldOperand(rdi, ConsString::kSecondOffset));
__ Cmp(rdx, Factory::empty_string());
__ j(not_equal, &runtime);
- __ movq(rax, FieldOperand(rax, ConsString::kFirstOffset));
- __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
+ __ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset));
+ __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset));
// String is a cons string with empty second part.
- // rax: first part of cons string.
+ // rdi: first part of cons string.
// rbx: map of first part of cons string.
// Is first part a flat two byte string?
__ testb(FieldOperand(rbx, Map::kInstanceTypeOffset),
@@ -2347,17 +2347,17 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ j(not_zero, &runtime);
__ bind(&seq_ascii_string);
- // rax: subject string (sequential ascii)
- // rcx: RegExp data (FixedArray)
- __ movq(r11, FieldOperand(rcx, JSRegExp::kDataAsciiCodeOffset));
- __ Set(rdi, 1); // Type is ascii.
+ // rdi: subject string (sequential ascii)
+ // rax: RegExp data (FixedArray)
+ __ movq(r11, FieldOperand(rax, JSRegExp::kDataAsciiCodeOffset));
+ __ Set(rcx, 1); // Type is ascii.
__ jmp(&check_code);
__ bind(&seq_two_byte_string);
- // rax: subject string (flat two-byte)
- // rcx: RegExp data (FixedArray)
- __ movq(r11, FieldOperand(rcx, JSRegExp::kDataUC16CodeOffset));
- __ Set(rdi, 0); // Type is two byte.
+ // rdi: subject string (flat two-byte)
+ // rax: RegExp data (FixedArray)
+ __ movq(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset));
+ __ Set(rcx, 0); // Type is two byte.
__ bind(&check_code);
// Check that the irregexp code has been generated for the actual string
@@ -2366,27 +2366,24 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ CmpObjectType(r11, CODE_TYPE, kScratchRegister);
__ j(not_equal, &runtime);
- // rax: subject string
- // rdi: encoding of subject string (1 if ascii, 0 if two_byte);
+ // rdi: subject string
+ // rcx: encoding of subject string (1 if ascii, 0 if two_byte);
// r11: code
// Load used arguments before starting to push arguments for call to native
// RegExp code to avoid handling changing stack height.
__ SmiToInteger64(rbx, Operand(rsp, kPreviousIndexOffset));
- // rax: subject string
+ // rdi: subject string
// rbx: previous index
- // rdi: encoding of subject string (1 if ascii 0 if two_byte);
+ // rcx: encoding of subject string (1 if ascii 0 if two_byte);
// r11: code
// All checks done. Now push arguments for native regexp code.
__ IncrementCounter(&Counters::regexp_entry_native, 1);
- // rsi is caller save on Windows and used to pass parameter on Linux.
- __ push(rsi);
-
static const int kRegExpExecuteArguments = 7;
- __ PrepareCallCFunction(kRegExpExecuteArguments);
int argument_slots_on_stack =
masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments);
+ __ EnterApiExitFrame(argument_slots_on_stack); // Clobbers rax!
// Argument 7: Indicate that this is a direct call from JavaScript.
__ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize),
@@ -2423,60 +2420,57 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
#endif
// Keep track on aliasing between argX defined above and the registers used.
- // rax: subject string
+ // rdi: subject string
// rbx: previous index
- // rdi: encoding of subject string (1 if ascii 0 if two_byte);
+ // rcx: encoding of subject string (1 if ascii 0 if two_byte);
// r11: code
// Argument 4: End of string data
// Argument 3: Start of string data
NearLabel setup_two_byte, setup_rest;
- __ testb(rdi, rdi);
+ __ testb(rcx, rcx); // Last use of rcx as encoding of subject string.
__ j(zero, &setup_two_byte);
- __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset));
- __ lea(arg4, FieldOperand(rax, rdi, times_1, SeqAsciiString::kHeaderSize));
- __ lea(arg3, FieldOperand(rax, rbx, times_1, SeqAsciiString::kHeaderSize));
+ __ SmiToInteger32(rcx, FieldOperand(rdi, String::kLengthOffset));
+ __ lea(arg4, FieldOperand(rdi, rcx, times_1, SeqAsciiString::kHeaderSize));
+ __ lea(arg3, FieldOperand(rdi, rbx, times_1, SeqAsciiString::kHeaderSize));
__ jmp(&setup_rest);
__ bind(&setup_two_byte);
- __ SmiToInteger32(rdi, FieldOperand(rax, String::kLengthOffset));
- __ lea(arg4, FieldOperand(rax, rdi, times_2, SeqTwoByteString::kHeaderSize));
- __ lea(arg3, FieldOperand(rax, rbx, times_2, SeqTwoByteString::kHeaderSize));
+ __ SmiToInteger32(rcx, FieldOperand(rdi, String::kLengthOffset));
+ __ lea(arg4, FieldOperand(rdi, rcx, times_2, SeqTwoByteString::kHeaderSize));
+ __ lea(arg3, FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize));
__ bind(&setup_rest);
// Argument 2: Previous index.
__ movq(arg2, rbx);
// Argument 1: Subject string.
- __ movq(arg1, rax);
+#ifdef WIN64_
+ __ movq(arg1, rdi);
+#else
+ // Already there in AMD64 calling convention.
+ ASSERT(arg1.is(rdi));
+#endif
// Locate the code entry and call it.
__ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag));
- __ CallCFunction(r11, kRegExpExecuteArguments);
+ __ call(r11);
- // rsi is caller save, as it is used to pass parameter.
- __ pop(rsi);
+ __ LeaveApiExitFrame();
// Check the result.
NearLabel success;
+ Label exception;
__ cmpl(rax, Immediate(NativeRegExpMacroAssembler::SUCCESS));
__ j(equal, &success);
- NearLabel failure;
- __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE));
- __ j(equal, &failure);
__ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION));
- // If not exception it can only be retry. Handle that in the runtime system.
+ __ j(equal, &exception);
+ __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE));
+ // If none of the above, it can only be retry.
+ // Handle that in the runtime system.
__ j(not_equal, &runtime);
- // Result must now be exception. If there is no pending exception already a
- // stack overflow (on the backtrack stack) was detected in RegExp code but
- // haven't created the exception yet. Handle that in the runtime system.
- // TODO(592): Rerunning the RegExp to get the stack overflow exception.
- ExternalReference pending_exception_address(Top::k_pending_exception_address);
- __ movq(kScratchRegister, pending_exception_address);
- __ Cmp(kScratchRegister, Factory::the_hole_value());
- __ j(equal, &runtime);
- __ bind(&failure);
- // For failure and exception return null.
- __ Move(rax, Factory::null_value());
+
+ // For failure return null.
+ __ LoadRoot(rax, Heap::kNullValueRootIndex);
__ ret(4 * kPointerSize);
// Load RegExp data.
@@ -2537,6 +2531,27 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ movq(rax, Operand(rsp, kLastMatchInfoOffset));
__ ret(4 * kPointerSize);
+ __ bind(&exception);
+ // Result must now be exception. If there is no pending exception already a
+ // stack overflow (on the backtrack stack) was detected in RegExp code but
+ // haven't created the exception yet. Handle that in the runtime system.
+ // TODO(592): Rerunning the RegExp to get the stack overflow exception.
+ ExternalReference pending_exception_address(Top::k_pending_exception_address);
+ __ movq(rbx, pending_exception_address);
+ __ movq(rax, Operand(rbx, 0));
+ __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex);
+ __ cmpq(rax, rdx);
+ __ j(equal, &runtime);
+ __ movq(Operand(rbx, 0), rdx);
+
+ __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex);
+ NearLabel termination_exception;
+ __ j(equal, &termination_exception);
+ __ Throw(rax);
+
+ __ bind(&termination_exception);
+ __ ThrowUncatchable(TERMINATION, rax);
+
// Do the runtime call to execute the regexp.
__ bind(&runtime);
__ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
@@ -3085,31 +3100,8 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
- // 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);
-
- 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);
+ // Throw exception in eax.
+ __ Throw(rax);
}
@@ -3251,54 +3243,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm,
UncatchableExceptionType type) {
- // 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);
+ __ ThrowUncatchable(type, rax);
}
@@ -4627,10 +4572,10 @@ void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
if (GetCondition() == equal) {
// For equality we do not care about the sign of the result.
- __ SmiSub(rax, rax, rdx);
+ __ subq(rax, rdx);
} else {
NearLabel done;
- __ SmiSub(rdx, rdx, rax);
+ __ subq(rdx, rax);
__ j(no_overflow, &done);
// Correct sign of result in case of overflow.
__ SmiNot(rdx, rdx);
@@ -4767,9 +4712,19 @@ void GenerateFastPixelArrayLoad(MacroAssembler* masm,
}
__ SmiToInteger32(untagged_key, key);
- // Verify that the receiver has pixel array elements.
__ movq(elements, FieldOperand(receiver, JSObject::kElementsOffset));
- __ CheckMap(elements, Factory::pixel_array_map(), not_pixel_array, true);
+ // By passing NULL as not_pixel_array, callers signal that they have already
+ // verified that the receiver has pixel array elements.
+ if (not_pixel_array != NULL) {
+ __ CheckMap(elements, Factory::pixel_array_map(), not_pixel_array, true);
+ } else {
+ if (FLAG_debug_code) {
+ // Map check should have already made sure that elements is a pixel array.
+ __ Cmp(FieldOperand(elements, HeapObject::kMapOffset),
+ Factory::pixel_array_map());
+ __ Assert(equal, "Elements isn't a pixel array");
+ }
+ }
// Check that the smi is in range.
__ cmpl(untagged_key, FieldOperand(elements, PixelArray::kLengthOffset));
@@ -4783,6 +4738,88 @@ void GenerateFastPixelArrayLoad(MacroAssembler* masm,
}
+// Stores an indexed element into a pixel array, clamping the stored value.
+void GenerateFastPixelArrayStore(MacroAssembler* masm,
+ Register receiver,
+ Register key,
+ Register value,
+ Register elements,
+ Register scratch1,
+ bool load_elements_from_receiver,
+ bool key_is_untagged,
+ Label* key_not_smi,
+ Label* value_not_smi,
+ Label* not_pixel_array,
+ Label* out_of_range) {
+ // Register use:
+ // receiver - holds the receiver and is unchanged.
+ // key - holds the key (must be a smi) and is unchanged.
+ // value - holds the value (must be a smi) and is unchanged.
+ // elements - holds the element object of the receiver on entry if
+ // load_elements_from_receiver is false, otherwise used
+ // internally to store the pixel arrays elements and
+ // external array pointer.
+ //
+ Register external_pointer = elements;
+ Register untagged_key = scratch1;
+ Register untagged_value = receiver; // Only set once success guaranteed.
+
+ // Fetch the receiver's elements if the caller hasn't already done so.
+ if (load_elements_from_receiver) {
+ __ movq(elements, FieldOperand(receiver, JSObject::kElementsOffset));
+ }
+
+ // By passing NULL as not_pixel_array, callers signal that they have already
+ // verified that the receiver has pixel array elements.
+ if (not_pixel_array != NULL) {
+ __ CheckMap(elements, Factory::pixel_array_map(), not_pixel_array, true);
+ } else {
+ if (FLAG_debug_code) {
+ // Map check should have already made sure that elements is a pixel array.
+ __ Cmp(FieldOperand(elements, HeapObject::kMapOffset),
+ Factory::pixel_array_map());
+ __ Assert(equal, "Elements isn't a pixel array");
+ }
+ }
+
+ // Key must be a smi and it must be in range.
+ if (key_is_untagged) {
+ untagged_key = key;
+ } else {
+ // Some callers already have verified that the key is a smi. key_not_smi is
+ // set to NULL as a sentinel for that case. Otherwise, add an explicit
+ // check to ensure the key is a smi.
+ if (key_not_smi != NULL) {
+ __ JumpIfNotSmi(key, key_not_smi);
+ } else {
+ if (FLAG_debug_code) {
+ __ AbortIfNotSmi(key);
+ }
+ }
+ __ SmiToInteger32(untagged_key, key);
+ }
+ __ cmpl(untagged_key, FieldOperand(elements, PixelArray::kLengthOffset));
+ __ j(above_equal, out_of_range); // unsigned check handles negative keys.
+
+ // Value must be a smi.
+ __ JumpIfNotSmi(value, value_not_smi);
+ __ SmiToInteger32(untagged_value, value);
+
+ { // Clamp the value to [0..255].
+ NearLabel done;
+ __ testl(untagged_value, Immediate(0xFFFFFF00));
+ __ j(zero, &done);
+ __ setcc(negative, untagged_value); // 1 if negative, 0 if positive.
+ __ decb(untagged_value); // 0 if negative, 255 if positive.
+ __ bind(&done);
+ }
+
+ __ movq(external_pointer,
+ FieldOperand(elements, PixelArray::kExternalPointerOffset));
+ __ movb(Operand(external_pointer, untagged_key, times_1, 0), untagged_value);
+ __ ret(0); // Return value in eax.
+}
+
#undef __
} } // namespace v8::internal