Commit 3f208328 authored by vitalyr@chromium.org's avatar vitalyr@chromium.org

Start using String type info:

 * Improved string concatenation.

 * Fixed type inference in prefix/postfix count operations.

Review URL: http://codereview.chromium.org/1520001

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4305 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 0b42d25c
......@@ -1132,9 +1132,9 @@ void DeferredInlineBinaryOperation::Generate() {
static TypeInfo CalculateTypeInfo(TypeInfo operands_type,
Token::Value op,
const Result& right,
const Result& left) {
Token::Value op,
const Result& right,
const Result& left) {
// Set TypeInfo of result according to the operation performed.
// Rely on the fact that smis have a 31 bit payload on ia32.
ASSERT(kSmiValueSize == 31);
......@@ -1193,11 +1193,12 @@ static TypeInfo CalculateTypeInfo(TypeInfo operands_type,
if (operands_type.IsSmi()) {
// The Integer32 range is big enough to take the sum of any two Smis.
return TypeInfo::Integer32();
} else if (operands_type.IsNumber()) {
return TypeInfo::Number();
} else if (left.type_info().IsString() || right.type_info().IsString()) {
return TypeInfo::String();
} else {
// Result could be a string or a number. Check types of inputs.
return operands_type.IsNumber()
? TypeInfo::Number()
: TypeInfo::Unknown();
return TypeInfo::Unknown();
}
case Token::SHL:
return TypeInfo::Integer32();
......@@ -1237,8 +1238,13 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
Result left = frame_->Pop();
if (op == Token::ADD) {
bool left_is_string = left.is_constant() && left.handle()->IsString();
bool right_is_string = right.is_constant() && right.handle()->IsString();
const bool left_is_string = left.type_info().IsString();
const bool right_is_string = right.type_info().IsString();
// Make sure constant strings have string type info.
ASSERT(!(left.is_constant() && left.handle()->IsString()) ||
left_is_string);
ASSERT(!(right.is_constant() && right.handle()->IsString()) ||
right_is_string);
if (left_is_string || right_is_string) {
frame_->Push(&left);
frame_->Push(&right);
......@@ -1247,7 +1253,8 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
if (right_is_string) {
// TODO(lrn): if both are constant strings
// -- do a compile time cons, if allocation during codegen is allowed.
answer = frame_->CallRuntime(Runtime::kStringAdd, 2);
StringAddStub stub(NO_STRING_CHECK_IN_STUB);
answer = frame_->CallStub(&stub, 2);
} else {
answer =
frame_->InvokeBuiltin(Builtins::STRING_ADD_LEFT, CALL_FUNCTION, 2);
......@@ -1256,6 +1263,7 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
answer =
frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION, 2);
}
answer.set_type_info(TypeInfo::String());
frame_->Push(&answer);
return;
}
......@@ -7003,8 +7011,10 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
// specialized add or subtract stub. The result is left in dst.
class DeferredPrefixCountOperation: public DeferredCode {
public:
DeferredPrefixCountOperation(Register dst, bool is_increment)
: dst_(dst), is_increment_(is_increment) {
DeferredPrefixCountOperation(Register dst,
bool is_increment,
TypeInfo input_type)
: dst_(dst), is_increment_(is_increment), input_type_(input_type) {
set_comment("[ DeferredCountOperation");
}
......@@ -7013,6 +7023,7 @@ class DeferredPrefixCountOperation: public DeferredCode {
private:
Register dst_;
bool is_increment_;
TypeInfo input_type_;
};
......@@ -7024,8 +7035,10 @@ void DeferredPrefixCountOperation::Generate() {
__ add(Operand(dst_), Immediate(Smi::FromInt(1)));
}
__ push(dst_);
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
__ push(eax);
if (!input_type_.IsNumber()) {
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
__ push(eax);
}
__ push(Immediate(Smi::FromInt(1)));
if (is_increment_) {
__ CallRuntime(Runtime::kNumberAdd, 2);
......@@ -7043,8 +7056,14 @@ void DeferredPrefixCountOperation::Generate() {
// The result is left in dst.
class DeferredPostfixCountOperation: public DeferredCode {
public:
DeferredPostfixCountOperation(Register dst, Register old, bool is_increment)
: dst_(dst), old_(old), is_increment_(is_increment) {
DeferredPostfixCountOperation(Register dst,
Register old,
bool is_increment,
TypeInfo input_type)
: dst_(dst),
old_(old),
is_increment_(is_increment),
input_type_(input_type) {
set_comment("[ DeferredCountOperation");
}
......@@ -7054,6 +7073,7 @@ class DeferredPostfixCountOperation: public DeferredCode {
Register dst_;
Register old_;
bool is_increment_;
TypeInfo input_type_;
};
......@@ -7064,14 +7084,17 @@ void DeferredPostfixCountOperation::Generate() {
} else {
__ add(Operand(dst_), Immediate(Smi::FromInt(1)));
}
__ push(dst_);
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
// Save the result of ToNumber to use as the old value.
__ push(eax);
if (input_type_.IsNumber()) {
__ push(dst_); // Save the input to use as the old value.
__ push(dst_);
} else {
__ push(dst_);
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
__ push(eax); // Save the result of ToNumber to use as the old value.
__ push(eax);
}
// Call the runtime for the addition or subtraction.
__ push(eax);
__ push(Immediate(Smi::FromInt(1)));
if (is_increment_) {
__ CallRuntime(Runtime::kNumberAdd, 2);
......@@ -7120,9 +7143,13 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
ASSERT(old_value.is_valid());
__ mov(old_value.reg(), new_value.reg());
// The return value for postfix operations is the
// same as the input, and has the same number info.
old_value.set_type_info(new_value.type_info());
// The return value for postfix operations is ToNumber(input).
// Keep more precise type info if the input is some kind of
// number already. If the input is not a number we have to wait
// for the deferred code to convert it.
if (new_value.type_info().IsNumber()) {
old_value.set_type_info(new_value.type_info());
}
}
// Ensure the new value is writable.
......@@ -7156,10 +7183,12 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
if (is_postfix) {
deferred = new DeferredPostfixCountOperation(new_value.reg(),
old_value.reg(),
is_increment);
is_increment,
new_value.type_info());
} else {
deferred = new DeferredPrefixCountOperation(new_value.reg(),
is_increment);
is_increment,
new_value.type_info());
}
if (new_value.is_smi()) {
......@@ -7186,6 +7215,13 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
}
deferred->BindExit();
// Postfix count operations return their input converted to
// number. The case when the input is already a number is covered
// above in the allocation code for old_value.
if (is_postfix && !new_value.type_info().IsNumber()) {
old_value.set_type_info(TypeInfo::Number());
}
// The result of ++ or -- is an Integer32 if the
// input is a smi. Otherwise it is a number.
if (new_value.is_smi()) {
......
......@@ -41,6 +41,8 @@ TypeInfo TypeInfo::TypeFromValue(Handle<Object> value) {
info = TypeInfo::IsInt32Double(HeapNumber::cast(*value)->value())
? TypeInfo::Integer32()
: TypeInfo::Double();
} else if (value->IsString()) {
info = TypeInfo::String();
} else {
info = TypeInfo::Unknown();
}
......
......@@ -156,6 +156,11 @@ class TypeInfo {
return ((type_ & kDoubleType) == kDoubleType);
}
inline bool IsString() {
ASSERT(type_ != kUninitializedType);
return ((type_ & kStringType) == kStringType);
}
inline bool IsUninitialized() {
return type_ == kUninitializedType;
}
......
......@@ -3129,14 +3129,16 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
}
// The value in dst was optimistically incremented or decremented. The
// result overflowed or was not smi tagged. Undo the operation, call
// into the runtime to convert the argument to a number, and call the
// specialized add or subtract stub. The result is left in dst.
// The value in dst was optimistically incremented or decremented.
// The result overflowed or was not smi tagged. Call into the runtime
// to convert the argument to a number, and call the specialized add
// or subtract stub. The result is left in dst.
class DeferredPrefixCountOperation: public DeferredCode {
public:
DeferredPrefixCountOperation(Register dst, bool is_increment)
: dst_(dst), is_increment_(is_increment) {
DeferredPrefixCountOperation(Register dst,
bool is_increment,
TypeInfo input_type)
: dst_(dst), is_increment_(is_increment), input_type_(input_type) {
set_comment("[ DeferredCountOperation");
}
......@@ -3145,13 +3147,16 @@ class DeferredPrefixCountOperation: public DeferredCode {
private:
Register dst_;
bool is_increment_;
TypeInfo input_type_;
};
void DeferredPrefixCountOperation::Generate() {
__ push(dst_);
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
__ push(rax);
if (!input_type_.IsNumber()) {
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
__ push(rax);
}
__ Push(Smi::FromInt(1));
if (is_increment_) {
__ CallRuntime(Runtime::kNumberAdd, 2);
......@@ -3162,15 +3167,21 @@ void DeferredPrefixCountOperation::Generate() {
}
// The value in dst was optimistically incremented or decremented. The
// result overflowed or was not smi tagged. Undo the operation and call
// into the runtime to convert the argument to a number. Update the
// original value in old. Call the specialized add or subtract stub.
// The result is left in dst.
// The value in dst was optimistically incremented or decremented.
// The result overflowed or was not smi tagged. Call into the runtime
// to convert the argument to a number. Update the original value in
// old. Call the specialized add or subtract stub. The result is
// left in dst.
class DeferredPostfixCountOperation: public DeferredCode {
public:
DeferredPostfixCountOperation(Register dst, Register old, bool is_increment)
: dst_(dst), old_(old), is_increment_(is_increment) {
DeferredPostfixCountOperation(Register dst,
Register old,
bool is_increment,
TypeInfo input_type)
: dst_(dst),
old_(old),
is_increment_(is_increment),
input_type_(input_type) {
set_comment("[ DeferredCountOperation");
}
......@@ -3180,18 +3191,22 @@ class DeferredPostfixCountOperation: public DeferredCode {
Register dst_;
Register old_;
bool is_increment_;
TypeInfo input_type_;
};
void DeferredPostfixCountOperation::Generate() {
__ push(dst_);
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
// Save the result of ToNumber to use as the old value.
__ push(rax);
if (input_type_.IsNumber()) {
__ push(dst_); // Save the input to use as the old value.
__ push(dst_);
} else {
__ push(dst_);
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
__ push(rax); // Save the result of ToNumber to use as the old value.
__ push(rax);
}
// Call the runtime for the addition or subtraction.
__ push(rax);
__ Push(Smi::FromInt(1));
if (is_increment_) {
__ CallRuntime(Runtime::kNumberAdd, 2);
......@@ -3238,6 +3253,14 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
old_value = allocator_->Allocate();
ASSERT(old_value.is_valid());
__ movq(old_value.reg(), new_value.reg());
// The return value for postfix operations is ToNumber(input).
// Keep more precise type info if the input is some kind of
// number already. If the input is not a number we have to wait
// for the deferred code to convert it.
if (new_value.type_info().IsNumber()) {
old_value.set_type_info(new_value.type_info());
}
}
// Ensure the new value is writable.
frame_->Spill(new_value.reg());
......@@ -3246,10 +3269,12 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
if (is_postfix) {
deferred = new DeferredPostfixCountOperation(new_value.reg(),
old_value.reg(),
is_increment);
is_increment,
new_value.type_info());
} else {
deferred = new DeferredPrefixCountOperation(new_value.reg(),
is_increment);
is_increment,
new_value.type_info());
}
__ JumpIfNotSmi(new_value.reg(), deferred->entry_label());
......@@ -3267,6 +3292,15 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
__ movq(new_value.reg(), kScratchRegister);
deferred->BindExit();
// Postfix count operations return their input converted to
// number. The case when the input is already a number is covered
// above in the allocation code for old_value.
if (is_postfix && !new_value.type_info().IsNumber()) {
old_value.set_type_info(TypeInfo::Number());
}
new_value.set_type_info(TypeInfo::Number());
// Postfix: store the old value in the allocated slot under the
// reference.
if (is_postfix) frame_->SetElementAt(target.size(), &old_value);
......@@ -5254,8 +5288,13 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
Result left = frame_->Pop();
if (op == Token::ADD) {
bool left_is_string = left.is_constant() && left.handle()->IsString();
bool right_is_string = right.is_constant() && right.handle()->IsString();
const bool left_is_string = left.type_info().IsString();
const bool right_is_string = right.type_info().IsString();
// Make sure constant strings have string type info.
ASSERT(!(left.is_constant() && left.handle()->IsString()) ||
left_is_string);
ASSERT(!(right.is_constant() && right.handle()->IsString()) ||
right_is_string);
if (left_is_string || right_is_string) {
frame_->Push(&left);
frame_->Push(&right);
......@@ -5264,7 +5303,8 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
if (right_is_string) {
// TODO(lrn): if both are constant strings
// -- do a compile time cons, if allocation during codegen is allowed.
answer = frame_->CallRuntime(Runtime::kStringAdd, 2);
StringAddStub stub(NO_STRING_CHECK_IN_STUB);
answer = frame_->CallStub(&stub, 2);
} else {
answer =
frame_->InvokeBuiltin(Builtins::STRING_ADD_LEFT, CALL_FUNCTION, 2);
......@@ -5273,6 +5313,7 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
answer =
frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION, 2);
}
answer.set_type_info(TypeInfo::String());
frame_->Push(&answer);
return;
}
......@@ -5358,10 +5399,13 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
: TypeInfo::Number();
break;
case Token::ADD:
// Result could be a string or a number. Check types of inputs.
result_type = operands_type.IsNumber()
? TypeInfo::Number()
: TypeInfo::Unknown();
if (operands_type.IsNumber()) {
result_type = TypeInfo::Number();
} else if (operands_type.IsString()) {
result_type = TypeInfo::String();
} else {
result_type = TypeInfo::Unknown();
}
break;
case Token::SUB:
case Token::MUL:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment