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