}
-void SeqStringSetCharGenerator::Generate(MacroAssembler* masm,
- String::Encoding encoding,
- Register string,
- Register index,
- Register value) {
- if (FLAG_debug_code) {
- __ SmiTst(index);
- __ Check(eq, "Non-smi index");
- __ SmiTst(value);
- __ Check(eq, "Non-smi value");
-
- __ ldr(ip, FieldMemOperand(string, String::kLengthOffset));
- __ cmp(index, ip);
- __ Check(lt, "Index is too large");
-
- __ cmp(index, Operand(Smi::FromInt(0)));
- __ Check(ge, "Index is negative");
-
- __ ldr(ip, FieldMemOperand(string, HeapObject::kMapOffset));
- __ ldrb(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset));
-
- __ and_(ip, ip, Operand(kStringRepresentationMask | kStringEncodingMask));
- static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
- static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
- __ cmp(ip, Operand(encoding == String::ONE_BYTE_ENCODING
- ? one_byte_seq_type : two_byte_seq_type));
- __ Check(eq, "Unexpected string type");
- }
-
- __ add(ip,
- string,
- Operand(SeqString::kHeaderSize - kHeapObjectTag));
- __ SmiUntag(value, value);
- STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
- if (encoding == String::ONE_BYTE_ENCODING) {
- // Smis are tagged by left shift by 1, thus LSR by 1 to smi-untag inline.
- __ strb(value, MemOperand(ip, index, LSR, kSmiTagSize));
- } else {
- // No need to untag a smi for two-byte addressing.
- __ strh(value, MemOperand(ip, index)); // LSL(1 - kSmiTagSize).
- }
-}
-
-
static MemOperand ExpConstant(int index, Register base) {
return MemOperand(base, index * kDoubleSize);
}
}
+void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string,
+ Register index,
+ Register value,
+ uint32_t encoding_mask) {
+ __ SmiTst(index);
+ __ Check(eq, "Non-smi index");
+ __ SmiTst(value);
+ __ Check(eq, "Non-smi value");
+
+ __ ldr(ip, FieldMemOperand(string, String::kLengthOffset));
+ __ cmp(index, ip);
+ __ Check(lt, "Index is too large");
+
+ __ cmp(index, Operand(Smi::FromInt(0)));
+ __ Check(ge, "Index is negative");
+
+ __ ldr(ip, FieldMemOperand(string, HeapObject::kMapOffset));
+ __ ldrb(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset));
+
+ __ and_(ip, ip, Operand(kStringRepresentationMask | kStringEncodingMask));
+ __ cmp(ip, Operand(encoding_mask));
+ __ Check(eq, "Unexpected string type");
+}
+
+
void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT_EQ(3, args->length());
+ Register string = r0;
+ Register index = r1;
+ Register value = r2;
+
VisitForStackValue(args->at(1)); // index
VisitForStackValue(args->at(2)); // value
- __ pop(r2);
- __ pop(r1);
+ __ pop(value);
+ __ pop(index);
VisitForAccumulatorValue(args->at(0)); // string
- static const String::Encoding encoding = String::ONE_BYTE_ENCODING;
- SeqStringSetCharGenerator::Generate(masm_, encoding, r0, r1, r2);
- context()->Plug(r0);
+ if (FLAG_debug_code) {
+ static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+ }
+
+ __ SmiUntag(value, value);
+ __ add(ip,
+ string,
+ Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
+ __ strb(value, MemOperand(ip, index, LSR, kSmiTagSize));
+ context()->Plug(string);
}
ZoneList<Expression*>* args = expr->arguments();
ASSERT_EQ(3, args->length());
+ Register string = r0;
+ Register index = r1;
+ Register value = r2;
+
VisitForStackValue(args->at(1)); // index
VisitForStackValue(args->at(2)); // value
- __ pop(r2);
- __ pop(r1);
+ __ pop(value);
+ __ pop(index);
VisitForAccumulatorValue(args->at(0)); // string
- static const String::Encoding encoding = String::TWO_BYTE_ENCODING;
- SeqStringSetCharGenerator::Generate(masm_, encoding, r0, r1, r2);
- context()->Plug(r0);
+ if (FLAG_debug_code) {
+ static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
+ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+ }
+
+ __ SmiUntag(value, value);
+ __ add(ip,
+ string,
+ Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
+ STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
+ __ strh(value, MemOperand(ip, index));
+ context()->Plug(string);
}
void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
- SeqStringSetCharGenerator::Generate(masm(),
- instr->encoding(),
- ToRegister(instr->string()),
- ToRegister(instr->index()),
- ToRegister(instr->value()));
+ Register string = ToRegister(instr->string());
+ Register index = ToRegister(instr->index());
+ Register value = ToRegister(instr->value());
+ String::Encoding encoding = instr->encoding();
+
+ if (FLAG_debug_code) {
+ __ ldr(ip, FieldMemOperand(string, HeapObject::kMapOffset));
+ __ ldrb(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset));
+
+ __ and_(ip, ip, Operand(kStringRepresentationMask | kStringEncodingMask));
+ static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+ static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
+ __ cmp(ip, Operand(encoding == String::ONE_BYTE_ENCODING
+ ? one_byte_seq_type : two_byte_seq_type));
+ __ Check(eq, "Unexpected string type");
+ }
+
+ __ add(ip,
+ string,
+ Operand(SeqString::kHeaderSize - kHeapObjectTag));
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ __ strb(value, MemOperand(ip, index));
+ } else {
+ // MemOperand with ip as the base register is not allowed for strh, so
+ // we do the address calculation explicitly.
+ __ add(ip, ip, Operand(index, LSL, 1));
+ __ strh(value, MemOperand(ip));
+ }
}
};
-class SeqStringSetCharGenerator : public AllStatic {
- public:
- static void Generate(MacroAssembler* masm,
- String::Encoding encoding,
- Register string,
- Register index,
- Register value);
- private:
- DISALLOW_COPY_AND_ASSIGN(SeqStringSetCharGenerator);
-};
-
-
} } // namespace v8::internal
#endif // V8_CODEGEN_H_
INLINE_RUNTIME_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
#undef EMIT_INLINE_RUNTIME_CALL
+ void EmitSeqStringSetCharCheck(Register string,
+ Register index,
+ Register value,
+ uint32_t encoding_mask);
+
// Platform-specific code for resuming generators.
void EmitGeneratorResume(Expression *generator,
Expression *value,
SetOperandAt(0, string);
SetOperandAt(1, index);
SetOperandAt(2, value);
+ set_representation(Representation::Tagged());
}
String::Encoding encoding() { return encoding_; }
HValue* value() { return OperandAt(2); }
virtual Representation RequiredInputRepresentation(int index) {
- return Representation::Tagged();
+ return (index == 0) ? Representation::Tagged()
+ : Representation::Integer32();
}
DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar)
HValue* value = Pop();
HValue* index = Pop();
HValue* string = Pop();
- HValue* context = environment()->LookupContext();
- HInstruction* char_code = BuildStringCharCodeAt(context, string, index);
- AddInstruction(char_code);
HSeqStringSetChar* result = new(zone()) HSeqStringSetChar(
String::TWO_BYTE_ENCODING, string, index, value);
return ast_context()->ReturnInstruction(result, call->id());
}
-void SeqStringSetCharGenerator::Generate(MacroAssembler* masm,
- String::Encoding encoding,
- Register string,
- Register index,
- Register value) {
- if (FLAG_debug_code) {
- __ test(index, Immediate(kSmiTagMask));
- __ Check(zero, "Non-smi index");
- __ test(value, Immediate(kSmiTagMask));
- __ Check(zero, "Non-smi value");
-
- __ cmp(index, FieldOperand(string, String::kLengthOffset));
- __ Check(less, "Index is too large");
-
- __ cmp(index, Immediate(Smi::FromInt(0)));
- __ Check(greater_equal, "Index is negative");
-
- __ push(value);
- __ mov(value, FieldOperand(string, HeapObject::kMapOffset));
- __ movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset));
-
- __ and_(value, 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));
- __ Check(equal, "Unexpected string type");
- __ pop(value);
- }
-
- __ SmiUntag(value);
- STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
- if (encoding == String::ONE_BYTE_ENCODING) {
- __ SmiUntag(index);
- __ mov_b(FieldOperand(string, index, times_1, SeqString::kHeaderSize),
- value);
- } else {
- // No need to untag a smi for two-byte addressing.
- __ mov_w(FieldOperand(string, index, times_1, SeqString::kHeaderSize),
- value);
- }
-}
-
-
static Operand ExpConstant(int index) {
return Operand::StaticVariable(ExternalReference::math_exp_constants(index));
}
}
+void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string,
+ Register index,
+ Register value,
+ uint32_t encoding_mask) {
+ __ test(index, Immediate(kSmiTagMask));
+ __ Check(zero, "Non-smi index");
+ __ test(value, Immediate(kSmiTagMask));
+ __ Check(zero, "Non-smi value");
+
+ __ cmp(index, FieldOperand(string, String::kLengthOffset));
+ __ Check(less, "Index is too large");
+
+ __ cmp(index, Immediate(Smi::FromInt(0)));
+ __ Check(greater_equal, "Index is negative");
+
+ __ push(value);
+ __ mov(value, FieldOperand(string, HeapObject::kMapOffset));
+ __ movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset));
+
+ __ and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
+ __ cmp(value, Immediate(encoding_mask));
+ __ Check(equal, "Unexpected string type");
+ __ pop(value);
+}
+
+
void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT_EQ(3, args->length());
+ Register string = eax;
+ Register index = ebx;
+ Register value = ecx;
+
VisitForStackValue(args->at(1)); // index
VisitForStackValue(args->at(2)); // value
- __ pop(ecx);
- __ pop(ebx);
+ __ pop(value);
+ __ pop(index);
VisitForAccumulatorValue(args->at(0)); // string
- static const String::Encoding encoding = String::ONE_BYTE_ENCODING;
- SeqStringSetCharGenerator::Generate(masm_, encoding, eax, ebx, ecx);
- context()->Plug(eax);
+
+ if (FLAG_debug_code) {
+ static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+ }
+
+ __ SmiUntag(value);
+ __ SmiUntag(index);
+ __ mov_b(FieldOperand(string, index, times_1, SeqOneByteString::kHeaderSize),
+ value);
+ context()->Plug(string);
}
ZoneList<Expression*>* args = expr->arguments();
ASSERT_EQ(3, args->length());
+ Register string = eax;
+ Register index = ebx;
+ Register value = ecx;
+
VisitForStackValue(args->at(1)); // index
VisitForStackValue(args->at(2)); // value
- __ pop(ecx);
- __ pop(ebx);
+ __ pop(value);
+ __ pop(index);
VisitForAccumulatorValue(args->at(0)); // string
- static const String::Encoding encoding = String::TWO_BYTE_ENCODING;
- SeqStringSetCharGenerator::Generate(masm_, encoding, eax, ebx, ecx);
- context()->Plug(eax);
+ if (FLAG_debug_code) {
+ static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
+ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+ }
+
+ __ SmiUntag(value);
+ // No need to untag a smi for two-byte addressing.
+ __ mov_w(FieldOperand(string, index, times_1, SeqTwoByteString::kHeaderSize),
+ value);
+ context()->Plug(string);
}
void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
- SeqStringSetCharGenerator::Generate(masm(),
- instr->encoding(),
- ToRegister(instr->string()),
- ToRegister(instr->index()),
- ToRegister(instr->value()));
+ 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));
+
+ __ and_(value, 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));
+ __ Check(equal, "Unexpected string type");
+ __ pop(value);
+ }
+
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ __ mov_b(FieldOperand(string, index, times_1, SeqString::kHeaderSize),
+ value);
+ } else {
+ __ mov_w(FieldOperand(string, index, times_2, SeqString::kHeaderSize),
+ value);
+ }
}
LOperand* string = UseRegister(instr->string());
LOperand* index = UseRegister(instr->index());
ASSERT(ecx.is_byte_register());
- // TODO(titzer): the machine code for this instruction overwrites ecx! fix!
LOperand* value = UseFixed(instr->value(), ecx);
LSeqStringSetChar* result =
new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
}
-void SeqStringSetCharGenerator::Generate(MacroAssembler* masm,
- String::Encoding encoding,
- Register string,
- Register index,
- Register value) {
- if (FLAG_debug_code) {
- __ Check(masm->CheckSmi(index), "Non-smi index");
- __ Check(masm->CheckSmi(value), "Non-smi value");
-
- __ SmiCompare(index, FieldOperand(string, String::kLengthOffset));
- __ Check(less, "Index is too large");
-
- __ SmiCompare(index, Smi::FromInt(0));
- __ Check(greater_equal, "Index is negative");
-
- __ push(value);
- __ movq(value, FieldOperand(string, HeapObject::kMapOffset));
- __ movzxbq(value, FieldOperand(value, Map::kInstanceTypeOffset));
-
- __ andb(value, 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));
- __ Check(equal, "Unexpected string type");
- __ pop(value);
- }
-
- __ SmiToInteger32(value, value);
- __ SmiToInteger32(index, index);
- if (encoding == String::ONE_BYTE_ENCODING) {
- __ movb(FieldOperand(string, index, times_1, SeqString::kHeaderSize),
- value);
- } else {
- __ movw(FieldOperand(string, index, times_2, SeqString::kHeaderSize),
- value);
- }
-}
-
-
void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
XMMRegister input,
XMMRegister result,
}
+void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string,
+ Register index,
+ Register value,
+ uint32_t encoding_mask) {
+ __ Check(masm()->CheckSmi(index), "Non-smi index");
+ __ Check(masm()->CheckSmi(value), "Non-smi value");
+
+ __ SmiCompare(index, FieldOperand(string, String::kLengthOffset));
+ __ Check(less, "Index is too large");
+
+ __ SmiCompare(index, Smi::FromInt(0));
+ __ Check(greater_equal, "Index is negative");
+
+ __ push(value);
+ __ movq(value, FieldOperand(string, HeapObject::kMapOffset));
+ __ movzxbq(value, FieldOperand(value, Map::kInstanceTypeOffset));
+
+ __ andb(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
+ __ cmpq(value, Immediate(encoding_mask));
+ __ Check(equal, "Unexpected string type");
+ __ pop(value);
+}
+
+
void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT_EQ(3, args->length());
+ Register string = rax;
+ Register index = rbx;
+ Register value = rcx;
+
VisitForStackValue(args->at(1)); // index
VisitForStackValue(args->at(2)); // value
- __ pop(rcx);
- __ pop(rbx);
+ __ pop(value);
+ __ pop(index);
VisitForAccumulatorValue(args->at(0)); // string
- static const String::Encoding encoding = String::ONE_BYTE_ENCODING;
- SeqStringSetCharGenerator::Generate(masm_, encoding, rax, rbx, rcx);
- context()->Plug(rax);
+ if (FLAG_debug_code) {
+ static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+ }
+
+ __ SmiToInteger32(value, value);
+ __ SmiToInteger32(index, index);
+ __ movb(FieldOperand(string, index, times_1, SeqOneByteString::kHeaderSize),
+ value);
+ context()->Plug(string);
}
ZoneList<Expression*>* args = expr->arguments();
ASSERT_EQ(3, args->length());
+ Register string = rax;
+ Register index = rbx;
+ Register value = rcx;
+
VisitForStackValue(args->at(1)); // index
VisitForStackValue(args->at(2)); // value
- __ pop(rcx);
- __ pop(rbx);
+ __ pop(value);
+ __ pop(index);
VisitForAccumulatorValue(args->at(0)); // string
- static const String::Encoding encoding = String::TWO_BYTE_ENCODING;
- SeqStringSetCharGenerator::Generate(masm_, encoding, rax, rbx, rcx);
+ if (FLAG_debug_code) {
+ static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
+ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+ }
+
+ __ SmiToInteger32(value, value);
+ __ SmiToInteger32(index, index);
+ __ movw(FieldOperand(string, index, times_2, SeqTwoByteString::kHeaderSize),
+ value);
context()->Plug(rax);
}
void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
- SeqStringSetCharGenerator::Generate(masm(),
- instr->encoding(),
- ToRegister(instr->string()),
- ToRegister(instr->index()),
- ToRegister(instr->value()));
+ 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));
+
+ __ andb(value, 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));
+ __ Check(equal, "Unexpected string type");
+ __ pop(value);
+ }
+
+ if (encoding == String::ONE_BYTE_ENCODING) {
+ __ movb(FieldOperand(string, index, times_1, SeqString::kHeaderSize),
+ value);
+ } else {
+ __ movw(FieldOperand(string, index, times_2, SeqString::kHeaderSize),
+ value);
+ }
}
test(i);
}
+assertEquals("AAAA", String.fromCharCode(65, 65, 65, 65));
+assertEquals("AAAA", String.fromCharCode(65, 65, 65, 65));
+%OptimizeFunctionOnNextCall(String.fromCharCode);
+assertEquals("AAAA", String.fromCharCode(65, 65, 65, 65));
// Test the custom IC works correctly when the map changes.
for (var i = 0; i < 10; i++) {