Bug 1655465 - Part 10: Support StringSplitString in CacheIR and Warp. r=jandem
☠☠ backed out by 801b59414882 ☠ ☠
authorAndré Bargull <andre.bargull@gmail.com>
Fri, 31 Jul 2020 14:09:44 +0000
changeset 542942 a5491d62d560707214291f1cef2f157a602f6a17
parent 542941 5ead4048955fa24b83dc4a6f407d1db9ebd886f2
child 542943 6567d54b63c8271853f9f33548f7d61f596a8314
push id37657
push usernerli@mozilla.com
push dateSat, 01 Aug 2020 09:48:10 +0000
treeherdermozilla-central@750bc4c5c4ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1655465
milestone81.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1655465 - Part 10: Support StringSplitString in CacheIR and Warp. r=jandem Drive-by change: - Make `intrinsic_StringSplitString` a static function. Differential Revision: https://phabricator.services.mozilla.com/D84989
js/src/jit/CacheIR.cpp
js/src/jit/CacheIR.h
js/src/jit/CacheIRCompiler.cpp
js/src/jit/CacheIROps.yaml
js/src/jit/MIR.h
js/src/jit/WarpCacheIRTranspiler.cpp
js/src/vm/SelfHosting.cpp
js/src/vm/SelfHosting.h
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -5933,16 +5933,49 @@ AttachDecision CallIRGenerator::tryAttac
   // No type monitoring because this always returns a string.
   writer.returnFromIC();
   cacheIRStubKind_ = BaselineCacheIRStubKind::Regular;
 
   trackAttached("StringReplaceString");
   return AttachDecision::Attach;
 }
 
