Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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 #include "src/code-stub-assembler.h" | 4 #include "src/code-stub-assembler.h" |
| 5 #include "src/code-factory.h" | 5 #include "src/code-factory.h" |
| 6 #include "src/frames-inl.h" | 6 #include "src/frames-inl.h" |
| 7 #include "src/frames.h" | 7 #include "src/frames.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| (...skipping 2894 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2905 Int32Constant(kOneByteStringTag)); | 2905 Int32Constant(kOneByteStringTag)); |
| 2906 } | 2906 } |
| 2907 | 2907 |
| 2908 Node* CodeStubAssembler::IsSequentialStringInstanceType(Node* instance_type) { | 2908 Node* CodeStubAssembler::IsSequentialStringInstanceType(Node* instance_type) { |
| 2909 CSA_ASSERT(this, IsStringInstanceType(instance_type)); | 2909 CSA_ASSERT(this, IsStringInstanceType(instance_type)); |
| 2910 return Word32Equal( | 2910 return Word32Equal( |
| 2911 Word32And(instance_type, Int32Constant(kStringRepresentationMask)), | 2911 Word32And(instance_type, Int32Constant(kStringRepresentationMask)), |
| 2912 Int32Constant(kSeqStringTag)); | 2912 Int32Constant(kSeqStringTag)); |
| 2913 } | 2913 } |
| 2914 | 2914 |
| 2915 Node* CodeStubAssembler::IsExternalStringInstanceType(Node* instance_type) { | |
| 2916 CSA_ASSERT(this, IsStringInstanceType(instance_type)); | |
| 2917 return Word32Equal( | |
| 2918 Word32And(instance_type, Int32Constant(kStringRepresentationMask)), | |
| 2919 Int32Constant(kExternalStringTag)); | |
| 2920 } | |
| 2921 | |
| 2922 Node* CodeStubAssembler::IsShortExternalStringInstanceType( | |
| 2923 Node* instance_type) { | |
| 2924 CSA_ASSERT(this, IsStringInstanceType(instance_type)); | |
| 2925 STATIC_ASSERT(kShortExternalStringTag != 0); | |
| 2926 return Word32NotEqual( | |
| 2927 Word32And(instance_type, Int32Constant(kShortExternalStringMask)), | |
| 2928 Int32Constant(0)); | |
| 2929 } | |
| 2930 | |
| 2915 Node* CodeStubAssembler::IsJSReceiverInstanceType(Node* instance_type) { | 2931 Node* CodeStubAssembler::IsJSReceiverInstanceType(Node* instance_type) { |
| 2916 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | 2932 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
| 2917 return Int32GreaterThanOrEqual(instance_type, | 2933 return Int32GreaterThanOrEqual(instance_type, |
| 2918 Int32Constant(FIRST_JS_RECEIVER_TYPE)); | 2934 Int32Constant(FIRST_JS_RECEIVER_TYPE)); |
| 2919 } | 2935 } |
| 2920 | 2936 |
| 2921 Node* CodeStubAssembler::IsJSReceiver(Node* object) { | 2937 Node* CodeStubAssembler::IsJSReceiver(Node* object) { |
| 2922 STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE); | 2938 STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE); |
| 2923 return IsJSReceiverInstanceType(LoadInstanceType(object)); | 2939 return IsJSReceiverInstanceType(LoadInstanceType(object)); |
| 2924 } | 2940 } |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3010 LoadRoot(Heap::kUnseededNumberDictionaryMapRootIndex)); | 3026 LoadRoot(Heap::kUnseededNumberDictionaryMapRootIndex)); |
| 3011 } | 3027 } |
| 3012 | 3028 |
| 3013 Node* CodeStubAssembler::IsJSFunction(Node* object) { | 3029 Node* CodeStubAssembler::IsJSFunction(Node* object) { |
| 3014 return HasInstanceType(object, JS_FUNCTION_TYPE); | 3030 return HasInstanceType(object, JS_FUNCTION_TYPE); |
| 3015 } | 3031 } |
| 3016 | 3032 |
| 3017 Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index, | 3033 Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index, |
| 3018 ParameterMode parameter_mode) { | 3034 ParameterMode parameter_mode) { |
| 3019 CSA_ASSERT(this, IsString(string)); | 3035 CSA_ASSERT(this, IsString(string)); |
| 3036 | |
| 3020 // Translate the {index} into a Word. | 3037 // Translate the {index} into a Word. |
| 3021 index = ParameterToWord(index, parameter_mode); | 3038 Node* const int_index = ParameterToWord(index, parameter_mode); |
| 3022 | 3039 |
| 3023 // We may need to loop in case of cons, thin, or sliced strings. | |
| 3024 Variable var_index(this, MachineType::PointerRepresentation(), index); | |
| 3025 Variable var_string(this, MachineRepresentation::kTagged, string); | |
| 3026 Variable var_result(this, MachineRepresentation::kWord32); | 3040 Variable var_result(this, MachineRepresentation::kWord32); |
| 3027 Variable* loop_vars[] = {&var_index, &var_string}; | 3041 |
| 3028 Label done_loop(this, &var_result), loop(this, 2, loop_vars); | 3042 Label out(this, &var_result), runtime_generic(this), runtime_external(this); |
| 3029 Goto(&loop); | 3043 |
| 3030 Bind(&loop); | 3044 ToDirectStringAssembler to_direct(state(), string); |
| 3045 Node* const direct_string = to_direct.TryToDirect(&runtime_generic); | |
| 3046 Node* const offset = IntPtrAdd(int_index, to_direct.offset()); | |
| 3047 Node* const instance_type = to_direct.instance_type(); | |
| 3048 | |
| 3049 Node* const string_data = to_direct.PointerToData(&runtime_external); | |
| 3050 | |
| 3051 // Check if the {string} is a TwoByteSeqString or a OneByteSeqString. | |
| 3052 Label if_stringistwobyte(this), if_stringisonebyte(this); | |
| 3053 Branch(IsOneByteStringInstanceType(instance_type), &if_stringisonebyte, | |
| 3054 &if_stringistwobyte); | |
| 3055 | |
| 3056 Bind(&if_stringisonebyte); | |
| 3031 { | 3057 { |
| 3032 // Load the current {index}. | 3058 var_result.Bind(Load(MachineType::Uint8(), string_data, offset)); |
| 3033 index = var_index.value(); | 3059 Goto(&out); |
| 3034 | |
| 3035 // Load the current {string}. | |
| 3036 string = var_string.value(); | |
| 3037 | |
| 3038 // Load the instance type of the {string}. | |
| 3039 Node* string_instance_type = LoadInstanceType(string); | |
| 3040 | |
| 3041 // Check if the {string} is a SeqString. | |
| 3042 Label if_stringissequential(this), if_stringisnotsequential(this); | |
| 3043 Branch(Word32Equal(Word32And(string_instance_type, | |
| 3044 Int32Constant(kStringRepresentationMask)), | |
| 3045 Int32Constant(kSeqStringTag)), | |
| 3046 &if_stringissequential, &if_stringisnotsequential); | |
| 3047 | |
| 3048 Bind(&if_stringissequential); | |
| 3049 { | |
| 3050 // Check if the {string} is a TwoByteSeqString or a OneByteSeqString. | |
| 3051 Label if_stringistwobyte(this), if_stringisonebyte(this); | |
| 3052 Branch(Word32Equal(Word32And(string_instance_type, | |
| 3053 Int32Constant(kStringEncodingMask)), | |
| 3054 Int32Constant(kTwoByteStringTag)), | |
| 3055 &if_stringistwobyte, &if_stringisonebyte); | |
| 3056 | |
| 3057 Bind(&if_stringisonebyte); | |
| 3058 { | |
| 3059 var_result.Bind( | |
| 3060 Load(MachineType::Uint8(), string, | |
| 3061 IntPtrAdd(index, IntPtrConstant(SeqOneByteString::kHeaderSize - | |
| 3062 kHeapObjectTag)))); | |
| 3063 Goto(&done_loop); | |
| 3064 } | |
| 3065 | |
| 3066 Bind(&if_stringistwobyte); | |
| 3067 { | |
| 3068 var_result.Bind( | |
| 3069 Load(MachineType::Uint16(), string, | |
| 3070 IntPtrAdd(WordShl(index, IntPtrConstant(1)), | |
| 3071 IntPtrConstant(SeqTwoByteString::kHeaderSize - | |
| 3072 kHeapObjectTag)))); | |
| 3073 Goto(&done_loop); | |
| 3074 } | |
| 3075 } | |
| 3076 | |
| 3077 Bind(&if_stringisnotsequential); | |
| 3078 { | |
| 3079 // Check if the {string} is a ConsString. | |
| 3080 Label if_stringiscons(this), if_stringisnotcons(this); | |
| 3081 Branch(Word32Equal(Word32And(string_instance_type, | |
| 3082 Int32Constant(kStringRepresentationMask)), | |
| 3083 Int32Constant(kConsStringTag)), | |
| 3084 &if_stringiscons, &if_stringisnotcons); | |
| 3085 | |
| 3086 Bind(&if_stringiscons); | |
| 3087 { | |
| 3088 // Check whether the right hand side is the empty string (i.e. if | |
| 3089 // this is really a flat string in a cons string). If that is not | |
| 3090 // the case we flatten the string first. | |
| 3091 Label if_rhsisempty(this), if_rhsisnotempty(this, Label::kDeferred); | |
| 3092 Node* rhs = LoadObjectField(string, ConsString::kSecondOffset); | |
| 3093 Branch(WordEqual(rhs, EmptyStringConstant()), &if_rhsisempty, | |
| 3094 &if_rhsisnotempty); | |
| 3095 | |
| 3096 Bind(&if_rhsisempty); | |
| 3097 { | |
| 3098 // Just operate on the left hand side of the {string}. | |
| 3099 var_string.Bind(LoadObjectField(string, ConsString::kFirstOffset)); | |
| 3100 Goto(&loop); | |
| 3101 } | |
| 3102 | |
| 3103 Bind(&if_rhsisnotempty); | |
| 3104 { | |
| 3105 // Flatten the {string} and lookup in the resulting string. | |
| 3106 var_string.Bind(CallRuntime(Runtime::kFlattenString, | |
| 3107 NoContextConstant(), string)); | |
| 3108 Goto(&loop); | |
| 3109 } | |
| 3110 } | |
| 3111 | |
| 3112 Bind(&if_stringisnotcons); | |
| 3113 { | |
| 3114 // Check if the {string} is an ExternalString. | |
| 3115 Label if_stringisexternal(this), if_stringisnotexternal(this); | |
| 3116 Branch(Word32Equal(Word32And(string_instance_type, | |
| 3117 Int32Constant(kStringRepresentationMask)), | |
| 3118 Int32Constant(kExternalStringTag)), | |
| 3119 &if_stringisexternal, &if_stringisnotexternal); | |
| 3120 | |
| 3121 Bind(&if_stringisexternal); | |
| 3122 { | |
| 3123 // Check if the {string} is a short external string. | |
| 3124 Label if_stringisnotshort(this), | |
| 3125 if_stringisshort(this, Label::kDeferred); | |
| 3126 Branch(Word32Equal(Word32And(string_instance_type, | |
| 3127 Int32Constant(kShortExternalStringMask)), | |
| 3128 Int32Constant(0)), | |
| 3129 &if_stringisnotshort, &if_stringisshort); | |
| 3130 | |
| 3131 Bind(&if_stringisnotshort); | |
| 3132 { | |
| 3133 // Load the actual resource data from the {string}. | |
| 3134 Node* string_resource_data = | |
| 3135 LoadObjectField(string, ExternalString::kResourceDataOffset, | |
| 3136 MachineType::Pointer()); | |
| 3137 | |
| 3138 // Check if the {string} is a TwoByteExternalString or a | |
| 3139 // OneByteExternalString. | |
| 3140 Label if_stringistwobyte(this), if_stringisonebyte(this); | |
| 3141 Branch(Word32Equal(Word32And(string_instance_type, | |
| 3142 Int32Constant(kStringEncodingMask)), | |
| 3143 Int32Constant(kTwoByteStringTag)), | |
| 3144 &if_stringistwobyte, &if_stringisonebyte); | |
| 3145 | |
| 3146 Bind(&if_stringisonebyte); | |
| 3147 { | |
| 3148 var_result.Bind( | |
| 3149 Load(MachineType::Uint8(), string_resource_data, index)); | |
| 3150 Goto(&done_loop); | |
| 3151 } | |
| 3152 | |
| 3153 Bind(&if_stringistwobyte); | |
| 3154 { | |
| 3155 var_result.Bind(Load(MachineType::Uint16(), string_resource_data, | |
| 3156 WordShl(index, IntPtrConstant(1)))); | |
| 3157 Goto(&done_loop); | |
| 3158 } | |
| 3159 } | |
| 3160 | |
| 3161 Bind(&if_stringisshort); | |
| 3162 { | |
| 3163 // The {string} might be compressed, call the runtime. | |
| 3164 var_result.Bind(SmiToWord32( | |
| 3165 CallRuntime(Runtime::kExternalStringGetChar, | |
| 3166 NoContextConstant(), string, SmiTag(index)))); | |
| 3167 Goto(&done_loop); | |
| 3168 } | |
| 3169 } | |
| 3170 | |
| 3171 Bind(&if_stringisnotexternal); | |
| 3172 { | |
| 3173 Label if_stringissliced(this), if_stringisthin(this); | |
| 3174 Branch( | |
| 3175 Word32Equal(Word32And(string_instance_type, | |
| 3176 Int32Constant(kStringRepresentationMask)), | |
| 3177 Int32Constant(kSlicedStringTag)), | |
| 3178 &if_stringissliced, &if_stringisthin); | |
| 3179 Bind(&if_stringissliced); | |
| 3180 { | |
| 3181 // The {string} is a SlicedString, continue with its parent. | |
| 3182 Node* string_offset = | |
| 3183 LoadAndUntagObjectField(string, SlicedString::kOffsetOffset); | |
| 3184 Node* string_parent = | |
| 3185 LoadObjectField(string, SlicedString::kParentOffset); | |
| 3186 var_index.Bind(IntPtrAdd(index, string_offset)); | |
| 3187 var_string.Bind(string_parent); | |
| 3188 Goto(&loop); | |
| 3189 } | |
| 3190 Bind(&if_stringisthin); | |
| 3191 { | |
| 3192 // The {string} is a ThinString, continue with its actual value. | |
| 3193 var_string.Bind(LoadObjectField(string, ThinString::kActualOffset)); | |
| 3194 Goto(&loop); | |
| 3195 } | |
| 3196 } | |
| 3197 } | |
| 3198 } | |
| 3199 } | 3060 } |
| 3200 | 3061 |
| 3201 Bind(&done_loop); | 3062 Bind(&if_stringistwobyte); |
| 3063 { | |
| 3064 var_result.Bind(Load(MachineType::Uint16(), string_data, | |
| 3065 WordShl(offset, IntPtrConstant(1)))); | |
| 3066 Goto(&out); | |
| 3067 } | |
| 3068 | |
| 3069 Bind(&runtime_generic); | |
| 3070 { | |
| 3071 Node* const smi_index = ParameterToTagged(index, parameter_mode); | |
| 3072 Node* const result = CallRuntime(Runtime::kStringCharCodeAtRT, | |
| 3073 NoContextConstant(), string, smi_index); | |
| 3074 var_result.Bind(SmiToWord32(result)); | |
| 3075 Goto(&out); | |
| 3076 } | |
| 3077 | |
| 3078 Bind(&runtime_external); | |
| 3079 { | |
| 3080 Node* const result = | |
| 3081 CallRuntime(Runtime::kExternalStringGetChar, NoContextConstant(), | |
| 3082 direct_string, SmiTag(offset)); | |
| 3083 var_result.Bind(SmiToWord32(result)); | |
| 3084 Goto(&out); | |
| 3085 } | |
| 3086 | |
| 3087 Bind(&out); | |
| 3202 return var_result.value(); | 3088 return var_result.value(); |
| 3203 } | 3089 } |
| 3204 | 3090 |
| 3205 Node* CodeStubAssembler::StringFromCharCode(Node* code) { | 3091 Node* CodeStubAssembler::StringFromCharCode(Node* code) { |
| 3206 Variable var_result(this, MachineRepresentation::kTagged); | 3092 Variable var_result(this, MachineRepresentation::kTagged); |
| 3207 | 3093 |
| 3208 // Check if the {code} is a one-byte char code. | 3094 // Check if the {code} is a one-byte char code. |
| 3209 Label if_codeisonebyte(this), if_codeistwobyte(this, Label::kDeferred), | 3095 Label if_codeisonebyte(this), if_codeistwobyte(this, Label::kDeferred), |
| 3210 if_done(this); | 3096 if_done(this); |
| 3211 Branch(Int32LessThanOrEqual(code, Int32Constant(String::kMaxOneByteCharCode)), | 3097 Branch(Int32LessThanOrEqual(code, Int32Constant(String::kMaxOneByteCharCode)), |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3310 } | 3196 } |
| 3311 | 3197 |
| 3312 a->Bind(&end); | 3198 a->Bind(&end); |
| 3313 return var_result.value(); | 3199 return var_result.value(); |
| 3314 } | 3200 } |
| 3315 | 3201 |
| 3316 } // namespace | 3202 } // namespace |
| 3317 | 3203 |
| 3318 Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, | 3204 Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, |
| 3319 Node* to) { | 3205 Node* to) { |
| 3320 Label end(this); | 3206 Variable var_result(this, MachineRepresentation::kTagged); |
| 3321 Label runtime(this); | 3207 ToDirectStringAssembler to_direct(state(), string); |
| 3322 | 3208 Label end(this), runtime(this); |
| 3323 Node* const int_zero = Int32Constant(0); | |
| 3324 | |
| 3325 // Int32 variables. | |
| 3326 Variable var_instance_type(this, MachineRepresentation::kWord32, int_zero); | |
| 3327 Variable var_representation(this, MachineRepresentation::kWord32, int_zero); | |
| 3328 | |
| 3329 Variable var_from(this, MachineRepresentation::kTagged, from); // Smi. | |
| 3330 Variable var_string(this, MachineRepresentation::kTagged, string); // String. | |
| 3331 Variable var_result(this, MachineRepresentation::kTagged); // String. | |
| 3332 | 3209 |
| 3333 // Make sure first argument is a string. | 3210 // Make sure first argument is a string. |
| 3334 CSA_ASSERT(this, TaggedIsNotSmi(string)); | 3211 CSA_ASSERT(this, TaggedIsNotSmi(string)); |
| 3335 CSA_ASSERT(this, IsString(string)); | 3212 CSA_ASSERT(this, IsString(string)); |
| 3336 | 3213 |
| 3337 // Load the instance type of the {string}. | |
| 3338 Node* const instance_type = LoadInstanceType(string); | |
| 3339 var_instance_type.Bind(instance_type); | |
| 3340 | |
| 3341 // Make sure that both from and to are non-negative smis. | 3214 // Make sure that both from and to are non-negative smis. |
| 3342 | 3215 |
| 3343 GotoIfNot(TaggedIsPositiveSmi(from), &runtime); | 3216 GotoIfNot(TaggedIsPositiveSmi(from), &runtime); |
| 3344 GotoIfNot(TaggedIsPositiveSmi(to), &runtime); | 3217 GotoIfNot(TaggedIsPositiveSmi(to), &runtime); |
| 3345 | 3218 |
| 3346 Node* const substr_length = SmiSub(to, from); | 3219 Node* const substr_length = SmiSub(to, from); |
| 3347 Node* const string_length = LoadStringLength(string); | 3220 Node* const string_length = LoadStringLength(string); |
| 3348 | 3221 |
| 3349 // Begin dispatching based on substring length. | 3222 // Begin dispatching based on substring length. |
| 3350 | 3223 |
| 3351 Label original_string_or_invalid_length(this); | 3224 Label original_string_or_invalid_length(this); |
| 3352 GotoIf(SmiAboveOrEqual(substr_length, string_length), | 3225 GotoIf(SmiAboveOrEqual(substr_length, string_length), |
| 3353 &original_string_or_invalid_length); | 3226 &original_string_or_invalid_length); |
| 3354 | 3227 |
| 3355 // A real substring (substr_length < string_length). | 3228 // A real substring (substr_length < string_length). |
| 3356 | 3229 |
| 3357 Label single_char(this); | 3230 Label single_char(this); |
| 3358 GotoIf(SmiEqual(substr_length, SmiConstant(Smi::FromInt(1))), &single_char); | 3231 GotoIf(SmiEqual(substr_length, SmiConstant(Smi::FromInt(1))), &single_char); |
| 3359 | 3232 |
| 3360 // TODO(jgruber): Add an additional case for substring of length == 0? | 3233 // TODO(jgruber): Add an additional case for substring of length == 0? |
| 3361 | 3234 |
| 3362 // Deal with different string types: update the index if necessary | 3235 // Deal with different string types: update the index if necessary |
| 3363 // and put the underlying string into var_string. | 3236 // and extract the underlying string. |
| 3364 | 3237 |
| 3365 // If the string is not indirect, it can only be sequential or external. | 3238 Node* const direct_string = to_direct.TryToDirect(&runtime); |
| 3366 STATIC_ASSERT(kIsIndirectStringMask == | 3239 Node* const offset = SmiAdd(from, SmiTag(to_direct.offset())); |
|
Camillo Bruni
2017/03/14 09:06:04
Future refactoring: make offset an intptr, from wh
jgruber
2017/03/16 08:44:54
Acknowledged.
| |
| 3367 (kSlicedStringTag & kConsStringTag & kThinStringTag)); | 3240 Node* const instance_type = to_direct.instance_type(); |
| 3368 STATIC_ASSERT(kIsIndirectStringMask != 0); | |
| 3369 Label underlying_unpacked(this); | |
| 3370 GotoIf(Word32Equal( | |
| 3371 Word32And(instance_type, Int32Constant(kIsIndirectStringMask)), | |
| 3372 Int32Constant(0)), | |
| 3373 &underlying_unpacked); | |
| 3374 | |
| 3375 // The subject string is a sliced, cons, or thin string. | |
| 3376 | |
| 3377 Label thin_string(this), thin_or_sliced(this); | |
| 3378 var_representation.Bind( | |
| 3379 Word32And(instance_type, Int32Constant(kStringRepresentationMask))); | |
| 3380 GotoIf( | |
| 3381 Word32NotEqual(var_representation.value(), Int32Constant(kConsStringTag)), | |
| 3382 &thin_or_sliced); | |
| 3383 | |
| 3384 // Cons string. Check whether it is flat, then fetch first part. | |
| 3385 // Flat cons strings have an empty second part. | |
| 3386 { | |
| 3387 GotoIf(WordNotEqual(LoadObjectField(string, ConsString::kSecondOffset), | |
| 3388 EmptyStringConstant()), | |
| 3389 &runtime); | |
| 3390 | |
| 3391 Node* first_string_part = LoadObjectField(string, ConsString::kFirstOffset); | |
| 3392 var_string.Bind(first_string_part); | |
| 3393 var_instance_type.Bind(LoadInstanceType(first_string_part)); | |
| 3394 var_representation.Bind(Word32And( | |
| 3395 var_instance_type.value(), Int32Constant(kStringRepresentationMask))); | |
| 3396 | |
| 3397 // The loaded first part might be a thin string. | |
| 3398 Branch(Word32Equal(Word32And(var_instance_type.value(), | |
| 3399 Int32Constant(kIsIndirectStringMask)), | |
| 3400 Int32Constant(0)), | |
| 3401 &underlying_unpacked, &thin_string); | |
| 3402 } | |
| 3403 | |
| 3404 Bind(&thin_or_sliced); | |
| 3405 { | |
| 3406 GotoIf( | |
| 3407 Word32Equal(var_representation.value(), Int32Constant(kThinStringTag)), | |
| 3408 &thin_string); | |
| 3409 // Otherwise it's a sliced string. | |
| 3410 // Fetch parent and correct start index by offset. | |
| 3411 Node* sliced_offset = | |
| 3412 LoadObjectField(var_string.value(), SlicedString::kOffsetOffset); | |
| 3413 var_from.Bind(SmiAdd(from, sliced_offset)); | |
| 3414 | |
| 3415 Node* slice_parent = LoadObjectField(string, SlicedString::kParentOffset); | |
| 3416 var_string.Bind(slice_parent); | |
| 3417 | |
| 3418 Node* slice_parent_instance_type = LoadInstanceType(slice_parent); | |
| 3419 var_instance_type.Bind(slice_parent_instance_type); | |
| 3420 | |
| 3421 // The loaded parent might be a thin string. | |
| 3422 Branch(Word32Equal(Word32And(var_instance_type.value(), | |
| 3423 Int32Constant(kIsIndirectStringMask)), | |
| 3424 Int32Constant(0)), | |
| 3425 &underlying_unpacked, &thin_string); | |
| 3426 } | |
| 3427 | |
| 3428 Bind(&thin_string); | |
| 3429 { | |
| 3430 Node* actual_string = | |
| 3431 LoadObjectField(var_string.value(), ThinString::kActualOffset); | |
| 3432 var_string.Bind(actual_string); | |
| 3433 var_instance_type.Bind(LoadInstanceType(actual_string)); | |
| 3434 Goto(&underlying_unpacked); | |
| 3435 } | |
| 3436 | 3241 |
| 3437 // The subject string can only be external or sequential string of either | 3242 // The subject string can only be external or sequential string of either |
| 3438 // encoding at this point. | 3243 // encoding at this point. |
| 3439 Label external_string(this); | 3244 Label external_string(this); |
| 3440 Bind(&underlying_unpacked); | |
| 3441 { | 3245 { |
| 3442 if (FLAG_string_slices) { | 3246 if (FLAG_string_slices) { |
| 3443 Label copy_routine(this); | 3247 Label next(this); |
| 3444 | 3248 |
| 3445 // Short slice. Copy instead of slicing. | 3249 // Short slice. Copy instead of slicing. |
| 3446 GotoIf(SmiLessThan(substr_length, | 3250 GotoIf(SmiLessThan(substr_length, |
| 3447 SmiConstant(Smi::FromInt(SlicedString::kMinLength))), | 3251 SmiConstant(Smi::FromInt(SlicedString::kMinLength))), |
| 3448 ©_routine); | 3252 &next); |
| 3449 | 3253 |
| 3450 // Allocate new sliced string. | 3254 // Allocate new sliced string. |
| 3451 | 3255 |
| 3452 Label two_byte_slice(this); | |
| 3453 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); | |
| 3454 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | |
| 3455 | |
| 3456 Counters* counters = isolate()->counters(); | 3256 Counters* counters = isolate()->counters(); |
| 3457 IncrementCounter(counters->sub_string_native(), 1); | 3257 IncrementCounter(counters->sub_string_native(), 1); |
| 3458 | 3258 |
| 3459 GotoIf(Word32Equal(Word32And(var_instance_type.value(), | 3259 Label one_byte_slice(this), two_byte_slice(this); |
| 3460 Int32Constant(kStringEncodingMask)), | 3260 Branch(IsOneByteStringInstanceType(to_direct.instance_type()), |
| 3461 Int32Constant(0)), | 3261 &one_byte_slice, &two_byte_slice); |
| 3462 &two_byte_slice); | |
| 3463 | 3262 |
| 3464 var_result.Bind(AllocateSlicedOneByteString( | 3263 Bind(&one_byte_slice); |
| 3465 substr_length, var_string.value(), var_from.value())); | 3264 { |
| 3466 Goto(&end); | 3265 var_result.Bind( |
| 3266 AllocateSlicedOneByteString(substr_length, direct_string, offset)); | |
| 3267 Goto(&end); | |
| 3268 } | |
| 3467 | 3269 |
| 3468 Bind(&two_byte_slice); | 3270 Bind(&two_byte_slice); |
| 3271 { | |
| 3272 var_result.Bind( | |
| 3273 AllocateSlicedTwoByteString(substr_length, direct_string, offset)); | |
| 3274 Goto(&end); | |
| 3275 } | |
| 3469 | 3276 |
| 3470 var_result.Bind(AllocateSlicedTwoByteString( | 3277 Bind(&next); |
| 3471 substr_length, var_string.value(), var_from.value())); | |
| 3472 Goto(&end); | |
| 3473 | |
| 3474 Bind(©_routine); | |
| 3475 } | 3278 } |
| 3476 | 3279 |
| 3477 // The subject string can only be external or sequential string of either | 3280 // The subject string can only be external or sequential string of either |
| 3478 // encoding at this point. | 3281 // encoding at this point. |
| 3479 STATIC_ASSERT(kExternalStringTag != 0); | 3282 GotoIf(to_direct.is_external(), &external_string); |
| 3480 STATIC_ASSERT(kSeqStringTag == 0); | |
| 3481 GotoIfNot(Word32Equal(Word32And(var_instance_type.value(), | |
| 3482 Int32Constant(kExternalStringTag)), | |
| 3483 Int32Constant(0)), | |
| 3484 &external_string); | |
| 3485 | 3283 |
| 3486 var_result.Bind(AllocAndCopyStringCharacters( | 3284 var_result.Bind(AllocAndCopyStringCharacters( |
| 3487 this, context, var_string.value(), var_instance_type.value(), | 3285 this, context, direct_string, instance_type, offset, substr_length)); |
| 3488 var_from.value(), substr_length)); | |
| 3489 | 3286 |
| 3490 Counters* counters = isolate()->counters(); | 3287 Counters* counters = isolate()->counters(); |
| 3491 IncrementCounter(counters->sub_string_native(), 1); | 3288 IncrementCounter(counters->sub_string_native(), 1); |
| 3492 | 3289 |
| 3493 Goto(&end); | 3290 Goto(&end); |
| 3494 } | 3291 } |
| 3495 | 3292 |
| 3496 // Handle external string. | 3293 // Handle external string. |
| 3497 Bind(&external_string); | 3294 Bind(&external_string); |
| 3498 { | 3295 { |
| 3499 Node* const fake_sequential_string = TryDerefExternalString( | 3296 Node* const fake_sequential_string = to_direct.PointerToString(&runtime); |
| 3500 var_string.value(), var_instance_type.value(), &runtime); | |
| 3501 | 3297 |
| 3502 var_result.Bind(AllocAndCopyStringCharacters( | 3298 var_result.Bind( |
| 3503 this, context, fake_sequential_string, var_instance_type.value(), | 3299 AllocAndCopyStringCharacters(this, context, fake_sequential_string, |
| 3504 var_from.value(), substr_length)); | 3300 instance_type, offset, substr_length)); |
| 3505 | 3301 |
| 3506 Counters* counters = isolate()->counters(); | 3302 Counters* counters = isolate()->counters(); |
| 3507 IncrementCounter(counters->sub_string_native(), 1); | 3303 IncrementCounter(counters->sub_string_native(), 1); |
| 3508 | 3304 |
| 3509 Goto(&end); | 3305 Goto(&end); |
| 3510 } | 3306 } |
| 3511 | 3307 |
| 3512 // Substrings of length 1 are generated through CharCodeAt and FromCharCode. | 3308 // Substrings of length 1 are generated through CharCodeAt and FromCharCode. |
| 3513 Bind(&single_char); | 3309 Bind(&single_char); |
| 3514 { | 3310 { |
| 3515 Node* char_code = StringCharCodeAt(var_string.value(), var_from.value()); | 3311 Node* char_code = StringCharCodeAt(string, from); |
| 3516 var_result.Bind(StringFromCharCode(char_code)); | 3312 var_result.Bind(StringFromCharCode(char_code)); |
| 3517 Goto(&end); | 3313 Goto(&end); |
| 3518 } | 3314 } |
| 3519 | 3315 |
| 3520 Bind(&original_string_or_invalid_length); | 3316 Bind(&original_string_or_invalid_length); |
| 3521 { | 3317 { |
| 3522 // Longer than original string's length or negative: unsafe arguments. | 3318 // Longer than original string's length or negative: unsafe arguments. |
| 3523 GotoIf(SmiAbove(substr_length, string_length), &runtime); | 3319 GotoIf(SmiAbove(substr_length, string_length), &runtime); |
| 3524 | 3320 |
| 3525 // Equal length - check if {from, to} == {0, str.length}. | 3321 // Equal length - check if {from, to} == {0, str.length}. |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 3539 { | 3335 { |
| 3540 var_result.Bind( | 3336 var_result.Bind( |
| 3541 CallRuntime(Runtime::kSubString, context, string, from, to)); | 3337 CallRuntime(Runtime::kSubString, context, string, from, to)); |
| 3542 Goto(&end); | 3338 Goto(&end); |
| 3543 } | 3339 } |
| 3544 | 3340 |
| 3545 Bind(&end); | 3341 Bind(&end); |
| 3546 return var_result.value(); | 3342 return var_result.value(); |
| 3547 } | 3343 } |
| 3548 | 3344 |
| 3549 namespace { | 3345 ToDirectStringAssembler::ToDirectStringAssembler( |
| 3346 compiler::CodeAssemblerState* state, Node* string) | |
| 3347 : CodeStubAssembler(state), | |
| 3348 var_string_(this, MachineRepresentation::kTagged, string), | |
| 3349 var_instance_type_(this, MachineRepresentation::kWord32), | |
| 3350 var_offset_(this, MachineType::PointerRepresentation()), | |
| 3351 var_is_external_(this, MachineRepresentation::kWord32) { | |
| 3352 CSA_ASSERT(this, TaggedIsNotSmi(string)); | |
| 3353 CSA_ASSERT(this, IsString(string)); | |
| 3550 | 3354 |
| 3551 Node* IsExternalStringInstanceType(CodeStubAssembler* a, | 3355 var_string_.Bind(string); |
| 3552 Node* const instance_type) { | 3356 var_offset_.Bind(IntPtrConstant(0)); |
| 3553 CSA_ASSERT(a, a->IsStringInstanceType(instance_type)); | 3357 var_instance_type_.Bind(LoadInstanceType(string)); |
| 3554 return a->Word32Equal( | 3358 var_is_external_.Bind(Int32Constant(0)); |
| 3555 a->Word32And(instance_type, a->Int32Constant(kStringRepresentationMask)), | |
| 3556 a->Int32Constant(kExternalStringTag)); | |
| 3557 } | 3359 } |
| 3558 | 3360 |
| 3559 Node* IsShortExternalStringInstanceType(CodeStubAssembler* a, | 3361 Node* ToDirectStringAssembler::TryToDirect(Label* if_bailout) { |
| 3560 Node* const instance_type) { | 3362 VariableList vars({&var_string_, &var_offset_, &var_instance_type_}, zone()); |
| 3561 CSA_ASSERT(a, a->IsStringInstanceType(instance_type)); | 3363 Label dispatch(this, vars); |
| 3562 STATIC_ASSERT(kShortExternalStringTag != 0); | 3364 Label if_iscons(this); |
| 3563 return a->Word32NotEqual( | 3365 Label if_isexternal(this); |
| 3564 a->Word32And(instance_type, a->Int32Constant(kShortExternalStringMask)), | 3366 Label if_issliced(this); |
| 3565 a->Int32Constant(0)); | 3367 Label if_isthin(this); |
| 3566 } | |
| 3567 | |
| 3568 } // namespace | |
| 3569 | |
| 3570 void CodeStubAssembler::TryUnpackString(Variable* var_string, | |
| 3571 Variable* var_offset, | |
| 3572 Variable* var_instance_type, | |
| 3573 Label* if_bailout) { | |
| 3574 DCHECK_EQ(var_string->rep(), MachineType::PointerRepresentation()); | |
| 3575 DCHECK_EQ(var_offset->rep(), MachineType::PointerRepresentation()); | |
| 3576 DCHECK_EQ(var_instance_type->rep(), MachineRepresentation::kWord32); | |
| 3577 CSA_ASSERT(this, IsString(var_string->value())); | |
| 3578 | |
| 3579 Label out(this); | 3368 Label out(this); |
| 3580 | 3369 |
| 3581 VariableList vars({var_string, var_offset, var_instance_type}, zone()); | |
| 3582 Label dispatch(this, vars); | |
| 3583 Label if_isdirect(this); | |
| 3584 Label if_iscons(this, Label::kDeferred); | |
| 3585 Label if_isexternal(this, Label::kDeferred); | |
| 3586 Label if_issliced(this, Label::kDeferred); | |
| 3587 Label if_isthin(this, Label::kDeferred); | |
| 3588 | |
| 3589 Goto(&dispatch); | 3370 Goto(&dispatch); |
| 3590 | 3371 |
| 3591 // Dispatch based on string representation. | 3372 // Dispatch based on string representation. |
| 3592 Bind(&dispatch); | 3373 Bind(&dispatch); |
| 3593 { | 3374 { |
| 3594 int32_t values[] = { | 3375 int32_t values[] = { |
| 3595 kSeqStringTag, kConsStringTag, kExternalStringTag, | 3376 kSeqStringTag, kConsStringTag, kExternalStringTag, |
| 3596 kSlicedStringTag, kThinStringTag, | 3377 kSlicedStringTag, kThinStringTag, |
| 3597 }; | 3378 }; |
| 3598 Label* labels[] = { | 3379 Label* labels[] = { |
| 3599 &if_isdirect, &if_iscons, &if_isexternal, &if_issliced, &if_isthin, | 3380 &out, &if_iscons, &if_isexternal, &if_issliced, &if_isthin, |
| 3600 }; | 3381 }; |
| 3601 STATIC_ASSERT(arraysize(values) == arraysize(labels)); | 3382 STATIC_ASSERT(arraysize(values) == arraysize(labels)); |
| 3602 | 3383 |
| 3603 Node* const representation = Word32And( | 3384 Node* const representation = Word32And( |
| 3604 var_instance_type->value(), Int32Constant(kStringRepresentationMask)); | 3385 var_instance_type_.value(), Int32Constant(kStringRepresentationMask)); |
| 3605 Switch(representation, if_bailout, values, labels, arraysize(values)); | 3386 Switch(representation, if_bailout, values, labels, arraysize(values)); |
| 3606 } | 3387 } |
| 3607 | 3388 |
| 3608 // Cons string. Check whether it is flat, then fetch first part. | 3389 // Cons string. Check whether it is flat, then fetch first part. |
| 3609 // Flat cons strings have an empty second part. | 3390 // Flat cons strings have an empty second part. |
| 3610 Bind(&if_iscons); | 3391 Bind(&if_iscons); |
| 3611 { | 3392 { |
| 3612 Node* const string = var_string->value(); | 3393 Node* const string = var_string_.value(); |
| 3613 GotoIfNot(IsEmptyString(LoadObjectField(string, ConsString::kSecondOffset)), | 3394 GotoIfNot(IsEmptyString(LoadObjectField(string, ConsString::kSecondOffset)), |
| 3614 if_bailout); | 3395 if_bailout); |
| 3615 | 3396 |
| 3616 Node* const lhs = LoadObjectField(string, ConsString::kFirstOffset); | 3397 Node* const lhs = LoadObjectField(string, ConsString::kFirstOffset); |
| 3617 var_string->Bind(BitcastTaggedToWord(lhs)); | 3398 var_string_.Bind(lhs); |
| 3618 var_instance_type->Bind(LoadInstanceType(lhs)); | 3399 var_instance_type_.Bind(LoadInstanceType(lhs)); |
| 3619 | 3400 |
| 3620 Goto(&dispatch); | 3401 Goto(&dispatch); |
| 3621 } | 3402 } |
| 3622 | 3403 |
| 3623 // Sliced string. Fetch parent and correct start index by offset. | 3404 // Sliced string. Fetch parent and correct start index by offset. |
| 3624 Bind(&if_issliced); | 3405 Bind(&if_issliced); |
| 3625 { | 3406 { |
| 3626 Node* const string = var_string->value(); | 3407 Node* const string = var_string_.value(); |
| 3627 Node* const sliced_offset = | 3408 Node* const sliced_offset = |
| 3628 LoadObjectField(string, SlicedString::kOffsetOffset); | 3409 LoadAndUntagObjectField(string, SlicedString::kOffsetOffset); |
| 3629 var_offset->Bind(IntPtrAdd(var_offset->value(), SmiUntag(sliced_offset))); | 3410 var_offset_.Bind(IntPtrAdd(var_offset_.value(), sliced_offset)); |
| 3630 | 3411 |
| 3631 Node* const parent = LoadObjectField(string, SlicedString::kParentOffset); | 3412 Node* const parent = LoadObjectField(string, SlicedString::kParentOffset); |
| 3632 var_string->Bind(BitcastTaggedToWord(parent)); | 3413 var_string_.Bind(LoadObjectField(string, SlicedString::kParentOffset)); |
| 3633 var_instance_type->Bind(LoadInstanceType(parent)); | 3414 var_instance_type_.Bind(LoadInstanceType(parent)); |
| 3634 | 3415 |
| 3635 Goto(&dispatch); | 3416 Goto(&dispatch); |
| 3636 } | 3417 } |
| 3637 | 3418 |
| 3638 // Thin string. Fetch the actual string. | 3419 // Thin string. Fetch the actual string. |
| 3639 Bind(&if_isthin); | 3420 Bind(&if_isthin); |
| 3640 { | 3421 { |
| 3641 Node* const string = var_string->value(); | 3422 Node* const string = var_string_.value(); |
| 3642 Node* const actual_string = | 3423 Node* const actual_string = |
| 3643 LoadObjectField(string, ThinString::kActualOffset); | 3424 LoadObjectField(string, ThinString::kActualOffset); |
| 3644 Node* const actual_instance_type = LoadInstanceType(actual_string); | 3425 Node* const actual_instance_type = LoadInstanceType(actual_string); |
| 3645 CSA_ASSERT(this, IsSequentialStringInstanceType(actual_instance_type)); | 3426 CSA_ASSERT(this, IsSequentialStringInstanceType(actual_instance_type)); |
| 3646 | 3427 |
| 3647 var_string->Bind(BitcastTaggedToWord(actual_string)); | 3428 var_string_.Bind(actual_string); |
| 3648 var_instance_type->Bind(actual_instance_type); | 3429 var_instance_type_.Bind(actual_instance_type); |
| 3649 | 3430 |
| 3650 Goto(&if_isdirect); | 3431 Goto(&out); |
| 3651 } | 3432 } |
| 3652 | 3433 |
| 3653 // External string. | 3434 // External string. |
| 3654 Bind(&if_isexternal); | 3435 Bind(&if_isexternal); |
| 3436 var_is_external_.Bind(Int32Constant(1)); | |
| 3437 Goto(&out); | |
| 3438 | |
| 3439 Bind(&out); | |
| 3440 return var_string_.value(); | |
| 3441 } | |
| 3442 | |
| 3443 Node* ToDirectStringAssembler::TryToSequential(StringPointerKind ptr_kind, | |
| 3444 Label* if_bailout) { | |
| 3445 CHECK(ptr_kind == PTR_TO_DATA || ptr_kind == PTR_TO_STRING); | |
| 3446 | |
| 3447 Variable var_result(this, MachineType::PointerRepresentation()); | |
| 3448 Label out(this), if_issequential(this), if_isexternal(this); | |
| 3449 Branch(is_external(), &if_isexternal, &if_issequential); | |
| 3450 | |
| 3451 Bind(&if_issequential); | |
| 3655 { | 3452 { |
| 3656 Node* const string = var_string->value(); | 3453 STATIC_ASSERT(SeqOneByteString::kHeaderSize == |
| 3657 Node* const faked_seq_string = | 3454 SeqTwoByteString::kHeaderSize); |
| 3658 TryDerefExternalString(string, var_instance_type->value(), if_bailout); | 3455 Node* result = BitcastTaggedToWord(var_string_.value()); |
| 3659 | 3456 if (ptr_kind == PTR_TO_DATA) { |
| 3660 STATIC_ASSERT(kSeqStringTag == 0x0); | 3457 result = IntPtrAdd(result, IntPtrConstant(SeqOneByteString::kHeaderSize - |
| 3661 Node* const faked_seq_instance_type = Word32Xor( | 3458 kHeapObjectTag)); |
| 3662 var_instance_type->value(), Int32Constant(kExternalStringTag)); | 3459 } |
| 3663 CSA_ASSERT(this, IsSequentialStringInstanceType(faked_seq_instance_type)); | 3460 var_result.Bind(result); |
| 3664 | 3461 Goto(&out); |
| 3665 var_string->Bind(faked_seq_string); | |
| 3666 var_instance_type->Bind(faked_seq_instance_type); | |
| 3667 | |
| 3668 Goto(&if_isdirect); | |
| 3669 } | 3462 } |
| 3670 | 3463 |
| 3671 Bind(&if_isdirect); | 3464 Bind(&if_isexternal); |
| 3465 { | |
| 3466 GotoIf(IsShortExternalStringInstanceType(var_instance_type_.value()), | |
| 3467 if_bailout); | |
| 3468 | |
| 3469 Node* const string = var_string_.value(); | |
| 3470 Node* result = LoadObjectField(string, ExternalString::kResourceDataOffset, | |
| 3471 MachineType::Pointer()); | |
| 3472 if (ptr_kind == PTR_TO_STRING) { | |
| 3473 result = IntPtrSub(result, IntPtrConstant(SeqOneByteString::kHeaderSize - | |
| 3474 kHeapObjectTag)); | |
| 3475 } | |
| 3476 var_result.Bind(result); | |
| 3477 Goto(&out); | |
| 3478 } | |
| 3479 | |
| 3480 Bind(&out); | |
| 3481 return var_result.value(); | |
| 3672 } | 3482 } |
| 3673 | 3483 |
| 3674 Node* CodeStubAssembler::TryDerefExternalString(Node* const string, | 3484 Node* CodeStubAssembler::TryDerefExternalString(Node* const string, |
| 3675 Node* const instance_type, | 3485 Node* const instance_type, |
| 3676 Label* if_bailout) { | 3486 Label* if_bailout) { |
| 3677 Label out(this); | 3487 Label out(this); |
| 3678 | 3488 |
| 3679 USE(IsExternalStringInstanceType); | 3489 CSA_ASSERT(this, IsExternalStringInstanceType(instance_type)); |
| 3680 CSA_ASSERT(this, IsExternalStringInstanceType(this, instance_type)); | 3490 GotoIf(IsShortExternalStringInstanceType(instance_type), if_bailout); |
| 3681 GotoIf(IsShortExternalStringInstanceType(this, instance_type), if_bailout); | |
| 3682 | 3491 |
| 3683 // Move the pointer so that offset-wise, it looks like a sequential string. | 3492 // Move the pointer so that offset-wise, it looks like a sequential string. |
| 3684 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | 3493 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); |
| 3685 | 3494 |
| 3686 Node* resource_data = LoadObjectField( | 3495 Node* resource_data = LoadObjectField( |
| 3687 string, ExternalString::kResourceDataOffset, MachineType::Pointer()); | 3496 string, ExternalString::kResourceDataOffset, MachineType::Pointer()); |
| 3688 Node* const fake_sequential_string = | 3497 Node* const fake_sequential_string = |
| 3689 IntPtrSub(resource_data, | 3498 IntPtrSub(resource_data, |
| 3690 IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 3499 IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 3691 | 3500 |
| (...skipping 4731 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8423 formatted.c_str(), TENURED); | 8232 formatted.c_str(), TENURED); |
| 8424 CallRuntime(Runtime::kGlobalPrint, NoContextConstant(), | 8233 CallRuntime(Runtime::kGlobalPrint, NoContextConstant(), |
| 8425 HeapConstant(string)); | 8234 HeapConstant(string)); |
| 8426 } | 8235 } |
| 8427 CallRuntime(Runtime::kDebugPrint, NoContextConstant(), tagged_value); | 8236 CallRuntime(Runtime::kDebugPrint, NoContextConstant(), tagged_value); |
| 8428 #endif | 8237 #endif |
| 8429 } | 8238 } |
| 8430 | 8239 |
| 8431 } // namespace internal | 8240 } // namespace internal |
| 8432 } // namespace v8 | 8241 } // namespace v8 |
| OLD | NEW |