1 // Copyright 2017 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 #ifndef V8_BUILTINS_BUILTINS_REGEXP_GEN_H_ 6 #define V8_BUILTINS_BUILTINS_REGEXP_GEN_H_ 7 8 #include "src/base/optional.h" 9 #include "src/codegen/code-stub-assembler.h" 10 #include "src/common/message-template.h" 11 #include "src/regexp/regexp.h" 12 13 namespace v8 { 14 namespace internal { 15 16 class RegExpBuiltinsAssembler : public CodeStubAssembler { 17 public: RegExpBuiltinsAssembler(compiler::CodeAssemblerState * state)18 explicit RegExpBuiltinsAssembler(compiler::CodeAssemblerState* state) 19 : CodeStubAssembler(state) {} 20 21 TNode<Smi> SmiZero(); 22 TNode<IntPtrT> IntPtrZero(); 23 24 TNode<RawPtrT> LoadCodeObjectEntry(TNode<CodeT> code); 25 26 // Allocate either a JSRegExpResult or a JSRegExpResultWithIndices (depending 27 // on has_indices) with the given length (the number of captures, including 28 // the match itself), index (the index where the match starts), and input 29 // string. 30 TNode<JSRegExpResult> AllocateRegExpResult( 31 TNode<Context> context, TNode<Smi> length, TNode<Smi> index, 32 TNode<String> input, TNode<JSRegExp> regexp, TNode<Number> last_index, 33 TNode<BoolT> has_indices, TNode<FixedArray>* elements_out = nullptr); 34 35 TNode<Object> FastLoadLastIndexBeforeSmiCheck(TNode<JSRegExp> regexp); FastLoadLastIndex(TNode<JSRegExp> regexp)36 TNode<Smi> FastLoadLastIndex(TNode<JSRegExp> regexp) { 37 return CAST(FastLoadLastIndexBeforeSmiCheck(regexp)); 38 } 39 TNode<Object> SlowLoadLastIndex(TNode<Context> context, TNode<Object> regexp); 40 41 void FastStoreLastIndex(TNode<JSRegExp> regexp, TNode<Smi> value); 42 void SlowStoreLastIndex(TNode<Context> context, TNode<Object> regexp, 43 TNode<Object> value); 44 45 // Loads {var_string_start} and {var_string_end} with the corresponding 46 // offsets into the given {string_data}. 47 void GetStringPointers(TNode<RawPtrT> string_data, TNode<IntPtrT> offset, 48 TNode<IntPtrT> last_index, 49 TNode<IntPtrT> string_length, 50 String::Encoding encoding, 51 TVariable<RawPtrT>* var_string_start, 52 TVariable<RawPtrT>* var_string_end); 53 54 // Low level logic around the actual call into pattern matching code. 55 TNode<HeapObject> RegExpExecInternal( 56 TNode<Context> context, TNode<JSRegExp> regexp, TNode<String> string, 57 TNode<Number> last_index, TNode<RegExpMatchInfo> match_info, 58 RegExp::ExecQuirks exec_quirks = RegExp::ExecQuirks::kNone); 59 60 TNode<JSRegExpResult> ConstructNewResultFromMatchInfo( 61 TNode<Context> context, TNode<JSRegExp> regexp, 62 TNode<RegExpMatchInfo> match_info, TNode<String> string, 63 TNode<Number> last_index); 64 65 // Fast path check logic. 66 // 67 // Are you afraid? If not, you should be. 68 // 69 // It's complicated. Fast path checks protect certain assumptions, e.g. that 70 // relevant properties on the regexp prototype (such as exec, @@split, global) 71 // are unmodified. 72 // 73 // These assumptions differ by callsite. For example, RegExpPrototypeExec 74 // cares whether the exec property has been modified; but it's totally fine 75 // to modify other prototype properties. On the other hand, 76 // StringPrototypeSplit does care very much whether @@split has been changed. 77 // 78 // We want to keep regexp execution on the fast path as much as possible. 79 // Ideally, we could simply check if the regexp prototype has been modified; 80 // yet common web frameworks routinely mutate it for various reasons. But most 81 // of these mutations should happen in a way that still allows us to remain 82 // on the fast path. To support this, the fast path check logic necessarily 83 // becomes more involved. 84 // 85 // There are multiple knobs to twiddle for regexp fast path checks. We support 86 // checks that completely ignore the prototype, checks that verify specific 87 // properties on the prototype (the caller must ensure it passes in the right 88 // ones), and strict checks that additionally ensure the prototype is 89 // unchanged (we use these when we'd have to check multiple properties we 90 // don't care too much about, e.g. all individual flag getters). 91 92 using DescriptorIndexNameValue = 93 PrototypeCheckAssembler::DescriptorIndexNameValue; 94 95 void BranchIfFastRegExp( 96 TNode<Context> context, TNode<HeapObject> object, TNode<Map> map, 97 PrototypeCheckAssembler::Flags prototype_check_flags, 98 base::Optional<DescriptorIndexNameValue> additional_property_to_check, 99 Label* if_isunmodified, Label* if_ismodified); 100 101 void BranchIfFastRegExpForSearch(TNode<Context> context, 102 TNode<HeapObject> object, 103 Label* if_isunmodified, 104 Label* if_ismodified); 105 void BranchIfFastRegExpForMatch(TNode<Context> context, 106 TNode<HeapObject> object, 107 Label* if_isunmodified, Label* if_ismodified); 108 109 // Strict: Does not tolerate any changes to the prototype map. 110 // Permissive: Allows changes to the prototype map except for the exec 111 // property. 112 void BranchIfFastRegExp_Strict(TNode<Context> context, 113 TNode<HeapObject> object, 114 Label* if_isunmodified, Label* if_ismodified); 115 void BranchIfFastRegExp_Permissive(TNode<Context> context, 116 TNode<HeapObject> object, 117 Label* if_isunmodified, 118 Label* if_ismodified); 119 120 // Performs fast path checks on the given object itself, but omits prototype 121 // checks. 122 TNode<BoolT> IsFastRegExpNoPrototype(TNode<Context> context, 123 TNode<Object> object); 124 TNode<BoolT> IsFastRegExpNoPrototype(TNode<Context> context, 125 TNode<Object> object, TNode<Map> map); 126 127 void BranchIfRegExpResult(const TNode<Context> context, 128 const TNode<Object> object, Label* if_isunmodified, 129 Label* if_ismodified); 130 131 TNode<String> FlagsGetter(TNode<Context> context, TNode<Object> regexp, 132 const bool is_fastpath); 133 134 TNode<BoolT> FastFlagGetter(TNode<JSRegExp> regexp, JSRegExp::Flag flag); FastFlagGetterGlobal(TNode<JSRegExp> regexp)135 TNode<BoolT> FastFlagGetterGlobal(TNode<JSRegExp> regexp) { 136 return FastFlagGetter(regexp, JSRegExp::kGlobal); 137 } FastFlagGetterUnicode(TNode<JSRegExp> regexp)138 TNode<BoolT> FastFlagGetterUnicode(TNode<JSRegExp> regexp) { 139 return FastFlagGetter(regexp, JSRegExp::kUnicode); 140 } 141 TNode<BoolT> SlowFlagGetter(TNode<Context> context, TNode<Object> regexp, 142 JSRegExp::Flag flag); 143 TNode<BoolT> FlagGetter(TNode<Context> context, TNode<Object> regexp, 144 JSRegExp::Flag flag, bool is_fastpath); 145 146 TNode<Object> RegExpInitialize(const TNode<Context> context, 147 const TNode<JSRegExp> regexp, 148 const TNode<Object> maybe_pattern, 149 const TNode<Object> maybe_flags); 150 151 TNode<Number> AdvanceStringIndex(TNode<String> string, TNode<Number> index, 152 TNode<BoolT> is_unicode, bool is_fastpath); 153 AdvanceStringIndexFast(TNode<String> string,TNode<Smi> index,TNode<BoolT> is_unicode)154 TNode<Smi> AdvanceStringIndexFast(TNode<String> string, TNode<Smi> index, 155 TNode<BoolT> is_unicode) { 156 return CAST(AdvanceStringIndex(string, index, is_unicode, true)); 157 } 158 AdvanceStringIndexSlow(TNode<String> string,TNode<Number> index,TNode<BoolT> is_unicode)159 TNode<Smi> AdvanceStringIndexSlow(TNode<String> string, TNode<Number> index, 160 TNode<BoolT> is_unicode) { 161 return CAST(AdvanceStringIndex(string, index, is_unicode, false)); 162 } 163 164 TNode<JSArray> RegExpPrototypeSplitBody(TNode<Context> context, 165 TNode<JSRegExp> regexp, 166 const TNode<String> string, 167 const TNode<Smi> limit); 168 }; 169 170 class RegExpMatchAllAssembler : public RegExpBuiltinsAssembler { 171 public: RegExpMatchAllAssembler(compiler::CodeAssemblerState * state)172 explicit RegExpMatchAllAssembler(compiler::CodeAssemblerState* state) 173 : RegExpBuiltinsAssembler(state) {} 174 175 TNode<Object> CreateRegExpStringIterator(TNode<NativeContext> native_context, 176 TNode<Object> regexp, 177 TNode<String> string, 178 TNode<BoolT> global, 179 TNode<BoolT> full_unicode); 180 }; 181 182 } // namespace internal 183 } // namespace v8 184 185 #endif // V8_BUILTINS_BUILTINS_REGEXP_GEN_H_ 186