diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index 1859bc8852..9d93aafb9d 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -3516,29 +3516,6 @@ void FullCodeGenerator::EmitDateField(CallRuntime* expr) { } -void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string, - Register index, - Register value, - uint32_t encoding_mask) { - __ And(at, index, Operand(kSmiTagMask)); - __ Check(eq, kNonSmiIndex, at, Operand(zero_reg)); - __ And(at, value, Operand(kSmiTagMask)); - __ Check(eq, kNonSmiValue, at, Operand(zero_reg)); - - __ lw(at, FieldMemOperand(string, String::kLengthOffset)); - __ Check(lt, kIndexIsTooLarge, index, Operand(at)); - - __ Check(ge, kIndexIsNegative, index, Operand(zero_reg)); - - __ lw(at, FieldMemOperand(string, HeapObject::kMapOffset)); - __ lbu(at, FieldMemOperand(at, Map::kInstanceTypeOffset)); - - __ And(at, at, Operand(kStringRepresentationMask | kStringEncodingMask)); - __ Subu(at, at, Operand(encoding_mask)); - __ Check(eq, kUnexpectedStringType, at, Operand(zero_reg)); -} - - void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) { ZoneList* args = expr->arguments(); ASSERT_EQ(3, args->length()); @@ -3553,8 +3530,16 @@ void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) { __ Pop(index, value); if (FLAG_debug_code) { + __ And(at, value, Operand(kSmiTagMask)); + __ ThrowIf(ne, kNonSmiValue, at, Operand(zero_reg)); + __ And(at, index, Operand(kSmiTagMask)); + __ ThrowIf(ne, kNonSmiIndex, at, Operand(zero_reg)); + __ SmiUntag(index, index); static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; - EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type); + Register scratch = t5; + __ EmitSeqStringSetCharCheck( + string, index, value, scratch, one_byte_seq_type); + __ SmiTag(index, index); } __ SmiUntag(value, value); @@ -3582,8 +3567,16 @@ void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) { __ Pop(index, value); if (FLAG_debug_code) { + __ And(at, value, Operand(kSmiTagMask)); + __ ThrowIf(ne, kNonSmiValue, at, Operand(zero_reg)); + __ And(at, index, Operand(kSmiTagMask)); + __ ThrowIf(ne, kNonSmiIndex, at, Operand(zero_reg)); + __ SmiUntag(index, index); static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; - EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type); + Register scratch = t5; + __ EmitSeqStringSetCharCheck( + string, index, value, scratch, two_byte_seq_type); + __ SmiTag(index, index); } __ SmiUntag(value, value); diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index d71c055c7f..7dc341f2ed 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -1820,16 +1820,13 @@ void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { if (FLAG_debug_code) { Register scratch = scratch0(); - __ lw(scratch, FieldMemOperand(string, HeapObject::kMapOffset)); - __ lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); - - __ And(scratch, scratch, - Operand(kStringRepresentationMask | kStringEncodingMask)); + Register index = ToRegister(instr->index()); static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; - __ Subu(at, scratch, Operand(encoding == String::ONE_BYTE_ENCODING - ? one_byte_seq_type : two_byte_seq_type)); - __ Check(eq, kUnexpectedStringType, at, Operand(zero_reg)); + int encoding_mask = + instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING + ? one_byte_seq_type : two_byte_seq_type; + __ EmitSeqStringSetCharCheck(string, index, value, scratch, encoding_mask); } MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding); diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc index 09bae598db..fb81627354 100644 --- a/src/mips/lithium-mips.cc +++ b/src/mips/lithium-mips.cc @@ -1826,10 +1826,13 @@ LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) { LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) { - LOperand* string = UseRegister(instr->string()); - LOperand* index = UseRegisterOrConstant(instr->index()); - LOperand* value = UseRegister(instr->value()); - return new(zone()) LSeqStringSetChar(string, index, value); + LOperand* string = UseRegisterAtStart(instr->string()); + LOperand* index = FLAG_debug_code + ? UseRegisterAtStart(instr->index()) + : UseRegisterOrConstantAtStart(instr->index()); + LOperand* value = UseRegisterAtStart(instr->value()); + LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), cp) : NULL; + return new(zone()) LSeqStringSetChar(context, string, index, value); } diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h index 8c82a9d7cb..452963b169 100644 --- a/src/mips/lithium-mips.h +++ b/src/mips/lithium-mips.h @@ -1381,19 +1381,21 @@ class LSeqStringGetChar V8_FINAL : public LTemplateInstruction<1, 2, 0> { }; -class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> { +class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 4, 0> { public: - LSeqStringSetChar(LOperand* string, + LSeqStringSetChar(LOperand* context, + LOperand* string, LOperand* index, LOperand* value) { - inputs_[0] = string; - inputs_[1] = index; - inputs_[2] = value; + inputs_[0] = context; + inputs_[1] = string; + inputs_[2] = index; + inputs_[3] = value; } - LOperand* string() { return inputs_[0]; } - LOperand* index() { return inputs_[1]; } - LOperand* value() { return inputs_[2]; } + LOperand* string() { return inputs_[1]; } + LOperand* index() { return inputs_[2]; } + LOperand* value() { return inputs_[3]; } DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char") DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar) diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc index 5519110d54..930afcb72a 100644 --- a/src/mips/macro-assembler-mips.cc +++ b/src/mips/macro-assembler-mips.cc @@ -5051,6 +5051,44 @@ int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments, } +void MacroAssembler::EmitSeqStringSetCharCheck(Register string, + Register index, + Register value, + Register scratch, + uint32_t encoding_mask) { + Label is_object; + And(at, string, Operand(kSmiTagMask)); + ThrowIf(eq, kNonObject, at, Operand(zero_reg)); + + lw(at, FieldMemOperand(string, HeapObject::kMapOffset)); + lbu(at, FieldMemOperand(at, Map::kInstanceTypeOffset)); + + andi(at, at, kStringRepresentationMask | kStringEncodingMask); + li(scratch, Operand(encoding_mask)); + ThrowIf(ne, kUnexpectedStringType, at, Operand(scratch)); + + // The index is assumed to be untagged coming in, tag it to compare with the + // string length without using a temp register, it is restored at the end of + // this function. + Label index_tag_ok, index_tag_bad; + // On ARM TrySmiTag is used here. + AdduAndCheckForOverflow(index, index, index, scratch); + BranchOnOverflow(&index_tag_bad, scratch); + Branch(&index_tag_ok); + bind(&index_tag_bad); + Throw(kIndexIsTooLarge); + bind(&index_tag_ok); + + lw(at, FieldMemOperand(string, String::kLengthOffset)); + ThrowIf(ge, kIndexIsTooLarge, index, Operand(at)); + + li(at, Operand(Smi::FromInt(0))); + ThrowIf(lt, kIndexIsNegative, index, Operand(at)); + + SmiUntag(index, index); +} + + void MacroAssembler::PrepareCallCFunction(int num_reg_arguments, int num_double_arguments, Register scratch) { @@ -5431,6 +5469,57 @@ void MacroAssembler::EnsureNotWhite( } +void MacroAssembler::Throw(BailoutReason reason) { + Label throw_start; + bind(&throw_start); +#ifdef DEBUG + const char* msg = GetBailoutReason(reason); + if (msg != NULL) { + RecordComment("Throw message: "); + RecordComment(msg); + } +#endif + + li(a0, Operand(Smi::FromInt(reason))); + push(a0); + // Disable stub call restrictions to always allow calls to throw. + if (!has_frame_) { + // We don't actually want to generate a pile of code for this, so just + // claim there is a stack frame, without generating one. + FrameScope scope(this, StackFrame::NONE); + CallRuntime(Runtime::kThrowMessage, 1); + } else { + CallRuntime(Runtime::kThrowMessage, 1); + } + // will not return here + if (is_trampoline_pool_blocked()) { + // If the calling code cares throw the exact number of + // instructions generated, we insert padding here to keep the size + // of the ThrowMessage macro constant. + // Currently in debug mode with debug_code enabled the number of + // generated instructions is 14, so we use this as a maximum value. + static const int kExpectedThrowMessageInstructions = 14; + int throw_instructions = InstructionsGeneratedSince(&throw_start); + ASSERT(throw_instructions <= kExpectedThrowMessageInstructions); + while (throw_instructions++ < kExpectedThrowMessageInstructions) { + nop(); + } + } +} + + +void MacroAssembler::ThrowIf(Condition cc, + BailoutReason reason, + Register rs, + Operand rt) { + Label L; + Branch(&L, NegateCondition(cc), rs, rt); + Throw(reason); + // will not return here + bind(&L); +} + + void MacroAssembler::LoadInstanceDescriptors(Register map, Register descriptors) { lw(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset)); diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h index a9ad5cf697..d3fdbd6b33 100644 --- a/src/mips/macro-assembler-mips.h +++ b/src/mips/macro-assembler-mips.h @@ -967,6 +967,12 @@ class MacroAssembler: public Assembler { // handler chain. void ThrowUncatchable(Register value); + // Throw a message string as an exception. + void Throw(BailoutReason reason); + + // Throw a message string as an exception if a condition is not true. + void ThrowIf(Condition cc, BailoutReason reason, Register rs, Operand rt); + // Copies a fixed number of fields of heap objects from src to dst. void CopyFields(Register dst, Register src, RegList temps, int field_count); @@ -1452,6 +1458,12 @@ class MacroAssembler: public Assembler { void JumpIfNotUniqueName(Register reg, Label* not_unique_name); + void EmitSeqStringSetCharCheck(Register string, + Register index, + Register value, + Register scratch, + uint32_t encoding_mask); + // Test that both first and second are sequential ASCII strings. // Assume that they are non-smis. void JumpIfNonSmisNotBothSequentialAsciiStrings(Register first,