OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 3182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3193 } | 3193 } |
3194 | 3194 |
3195 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset)); | 3195 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset)); |
3196 __ IndexFromHash(r0, r0); | 3196 __ IndexFromHash(r0, r0); |
3197 | 3197 |
3198 context()->Plug(r0); | 3198 context()->Plug(r0); |
3199 } | 3199 } |
3200 | 3200 |
3201 | 3201 |
3202 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { | 3202 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { |
| 3203 Label bailout, done, one_char_separator, long_separator, |
| 3204 non_trivial_array, not_size_one_array, loop, |
| 3205 empty_separator_loop, one_char_separator_loop, |
| 3206 one_char_separator_loop_entry, long_separator_loop; |
| 3207 |
| 3208 ASSERT(args->length() == 2); |
| 3209 VisitForStackValue(args->at(1)); |
| 3210 VisitForAccumulatorValue(args->at(0)); |
| 3211 |
| 3212 // All aliases of the same register have disjoint lifetimes. |
| 3213 Register array = r0; |
| 3214 Register elements = no_reg; // Will be r0. |
| 3215 Register result = no_reg; // Will be r0. |
| 3216 Register separator = r1; |
| 3217 Register array_length = r2; |
| 3218 Register result_pos = no_reg; // Will be r2 |
| 3219 Register string_length = r3; |
| 3220 Register string = r4; |
| 3221 Register element = r5; |
| 3222 Register elements_end = r6; |
| 3223 Register scratch1 = r7; |
| 3224 Register scratch2 = r9; |
| 3225 |
| 3226 // Separator operand is on the stack. |
| 3227 __ pop(separator); |
| 3228 |
| 3229 // Check that the array is a JSArray. |
| 3230 __ JumpIfSmi(array, &bailout); |
| 3231 __ CompareObjectType(array, scratch1, scratch2, JS_ARRAY_TYPE); |
| 3232 __ b(ne, &bailout); |
| 3233 |
| 3234 // Check that the array has fast elements. |
| 3235 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitField2Offset)); |
| 3236 __ tst(scratch2, Operand(1 << Map::kHasFastElements)); |
| 3237 __ b(eq, &bailout); |
| 3238 |
| 3239 // If the array has length zero, return the empty string. |
| 3240 __ ldr(array_length, FieldMemOperand(array, JSArray::kLengthOffset)); |
| 3241 __ SmiUntag(array_length, SetCC); |
| 3242 __ b(ne, &non_trivial_array); |
| 3243 __ LoadRoot(r0, Heap::kEmptyStringRootIndex); |
| 3244 __ b(&done); |
| 3245 |
| 3246 __ bind(&non_trivial_array); |
| 3247 |
| 3248 // Get the FixedArray containing array's elements. |
| 3249 elements = array; |
| 3250 __ ldr(elements, FieldMemOperand(array, JSArray::kElementsOffset)); |
| 3251 array = no_reg; // End of array's live range. |
| 3252 |
| 3253 // Check that all array elements are sequential ASCII strings, and |
| 3254 // accumulate the sum of their lengths, as a smi-encoded value. |
| 3255 __ mov(string_length, Operand(0)); |
| 3256 __ add(element, |
| 3257 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 3258 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2)); |
| 3259 // Loop condition: while (element < elements_end). |
| 3260 // Live values in registers: |
| 3261 // elements: Fixed array of strings. |
| 3262 // array_length: Length of the fixed array of strings (not smi) |
| 3263 // separator: Separator string |
| 3264 // string_length: Accumulated sum of string lengths (smi). |
| 3265 // element: Current array element. |
| 3266 // elements_end: Array end. |
| 3267 if (FLAG_debug_code) { |
| 3268 __ cmp(array_length, Operand(0)); |
| 3269 __ Assert(gt, "No empty arrays here in EmitFastAsciiArrayJoin"); |
| 3270 } |
| 3271 __ bind(&loop); |
| 3272 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
| 3273 __ JumpIfSmi(string, &bailout); |
| 3274 __ ldr(scratch1, FieldMemOperand(string, HeapObject::kMapOffset)); |
| 3275 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); |
| 3276 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout); |
| 3277 __ ldr(scratch1, FieldMemOperand(string, SeqAsciiString::kLengthOffset)); |
| 3278 __ add(string_length, string_length, Operand(scratch1)); |
| 3279 __ b(vs, &bailout); |
| 3280 __ cmp(element, elements_end); |
| 3281 __ b(lt, &loop); |
| 3282 |
| 3283 // If array_length is 1, return elements[0], a string. |
| 3284 __ cmp(array_length, Operand(1)); |
| 3285 __ b(ne, ¬_size_one_array); |
| 3286 __ ldr(r0, FieldMemOperand(elements, FixedArray::kHeaderSize)); |
| 3287 __ b(&done); |
| 3288 |
| 3289 __ bind(¬_size_one_array); |
| 3290 |
| 3291 // Live values in registers: |
| 3292 // separator: Separator string |
| 3293 // array_length: Length of the array. |
| 3294 // string_length: Sum of string lengths (smi). |
| 3295 // elements: FixedArray of strings. |
| 3296 |
| 3297 // Check that the separator is a flat ASCII string. |
| 3298 __ JumpIfSmi(separator, &bailout); |
| 3299 __ ldr(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset)); |
| 3300 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); |
| 3301 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout); |
| 3302 |
| 3303 // Add (separator length times array_length) - separator length to the |
| 3304 // string_length to get the length of the result string. array_length is not |
| 3305 // smi but the other values are, so the result is a smi |
| 3306 __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset)); |
| 3307 __ sub(string_length, string_length, Operand(scratch1)); |
| 3308 __ smull(scratch2, ip, array_length, scratch1); |
| 3309 // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are |
| 3310 // zero. |
| 3311 __ cmp(ip, Operand(0)); |
| 3312 __ b(ne, &bailout); |
| 3313 __ tst(scratch2, Operand(0x80000000)); |
| 3314 __ b(ne, &bailout); |
| 3315 __ add(string_length, string_length, Operand(scratch2)); |
| 3316 __ b(vs, &bailout); |
| 3317 __ SmiUntag(string_length); |
| 3318 |
| 3319 // Get first element in the array to free up the elements register to be used |
| 3320 // for the result. |
| 3321 __ add(element, |
| 3322 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 3323 result = elements; // End of live range for elements. |
| 3324 elements = no_reg; |
| 3325 // Live values in registers: |
| 3326 // element: First array element |
| 3327 // separator: Separator string |
| 3328 // string_length: Length of result string (not smi) |
| 3329 // array_length: Length of the array. |
| 3330 __ AllocateAsciiString(result, |
| 3331 string_length, |
| 3332 scratch1, |
| 3333 scratch2, |
| 3334 elements_end, |
| 3335 &bailout); |
| 3336 // Prepare for looping. Set up elements_end to end of the array. Set |
| 3337 // result_pos to the position of the result where to write the first |
| 3338 // character. |
| 3339 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2)); |
| 3340 result_pos = array_length; // End of live range for array_length. |
| 3341 array_length = no_reg; |
| 3342 __ add(result_pos, |
| 3343 result, |
| 3344 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 3345 |
| 3346 // Check the length of the separator. |
| 3347 __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset)); |
| 3348 __ cmp(scratch1, Operand(Smi::FromInt(1))); |
| 3349 __ b(eq, &one_char_separator); |
| 3350 __ b(gt, &long_separator); |
| 3351 |
| 3352 // Empty separator case |
| 3353 __ bind(&empty_separator_loop); |
| 3354 // Live values in registers: |
| 3355 // result_pos: the position to which we are currently copying characters. |
| 3356 // element: Current array element. |
| 3357 // elements_end: Array end. |
| 3358 |
| 3359 // Copy next array element to the result. |
| 3360 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
| 3361 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); |
| 3362 __ SmiUntag(string_length); |
| 3363 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 3364 __ CopyBytes(string, result_pos, string_length, scratch1); |
| 3365 __ cmp(element, elements_end); |
| 3366 __ b(lt, &empty_separator_loop); // End while (element < elements_end). |
| 3367 ASSERT(result.is(r0)); |
| 3368 __ b(&done); |
| 3369 |
| 3370 // One-character separator case |
| 3371 __ bind(&one_char_separator); |
| 3372 // Replace separator with its ascii character value. |
| 3373 __ ldrb(separator, FieldMemOperand(separator, SeqAsciiString::kHeaderSize)); |
| 3374 // Jump into the loop after the code that copies the separator, so the first |
| 3375 // element is not preceded by a separator |
| 3376 __ jmp(&one_char_separator_loop_entry); |
| 3377 |
| 3378 __ bind(&one_char_separator_loop); |
| 3379 // Live values in registers: |
| 3380 // result_pos: the position to which we are currently copying characters. |
| 3381 // element: Current array element. |
| 3382 // elements_end: Array end. |
| 3383 // separator: Single separator ascii char (in lower byte). |
| 3384 |
| 3385 // Copy the separator character to the result. |
| 3386 __ strb(separator, MemOperand(result_pos, 1, PostIndex)); |
| 3387 |
| 3388 // Copy next array element to the result. |
| 3389 __ bind(&one_char_separator_loop_entry); |
| 3390 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
| 3391 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); |
| 3392 __ SmiUntag(string_length); |
| 3393 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 3394 __ CopyBytes(string, result_pos, string_length, scratch1); |
| 3395 __ cmp(element, elements_end); |
| 3396 __ b(lt, &one_char_separator_loop); // End while (element < elements_end). |
| 3397 ASSERT(result.is(r0)); |
| 3398 __ b(&done); |
| 3399 |
| 3400 // Long separator case (separator is more than one character). Entry is at the |
| 3401 // label long_separator below. |
| 3402 __ bind(&long_separator_loop); |
| 3403 // Live values in registers: |
| 3404 // result_pos: the position to which we are currently copying characters. |
| 3405 // element: Current array element. |
| 3406 // elements_end: Array end. |
| 3407 // separator: Separator string. |
| 3408 |
| 3409 // Copy the separator to the result. |
| 3410 __ ldr(string_length, FieldMemOperand(separator, String::kLengthOffset)); |
| 3411 __ SmiUntag(string_length); |
| 3412 __ add(string, |
| 3413 separator, |
| 3414 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 3415 __ CopyBytes(string, result_pos, string_length, scratch1); |
| 3416 |
| 3417 __ bind(&long_separator); |
| 3418 __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); |
| 3419 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); |
| 3420 __ SmiUntag(string_length); |
| 3421 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 3422 __ CopyBytes(string, result_pos, string_length, scratch1); |
| 3423 __ cmp(element, elements_end); |
| 3424 __ b(lt, &long_separator_loop); // End while (element < elements_end). |
| 3425 ASSERT(result.is(r0)); |
| 3426 __ b(&done); |
| 3427 |
| 3428 __ bind(&bailout); |
3203 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 3429 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
| 3430 __ bind(&done); |
3204 context()->Plug(r0); | 3431 context()->Plug(r0); |
3205 return; | |
3206 } | 3432 } |
3207 | 3433 |
3208 | 3434 |
3209 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 3435 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
3210 Handle<String> name = expr->name(); | 3436 Handle<String> name = expr->name(); |
3211 if (name->length() > 0 && name->Get(0) == '_') { | 3437 if (name->length() > 0 && name->Get(0) == '_') { |
3212 Comment cmnt(masm_, "[ InlineRuntimeCall"); | 3438 Comment cmnt(masm_, "[ InlineRuntimeCall"); |
3213 EmitInlineRuntimeCall(expr); | 3439 EmitInlineRuntimeCall(expr); |
3214 return; | 3440 return; |
3215 } | 3441 } |
(...skipping 733 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3949 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. | 4175 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. |
3950 __ add(pc, r1, Operand(masm_->CodeObject())); | 4176 __ add(pc, r1, Operand(masm_->CodeObject())); |
3951 } | 4177 } |
3952 | 4178 |
3953 | 4179 |
3954 #undef __ | 4180 #undef __ |
3955 | 4181 |
3956 } } // namespace v8::internal | 4182 } } // namespace v8::internal |
3957 | 4183 |
3958 #endif // V8_TARGET_ARCH_ARM | 4184 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |