LOperand* string = UseRegister(instr->string());
LOperand* index = UseRegisterOrConstant(instr->index());
LOperand* value = UseRegister(instr->value());
- return new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
+ return new(zone()) LSeqStringSetChar(string, index, value);
}
class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> {
public:
- LSeqStringSetChar(String::Encoding encoding,
- LOperand* string,
+ LSeqStringSetChar(LOperand* string,
LOperand* index,
- LOperand* value) : encoding_(encoding) {
+ LOperand* value) {
inputs_[0] = string;
inputs_[1] = index;
inputs_[2] = value;
}
- String::Encoding encoding() { return encoding_; }
LOperand* string() { return inputs_[0]; }
LOperand* index() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
-
- private:
- String::Encoding encoding_;
};
}
+MemOperand LCodeGen::BuildSeqStringOperand(Register string,
+ LOperand* index,
+ String::Encoding encoding) {
+ if (index->IsConstantOperand()) {
+ int offset = ToInteger32(LConstantOperand::cast(index));
+ if (encoding == String::TWO_BYTE_ENCODING) {
+ offset *= kUC16Size;
+ }
+ STATIC_ASSERT(kCharSize == 1);
+ return FieldMemOperand(string, SeqString::kHeaderSize + offset);
+ }
+ Register scratch = scratch0();
+ ASSERT(!scratch.is(string));
+ ASSERT(!scratch.is(ToRegister(index)));
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ __ add(scratch, string, Operand(ToRegister(index)));
+ } else {
+ STATIC_ASSERT(kUC16Size == 2);
+ __ add(scratch, string, Operand(ToRegister(index), LSL, 1));
+ }
+ return FieldMemOperand(scratch, SeqString::kHeaderSize);
+}
+
+
void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
+ String::Encoding encoding = instr->hydrogen()->encoding();
Register string = ToRegister(instr->string());
- LOperand* index_op = instr->index();
Register value = ToRegister(instr->value());
- Register scratch = scratch0();
- String::Encoding encoding = instr->encoding();
if (FLAG_debug_code) {
+ Register scratch = scratch0();
__ ldr(scratch, FieldMemOperand(string, HeapObject::kMapOffset));
__ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
__ Check(eq, kUnexpectedStringType);
}
- if (index_op->IsConstantOperand()) {
- int constant_index = ToInteger32(LConstantOperand::cast(index_op));
- if (encoding == String::ONE_BYTE_ENCODING) {
- __ strb(value,
- FieldMemOperand(string, SeqString::kHeaderSize + constant_index));
- } else {
- __ strh(value,
- FieldMemOperand(string, SeqString::kHeaderSize + constant_index * 2));
- }
+ MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding);
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ __ strb(value, operand);
} else {
- Register index = ToRegister(index_op);
- if (encoding == String::ONE_BYTE_ENCODING) {
- __ add(scratch, string, Operand(index));
- __ strb(value, FieldMemOperand(scratch, SeqString::kHeaderSize));
- } else {
- __ add(scratch, string, Operand(index, LSL, 1));
- __ strh(value, FieldMemOperand(scratch, SeqString::kHeaderSize));
- }
+ __ strh(value, operand);
}
}
Register ToRegister(int index) const;
DwVfpRegister ToDoubleRegister(int index) const;
+ MemOperand BuildSeqStringOperand(Register string,
+ LOperand* index,
+ String::Encoding encoding);
+
void EmitIntegerMathAbs(LMathAbs* instr);
// Support for recording safepoint and position information.
V(GlobalVars) \
V(InobjectFields) \
V(OsrEntries) \
- V(ExternalMemory)
+ V(ExternalMemory) \
+ V(StringChars)
#define DECLARE_ABSTRACT_INSTRUCTION(type) \
};
-typedef EnumSet<GVNFlag> GVNFlagSet;
+typedef EnumSet<GVNFlag, int64_t> GVNFlagSet;
class HValue : public ZoneObject {
set_representation(Representation::Integer32());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
+ SetGVNFlag(kDependsOnStringChars);
SetGVNFlag(kChangesNewSpacePromotion);
}
SetOperandAt(1, index);
SetOperandAt(2, value);
set_representation(Representation::Tagged());
+ SetGVNFlag(kChangesStringChars);
}
String::Encoding encoding_;
}
+void Assembler::mov_w(const Operand& dst, int16_t imm16) {
+ EnsureSpace ensure_space(this);
+ EMIT(0x66);
+ EMIT(0xC7);
+ emit_operand(eax, dst);
+ EMIT(static_cast<int8_t>(imm16 & 0xff));
+ EMIT(static_cast<int8_t>(imm16 >> 8));
+}
+
+
void Assembler::mov(Register dst, int32_t imm32) {
EnsureSpace ensure_space(this);
EMIT(0xB8 | dst.code());
void mov_w(Register dst, const Operand& src);
void mov_w(const Operand& dst, Register src);
+ void mov_w(const Operand& dst, int16_t imm16);
void mov(Register dst, int32_t imm32);
void mov(Register dst, const Immediate& x);
AppendToBuffer("mov_w ");
data += PrintRightOperand(data);
AppendToBuffer(",%s", NameOfCPURegister(regop));
+ } else if (*data == 0xC7) {
+ data++;
+ AppendToBuffer("%s ", "mov_w");
+ data += PrintRightOperand(data);
+ int imm = *reinterpret_cast<int16_t*>(data);
+ AppendToBuffer(",0x%x", imm);
+ data += 2;
} else if (*data == 0x0F) {
data++;
if (*data == 0x38) {
}
+Operand LCodeGen::BuildSeqStringOperand(Register string,
+ LOperand* index,
+ String::Encoding encoding) {
+ if (index->IsConstantOperand()) {
+ int offset = ToRepresentation(LConstantOperand::cast(index),
+ Representation::Integer32());
+ if (encoding == String::TWO_BYTE_ENCODING) {
+ offset *= kUC16Size;
+ }
+ STATIC_ASSERT(kCharSize == 1);
+ return FieldOperand(string, SeqString::kHeaderSize + offset);
+ }
+ return FieldOperand(
+ string, ToRegister(index),
+ encoding == String::ONE_BYTE_ENCODING ? times_1 : times_2,
+ SeqString::kHeaderSize);
+}
+
+
void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
+ String::Encoding encoding = instr->hydrogen()->encoding();
Register string = ToRegister(instr->string());
- Register index = ToRegister(instr->index());
- Register value = ToRegister(instr->value());
- String::Encoding encoding = instr->encoding();
if (FLAG_debug_code) {
- __ push(value);
- __ mov(value, FieldOperand(string, HeapObject::kMapOffset));
- __ movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset));
+ __ push(string);
+ __ mov(string, FieldOperand(string, HeapObject::kMapOffset));
+ __ movzx_b(string, FieldOperand(string, Map::kInstanceTypeOffset));
- __ and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
+ __ and_(string, Immediate(kStringRepresentationMask | kStringEncodingMask));
static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
- __ cmp(value, Immediate(encoding == String::ONE_BYTE_ENCODING
- ? one_byte_seq_type : two_byte_seq_type));
+ __ cmp(string, Immediate(encoding == String::ONE_BYTE_ENCODING
+ ? one_byte_seq_type : two_byte_seq_type));
__ Check(equal, kUnexpectedStringType);
- __ pop(value);
+ __ pop(string);
}
- if (encoding == String::ONE_BYTE_ENCODING) {
- __ mov_b(FieldOperand(string, index, times_1, SeqString::kHeaderSize),
- value);
+ Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
+ if (instr->value()->IsConstantOperand()) {
+ int value = ToRepresentation(LConstantOperand::cast(instr->value()),
+ Representation::Integer32());
+ ASSERT_LE(0, value);
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ ASSERT_LE(value, String::kMaxOneByteCharCode);
+ __ mov_b(operand, static_cast<int8_t>(value));
+ } else {
+ ASSERT_LE(value, String::kMaxUtf16CodeUnit);
+ __ mov_w(operand, static_cast<int16_t>(value));
+ }
} else {
- __ mov_w(FieldOperand(string, index, times_2, SeqString::kHeaderSize),
- value);
+ Register value = ToRegister(instr->value());
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ __ mov_b(operand, value);
+ } else {
+ __ mov_w(operand, value);
+ }
}
}
uint32_t offset,
uint32_t additional_index = 0);
+ Operand BuildSeqStringOperand(Register string,
+ LOperand* index,
+ String::Encoding encoding);
+
void EmitIntegerMathAbs(LMathAbs* instr);
// Support for recording safepoint and position information.
}
+LOperand* LChunkBuilder::UseFixedOrConstant(HValue* value,
+ Register fixed_register) {
+ return CanBeImmediateConstant(value)
+ ? chunk_->DefineConstantOperand(HConstant::cast(value))
+ : UseFixed(value, fixed_register);
+}
+
+
LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
return CanBeImmediateConstant(value)
? chunk_->DefineConstantOperand(HConstant::cast(value))
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
- LOperand* string = UseRegister(instr->string());
- LOperand* index = UseRegister(instr->index());
- ASSERT(ecx.is_byte_register());
- LOperand* value = UseFixed(instr->value(), ecx);
- LSeqStringSetChar* result =
- new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
- return DefineSameAsFirst(result);
+ LOperand* string = UseRegisterAtStart(instr->string());
+ LOperand* index = UseRegisterOrConstantAtStart(instr->index());
+ LOperand* value = (instr->encoding() == String::ONE_BYTE_ENCODING)
+ ? UseFixedOrConstant(instr->value(), eax)
+ : UseRegisterOrConstantAtStart(instr->value());
+ return new(zone()) LSeqStringSetChar(string, index, value);
}
class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> {
public:
- LSeqStringSetChar(String::Encoding encoding,
- LOperand* string,
+ LSeqStringSetChar(LOperand* string,
LOperand* index,
- LOperand* value) : encoding_(encoding) {
+ LOperand* value) {
inputs_[0] = string;
inputs_[1] = index;
inputs_[2] = value;
}
- String::Encoding encoding() { return encoding_; }
LOperand* string() { return inputs_[0]; }
LOperand* index() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
-
- private:
- String::Encoding encoding_;
};
MUST_USE_RESULT LOperand* UseOrConstant(HValue* value);
MUST_USE_RESULT LOperand* UseOrConstantAtStart(HValue* value);
+ // An input operand in a fixed register or a constant operand.
+ MUST_USE_RESULT LOperand* UseFixedOrConstant(HValue* value,
+ Register fixed_register);
+
// An input operand in a register or a constant operand.
MUST_USE_RESULT LOperand* UseRegisterOrConstant(HValue* value);
MUST_USE_RESULT LOperand* UseRegisterOrConstantAtStart(HValue* value);
}
+void Assembler::movb(const Operand& dst, Immediate imm) {
+ EnsureSpace ensure_space(this);
+ emit_optional_rex_32(dst);
+ emit(0xC6);
+ emit_operand(0x0, dst);
+ emit(static_cast<byte>(imm.value_));
+}
+
+
void Assembler::movw(const Operand& dst, Register src) {
EnsureSpace ensure_space(this);
emit(0x66);
}
+void Assembler::movw(const Operand& dst, Immediate imm) {
+ EnsureSpace ensure_space(this);
+ emit(0x66);
+ emit_optional_rex_32(dst);
+ emit(0xC7);
+ emit_operand(0x0, dst);
+ emit(static_cast<byte>(imm.value_ & 0xff));
+ emit(static_cast<byte>(imm.value_ >> 8));
+}
+
+
void Assembler::movl(Register dst, const Operand& src) {
EnsureSpace ensure_space(this);
emit_optional_rex_32(dst, src);
void movb(Register dst, const Operand& src);
void movb(Register dst, Immediate imm);
void movb(const Operand& dst, Register src);
+ void movb(const Operand& dst, Immediate imm);
// Move the low 16 bits of a 64-bit register value to a 16-bit
// memory location.
void movw(const Operand& dst, Register src);
+ void movw(const Operand& dst, Immediate imm);
void movl(Register dst, Register src);
void movl(Register dst, const Operand& src);
} else {
AppendToBuffer("mov%c ", operand_size_code());
data += PrintRightOperand(data);
- int32_t imm = *reinterpret_cast<int32_t*>(data);
- AppendToBuffer(",0x%x", imm);
- data += 4;
+ if (operand_size() == OPERAND_WORD_SIZE) {
+ int16_t imm = *reinterpret_cast<int16_t*>(data);
+ AppendToBuffer(",0x%x", imm);
+ data += 2;
+ } else {
+ int32_t imm = *reinterpret_cast<int32_t*>(data);
+ AppendToBuffer(",0x%x", imm);
+ data += 4;
+ }
}
}
break;
}
+Operand LCodeGen::BuildSeqStringOperand(Register string,
+ LOperand* index,
+ String::Encoding encoding) {
+ if (index->IsConstantOperand()) {
+ int offset = ToInteger32(LConstantOperand::cast(index));
+ if (encoding == String::TWO_BYTE_ENCODING) {
+ offset *= kUC16Size;
+ }
+ STATIC_ASSERT(kCharSize == 1);
+ return FieldOperand(string, SeqString::kHeaderSize + offset);
+ }
+ return FieldOperand(
+ string, ToRegister(index),
+ encoding == String::ONE_BYTE_ENCODING ? times_1 : times_2,
+ SeqString::kHeaderSize);
+}
+
+
void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
+ String::Encoding encoding = instr->hydrogen()->encoding();
Register string = ToRegister(instr->string());
- Register index = ToRegister(instr->index());
- Register value = ToRegister(instr->value());
- String::Encoding encoding = instr->encoding();
if (FLAG_debug_code) {
- __ push(value);
- __ movq(value, FieldOperand(string, HeapObject::kMapOffset));
- __ movzxbq(value, FieldOperand(value, Map::kInstanceTypeOffset));
+ __ push(string);
+ __ movq(string, FieldOperand(string, HeapObject::kMapOffset));
+ __ movzxbq(string, FieldOperand(string, Map::kInstanceTypeOffset));
- __ andb(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
+ __ andb(string, Immediate(kStringRepresentationMask | kStringEncodingMask));
static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
- __ cmpq(value, Immediate(encoding == String::ONE_BYTE_ENCODING
- ? one_byte_seq_type : two_byte_seq_type));
+ __ cmpq(string, Immediate(encoding == String::ONE_BYTE_ENCODING
+ ? one_byte_seq_type : two_byte_seq_type));
__ Check(equal, kUnexpectedStringType);
- __ pop(value);
+ __ pop(string);
}
- if (encoding == String::ONE_BYTE_ENCODING) {
- __ movb(FieldOperand(string, index, times_1, SeqString::kHeaderSize),
- value);
+ Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
+ if (instr->value()->IsConstantOperand()) {
+ int value = ToInteger32(LConstantOperand::cast(instr->value()));
+ ASSERT_LE(0, value);
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ ASSERT_LE(value, String::kMaxOneByteCharCode);
+ __ movb(operand, Immediate(value));
+ } else {
+ ASSERT_LE(value, String::kMaxUtf16CodeUnit);
+ __ movw(operand, Immediate(value));
+ }
} else {
- __ movw(FieldOperand(string, index, times_2, SeqString::kHeaderSize),
- value);
+ Register value = ToRegister(instr->value());
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ __ movb(operand, value);
+ } else {
+ __ movw(operand, value);
+ }
}
}
uint32_t offset,
uint32_t additional_index = 0);
+ Operand BuildSeqStringOperand(Register string,
+ LOperand* index,
+ String::Encoding encoding);
+
void EmitIntegerMathAbs(LMathAbs* instr);
void EmitSmiMathAbs(LMathAbs* instr);
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
- LOperand* string = UseRegister(instr->string());
- LOperand* index = UseRegister(instr->index());
- ASSERT(rcx.is_byte_register());
- LOperand* value = UseFixed(instr->value(), rcx);
- LSeqStringSetChar* result =
- new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
- return DefineSameAsFirst(result);
+ LOperand* string = UseRegisterAtStart(instr->string());
+ LOperand* index = UseRegisterOrConstantAtStart(instr->index());
+ LOperand* value = UseRegisterOrConstantAtStart(instr->value());
+ return new(zone()) LSeqStringSetChar(string, index, value);
}
class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> {
public:
- LSeqStringSetChar(String::Encoding encoding,
- LOperand* string,
+ LSeqStringSetChar(LOperand* string,
LOperand* index,
- LOperand* value) : encoding_(encoding) {
+ LOperand* value) {
inputs_[0] = string;
inputs_[1] = index;
inputs_[2] = value;
}
- String::Encoding encoding() { return encoding_; }
LOperand* string() { return inputs_[0]; }
LOperand* index() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
-
- private:
- String::Encoding encoding_;
};
function test() {
var s1 = %NewString(26, true);
+ for (i = 0; i < 26; i++) %_OneByteSeqStringSetChar(s1, i, 65);
+ assertEquals("AAAAAAAAAAAAAAAAAAAAAAAAAA", s1);
+ %_OneByteSeqStringSetChar(s1, 25, 66);
+ assertEquals("AAAAAAAAAAAAAAAAAAAAAAAAAB", s1);
for (i = 0; i < 26; i++) %_OneByteSeqStringSetChar(s1, i, i+65);
assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZ", s1);
s1 = %TruncateString(s1, 13);
assertEquals("ABCDEFGHIJKLM", s1);
var s2 = %NewString(26, false);
+ for (i = 0; i < 26; i++) %_TwoByteSeqStringSetChar(s2, i, 65);
+ assertEquals("AAAAAAAAAAAAAAAAAAAAAAAAAA", s2);
+ %_TwoByteSeqStringSetChar(s2, 25, 66);
+ assertEquals("AAAAAAAAAAAAAAAAAAAAAAAAAB", s2);
for (i = 0; i < 26; i++) %_TwoByteSeqStringSetChar(s2, i, i+65);
assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZ", s2);
- s2 = %TruncateString(s1, 13);
+ s2 = %TruncateString(s2, 13);
assertEquals("ABCDEFGHIJKLM", s2);
var s3 = %NewString(26, false);