Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(113)

Side by Side Diff: src/runtime/runtime-regexp.cc

Issue 2433923003: [regexp] Add fast-path for global, callable replace (Closed)
Patch Set: Re-add asserts and COW array usage Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/runtime/runtime.h ('k') | src/string-builder.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/runtime/runtime-utils.h" 5 #include "src/runtime/runtime-utils.h"
6 6
7 #include "src/arguments.h" 7 #include "src/arguments.h"
8 #include "src/conversions-inl.h" 8 #include "src/conversions-inl.h"
9 #include "src/isolate-inl.h" 9 #include "src/isolate-inl.h"
10 #include "src/messages.h" 10 #include "src/messages.h"
(...skipping 955 matching lines...) Expand 10 before | Expand all | Expand 10 after
966 virtual ~VectorBackedMatch() {} 966 virtual ~VectorBackedMatch() {}
967 967
968 private: 968 private:
969 Isolate* isolate_; 969 Isolate* isolate_;
970 Handle<String> subject_; 970 Handle<String> subject_;
971 Handle<String> match_; 971 Handle<String> match_;
972 const int match_position_; 972 const int match_position_;
973 ZoneVector<Handle<Object>>* captures_; 973 ZoneVector<Handle<Object>>* captures_;
974 }; 974 };
975 975
976 // Only called from RegExpExecMultiple so it doesn't need to maintain 976 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain
977 // separate last match info. See comment on that function. 977 // separate last match info. See comment on that function.
978 template <bool has_capture> 978 template <bool has_capture>
979 MaybeHandle<Object> SearchRegExpMultiple( 979 static Object* SearchRegExpMultiple(Isolate* isolate, Handle<String> subject,
980 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, 980 Handle<JSRegExp> regexp,
981 Handle<RegExpMatchInfo> last_match_array, 981 Handle<RegExpMatchInfo> last_match_array,
982 Handle<FixedArray> result_elements) { 982 Handle<JSArray> result_array) {
983 DCHECK(subject->IsFlat()); 983 DCHECK(subject->IsFlat());
984 DCHECK_NE(has_capture, regexp->CaptureCount() == 0); 984 DCHECK_NE(has_capture, regexp->CaptureCount() == 0);
985 985
986 int capture_count = regexp->CaptureCount(); 986 int capture_count = regexp->CaptureCount();
987 int subject_length = subject->length(); 987 int subject_length = subject->length();
988 988
989 static const int kMinLengthToCache = 0x1000; 989 static const int kMinLengthToCache = 0x1000;
990 990
991 if (subject_length > kMinLengthToCache) { 991 if (subject_length > kMinLengthToCache) {
992 FixedArray* last_match_cache; 992 FixedArray* last_match_cache;
993 Object* cached_answer = RegExpResultsCache::Lookup( 993 Object* cached_answer = RegExpResultsCache::Lookup(
994 isolate->heap(), *subject, regexp->data(), &last_match_cache, 994 isolate->heap(), *subject, regexp->data(), &last_match_cache,
995 RegExpResultsCache::REGEXP_MULTIPLE_INDICES); 995 RegExpResultsCache::REGEXP_MULTIPLE_INDICES);
996 if (cached_answer->IsFixedArray()) { 996 if (cached_answer->IsFixedArray()) {
997 int capture_registers = (capture_count + 1) * 2; 997 int capture_registers = (capture_count + 1) * 2;
998 int32_t* last_match = NewArray<int32_t>(capture_registers); 998 int32_t* last_match = NewArray<int32_t>(capture_registers);
999 for (int i = 0; i < capture_registers; i++) { 999 for (int i = 0; i < capture_registers; i++) {
1000 last_match[i] = Smi::cast(last_match_cache->get(i))->value(); 1000 last_match[i] = Smi::cast(last_match_cache->get(i))->value();
1001 } 1001 }
1002 Handle<FixedArray> cached_fixed_array(FixedArray::cast(cached_answer)); 1002 Handle<FixedArray> cached_fixed_array =
1003 Handle<FixedArray>(FixedArray::cast(cached_answer));
1004 // The cache FixedArray is a COW-array and we need to return a copy.
jgruber 2016/10/19 16:39:13 It might not make sense anymore for the result cac
Yang 2016/10/20 09:53:14 I'd simply introduce a version of SBC that only ta
jgruber 2016/10/20 10:58:30 That would work, I'm just not sure what we would g
1005 Handle<FixedArray> copied_fixed_array =
1006 isolate->factory()->CopyFixedArrayWithMap(
1007 cached_fixed_array, isolate->factory()->fixed_array_map());
1008 JSArray::SetContent(result_array, copied_fixed_array);
1003 RegExpImpl::SetLastMatchInfo(last_match_array, subject, capture_count, 1009 RegExpImpl::SetLastMatchInfo(last_match_array, subject, capture_count,
1004 last_match); 1010 last_match);
1005 DeleteArray(last_match); 1011 DeleteArray(last_match);
1006 // The cache FixedArray is a COW-array and we need to return a copy. 1012 return *result_array;
1007 return isolate->factory()->CopyFixedArrayWithMap(
1008 cached_fixed_array, isolate->factory()->fixed_array_map());
1009 } 1013 }
1010 } 1014 }
1011 1015
1012 RegExpImpl::GlobalCache global_cache(regexp, subject, isolate); 1016 RegExpImpl::GlobalCache global_cache(regexp, subject, isolate);
1013 if (global_cache.HasException()) return MaybeHandle<Object>(); 1017 if (global_cache.HasException()) return isolate->heap()->exception();
1014 1018
1015 // Ensured in Runtime_RegExpExecMultiple. 1019 // Ensured in Runtime_RegExpExecMultiple.
1020 DCHECK(result_array->HasFastObjectElements());
1021 Handle<FixedArray> result_elements(
1022 FixedArray::cast(result_array->elements()));
1016 if (result_elements->length() < 16) { 1023 if (result_elements->length() < 16) {
1017 result_elements = isolate->factory()->NewFixedArrayWithHoles(16); 1024 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
1018 } 1025 }
1019 1026
1020 FixedArrayBuilder builder(result_elements); 1027 FixedArrayBuilder builder(result_elements);
1021 1028
1022 // Position to search from. 1029 // Position to search from.
1023 int match_start = -1; 1030 int match_start = -1;
1024 int match_end = 0; 1031 int match_end = 0;
1025 bool first = true; 1032 bool first = true;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1072 } 1079 }
1073 elements->set(capture_count + 1, Smi::FromInt(match_start)); 1080 elements->set(capture_count + 1, Smi::FromInt(match_start));
1074 elements->set(capture_count + 2, *subject); 1081 elements->set(capture_count + 2, *subject);
1075 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements)); 1082 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements));
1076 } else { 1083 } else {
1077 builder.Add(*match); 1084 builder.Add(*match);
1078 } 1085 }
1079 } 1086 }
1080 } 1087 }
1081 1088
1082 if (global_cache.HasException()) return MaybeHandle<Object>(); 1089 if (global_cache.HasException()) return isolate->heap()->exception();
1083 1090
1084 if (match_start >= 0) { 1091 if (match_start >= 0) {
1085 // Finished matching, with at least one match. 1092 // Finished matching, with at least one match.
1086 if (match_end < subject_length) { 1093 if (match_end < subject_length) {
1087 ReplacementStringBuilder::AddSubjectSlice(&builder, match_end, 1094 ReplacementStringBuilder::AddSubjectSlice(&builder, match_end,
1088 subject_length); 1095 subject_length);
1089 } 1096 }
1090 1097
1091 RegExpImpl::SetLastMatchInfo(last_match_array, subject, capture_count, 1098 RegExpImpl::SetLastMatchInfo(last_match_array, subject, capture_count,
1092 global_cache.LastSuccessfulMatch()); 1099 global_cache.LastSuccessfulMatch());
1093 1100
1094 Handle<FixedArray> result_fixed_array = builder.array();
1095 result_fixed_array->Shrink(builder.length());
1096
1097 if (subject_length > kMinLengthToCache) { 1101 if (subject_length > kMinLengthToCache) {
1098 // Store the last successful match into the array for caching. 1102 // Store the last successful match into the array for caching.
1099 // TODO(yangguo): do not expose last match to JS and simplify caching. 1103 // TODO(yangguo): do not expose last match to JS and simplify caching.
1100 int capture_registers = (capture_count + 1) * 2; 1104 int capture_registers = (capture_count + 1) * 2;
1101 Handle<FixedArray> last_match_cache = 1105 Handle<FixedArray> last_match_cache =
1102 isolate->factory()->NewFixedArray(capture_registers); 1106 isolate->factory()->NewFixedArray(capture_registers);
1103 int32_t* last_match = global_cache.LastSuccessfulMatch(); 1107 int32_t* last_match = global_cache.LastSuccessfulMatch();
1104 for (int i = 0; i < capture_registers; i++) { 1108 for (int i = 0; i < capture_registers; i++) {
1105 last_match_cache->set(i, Smi::FromInt(last_match[i])); 1109 last_match_cache->set(i, Smi::FromInt(last_match[i]));
1106 } 1110 }
1107 // Cache the result and turn the FixedArray into a COW array. 1111 Handle<FixedArray> result_fixed_array = builder.array();
1112 result_fixed_array->Shrink(builder.length());
1113 // Cache the result and copy the FixedArray into a COW array.
1114 Handle<FixedArray> copied_fixed_array =
1115 isolate->factory()->CopyFixedArrayWithMap(
1116 result_fixed_array, isolate->factory()->fixed_array_map());
1108 RegExpResultsCache::Enter( 1117 RegExpResultsCache::Enter(
1109 isolate, subject, handle(regexp->data(), isolate), result_fixed_array, 1118 isolate, subject, handle(regexp->data(), isolate), copied_fixed_array,
1110 last_match_cache, RegExpResultsCache::REGEXP_MULTIPLE_INDICES); 1119 last_match_cache, RegExpResultsCache::REGEXP_MULTIPLE_INDICES);
1111 } 1120 }
1112 // The cache FixedArray is a COW-array and we need to return a copy. 1121 return *builder.ToJSArray(result_array);
1113 return isolate->factory()->CopyFixedArrayWithMap(
1114 result_fixed_array, isolate->factory()->fixed_array_map());
1115 } else { 1122 } else {
1116 return isolate->factory()->null_value(); // No matches at all. 1123 return isolate->heap()->null_value(); // No matches at all.
1117 } 1124 }
1118 } 1125 }
1119 1126
1120 // This is only called for StringReplaceGlobalRegExpWithFunction. This sets
1121 // lastMatchInfoOverride to maintain the last match info, so we don't need to
1122 // set any other last match array info.
1123 MaybeHandle<Object> RegExpExecMultiple(Isolate* isolate,
1124 Handle<JSRegExp> regexp,
1125 Handle<String> subject,
1126 Handle<RegExpMatchInfo> last_match_info,
1127 Handle<FixedArray> result_array) {
1128 subject = String::Flatten(subject);
1129 CHECK(regexp->GetFlags() & JSRegExp::kGlobal);
1130
1131 if (regexp->CaptureCount() == 0) {
1132 return SearchRegExpMultiple<false>(isolate, subject, regexp,
1133 last_match_info, result_array);
1134 } else {
1135 return SearchRegExpMultiple<true>(isolate, subject, regexp, last_match_info,
1136 result_array);
1137 }
1138 }
1139
1140 // Helper function for replacing regular expressions with the result of a
1141 // function application in String.prototype.replace.
1142 MaybeHandle<String> StringReplaceGlobalRegExpWithFunction(
1143 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp,
1144 Handle<Object> replace_obj) {
1145 Factory* factory = isolate->factory();
1146
1147 // TODO(jgruber): Convert result_array into a List<Handle<Object>> (or
1148 // similar) and adapt / remove FixedArrayBuilder.
1149 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info();
1150 Handle<FixedArray> result_array = factory->NewFixedArrayWithHoles(16);
1151
1152 Handle<Object> res;
1153 ASSIGN_RETURN_ON_EXCEPTION(isolate, res,
1154 RegExpExecMultiple(isolate, regexp, subject,
1155 last_match_info, result_array),
1156 String);
1157
1158 // Reload the last match info since it might have changed in the meantime.
1159 last_match_info = isolate->regexp_last_match_info();
1160
1161 if (res->IsNull(isolate)) return subject; // No matches at all.
1162
1163 result_array = Handle<FixedArray>::cast(res);
1164 const int result_length = result_array->length();
1165
1166 const int num_captures = last_match_info->NumberOfCaptureRegisters() / 2;
1167 if (num_captures == 1) {
1168 // If the number of captures is one then there are no explicit captures in
1169 // the regexp, just the implicit capture that captures the whole match. In
1170 // this case we can simplify quite a bit and end up with something faster.
1171 // The builder will consist of some integers that indicate slices of the
1172 // input string and some replacements that were returned from the replace
1173 // function.
1174 int match_start = 0;
1175 for (int i = 0; i < result_length; i++) {
1176 Handle<Object> elem = FixedArray::get(*result_array, i, isolate);
1177 if (elem->IsSmi()) {
1178 // Integers represent slices of the original string.
1179 // TODO(jgruber): Maybe we don't need this weird encoding anymore (in
1180 // preparation to invoking StringBuilderConcat), but can just copy into
1181 // the result string with the IncrementalStringBuilder as we go?
1182 const int elem_value = Handle<Smi>::cast(elem)->value();
1183 if (elem_value > 0) {
1184 match_start = (elem_value >> 11) + (elem_value & 0x7ff);
1185 } else {
1186 Handle<Object> next_elem =
1187 FixedArray::get(*result_array, ++i, isolate);
1188 const int next_elem_value = Handle<Smi>::cast(next_elem)->value();
1189 match_start = next_elem_value - elem_value;
1190 }
1191 } else {
1192 DCHECK(elem->IsString());
1193 Handle<String> elem_string = Handle<String>::cast(elem);
1194
1195 // Overwrite the i'th element in the results with the string we got
1196 // back from the callback function.
1197 const int argc = 3;
1198 ScopedVector<Handle<Object>> argv(argc);
1199
1200 argv[0] = elem_string;
1201 argv[1] = handle(Smi::FromInt(match_start), isolate);
1202 argv[2] = subject;
1203
1204 Handle<Object> replacement_obj;
1205 ASSIGN_RETURN_ON_EXCEPTION(
1206 isolate, replacement_obj,
1207 Execution::Call(isolate, replace_obj, factory->undefined_value(),
1208 argc, argv.start()),
1209 String);
1210
1211 Handle<String> replacement;
1212 ASSIGN_RETURN_ON_EXCEPTION(isolate, replacement,
1213 Object::ToString(isolate, replacement_obj),
1214 String);
1215
1216 result_array->set(i, *replacement);
1217 match_start += elem_string->length();
1218 }
1219 }
1220 } else {
1221 DCHECK(num_captures > 1);
1222 for (int i = 0; i < result_length; i++) {
1223 Handle<Object> elem = FixedArray::get(*result_array, i, isolate);
1224 if (elem->IsSmi()) continue;
1225
1226 // TODO(jgruber): We can skip this whole round-trip through a JS array
1227 // for result_array.
1228 Handle<JSArray> elem_array = Handle<JSArray>::cast(elem);
1229 Handle<FixedArray> elem_array_elems(
1230 FixedArray::cast(elem_array->elements()), isolate);
1231
1232 const int argc = elem_array_elems->length();
1233 ScopedVector<Handle<Object>> argv(argc);
1234
1235 for (int j = 0; j < argc; j++) {
1236 argv[j] = FixedArray::get(*elem_array_elems, j, isolate);
1237 }
1238
1239 // TODO(jgruber): This call is another pattern we could refactor.
1240 Handle<Object> replacement_obj;
1241 ASSIGN_RETURN_ON_EXCEPTION(
1242 isolate, replacement_obj,
1243 Execution::Call(isolate, replace_obj, factory->undefined_value(),
1244 argc, argv.start()),
1245 String);
1246
1247 Handle<String> replacement;
1248 ASSIGN_RETURN_ON_EXCEPTION(isolate, replacement,
1249 Object::ToString(isolate, replacement_obj),
1250 String);
1251
1252 result_array->set(i, *replacement);
1253 }
1254 }
1255
1256 if (result_length == 0) {
1257 return factory->empty_string();
1258 } else if (result_length == 1) {
1259 Handle<Object> first = FixedArray::get(*result_array, 0, isolate);
1260 if (first->IsString()) return Handle<String>::cast(first);
1261 }
1262
1263 bool one_byte = subject->HasOnlyOneByteChars();
1264 const int length = StringBuilderConcatLength(subject->length(), *result_array,
1265 result_length, &one_byte);
1266
1267 if (length == -1) {
1268 isolate->Throw(isolate->heap()->illegal_argument_string());
1269 return MaybeHandle<String>();
1270 }
1271
1272 if (one_byte) {
1273 Handle<SeqOneByteString> answer;
1274 ASSIGN_RETURN_ON_EXCEPTION(isolate, answer,
1275 isolate->factory()->NewRawOneByteString(length),
1276 String);
1277 StringBuilderConcatHelper(*subject, answer->GetChars(), *result_array,
1278 result_length);
1279 return answer;
1280 } else {
1281 DCHECK(!one_byte);
1282 Handle<SeqTwoByteString> answer;
1283 ASSIGN_RETURN_ON_EXCEPTION(isolate, answer,
1284 isolate->factory()->NewRawTwoByteString(length),
1285 String);
1286 StringBuilderConcatHelper(*subject, answer->GetChars(), *result_array,
1287 result_length);
1288 return answer;
1289 }
1290
1291 UNREACHABLE();
1292 return MaybeHandle<String>();
1293 }
1294
1295 MaybeHandle<String> StringReplaceNonGlobalRegExpWithFunction( 1127 MaybeHandle<String> StringReplaceNonGlobalRegExpWithFunction(
1296 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, 1128 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp,
1297 Handle<Object> replace_obj) { 1129 Handle<Object> replace_obj) {
1298 Factory* factory = isolate->factory(); 1130 Factory* factory = isolate->factory();
1299 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); 1131 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info();
1300 1132
1301 // TODO(jgruber): This is a pattern we could refactor. 1133 // TODO(jgruber): This is a pattern we could refactor.
1302 Handle<Object> match_indices_obj; 1134 Handle<Object> match_indices_obj;
1303 ASSIGN_RETURN_ON_EXCEPTION( 1135 ASSIGN_RETURN_ON_EXCEPTION(
1304 isolate, match_indices_obj, 1136 isolate, match_indices_obj,
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
1437 Object* result = StringReplaceGlobalRegExpWithString( 1269 Object* result = StringReplaceGlobalRegExpWithString(
1438 isolate, string, regexp, replace, last_match_info); 1270 isolate, string, regexp, replace, last_match_info);
1439 if (result->IsString()) { 1271 if (result->IsString()) {
1440 return handle(String::cast(result), isolate); 1272 return handle(String::cast(result), isolate);
1441 } else { 1273 } else {
1442 return MaybeHandle<String>(); 1274 return MaybeHandle<String>();
1443 } 1275 }
1444 } 1276 }
1445 } else { 1277 } else {
1446 DCHECK(functional_replace); 1278 DCHECK(functional_replace);
1447 if (global) { 1279 DCHECK(!global); // Handled as fast path.
jgruber 2016/10/19 16:39:13 The entire functional_replace branch should be rem
1448 // Global regexp search, function replace. 1280 // Non-global regexp search, function replace.
1449 return StringReplaceGlobalRegExpWithFunction(isolate, string, regexp, 1281 return StringReplaceNonGlobalRegExpWithFunction(isolate, string, regexp,
1450 replace_obj); 1282 replace_obj);
1451 } else {
1452 // Non-global regexp search, function replace.
1453 return StringReplaceNonGlobalRegExpWithFunction(isolate, string, regexp,
1454 replace_obj);
1455 }
1456 } 1283 }
1457 1284
1458 UNREACHABLE(); 1285 UNREACHABLE();
1459 return MaybeHandle<String>(); 1286 return MaybeHandle<String>();
1460 } 1287 }
1461 1288
1462 } // namespace 1289 } // namespace
1463 1290
1464 RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithFunction) { 1291 // This is only called for StringReplaceGlobalRegExpWithFunction.
1465 HandleScope scope(isolate); 1292 RUNTIME_FUNCTION(Runtime_RegExpExecMultiple) {
1466 DCHECK(args.length() == 3); 1293 HandleScope handles(isolate);
1294 DCHECK(args.length() == 4);
1467 1295
1468 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 1296 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1469 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); 1297 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
1470 CONVERT_ARG_HANDLE_CHECKED(JSObject, replace, 2); 1298 CONVERT_ARG_HANDLE_CHECKED(RegExpMatchInfo, last_match_info, 2);
1299 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
jgruber 2016/10/19 16:39:13 Reusing the result array does not seem to make any
Yang 2016/10/20 09:53:14 I wonder whether we need a JSArray for this at all
jgruber 2016/10/20 10:58:30 Sure. I kept the JSArray return type for now becau
1300 CHECK(result_array->HasFastObjectElements());
1471 1301
1472 RETURN_RESULT_OR_FAILURE(isolate, StringReplaceGlobalRegExpWithFunction( 1302 subject = String::Flatten(subject);
1473 isolate, subject, regexp, replace)); 1303 CHECK(regexp->GetFlags() & JSRegExp::kGlobal);
1304
1305 if (regexp->CaptureCount() == 0) {
1306 return SearchRegExpMultiple<false>(isolate, subject, regexp,
1307 last_match_info, result_array);
1308 } else {
1309 return SearchRegExpMultiple<true>(isolate, subject, regexp, last_match_info,
1310 result_array);
1311 }
1474 } 1312 }
1475 1313
1476 RUNTIME_FUNCTION(Runtime_StringReplaceNonGlobalRegExpWithFunction) { 1314 RUNTIME_FUNCTION(Runtime_StringReplaceNonGlobalRegExpWithFunction) {
1477 HandleScope scope(isolate); 1315 HandleScope scope(isolate);
1478 DCHECK(args.length() == 3); 1316 DCHECK(args.length() == 3);
1479 1317
1480 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 1318 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
1481 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); 1319 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
1482 CONVERT_ARG_HANDLE_CHECKED(JSObject, replace, 2); 1320 CONVERT_ARG_HANDLE_CHECKED(JSObject, replace, 2);
1483 1321
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
1681 1519
1682 RUNTIME_FUNCTION(Runtime_IsRegExp) { 1520 RUNTIME_FUNCTION(Runtime_IsRegExp) {
1683 SealHandleScope shs(isolate); 1521 SealHandleScope shs(isolate);
1684 DCHECK(args.length() == 1); 1522 DCHECK(args.length() == 1);
1685 CONVERT_ARG_CHECKED(Object, obj, 0); 1523 CONVERT_ARG_CHECKED(Object, obj, 0);
1686 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); 1524 return isolate->heap()->ToBoolean(obj->IsJSRegExp());
1687 } 1525 }
1688 1526
1689 } // namespace internal 1527 } // namespace internal
1690 } // namespace v8 1528 } // namespace v8
OLDNEW
« no previous file with comments | « src/runtime/runtime.h ('k') | src/string-builder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698