+AttachDecision CallIRGenerator::tryAttachStringSplitString(
+    HandleFunction callee) {
+  // Self-hosted code calls this with (string, string) arguments.
+  MOZ_ASSERT(argc_ == 2);
+  MOZ_ASSERT(args_[0].isString());
+  MOZ_ASSERT(args_[1].isString());
+
+  ObjectGroup* group = ObjectGroupRealm::getStringSplitStringGroup(cx_);
+  if (!group) {
+    cx_->clearPendingException();
+    return AttachDecision::NoAction;
+  }
+
+  // Initialize the input operand.
+  Int32OperandId argcId(writer.setInputOperandId(0));
+
+  // Note: we don't need to call emitNativeCalleeGuard for intrinsics.
+
+  ValOperandId arg0Id = writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_);
+  StringOperandId strId = writer.guardToString(arg0Id);
+
+  ValOperandId arg1Id = writer.loadArgumentFixedSlot(ArgumentKind::Arg1, argc_);
+  StringOperandId separatorId = writer.guardToString(arg1Id);
+
+  writer.callStringSplitStringResult(strId, separatorId, group);
+
+  writer.typeMonitorResult();
+  cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored;
+
+  trackAttached("StringSplitString");
+  return AttachDecision::Attach;
+}
+
 AttachDecision CallIRGenerator::tryAttachStringChar(HandleFunction callee,
                                                     StringChar kind) {
   // Need one argument.
   if (argc_ != 1) {
     return AttachDecision::NoAction;
   }
 
   if (!CanAttachStringChar(thisval_, args_[0], kind)) {
@@ -7290,16 +7323,18 @@ AttachDecision CallIRGenerator::tryAttac
     case InlinableNative::StringFromCodePoint:
       return tryAttachStringFromCodePoint(callee);
     case InlinableNative::StringToLowerCase:
       return tryAttachStringToLowerCase(callee);
     case InlinableNative::StringToUpperCase:
       return tryAttachStringToUpperCase(callee);
     case InlinableNative::IntrinsicStringReplaceString:
       return tryAttachStringReplaceString(callee);
+    case InlinableNative::IntrinsicStringSplitString:
+      return tryAttachStringSplitString(callee);
 
     // Math natives.
     case InlinableNative::MathRandom:
       return tryAttachMathRandom(callee);
     case InlinableNative::MathAbs:
       return tryAttachMathAbs(callee);
     case InlinableNative::MathClz32:
       return tryAttachMathClz32(callee);
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -1623,16 +1623,17 @@ class MOZ_RAII CallIRGenerator : public 
   AttachDecision tryAttachStringChar(HandleFunction callee, StringChar kind);
   AttachDecision tryAttachStringCharCodeAt(HandleFunction callee);
   AttachDecision tryAttachStringCharAt(HandleFunction callee);
   AttachDecision tryAttachStringFromCharCode(HandleFunction callee);
   AttachDecision tryAttachStringFromCodePoint(HandleFunction callee);
   AttachDecision tryAttachStringToLowerCase(HandleFunction callee);
   AttachDecision tryAttachStringToUpperCase(HandleFunction callee);
   AttachDecision tryAttachStringReplaceString(HandleFunction callee);
+  AttachDecision tryAttachStringSplitString(HandleFunction callee);
   AttachDecision tryAttachMathRandom(HandleFunction callee);
   AttachDecision tryAttachMathAbs(HandleFunction callee);
   AttachDecision tryAttachMathClz32(HandleFunction callee);
   AttachDecision tryAttachMathSign(HandleFunction callee);
   AttachDecision tryAttachMathImul(HandleFunction callee);
   AttachDecision tryAttachMathFloor(HandleFunction callee);
   AttachDecision tryAttachMathCeil(HandleFunction callee);
   AttachDecision tryAttachMathTrunc(HandleFunction callee);
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -7191,16 +7191,41 @@ bool CacheIRCompiler::emitCallStringRepl
   masm.Push(str);
 
   using Fn =
       JSString* (*)(JSContext*, HandleString, HandleString, HandleString);
   callvm.call<Fn, jit::StringReplace>();
   return true;
 }
 
+bool CacheIRCompiler::emitCallStringSplitStringResult(
+    StringOperandId strId, StringOperandId separatorId, uint32_t groupOffset) {
+  JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
+
+  AutoCallVM callvm(masm, this, allocator);
+
+  Register str = allocator.useRegister(masm, strId);
+  Register separator = allocator.useRegister(masm, separatorId);
+  AutoScratchRegister scratch(allocator, masm);
+
+  StubFieldOffset group(groupOffset, StubField::Type::ObjectGroup);
+  emitLoadStubField(group, scratch);
+
+  callvm.prepare();
+  masm.Push(Imm32(INT32_MAX));
+  masm.Push(separator);
+  masm.Push(str);
+  masm.Push(scratch);
+
+  using Fn = ArrayObject* (*)(JSContext*, HandleObjectGroup, HandleString,
+                              HandleString, uint32_t);
+  callvm.call<Fn, js::StringSplitString>();
+  return true;
+}
+
 bool CacheIRCompiler::emitRegExpPrototypeOptimizableResult(
     ObjOperandId protoId) {
   JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
 
   AutoOutputRegister output(*this);
   Register proto = allocator.useRegister(masm, protoId);
   AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
 
@@ -7432,16 +7457,20 @@ template <>
 struct ReturnTypeToJSValueType<JSString*> {
   static constexpr JSValueType result = JSVAL_TYPE_STRING;
 };
 template <>
 struct ReturnTypeToJSValueType<BigInt*> {
   static constexpr JSValueType result = JSVAL_TYPE_BIGINT;
 };
 template <>
+struct ReturnTypeToJSValueType<ArrayObject*> {
+  static constexpr JSValueType result = JSVAL_TYPE_OBJECT;
+};
+template <>
 struct ReturnTypeToJSValueType<ArrayIteratorObject*> {
   static constexpr JSValueType result = JSVAL_TYPE_OBJECT;
 };
 template <>
 struct ReturnTypeToJSValueType<StringIteratorObject*> {
   static constexpr JSValueType result = JSVAL_TYPE_OBJECT;
 };
 template <>
--- a/js/src/jit/CacheIROps.yaml
+++ b/js/src/jit/CacheIROps.yaml
@@ -318,16 +318,25 @@
   shared: true
   transpile: true
   cost_estimate: 5
   args:
     str: StringId
     pattern: StringId
     replacement: StringId
 
+- name: CallStringSplitStringResult
+  shared: true
+  transpile: true
+  cost_estimate: 5
+  args:
+    str: StringId
+    separator: StringId
+    group: GroupField
+
 - name: RegExpPrototypeOptimizableResult
   shared: true
   transpile: true
   cost_estimate: 4
   args:
     proto: ObjId
 
 - name: RegExpInstanceOptimizableResult
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -5912,18 +5912,20 @@ class MStringConvertCase : public MUnary
 class MStringSplit : public MBinaryInstruction,
                      public MixPolicy<StringPolicy<0>, StringPolicy<1>>::Data {
   CompilerObjectGroup group_;
 
   MStringSplit(TempAllocator& alloc, CompilerConstraintList* constraints,
                MDefinition* string, MDefinition* sep, ObjectGroup* group)
       : MBinaryInstruction(classOpcode, string, sep), group_(group) {
     setResultType(MIRType::Object);
-    TemporaryTypeSet* types = MakeSingletonTypeSet(alloc, constraints, group);
-    setResultTypeSet(types);
+    if (!JitOptions.warpBuilder) {
+      TemporaryTypeSet* types = MakeSingletonTypeSet(alloc, constraints, group);
+      setResultTypeSet(types);
+    }
   }
 
  public:
   INSTRUCTION_HEADER(StringSplit)
   TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
   NAMED_OPERANDS((0, string), (1, separator))
 
   ObjectGroup* group() const { return group_; }
--- a/js/src/jit/WarpCacheIRTranspiler.cpp
+++ b/js/src/jit/WarpCacheIRTranspiler.cpp
@@ -92,16 +92,19 @@ class MOZ_RAII WarpCacheIRTranspiler : p
     return reinterpret_cast<const JSClass*>(readStubWord(offset));
   }
   JSString* stringStubField(uint32_t offset) {
     return reinterpret_cast<JSString*>(readStubWord(offset));
   }
   JS::Symbol* symbolStubField(uint32_t offset) {
     return reinterpret_cast<JS::Symbol*>(readStubWord(offset));
   }
+  ObjectGroup* groupStubField(uint32_t offset) {
+    return reinterpret_cast<ObjectGroup*>(readStubWord(offset));
+  }
   const void* rawPointerField(uint32_t offset) {
     return reinterpret_cast<const void*>(readStubWord(offset));
   }
   int32_t int32StubField(uint32_t offset) {
     return static_cast<int32_t>(readStubWord(offset));
   }
   uint32_t uint32StubField(uint32_t offset) {
     return static_cast<uint32_t>(readStubWord(offset));
@@ -1835,16 +1838,30 @@ bool WarpCacheIRTranspiler::emitCallStri
 
   auto* replace = MStringReplace::New(alloc(), str, pattern, replacement);
   add(replace);
 
   pushResult(replace);
   return true;
 }
 
+bool WarpCacheIRTranspiler::emitCallStringSplitStringResult(
+    StringOperandId strId, StringOperandId separatorId, uint32_t groupOffset) {
+  MDefinition* str = getOperand(strId);
+  MDefinition* separator = getOperand(separatorId);
+  ObjectGroup* group = groupStubField(groupOffset);
+
+  auto* replace = MStringSplit::New(alloc(), /* constraints = */ nullptr, str,
+                                    separator, group);
+  add(replace);
+
+  pushResult(replace);
+  return true;
+}
+
 bool WarpCacheIRTranspiler::emitRegExpPrototypeOptimizableResult(
     ObjOperandId protoId) {
   MDefinition* proto = getOperand(protoId);
 
   auto* optimizable = MRegExpPrototypeOptimizable::New(alloc(), proto);
   add(optimizable);
 
   pushResult(optimizable);
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1617,17 +1617,18 @@ static bool intrinsic_StringReplaceAllSt
   if (!result) {
     return false;
   }
 
   args.rval().setString(result);
   return true;
 }
 
-bool js::intrinsic_StringSplitString(JSContext* cx, unsigned argc, Value* vp) {
+static bool intrinsic_StringSplitString(JSContext* cx, unsigned argc,
+                                        Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   MOZ_ASSERT(args.length() == 2);
 
   RootedString string(cx, args[0].toString());
   RootedString sep(cx, args[1].toString());
 
   RootedObjectGroup group(cx, ObjectGroupRealm::getStringSplitStringGroup(cx));
   if (!group) {
--- a/js/src/vm/SelfHosting.h
+++ b/js/src/vm/SelfHosting.h
@@ -66,18 +66,16 @@ bool CallSelfHostedFunction(JSContext* c
 
 /*
  * Calls a self-hosted function by name.
  */
 bool CallSelfHostedFunction(JSContext* cx, HandlePropertyName name,
                             HandleValue thisv, const AnyInvokeArgs& args,
                             MutableHandleValue rval);
 
-bool intrinsic_StringSplitString(JSContext* cx, unsigned argc, JS::Value* vp);
-
 bool intrinsic_NewArrayIterator(JSContext* cx, unsigned argc, JS::Value* vp);
 
 bool intrinsic_NewStringIterator(JSContext* cx, unsigned argc, JS::Value* vp);
 
 bool intrinsic_NewRegExpStringIterator(JSContext* cx, unsigned argc,
                                        JS::Value* vp);
 
 } /* namespace js */