• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include 'src/objects/js-objects.h'
6#include 'src/objects/intl-objects.h'
7
8extern macro IntlAsciiCollationWeightsL1(): RawPtr<uint8>;
9extern macro IntlAsciiCollationWeightsL3(): RawPtr<uint8>;
10const kIntlAsciiCollationWeightsLength:
11    constexpr int31 generates 'Intl::kAsciiCollationWeightsLength';
12
13macro IntlAsciiCollationWeightL1(c: char8): uint8 labels _Bailout {
14  static_assert(kIntlAsciiCollationWeightsLength == 256);
15  return IntlAsciiCollationWeightsL1()[Convert<intptr>(c)];
16}
17macro IntlAsciiCollationWeightL1(c: char16): uint8 labels Bailout {
18  if (Convert<uint32>(c) >= kIntlAsciiCollationWeightsLength) goto Bailout;
19  return IntlAsciiCollationWeightsL1()[Convert<intptr>(c)];
20}
21
22macro IntlAsciiCollationWeightL3(c: char8): uint8 labels _Bailout {
23  static_assert(kIntlAsciiCollationWeightsLength == 256);
24  return IntlAsciiCollationWeightsL3()[Convert<intptr>(c)];
25}
26macro IntlAsciiCollationWeightL3(c: char16): uint8 labels Bailout {
27  if (Convert<uint32>(c) >= kIntlAsciiCollationWeightsLength) goto Bailout;
28  return IntlAsciiCollationWeightsL3()[Convert<intptr>(c)];
29}
30
31macro CheckEmptyOr1Byte(
32    _it: torque_internal::SliceIterator<char8, const &char8>):
33    void labels _Bailout {
34  // char8 is always within 0xFF.
35}
36macro CheckEmptyOr1Byte(
37    it: torque_internal::SliceIterator<char16, const &char16>):
38    void labels Bailout {
39  let it = it;
40  if ((it.Next() otherwise return ) > 0xFF) goto Bailout;
41}
42
43// This fast path works for ASCII-only strings and is based on the assumption
44// that most strings are either bytewise equal or differ on L1 (i.e., not just
45// in capitalization). So we first compare the strings on L1 and only afterwards
46// consider L3. This makes use of the 256-entry L1 and L3 tables defined in
47// src/objects/intl-objects.cc.
48macro LocaleCompareFastPath<T1: type, T2: type>(
49    left: ConstSlice<T1>, right: ConstSlice<T2>): Number labels Bailout {
50  if (EqualContent(left, right)) return 0;
51  let leftIt = left.Iterator();
52  let rightIt = right.Iterator();
53  while (true) {
54    try {
55      const lChar = leftIt.Next() otherwise goto LeftExhausted;
56      const leftWeight = IntlAsciiCollationWeightL1(lChar) otherwise Bailout;
57      if (leftWeight == 0) goto Bailout;
58      // If rightIt is exhausted, we already checked that the next char of the
59      // left string has non-zero weight, so it cannot be ignorable or a
60      // combining character.
61      // Return 1 because right string is shorter and L1 is equal.
62      const rChar = rightIt.Next() otherwise return 1;
63      const rightWeight = IntlAsciiCollationWeightL1(rChar) otherwise Bailout;
64      if (rightWeight == 0) goto Bailout;
65      if (leftWeight == rightWeight) continue;
66      // The result is only valid if the last processed character is not
67      // followed by a unicode combining character (we are overly strict and
68      // restrict to code points up to 0xFF).
69      CheckEmptyOr1Byte(leftIt) otherwise Bailout;
70      CheckEmptyOr1Byte(rightIt) otherwise Bailout;
71      if (leftWeight < rightWeight) return -1;
72      return 1;
73    } label LeftExhausted {
74      const rChar = rightIt.Next() otherwise break;
75      const rightWeight = IntlAsciiCollationWeightL1(rChar) otherwise Bailout;
76      // If the following character might be ignorable or a combining character,
77      // we bail out because the strings might still be considered equal.
78      if (rightWeight == 0) goto Bailout;
79      // Return -1 because left string is shorter and L1 is equal.
80      return -1;
81    }
82  }
83  leftIt = left.Iterator();
84  rightIt = right.Iterator();
85  while (true) {
86    const lChar = leftIt.Next() otherwise unreachable;
87    const leftWeight = IntlAsciiCollationWeightL3(lChar) otherwise unreachable;
88    dcheck(leftWeight != 0);
89    const rChar = rightIt.Next() otherwise unreachable;
90    const rightWeight = IntlAsciiCollationWeightL3(rChar) otherwise unreachable;
91    dcheck(rightWeight != 0);
92    dcheck(
93        IntlAsciiCollationWeightL1(lChar) otherwise unreachable ==
94        IntlAsciiCollationWeightL1(rChar) otherwise unreachable);
95    if (leftWeight == rightWeight) continue;
96    if (leftWeight < rightWeight) return -1;
97    return 1;
98  }
99  VerifiedUnreachable();
100}
101
102transitioning builtin StringFastLocaleCompare(implicit context: Context)(
103    localeCompareFn: JSFunction, left: JSAny, right: JSAny,
104    locales: JSAny): JSAny {
105  try {
106    const left = Cast<String>(left) otherwise Bailout;
107    if (TaggedEqual(left, right)) return SmiConstant(0);
108    StringToSlice(left) otherwise LeftOneByte, LeftTwoByte;
109  } label LeftOneByte(leftSlice: ConstSlice<char8>) {
110    try {
111      const right = Cast<String>(right) otherwise Bailout;
112      StringToSlice(right) otherwise RightOneByte, RightTwoByte;
113    } label RightOneByte(rightSlice: ConstSlice<char8>) {
114      return LocaleCompareFastPath(leftSlice, rightSlice) otherwise Bailout;
115    } label RightTwoByte(rightSlice: ConstSlice<char16>) {
116      return LocaleCompareFastPath(leftSlice, rightSlice) otherwise Bailout;
117    }
118  } label LeftTwoByte(leftSlice: ConstSlice<char16>) {
119    try {
120      const right = Cast<String>(right) otherwise Bailout;
121      StringToSlice(right) otherwise RightOneByte, RightTwoByte;
122    } label RightOneByte(rightSlice: ConstSlice<char8>) {
123      return LocaleCompareFastPath(leftSlice, rightSlice) otherwise Bailout;
124    } label RightTwoByte(rightSlice: ConstSlice<char16>) {
125      return LocaleCompareFastPath(leftSlice, rightSlice) otherwise Bailout;
126    }
127  } label Bailout deferred {
128    return Call(context, localeCompareFn, left, right, locales);
129  }
130}
131