Revision: 3980
Author: [email protected]
Date: Fri Feb 26 12:14:20 2010
Log: Implemented one-char cache lookup in generated code.
This speeds up string,charAt(n) and string[n].
Review URL: http://codereview.chromium.org/660184
http://code.google.com/p/v8/source/detail?r=3980
Modified:
/branches/bleeding_edge/src/arm/codegen-arm.cc
/branches/bleeding_edge/src/arm/codegen-arm.h
/branches/bleeding_edge/src/codegen.cc
/branches/bleeding_edge/src/heap.cc
/branches/bleeding_edge/src/ia32/codegen-ia32.cc
/branches/bleeding_edge/src/ia32/codegen-ia32.h
/branches/bleeding_edge/src/mips/codegen-mips.cc
/branches/bleeding_edge/src/mips/codegen-mips.h
/branches/bleeding_edge/src/runtime.js
/branches/bleeding_edge/src/string.js
/branches/bleeding_edge/src/x64/codegen-x64.cc
/branches/bleeding_edge/src/x64/codegen-x64.h
/branches/bleeding_edge/test/mjsunit/string-charat.js
/branches/bleeding_edge/test/mjsunit/string-index.js
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc Fri Feb 26 02:24:58 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc Fri Feb 26 12:14:20 2010
@@ -3412,6 +3412,44 @@
__ bind(&end);
frame_->EmitPush(r0);
}
+
+
+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) {
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h Fri Feb 26 02:24:58 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.h Fri Feb 26 12:14:20 2010
@@ -370,6 +370,9 @@
// Fast support for charCodeAt(n).
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.
void GenerateObjectEquals(ZoneList<Expression*>* args);
=======================================
--- /branches/bleeding_edge/src/codegen.cc Fri Feb 26 02:24:58 2010
+++ /branches/bleeding_edge/src/codegen.cc Fri Feb 26 12:14:20 2010
@@ -369,6 +369,7 @@
{&CodeGenerator::GenerateValueOf, "_ValueOf"},
{&CodeGenerator::GenerateSetValueOf, "_SetValueOf"},
{&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"},
+ {&CodeGenerator::GenerateCharFromCode, "_CharFromCode"},
{&CodeGenerator::GenerateObjectEquals, "_ObjectEquals"},
{&CodeGenerator::GenerateLog, "_Log"},
{&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"},
=======================================
--- /branches/bleeding_edge/src/heap.cc Fri Feb 26 07:19:13 2010
+++ /branches/bleeding_edge/src/heap.cc Fri Feb 26 12:14:20 2010
@@ -1655,7 +1655,7 @@
if (InitializeNumberStringCache()->IsFailure()) return false;
// Allocate cache for single character strings.
- obj = AllocateFixedArray(String::kMaxAsciiCharCode+1);
+ obj = AllocateFixedArray(String::kMaxAsciiCharCode+1, TENURED);
if (obj->IsFailure()) return false;
set_single_character_string_cache(FixedArray::cast(obj));
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Fri Feb 26 04:28:25
2010
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Fri Feb 26 12:14:20
2010
@@ -5595,6 +5595,54 @@
__ bind(&end);
frame_->Push(&temp);
}
+
+
+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) {
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.h Fri Feb 26 02:24:58 2010
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.h Fri Feb 26 12:14:20 2010
@@ -563,6 +563,9 @@
// Fast support for charCodeAt(n).
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.
void GenerateObjectEquals(ZoneList<Expression*>* args);
=======================================
--- /branches/bleeding_edge/src/mips/codegen-mips.cc Fri Feb 26 02:24:58
2010
+++ /branches/bleeding_edge/src/mips/codegen-mips.cc Fri Feb 26 12:14:20
2010
@@ -303,6 +303,11 @@
void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
+
+
+void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) {
+ UNIMPLEMENTED_MIPS();
+}
void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
=======================================
--- /branches/bleeding_edge/src/mips/codegen-mips.h Fri Feb 26 02:24:58 2010
+++ /branches/bleeding_edge/src/mips/codegen-mips.h Fri Feb 26 12:14:20 2010
@@ -227,6 +227,9 @@
// Fast support for charCodeAt(n).
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.
void GenerateObjectEquals(ZoneList<Expression*>* args);
=======================================
--- /branches/bleeding_edge/src/runtime.js Fri Feb 19 05:07:37 2010
+++ /branches/bleeding_edge/src/runtime.js Fri Feb 26 12:14:20 2010
@@ -478,7 +478,7 @@
if (!%_IsSmi(char_code)) {
return %StringCharAt(this, pos);
}
- return %CharFromCode(char_code);
+ return %_CharFromCode(char_code);
}
=======================================
--- /branches/bleeding_edge/src/string.js Fri Feb 19 05:07:37 2010
+++ /branches/bleeding_edge/src/string.js Fri Feb 26 12:14:20 2010
@@ -69,7 +69,7 @@
if (index >= subject.length || index < 0) return "";
char_code = %StringCharCodeAt(subject, index);
}
- return %CharFromCode(char_code);
+ return %_CharFromCode(char_code);
}
@@ -184,7 +184,7 @@
if (!%_IsSmi(char_code)) {
char_code = %StringCharCodeAt(string, start);
}
- return %CharFromCode(char_code);
+ return %_CharFromCode(char_code);
}
return %_SubString(string, start, end);
}
@@ -726,7 +726,7 @@
// ECMA-262, section 15.5.3.2
function StringFromCharCode(code) {
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
// want to avoid converting to numbers from within the virtual
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc Fri Feb 26 02:24:58 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc Fri Feb 26 12:14:20 2010
@@ -3875,6 +3875,49 @@
__ bind(&end);
frame_->Push(&temp);
}
+
+
+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) {
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.h Fri Feb 26 02:24:58 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.h Fri Feb 26 12:14:20 2010
@@ -547,6 +547,9 @@
// Fast support for charCodeAt(n).
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.
void GenerateObjectEquals(ZoneList<Expression*>* args);
=======================================
--- /branches/bleeding_edge/test/mjsunit/string-charat.js Tue Sep 9
13:08:45 2008
+++ /branches/bleeding_edge/test/mjsunit/string-charat.js Fri Feb 26
12:14:20 2010
@@ -51,3 +51,16 @@
assertTrue(isNaN(s.charCodeAt(-1)));
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));
+}
=======================================
--- /branches/bleeding_edge/test/mjsunit/string-index.js Tue Sep 9
13:08:45 2008
+++ /branches/bleeding_edge/test/mjsunit/string-index.js Fri Feb 26
12:14:20 2010
@@ -152,3 +152,17 @@
var s2 = (s[-2] = 't');
assertEquals('undefined', typeof(s[-2]));
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]);
+}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev