Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1318)

Unified Diff: src/x64/code-stubs-x64.cc

Issue 6697023: Merge 6800:7180 from the bleeding edge branch to the experimental/gc branch. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/x64/code-stubs-x64.h ('k') | src/x64/codegen-x64.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/x64/code-stubs-x64.cc
===================================================================
--- src/x64/code-stubs-x64.cc (revision 7180)
+++ src/x64/code-stubs-x64.cc (working copy)
@@ -46,8 +46,8 @@
__ Ret();
__ bind(&check_heap_number);
- __ Move(rbx, Factory::heap_number_map());
- __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
+ __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
+ Heap::kHeapNumberMapRootIndex);
__ j(not_equal, &call_builtin);
__ Ret();
@@ -104,7 +104,7 @@
__ pop(rdx);
__ push(rsi);
__ push(rdx);
- __ Push(Factory::false_value());
+ __ PushRoot(Heap::kFalseValueRootIndex);
__ push(rcx); // Restore return address.
__ TailCallRuntime(Runtime::kNewClosure, 3, 1);
}
@@ -1375,54 +1375,33 @@
void TypeRecordingBinaryOpStub::GenerateStringAddCode(MacroAssembler* masm) {
- GenerateRegisterArgsPush(masm);
+ ASSERT(op_ == Token::ADD);
+ NearLabel left_not_string, call_runtime;
+
// Registers containing left and right operands respectively.
- Register lhs = rdx;
- Register rhs = rax;
+ Register left = rdx;
+ Register right = rax;
- // Test for string arguments before calling runtime.
- Label not_strings, both_strings, not_string1, string1, string1_smi2;
+ // Test if left operand is a string.
+ __ JumpIfSmi(left, &left_not_string);
+ __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx);
+ __ j(above_equal, &left_not_string);
+ StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB);
+ GenerateRegisterArgsPush(masm);
+ __ TailCallStub(&string_add_left_stub);
- __ JumpIfNotString(lhs, r8, &not_string1);
+ // Left operand is not a string, test right.
+ __ bind(&left_not_string);
+ __ JumpIfSmi(right, &call_runtime);
+ __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx);
+ __ j(above_equal, &call_runtime);
- // First argument is a a string, test second.
- __ JumpIfSmi(rhs, &string1_smi2);
- __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, r9);
- __ j(above_equal, &string1);
+ StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
+ GenerateRegisterArgsPush(masm);
+ __ TailCallStub(&string_add_right_stub);
- // First and second argument are strings.
- StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
- __ TailCallStub(&string_add_stub);
-
- __ bind(&string1_smi2);
- // First argument is a string, second is a smi. Try to lookup the number
- // string for the smi in the number string cache.
- NumberToStringStub::GenerateLookupNumberStringCache(
- masm, rhs, rbx, rcx, r8, true, &string1);
-
- // Replace second argument on stack and tailcall string add stub to make
- // the result.
- __ movq(Operand(rsp, 1 * kPointerSize), rbx);
- __ TailCallStub(&string_add_stub);
-
- // Only first argument is a string.
- __ bind(&string1);
- __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION);
-
- // First argument was not a string, test second.
- __ bind(&not_string1);
- __ JumpIfNotString(rhs, rhs, &not_strings);
-
- // Only second argument is a string.
- __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION);
-
- __ bind(&not_strings);
// Neither argument is a string.
- // Pop arguments, because CallRuntimeCode wants to push them again.
- __ pop(rcx);
- __ pop(rax);
- __ pop(rdx);
- __ push(rcx);
+ __ bind(&call_runtime);
}
@@ -1479,9 +1458,11 @@
void TypeRecordingBinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
+ ASSERT(operands_type_ == TRBinaryOpIC::STRING);
ASSERT(op_ == Token::ADD);
GenerateStringAddCode(masm);
-
+ // Try to add arguments as strings, otherwise, transition to the generic
+ // TRBinaryOpIC type.
GenerateTypeTransition(masm);
}
@@ -1564,40 +1545,59 @@
void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
- // Input on stack:
- // rsp[8]: argument (should be number).
- // rsp[0]: return address.
+ // TAGGED case:
+ // Input:
+ // rsp[8]: argument (should be number).
+ // rsp[0]: return address.
+ // Output:
+ // rax: tagged double result.
+ // UNTAGGED case:
+ // Input::
+ // rsp[0]: return address.
+ // xmm1: untagged double input argument
+ // Output:
+ // xmm1: untagged double result.
+
Label runtime_call;
Label runtime_call_clear_stack;
- Label input_not_smi;
- NearLabel loaded;
- // Test that rax is a number.
- __ movq(rax, Operand(rsp, kPointerSize));
- __ JumpIfNotSmi(rax, &input_not_smi);
- // Input is a smi. Untag and load it onto the FPU stack.
- // Then load the bits of the double into rbx.
- __ SmiToInteger32(rax, rax);
- __ subq(rsp, Immediate(kPointerSize));
- __ cvtlsi2sd(xmm1, rax);
- __ movsd(Operand(rsp, 0), xmm1);
- __ movq(rbx, xmm1);
- __ movq(rdx, xmm1);
- __ fld_d(Operand(rsp, 0));
- __ addq(rsp, Immediate(kPointerSize));
- __ jmp(&loaded);
+ Label skip_cache;
+ const bool tagged = (argument_type_ == TAGGED);
+ if (tagged) {
+ NearLabel input_not_smi;
+ NearLabel loaded;
+ // Test that rax is a number.
+ __ movq(rax, Operand(rsp, kPointerSize));
+ __ JumpIfNotSmi(rax, &input_not_smi);
+ // Input is a smi. Untag and load it onto the FPU stack.
+ // Then load the bits of the double into rbx.
+ __ SmiToInteger32(rax, rax);
+ __ subq(rsp, Immediate(kDoubleSize));
+ __ cvtlsi2sd(xmm1, rax);
+ __ movsd(Operand(rsp, 0), xmm1);
+ __ movq(rbx, xmm1);
+ __ movq(rdx, xmm1);
+ __ fld_d(Operand(rsp, 0));
+ __ addq(rsp, Immediate(kDoubleSize));
+ __ jmp(&loaded);
- __ bind(&input_not_smi);
- // Check if input is a HeapNumber.
- __ Move(rbx, Factory::heap_number_map());
- __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
- __ j(not_equal, &runtime_call);
- // Input is a HeapNumber. Push it on the FPU stack and load its
- // bits into rbx.
- __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
- __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
- __ movq(rdx, rbx);
- __ bind(&loaded);
- // ST[0] == double value
+ __ bind(&input_not_smi);
+ // Check if input is a HeapNumber.
+ __ LoadRoot(rbx, Heap::kHeapNumberMapRootIndex);
+ __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
+ __ j(not_equal, &runtime_call);
+ // Input is a HeapNumber. Push it on the FPU stack and load its
+ // bits into rbx.
+ __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
+ __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
+ __ movq(rdx, rbx);
+
+ __ bind(&loaded);
+ } else { // UNTAGGED.
+ __ movq(rbx, xmm1);
+ __ movq(rdx, xmm1);
+ }
+
+ // ST[0] == double value, if TAGGED.
// rbx = bits of double value.
// rdx = also bits of double value.
// Compute hash (h is 32 bits, bits are 64 and the shifts are arithmetic):
@@ -1629,7 +1629,7 @@
// rax points to the cache for the type type_.
// If NULL, the cache hasn't been initialized yet, so go through runtime.
__ testq(rax, rax);
- __ j(zero, &runtime_call_clear_stack);
+ __ j(zero, &runtime_call_clear_stack); // Only clears stack if TAGGED.
#ifdef DEBUG
// Check that the layout of cache elements match expectations.
{ // NOLINT - doesn't like a single brace on a line.
@@ -1655,30 +1655,70 @@
__ j(not_equal, &cache_miss);
// Cache hit!
__ movq(rax, Operand(rcx, 2 * kIntSize));
- __ fstp(0); // Clear FPU stack.
- __ ret(kPointerSize);
+ if (tagged) {
+ __ fstp(0); // Clear FPU stack.
+ __ ret(kPointerSize);
+ } else { // UNTAGGED.
+ __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
+ __ Ret();
+ }
__ bind(&cache_miss);
// Update cache with new value.
- Label nan_result;
- GenerateOperation(masm, &nan_result);
+ if (tagged) {
__ AllocateHeapNumber(rax, rdi, &runtime_call_clear_stack);
+ } else { // UNTAGGED.
+ __ AllocateHeapNumber(rax, rdi, &skip_cache);
+ __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm1);
+ __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
+ }
+ GenerateOperation(masm);
__ movq(Operand(rcx, 0), rbx);
__ movq(Operand(rcx, 2 * kIntSize), rax);
__ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset));
- __ ret(kPointerSize);
+ if (tagged) {
+ __ ret(kPointerSize);
+ } else { // UNTAGGED.
+ __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
+ __ Ret();
- __ bind(&runtime_call_clear_stack);
- __ fstp(0);
- __ bind(&runtime_call);
- __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
+ // Skip cache and return answer directly, only in untagged case.
+ __ bind(&skip_cache);
+ __ subq(rsp, Immediate(kDoubleSize));
+ __ movsd(Operand(rsp, 0), xmm1);
+ __ fld_d(Operand(rsp, 0));
+ GenerateOperation(masm);
+ __ fstp_d(Operand(rsp, 0));
+ __ movsd(xmm1, Operand(rsp, 0));
+ __ addq(rsp, Immediate(kDoubleSize));
+ // We return the value in xmm1 without adding it to the cache, but
+ // we cause a scavenging GC so that future allocations will succeed.
+ __ EnterInternalFrame();
+ // Allocate an unused object bigger than a HeapNumber.
+ __ Push(Smi::FromInt(2 * kDoubleSize));
+ __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
+ __ LeaveInternalFrame();
+ __ Ret();
+ }
- __ bind(&nan_result);
- __ fstp(0); // Remove argument from FPU stack.
- __ LoadRoot(rax, Heap::kNanValueRootIndex);
- __ movq(Operand(rcx, 0), rbx);
- __ movq(Operand(rcx, 2 * kIntSize), rax);
- __ ret(kPointerSize);
+ // Call runtime, doing whatever allocation and cleanup is necessary.
+ if (tagged) {
+ __ bind(&runtime_call_clear_stack);
+ __ fstp(0);
+ __ bind(&runtime_call);
+ __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
+ } else { // UNTAGGED.
+ __ bind(&runtime_call_clear_stack);
+ __ bind(&runtime_call);
+ __ AllocateHeapNumber(rax, rdi, &skip_cache);
+ __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm1);
+ __ EnterInternalFrame();
+ __ push(rax);
+ __ CallRuntime(RuntimeFunction(), 1);
+ __ LeaveInternalFrame();
+ __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
+ __ Ret();
+ }
}
@@ -1695,9 +1735,9 @@
}
-void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm,
- Label* on_nan_result) {
+void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
// Registers:
+ // rax: Newly allocated HeapNumber, which must be preserved.
// rbx: Bits of input double. Must be preserved.
// rcx: Pointer to cache entry. Must be preserved.
// st(0): Input double
@@ -1719,9 +1759,18 @@
__ j(below, &in_range);
// Check for infinity and NaN. Both return NaN for sin.
__ cmpl(rdi, Immediate(0x7ff));
- __ j(equal, on_nan_result);
+ NearLabel non_nan_result;
+ __ j(not_equal, &non_nan_result);
+ // Input is +/-Infinity or NaN. Result is NaN.
+ __ fstp(0);
+ __ LoadRoot(kScratchRegister, Heap::kNanValueRootIndex);
+ __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset));
+ __ jmp(&done);
+ __ bind(&non_nan_result);
+
// Use fpmod to restrict argument to the range +/-2*PI.
+ __ movq(rdi, rax); // Save rax before using fnstsw_ax.
__ fldpi();
__ fadd(0);
__ fld(1);
@@ -1754,6 +1803,7 @@
// FPU Stack: input % 2*pi, 2*pi,
__ fstp(0);
// FPU Stack: input % 2*pi
+ __ movq(rax, rdi); // Restore rax, pointer to the new HeapNumber.
__ bind(&in_range);
switch (type_) {
case TranscendentalCache::SIN:
@@ -2006,8 +2056,8 @@
__ AbortIfSmi(rax);
}
- __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
- __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex);
+ __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
+ Heap::kHeapNumberMapRootIndex);
__ j(not_equal, &slow);
// Operand is a float, negate its value by flipping sign bit.
__ movq(rdx, FieldOperand(rax, HeapNumber::kValueOffset));
@@ -2036,8 +2086,8 @@
}
// Check if the operand is a heap number.
- __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
- __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex);
+ __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
+ Heap::kHeapNumberMapRootIndex);
__ j(not_equal, &slow);
// Convert the heap number in rax to an untagged integer in rcx.
@@ -2070,6 +2120,157 @@
}
+void MathPowStub::Generate(MacroAssembler* masm) {
+ // Registers are used as follows:
+ // rdx = base
+ // rax = exponent
+ // rcx = temporary, result
+
+ Label allocate_return, call_runtime;
+
+ // Load input parameters.
+ __ movq(rdx, Operand(rsp, 2 * kPointerSize));
+ __ movq(rax, Operand(rsp, 1 * kPointerSize));
+
+ // Save 1 in xmm3 - we need this several times later on.
+ __ movl(rcx, Immediate(1));
+ __ cvtlsi2sd(xmm3, rcx);
+
+ Label exponent_nonsmi;
+ Label base_nonsmi;
+ // If the exponent is a heap number go to that specific case.
+ __ JumpIfNotSmi(rax, &exponent_nonsmi);
+ __ JumpIfNotSmi(rdx, &base_nonsmi);
+
+ // Optimized version when both exponent and base are smis.
+ Label powi;
+ __ SmiToInteger32(rdx, rdx);
+ __ cvtlsi2sd(xmm0, rdx);
+ __ jmp(&powi);
+ // Exponent is a smi and base is a heapnumber.
+ __ bind(&base_nonsmi);
+ __ CompareRoot(FieldOperand(rdx, HeapObject::kMapOffset),
+ Heap::kHeapNumberMapRootIndex);
+ __ j(not_equal, &call_runtime);
+
+ __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
+
+ // Optimized version of pow if exponent is a smi.
+ // xmm0 contains the base.
+ __ bind(&powi);
+ __ SmiToInteger32(rax, rax);
+
+ // Save exponent in base as we need to check if exponent is negative later.
+ // We know that base and exponent are in different registers.
+ __ movq(rdx, rax);
+
+ // Get absolute value of exponent.
+ NearLabel no_neg;
+ __ cmpl(rax, Immediate(0));
+ __ j(greater_equal, &no_neg);
+ __ negl(rax);
+ __ bind(&no_neg);
+
+ // Load xmm1 with 1.
+ __ movsd(xmm1, xmm3);
+ NearLabel while_true;
+ NearLabel no_multiply;
+
+ __ bind(&while_true);
+ __ shrl(rax, Immediate(1));
+ __ j(not_carry, &no_multiply);
+ __ mulsd(xmm1, xmm0);
+ __ bind(&no_multiply);
+ __ mulsd(xmm0, xmm0);
+ __ j(not_zero, &while_true);
+
+ // Base has the original value of the exponent - if the exponent is
+ // negative return 1/result.
+ __ testl(rdx, rdx);
+ __ j(positive, &allocate_return);
+ // Special case if xmm1 has reached infinity.
+ __ divsd(xmm3, xmm1);
+ __ movsd(xmm1, xmm3);
+ __ xorpd(xmm0, xmm0);
+ __ ucomisd(xmm0, xmm1);
+ __ j(equal, &call_runtime);
+
+ __ jmp(&allocate_return);
+
+ // Exponent (or both) is a heapnumber - no matter what we should now work
+ // on doubles.
+ __ bind(&exponent_nonsmi);
+ __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
+ Heap::kHeapNumberMapRootIndex);
+ __ j(not_equal, &call_runtime);
+ __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
+ // Test if exponent is nan.
+ __ ucomisd(xmm1, xmm1);
+ __ j(parity_even, &call_runtime);
+
+ NearLabel base_not_smi;
+ NearLabel handle_special_cases;
+ __ JumpIfNotSmi(rdx, &base_not_smi);
+ __ SmiToInteger32(rdx, rdx);
+ __ cvtlsi2sd(xmm0, rdx);
+ __ jmp(&handle_special_cases);
+
+ __ bind(&base_not_smi);
+ __ CompareRoot(FieldOperand(rdx, HeapObject::kMapOffset),
+ Heap::kHeapNumberMapRootIndex);
+ __ j(not_equal, &call_runtime);
+ __ movl(rcx, FieldOperand(rdx, HeapNumber::kExponentOffset));
+ __ andl(rcx, Immediate(HeapNumber::kExponentMask));
+ __ cmpl(rcx, Immediate(HeapNumber::kExponentMask));
+ // base is NaN or +/-Infinity
+ __ j(greater_equal, &call_runtime);
+ __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
+
+ // base is in xmm0 and exponent is in xmm1.
+ __ bind(&handle_special_cases);
+ NearLabel not_minus_half;
+ // Test for -0.5.
+ // Load xmm2 with -0.5.
+ __ movq(rcx, V8_UINT64_C(0xBFE0000000000000), RelocInfo::NONE);
+ __ movq(xmm2, rcx);
+ // xmm2 now has -0.5.
+ __ ucomisd(xmm2, xmm1);
+ __ j(not_equal, &not_minus_half);
+
+ // Calculates reciprocal of square root.
+ // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
+ __ xorpd(xmm1, xmm1);
+ __ addsd(xmm1, xmm0);
+ __ sqrtsd(xmm1, xmm1);
+ __ divsd(xmm3, xmm1);
+ __ movsd(xmm1, xmm3);
+ __ jmp(&allocate_return);
+
+ // Test for 0.5.
+ __ bind(&not_minus_half);
+ // Load xmm2 with 0.5.
+ // Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3.
+ __ addsd(xmm2, xmm3);
+ // xmm2 now has 0.5.
+ __ ucomisd(xmm2, xmm1);
+ __ j(not_equal, &call_runtime);
+ // Calculates square root.
+ // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
+ __ xorpd(xmm1, xmm1);
+ __ addsd(xmm1, xmm0);
+ __ sqrtsd(xmm1, xmm1);
+
+ __ bind(&allocate_return);
+ __ AllocateHeapNumber(rcx, rax, &call_runtime);
+ __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm1);
+ __ movq(rax, rcx);
+ __ ret(2 * kPointerSize);
+
+ __ bind(&call_runtime);
+ __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
+}
+
+
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
// The key is in rdx and the parameter count is in rax.
@@ -2082,11 +2283,14 @@
Label slow;
__ JumpIfNotSmi(rdx, &slow);
- // Check if the calling frame is an arguments adaptor frame.
+ // Check if the calling frame is an arguments adaptor frame. We look at the
+ // context offset, and if the frame is not a regular one, then we find a
+ // Smi instead of the context. We can't use SmiCompare here, because that
+ // only works for comparing two smis.
Label adaptor;
__ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
- __ SmiCompare(Operand(rbx, StandardFrameConstants::kContextOffset),
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+ __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset),
+ Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
__ j(equal, &adaptor);
// Check index against formal parameters count limit passed in
@@ -2141,8 +2345,8 @@
// Check if the calling frame is an arguments adaptor frame.
Label adaptor_frame, try_allocate, runtime;
__ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
- __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset),
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+ __ Cmp(Operand(rdx, StandardFrameConstants::kContextOffset),
+ Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
__ j(equal, &adaptor_frame);
// Get the length from the frame.
@@ -2261,7 +2465,6 @@
static const int kJSRegExpOffset = 4 * kPointerSize;
Label runtime;
-
// Ensure that a RegExp stack is allocated.
ExternalReference address_of_regexp_stack_memory_address =
ExternalReference::address_of_regexp_stack_memory_address();
@@ -2279,32 +2482,32 @@
__ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister);
__ j(not_equal, &runtime);
// Check that the RegExp has been compiled (data contains a fixed array).
- __ movq(rcx, FieldOperand(rax, JSRegExp::kDataOffset));
+ __ movq(rax, FieldOperand(rax, JSRegExp::kDataOffset));
if (FLAG_debug_code) {
- Condition is_smi = masm->CheckSmi(rcx);
+ Condition is_smi = masm->CheckSmi(rax);
__ Check(NegateCondition(is_smi),
"Unexpected type for RegExp data, FixedArray expected");
- __ CmpObjectType(rcx, FIXED_ARRAY_TYPE, kScratchRegister);
+ __ CmpObjectType(rax, FIXED_ARRAY_TYPE, kScratchRegister);
__ Check(equal, "Unexpected type for RegExp data, FixedArray expected");
}
- // rcx: RegExp data (FixedArray)
+ // rax: RegExp data (FixedArray)
// Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
- __ SmiToInteger32(rbx, FieldOperand(rcx, JSRegExp::kDataTagOffset));
+ __ SmiToInteger32(rbx, FieldOperand(rax, JSRegExp::kDataTagOffset));
__ cmpl(rbx, Immediate(JSRegExp::IRREGEXP));
__ j(not_equal, &runtime);
- // rcx: RegExp data (FixedArray)
+ // rax: RegExp data (FixedArray)
// Check that the number of captures fit in the static offsets vector buffer.
__ SmiToInteger32(rdx,
- FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset));
+ FieldOperand(rax, JSRegExp::kIrregexpCaptureCountOffset));
// Calculate number of capture registers (number_of_captures + 1) * 2.
__ leal(rdx, Operand(rdx, rdx, times_1, 2));
// Check that the static offsets vector buffer is large enough.
__ cmpl(rdx, Immediate(OffsetsVector::kStaticOffsetsVectorSize));
__ j(above, &runtime);
- // rcx: RegExp data (FixedArray)
+ // rax: RegExp data (FixedArray)
// rdx: Number of capture registers
// Check that the second argument is a string.
__ movq(rdi, Operand(rsp, kSubjectOffset));
@@ -2332,7 +2535,8 @@
// Check that the JSArray is in fast case.
__ movq(rbx, FieldOperand(rdi, JSArray::kElementsOffset));
__ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
- __ Cmp(rdi, Factory::fixed_array_map());
+ __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
+ Heap::kFixedArrayMapRootIndex);
__ 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.
@@ -2367,8 +2571,8 @@
__ testb(rbx, Immediate(kIsNotStringMask | kExternalStringTag));
__ j(not_zero, &runtime);
// String is a cons string.
- __ movq(rdx, FieldOperand(rdi, ConsString::kSecondOffset));
- __ Cmp(rdx, Factory::empty_string());
+ __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset),
+ Heap::kEmptyStringRootIndex);
__ j(not_equal, &runtime);
__ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset));
__ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset));
@@ -2422,7 +2626,7 @@
static const int kRegExpExecuteArguments = 7;
int argument_slots_on_stack =
masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments);
- __ EnterApiExitFrame(argument_slots_on_stack); // Clobbers rax!
+ __ EnterApiExitFrame(argument_slots_on_stack);
// Argument 7: Indicate that this is a direct call from JavaScript.
__ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize),
@@ -2483,7 +2687,7 @@
__ movq(arg2, rbx);
// Argument 1: Subject string.
-#ifdef WIN64_
+#ifdef _WIN64
__ movq(arg1, rdi);
#else
// Already there in AMD64 calling convention.
@@ -2636,8 +2840,8 @@
__ movq(FieldOperand(rax, HeapObject::kMapOffset), rdx);
// Set empty properties FixedArray.
- __ Move(FieldOperand(rax, JSObject::kPropertiesOffset),
- Factory::empty_fixed_array());
+ __ LoadRoot(kScratchRegister, Heap::kEmptyFixedArrayRootIndex);
+ __ movq(FieldOperand(rax, JSObject::kPropertiesOffset), kScratchRegister);
// Set elements to point to FixedArray allocated right after the JSArray.
__ lea(rcx, Operand(rax, JSRegExpResult::kSize));
@@ -2657,13 +2861,13 @@
// rbx: Number of elements in array as int32.
// Set map.
- __ Move(FieldOperand(rcx, HeapObject::kMapOffset),
- Factory::fixed_array_map());
+ __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex);
+ __ movq(FieldOperand(rcx, HeapObject::kMapOffset), kScratchRegister);
// Set length.
__ Integer32ToSmi(rdx, rbx);
__ movq(FieldOperand(rcx, FixedArray::kLengthOffset), rdx);
// Fill contents of fixed-array with the-hole.
- __ Move(rdx, Factory::the_hole_value());
+ __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex);
__ lea(rcx, FieldOperand(rcx, FixedArray::kHeaderSize));
// Fill fixed array elements with hole.
// rax: JSArray.
@@ -3142,6 +3346,11 @@
}
+bool CEntryStub::NeedsImmovableCode() {
+ return false;
+}
+
+
void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
// Throw exception in eax.
__ Throw(rax);
@@ -3159,7 +3368,7 @@
// rbp: frame pointer (restored after C call).
// rsp: stack pointer (restored after C call).
// r14: number of arguments including receiver (C callee-saved).
- // r12: pointer to the first argument (C callee-saved).
+ // r15: pointer to the first argument (C callee-saved).
// This pointer is reused in LeaveExitFrame(), so it is stored in a
// callee-saved register.
@@ -3200,7 +3409,7 @@
// Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9
// Store Arguments object on stack, below the 4 WIN64 ABI parameter slots.
__ movq(StackSpaceOperand(0), r14); // argc.
- __ movq(StackSpaceOperand(1), r12); // argv.
+ __ movq(StackSpaceOperand(1), r15); // argv.
if (result_size_ < 2) {
// Pass a pointer to the Arguments object as the first argument.
// Return result in single register (rax).
@@ -3216,7 +3425,7 @@
#else // _WIN64
// GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9.
__ movq(rdi, r14); // argc.
- __ movq(rsi, r12); // argv.
+ __ movq(rsi, r15); // argv.
#endif
__ call(rbx);
// Result is in rax - do not destroy this register!
@@ -3320,7 +3529,7 @@
// rbp: frame pointer of exit frame (restored after C call).
// rsp: stack pointer (restored after C call).
// r14: number of arguments including receiver (C callee-saved).
- // r12: argv pointer (C callee-saved).
+ // r15: argv pointer (C callee-saved).
Label throw_normal_exception;
Label throw_termination_exception;
@@ -3403,8 +3612,7 @@
// Set up the roots and smi constant registers.
// Needs to be done before any further smi loads.
- ExternalReference roots_address = ExternalReference::roots_address();
- __ movq(kRootRegister, roots_address);
+ __ InitializeRootRegister();
__ InitializeSmiConstantRegister();
#ifdef ENABLE_LOGGING_AND_PROFILING
@@ -3496,17 +3704,39 @@
void InstanceofStub::Generate(MacroAssembler* masm) {
// Implements "value instanceof function" operator.
- // Expected input state:
+ // Expected input state with no inline cache:
// rsp[0] : return address
// rsp[1] : function pointer
// rsp[2] : value
+ // Expected input state with an inline one-element cache:
+ // rsp[0] : return address
+ // rsp[1] : offset from return address to location of inline cache
+ // rsp[2] : function pointer
+ // rsp[3] : value
// Returns a bitwise zero to indicate that the value
// is and instance of the function and anything else to
// indicate that the value is not an instance.
+ static const int kOffsetToMapCheckValue = 5;
+ static const int kOffsetToResultValue = 21;
+ // The last 4 bytes of the instruction sequence
+ // movq(rax, FieldOperand(rdi, HeapObject::kMapOffset)
+ // Move(kScratchRegister, Factory::the_hole_value)
+ // in front of the hole value address.
+ static const unsigned int kWordBeforeMapCheckValue = 0xBA49FF78;
+ // The last 4 bytes of the instruction sequence
+ // __ j(not_equal, &cache_miss);
+ // __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex);
+ // before the offset of the hole value in the root array.
+ static const unsigned int kWordBeforeResultValue = 0x458B4909;
+ // Only the inline check flag is supported on X64.
+ ASSERT(flags_ == kNoFlags || HasCallSiteInlineCheck());
+ int extra_stack_space = HasCallSiteInlineCheck() ? kPointerSize : 0;
+
// Get the object - go slow case if it's a smi.
Label slow;
- __ movq(rax, Operand(rsp, 2 * kPointerSize));
+
+ __ movq(rax, Operand(rsp, 2 * kPointerSize + extra_stack_space));
__ JumpIfSmi(rax, &slow);
// Check that the left hand is a JS object. Leave its map in rax.
@@ -3516,19 +3746,23 @@
__ j(above, &slow);
// Get the prototype of the function.
- __ movq(rdx, Operand(rsp, 1 * kPointerSize));
+ __ movq(rdx, Operand(rsp, 1 * kPointerSize + extra_stack_space));
// rdx is function, rax is map.
- // Look up the function and the map in the instanceof cache.
- NearLabel miss;
- __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex);
- __ j(not_equal, &miss);
- __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex);
- __ j(not_equal, &miss);
- __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
- __ ret(2 * kPointerSize);
+ // If there is a call site cache don't look in the global cache, but do the
+ // real lookup and update the call site cache.
+ if (!HasCallSiteInlineCheck()) {
+ // Look up the function and the map in the instanceof cache.
+ NearLabel miss;
+ __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex);
+ __ j(not_equal, &miss);
+ __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex);
+ __ j(not_equal, &miss);
+ __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
+ __ ret(2 * kPointerSize);
+ __ bind(&miss);
+ }
- __ bind(&miss);
__ TryGetFunctionPrototype(rdx, rbx, &slow);
// Check that the function prototype is a JS object.
@@ -3542,8 +3776,19 @@
// rax is object map.
// rdx is function.
// rbx is function prototype.
- __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex);
- __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex);
+ if (!HasCallSiteInlineCheck()) {
+ __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex);
+ __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex);
+ } else {
+ __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize));
+ __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
+ __ movq(Operand(kScratchRegister, kOffsetToMapCheckValue), rax);
+ if (FLAG_debug_code) {
+ __ movl(rdi, Immediate(kWordBeforeMapCheckValue));
+ __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), rdi);
+ __ Assert(equal, "InstanceofStub unexpected call site cache.");
+ }
+ }
__ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset));
@@ -3562,27 +3807,65 @@
__ jmp(&loop);
__ bind(&is_instance);
- __ xorl(rax, rax);
- // Store bitwise zero in the cache. This is a Smi in GC terms.
- STATIC_ASSERT(kSmiTag == 0);
- __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
- __ ret(2 * kPointerSize);
+ if (!HasCallSiteInlineCheck()) {
+ __ xorl(rax, rax);
+ // Store bitwise zero in the cache. This is a Smi in GC terms.
+ STATIC_ASSERT(kSmiTag == 0);
+ __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
+ } else {
+ // Store offset of true in the root array at the inline check site.
+ ASSERT((Heap::kTrueValueRootIndex << kPointerSizeLog2) - kRootRegisterBias
+ == 0xB0 - 0x100);
+ __ movl(rax, Immediate(0xB0)); // TrueValue is at -10 * kPointerSize.
+ __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize));
+ __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
+ __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax);
+ if (FLAG_debug_code) {
+ __ movl(rax, Immediate(kWordBeforeResultValue));
+ __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax);
+ __ Assert(equal, "InstanceofStub unexpected call site cache.");
+ }
+ __ xorl(rax, rax);
+ }
+ __ ret(2 * kPointerSize + extra_stack_space);
__ bind(&is_not_instance);
- // We have to store a non-zero value in the cache.
- __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex);
- __ ret(2 * kPointerSize);
+ if (!HasCallSiteInlineCheck()) {
+ // We have to store a non-zero value in the cache.
+ __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex);
+ } else {
+ // Store offset of false in the root array at the inline check site.
+ ASSERT((Heap::kFalseValueRootIndex << kPointerSizeLog2) - kRootRegisterBias
+ == 0xB8 - 0x100);
+ __ movl(rax, Immediate(0xB8)); // FalseValue is at -9 * kPointerSize.
+ __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize));
+ __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
+ __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax);
+ if (FLAG_debug_code) {
+ __ movl(rax, Immediate(kWordBeforeResultValue));
+ __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax);
+ __ Assert(equal, "InstanceofStub unexpected call site cache (mov)");
+ }
+ }
+ __ ret(2 * kPointerSize + extra_stack_space);
// Slow-case: Go through the JavaScript implementation.
__ bind(&slow);
+ if (HasCallSiteInlineCheck()) {
+ // Remove extra value from the stack.
+ __ pop(rcx);
+ __ pop(rax);
+ __ push(rcx);
+ }
__ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
}
-Register InstanceofStub::left() { return rax; }
+// Passing arguments in registers is not supported.
+Register InstanceofStub::left() { return no_reg; }
-Register InstanceofStub::right() { return rdx; }
+Register InstanceofStub::right() { return no_reg; }
int CompareStub::MinorKey() {
@@ -3841,14 +4124,15 @@
void StringAddStub::Generate(MacroAssembler* masm) {
- Label string_add_runtime;
+ Label string_add_runtime, call_builtin;
+ Builtins::JavaScript builtin_id = Builtins::ADD;
// Load the two arguments.
- __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument.
- __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument.
+ __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument (left).
+ __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument (right).
// Make sure that both arguments are strings if not known in advance.
- if (string_check_) {
+ if (flags_ == NO_STRING_ADD_FLAGS) {
Condition is_smi;
is_smi = masm->CheckSmi(rax);
__ j(is_smi, &string_add_runtime);
@@ -3860,6 +4144,20 @@
__ j(is_smi, &string_add_runtime);
__ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9);
__ j(above_equal, &string_add_runtime);
+ } else {
+ // Here at least one of the arguments is definitely a string.
+ // We convert the one that is not known to be a string.
+ if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) {
+ ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0);
+ GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi,
+ &call_builtin);
+ builtin_id = Builtins::STRING_ADD_RIGHT;
+ } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) {
+ ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0);
+ GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi,
+ &call_builtin);
+ builtin_id = Builtins::STRING_ADD_LEFT;
+ }
}
// Both arguments are strings.
@@ -3887,14 +4185,14 @@
// rbx: length of first string
// rcx: length of second string
// rdx: second string
- // r8: map of first string if string check was performed above
- // r9: map of second string if string check was performed above
+ // r8: map of first string (if flags_ == NO_STRING_ADD_FLAGS)
+ // r9: map of second string (if flags_ == NO_STRING_ADD_FLAGS)
Label string_add_flat_result, longer_than_two;
__ bind(&both_not_zero_length);
// If arguments where known to be strings, maps are not loaded to r8 and r9
// by the code above.
- if (!string_check_) {
+ if (flags_ != NO_STRING_ADD_FLAGS) {
__ movq(r8, FieldOperand(rax, HeapObject::kMapOffset));
__ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset));
}
@@ -3905,8 +4203,8 @@
// Look at the length of the result of adding the two strings.
STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2);
__ SmiAdd(rbx, rbx, rcx);
- // Use the runtime system when adding two one character strings, as it
- // contains optimizations for this specific case using the symbol table.
+ // Use the symbol table when adding two one character strings, as it
+ // helps later optimizations to return a symbol here.
__ SmiCompare(rbx, Smi::FromInt(2));
__ j(not_equal, &longer_than_two);
@@ -3922,7 +4220,7 @@
// just allocate a new one.
Label make_two_character_string, make_flat_ascii_string;
StringHelper::GenerateTwoCharacterSymbolTableProbe(
- masm, rbx, rcx, r14, r11, rdi, r12, &make_two_character_string);
+ masm, rbx, rcx, r14, r11, rdi, r15, &make_two_character_string);
__ IncrementCounter(&Counters::string_add_native, 1);
__ ret(2 * kPointerSize);
@@ -4080,9 +4378,57 @@
// Just jump to runtime to add the two strings.
__ bind(&string_add_runtime);
__ TailCallRuntime(Runtime::kStringAdd, 2, 1);
+
+ if (call_builtin.is_linked()) {
+ __ bind(&call_builtin);
+ __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
+ }
}
+void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
+ int stack_offset,
+ Register arg,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Label* slow) {
+ // First check if the argument is already a string.
+ Label not_string, done;
+ __ JumpIfSmi(arg, &not_string);
+ __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1);
+ __ j(below, &done);
+
+ // Check the number to string cache.
+ Label not_cached;
+ __ bind(&not_string);
+ // Puts the cached result into scratch1.
+ NumberToStringStub::GenerateLookupNumberStringCache(masm,
+ arg,
+ scratch1,
+ scratch2,
+ scratch3,
+ false,
+ &not_cached);
+ __ movq(arg, scratch1);
+ __ movq(Operand(rsp, stack_offset), arg);
+ __ jmp(&done);
+
+ // Check if the argument is a safe string wrapper.
+ __ bind(&not_cached);
+ __ JumpIfSmi(arg, slow);
+ __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1); // map -> scratch1.
+ __ j(not_equal, slow);
+ __ testb(FieldOperand(scratch1, Map::kBitField2Offset),
+ Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
+ __ j(zero, slow);
+ __ movq(arg, FieldOperand(arg, JSValue::kValueOffset));
+ __ movq(Operand(rsp, stack_offset), arg);
+
+ __ bind(&done);
+}
+
+
void StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
Register dest,
Register src,
@@ -4210,15 +4556,14 @@
FieldOperand(symbol_table, SymbolTable::kCapacityOffset));
__ decl(mask);
- Register undefined = scratch4;
- __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
+ Register map = scratch4;
// Registers
// chars: two character string, char 1 in byte 0 and char 2 in byte 1.
// hash: hash of two character string (32-bit int)
// symbol_table: symbol table
// mask: capacity mask (32-bit int)
- // undefined: undefined value
+ // map: -
// scratch: -
// Perform a number of probes in the symbol table.
@@ -4233,7 +4578,7 @@
}
__ andl(scratch, mask);
- // Load the entry from the symble table.
+ // Load the entry from the symbol table.
Register candidate = scratch; // Scratch register contains candidate.
STATIC_ASSERT(SymbolTable::kEntrySize == 1);
__ movq(candidate,
@@ -4243,9 +4588,17 @@
SymbolTable::kElementsStartOffset));
// If entry is undefined no string with this hash can be found.
- __ cmpq(candidate, undefined);
+ NearLabel is_string;
+ __ CmpObjectType(candidate, ODDBALL_TYPE, map);
+ __ j(not_equal, &is_string);
+
+ __ CompareRoot(candidate, Heap::kUndefinedValueRootIndex);
__ j(equal, not_found);
+ // Must be null (deleted entry).
+ __ jmp(&next_probe[i]);
+ __ bind(&is_string);
+
// If length is not 2 the string is not a candidate.
__ SmiCompare(FieldOperand(candidate, String::kLengthOffset),
Smi::FromInt(2));
@@ -4256,8 +4609,7 @@
Register temp = kScratchRegister;
// Check that the candidate is a non-external ascii string.
- __ movq(temp, FieldOperand(candidate, HeapObject::kMapOffset));
- __ movzxbl(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
+ __ movzxbl(temp, FieldOperand(map, Map::kInstanceTypeOffset));
__ JumpIfInstanceTypeIsNotSequentialAscii(
temp, temp, &next_probe[i]);
@@ -4608,6 +4960,7 @@
__ TailCallRuntime(Runtime::kStringCompare, 2, 1);
}
+
void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
ASSERT(state_ == CompareIC::SMIS);
NearLabel miss;
@@ -4725,144 +5078,6 @@
}
-void GenerateFastPixelArrayLoad(MacroAssembler* masm,
- Register receiver,
- Register key,
- Register elements,
- Register untagged_key,
- Register result,
- Label* not_pixel_array,
- Label* key_not_smi,
- Label* out_of_range) {
- // Register use:
- // receiver - holds the receiver and is unchanged.
- // key - holds the key and is unchanged (must be a smi).
- // elements - is set to the the receiver's element if
- // the receiver doesn't have a pixel array or the
- // key is not a smi, otherwise it's the elements'
- // external pointer.
- // untagged_key - is set to the untagged key
-
- // 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 must be added.
- if (key_not_smi != NULL) {
- __ JumpIfNotSmi(key, key_not_smi);
- } else {
- if (FLAG_debug_code) {
- __ AbortIfNotSmi(key);
- }
- }
- __ SmiToInteger32(untagged_key, key);
-
- __ 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");
- }
- }
-
- // Check that the smi is in range.
- __ cmpl(untagged_key, FieldOperand(elements, PixelArray::kLengthOffset));
- __ j(above_equal, out_of_range); // unsigned check handles negative keys.
-
- // Load and tag the element as a smi.
- __ movq(elements, FieldOperand(elements, PixelArray::kExternalPointerOffset));
- __ movzxbq(result, Operand(elements, untagged_key, times_1, 0));
- __ Integer32ToSmi(result, result);
- __ ret(0);
-}
-
-
-// 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
« no previous file with comments | « src/x64/code-stubs-x64.h ('k') | src/x64/codegen-x64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698