JavascriptRegularExpression.cpp 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "RuntimeLibraryPch.h"
  6. // Parser Includes
  7. #include "DebugWriter.h"
  8. #include "RegexPattern.h"
  9. namespace Js
  10. {
  11. JavascriptRegExp::JavascriptRegExp(UnifiedRegex::RegexPattern* pattern, DynamicType* type) :
  12. DynamicObject(type),
  13. pattern(pattern),
  14. splitPattern(nullptr),
  15. lastIndexVar(nullptr),
  16. lastIndexOrFlag(0)
  17. {
  18. Assert(type->GetTypeId() == TypeIds_RegEx);
  19. Assert(!this->GetType()->AreThisAndPrototypesEnsuredToHaveOnlyWritableDataProperties());
  20. Assert(!this->GetType()->ThisAndPrototypesHaveNoSpecialProperties());
  21. #if ENABLE_REGEX_CONFIG_OPTIONS
  22. if (REGEX_CONFIG_FLAG(RegexTracing))
  23. {
  24. UnifiedRegex::DebugWriter* w = type->GetScriptContext()->GetRegexDebugWriter();
  25. if (pattern == 0)
  26. w->PrintEOL(_u("// REGEX CREATE"));
  27. else
  28. {
  29. w->Print(_u("// REGEX CREATE "));
  30. pattern->Print(w);
  31. w->EOL();
  32. }
  33. }
  34. #endif
  35. }
  36. JavascriptRegExp::JavascriptRegExp(DynamicType * type) :
  37. DynamicObject(type),
  38. pattern(nullptr),
  39. splitPattern(nullptr),
  40. lastIndexVar(nullptr),
  41. lastIndexOrFlag(0)
  42. {
  43. Assert(type->GetTypeId() == TypeIds_RegEx);
  44. #if DBG
  45. if (REGEX_CONFIG_FLAG(RegexTracing))
  46. {
  47. UnifiedRegex::DebugWriter* w = type->GetScriptContext()->GetRegexDebugWriter();
  48. w->PrintEOL(_u("REGEX CREATE"));
  49. }
  50. #endif
  51. }
  52. JavascriptRegExp::JavascriptRegExp(JavascriptRegExp * instance, bool deepCopy) :
  53. DynamicObject(instance, deepCopy),
  54. pattern(instance->GetPattern()),
  55. splitPattern(instance->GetSplitPattern()),
  56. lastIndexVar(instance->lastIndexVar),
  57. lastIndexOrFlag(instance->lastIndexOrFlag)
  58. {
  59. // For boxing stack instance
  60. Assert(ThreadContext::IsOnStack(instance));
  61. // These members should never be on the stack and thus never need to be deep copied
  62. Assert(!ThreadContext::IsOnStack(instance->GetPattern()));
  63. Assert(!ThreadContext::IsOnStack(instance->GetSplitPattern()));
  64. Assert(!ThreadContext::IsOnStack(instance->lastIndexVar));
  65. }
  66. bool JavascriptRegExp::Is(Var aValue)
  67. {
  68. return JavascriptOperators::GetTypeId(aValue) == TypeIds_RegEx;
  69. }
  70. // IsRegExp in the spec.
  71. bool JavascriptRegExp::IsRegExpLike(Var aValue, ScriptContext* scriptContext)
  72. {
  73. if (scriptContext->GetConfig()->IsES6RegExSymbolsEnabled())
  74. {
  75. if (!JavascriptOperators::IsObject(aValue))
  76. {
  77. return false;
  78. }
  79. Var symbolMatchProperty = JavascriptOperators::GetProperty(
  80. RecyclableObject::FromVar(aValue),
  81. PropertyIds::_symbolMatch,
  82. scriptContext);
  83. if (!JavascriptOperators::IsUndefined(symbolMatchProperty))
  84. {
  85. return JavascriptConversion::ToBool(symbolMatchProperty, scriptContext);
  86. }
  87. }
  88. return JavascriptRegExp::Is(aValue);
  89. }
  90. JavascriptRegExp* JavascriptRegExp::FromVar(Var aValue)
  91. {
  92. AssertOrFailFastMsg(Is(aValue), "Ensure var is actually a 'JavascriptRegExp'");
  93. return static_cast<JavascriptRegExp *>(aValue);
  94. }
  95. JavascriptRegExp* JavascriptRegExp::UnsafeFromVar(Var aValue)
  96. {
  97. AssertMsg(Is(aValue), "Ensure var is actually a 'JavascriptRegExp'");
  98. return static_cast<JavascriptRegExp *>(aValue);
  99. }
  100. CharCount JavascriptRegExp::GetLastIndexProperty(RecyclableObject* instance, ScriptContext* scriptContext)
  101. {
  102. int64 lastIndex = JavascriptConversion::ToLength(
  103. JavascriptOperators::GetProperty(instance, PropertyIds::lastIndex, scriptContext),
  104. scriptContext);
  105. return GetIndexOrMax(lastIndex);
  106. }
  107. void JavascriptRegExp::SetLastIndexProperty(Var instance, CharCount lastIndex, ScriptContext* scriptContext)
  108. {
  109. SetLastIndexProperty(
  110. instance,
  111. JavascriptNumber::ToVar(lastIndex, scriptContext),
  112. scriptContext);
  113. }
  114. void JavascriptRegExp::SetLastIndexProperty(Var instance, Var lastIndex, ScriptContext* scriptContext)
  115. {
  116. JavascriptOperators::SetProperty(
  117. instance,
  118. RecyclableObject::FromVar(instance),
  119. PropertyIds::lastIndex,
  120. lastIndex,
  121. scriptContext,
  122. static_cast<PropertyOperationFlags>(PropertyOperation_ThrowIfNotExtensible | PropertyOperation_ThrowIfNonWritable));
  123. }
  124. bool JavascriptRegExp::GetGlobalProperty(RecyclableObject* instance, ScriptContext* scriptContext)
  125. {
  126. return JavascriptConversion::ToBool(
  127. JavascriptOperators::GetProperty(instance, PropertyIds::global, scriptContext),
  128. scriptContext);
  129. }
  130. bool JavascriptRegExp::GetUnicodeProperty(RecyclableObject* instance, ScriptContext* scriptContext)
  131. {
  132. return JavascriptConversion::ToBool(
  133. JavascriptOperators::GetProperty(instance, PropertyIds::unicode, scriptContext),
  134. scriptContext);
  135. }
  136. CharCount JavascriptRegExp::AddIndex(CharCount base, CharCount offset)
  137. {
  138. return (base + offset < base) // Overflow?
  139. ? MaxCharCount
  140. : base + offset;
  141. }
  142. CharCount JavascriptRegExp::GetIndexOrMax(int64 index)
  143. {
  144. return (index > SIZE_MAX || IsValidCharCount((size_t) index))
  145. ? (CharCount) index
  146. : MaxCharCount;
  147. }
  148. InternalString JavascriptRegExp::GetSource() const
  149. {
  150. return GetPattern()->GetSource();
  151. }
  152. UnifiedRegex::RegexFlags JavascriptRegExp::GetFlags() const
  153. {
  154. return GetPattern()->GetFlags();
  155. }
  156. JavascriptRegExp* JavascriptRegExp::GetJavascriptRegExp(Arguments& args, PCWSTR propertyName, ScriptContext* scriptContext)
  157. {
  158. if (args.Info.Count == 0)
  159. {
  160. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedRegExp, propertyName);
  161. }
  162. return ToRegExp(args[0], propertyName, scriptContext);
  163. }
  164. JavascriptRegExp* JavascriptRegExp::ToRegExp(Var var, PCWSTR varName, ScriptContext* scriptContext)
  165. {
  166. JavascriptRegExp * regExp = JavascriptOperators::TryFromVar<JavascriptRegExp>(var);
  167. if (regExp)
  168. {
  169. return regExp;
  170. }
  171. if (JavascriptOperators::GetTypeId(var) == TypeIds_HostDispatch)
  172. {
  173. TypeId remoteTypeId = TypeIds_Limit;
  174. RecyclableObject* reclObj = RecyclableObject::UnsafeFromVar(var);
  175. if (reclObj->GetRemoteTypeId(&remoteTypeId) && remoteTypeId == TypeIds_RegEx)
  176. {
  177. return static_cast<JavascriptRegExp *>(reclObj->GetRemoteObject());
  178. }
  179. }
  180. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedRegExp, varName);
  181. }
  182. RecyclableObject* JavascriptRegExp::GetThisObject(Arguments& args, PCWSTR varName, ScriptContext* scriptContext)
  183. {
  184. if (args.Info.Count == 0 || !JavascriptOperators::IsObject(args[0]))
  185. {
  186. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedObject, varName);
  187. }
  188. return RecyclableObject::FromVar(args[0]);
  189. }
  190. JavascriptString* JavascriptRegExp::GetFirstStringArg(Arguments& args, ScriptContext* scriptContext)
  191. {
  192. if (args.Info.Count == 1)
  193. {
  194. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  195. }
  196. else
  197. {
  198. JavascriptString *jsString = JavascriptOperators::TryFromVar<JavascriptString>(args[1]);
  199. if (jsString)
  200. {
  201. return jsString;
  202. }
  203. else
  204. {
  205. return JavascriptConversion::ToString(args[1], scriptContext);
  206. }
  207. }
  208. }
  209. bool JavascriptRegExp::ShouldApplyPrototypeWebWorkaround(Arguments& args, ScriptContext* scriptContext)
  210. {
  211. return scriptContext->GetConfig()->IsES6PrototypeChain() && \
  212. args.Info.Count >= 1 && args[0] == scriptContext->GetLibrary()->GetRegExpPrototype();
  213. }
  214. Var JavascriptRegExp::NewInstance(RecyclableObject* function, CallInfo callInfo, ...)
  215. {
  216. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  217. ARGUMENTS(args, callInfo);
  218. ScriptContext* scriptContext = function->GetScriptContext();
  219. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  220. // SkipDefaultNewObject function flag should have prevented the default object from
  221. // being created, except when call true a host dispatch.
  222. Var newTarget = args.HasNewTarget() ? args.Values[args.Info.Count] : function;
  223. bool isCtorSuperCall = JavascriptOperators::GetAndAssertIsConstructorSuperCall(args);
  224. UnifiedRegex::RegexPattern* pattern = nullptr;
  225. UnifiedRegex::RegexPattern* splitPattern = nullptr;
  226. JavascriptRegExp* regex = nullptr;
  227. if (callInfo.Count < 2)
  228. {
  229. pattern = scriptContext->GetLibrary()->GetEmptyRegexPattern();
  230. }
  231. else if (JavascriptRegExp::IsRegExpLike(args[1], scriptContext))
  232. {
  233. // JavascriptRegExp::IsRegExpLike() makes sure that args[1] is an Object.
  234. RecyclableObject* regexLikeObj = RecyclableObject::FromVar(args[1]);
  235. if (!(callInfo.Flags & CallFlags_New) &&
  236. (callInfo.Count == 2 || JavascriptOperators::IsUndefinedObject(args[2])) &&
  237. newTarget == JavascriptOperators::GetProperty(regexLikeObj, PropertyIds::constructor, scriptContext))
  238. {
  239. // ES5 15.10.3.1 Called as a function: If pattern R is a regexp object and flags is undefined, then return R unchanged.
  240. // As per ES6 21.2.3.1: We should only return pattern when the this argument is not an uninitialized RegExp object.
  241. // If regex is null, we can be sure the this argument is not initialized.
  242. return regexLikeObj;
  243. }
  244. if (JavascriptRegExp::Is(regexLikeObj))
  245. {
  246. JavascriptRegExp* source = JavascriptRegExp::FromVar(regexLikeObj);
  247. if (callInfo.Count > 2)
  248. {
  249. // As per ES 2015 21.2.3.1: If 1st argument is RegExp and 2nd argument is flag then return regexp with same pattern as 1st
  250. // argument and flags supplied by the 2nd argument.
  251. if (!JavascriptOperators::IsUndefinedObject(args[2]))
  252. {
  253. InternalString str = source->GetSource();
  254. pattern = CreatePattern(JavascriptString::NewCopyBuffer(str.GetBuffer(), str.GetLength(), scriptContext),
  255. args[2], scriptContext);
  256. // "splitPattern" is a version of "pattern" without the sticky flag. If other flags are the same, we can safely
  257. // reuse "splitPattern".
  258. UnifiedRegex::RegexFlags currentSplitFlags =
  259. static_cast<UnifiedRegex::RegexFlags>(source->GetPattern()->GetFlags() & ~UnifiedRegex::StickyRegexFlag);
  260. UnifiedRegex::RegexFlags newSplitFlags =
  261. static_cast<UnifiedRegex::RegexFlags>(pattern->GetFlags() & ~UnifiedRegex::StickyRegexFlag);
  262. if (newSplitFlags == currentSplitFlags)
  263. {
  264. splitPattern = source->GetSplitPattern();
  265. }
  266. }
  267. }
  268. if (!pattern)
  269. {
  270. pattern = source->GetPattern();
  271. splitPattern = source->GetSplitPattern();
  272. }
  273. }
  274. else // RegExp-like
  275. {
  276. Var source = JavascriptOperators::GetProperty(regexLikeObj, PropertyIds::source, scriptContext);
  277. Var flags = args.Info.Count < 3 || JavascriptOperators::IsUndefinedObject(args[2])
  278. ? JavascriptOperators::GetProperty(regexLikeObj, PropertyIds::flags, scriptContext)
  279. : args[2];
  280. pattern = CreatePattern(source, flags, scriptContext);
  281. }
  282. }
  283. else
  284. {
  285. pattern = CreatePattern(args[1], (callInfo.Count > 2) ? args[2] : nullptr, scriptContext);
  286. }
  287. if (regex == nullptr)
  288. {
  289. regex = scriptContext->GetLibrary()->CreateRegExp(nullptr);
  290. }
  291. regex->SetPattern(pattern);
  292. regex->SetSplitPattern(splitPattern);
  293. return isCtorSuperCall ?
  294. JavascriptOperators::OrdinaryCreateFromConstructor(RecyclableObject::FromVar(newTarget), regex, nullptr, scriptContext) :
  295. regex;
  296. }
  297. UnifiedRegex::RegexPattern* JavascriptRegExp::CreatePattern(Var aValue, Var options, ScriptContext *scriptContext)
  298. {
  299. JavascriptString * strBody;
  300. if (JavascriptString::Is(aValue))
  301. {
  302. strBody = JavascriptString::FromVar(aValue);
  303. }
  304. else if (JavascriptOperators::GetTypeId(aValue) == TypeIds_Undefined)
  305. {
  306. strBody = scriptContext->GetLibrary()->GetEmptyString();
  307. }
  308. else
  309. {
  310. strBody = JavascriptConversion::ToString(aValue, scriptContext); // must be null terminated!
  311. }
  312. int cBody = strBody->GetLength();
  313. const char16 *szRegex = strBody->GetSz();
  314. int cOpts = 0;
  315. const char16 *szOptions = nullptr;
  316. JavascriptString * strOptions = nullptr;
  317. if (options != nullptr && !JavascriptOperators::IsUndefinedObject(options))
  318. {
  319. if (JavascriptString::Is(options))
  320. {
  321. strOptions = JavascriptString::FromVar(options);
  322. }
  323. else
  324. {
  325. strOptions = JavascriptConversion::ToString(options, scriptContext);
  326. }
  327. szOptions = strOptions->GetSz(); // must be null terminated!
  328. cOpts = strOptions->GetLength();
  329. }
  330. UnifiedRegex::RegexPattern* pattern = RegexHelper::CompileDynamic(scriptContext, szRegex, cBody, szOptions, cOpts, false);
  331. return pattern;
  332. }
  333. JavascriptRegExp* JavascriptRegExp::CreateRegEx(const char16* pSource, CharCount sourceLen, UnifiedRegex::RegexFlags flags, ScriptContext *scriptContext)
  334. {
  335. UnifiedRegex::RegexPattern* pattern = RegexHelper::CompileDynamic(scriptContext, pSource, sourceLen, flags, false);
  336. return scriptContext->GetLibrary()->CreateRegExp(pattern);
  337. }
  338. JavascriptRegExp* JavascriptRegExp::CreateRegEx(Var aValue, Var options, ScriptContext *scriptContext)
  339. {
  340. // This is called as helper from OpCode::CoerseRegEx. If aValue is regex pattern /a/, CreatePattern converts
  341. // it to pattern "/a/" instead of "a". So if we know that aValue is regex, then just return the same object
  342. if (JavascriptRegExp::Is(aValue))
  343. {
  344. return JavascriptRegExp::FromVar(aValue);
  345. }
  346. else
  347. {
  348. return CreateRegExNoCoerce(aValue, options, scriptContext);
  349. }
  350. }
  351. JavascriptRegExp* JavascriptRegExp::CreateRegExNoCoerce(Var aValue, Var options, ScriptContext *scriptContext)
  352. {
  353. UnifiedRegex::RegexPattern* pattern = CreatePattern(aValue, options, scriptContext);
  354. return scriptContext->GetLibrary()->CreateRegExp(pattern);
  355. }
  356. void JavascriptRegExp::CacheLastIndex()
  357. {
  358. if (lastIndexVar == nullptr)
  359. lastIndexOrFlag = 0;
  360. else
  361. {
  362. // Does ToInteger(lastIndex) yield an integer in [0, MaxCharCount]?
  363. double v = JavascriptConversion::ToInteger(lastIndexVar, GetScriptContext());
  364. if (JavascriptNumber::IsNan(v))
  365. lastIndexOrFlag = 0;
  366. else if (JavascriptNumber::IsPosInf(v) ||
  367. JavascriptNumber::IsNegInf(v) ||
  368. v < 0.0 ||
  369. v > (double)MaxCharCount)
  370. lastIndexOrFlag = InvalidValue;
  371. else
  372. lastIndexOrFlag = (CharCount)v;
  373. }
  374. }
  375. JavascriptString *JavascriptRegExp::ToString(bool sourceOnly)
  376. {
  377. Js::InternalString str = pattern->GetSource();
  378. CompoundString *const builder = CompoundString::NewWithCharCapacity(str.GetLength() + 5, GetLibrary());
  379. if (!sourceOnly)
  380. {
  381. builder->AppendChars(_u('/'));
  382. }
  383. if (pattern->IsLiteral())
  384. {
  385. builder->AppendChars(str.GetBuffer(), str.GetLength());
  386. }
  387. else
  388. {
  389. // Need to ensure that the resulting static regex is functionally equivalent (as written) to 'this' regex. This
  390. // involves the following:
  391. // - Empty regex should result in /(?:)/ rather than //, which is a comment
  392. // - Unescaped '/' needs to be escaped so that it doesn't end the static regex prematurely
  393. // - Line terminators need to be escaped since they're not allowed in a static regex
  394. if (str.GetLength() == 0)
  395. {
  396. builder->AppendChars(_u("(?:)"));
  397. }
  398. else
  399. {
  400. bool escape = false;
  401. for (charcount_t i = 0; i < str.GetLength(); ++i)
  402. {
  403. const char16 c = str.GetBuffer()[i];
  404. if(!escape)
  405. {
  406. switch(c)
  407. {
  408. case _u('/'):
  409. case _u('\n'):
  410. case _u('\r'):
  411. case _u('\x2028'):
  412. case _u('\x2029'):
  413. // Unescaped '/' or line terminator needs to be escaped
  414. break;
  415. case _u('\\'):
  416. // Escape sequence; the next character is escaped and shouldn't be escaped further
  417. escape = true;
  418. Assert(i + 1 < str.GetLength()); // cannot end in a '\'
  419. // '\' is appended on the next iteration as 'escape' is true. This handles the case where we
  420. // have an escaped line terminator (\<lineTerminator>), where \\n has a different meaning and we
  421. // need to use \n instead.
  422. continue;
  423. default:
  424. builder->AppendChars(c);
  425. continue;
  426. }
  427. }
  428. else
  429. {
  430. escape = false;
  431. }
  432. builder->AppendChars(_u('\\'));
  433. switch(c)
  434. {
  435. // Line terminators need to be escaped. \<lineTerminator> is a special case, where \\n doesn't work
  436. // since that means a '\' followed by an 'n'. We need to use \n instead.
  437. case _u('\n'):
  438. builder->AppendChars(_u('n'));
  439. break;
  440. case _u('\r'):
  441. builder->AppendChars(_u('r'));
  442. break;
  443. case _u('\x2028'):
  444. builder->AppendChars(_u("u2028"));
  445. break;
  446. case _u('\x2029'):
  447. builder->AppendChars(_u("u2029"));
  448. break;
  449. default:
  450. builder->AppendChars(c);
  451. }
  452. }
  453. }
  454. }
  455. if (!sourceOnly)
  456. {
  457. builder->AppendChars(_u('/'));
  458. // Cross-browser compatibility - flags are listed in alphabetical order in the spec and by other browsers
  459. // If you change the order of the flags, don't forget to change it in EntryGetterFlags() and GetOptions() too.
  460. if (pattern->IsGlobal())
  461. {
  462. builder->AppendChars(_u('g'));
  463. }
  464. if (pattern->IsIgnoreCase())
  465. {
  466. builder->AppendChars(_u('i'));
  467. }
  468. if (pattern->IsMultiline())
  469. {
  470. builder->AppendChars(_u('m'));
  471. }
  472. if (pattern->IsUnicode())
  473. {
  474. builder->AppendChars(_u('u'));
  475. }
  476. if (pattern->IsSticky())
  477. {
  478. builder->AppendChars(_u('y'));
  479. }
  480. }
  481. return builder;
  482. }
  483. Var JavascriptRegExp::EntryCompile(RecyclableObject* function, CallInfo callInfo, ...)
  484. {
  485. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  486. ARGUMENTS(args, callInfo);
  487. ScriptContext* scriptContext = function->GetScriptContext();
  488. JavascriptRegExp* thisRegularExpression = GetJavascriptRegExp(args, _u("RegExp.prototype.compile"), scriptContext);
  489. UnifiedRegex::RegexPattern* pattern;
  490. UnifiedRegex::RegexPattern* splitPattern = nullptr;
  491. if (callInfo.Count == 1 )
  492. {
  493. pattern = scriptContext->GetLibrary()->GetEmptyRegexPattern();
  494. }
  495. else if (JavascriptRegExp::Is(args[1]))
  496. {
  497. JavascriptRegExp* source = JavascriptRegExp::FromVar(args[1]);
  498. //compile with a regular expression
  499. pattern = source->GetPattern();
  500. splitPattern = source->GetSplitPattern();
  501. // second arg must be undefined if a reg expression is passed
  502. if(callInfo.Count > 2 && JavascriptOperators::GetTypeId(args[2]) != TypeIds_Undefined)
  503. {
  504. JavascriptError::ThrowSyntaxError(scriptContext, JSERR_RegExpSyntax);
  505. }
  506. }
  507. else
  508. {
  509. //compile with a string
  510. JavascriptString * strBody;
  511. if (JavascriptString::Is(args[1]))
  512. {
  513. strBody = JavascriptString::FromVar(args[1]);
  514. }
  515. else if(JavascriptOperators::GetTypeId(args[1]) == TypeIds_Undefined)
  516. {
  517. strBody = scriptContext->GetLibrary()->GetEmptyString();
  518. }
  519. else
  520. {
  521. strBody = JavascriptConversion::ToString(args[1], scriptContext);
  522. }
  523. int cBody = strBody->GetLength();
  524. const char16 *szRegex = strBody->GetSz(); // must be null terminated!
  525. int cOpts = 0;
  526. const char16 *szOptions = nullptr;
  527. JavascriptString * strOptions = nullptr;
  528. if (callInfo.Count > 2 && !JavascriptOperators::IsUndefinedObject(args[2]))
  529. {
  530. if (JavascriptString::Is(args[2]))
  531. {
  532. strOptions = JavascriptString::FromVar(args[2]);
  533. }
  534. else
  535. {
  536. strOptions = JavascriptConversion::ToString(args[2], scriptContext);
  537. }
  538. szOptions = strOptions->GetSz(); // must be null terminated!
  539. cOpts = strOptions->GetLength();
  540. }
  541. pattern = RegexHelper::CompileDynamic(scriptContext, szRegex, cBody, szOptions, cOpts, false);
  542. }
  543. thisRegularExpression->SetPattern(pattern);
  544. thisRegularExpression->SetSplitPattern(splitPattern);
  545. thisRegularExpression->SetLastIndex(0);
  546. return thisRegularExpression;
  547. }
  548. Var JavascriptRegExp::OP_NewRegEx(Var aCompiledRegex, ScriptContext* scriptContext)
  549. {
  550. JavascriptRegExp * pNewInstance =
  551. RecyclerNew(scriptContext->GetRecycler(),JavascriptRegExp,((UnifiedRegex::RegexPattern*)aCompiledRegex),
  552. scriptContext->GetLibrary()->GetRegexType());
  553. return pNewInstance;
  554. }
  555. Var JavascriptRegExp::EntryExec(RecyclableObject* function, CallInfo callInfo, ...)
  556. {
  557. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  558. ARGUMENTS(args, callInfo);
  559. ScriptContext* scriptContext = function->GetScriptContext();
  560. Assert(!(callInfo.Flags & CallFlags_New));
  561. JavascriptRegExp * pRegEx = GetJavascriptRegExp(args, _u("RegExp.prototype.exec"), scriptContext);
  562. JavascriptString * pStr = GetFirstStringArg(args, scriptContext);
  563. return RegexHelper::RegexExec(scriptContext, pRegEx, pStr, RegexHelper::IsResultNotUsed(callInfo.Flags));
  564. }
  565. Var JavascriptRegExp::EntryTest(RecyclableObject* function, CallInfo callInfo, ...)
  566. {
  567. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  568. ARGUMENTS(args, callInfo);
  569. ScriptContext* scriptContext = function->GetScriptContext();
  570. Assert(!(callInfo.Flags & CallFlags_New));
  571. RecyclableObject *thisObj = GetThisObject(args, _u("RegExp.prototype.test"), scriptContext);
  572. JavascriptString* string = GetFirstStringArg(args, scriptContext);
  573. return RegexHelper::RegexTest(scriptContext, thisObj, string);
  574. }
  575. Var JavascriptRegExp::EntryToString(RecyclableObject* function, CallInfo callInfo, ...)
  576. {
  577. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  578. ARGUMENTS(args, callInfo);
  579. ScriptContext* scriptContext = function->GetScriptContext();
  580. Assert(!(callInfo.Flags & CallFlags_New));
  581. Assert(args.Info.Count > 0);
  582. PCWSTR const varName = _u("RegExp.prototype.toString");
  583. const ScriptConfiguration* scriptConfig = scriptContext->GetConfig();
  584. if (scriptConfig->IsES6RegExPrototypePropertiesEnabled())
  585. {
  586. RecyclableObject *thisObj = GetThisObject(args, varName, scriptContext);
  587. JavascriptString* source = JavascriptConversion::ToString(
  588. JavascriptOperators::GetProperty(thisObj, PropertyIds::source, scriptContext),
  589. scriptContext);
  590. JavascriptString* flags = JavascriptConversion::ToString(
  591. JavascriptOperators::GetProperty(thisObj, PropertyIds::flags, scriptContext),
  592. scriptContext);
  593. CharCount length = source->GetLength() + flags->GetLength() + 2; // 2 for the two '/'s
  594. CompoundString *const builder =
  595. CompoundString::NewWithCharCapacity(length, scriptContext->GetLibrary());
  596. builder->Append(_u('/'));
  597. builder->Append(source);
  598. builder->Append(_u('/'));
  599. builder->Append(flags);
  600. return builder;
  601. }
  602. else
  603. {
  604. JavascriptRegExp* obj = GetJavascriptRegExp(args, varName, scriptContext);
  605. bool sourceOnly = false;
  606. return obj->ToString(sourceOnly);
  607. }
  608. }
  609. Var JavascriptRegExp::EntrySymbolMatch(RecyclableObject* function, CallInfo callInfo, ...)
  610. {
  611. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  612. ARGUMENTS(args, callInfo);
  613. Assert(!(callInfo.Flags & CallFlags_New));
  614. ScriptContext* scriptContext = function->GetScriptContext();
  615. CHAKRATEL_LANGSTATS_INC_LANGFEATURECOUNT(ES6, RegexSymbolMatch, scriptContext);
  616. PCWSTR const varName = _u("RegExp.prototype[Symbol.match]");
  617. RecyclableObject *thisObj = GetThisObject(args, varName, scriptContext);
  618. JavascriptString* string = GetFirstStringArg(args, scriptContext);
  619. return RegexHelper::RegexMatch(
  620. scriptContext,
  621. thisObj,
  622. string,
  623. RegexHelper::IsResultNotUsed(callInfo.Flags));
  624. }
  625. bool JavascriptRegExp::HasOriginalRegExType(RecyclableObject* instance)
  626. {
  627. JavascriptLibrary* library = instance->GetLibrary();
  628. if (instance->GetType() != library->GetRegexType())
  629. {
  630. return false;
  631. }
  632. DynamicObject* regexPrototype = library->GetRegExpPrototype();
  633. return JavascriptOperators::GetPrototype(instance) == regexPrototype
  634. && regexPrototype->GetType() == library->GetRegexPrototypeType();
  635. }
  636. bool JavascriptRegExp::HasObservableConstructor(DynamicObject* regexPrototype)
  637. {
  638. JavascriptLibrary* library = regexPrototype->GetLibrary();
  639. return regexPrototype->GetSlot(library->GetRegexConstructorSlotIndex()) != library->GetRegExpConstructor();
  640. }
  641. bool JavascriptRegExp::HasObservableExec(DynamicObject* regexPrototype)
  642. {
  643. JavascriptLibrary* library = regexPrototype->GetLibrary();
  644. return regexPrototype->GetSlot(library->GetRegexExecSlotIndex()) != library->GetRegexExecFunction();
  645. }
  646. bool JavascriptRegExp::HasObservableFlags(DynamicObject* regexPrototype)
  647. {
  648. JavascriptLibrary* library = regexPrototype->GetLibrary();
  649. return regexPrototype->GetScriptContext()->GetConfig()->IsES6RegExPrototypePropertiesEnabled()
  650. && regexPrototype->GetSlot(library->GetRegexFlagsGetterSlotIndex()) != library->GetRegexFlagsGetterFunction();
  651. }
  652. bool JavascriptRegExp::HasObservableGlobalFlag(DynamicObject* regexPrototype)
  653. {
  654. JavascriptLibrary* library = regexPrototype->GetLibrary();
  655. return regexPrototype->GetScriptContext()->GetConfig()->IsES6RegExPrototypePropertiesEnabled()
  656. && regexPrototype->GetSlot(library->GetRegexGlobalGetterSlotIndex()) != library->GetRegexGlobalGetterFunction();
  657. }
  658. bool JavascriptRegExp::HasObservableUnicodeFlag(DynamicObject* regexPrototype)
  659. {
  660. const ScriptConfiguration* scriptConfig = regexPrototype->GetScriptContext()->GetConfig();
  661. JavascriptLibrary* library = regexPrototype->GetLibrary();
  662. return scriptConfig->IsES6UnicodeExtensionsEnabled()
  663. && scriptConfig->IsES6RegExPrototypePropertiesEnabled()
  664. && regexPrototype->GetSlot(library->GetRegexUnicodeGetterSlotIndex()) != library->GetRegexUnicodeGetterFunction();
  665. }
  666. Var JavascriptRegExp::EntrySymbolReplace(RecyclableObject* function, CallInfo callInfo, ...)
  667. {
  668. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  669. ARGUMENTS(args, callInfo);
  670. Assert(!(callInfo.Flags & CallFlags_New));
  671. ScriptContext* scriptContext = function->GetScriptContext();
  672. CHAKRATEL_LANGSTATS_INC_LANGFEATURECOUNT(ES6, RegexSymbolReplace, scriptContext);
  673. PCWSTR varName = _u("RegExp.prototype[Symbol.replace]");
  674. RecyclableObject* thisObj = GetThisObject(args, varName, scriptContext);
  675. JavascriptString* string = GetFirstStringArg(args, scriptContext);
  676. Var replaceValue = (args.Info.Count > 2) ? args[2] : scriptContext->GetLibrary()->GetUndefined();
  677. if (JavascriptFunction::Is(replaceValue))
  678. {
  679. JavascriptFunction* replaceFunction = JavascriptFunction::FromVar(replaceValue);
  680. return RegexHelper::RegexReplaceFunction(scriptContext, thisObj, string, replaceFunction);
  681. }
  682. else
  683. {
  684. JavascriptString* replaceString = JavascriptConversion::ToString(replaceValue, scriptContext);
  685. return RegexHelper::RegexReplace(
  686. scriptContext,
  687. thisObj,
  688. string,
  689. replaceString,
  690. RegexHelper::IsResultNotUsed(callInfo.Flags));
  691. }
  692. }
  693. Var JavascriptRegExp::EntrySymbolSearch(RecyclableObject* function, CallInfo callInfo, ...)
  694. {
  695. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  696. ARGUMENTS(args, callInfo);
  697. Assert(!(callInfo.Flags & CallFlags_New));
  698. ScriptContext* scriptContext = function->GetScriptContext();
  699. CHAKRATEL_LANGSTATS_INC_LANGFEATURECOUNT(ES6, RegexSymbolSearch, scriptContext);
  700. PCWSTR const varName = _u("RegExp.prototype[Symbol.search]");
  701. RecyclableObject *thisObj = GetThisObject(args, varName, scriptContext);
  702. Var regEx = args[0];
  703. JavascriptString* string = GetFirstStringArg(args, scriptContext);
  704. Var previousLastIndex = JavascriptOperators::GetProperty(thisObj, PropertyIds::lastIndex, scriptContext);
  705. SetLastIndexProperty(regEx, TaggedInt::ToVarUnchecked(0), scriptContext);
  706. Var result = CallExec(thisObj, string, varName, scriptContext);
  707. SetLastIndexProperty(regEx, previousLastIndex, scriptContext);
  708. return JavascriptOperators::IsNull(result)
  709. ? TaggedInt::ToVarUnchecked(-1)
  710. : JavascriptOperators::GetProperty(RecyclableObject::FromVar(result), PropertyIds::index, scriptContext);
  711. }
  712. Var JavascriptRegExp::EntrySymbolSplit(RecyclableObject* function, CallInfo callInfo, ...)
  713. {
  714. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  715. ARGUMENTS(args, callInfo);
  716. Assert(!(callInfo.Flags & CallFlags_New));
  717. ScriptContext* scriptContext = function->GetScriptContext();
  718. CHAKRATEL_LANGSTATS_INC_LANGFEATURECOUNT(ES6, RegexSymbolSplit, scriptContext);
  719. RecyclableObject *thisObj = GetThisObject(args, _u("RegExp.prototype[Symbol.match]"), scriptContext);
  720. JavascriptString* string = GetFirstStringArg(args, scriptContext);
  721. // TODO: SPEC DEVIATION
  722. //
  723. // In RegexHelper::RegexSplit, we check if RegExp properties are overridden in order to determine
  724. // if the algorithm is observable. If it is, we go through the new ES6 algorithm, but otherwise, we
  725. // run the faster ES5 version.
  726. //
  727. // According to the spec, we're supposed to process "limit" after we use some of the RegExp properties.
  728. // However, there doesn't seem to be any reason why "limit" processing can't be pulled above the rest
  729. // in the spec. Therefore, we should see if such a spec update is OK. If not, this would have to be
  730. // moved to its correct place in the code.
  731. uint32 limit = (args.Info.Count < 3 || JavascriptOperators::IsUndefinedObject(args[2]))
  732. ? UINT_MAX
  733. : JavascriptConversion::ToUInt32(args[2], scriptContext);
  734. return RegexHelper::RegexSplit(
  735. scriptContext,
  736. thisObj,
  737. string,
  738. limit,
  739. RegexHelper::IsResultNotUsed(callInfo.Flags));
  740. }
  741. Var JavascriptRegExp::CallExec(RecyclableObject* thisObj, JavascriptString* string, PCWSTR varName, ScriptContext* scriptContext)
  742. {
  743. Var exec = JavascriptOperators::GetProperty(thisObj, PropertyIds::exec, scriptContext);
  744. if (JavascriptConversion::IsCallable(exec))
  745. {
  746. RecyclableObject* execFn = RecyclableObject::UnsafeFromVar(exec);
  747. ThreadContext * threadContext = scriptContext->GetThreadContext();
  748. Var result = threadContext->ExecuteImplicitCall(execFn, ImplicitCall_Accessor, [=]()->Js::Var
  749. {
  750. return CALL_FUNCTION(scriptContext->GetThreadContext(), execFn, CallInfo(CallFlags_Value, 2), thisObj, string);
  751. });
  752. if (!JavascriptOperators::IsObjectOrNull(result))
  753. {
  754. JavascriptError::ThrowTypeError(scriptContext, JSERR_RegExpExecInvalidReturnType, varName);
  755. }
  756. return result;
  757. }
  758. JavascriptRegExp* regExObj = ToRegExp(thisObj, varName, scriptContext);
  759. return RegexHelper::RegexExec(scriptContext, regExObj, string, false);
  760. }
  761. UnifiedRegex::RegexFlags JavascriptRegExp::SetRegexFlag(
  762. PropertyId propertyId,
  763. UnifiedRegex::RegexFlags flags,
  764. UnifiedRegex::RegexFlags flag,
  765. ScriptContext* scriptContext)
  766. {
  767. bool isEnabled = JavascriptConversion::ToBool(
  768. JavascriptOperators::GetProperty(this, propertyId, scriptContext),
  769. scriptContext);
  770. return isEnabled
  771. ? static_cast<UnifiedRegex::RegexFlags>(flags | flag)
  772. : static_cast<UnifiedRegex::RegexFlags>(flags & ~flag);
  773. }
  774. Var JavascriptRegExp::EntryGetterSymbolSpecies(RecyclableObject* function, CallInfo callInfo, ...)
  775. {
  776. ARGUMENTS(args, callInfo);
  777. Assert(args.Info.Count > 0);
  778. return args[0];
  779. }
  780. Var JavascriptRegExp::EntryGetterFlags(RecyclableObject* function, CallInfo callInfo, ...)
  781. {
  782. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  783. ARGUMENTS(args, callInfo);
  784. Assert(!(callInfo.Flags & CallFlags_New));
  785. ScriptContext* scriptContext = function->GetScriptContext();
  786. RecyclableObject *thisObj = GetThisObject(args, _u("RegExp.prototype.flags"), scriptContext);
  787. Var flags;
  788. BEGIN_TEMP_ALLOCATOR(tempAlloc, scriptContext, _u("JavascriptRegExp"))
  789. {
  790. StringBuilder<ArenaAllocator> bs(tempAlloc, 5);
  791. #define APPEND_FLAG(propertyId, flag) AppendFlagForFlagsProperty(&bs, thisObj, propertyId, flag, scriptContext)
  792. // If you change the order of the flags, don't forget to change it in GetOptions() and ToString() too.
  793. APPEND_FLAG(PropertyIds::global, _u('g'));
  794. APPEND_FLAG(PropertyIds::ignoreCase, _u('i'));
  795. APPEND_FLAG(PropertyIds::multiline, _u('m'));
  796. ScriptConfiguration const * scriptConfig = scriptContext->GetConfig();
  797. if (scriptConfig->IsES6UnicodeExtensionsEnabled())
  798. {
  799. APPEND_FLAG(PropertyIds::unicode, _u('u'));
  800. }
  801. if (scriptConfig->IsES6RegExStickyEnabled())
  802. {
  803. APPEND_FLAG(PropertyIds::sticky, _u('y'));
  804. }
  805. #undef APPEND_FLAG
  806. flags = Js::JavascriptString::NewCopyBuffer(bs.Detach(), bs.Count(), scriptContext);
  807. }
  808. END_TEMP_ALLOCATOR(tempAlloc, scriptContext);
  809. return flags;
  810. }
  811. void JavascriptRegExp::AppendFlagForFlagsProperty(
  812. StringBuilder<ArenaAllocator>* builder,
  813. RecyclableObject* thisObj,
  814. PropertyId propertyId,
  815. char16 flag,
  816. ScriptContext* scriptContext)
  817. {
  818. Var propertyValue = JavascriptOperators::GetProperty(thisObj, propertyId, scriptContext);
  819. if (JavascriptConversion::ToBoolean(propertyValue, scriptContext))
  820. {
  821. builder->Append(flag);
  822. }
  823. }
  824. Var JavascriptRegExp::EntryGetterOptions(RecyclableObject* function, CallInfo callInfo, ...)
  825. {
  826. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  827. ARGUMENTS(args, callInfo);
  828. Assert(!(callInfo.Flags & CallFlags_New));
  829. ScriptContext* scriptContext = function->GetScriptContext();
  830. if (ShouldApplyPrototypeWebWorkaround(args, scriptContext))
  831. {
  832. return scriptContext->GetLibrary()->GetUndefined();
  833. }
  834. return GetJavascriptRegExp(args, _u("RegExp.prototype.options"), scriptContext)->GetOptions();
  835. }
  836. Var JavascriptRegExp::GetOptions()
  837. {
  838. Var options;
  839. ScriptContext* scriptContext = this->GetLibrary()->GetScriptContext();
  840. BEGIN_TEMP_ALLOCATOR(tempAlloc, scriptContext, _u("JavascriptRegExp"))
  841. {
  842. StringBuilder<ArenaAllocator> bs(tempAlloc, 4);
  843. // If you change the order of the flags, don't forget to change it in EntryGetterFlags() and ToString() too.
  844. if(GetPattern()->IsGlobal())
  845. {
  846. bs.Append(_u('g'));
  847. }
  848. if(GetPattern()->IsIgnoreCase())
  849. {
  850. bs.Append(_u('i'));
  851. }
  852. if(GetPattern()->IsMultiline())
  853. {
  854. bs.Append(_u('m'));
  855. }
  856. if (GetPattern()->IsUnicode())
  857. {
  858. bs.Append(_u('u'));
  859. }
  860. if (GetPattern()->IsSticky())
  861. {
  862. bs.Append(_u('y'));
  863. }
  864. options = Js::JavascriptString::NewCopyBuffer(bs.Detach(), bs.Count(), scriptContext);
  865. }
  866. END_TEMP_ALLOCATOR(tempAlloc, scriptContext);
  867. return options;
  868. }
  869. Var JavascriptRegExp::EntryGetterSource(RecyclableObject* function, CallInfo callInfo, ...)
  870. {
  871. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  872. ARGUMENTS(args, callInfo);
  873. Assert(!(callInfo.Flags & CallFlags_New));
  874. ScriptContext* scriptContext = function->GetScriptContext();
  875. if (ShouldApplyPrototypeWebWorkaround(args, scriptContext))
  876. {
  877. return JavascriptString::NewCopyBuffer(_u("(?:)"), 4, scriptContext);
  878. }
  879. return GetJavascriptRegExp(args, _u("RegExp.prototype.source"), scriptContext)->ToString(true);
  880. }
  881. #define DEFINE_FLAG_GETTER(methodName, propertyName, patternMethodName) \
  882. Var JavascriptRegExp::##methodName##(RecyclableObject* function, CallInfo callInfo, ...) \
  883. { \
  884. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); \
  885. ARGUMENTS(args, callInfo); \
  886. Assert(!(callInfo.Flags & CallFlags_New)); \
  887. \
  888. ScriptContext* scriptContext = function->GetScriptContext(); \
  889. if (ShouldApplyPrototypeWebWorkaround(args, scriptContext)) \
  890. {\
  891. return scriptContext->GetLibrary()->GetUndefined(); \
  892. }\
  893. \
  894. JavascriptRegExp* pRegEx = GetJavascriptRegExp(args, _u("RegExp.prototype.") _u(#propertyName), scriptContext); \
  895. return pRegEx->GetLibrary()->CreateBoolean(pRegEx->GetPattern()->##patternMethodName##()); \
  896. }
  897. DEFINE_FLAG_GETTER(EntryGetterGlobal, global, IsGlobal)
  898. DEFINE_FLAG_GETTER(EntryGetterIgnoreCase, ignoreCase, IsIgnoreCase)
  899. DEFINE_FLAG_GETTER(EntryGetterMultiline, multiline, IsMultiline)
  900. DEFINE_FLAG_GETTER(EntryGetterSticky, sticky, IsSticky)
  901. DEFINE_FLAG_GETTER(EntryGetterUnicode, unicode, IsUnicode)
  902. JavascriptRegExp * JavascriptRegExp::BoxStackInstance(JavascriptRegExp * instance, bool deepCopy)
  903. {
  904. Assert(ThreadContext::IsOnStack(instance));
  905. // On the stack, the we reserved a pointer before the object as to store the boxed value
  906. JavascriptRegExp ** boxedInstanceRef = ((JavascriptRegExp **)instance) - 1;
  907. JavascriptRegExp * boxedInstance = *boxedInstanceRef;
  908. if (boxedInstance)
  909. {
  910. return boxedInstance;
  911. }
  912. Assert(instance->GetTypeHandler()->GetInlineSlotsSize() == 0);
  913. boxedInstance = RecyclerNew(instance->GetRecycler(), JavascriptRegExp, instance, deepCopy);
  914. *boxedInstanceRef = boxedInstance;
  915. return boxedInstance;
  916. }
  917. // Both 'unicode' and 'sticky' special properties could be controlled via config
  918. // flags. Below, 'sticky' is listed after 'unicode' (for no special reason).
  919. // When the 'unicode' config flag is disabled, we want 'unicode' to be excluded
  920. // from the list, but we still want 'sticky' to be included depending on its
  921. // config flag. That's the reason why we have two lists for the special property
  922. // IDs.
  923. #define DEFAULT_SPECIAL_PROPERTY_IDS \
  924. PropertyIds::lastIndex, \
  925. PropertyIds::global, \
  926. PropertyIds::multiline, \
  927. PropertyIds::ignoreCase, \
  928. PropertyIds::source, \
  929. PropertyIds::options
  930. PropertyId const JavascriptRegExp::specialPropertyIdsAll[] =
  931. {
  932. DEFAULT_SPECIAL_PROPERTY_IDS,
  933. PropertyIds::unicode,
  934. PropertyIds::sticky
  935. };
  936. PropertyId const JavascriptRegExp::specialPropertyIdsWithoutUnicode[] =
  937. {
  938. DEFAULT_SPECIAL_PROPERTY_IDS,
  939. PropertyIds::sticky
  940. };
  941. PropertyQueryFlags JavascriptRegExp::HasPropertyQuery(PropertyId propertyId, _Inout_opt_ PropertyValueInfo* info)
  942. {
  943. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  944. #define HAS_PROPERTY(ownProperty) \
  945. return (ownProperty ? PropertyQueryFlags::Property_Found : DynamicObject::HasPropertyQuery(propertyId, info));
  946. switch (propertyId)
  947. {
  948. case PropertyIds::lastIndex:
  949. return PropertyQueryFlags::Property_Found;
  950. case PropertyIds::global:
  951. case PropertyIds::multiline:
  952. case PropertyIds::ignoreCase:
  953. case PropertyIds::source:
  954. case PropertyIds::options:
  955. HAS_PROPERTY(!scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  956. case PropertyIds::unicode:
  957. HAS_PROPERTY(scriptConfig->IsES6UnicodeExtensionsEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled())
  958. case PropertyIds::sticky:
  959. HAS_PROPERTY(scriptConfig->IsES6RegExStickyEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled())
  960. default:
  961. return DynamicObject::HasPropertyQuery(propertyId, info);
  962. }
  963. #undef HAS_PROPERTY
  964. }
  965. PropertyQueryFlags JavascriptRegExp::GetPropertyReferenceQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  966. {
  967. return JavascriptRegExp::GetPropertyQuery(originalInstance, propertyId, value, info, requestContext);
  968. }
  969. PropertyQueryFlags JavascriptRegExp::GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  970. {
  971. BOOL result;
  972. if (GetPropertyBuiltIns(propertyId, value, &result))
  973. {
  974. return JavascriptConversion::BooleanToPropertyQueryFlags(result);
  975. }
  976. return DynamicObject::GetPropertyQuery(originalInstance, propertyId, value, info, requestContext);
  977. }
  978. PropertyQueryFlags JavascriptRegExp::GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  979. {
  980. BOOL result;
  981. PropertyRecord const* propertyRecord;
  982. this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
  983. if (propertyRecord != nullptr && GetPropertyBuiltIns(propertyRecord->GetPropertyId(), value, &result))
  984. {
  985. return JavascriptConversion::BooleanToPropertyQueryFlags(result);
  986. }
  987. return DynamicObject::GetPropertyQuery(originalInstance, propertyNameString, value, info, requestContext);
  988. }
  989. bool JavascriptRegExp::GetPropertyBuiltIns(PropertyId propertyId, Var* value, BOOL* result)
  990. {
  991. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  992. #define GET_FLAG(patternMethod) \
  993. if (!scriptConfig->IsES6RegExPrototypePropertiesEnabled()) \
  994. { \
  995. *value = this->GetLibrary()->CreateBoolean(this->GetPattern()->##patternMethod##()); \
  996. *result = true; \
  997. return true; \
  998. } \
  999. else \
  1000. { \
  1001. return false; \
  1002. }
  1003. switch (propertyId)
  1004. {
  1005. case PropertyIds::lastIndex:
  1006. if (this->lastIndexVar == nullptr)
  1007. {
  1008. Assert(lastIndexOrFlag <= MaxCharCount);
  1009. this->lastIndexVar = JavascriptNumber::ToVar(lastIndexOrFlag, GetScriptContext());
  1010. }
  1011. *value = this->lastIndexVar;
  1012. *result = true;
  1013. return true;
  1014. case PropertyIds::global:
  1015. GET_FLAG(IsGlobal)
  1016. case PropertyIds::multiline:
  1017. GET_FLAG(IsMultiline)
  1018. case PropertyIds::ignoreCase:
  1019. GET_FLAG(IsIgnoreCase)
  1020. case PropertyIds::unicode:
  1021. GET_FLAG(IsUnicode)
  1022. case PropertyIds::sticky:
  1023. GET_FLAG(IsSticky)
  1024. case PropertyIds::source:
  1025. if (!scriptConfig->IsES6RegExPrototypePropertiesEnabled())
  1026. {
  1027. *value = this->ToString(true);
  1028. *result = true;
  1029. return true;
  1030. }
  1031. else
  1032. {
  1033. return false;
  1034. }
  1035. case PropertyIds::options:
  1036. if (!scriptConfig->IsES6RegExPrototypePropertiesEnabled())
  1037. {
  1038. *value = GetOptions();
  1039. *result = true;
  1040. return true;
  1041. }
  1042. else
  1043. {
  1044. return false;
  1045. }
  1046. default:
  1047. return false;
  1048. }
  1049. #undef GET_FLAG
  1050. }
  1051. BOOL JavascriptRegExp::SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  1052. {
  1053. BOOL result;
  1054. if (SetPropertyBuiltIns(propertyId, value, flags, &result))
  1055. {
  1056. return result;
  1057. }
  1058. return DynamicObject::SetProperty(propertyId, value, flags, info);
  1059. }
  1060. BOOL JavascriptRegExp::SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  1061. {
  1062. BOOL result;
  1063. PropertyRecord const * propertyRecord;
  1064. this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
  1065. if (propertyRecord != nullptr && SetPropertyBuiltIns(propertyRecord->GetPropertyId(), value, flags, &result))
  1066. {
  1067. return result;
  1068. }
  1069. return DynamicObject::SetProperty(propertyNameString, value, flags, info);
  1070. }
  1071. bool JavascriptRegExp::SetPropertyBuiltIns(PropertyId propertyId, Var value, PropertyOperationFlags flags, BOOL* result)
  1072. {
  1073. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  1074. #define SET_PROPERTY(ownProperty) \
  1075. if (ownProperty) \
  1076. { \
  1077. JavascriptError::ThrowCantAssignIfStrictMode(flags, this->GetScriptContext()); \
  1078. *result = false; \
  1079. return true; \
  1080. } \
  1081. return false;
  1082. switch (propertyId)
  1083. {
  1084. case PropertyIds::lastIndex:
  1085. this->lastIndexVar = value;
  1086. lastIndexOrFlag = NotCachedValue;
  1087. *result = true;
  1088. return true;
  1089. case PropertyIds::global:
  1090. case PropertyIds::multiline:
  1091. case PropertyIds::ignoreCase:
  1092. case PropertyIds::source:
  1093. case PropertyIds::options:
  1094. SET_PROPERTY(!scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1095. case PropertyIds::unicode:
  1096. SET_PROPERTY(scriptConfig->IsES6UnicodeExtensionsEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1097. case PropertyIds::sticky:
  1098. SET_PROPERTY(scriptConfig->IsES6RegExStickyEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1099. default:
  1100. return false;
  1101. }
  1102. #undef SET_PROPERTY
  1103. }
  1104. BOOL JavascriptRegExp::InitProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  1105. {
  1106. return SetProperty(propertyId, value, flags, info);
  1107. }
  1108. BOOL JavascriptRegExp::DeleteProperty(PropertyId propertyId, PropertyOperationFlags propertyOperationFlags)
  1109. {
  1110. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  1111. #define DELETE_PROPERTY(ownProperty) \
  1112. if (ownProperty) \
  1113. { \
  1114. JavascriptError::ThrowCantDeleteIfStrictMode(propertyOperationFlags, this->GetScriptContext(), this->GetScriptContext()->GetPropertyName(propertyId)->GetBuffer()); \
  1115. return false; \
  1116. } \
  1117. return DynamicObject::DeleteProperty(propertyId, propertyOperationFlags);
  1118. switch (propertyId)
  1119. {
  1120. case PropertyIds::lastIndex:
  1121. DELETE_PROPERTY(true);
  1122. case PropertyIds::global:
  1123. case PropertyIds::multiline:
  1124. case PropertyIds::ignoreCase:
  1125. case PropertyIds::source:
  1126. case PropertyIds::options:
  1127. DELETE_PROPERTY(!scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1128. case PropertyIds::unicode:
  1129. DELETE_PROPERTY(scriptConfig->IsES6UnicodeExtensionsEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1130. case PropertyIds::sticky:
  1131. DELETE_PROPERTY(scriptConfig->IsES6RegExStickyEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1132. default:
  1133. return DynamicObject::DeleteProperty(propertyId, propertyOperationFlags);
  1134. }
  1135. #undef DELETE_PROPERTY
  1136. }
  1137. BOOL JavascriptRegExp::DeleteProperty(JavascriptString *propertyNameString, PropertyOperationFlags flags)
  1138. {
  1139. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  1140. #define DELETE_PROPERTY(ownProperty) \
  1141. if (ownProperty) \
  1142. { \
  1143. JavascriptError::ThrowCantDeleteIfStrictMode(flags, this->GetScriptContext(), propertyNameString->GetString()); \
  1144. return false; \
  1145. } \
  1146. return DynamicObject::DeleteProperty(propertyNameString, flags);
  1147. if (BuiltInPropertyRecords::lastIndex.Equals(propertyNameString))
  1148. {
  1149. DELETE_PROPERTY(true);
  1150. }
  1151. else if (BuiltInPropertyRecords::global.Equals(propertyNameString)
  1152. || BuiltInPropertyRecords::multiline.Equals(propertyNameString)
  1153. || BuiltInPropertyRecords::ignoreCase.Equals(propertyNameString)
  1154. || BuiltInPropertyRecords::source.Equals(propertyNameString)
  1155. || BuiltInPropertyRecords::options.Equals(propertyNameString))
  1156. {
  1157. DELETE_PROPERTY(!scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1158. }
  1159. else if (BuiltInPropertyRecords::unicode.Equals(propertyNameString))
  1160. {
  1161. DELETE_PROPERTY(scriptConfig->IsES6UnicodeExtensionsEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1162. }
  1163. else if (BuiltInPropertyRecords::sticky.Equals(propertyNameString))
  1164. {
  1165. DELETE_PROPERTY(scriptConfig->IsES6RegExStickyEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1166. }
  1167. else
  1168. {
  1169. return DynamicObject::DeleteProperty(propertyNameString, flags);
  1170. }
  1171. #undef DELETE_PROPERTY
  1172. }
  1173. DescriptorFlags JavascriptRegExp::GetSetter(PropertyId propertyId, Var* setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
  1174. {
  1175. DescriptorFlags result;
  1176. if (GetSetterBuiltIns(propertyId, info, &result))
  1177. {
  1178. return result;
  1179. }
  1180. return DynamicObject::GetSetter(propertyId, setterValue, info, requestContext);
  1181. }
  1182. DescriptorFlags JavascriptRegExp::GetSetter(JavascriptString* propertyNameString, Var* setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
  1183. {
  1184. DescriptorFlags result;
  1185. PropertyRecord const * propertyRecord;
  1186. this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
  1187. if (propertyRecord != nullptr && GetSetterBuiltIns(propertyRecord->GetPropertyId(), info, &result))
  1188. {
  1189. return result;
  1190. }
  1191. return DynamicObject::GetSetter(propertyNameString, setterValue, info, requestContext);
  1192. }
  1193. bool JavascriptRegExp::GetSetterBuiltIns(PropertyId propertyId, PropertyValueInfo* info, DescriptorFlags* result)
  1194. {
  1195. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  1196. #define GET_SETTER(ownProperty) \
  1197. if (ownProperty) \
  1198. { \
  1199. PropertyValueInfo::SetNoCache(info, this); \
  1200. *result = JavascriptRegExp::IsWritable(propertyId) ? WritableData : Data; \
  1201. return true; \
  1202. } \
  1203. return false;
  1204. switch (propertyId)
  1205. {
  1206. case PropertyIds::lastIndex:
  1207. GET_SETTER(true);
  1208. case PropertyIds::global:
  1209. case PropertyIds::multiline:
  1210. case PropertyIds::ignoreCase:
  1211. case PropertyIds::source:
  1212. case PropertyIds::options:
  1213. GET_SETTER(!scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1214. case PropertyIds::unicode:
  1215. GET_SETTER(scriptConfig->IsES6UnicodeExtensionsEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1216. case PropertyIds::sticky:
  1217. GET_SETTER(scriptConfig->IsES6RegExStickyEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1218. default:
  1219. return false;
  1220. }
  1221. #undef GET_SETTER
  1222. }
  1223. BOOL JavascriptRegExp::GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  1224. {
  1225. Js::InternalString str = pattern->GetSource();
  1226. stringBuilder->Append(str.GetBuffer(), str.GetLength());
  1227. return TRUE;
  1228. }
  1229. BOOL JavascriptRegExp::GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  1230. {
  1231. stringBuilder->AppendCppLiteral(JS_DIAG_TYPE_JavascriptRegExp);
  1232. return TRUE;
  1233. }
  1234. BOOL JavascriptRegExp::IsEnumerable(PropertyId propertyId)
  1235. {
  1236. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  1237. #define IS_ENUMERABLE(ownProperty) \
  1238. return (ownProperty ? false : DynamicObject::IsEnumerable(propertyId));
  1239. switch (propertyId)
  1240. {
  1241. case PropertyIds::lastIndex:
  1242. return false;
  1243. case PropertyIds::global:
  1244. case PropertyIds::multiline:
  1245. case PropertyIds::ignoreCase:
  1246. case PropertyIds::source:
  1247. case PropertyIds::options:
  1248. IS_ENUMERABLE(!scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1249. case PropertyIds::unicode:
  1250. IS_ENUMERABLE(scriptConfig->IsES6UnicodeExtensionsEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1251. case PropertyIds::sticky:
  1252. IS_ENUMERABLE(scriptConfig->IsES6RegExStickyEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1253. default:
  1254. return DynamicObject::IsEnumerable(propertyId);
  1255. }
  1256. #undef IS_ENUMERABLE
  1257. }
  1258. BOOL JavascriptRegExp::IsConfigurable(PropertyId propertyId)
  1259. {
  1260. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  1261. #define IS_CONFIGURABLE(ownProperty) \
  1262. return (ownProperty ? false : DynamicObject::IsConfigurable(propertyId));
  1263. switch (propertyId)
  1264. {
  1265. case PropertyIds::lastIndex:
  1266. return false;
  1267. case PropertyIds::global:
  1268. case PropertyIds::multiline:
  1269. case PropertyIds::ignoreCase:
  1270. case PropertyIds::source:
  1271. case PropertyIds::options:
  1272. IS_CONFIGURABLE(!scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1273. case PropertyIds::unicode:
  1274. IS_CONFIGURABLE(scriptConfig->IsES6UnicodeExtensionsEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1275. case PropertyIds::sticky:
  1276. IS_CONFIGURABLE(scriptConfig->IsES6RegExStickyEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1277. default:
  1278. return DynamicObject::IsConfigurable(propertyId);
  1279. }
  1280. #undef IS_CONFIGURABLE
  1281. }
  1282. BOOL JavascriptRegExp::IsWritable(PropertyId propertyId)
  1283. {
  1284. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  1285. #define IS_WRITABLE(ownProperty) \
  1286. return (ownProperty ? false : DynamicObject::IsWritable(propertyId));
  1287. switch (propertyId)
  1288. {
  1289. case PropertyIds::lastIndex:
  1290. return true;
  1291. case PropertyIds::global:
  1292. case PropertyIds::multiline:
  1293. case PropertyIds::ignoreCase:
  1294. case PropertyIds::source:
  1295. case PropertyIds::options:
  1296. IS_WRITABLE(!scriptConfig->IsES6RegExPrototypePropertiesEnabled())
  1297. case PropertyIds::unicode:
  1298. IS_WRITABLE(scriptConfig->IsES6UnicodeExtensionsEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1299. case PropertyIds::sticky:
  1300. IS_WRITABLE(scriptConfig->IsES6RegExStickyEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1301. default:
  1302. return DynamicObject::IsWritable(propertyId);
  1303. }
  1304. #undef IS_WRITABLE
  1305. }
  1306. BOOL JavascriptRegExp::GetSpecialPropertyName(uint32 index, JavascriptString ** propertyName, ScriptContext * requestContext)
  1307. {
  1308. uint length = GetSpecialPropertyCount();
  1309. if (index < length)
  1310. {
  1311. *propertyName = requestContext->GetPropertyString(GetSpecialPropertyIdsInlined()[index]);
  1312. return true;
  1313. }
  1314. return false;
  1315. }
  1316. // Returns the number of special non-enumerable properties this type has.
  1317. uint JavascriptRegExp::GetSpecialPropertyCount() const
  1318. {
  1319. if (GetScriptContext()->GetConfig()->IsES6RegExPrototypePropertiesEnabled())
  1320. {
  1321. return 1; // lastIndex
  1322. }
  1323. uint specialPropertyCount = defaultSpecialPropertyIdsCount;
  1324. if (GetScriptContext()->GetConfig()->IsES6UnicodeExtensionsEnabled())
  1325. {
  1326. specialPropertyCount += 1;
  1327. }
  1328. if (GetScriptContext()->GetConfig()->IsES6RegExStickyEnabled())
  1329. {
  1330. specialPropertyCount += 1;
  1331. }
  1332. return specialPropertyCount;
  1333. }
  1334. // Returns the list of special non-enumerable properties for the type.
  1335. PropertyId const * JavascriptRegExp::GetSpecialPropertyIds() const
  1336. {
  1337. return GetSpecialPropertyIdsInlined();
  1338. }
  1339. inline PropertyId const * JavascriptRegExp::GetSpecialPropertyIdsInlined() const
  1340. {
  1341. return GetScriptContext()->GetConfig()->IsES6UnicodeExtensionsEnabled()
  1342. ? specialPropertyIdsAll
  1343. : specialPropertyIdsWithoutUnicode;
  1344. }
  1345. #if ENABLE_TTD
  1346. TTD::NSSnapObjects::SnapObjectType JavascriptRegExp::GetSnapTag_TTD() const
  1347. {
  1348. return TTD::NSSnapObjects::SnapObjectType::SnapRegexObject;
  1349. }
  1350. void JavascriptRegExp::ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc)
  1351. {
  1352. TTD::NSSnapObjects::SnapRegexInfo* sri = alloc.SlabAllocateStruct<TTD::NSSnapObjects::SnapRegexInfo>();
  1353. UnifiedRegex::RegexPattern* pattern = this->pattern;
  1354. alloc.CopyStringIntoWLength(pattern->GetSource().GetBuffer(), pattern->GetSource().GetLength(), sri->RegexStr);
  1355. //split regex should be automatically generated from regex string and flags so no need to exttract it as well
  1356. sri->Flags = this->GetFlags();
  1357. sri->LastIndexVar = TTD_CONVERT_JSVAR_TO_TTDVAR(this->lastIndexVar);
  1358. sri->LastIndexOrFlag = this->lastIndexOrFlag;
  1359. TTD::NSSnapObjects::StdExtractSetKindSpecificInfo<TTD::NSSnapObjects::SnapRegexInfo*, TTD::NSSnapObjects::SnapObjectType::SnapRegexObject>(objData, sri);
  1360. }
  1361. void JavascriptRegExp::SetLastIndexInfo_TTD(CharCount lastIndex, Js::Var lastVar)
  1362. {
  1363. this->lastIndexOrFlag = lastIndex;
  1364. this->lastIndexVar = lastVar;
  1365. }
  1366. #endif
  1367. } // namespace Js