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