Implemented one-char cache lookup in generated code.
This speeds up string,charAt(n) and string[n]. Review URL: http://codereview.chromium.org/660184 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3980 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
0c77912aaf
commit
dd7b55eb9f
@ -3414,6 +3414,44 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) {
|
||||||
|
Comment(masm_, "[ GenerateCharFromCode");
|
||||||
|
ASSERT(args->length() == 1);
|
||||||
|
|
||||||
|
LoadAndSpill(args->at(0));
|
||||||
|
frame_->EmitPop(r0);
|
||||||
|
|
||||||
|
JumpTarget slow_case;
|
||||||
|
JumpTarget exit;
|
||||||
|
|
||||||
|
// Fast case of Heap::LookupSingleCharacterStringFromCode.
|
||||||
|
ASSERT(kSmiTag == 0);
|
||||||
|
ASSERT(kSmiShiftSize == 0);
|
||||||
|
ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1));
|
||||||
|
__ tst(r0, Operand(kSmiTagMask |
|
||||||
|
((~String::kMaxAsciiCharCode) << kSmiTagSize)));
|
||||||
|
slow_case.Branch(nz);
|
||||||
|
|
||||||
|
ASSERT(kSmiTag == 0);
|
||||||
|
__ mov(r1, Operand(Factory::single_character_string_cache()));
|
||||||
|
__ add(r1, r1, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
|
||||||
|
__ ldr(r1, MemOperand(r1, FixedArray::kHeaderSize - kHeapObjectTag));
|
||||||
|
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
||||||
|
__ cmp(r1, ip);
|
||||||
|
slow_case.Branch(eq);
|
||||||
|
|
||||||
|
frame_->EmitPush(r1);
|
||||||
|
exit.Jump();
|
||||||
|
|
||||||
|
slow_case.Bind();
|
||||||
|
frame_->EmitPush(r0);
|
||||||
|
frame_->CallRuntime(Runtime::kCharFromCode, 1);
|
||||||
|
frame_->EmitPush(r0);
|
||||||
|
|
||||||
|
exit.Bind();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
|
void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
|
||||||
VirtualFrame::SpilledScope spilled_scope;
|
VirtualFrame::SpilledScope spilled_scope;
|
||||||
ASSERT(args->length() == 1);
|
ASSERT(args->length() == 1);
|
||||||
|
@ -370,6 +370,9 @@ class CodeGenerator: public AstVisitor {
|
|||||||
// Fast support for charCodeAt(n).
|
// Fast support for charCodeAt(n).
|
||||||
void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
|
void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
|
||||||
|
|
||||||
|
// Fast support for string.charAt(n) and string[n].
|
||||||
|
void GenerateCharFromCode(ZoneList<Expression*>* args);
|
||||||
|
|
||||||
// Fast support for object equality testing.
|
// Fast support for object equality testing.
|
||||||
void GenerateObjectEquals(ZoneList<Expression*>* args);
|
void GenerateObjectEquals(ZoneList<Expression*>* args);
|
||||||
|
|
||||||
|
@ -369,6 +369,7 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
|
|||||||
{&CodeGenerator::GenerateValueOf, "_ValueOf"},
|
{&CodeGenerator::GenerateValueOf, "_ValueOf"},
|
||||||
{&CodeGenerator::GenerateSetValueOf, "_SetValueOf"},
|
{&CodeGenerator::GenerateSetValueOf, "_SetValueOf"},
|
||||||
{&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"},
|
{&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"},
|
||||||
|
{&CodeGenerator::GenerateCharFromCode, "_CharFromCode"},
|
||||||
{&CodeGenerator::GenerateObjectEquals, "_ObjectEquals"},
|
{&CodeGenerator::GenerateObjectEquals, "_ObjectEquals"},
|
||||||
{&CodeGenerator::GenerateLog, "_Log"},
|
{&CodeGenerator::GenerateLog, "_Log"},
|
||||||
{&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"},
|
{&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"},
|
||||||
|
@ -1655,7 +1655,7 @@ bool Heap::CreateInitialObjects() {
|
|||||||
if (InitializeNumberStringCache()->IsFailure()) return false;
|
if (InitializeNumberStringCache()->IsFailure()) return false;
|
||||||
|
|
||||||
// Allocate cache for single character strings.
|
// Allocate cache for single character strings.
|
||||||
obj = AllocateFixedArray(String::kMaxAsciiCharCode+1);
|
obj = AllocateFixedArray(String::kMaxAsciiCharCode+1, TENURED);
|
||||||
if (obj->IsFailure()) return false;
|
if (obj->IsFailure()) return false;
|
||||||
set_single_character_string_cache(FixedArray::cast(obj));
|
set_single_character_string_cache(FixedArray::cast(obj));
|
||||||
|
|
||||||
|
@ -5597,6 +5597,54 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) {
|
||||||
|
Comment(masm_, "[ GenerateCharFromCode");
|
||||||
|
ASSERT(args->length() == 1);
|
||||||
|
|
||||||
|
Load(args->at(0));
|
||||||
|
Result code = frame_->Pop();
|
||||||
|
code.ToRegister();
|
||||||
|
ASSERT(code.is_valid());
|
||||||
|
|
||||||
|
Result temp = allocator()->Allocate();
|
||||||
|
ASSERT(temp.is_valid());
|
||||||
|
|
||||||
|
JumpTarget slow_case;
|
||||||
|
JumpTarget exit;
|
||||||
|
|
||||||
|
// Fast case of Heap::LookupSingleCharacterStringFromCode.
|
||||||
|
ASSERT(kSmiTag == 0);
|
||||||
|
ASSERT(kSmiShiftSize == 0);
|
||||||
|
ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1));
|
||||||
|
__ test(code.reg(),
|
||||||
|
Immediate(kSmiTagMask |
|
||||||
|
((~String::kMaxAsciiCharCode) << kSmiTagSize)));
|
||||||
|
slow_case.Branch(not_zero, &code, not_taken);
|
||||||
|
|
||||||
|
__ Set(temp.reg(), Immediate(Factory::single_character_string_cache()));
|
||||||
|
ASSERT(kSmiTag == 0);
|
||||||
|
ASSERT(kSmiTagSize == 1);
|
||||||
|
ASSERT(kSmiShiftSize == 0);
|
||||||
|
// At this point code register contains smi tagged ascii char code.
|
||||||
|
__ mov(temp.reg(), FieldOperand(temp.reg(),
|
||||||
|
code.reg(), times_half_pointer_size,
|
||||||
|
FixedArray::kHeaderSize));
|
||||||
|
__ cmp(temp.reg(), Factory::undefined_value());
|
||||||
|
slow_case.Branch(equal, &code, not_taken);
|
||||||
|
code.Unuse();
|
||||||
|
|
||||||
|
frame_->Push(&temp);
|
||||||
|
exit.Jump();
|
||||||
|
|
||||||
|
slow_case.Bind(&code);
|
||||||
|
frame_->Push(&code);
|
||||||
|
Result result = frame_->CallRuntime(Runtime::kCharFromCode, 1);
|
||||||
|
frame_->Push(&result);
|
||||||
|
|
||||||
|
exit.Bind();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
|
void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
|
||||||
ASSERT(args->length() == 1);
|
ASSERT(args->length() == 1);
|
||||||
Load(args->at(0));
|
Load(args->at(0));
|
||||||
|
@ -563,6 +563,9 @@ class CodeGenerator: public AstVisitor {
|
|||||||
// Fast support for charCodeAt(n).
|
// Fast support for charCodeAt(n).
|
||||||
void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
|
void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
|
||||||
|
|
||||||
|
// Fast support for string.charAt(n) and string[n].
|
||||||
|
void GenerateCharFromCode(ZoneList<Expression*>* args);
|
||||||
|
|
||||||
// Fast support for object equality testing.
|
// Fast support for object equality testing.
|
||||||
void GenerateObjectEquals(ZoneList<Expression*>* args);
|
void GenerateObjectEquals(ZoneList<Expression*>* args);
|
||||||
|
|
||||||
|
@ -305,6 +305,11 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) {
|
||||||
|
UNIMPLEMENTED_MIPS();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
|
void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
|
||||||
UNIMPLEMENTED_MIPS();
|
UNIMPLEMENTED_MIPS();
|
||||||
}
|
}
|
||||||
|
@ -227,6 +227,9 @@ class CodeGenerator: public AstVisitor {
|
|||||||
// Fast support for charCodeAt(n).
|
// Fast support for charCodeAt(n).
|
||||||
void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
|
void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
|
||||||
|
|
||||||
|
// Fast support for string.charAt(n) and string[n].
|
||||||
|
void GenerateCharFromCode(ZoneList<Expression*>* args);
|
||||||
|
|
||||||
// Fast support for object equality testing.
|
// Fast support for object equality testing.
|
||||||
void GenerateObjectEquals(ZoneList<Expression*>* args);
|
void GenerateObjectEquals(ZoneList<Expression*>* args);
|
||||||
|
|
||||||
|
@ -478,7 +478,7 @@ function STRING_CHAR_AT(pos) {
|
|||||||
if (!%_IsSmi(char_code)) {
|
if (!%_IsSmi(char_code)) {
|
||||||
return %StringCharAt(this, pos);
|
return %StringCharAt(this, pos);
|
||||||
}
|
}
|
||||||
return %CharFromCode(char_code);
|
return %_CharFromCode(char_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ function StringCharAt(pos) {
|
|||||||
if (index >= subject.length || index < 0) return "";
|
if (index >= subject.length || index < 0) return "";
|
||||||
char_code = %StringCharCodeAt(subject, index);
|
char_code = %StringCharCodeAt(subject, index);
|
||||||
}
|
}
|
||||||
return %CharFromCode(char_code);
|
return %_CharFromCode(char_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -184,7 +184,7 @@ function SubString(string, start, end) {
|
|||||||
if (!%_IsSmi(char_code)) {
|
if (!%_IsSmi(char_code)) {
|
||||||
char_code = %StringCharCodeAt(string, start);
|
char_code = %StringCharCodeAt(string, start);
|
||||||
}
|
}
|
||||||
return %CharFromCode(char_code);
|
return %_CharFromCode(char_code);
|
||||||
}
|
}
|
||||||
return %_SubString(string, start, end);
|
return %_SubString(string, start, end);
|
||||||
}
|
}
|
||||||
@ -726,7 +726,7 @@ function StringTrimRight() {
|
|||||||
// ECMA-262, section 15.5.3.2
|
// ECMA-262, section 15.5.3.2
|
||||||
function StringFromCharCode(code) {
|
function StringFromCharCode(code) {
|
||||||
var n = %_ArgumentsLength();
|
var n = %_ArgumentsLength();
|
||||||
if (n == 1) return %CharFromCode(ToNumber(code) & 0xffff)
|
if (n == 1) return %_CharFromCode(ToNumber(code) & 0xffff)
|
||||||
|
|
||||||
// NOTE: This is not super-efficient, but it is necessary because we
|
// NOTE: This is not super-efficient, but it is necessary because we
|
||||||
// want to avoid converting to numbers from within the virtual
|
// want to avoid converting to numbers from within the virtual
|
||||||
|
@ -3877,6 +3877,49 @@ void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) {
|
||||||
|
Comment(masm_, "[ GenerateCharFromCode");
|
||||||
|
ASSERT(args->length() == 1);
|
||||||
|
|
||||||
|
Load(args->at(0));
|
||||||
|
Result code = frame_->Pop();
|
||||||
|
code.ToRegister();
|
||||||
|
ASSERT(code.is_valid());
|
||||||
|
|
||||||
|
Result temp = allocator()->Allocate();
|
||||||
|
ASSERT(temp.is_valid());
|
||||||
|
|
||||||
|
JumpTarget slow_case;
|
||||||
|
JumpTarget exit;
|
||||||
|
|
||||||
|
// Fast case of Heap::LookupSingleCharacterStringFromCode.
|
||||||
|
Condition is_smi = __ CheckSmi(code.reg());
|
||||||
|
slow_case.Branch(NegateCondition(is_smi), &code, not_taken);
|
||||||
|
|
||||||
|
__ SmiToInteger32(kScratchRegister, code.reg());
|
||||||
|
__ cmpl(kScratchRegister, Immediate(String::kMaxAsciiCharCode));
|
||||||
|
slow_case.Branch(above, &code, not_taken);
|
||||||
|
|
||||||
|
__ Move(temp.reg(), Factory::single_character_string_cache());
|
||||||
|
__ movq(temp.reg(), FieldOperand(temp.reg(),
|
||||||
|
kScratchRegister, times_pointer_size,
|
||||||
|
FixedArray::kHeaderSize));
|
||||||
|
__ CompareRoot(temp.reg(), Heap::kUndefinedValueRootIndex);
|
||||||
|
slow_case.Branch(equal, &code, not_taken);
|
||||||
|
code.Unuse();
|
||||||
|
|
||||||
|
frame_->Push(&temp);
|
||||||
|
exit.Jump();
|
||||||
|
|
||||||
|
slow_case.Bind(&code);
|
||||||
|
frame_->Push(&code);
|
||||||
|
Result result = frame_->CallRuntime(Runtime::kCharFromCode, 1);
|
||||||
|
frame_->Push(&result);
|
||||||
|
|
||||||
|
exit.Bind();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
|
void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
|
||||||
ASSERT(args->length() == 1);
|
ASSERT(args->length() == 1);
|
||||||
Load(args->at(0));
|
Load(args->at(0));
|
||||||
|
@ -547,6 +547,9 @@ class CodeGenerator: public AstVisitor {
|
|||||||
// Fast support for charCodeAt(n).
|
// Fast support for charCodeAt(n).
|
||||||
void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
|
void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
|
||||||
|
|
||||||
|
// Fast support for string.charAt(n) and string[n].
|
||||||
|
void GenerateCharFromCode(ZoneList<Expression*>* args);
|
||||||
|
|
||||||
// Fast support for object equality testing.
|
// Fast support for object equality testing.
|
||||||
void GenerateObjectEquals(ZoneList<Expression*>* args);
|
void GenerateObjectEquals(ZoneList<Expression*>* args);
|
||||||
|
|
||||||
|
@ -51,3 +51,16 @@ assertEquals(116, s.charCodeAt(NaN));
|
|||||||
assertTrue(isNaN(s.charCodeAt(-1)));
|
assertTrue(isNaN(s.charCodeAt(-1)));
|
||||||
assertTrue(isNaN(s.charCodeAt(4)));
|
assertTrue(isNaN(s.charCodeAt(4)));
|
||||||
|
|
||||||
|
// Make sure enough of the one-char string cache is filled.
|
||||||
|
var alpha = ['@'];
|
||||||
|
for (var i = 1; i < 128; i++) {
|
||||||
|
var c = String.fromCharCode(i);
|
||||||
|
alpha[i] = c.charAt(0);
|
||||||
|
}
|
||||||
|
var alphaStr = alpha.join("");
|
||||||
|
|
||||||
|
// Now test chars.
|
||||||
|
for (var i = 1; i < 128; i++) {
|
||||||
|
assertEquals(alpha[i], alphaStr.charAt(i));
|
||||||
|
assertEquals(String.fromCharCode(i), alphaStr.charAt(i));
|
||||||
|
}
|
||||||
|
@ -152,3 +152,17 @@ assertEquals('o', S2);
|
|||||||
var s2 = (s[-2] = 't');
|
var s2 = (s[-2] = 't');
|
||||||
assertEquals('undefined', typeof(s[-2]));
|
assertEquals('undefined', typeof(s[-2]));
|
||||||
assertEquals('t', s2);
|
assertEquals('t', s2);
|
||||||
|
|
||||||
|
// Make sure enough of the one-char string cache is filled.
|
||||||
|
var alpha = ['@'];
|
||||||
|
for (var i = 1; i < 128; i++) {
|
||||||
|
var c = String.fromCharCode(i);
|
||||||
|
alpha[i] = c[0];
|
||||||
|
}
|
||||||
|
var alphaStr = alpha.join("");
|
||||||
|
|
||||||
|
// Now test chars.
|
||||||
|
for (var i = 1; i < 128; i++) {
|
||||||
|
assertEquals(alpha[i], alphaStr[i]);
|
||||||
|
assertEquals(String.fromCharCode(i), alphaStr[i]);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user