From 49d646b14c4c38045b16640913d4373d5e2b581f Mon Sep 17 00:00:00 2001 From: "ager@chromium.org" Date: Thu, 20 Jan 2011 14:20:54 +0000 Subject: [PATCH] ARM: Implement StringLength and StringCharCodeAt in the lithium-arm backend. Review URL: http://codereview.chromium.org/6368009 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6419 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/lithium-arm.cc | 10 +-- src/arm/lithium-arm.h | 26 ++++++++ src/arm/lithium-codegen-arm.cc | 137 +++++++++++++++++++++++++++++++++++++++ src/arm/lithium-codegen-arm.h | 1 + src/arm/macro-assembler-arm.cc | 7 ++ src/arm/macro-assembler-arm.h | 1 + src/ia32/lithium-codegen-ia32.cc | 25 +++---- src/ia32/lithium-ia32.cc | 4 +- 8 files changed, 194 insertions(+), 17 deletions(-) diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 10a24b5..8d839ca 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -1724,14 +1724,16 @@ LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) { LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) { - Abort("LStringCharCodeAt instruction not implemented on ARM"); - return NULL; + LOperand* string = UseRegister(instr->string()); + LOperand* index = UseRegisterOrConstant(instr->index()); + LInstruction* result = new LStringCharCodeAt(string, index); + return AssignEnvironment(AssignPointerMap(DefineAsRegister(result))); } LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) { - Abort("LStringLength instruction not implemented on ARM"); - return NULL; + LOperand* string = UseRegisterAtStart(instr->value()); + return DefineAsRegister(new LStringLength(string)); } diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index 701f5f3..1cf9898 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -67,6 +67,7 @@ class LCodeGen; // LModI // LMulI // LShiftI +// LStringCharCodeAt // LSubI // LCallConstantFunction // LCallFunction @@ -136,6 +137,7 @@ class LCodeGen; // LReturn // LSmiTag // LStoreGlobal +// LStringLength // LTaggedToI // LThrow // LTypeof @@ -251,6 +253,8 @@ class LCodeGen; V(StoreNamedField) \ V(StoreNamedGeneric) \ V(SubI) \ + V(StringCharCodeAt) \ + V(StringLength) \ V(TaggedToI) \ V(Throw) \ V(Typeof) \ @@ -1580,6 +1584,28 @@ class LStoreKeyedGeneric: public LStoreKeyed { }; +class LStringCharCodeAt: public LBinaryOperation { + public: + LStringCharCodeAt(LOperand* string, LOperand* index) + : LBinaryOperation(string, index) {} + + DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string-char-code-at") + DECLARE_HYDROGEN_ACCESSOR(StringCharCodeAt) + + LOperand* string() { return left(); } + LOperand* index() { return right(); } +}; + + +class LStringLength: public LUnaryOperation { + public: + explicit LStringLength(LOperand* string) : LUnaryOperation(string) {} + + DECLARE_CONCRETE_INSTRUCTION(StringLength, "string-length") + DECLARE_HYDROGEN_ACCESSOR(StringLength) +}; + + class LCheckFunction: public LUnaryOperation { public: explicit LCheckFunction(LOperand* use) : LUnaryOperation(use) { } diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 3420651..23bfb21 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -2780,6 +2780,143 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { } +void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { + class DeferredStringCharCodeAt: public LDeferredCode { + public: + DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) + : LDeferredCode(codegen), instr_(instr) { } + virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } + private: + LStringCharCodeAt* instr_; + }; + + DeferredStringCharCodeAt* deferred + = new DeferredStringCharCodeAt(this, instr); + + Register scratch = scratch0(); + Register string = ToRegister(instr->string()); + Register index = no_reg; + int const_index = -1; + if (instr->index()->IsConstantOperand()) { + const_index = ToInteger32(LConstantOperand::cast(instr->index())); + } else { + index = ToRegister(instr->index()); + } + Register result = ToRegister(instr->result()); + + Label flat_string, ascii_string, done; + + // Fetch the instance type of the receiver into result register. + __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); + __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); + + // We need special handling for non-flat strings. + STATIC_ASSERT(kSeqStringTag == 0); + __ tst(result, Operand(kStringRepresentationMask)); + __ b(eq, &flat_string); + + // Handle non-flat strings. + __ tst(result, Operand(kIsConsStringMask)); + __ b(eq, deferred->entry()); + + // ConsString. + // Check whether the right hand side is the empty string (i.e. if + // this is really a flat string in a cons string). If that is not + // the case we would rather go to the runtime system now to flatten + // the string. + __ ldr(scratch, FieldMemOperand(string, ConsString::kSecondOffset)); + __ LoadRoot(ip, Heap::kEmptyStringRootIndex); + __ cmp(scratch, ip); + __ b(ne, deferred->entry()); + // Get the first of the two strings and load its instance type. + __ ldr(string, FieldMemOperand(string, ConsString::kFirstOffset)); + __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); + __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); + // If the first cons component is also non-flat, then go to runtime. + STATIC_ASSERT(kSeqStringTag == 0); + __ tst(result, Operand(kStringRepresentationMask)); + __ b(ne, deferred->entry()); + + // Check for 1-byte or 2-byte string. + __ bind(&flat_string); + STATIC_ASSERT(kAsciiStringTag != 0); + __ tst(result, Operand(kStringEncodingMask)); + __ b(ne, &ascii_string); + + // 2-byte string. + // Load the 2-byte character code into the result register. + STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); + if (instr->index()->IsConstantOperand()) { + __ ldrh(result, + FieldMemOperand(string, + SeqTwoByteString::kHeaderSize + 2 * const_index)); + } else { + __ add(scratch, + string, + Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); + __ ldrh(result, MemOperand(scratch, index, LSL, 1)); + } + __ jmp(&done); + + // ASCII string. + // Load the byte into the result register. + __ bind(&ascii_string); + if (instr->index()->IsConstantOperand()) { + __ ldrb(result, FieldMemOperand(string, + SeqAsciiString::kHeaderSize + const_index)); + } else { + __ add(scratch, + string, + Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ ldrb(result, MemOperand(scratch, index)); + } + __ bind(&done); + __ bind(deferred->exit()); +} + + +void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { + Register string = ToRegister(instr->string()); + Register result = ToRegister(instr->result()); + Register scratch = scratch0(); + + // TODO(3095996): Get rid of this. For now, we need to make the + // result register contain a valid pointer because it is already + // contained in the register pointer map. + __ mov(result, Operand(0)); + + __ PushSafepointRegisters(); + __ push(string); + // Push the index as a smi. + if (instr->index()->IsConstantOperand()) { + int const_index = ToInteger32(LConstantOperand::cast(instr->index())); + __ mov(scratch, Operand(Smi::FromInt(const_index))); + __ push(scratch); + } else { + Register index = ToRegister(instr->index()); + __ SmiTag(index); + __ push(index); + } + __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt); + RecordSafepointWithRegisters( + instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex); + if (FLAG_debug_code) { + __ AbortIfNotSmi(r0); + } + __ SmiUntag(r0); + MemOperand result_stack_slot = masm()->SafepointRegisterSlot(result); + __ str(r0, result_stack_slot); + __ PopSafepointRegisters(); +} + + +void LCodeGen::DoStringLength(LStringLength* instr) { + Register string = ToRegister(instr->input()); + Register result = ToRegister(instr->result()); + __ ldr(result, FieldMemOperand(string, String::kLengthOffset)); +} + + void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { LOperand* input = instr->input(); ASSERT(input->IsRegister() || input->IsStackSlot()); diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h index 206d39e..cfdfdf6 100644 --- a/src/arm/lithium-codegen-arm.h +++ b/src/arm/lithium-codegen-arm.h @@ -99,6 +99,7 @@ class LCodeGen BASE_EMBEDDED { void DoDeferredTaggedToI(LTaggedToI* instr); void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr); void DoDeferredStackCheck(LGoto* instr); + void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, Label* map_check); diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index ae30d5d..a78de98 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -1970,6 +1970,13 @@ void MacroAssembler::AbortIfSmi(Register object) { } +void MacroAssembler::AbortIfNotSmi(Register object) { + ASSERT_EQ(0, kSmiTag); + tst(object, Operand(kSmiTagMask)); + Assert(eq, "Operand is not smi"); +} + + void MacroAssembler::JumpIfNonSmisNotBothSequentialAsciiStrings( Register first, Register second, diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index 55a8064..7392d36 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -741,6 +741,7 @@ class MacroAssembler: public Assembler { // Abort execution if argument is a smi. Used in debug code. void AbortIfSmi(Register object); + void AbortIfNotSmi(Register object); // --------------------------------------------------------------------------- // String utilities diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 1c35b68..0fc3f25 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -2656,8 +2656,8 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { LStringCharCodeAt* instr_; }; - DeferredStringCharCodeAt* deferred = new DeferredStringCharCodeAt(this, - instr); + DeferredStringCharCodeAt* deferred + = new DeferredStringCharCodeAt(this, instr); Register string = ToRegister(instr->string()); Register index = no_reg; @@ -2710,26 +2710,29 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { // 2-byte string. // Load the 2-byte character code into the result register. STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); - if (index.is_valid()) { + if (instr->index()->IsConstantOperand()) { + __ movzx_w(result, + FieldOperand(string, + SeqTwoByteString::kHeaderSize + 2 * const_index)); + } else { __ movzx_w(result, FieldOperand(string, - index, times_2, + index, + times_2, SeqTwoByteString::kHeaderSize)); - } else { - __ movzx_w(result, FieldOperand( - string, SeqTwoByteString::kHeaderSize + 2 * const_index)); } __ jmp(&done); // ASCII string. // Load the byte into the result register. __ bind(&ascii_string); - if (index.is_valid()) { + if (instr->index()->IsConstantOperand()) { __ movzx_b(result, FieldOperand(string, - index, times_1, - SeqAsciiString::kHeaderSize)); + SeqAsciiString::kHeaderSize + const_index)); } else { __ movzx_b(result, FieldOperand(string, - SeqAsciiString::kHeaderSize + const_index)); + index, + times_1, + SeqAsciiString::kHeaderSize)); } __ bind(&done); __ bind(deferred->exit()); diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index 8935d2c..554cc02 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -1769,8 +1769,8 @@ LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) { LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) { LOperand* string = UseRegister(instr->string()); LOperand* index = UseRegisterOrConstant(instr->index()); - return AssignEnvironment(AssignPointerMap(DefineAsRegister( - new LStringCharCodeAt(string, index)))); + LStringCharCodeAt* result = new LStringCharCodeAt(string, index); + return AssignEnvironment(AssignPointerMap(DefineAsRegister(result))); } -- 2.7.4