Revision: 7160
Author: [email protected]
Date: Mon Mar 14 08:36:00 2011
Log: Crankshaft support for StringCharFromCode.
This allows more efficient implementations of string keyed access,
String.prototype.chatAt, and String.fromCharCode.
Review URL: http://codereview.chromium.org/6682025
http://code.google.com/p/v8/source/detail?r=7160
Modified:
/branches/bleeding_edge/src/arm/lithium-arm.cc
/branches/bleeding_edge/src/arm/lithium-arm.h
/branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
/branches/bleeding_edge/src/arm/lithium-codegen-arm.h
/branches/bleeding_edge/src/ast.cc
/branches/bleeding_edge/src/ast.h
/branches/bleeding_edge/src/hydrogen-instructions.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h
/branches/bleeding_edge/src/ia32/lithium-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-ia32.h
/branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
/branches/bleeding_edge/src/x64/lithium-codegen-x64.h
/branches/bleeding_edge/src/x64/lithium-x64.cc
/branches/bleeding_edge/src/x64/lithium-x64.h
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc Mon Mar 14 07:42:14 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc Mon Mar 14 08:36:00 2011
@@ -1902,6 +1902,13 @@
LStringCharCodeAt* result = new LStringCharCodeAt(string, index);
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
}
+
+
+LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode*
instr) {
+ LOperand* char_code = UseRegister(instr->value());
+ LStringCharFromCode* result = new LStringCharFromCode(char_code);
+ return AssignPointerMap(DefineAsRegister(result));
+}
LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.h Wed Mar 9 07:01:16 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.h Mon Mar 14 08:36:00 2011
@@ -149,6 +149,7 @@
V(StoreNamedGeneric) \
V(StorePixelArrayElement) \
V(StringCharCodeAt) \
+ V(StringCharFromCode) \
V(StringLength) \
V(SubI) \
V(TaggedToI) \
@@ -1635,6 +1636,19 @@
};
+class LStringCharFromCode: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LStringCharFromCode(LOperand* char_code) {
+ inputs_[0] = char_code;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string-char-from-code")
+ DECLARE_HYDROGEN_ACCESSOR(StringCharFromCode)
+
+ LOperand* char_code() { return inputs_[0]; }
+};
+
+
class LStringLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LStringLength(LOperand* string) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Mar 14
07:42:14 2011
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Mar 14
08:36:00 2011
@@ -3121,6 +3121,56 @@
__ StoreToSafepointRegisterSlot(r0, result);
__ PopSafepointRegisters();
}
+
+
+void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
+ class DeferredStringCharFromCode: public LDeferredCode {
+ public:
+ DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode*
instr)
+ : LDeferredCode(codegen), instr_(instr) { }
+ virtual void Generate() {
codegen()->DoDeferredStringCharFromCode(instr_); }
+ private:
+ LStringCharFromCode* instr_;
+ };
+
+ DeferredStringCharFromCode* deferred =
+ new DeferredStringCharFromCode(this, instr);
+
+ ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
+ Register char_code = ToRegister(instr->char_code());
+ Register result = ToRegister(instr->result());
+ ASSERT(!char_code.is(result));
+
+ __ cmp(char_code, Operand(String::kMaxAsciiCharCode));
+ __ b(hi, deferred->entry());
+ __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
+ __ add(result, result, Operand(char_code, LSL, kPointerSizeLog2));
+ __ ldr(result, FieldMemOperand(result, FixedArray::kHeaderSize));
+ __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+ __ cmp(result, ip);
+ __ b(eq, deferred->entry());
+ __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
+ Register char_code = ToRegister(instr->char_code());
+ Register result = ToRegister(instr->result());
+
+ // TODO(3095996): Get rid of this. For now, we need to make the
+ // result register contain a valid pointer because it is already
+ // contained in the register pointer map.
+ __ mov(result, Operand(0));
+
+ __ PushSafepointRegisters();
+ __ SmiTag(char_code);
+ __ push(char_code);
+ __ CallRuntimeSaveDoubles(Runtime::kCharFromCode);
+ RecordSafepointWithRegisters(
+ instr->pointer_map(), 1, Safepoint::kNoDeoptimizationIndex);
+ __ StoreToSafepointRegisterSlot(r0, result);
+ __ PopSafepointRegisters();
+}
void LCodeGen::DoStringLength(LStringLength* instr) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.h Thu Mar 10
05:58:20 2011
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.h Mon Mar 14
08:36:00 2011
@@ -105,6 +105,7 @@
void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
void DoDeferredStackCheck(LGoto* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
+ void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check);
=======================================
--- /branches/bleeding_edge/src/ast.cc Wed Mar 9 07:01:16 2011
+++ /branches/bleeding_edge/src/ast.cc Mon Mar 14 08:36:00 2011
@@ -540,6 +540,8 @@
ZoneMapList* types = oracle->LoadReceiverTypes(this, name);
receiver_types_ = types;
}
+ } else if (oracle->LoadIsBuiltin(this, Builtins::KeyedLoadIC_String)) {
+ is_string_access_ = true;
} else if (is_monomorphic_) {
monomorphic_receiver_type_ = oracle->LoadMonomorphicReceiverType(this);
if (monomorphic_receiver_type_->has_external_array_elements()) {
=======================================
--- /branches/bleeding_edge/src/ast.h Wed Mar 9 07:01:16 2011
+++ /branches/bleeding_edge/src/ast.h Mon Mar 14 08:36:00 2011
@@ -1214,6 +1214,7 @@
is_monomorphic_(false),
is_array_length_(false),
is_string_length_(false),
+ is_string_access_(false),
is_function_prototype_(false),
is_arguments_access_(false) { }
@@ -1228,6 +1229,7 @@
bool is_synthetic() const { return type_ == SYNTHETIC; }
bool IsStringLength() const { return is_string_length_; }
+ bool IsStringAccess() const { return is_string_access_; }
bool IsFunctionPrototype() const { return is_function_prototype_; }
// Marks that this is actually an argument rewritten to a keyed property
@@ -1265,6 +1267,7 @@
bool is_monomorphic_ : 1;
bool is_array_length_ : 1;
bool is_string_length_ : 1;
+ bool is_string_access_ : 1;
bool is_function_prototype_ : 1;
bool is_arguments_access_ : 1;
Handle<Map> monomorphic_receiver_type_;
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Mon Mar 14 07:42:14
2011
+++ /branches/bleeding_edge/src/hydrogen-instructions.h Mon Mar 14 08:36:00
2011
@@ -151,6 +151,7 @@
V(StoreNamedField) \
V(StoreNamedGeneric) \
V(StringCharCodeAt) \
+ V(StringCharFromCode) \
V(StringLength) \
V(Sub) \
V(Test) \
@@ -3268,6 +3269,23 @@
};
+class HStringCharFromCode: public HUnaryOperation {
+ public:
+ explicit HStringCharFromCode(HValue* char_code) :
HUnaryOperation(char_code) {
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) const {
+ return Representation::Integer32();
+ }
+
+ virtual bool DataEquals(HValue* other) { return true; }
+
+ DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string_char_from_code")
+};
+
+
class HStringLength: public HUnaryOperation {
public:
explicit HStringLength(HValue* string) : HUnaryOperation(string) {
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Fri Mar 11 05:25:01 2011
+++ /branches/bleeding_edge/src/hydrogen.cc Mon Mar 14 08:36:00 2011
@@ -3703,6 +3703,13 @@
FIRST_STRING_TYPE,
LAST_STRING_TYPE));
instr = new HStringLength(string);
+ } else if (expr->IsStringAccess()) {
+ VISIT_FOR_VALUE(expr->key());
+ HValue* index = Pop();
+ HValue* string = Pop();
+ HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index);
+ AddInstruction(char_code);
+ instr = new HStringCharFromCode(char_code);
} else if (expr->IsFunctionPrototype()) {
HValue* function = Pop();
@@ -4083,6 +4090,7 @@
int argument_count = expr->arguments()->length() + 1; // Plus receiver.
switch (id) {
case kStringCharCodeAt:
+ case kStringCharAt:
if (argument_count == 2 && check_type == STRING_CHECK) {
HValue* index = Pop();
HValue* string = Pop();
@@ -4090,7 +4098,13 @@
AddInstruction(new HCheckPrototypeMaps(
oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK),
expr->holder()));
- HStringCharCodeAt* result = BuildStringCharCodeAt(string, index);
+ HStringCharCodeAt* char_code = BuildStringCharCodeAt(string,
index);
+ if (id == kStringCharCodeAt) {
+ ast_context()->ReturnInstruction(char_code, expr->id());
+ return true;
+ }
+ AddInstruction(char_code);
+ HStringCharFromCode* result = new HStringCharFromCode(char_code);
ast_context()->ReturnInstruction(result, expr->id());
return true;
}
@@ -5178,19 +5192,24 @@
// Fast support for string.charAt(n) and string[n].
void HGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) {
- BAILOUT("inlined runtime function: StringCharFromCode");
+ ASSERT(call->arguments()->length() == 1);
+ VISIT_FOR_VALUE(call->arguments()->at(0));
+ HValue* char_code = Pop();
+ HStringCharFromCode* result = new HStringCharFromCode(char_code);
+ ast_context()->ReturnInstruction(result, call->id());
}
// Fast support for string.charAt(n) and string[n].
void HGraphBuilder::GenerateStringCharAt(CallRuntime* call) {
- ASSERT_EQ(2, call->arguments()->length());
- VisitArgumentList(call->arguments());
- CHECK_BAILOUT;
- HContext* context = new HContext;
- AddInstruction(context);
- HCallStub* result = new HCallStub(context, CodeStub::StringCharAt, 2);
- Drop(2);
+ ASSERT(call->arguments()->length() == 2);
+ VISIT_FOR_VALUE(call->arguments()->at(0));
+ VISIT_FOR_VALUE(call->arguments()->at(1));
+ HValue* index = Pop();
+ HValue* string = Pop();
+ HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index);
+ AddInstruction(char_code);
+ HStringCharFromCode* result = new HStringCharFromCode(char_code);
ast_context()->ReturnInstruction(result, call->id());
}
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Mon Mar 14
07:42:14 2011
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Mon Mar 14
08:36:00 2011
@@ -3028,6 +3028,56 @@
__ StoreToSafepointRegisterSlot(result, eax);
__ PopSafepointRegisters();
}
+
+
+void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
+ class DeferredStringCharFromCode: public LDeferredCode {
+ public:
+ DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode*
instr)
+ : LDeferredCode(codegen), instr_(instr) { }
+ virtual void Generate() {
codegen()->DoDeferredStringCharFromCode(instr_); }
+ private:
+ LStringCharFromCode* instr_;
+ };
+
+ DeferredStringCharFromCode* deferred =
+ new DeferredStringCharFromCode(this, instr);
+
+ ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
+ Register char_code = ToRegister(instr->char_code());
+ Register result = ToRegister(instr->result());
+ ASSERT(!char_code.is(result));
+
+ __ cmp(char_code, String::kMaxAsciiCharCode);
+ __ j(above, deferred->entry());
+ __ Set(result, Immediate(Factory::single_character_string_cache()));
+ __ mov(result, FieldOperand(result,
+ char_code, times_pointer_size,
+ FixedArray::kHeaderSize));
+ __ cmp(result, Factory::undefined_value());
+ __ j(equal, deferred->entry());
+ __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
+ Register char_code = ToRegister(instr->char_code());
+ Register result = ToRegister(instr->result());
+
+ // TODO(3095996): Get rid of this. For now, we need to make the
+ // result register contain a valid pointer because it is already
+ // contained in the register pointer map.
+ __ Set(result, Immediate(0));
+
+ __ PushSafepointRegisters();
+ __ SmiTag(char_code);
+ __ push(char_code);
+ __ CallRuntimeSaveDoubles(Runtime::kCharFromCode);
+ RecordSafepointWithRegisters(
+ instr->pointer_map(), 1, Safepoint::kNoDeoptimizationIndex);
+ __ StoreToSafepointRegisterSlot(result, eax);
+ __ PopSafepointRegisters();
+}
void LCodeGen::DoStringLength(LStringLength* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h Mon Mar 7
03:52:36 2011
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h Mon Mar 14
08:36:00 2011
@@ -95,6 +95,7 @@
void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
void DoDeferredStackCheck(LGoto* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
+ void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check);
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Mon Mar 14 07:42:14
2011
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Mon Mar 14 08:36:00
2011
@@ -1941,6 +1941,13 @@
LStringCharCodeAt* result = new LStringCharCodeAt(string, index);
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
}
+
+
+LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode*
instr) {
+ LOperand* char_code = UseRegister(instr->value());
+ LStringCharFromCode* result = new LStringCharFromCode(char_code);
+ return AssignPointerMap(DefineAsRegister(result));
+}
LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.h Wed Mar 9 07:01:16 2011
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.h Mon Mar 14 08:36:00 2011
@@ -151,6 +151,7 @@
V(StoreNamedGeneric) \
V(StorePixelArrayElement) \
V(StringCharCodeAt) \
+ V(StringCharFromCode) \
V(StringLength) \
V(SubI) \
V(TaggedToI) \
@@ -1715,6 +1716,19 @@
};
+class LStringCharFromCode: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LStringCharFromCode(LOperand* char_code) {
+ inputs_[0] = char_code;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string-char-from-code")
+ DECLARE_HYDROGEN_ACCESSOR(StringCharFromCode)
+
+ LOperand* char_code() { return inputs_[0]; }
+};
+
+
class LStringLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LStringLength(LOperand* string) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Mon Mar 14
08:09:50 2011
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Mon Mar 14
08:36:00 2011
@@ -3000,6 +3000,56 @@
__ StoreToSafepointRegisterSlot(result, rax);
__ PopSafepointRegisters();
}
+
+
+void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
+ class DeferredStringCharFromCode: public LDeferredCode {
+ public:
+ DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode*
instr)
+ : LDeferredCode(codegen), instr_(instr) { }
+ virtual void Generate() {
codegen()->DoDeferredStringCharFromCode(instr_); }
+ private:
+ LStringCharFromCode* instr_;
+ };
+
+ DeferredStringCharFromCode* deferred =
+ new DeferredStringCharFromCode(this, instr);
+
+ ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
+ Register char_code = ToRegister(instr->char_code());
+ Register result = ToRegister(instr->result());
+ ASSERT(!char_code.is(result));
+
+ __ cmpl(char_code, Immediate(String::kMaxAsciiCharCode));
+ __ j(above, deferred->entry());
+ __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
+ __ movq(result, FieldOperand(result,
+ char_code, times_pointer_size,
+ FixedArray::kHeaderSize));
+ __ CompareRoot(result, Heap::kUndefinedValueRootIndex);
+ __ j(equal, deferred->entry());
+ __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
+ Register char_code = ToRegister(instr->char_code());
+ Register result = ToRegister(instr->result());
+
+ // TODO(3095996): Get rid of this. For now, we need to make the
+ // result register contain a valid pointer because it is already
+ // contained in the register pointer map.
+ __ Set(result, 0);
+
+ __ PushSafepointRegisters();
+ __ Integer32ToSmi(char_code, char_code);
+ __ push(char_code);
+ __ CallRuntimeSaveDoubles(Runtime::kCharFromCode);
+ RecordSafepointWithRegisters(
+ instr->pointer_map(), 1, Safepoint::kNoDeoptimizationIndex);
+ __ StoreToSafepointRegisterSlot(result, rax);
+ __ PopSafepointRegisters();
+}
void LCodeGen::DoStringLength(LStringLength* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Wed Mar 9
07:57:47 2011
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Mon Mar 14
08:36:00 2011
@@ -92,6 +92,7 @@
void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
void DoDeferredStackCheck(LGoto* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
+ void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check);
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc Mon Mar 14 08:09:50 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc Mon Mar 14 08:36:00 2011
@@ -1903,6 +1903,13 @@
LStringCharCodeAt* result = new LStringCharCodeAt(string, index);
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
}
+
+
+LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode*
instr) {
+ LOperand* char_code = UseRegister(instr->value());
+ LStringCharFromCode* result = new LStringCharFromCode(char_code);
+ return AssignPointerMap(DefineAsRegister(result));
+}
LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.h Wed Mar 9 07:57:47 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.h Mon Mar 14 08:36:00 2011
@@ -149,6 +149,7 @@
V(StoreNamedGeneric) \
V(StorePixelArrayElement) \
V(StringCharCodeAt) \
+ V(StringCharFromCode) \
V(StringLength) \
V(SubI) \
V(TaggedToI) \
@@ -1631,6 +1632,19 @@
};
+class LStringCharFromCode: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LStringCharFromCode(LOperand* char_code) {
+ inputs_[0] = char_code;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string-char-from-code")
+ DECLARE_HYDROGEN_ACCESSOR(StringCharFromCode)
+
+ LOperand* char_code() { return inputs_[0]; }
+};
+
+
class LStringLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LStringLength(LOperand* string) {
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev