Index: test/cctest/test-regexp.cc |
diff --git a/test/cctest/test-regexp.cc b/test/cctest/test-regexp.cc |
index 26b019eeb9e7c6ad4b09f526fed0a0b7c9cf2379..c6158448ae5e0dd8ad427410872c59f289685cce 100644 |
--- a/test/cctest/test-regexp.cc |
+++ b/test/cctest/test-regexp.cc |
@@ -28,6 +28,7 @@ |
#include <cstdlib> |
#include <sstream> |
+#include "include/v8.h" |
#include "src/v8.h" |
#include "src/ast/ast.h" |
@@ -1847,3 +1848,82 @@ TEST(CharacterRangeMerge) { |
TEST(Graph) { |
Execute("\\b\\w+\\b", false, true, true); |
} |
+ |
+ |
+namespace { |
+ |
+int* global_use_counts = NULL; |
+ |
+void MockUseCounterCallback(v8::Isolate* isolate, |
+ v8::Isolate::UseCounterFeature feature) { |
+ ++global_use_counts[feature]; |
+} |
+} |
+ |
+ |
+// Test that ES2015 RegExp compatibility fixes are in place, that they |
+// are not overly broad, and the appropriate UseCounters are incremented |
+TEST(UseCountRegExp) { |
+ i::FLAG_harmony_regexps = true; |
+ v8::Isolate* isolate = CcTest::isolate(); |
+ v8::HandleScope scope(isolate); |
+ LocalContext env; |
+ int use_counts[v8::Isolate::kUseCounterFeatureCount] = {}; |
+ global_use_counts = use_counts; |
+ CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback); |
+ |
+ // Compat fix: RegExp.prototype.sticky == undefined; UseCounter tracks it |
+ v8::Local<v8::Value> resultSticky = CompileRun("RegExp.prototype.sticky"); |
+ CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]); |
+ CHECK_EQ(0, use_counts[v8::Isolate::kRegExpPrototypeToString]); |
+ CHECK(resultSticky->IsUndefined()); |
+ |
+ // re.sticky has approriate value and doesn't touch UseCounter |
+ v8::Local<v8::Value> resultReSticky = CompileRun("/a/.sticky"); |
+ CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]); |
+ CHECK_EQ(0, use_counts[v8::Isolate::kRegExpPrototypeToString]); |
+ CHECK(resultReSticky->IsFalse()); |
+ |
+ // When the getter is caleld on another object, throw an exception |
+ // and don't increment the UseCounter |
+ v8::Local<v8::Value> resultStickyError = CompileRun( |
+ "var exception;" |
+ "try { " |
+ " Object.getOwnPropertyDescriptor(RegExp.prototype, 'sticky')" |
+ " .get.call(null);" |
+ "} catch (e) {" |
+ " exception = e;" |
+ "}" |
+ "exception"); |
+ CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]); |
+ CHECK_EQ(0, use_counts[v8::Isolate::kRegExpPrototypeToString]); |
+ CHECK(resultStickyError->IsObject()); |
+ |
+ // RegExp.prototype.toString() returns '/(?:)/' as a compatibility fix; |
+ // a UseCounter is incremented to track it. |
+ v8::Local<v8::Value> resultToString = |
+ CompileRun("RegExp.prototype.toString().length"); |
+ CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]); |
+ CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeToString]); |
+ CHECK(resultToString->IsInt32()); |
+ CHECK_EQ(6, |
+ resultToString->Int32Value(isolate->GetCurrentContext()).FromJust()); |
+ |
+ // .toString() works on normal RegExps |
+ v8::Local<v8::Value> resultReToString = CompileRun("/a/.toString().length"); |
+ CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]); |
+ CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeToString]); |
+ CHECK(resultReToString->IsInt32()); |
+ CHECK_EQ( |
+ 3, resultReToString->Int32Value(isolate->GetCurrentContext()).FromJust()); |
+ |
+ // .toString() throws on non-RegExps that aren't RegExp.prototype |
+ v8::Local<v8::Value> resultToStringError = CompileRun( |
+ "var exception;" |
+ "try { RegExp.prototype.toString.call(null) }" |
+ "catch (e) { exception = e; }" |
+ "exception"); |
+ CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]); |
+ CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeToString]); |
+ CHECK(resultToStringError->IsObject()); |
+} |