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

Side by Side Diff: src/arm/codegen-arm.cc

Issue 571005: ARM native string addition. (Closed)
Patch Set: Fixed bug in cons-allocation and string detection. Created 10 years, 10 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/arm/codegen-arm.h ('k') | src/arm/macro-assembler-arm.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 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 3533 matching lines...) Expand 10 before | Expand all | Expand 10 after
3544 frame_->EmitPush(r0); 3544 frame_->EmitPush(r0);
3545 } 3545 }
3546 3546
3547 3547
3548 void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) { 3548 void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) {
3549 ASSERT_EQ(2, args->length()); 3549 ASSERT_EQ(2, args->length());
3550 3550
3551 Load(args->at(0)); 3551 Load(args->at(0));
3552 Load(args->at(1)); 3552 Load(args->at(1));
3553 3553
3554 frame_->CallRuntime(Runtime::kStringAdd, 2); 3554 StringAddStub stub(NO_STRING_ADD_FLAGS);
3555 frame_->CallStub(&stub, 2);
3555 frame_->EmitPush(r0); 3556 frame_->EmitPush(r0);
3556 } 3557 }
3557 3558
3558 3559
3559 void CodeGenerator::GenerateSubString(ZoneList<Expression*>* args) { 3560 void CodeGenerator::GenerateSubString(ZoneList<Expression*>* args) {
3560 ASSERT_EQ(3, args->length()); 3561 ASSERT_EQ(3, args->length());
3561 3562
3562 Load(args->at(0)); 3563 Load(args->at(0));
3563 Load(args->at(1)); 3564 Load(args->at(1));
3564 Load(args->at(2)); 3565 Load(args->at(2));
(...skipping 1760 matching lines...) Expand 10 before | Expand all | Expand 10 after
5325 5326
5326 // Push arguments to the stack 5327 // Push arguments to the stack
5327 __ push(r1); 5328 __ push(r1);
5328 __ push(r0); 5329 __ push(r0);
5329 5330
5330 if (Token::ADD == operation) { 5331 if (Token::ADD == operation) {
5331 // Test for string arguments before calling runtime. 5332 // Test for string arguments before calling runtime.
5332 // r1 : first argument 5333 // r1 : first argument
5333 // r0 : second argument 5334 // r0 : second argument
5334 // sp[0] : second argument 5335 // sp[0] : second argument
5335 // sp[1] : first argument 5336 // sp[4] : first argument
5336 5337
5337 Label not_strings, not_string1, string1; 5338 Label not_strings, not_string1, string1;
5338 __ tst(r1, Operand(kSmiTagMask)); 5339 __ tst(r1, Operand(kSmiTagMask));
5339 __ b(eq, &not_string1); 5340 __ b(eq, &not_string1);
5340 __ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE); 5341 __ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE);
5341 __ b(ge, &not_string1); 5342 __ b(ge, &not_string1);
5342 5343
5343 // First argument is a a string, test second. 5344 // First argument is a a string, test second.
5344 __ tst(r0, Operand(kSmiTagMask)); 5345 __ tst(r0, Operand(kSmiTagMask));
5345 __ b(eq, &string1); 5346 __ b(eq, &string1);
5346 __ CompareObjectType(r0, r2, r2, FIRST_NONSTRING_TYPE); 5347 __ CompareObjectType(r0, r2, r2, FIRST_NONSTRING_TYPE);
5347 __ b(ge, &string1); 5348 __ b(ge, &string1);
5348 5349
5349 // First and second argument are strings. 5350 // First and second argument are strings.
5350 __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1); 5351 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
5352 __ TailCallStub(&stub);
5351 5353
5352 // Only first argument is a string. 5354 // Only first argument is a string.
5353 __ bind(&string1); 5355 __ bind(&string1);
5354 __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_JS); 5356 __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_JS);
5355 5357
5356 // First argument was not a string, test second. 5358 // First argument was not a string, test second.
5357 __ bind(&not_string1); 5359 __ bind(&not_string1);
5358 __ tst(r0, Operand(kSmiTagMask)); 5360 __ tst(r0, Operand(kSmiTagMask));
5359 __ b(eq, &not_strings); 5361 __ b(eq, &not_strings);
5360 __ CompareObjectType(r0, r2, r2, FIRST_NONSTRING_TYPE); 5362 __ CompareObjectType(r0, r2, r2, FIRST_NONSTRING_TYPE);
5361 __ b(ge, &not_strings); 5363 __ b(ge, &not_strings);
5362 5364
5363 // Only second argument is a string. 5365 // Only second argument is a string.
5364 __ b(&not_strings);
5365 __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_JS); 5366 __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_JS);
5366 5367
5367 __ bind(&not_strings); 5368 __ bind(&not_strings);
5368 } 5369 }
5369 5370
5370 __ InvokeBuiltin(builtin, JUMP_JS); // Tail call. No return. 5371 __ InvokeBuiltin(builtin, JUMP_JS); // Tail call. No return.
5371 5372
5372 // We branch here if at least one of r0 and r1 is not a Smi. 5373 // We branch here if at least one of r0 and r1 is not a Smi.
5373 __ bind(not_smi); 5374 __ bind(not_smi);
5374 if (mode == NO_OVERWRITE) { 5375 if (mode == NO_OVERWRITE) {
(...skipping 1459 matching lines...) Expand 10 before | Expand all | Expand 10 after
6834 // This loop just copies one character at a time, as it is only used for very 6835 // This loop just copies one character at a time, as it is only used for very
6835 // short strings. 6836 // short strings.
6836 if (!ascii) { 6837 if (!ascii) {
6837 __ add(count, count, Operand(count), SetCC); 6838 __ add(count, count, Operand(count), SetCC);
6838 } else { 6839 } else {
6839 __ cmp(count, Operand(0)); 6840 __ cmp(count, Operand(0));
6840 } 6841 }
6841 __ b(eq, &done); 6842 __ b(eq, &done);
6842 6843
6843 __ bind(&loop); 6844 __ bind(&loop);
6845 __ ldrb(scratch, MemOperand(src, 1, PostIndex));
6846 // Perform sub between load and dependent store to get the load time to
6847 // complete.
6844 __ sub(count, count, Operand(1), SetCC); 6848 __ sub(count, count, Operand(1), SetCC);
6845 __ ldrb(scratch, MemOperand(src, count), pl); 6849 __ strb(scratch, MemOperand(dest, 1, PostIndex));
6846 // Move branch between load and dependent store to not waste the cycle for
6847 // each iteration of the loop. It does cost an extra instruction on the
6848 // last iteration. 6850 // last iteration.
6849 __ b(mi, &done); 6851 __ b(gt, &loop);
6850 __ strb(scratch, MemOperand(dest, count)); 6852
6851 __ b(&loop);
6852 __ bind(&done); 6853 __ bind(&done);
6853 } 6854 }
6854 6855
6855 6856
6856 enum CopyCharactersFlags { 6857 enum CopyCharactersFlags {
6857 COPY_ASCII = 1, 6858 COPY_ASCII = 1,
6858 DEST_ALWAYS_ALIGNED = 2 6859 DEST_ALWAYS_ALIGNED = 2
6859 }; 6860 };
6860 6861
6861 6862
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after
7211 __ mov(r0, Operand(Smi::FromInt(GREATER)), LeaveCC, gt); 7212 __ mov(r0, Operand(Smi::FromInt(GREATER)), LeaveCC, gt);
7212 __ mov(r0, Operand(Smi::FromInt(LESS)), LeaveCC, lt); 7213 __ mov(r0, Operand(Smi::FromInt(LESS)), LeaveCC, lt);
7213 __ Ret(); 7214 __ Ret();
7214 } 7215 }
7215 7216
7216 7217
7217 void StringCompareStub::Generate(MacroAssembler* masm) { 7218 void StringCompareStub::Generate(MacroAssembler* masm) {
7218 Label runtime; 7219 Label runtime;
7219 7220
7220 // Stack frame on entry. 7221 // Stack frame on entry.
7221 // sp[0]: return address 7222 // sp[0]: right string
7222 // sp[4]: right string 7223 // sp[4]: left string
7223 // sp[8]: left string 7224 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // left
7224 7225 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // right
7225 __ ldr(r0, MemOperand(sp, 2 * kPointerSize)); // left
7226 __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); // right
7227 7226
7228 Label not_same; 7227 Label not_same;
7229 __ cmp(r0, r1); 7228 __ cmp(r0, r1);
7230 __ b(ne, &not_same); 7229 __ b(ne, &not_same);
7231 ASSERT_EQ(0, EQUAL); 7230 ASSERT_EQ(0, EQUAL);
7232 ASSERT_EQ(0, kSmiTag); 7231 ASSERT_EQ(0, kSmiTag);
7233 __ mov(r0, Operand(Smi::FromInt(EQUAL))); 7232 __ mov(r0, Operand(Smi::FromInt(EQUAL)));
7234 __ IncrementCounter(&Counters::string_compare_native, 1, r1, r2); 7233 __ IncrementCounter(&Counters::string_compare_native, 1, r1, r2);
7235 __ add(sp, sp, Operand(2 * kPointerSize)); 7234 __ add(sp, sp, Operand(2 * kPointerSize));
7236 __ Ret(); 7235 __ Ret();
7237 7236
7238 __ bind(&not_same); 7237 __ bind(&not_same);
7239 7238
7240 // Check that both objects are sequential ascii strings. 7239 // Check that both objects are sequential ascii strings.
7241 __ JumpIfNotBothSequentialAsciiStrings(r0, r1, r2, r3, &runtime); 7240 __ JumpIfNotBothSequentialAsciiStrings(r0, r1, r2, r3, &runtime);
7242 7241
7243 // Compare flat ascii strings natively. Remove arguments from stack first. 7242 // Compare flat ascii strings natively. Remove arguments from stack first.
7244 __ IncrementCounter(&Counters::string_compare_native, 1, r2, r3); 7243 __ IncrementCounter(&Counters::string_compare_native, 1, r2, r3);
7245 __ add(sp, sp, Operand(2 * kPointerSize)); 7244 __ add(sp, sp, Operand(2 * kPointerSize));
7246 GenerateCompareFlatAsciiStrings(masm, r0, r1, r2, r3, r4, r5); 7245 GenerateCompareFlatAsciiStrings(masm, r0, r1, r2, r3, r4, r5);
7247 7246
7248 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) 7247 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
7249 // tagged as a small integer. 7248 // tagged as a small integer.
7250 __ bind(&runtime); 7249 __ bind(&runtime);
7251 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); 7250 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1);
7252 } 7251 }
7253 7252
7254 7253
7254 void StringAddStub::Generate(MacroAssembler* masm) {
7255 Label string_add_runtime;
7256 // Stack on entry:
7257 // sp[0]: second argument.
7258 // sp[4]: first argument.
7259
7260 // Load the two arguments.
7261 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // First argument.
7262 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // Second argument.
7263
7264 // Make sure that both arguments are strings if not known in advance.
7265 if (string_check_) {
7266 ASSERT_EQ(0, kSmiTag);
7267 __ JumpIfEitherSmi(r0, r1, &string_add_runtime);
7268 // Load instance types.
7269 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
7270 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
7271 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
7272 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
7273 ASSERT_EQ(0, kStringTag);
7274 // If either is not a string, go to runtime.
7275 __ tst(r4, Operand(kIsNotStringMask));
7276 __ tst(r5, Operand(kIsNotStringMask), eq);
7277 __ b(ne, &string_add_runtime);
7278 }
7279
7280 // Both arguments are strings.
7281 // r0: first string
7282 // r1: second string
7283 // r4: first string instance type (if string_check_)
7284 // r5: second string instance type (if string_check_)
7285 {
7286 Label strings_not_empty;
7287 // Check if either of the strings are empty. In that case return the other.
7288 __ ldr(r2, FieldMemOperand(r0, String::kLengthOffset));
7289 __ ldr(r3, FieldMemOperand(r1, String::kLengthOffset));
7290 __ cmp(r2, Operand(0)); // Test if first string is empty.
7291 __ mov(r0, Operand(r1), LeaveCC, eq); // If first is empty, return second.
7292 __ cmp(r3, Operand(0), ne); // Else test if second string is empty.
7293 __ b(ne, &strings_not_empty); // If either string was empty, return r0.
7294
7295 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
7296 __ add(sp, sp, Operand(2 * kPointerSize));
7297 __ Ret();
7298
7299 __ bind(&strings_not_empty);
7300 }
7301
7302 // Both strings are non-empty.
7303 // r0: first string
7304 // r1: second string
7305 // r2: length of first string
7306 // r3: length of second string
7307 // r4: first string instance type (if string_check_)
7308 // r5: second string instance type (if string_check_)
7309 // Look at the length of the result of adding the two strings.
7310 Label string_add_flat_result;
7311 // Adding two lengths can't overflow.
7312 ASSERT(String::kMaxLength * 2 > String::kMaxLength);
7313 __ add(r6, r2, Operand(r3));
7314 // Use the runtime system when adding two one character strings, as it
7315 // contains optimizations for this specific case using the symbol table.
7316 __ cmp(r6, Operand(2));
7317 __ b(eq, &string_add_runtime);
7318 // Check if resulting string will be flat.
7319 __ cmp(r6, Operand(String::kMinNonFlatLength));
7320 __ b(lt, &string_add_flat_result);
7321 // Handle exceptionally long strings in the runtime system.
7322 ASSERT((String::kMaxLength & 0x80000000) == 0);
7323 ASSERT(IsPowerOf2(String::kMaxLength + 1));
7324 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not.
7325 __ cmp(r6, Operand(String::kMaxLength + 1));
7326 __ b(hs, &string_add_runtime);
7327
7328 // If result is not supposed to be flat, allocate a cons string object.
7329 // If both strings are ascii the result is an ascii cons string.
7330 if (!string_check_) {
7331 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
7332 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
7333 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
7334 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
7335 }
7336 Label non_ascii, allocated;
7337 ASSERT_EQ(0, kTwoByteStringTag);
7338 __ tst(r4, Operand(kStringEncodingMask));
7339 __ tst(r5, Operand(kStringEncodingMask), ne);
7340 __ b(eq, &non_ascii);
7341
7342 // Allocate an ASCII cons string.
7343 __ AllocateAsciiConsString(r7, r6, r4, r5, &string_add_runtime);
7344 __ bind(&allocated);
7345 // Fill the fields of the cons string.
7346 __ str(r0, FieldMemOperand(r7, ConsString::kFirstOffset));
7347 __ str(r1, FieldMemOperand(r7, ConsString::kSecondOffset));
7348 __ mov(r0, Operand(r7));
7349 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
7350 __ add(sp, sp, Operand(2 * kPointerSize));
7351 __ Ret();
7352
7353 __ bind(&non_ascii);
7354 // Allocate a two byte cons string.
7355 __ AllocateTwoByteConsString(r7, r6, r4, r5, &string_add_runtime);
7356 __ jmp(&allocated);
7357
7358 // Handle creating a flat result. First check that both strings are
7359 // sequential and that they have the same encoding.
7360 // r0: first string
7361 // r1: second string
7362 // r2: length of first string
7363 // r3: length of second string
7364 // r4: first string instance type (if string_check_)
7365 // r5: second string instance type (if string_check_)
7366 // r6: sum of lengths.
7367 __ bind(&string_add_flat_result);
7368 if (!string_check_) {
7369 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
7370 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
7371 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
7372 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
7373 }
7374 // Check that both strings are sequential.
7375 ASSERT_EQ(0, kSeqStringTag);
7376 __ tst(r4, Operand(kStringRepresentationMask));
7377 __ tst(r5, Operand(kStringRepresentationMask), eq);
7378 __ b(ne, &string_add_runtime);
7379 // Now check if both strings have the same encoding (ASCII/Two-byte).
7380 // r0: first string
7381 // r1: second string
7382 // r2: length of first string
7383 // r3: length of second string
7384 // r6: sum of lengths.
7385 Label non_ascii_string_add_flat_result;
7386 ASSERT(IsPowerOf2(kStringEncodingMask)); // Just one bit to test.
7387 __ eor(r7, r4, Operand(r5));
7388 __ tst(r7, Operand(kStringEncodingMask));
7389 __ b(ne, &string_add_runtime);
7390 // And see if it's ASCII or two-byte.
7391 __ tst(r4, Operand(kStringEncodingMask));
7392 __ b(eq, &non_ascii_string_add_flat_result);
7393
7394 // Both strings are sequential ASCII strings. We also know that they are
7395 // short (since the sum of the lengths is less than kMinNonFlatLength).
7396 __ AllocateAsciiString(r7, r6, r4, r5, r9, &string_add_runtime);
7397 // Locate first character of result.
7398 __ add(r6, r7, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
7399 // Locate first character of first argument.
7400 __ add(r0, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
7401 // r0: first character of first string
7402 // r1: second string
7403 // r2: length of first string
7404 // r3: length of second string
7405 // r6: first character of result
7406 // r7: result string
7407 GenerateCopyCharacters(masm, r6, r0, r2, r4, true);
7408
7409 // Load second argument and locate first character.
7410 __ add(r1, r1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
7411 // r1: first character of second string
7412 // r3: length of second string
7413 // r6: next character of result
7414 // r7: result string
7415 GenerateCopyCharacters(masm, r6, r1, r3, r4, true);
7416 __ mov(r0, Operand(r7));
7417 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
7418 __ add(sp, sp, Operand(2 * kPointerSize));
7419 __ Ret();
7420
7421 __ bind(&non_ascii_string_add_flat_result);
7422 // Both strings are sequential two byte strings.
7423 // r0: first character of first string
7424 // r1: second string
7425 // r2: length of first string
7426 // r3: length of second string
7427 // r6: sum of length of strings.
7428 __ AllocateTwoByteString(r7, r6, r4, r5, r9, &string_add_runtime);
7429 // r0: first string
7430 // r1: second string
7431 // r2: length of first string
7432 // r3: length of second string
7433 // r7: result string
7434
7435 // Locate first character of result.
7436 __ add(r6, r7, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
7437 // Locate first character of first argument.
7438 __ add(r0, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
7439
7440 // r0: first character of first string
7441 // r1: second string
7442 // r2: length of first string
7443 // r3: length of second string
7444 // r6: first character of result
7445 // r7: result string
7446 GenerateCopyCharacters(masm, r6, r0, r2, r4, false);
7447
7448 // Locate first character of second argument.
7449 __ add(r1, r1, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
7450
7451 // r1: first character of second string
7452 // r3: length of second string
7453 // r6: next character of result (after copy of first string)
7454 // r7: result string
7455 GenerateCopyCharacters(masm, r6, r1, r3, r4, false);
7456
7457 __ mov(r0, Operand(r7));
7458 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3);
7459 __ add(sp, sp, Operand(2 * kPointerSize));
7460 __ Ret();
7461
7462 // Just jump to runtime to add the two strings.
7463 __ bind(&string_add_runtime);
7464 __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1);
7465 }
7466
7467
7255 #undef __ 7468 #undef __
7256 7469
7257 } } // namespace v8::internal 7470 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/arm/codegen-arm.h ('k') | src/arm/macro-assembler-arm.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698