OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 | 4 |
5 #if V8_TARGET_ARCH_ARM64 | 5 #if V8_TARGET_ARCH_ARM64 |
6 | 6 |
7 #include "src/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/code-stubs.h" | 9 #include "src/code-stubs.h" |
10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
(...skipping 3225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3236 ZoneList<Expression*>* args = expr->arguments(); | 3236 ZoneList<Expression*>* args = expr->arguments(); |
3237 DCHECK_EQ(1, args->length()); | 3237 DCHECK_EQ(1, args->length()); |
3238 VisitForAccumulatorValue(args->at(0)); | 3238 VisitForAccumulatorValue(args->at(0)); |
3239 __ AssertFunction(x0); | 3239 __ AssertFunction(x0); |
3240 __ Ldr(x0, FieldMemOperand(x0, HeapObject::kMapOffset)); | 3240 __ Ldr(x0, FieldMemOperand(x0, HeapObject::kMapOffset)); |
3241 __ Ldr(x0, FieldMemOperand(x0, Map::kPrototypeOffset)); | 3241 __ Ldr(x0, FieldMemOperand(x0, Map::kPrototypeOffset)); |
3242 context()->Plug(x0); | 3242 context()->Plug(x0); |
3243 } | 3243 } |
3244 | 3244 |
3245 | 3245 |
3246 void FullCodeGenerator::EmitFastOneByteArrayJoin(CallRuntime* expr) { | |
3247 ASM_LOCATION("FullCodeGenerator::EmitFastOneByteArrayJoin"); | |
3248 | |
3249 ZoneList<Expression*>* args = expr->arguments(); | |
3250 DCHECK(args->length() == 2); | |
3251 VisitForStackValue(args->at(1)); | |
3252 VisitForAccumulatorValue(args->at(0)); | |
3253 | |
3254 Register array = x0; | |
3255 Register result = x0; | |
3256 Register elements = x1; | |
3257 Register element = x2; | |
3258 Register separator = x3; | |
3259 Register array_length = x4; | |
3260 Register result_pos = x5; | |
3261 Register map = x6; | |
3262 Register string_length = x10; | |
3263 Register elements_end = x11; | |
3264 Register string = x12; | |
3265 Register scratch1 = x13; | |
3266 Register scratch2 = x14; | |
3267 Register scratch3 = x7; | |
3268 Register separator_length = x15; | |
3269 | |
3270 Label bailout, done, one_char_separator, long_separator, | |
3271 non_trivial_array, not_size_one_array, loop, | |
3272 empty_separator_loop, one_char_separator_loop, | |
3273 one_char_separator_loop_entry, long_separator_loop; | |
3274 | |
3275 // The separator operand is on the stack. | |
3276 __ Pop(separator); | |
3277 | |
3278 // Check that the array is a JSArray. | |
3279 __ JumpIfSmi(array, &bailout); | |
3280 __ JumpIfNotObjectType(array, map, scratch1, JS_ARRAY_TYPE, &bailout); | |
3281 | |
3282 // Check that the array has fast elements. | |
3283 __ CheckFastElements(map, scratch1, &bailout); | |
3284 | |
3285 // If the array has length zero, return the empty string. | |
3286 // Load and untag the length of the array. | |
3287 // It is an unsigned value, so we can skip sign extension. | |
3288 // We assume little endianness. | |
3289 __ Ldrsw(array_length, | |
3290 UntagSmiFieldMemOperand(array, JSArray::kLengthOffset)); | |
3291 __ Cbnz(array_length, &non_trivial_array); | |
3292 __ LoadRoot(result, Heap::kempty_stringRootIndex); | |
3293 __ B(&done); | |
3294 | |
3295 __ Bind(&non_trivial_array); | |
3296 // Get the FixedArray containing array's elements. | |
3297 __ Ldr(elements, FieldMemOperand(array, JSArray::kElementsOffset)); | |
3298 | |
3299 // Check that all array elements are sequential one-byte strings, and | |
3300 // accumulate the sum of their lengths. | |
3301 __ Mov(string_length, 0); | |
3302 __ Add(element, elements, FixedArray::kHeaderSize - kHeapObjectTag); | |
3303 __ Add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2)); | |
3304 // Loop condition: while (element < elements_end). | |
3305 // Live values in registers: | |
3306 // elements: Fixed array of strings. | |
3307 // array_length: Length of the fixed array of strings (not smi) | |
3308 // separator: Separator string | |
3309 // string_length: Accumulated sum of string lengths (not smi). | |
3310 // element: Current array element. | |
3311 // elements_end: Array end. | |
3312 if (FLAG_debug_code) { | |
3313 __ Cmp(array_length, 0); | |
3314 __ Assert(gt, kNoEmptyArraysHereInEmitFastOneByteArrayJoin); | |
3315 } | |
3316 __ Bind(&loop); | |
3317 __ Ldr(string, MemOperand(element, kPointerSize, PostIndex)); | |
3318 __ JumpIfSmi(string, &bailout); | |
3319 __ Ldr(scratch1, FieldMemOperand(string, HeapObject::kMapOffset)); | |
3320 __ Ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); | |
3321 __ JumpIfInstanceTypeIsNotSequentialOneByte(scratch1, scratch2, &bailout); | |
3322 __ Ldrsw(scratch1, | |
3323 UntagSmiFieldMemOperand(string, SeqOneByteString::kLengthOffset)); | |
3324 __ Adds(string_length, string_length, scratch1); | |
3325 __ B(vs, &bailout); | |
3326 __ Cmp(element, elements_end); | |
3327 __ B(lt, &loop); | |
3328 | |
3329 // If array_length is 1, return elements[0], a string. | |
3330 __ Cmp(array_length, 1); | |
3331 __ B(ne, ¬_size_one_array); | |
3332 __ Ldr(result, FieldMemOperand(elements, FixedArray::kHeaderSize)); | |
3333 __ B(&done); | |
3334 | |
3335 __ Bind(¬_size_one_array); | |
3336 | |
3337 // Live values in registers: | |
3338 // separator: Separator string | |
3339 // array_length: Length of the array (not smi). | |
3340 // string_length: Sum of string lengths (not smi). | |
3341 // elements: FixedArray of strings. | |
3342 | |
3343 // Check that the separator is a flat one-byte string. | |
3344 __ JumpIfSmi(separator, &bailout); | |
3345 __ Ldr(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset)); | |
3346 __ Ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); | |
3347 __ JumpIfInstanceTypeIsNotSequentialOneByte(scratch1, scratch2, &bailout); | |
3348 | |
3349 // Add (separator length times array_length) - separator length to the | |
3350 // string_length to get the length of the result string. | |
3351 // Load the separator length as untagged. | |
3352 // We assume little endianness, and that the length is positive. | |
3353 __ Ldrsw(separator_length, | |
3354 UntagSmiFieldMemOperand(separator, | |
3355 SeqOneByteString::kLengthOffset)); | |
3356 __ Sub(string_length, string_length, separator_length); | |
3357 __ Umaddl(string_length, array_length.W(), separator_length.W(), | |
3358 string_length); | |
3359 | |
3360 // Bailout for large object allocations. | |
3361 __ Cmp(string_length, Page::kMaxRegularHeapObjectSize); | |
3362 __ B(gt, &bailout); | |
3363 | |
3364 // Get first element in the array. | |
3365 __ Add(element, elements, FixedArray::kHeaderSize - kHeapObjectTag); | |
3366 // Live values in registers: | |
3367 // element: First array element | |
3368 // separator: Separator string | |
3369 // string_length: Length of result string (not smi) | |
3370 // array_length: Length of the array (not smi). | |
3371 __ AllocateOneByteString(result, string_length, scratch1, scratch2, scratch3, | |
3372 &bailout); | |
3373 | |
3374 // Prepare for looping. Set up elements_end to end of the array. Set | |
3375 // result_pos to the position of the result where to write the first | |
3376 // character. | |
3377 // TODO(all): useless unless AllocateOneByteString trashes the register. | |
3378 __ Add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2)); | |
3379 __ Add(result_pos, result, SeqOneByteString::kHeaderSize - kHeapObjectTag); | |
3380 | |
3381 // Check the length of the separator. | |
3382 __ Cmp(separator_length, 1); | |
3383 __ B(eq, &one_char_separator); | |
3384 __ B(gt, &long_separator); | |
3385 | |
3386 // Empty separator case | |
3387 __ Bind(&empty_separator_loop); | |
3388 // Live values in registers: | |
3389 // result_pos: the position to which we are currently copying characters. | |
3390 // element: Current array element. | |
3391 // elements_end: Array end. | |
3392 | |
3393 // Copy next array element to the result. | |
3394 __ Ldr(string, MemOperand(element, kPointerSize, PostIndex)); | |
3395 __ Ldrsw(string_length, | |
3396 UntagSmiFieldMemOperand(string, String::kLengthOffset)); | |
3397 __ Add(string, string, SeqOneByteString::kHeaderSize - kHeapObjectTag); | |
3398 __ CopyBytes(result_pos, string, string_length, scratch1); | |
3399 __ Cmp(element, elements_end); | |
3400 __ B(lt, &empty_separator_loop); // End while (element < elements_end). | |
3401 __ B(&done); | |
3402 | |
3403 // One-character separator case | |
3404 __ Bind(&one_char_separator); | |
3405 // Replace separator with its one-byte character value. | |
3406 __ Ldrb(separator, FieldMemOperand(separator, SeqOneByteString::kHeaderSize)); | |
3407 // Jump into the loop after the code that copies the separator, so the first | |
3408 // element is not preceded by a separator | |
3409 __ B(&one_char_separator_loop_entry); | |
3410 | |
3411 __ Bind(&one_char_separator_loop); | |
3412 // Live values in registers: | |
3413 // result_pos: the position to which we are currently copying characters. | |
3414 // element: Current array element. | |
3415 // elements_end: Array end. | |
3416 // separator: Single separator one-byte char (in lower byte). | |
3417 | |
3418 // Copy the separator character to the result. | |
3419 __ Strb(separator, MemOperand(result_pos, 1, PostIndex)); | |
3420 | |
3421 // Copy next array element to the result. | |
3422 __ Bind(&one_char_separator_loop_entry); | |
3423 __ Ldr(string, MemOperand(element, kPointerSize, PostIndex)); | |
3424 __ Ldrsw(string_length, | |
3425 UntagSmiFieldMemOperand(string, String::kLengthOffset)); | |
3426 __ Add(string, string, SeqOneByteString::kHeaderSize - kHeapObjectTag); | |
3427 __ CopyBytes(result_pos, string, string_length, scratch1); | |
3428 __ Cmp(element, elements_end); | |
3429 __ B(lt, &one_char_separator_loop); // End while (element < elements_end). | |
3430 __ B(&done); | |
3431 | |
3432 // Long separator case (separator is more than one character). Entry is at the | |
3433 // label long_separator below. | |
3434 __ Bind(&long_separator_loop); | |
3435 // Live values in registers: | |
3436 // result_pos: the position to which we are currently copying characters. | |
3437 // element: Current array element. | |
3438 // elements_end: Array end. | |
3439 // separator: Separator string. | |
3440 | |
3441 // Copy the separator to the result. | |
3442 // TODO(all): hoist next two instructions. | |
3443 __ Ldrsw(string_length, | |
3444 UntagSmiFieldMemOperand(separator, String::kLengthOffset)); | |
3445 __ Add(string, separator, SeqOneByteString::kHeaderSize - kHeapObjectTag); | |
3446 __ CopyBytes(result_pos, string, string_length, scratch1); | |
3447 | |
3448 __ Bind(&long_separator); | |
3449 __ Ldr(string, MemOperand(element, kPointerSize, PostIndex)); | |
3450 __ Ldrsw(string_length, | |
3451 UntagSmiFieldMemOperand(string, String::kLengthOffset)); | |
3452 __ Add(string, string, SeqOneByteString::kHeaderSize - kHeapObjectTag); | |
3453 __ CopyBytes(result_pos, string, string_length, scratch1); | |
3454 __ Cmp(element, elements_end); | |
3455 __ B(lt, &long_separator_loop); // End while (element < elements_end). | |
3456 __ B(&done); | |
3457 | |
3458 __ Bind(&bailout); | |
3459 // Returning undefined will force slower code to handle it. | |
3460 __ LoadRoot(result, Heap::kUndefinedValueRootIndex); | |
3461 __ Bind(&done); | |
3462 context()->Plug(result); | |
3463 } | |
3464 | |
3465 | |
3466 void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) { | 3246 void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) { |
3467 DCHECK(expr->arguments()->length() == 0); | 3247 DCHECK(expr->arguments()->length() == 0); |
3468 ExternalReference debug_is_active = | 3248 ExternalReference debug_is_active = |
3469 ExternalReference::debug_is_active_address(isolate()); | 3249 ExternalReference::debug_is_active_address(isolate()); |
3470 __ Mov(x10, debug_is_active); | 3250 __ Mov(x10, debug_is_active); |
3471 __ Ldrb(x0, MemOperand(x10)); | 3251 __ Ldrb(x0, MemOperand(x10)); |
3472 __ SmiTag(x0); | 3252 __ SmiTag(x0); |
3473 context()->Plug(x0); | 3253 context()->Plug(x0); |
3474 } | 3254 } |
3475 | 3255 |
(...skipping 1085 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4561 } | 4341 } |
4562 | 4342 |
4563 return INTERRUPT; | 4343 return INTERRUPT; |
4564 } | 4344 } |
4565 | 4345 |
4566 | 4346 |
4567 } // namespace internal | 4347 } // namespace internal |
4568 } // namespace v8 | 4348 } // namespace v8 |
4569 | 4349 |
4570 #endif // V8_TARGET_ARCH_ARM64 | 4350 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |