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

Reply via email to