Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(104)

Side by Side Diff: src/code-stub-assembler.cc

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

Powered by Google App Engine
This is Rietveld 408576698