| Index: src/x64/stub-cache-x64.cc
|
| diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
|
| index 109985c726978f1fc63b5559e5ff7223fd772063..e85f37e01637f509087c502dd56459c6c0ad7a9e 100644
|
| --- a/src/x64/stub-cache-x64.cc
|
| +++ b/src/x64/stub-cache-x64.cc
|
| @@ -2563,43 +2563,6 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
|
| }
|
|
|
|
|
| -MaybeObject* KeyedStoreStubCompiler::CompileStorePixelArray(
|
| - JSObject* receiver) {
|
| - // ----------- S t a t e -------------
|
| - // -- rax : value
|
| - // -- rcx : key
|
| - // -- rdx : receiver
|
| - // -- rsp[0] : return address
|
| - // -----------------------------------
|
| - Label miss;
|
| -
|
| - // Check that the map matches.
|
| - __ CheckMap(rdx, Handle<Map>(receiver->map()), &miss, false);
|
| -
|
| - // Do the load.
|
| - GenerateFastPixelArrayStore(masm(),
|
| - rdx,
|
| - rcx,
|
| - rax,
|
| - rdi,
|
| - rbx,
|
| - true,
|
| - false,
|
| - &miss,
|
| - &miss,
|
| - NULL,
|
| - &miss);
|
| -
|
| - // Handle store cache miss.
|
| - __ bind(&miss);
|
| - Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
|
| - __ jmp(ic, RelocInfo::CODE_TARGET);
|
| -
|
| - // Return the generated code.
|
| - return GetCode(NORMAL, NULL);
|
| -}
|
| -
|
| -
|
| MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
|
| JSObject* object,
|
| JSObject* last) {
|
| @@ -3039,35 +3002,6 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
|
| }
|
|
|
|
|
| -MaybeObject* KeyedLoadStubCompiler::CompileLoadPixelArray(JSObject* receiver) {
|
| - // ----------- S t a t e -------------
|
| - // -- rax : key
|
| - // -- rdx : receiver
|
| - // -- esp[0] : return address
|
| - // -----------------------------------
|
| - Label miss;
|
| -
|
| - // Check that the map matches.
|
| - __ CheckMap(rdx, Handle<Map>(receiver->map()), &miss, false);
|
| -
|
| - GenerateFastPixelArrayLoad(masm(),
|
| - rdx,
|
| - rax,
|
| - rbx,
|
| - rcx,
|
| - rax,
|
| - &miss,
|
| - &miss,
|
| - &miss);
|
| -
|
| - __ bind(&miss);
|
| - GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
|
| -
|
| - // Return the generated code.
|
| - return GetCode(NORMAL, NULL);
|
| -}
|
| -
|
| -
|
| // Specialized stub for constructing objects from functions which only have only
|
| // simple assignments of the form this.x = ...; in their body.
|
| MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
|
| @@ -3200,7 +3134,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
|
|
|
|
|
| MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
|
| - ExternalArrayType array_type, Code::Flags flags) {
|
| + JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) {
|
| // ----------- S t a t e -------------
|
| // -- rax : key
|
| // -- rdx : receiver
|
| @@ -3214,24 +3148,9 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
|
| // Check that the key is a smi.
|
| __ JumpIfNotSmi(rax, &slow);
|
|
|
| - // Check that the object is a JS object.
|
| - __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
|
| - __ j(not_equal, &slow);
|
| - // Check that the receiver does not require access checks. We need
|
| - // to check this explicitly since this generic stub does not perform
|
| - // map checks. The map is already in rdx.
|
| - __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
|
| - Immediate(1 << Map::kIsAccessCheckNeeded));
|
| - __ j(not_zero, &slow);
|
| -
|
| - // Check that the elements array is the appropriate type of
|
| - // ExternalArray.
|
| - // rax: index (as a smi)
|
| - // rdx: JSObject
|
| + // Check that the map matches.
|
| + __ CheckMap(rdx, Handle<Map>(receiver->map()), &slow, false);
|
| __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
|
| - __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
|
| - Heap::RootIndexForExternalArrayType(array_type));
|
| - __ j(not_equal, &slow);
|
|
|
| // Check that the index is in range.
|
| __ SmiToInteger32(rcx, rax);
|
| @@ -3249,6 +3168,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
|
| case kExternalByteArray:
|
| __ movsxbq(rcx, Operand(rbx, rcx, times_1, 0));
|
| break;
|
| + case kExternalPixelArray:
|
| case kExternalUnsignedByteArray:
|
| __ movzxbq(rcx, Operand(rbx, rcx, times_1, 0));
|
| break;
|
| @@ -3341,7 +3261,7 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
|
|
|
|
|
| MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
|
| - ExternalArrayType array_type, Code::Flags flags) {
|
| + JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) {
|
| // ----------- S t a t e -------------
|
| // -- rax : value
|
| // -- rcx : key
|
| @@ -3352,29 +3272,13 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
|
|
|
| // Check that the object isn't a smi.
|
| __ JumpIfSmi(rdx, &slow);
|
| - // Get the map from the receiver.
|
| - __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
|
| - // Check that the receiver does not require access checks. We need
|
| - // to do this because this generic stub does not perform map checks.
|
| - __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
|
| - Immediate(1 << Map::kIsAccessCheckNeeded));
|
| - __ j(not_zero, &slow);
|
| - // Check that the key is a smi.
|
| - __ JumpIfNotSmi(rcx, &slow);
|
| -
|
| - // Check that the object is a JS object.
|
| - __ CmpInstanceType(rbx, JS_OBJECT_TYPE);
|
| - __ j(not_equal, &slow);
|
|
|
| - // Check that the elements array is the appropriate type of
|
| - // ExternalArray.
|
| - // rax: value
|
| - // rcx: key (a smi)
|
| - // rdx: receiver (a JSObject)
|
| + // Check that the map matches.
|
| + __ CheckMap(rdx, Handle<Map>(receiver->map()), &slow, false);
|
| __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
|
| - __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
|
| - Heap::RootIndexForExternalArrayType(array_type));
|
| - __ j(not_equal, &slow);
|
| +
|
| + // Check that the key is a smi.
|
| + __ JumpIfNotSmi(rcx, &slow);
|
|
|
| // Check that the index is in range.
|
| __ SmiToInteger32(rdi, rcx); // Untag the index.
|
| @@ -3390,12 +3294,28 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
|
| // rbx: elements array
|
| // rdi: untagged key
|
| NearLabel check_heap_number;
|
| - __ JumpIfNotSmi(rax, &check_heap_number);
|
| + if (array_type == kExternalPixelArray) {
|
| + // Float to pixel conversion is only implemented in the runtime for now.
|
| + __ JumpIfNotSmi(rax, &slow);
|
| + } else {
|
| + __ JumpIfNotSmi(rax, &check_heap_number);
|
| + }
|
| // No more branches to slow case on this path. Key and receiver not needed.
|
| __ SmiToInteger32(rdx, rax);
|
| __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
|
| // rbx: base pointer of external storage
|
| switch (array_type) {
|
| + case kExternalPixelArray:
|
| + { // Clamp the value to [0..255].
|
| + NearLabel done;
|
| + __ testl(rdx, Immediate(0xFFFFFF00));
|
| + __ j(zero, &done);
|
| + __ setcc(negative, rdx); // 1 if negative, 0 if positive.
|
| + __ decb(rdx); // 0 if negative, 255 if positive.
|
| + __ bind(&done);
|
| + }
|
| + __ movb(Operand(rbx, rdi, times_1, 0), rdx);
|
| + break;
|
| case kExternalByteArray:
|
| case kExternalUnsignedByteArray:
|
| __ movb(Operand(rbx, rdi, times_1, 0), rdx);
|
| @@ -3419,62 +3339,65 @@ MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
|
| }
|
| __ ret(0);
|
|
|
| - __ bind(&check_heap_number);
|
| - // rax: value
|
| - // rcx: key (a smi)
|
| - // rdx: receiver (a JSObject)
|
| - // rbx: elements array
|
| - // rdi: untagged key
|
| - __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister);
|
| - __ j(not_equal, &slow);
|
| - // No more branches to slow case on this path.
|
| -
|
| - // The WebGL specification leaves the behavior of storing NaN and
|
| - // +/-Infinity into integer arrays basically undefined. For more
|
| - // reproducible behavior, convert these to zero.
|
| - __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
|
| - __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
|
| - // rdi: untagged index
|
| - // rbx: base pointer of external storage
|
| - // top of FPU stack: value
|
| - if (array_type == kExternalFloatArray) {
|
| - __ cvtsd2ss(xmm0, xmm0);
|
| - __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
|
| - __ ret(0);
|
| - } else {
|
| - // Perform float-to-int conversion with truncation (round-to-zero)
|
| - // behavior.
|
| -
|
| - // Convert to int32 and store the low byte/word.
|
| - // If the value is NaN or +/-infinity, the result is 0x80000000,
|
| - // which is automatically zero when taken mod 2^n, n < 32.
|
| - // rdx: value (converted to an untagged integer)
|
| + // TODO(danno): handle heap number -> pixel array conversion
|
| + if (array_type != kExternalPixelArray) {
|
| + __ bind(&check_heap_number);
|
| + // rax: value
|
| + // rcx: key (a smi)
|
| + // rdx: receiver (a JSObject)
|
| + // rbx: elements array
|
| + // rdi: untagged key
|
| + __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister);
|
| + __ j(not_equal, &slow);
|
| + // No more branches to slow case on this path.
|
| +
|
| + // The WebGL specification leaves the behavior of storing NaN and
|
| + // +/-Infinity into integer arrays basically undefined. For more
|
| + // reproducible behavior, convert these to zero.
|
| + __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
|
| + __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
|
| // rdi: untagged index
|
| // rbx: base pointer of external storage
|
| - switch (array_type) {
|
| - case kExternalByteArray:
|
| - case kExternalUnsignedByteArray:
|
| - __ cvttsd2si(rdx, xmm0);
|
| - __ movb(Operand(rbx, rdi, times_1, 0), rdx);
|
| - break;
|
| - case kExternalShortArray:
|
| - case kExternalUnsignedShortArray:
|
| - __ cvttsd2si(rdx, xmm0);
|
| - __ movw(Operand(rbx, rdi, times_2, 0), rdx);
|
| - break;
|
| - case kExternalIntArray:
|
| - case kExternalUnsignedIntArray: {
|
| - // Convert to int64, so that NaN and infinities become
|
| - // 0x8000000000000000, which is zero mod 2^32.
|
| - __ cvttsd2siq(rdx, xmm0);
|
| - __ movl(Operand(rbx, rdi, times_4, 0), rdx);
|
| - break;
|
| + // top of FPU stack: value
|
| + if (array_type == kExternalFloatArray) {
|
| + __ cvtsd2ss(xmm0, xmm0);
|
| + __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
|
| + __ ret(0);
|
| + } else {
|
| + // Perform float-to-int conversion with truncation (round-to-zero)
|
| + // behavior.
|
| +
|
| + // Convert to int32 and store the low byte/word.
|
| + // If the value is NaN or +/-infinity, the result is 0x80000000,
|
| + // which is automatically zero when taken mod 2^n, n < 32.
|
| + // rdx: value (converted to an untagged integer)
|
| + // rdi: untagged index
|
| + // rbx: base pointer of external storage
|
| + switch (array_type) {
|
| + case kExternalByteArray:
|
| + case kExternalUnsignedByteArray:
|
| + __ cvttsd2si(rdx, xmm0);
|
| + __ movb(Operand(rbx, rdi, times_1, 0), rdx);
|
| + break;
|
| + case kExternalShortArray:
|
| + case kExternalUnsignedShortArray:
|
| + __ cvttsd2si(rdx, xmm0);
|
| + __ movw(Operand(rbx, rdi, times_2, 0), rdx);
|
| + break;
|
| + case kExternalIntArray:
|
| + case kExternalUnsignedIntArray: {
|
| + // Convert to int64, so that NaN and infinities become
|
| + // 0x8000000000000000, which is zero mod 2^32.
|
| + __ cvttsd2siq(rdx, xmm0);
|
| + __ movl(Operand(rbx, rdi, times_4, 0), rdx);
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
| - default:
|
| - UNREACHABLE();
|
| - break;
|
| + __ ret(0);
|
| }
|
| - __ ret(0);
|
| }
|
|
|
| // Slow case: call runtime.
|
|
|