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

Side by Side Diff: src/a64/code-stubs-a64.cc

Issue 143633007: A64: Synchronize with r18764. (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/a64
Patch Set: Created 6 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 | Annotate | Revision Log
« no previous file with comments | « src/a64/code-stubs-a64.h ('k') | src/a64/codegen-a64.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 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 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 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 CodeStubInterfaceDescriptor* descriptor) { 43 CodeStubInterfaceDescriptor* descriptor) {
44 // x2: function info 44 // x2: function info
45 static Register registers[] = { x2 }; 45 static Register registers[] = { x2 };
46 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); 46 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]);
47 descriptor->register_params_ = registers; 47 descriptor->register_params_ = registers;
48 descriptor->deoptimization_handler_ = 48 descriptor->deoptimization_handler_ =
49 Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry; 49 Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry;
50 } 50 }
51 51
52 52
53 void FastNewContextStub::InitializeInterfaceDescriptor(
54 Isolate* isolate,
55 CodeStubInterfaceDescriptor* descriptor) {
56 // x1: function
57 static Register registers[] = { x1 };
58 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]);
59 descriptor->register_params_ = registers;
60 descriptor->deoptimization_handler_ = NULL;
61 }
62
63
53 void ToNumberStub::InitializeInterfaceDescriptor( 64 void ToNumberStub::InitializeInterfaceDescriptor(
54 Isolate* isolate, 65 Isolate* isolate,
55 CodeStubInterfaceDescriptor* descriptor) { 66 CodeStubInterfaceDescriptor* descriptor) {
56 // x0: value 67 // x0: value
57 static Register registers[] = { x0 }; 68 static Register registers[] = { x0 };
58 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); 69 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]);
59 descriptor->register_params_ = registers; 70 descriptor->register_params_ = registers;
60 descriptor->deoptimization_handler_ = NULL; 71 descriptor->deoptimization_handler_ = NULL;
61 } 72 }
62 73
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 descriptor->SetMissHandler( 226 descriptor->SetMissHandler(
216 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate)); 227 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate));
217 } 228 }
218 229
219 230
220 static void InitializeArrayConstructorDescriptor( 231 static void InitializeArrayConstructorDescriptor(
221 Isolate* isolate, 232 Isolate* isolate,
222 CodeStubInterfaceDescriptor* descriptor, 233 CodeStubInterfaceDescriptor* descriptor,
223 int constant_stack_parameter_count) { 234 int constant_stack_parameter_count) {
224 // x1: function 235 // x1: function
225 // x2: type info cell with elements kind 236 // x2: allocation site with elements kind
226 // x0: number of arguments to the constructor function 237 // x0: number of arguments to the constructor function
227 static Register registers_variable_args[] = { x1, x2, x0 }; 238 static Register registers_variable_args[] = { x1, x2, x0 };
228 static Register registers_no_args[] = { x1, x2 }; 239 static Register registers_no_args[] = { x1, x2 };
229 240
230 if (constant_stack_parameter_count == 0) { 241 if (constant_stack_parameter_count == 0) {
231 descriptor->register_param_count_ = 242 descriptor->register_param_count_ =
232 sizeof(registers_no_args) / sizeof(registers_no_args[0]); 243 sizeof(registers_no_args) / sizeof(registers_no_args[0]);
233 descriptor->register_params_ = registers_no_args; 244 descriptor->register_params_ = registers_no_args;
234 } else { 245 } else {
235 // stack param count needs (constructor pointer, and single argument) 246 // stack param count needs (constructor pointer, and single argument)
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 // x1: left operand 392 // x1: left operand
382 // x0: right operand 393 // x0: right operand
383 static Register registers[] = { x2, x1, x0 }; 394 static Register registers[] = { x2, x1, x0 };
384 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); 395 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]);
385 descriptor->register_params_ = registers; 396 descriptor->register_params_ = registers;
386 descriptor->deoptimization_handler_ = 397 descriptor->deoptimization_handler_ =
387 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite); 398 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite);
388 } 399 }
389 400
390 401
391 void NewStringAddStub::InitializeInterfaceDescriptor( 402 void StringAddStub::InitializeInterfaceDescriptor(
392 Isolate* isolate, 403 Isolate* isolate,
393 CodeStubInterfaceDescriptor* descriptor) { 404 CodeStubInterfaceDescriptor* descriptor) {
394 // x1: left operand 405 // x1: left operand
395 // x0: right operand 406 // x0: right operand
396 static Register registers[] = { x1, x0 }; 407 static Register registers[] = { x1, x0 };
397 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); 408 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]);
398 descriptor->register_params_ = registers; 409 descriptor->register_params_ = registers;
399 descriptor->deoptimization_handler_ = 410 descriptor->deoptimization_handler_ =
400 Runtime::FunctionForId(Runtime::kStringAdd)->entry; 411 Runtime::FunctionForId(Runtime::kStringAdd)->entry;
401 } 412 }
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
481 __ Push(descriptor->register_params_[i]); 492 __ Push(descriptor->register_params_[i]);
482 } 493 }
483 ExternalReference miss = descriptor->miss_handler(); 494 ExternalReference miss = descriptor->miss_handler();
484 __ CallExternalReference(miss, descriptor->register_param_count_); 495 __ CallExternalReference(miss, descriptor->register_param_count_);
485 } 496 }
486 497
487 __ Ret(); 498 __ Ret();
488 } 499 }
489 500
490 501
491 void FastNewContextStub::Generate(MacroAssembler* masm) {
492 Register function = x0;
493 Register allocated = x1;
494 Label gc;
495
496 // Pop the function from the stack.
497 __ Pop(function);
498
499 // Attempt to allocate the context in new space.
500 int context_length = slots_ + Context::MIN_CONTEXT_SLOTS;
501 __ Allocate(FixedArray::SizeFor(context_length), allocated, x6, x7, &gc,
502 TAG_OBJECT);
503
504 // Set up the object header.
505 Register map = x2;
506 Register length = x2;
507 __ LoadRoot(map, Heap::kFunctionContextMapRootIndex);
508 __ Str(map, FieldMemOperand(allocated, HeapObject::kMapOffset));
509 __ Mov(length, Operand(Smi::FromInt(context_length)));
510 __ Str(length, FieldMemOperand(allocated, FixedArray::kLengthOffset));
511
512 // Set up the fixed slots.
513 Register extension = x2;
514 __ Mov(extension, Operand(Smi::FromInt(0)));
515 __ Str(function, ContextMemOperand(allocated, Context::CLOSURE_INDEX));
516 __ Str(cp, ContextMemOperand(allocated, Context::PREVIOUS_INDEX));
517 __ Str(extension, ContextMemOperand(allocated, Context::EXTENSION_INDEX));
518
519 // Copy the global object from the previous context.
520 Register global_object = x2;
521 __ Ldr(global_object, GlobalObjectMemOperand());
522 __ Str(global_object, ContextMemOperand(allocated,
523 Context::GLOBAL_OBJECT_INDEX));
524
525 // Initialize the rest of the slots to undefined.
526 Register undef_val = x2;
527 __ LoadRoot(undef_val, Heap::kUndefinedValueRootIndex);
528 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; i++) {
529 __ Str(undef_val, ContextMemOperand(allocated, i));
530 }
531
532 // Install new context and return.
533 __ Mov(cp, allocated);
534 __ Ret();
535
536 // Need to collect. Call into runtime system.
537 __ Bind(&gc);
538 __ Push(function);
539 __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1);
540 }
541
542
543 void FastNewBlockContextStub::Generate(MacroAssembler* masm) { 502 void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
544 // Stack on entry: 503 // Stack on entry:
545 // jssp[0]: function. 504 // jssp[0]: function.
546 // jssp[8]: serialized scope info. 505 // jssp[8]: serialized scope info.
547 506
548 // Try to allocate the context in new space. 507 // Try to allocate the context in new space.
549 Register context = x10; 508 Register context = x10;
550 Register function = x11; 509 Register function = x11;
551 Register scope = x12; 510 Register scope = x12;
552 Register global_obj = x13; 511 Register global_obj = x13;
(...skipping 3430 matching lines...) Expand 10 before | Expand all | Expand 10 after
3983 __ Add(stub_entry, x0, Code::kHeaderSize - kHeapObjectTag); 3942 __ Add(stub_entry, x0, Code::kHeaderSize - kHeapObjectTag);
3984 // Restore caller-saved registers. 3943 // Restore caller-saved registers.
3985 __ Pop(lr, x0, x1); 3944 __ Pop(lr, x0, x1);
3986 } 3945 }
3987 3946
3988 // Tail-call to the new stub. 3947 // Tail-call to the new stub.
3989 __ Jump(stub_entry); 3948 __ Jump(stub_entry);
3990 } 3949 }
3991 3950
3992 3951
3993 void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
3994 Register c1,
3995 Register c2,
3996 Register scratch1,
3997 Register scratch2,
3998 Register scratch3,
3999 Register scratch4,
4000 Register scratch5,
4001 Label* not_found) {
4002 ASSERT(!AreAliased(c1, c2, scratch1, scratch2, scratch3, scratch4, scratch5));
4003 // Register scratch3 is the general scratch register in this function.
4004 Register scratch = scratch3;
4005
4006 // Make sure that both characters are not digits as such strings have a
4007 // different hash algorithm. Don't try to look for these in the string table.
4008 Label not_array_index;
4009 __ Sub(scratch, c1, static_cast<int>('0'));
4010 __ Cmp(scratch, static_cast<int>('9' - '0'));
4011 __ B(hi, &not_array_index);
4012 __ Sub(scratch, c2, static_cast<int>('0'));
4013 __ Cmp(scratch, static_cast<int>('9' - '0'));
4014
4015 // If check failed, combine both characters into single halfword.
4016 // This is required by the contract of the method: code at the not_found
4017 // branch expects this combination in register c1.
4018 __ Orr(scratch, c1, Operand(c2, LSL, kBitsPerByte));
4019 __ Csel(c1, scratch, c1, ls);
4020 __ B(ls, not_found);
4021
4022 __ Bind(&not_array_index);
4023
4024 // Calculate the two character string hash.
4025 Register hash = scratch1;
4026 StringHelper::GenerateHashInit(masm, hash, c1);
4027 StringHelper::GenerateHashAddCharacter(masm, hash, c2);
4028 StringHelper::GenerateHashGetHash(masm, hash, scratch);
4029
4030 // Collect the two characters in a register.
4031 Register chars = c1;
4032 __ Orr(chars, chars, Operand(c2, LSL, kBitsPerByte));
4033
4034 // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
4035 // hash: hash of two character string.
4036
4037 // Load string table
4038 // Load address of first element of the string table.
4039 Register string_table = c2;
4040 __ LoadRoot(string_table, Heap::kStringTableRootIndex);
4041
4042 Register undefined = scratch4;
4043 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
4044
4045 // Calculate capacity mask from the string table capacity.
4046 Register mask = scratch2;
4047 __ Ldrsw(mask, UntagSmiFieldMemOperand(string_table,
4048 StringTable::kCapacityOffset));
4049 __ Sub(mask, mask, 1);
4050
4051 // Calculate untagged address of the first element of the string table.
4052 Register first_string_table_element = string_table;
4053 __ Add(first_string_table_element, string_table,
4054 StringTable::kElementsStartOffset - kHeapObjectTag);
4055
4056 // Registers
4057 // chars: two character string, char 1 in byte 0 and char 2 in byte 1
4058 // hash: hash of two character string
4059 // mask: capacity mask
4060 // first_string_table_element: address of the first element of the string
4061 // table
4062 // undefined: the undefined object
4063 // scratch: -
4064
4065 // Perform a number of probes of the string table.
4066 static const int kProbes = 4;
4067 Label found_in_string_table;
4068 Label next_probe[kProbes];
4069 Register candidate = scratch5; // Scratch register contains candidate.
4070 for (int i = 0; i < kProbes; i++) {
4071 // Calculate entry in string table.
4072 if (i > 0) {
4073 __ Add(candidate, hash, StringTable::GetProbeOffset(i));
4074 __ And(candidate, candidate, mask);
4075 } else {
4076 __ And(candidate, hash, mask);
4077 }
4078
4079 // Load the entry from the string table.
4080 STATIC_ASSERT(StringTable::kEntrySize == 1);
4081 __ Ldr(candidate, MemOperand(first_string_table_element,
4082 candidate, LSL, kPointerSizeLog2));
4083
4084 // If entry is undefined no string with this hash can be found.
4085 Label is_string;
4086 Register type = scratch;
4087 __ JumpIfNotObjectType(candidate, type, type, ODDBALL_TYPE, &is_string);
4088
4089 __ Cmp(undefined, candidate);
4090 __ B(eq, not_found);
4091 // Must be the hole (deleted entry).
4092 if (FLAG_debug_code) {
4093 __ CompareRoot(candidate, Heap::kTheHoleValueRootIndex);
4094 __ Assert(eq, kOddballInStringTableIsNotUndefinedOrTheHole);
4095 }
4096 __ B(&next_probe[i]);
4097
4098 __ Bind(&is_string);
4099
4100 // Check that the candidate is a non-external ASCII string. The instance
4101 // type is still in the type register from the CompareObjectType
4102 // operation.
4103 __ JumpIfInstanceTypeIsNotSequentialAscii(type, type, &next_probe[i]);
4104
4105 // If length is not two, the string is not a candidate.
4106 __ Ldrsw(scratch,
4107 UntagSmiFieldMemOperand(candidate, String::kLengthOffset));
4108 __ Cmp(scratch, 2);
4109 __ B(ne, &next_probe[i]);
4110
4111 // Check if the two characters match.
4112 // Assumes that word load is little endian.
4113 __ Ldrh(scratch, FieldMemOperand(candidate, SeqOneByteString::kHeaderSize));
4114 __ Cmp(chars, scratch);
4115 __ B(eq, &found_in_string_table);
4116 __ Bind(&next_probe[i]);
4117 }
4118
4119 // No matching two character string found by probing.
4120 __ B(not_found);
4121
4122 // Scratch register contains result when we fall through to here.
4123 __ Bind(&found_in_string_table);
4124 __ Mov(x0, candidate);
4125 }
4126
4127
4128 void StringHelper::LoadPairInstanceTypes(MacroAssembler* masm,
4129 Register first_type,
4130 Register second_type,
4131 Register first_string,
4132 Register second_string) {
4133 ASSERT(!AreAliased(first_string, second_string, first_type, second_type));
4134 __ Ldr(first_type, FieldMemOperand(first_string, HeapObject::kMapOffset));
4135 __ Ldr(second_type, FieldMemOperand(second_string, HeapObject::kMapOffset));
4136 __ Ldrb(first_type, FieldMemOperand(first_type, Map::kInstanceTypeOffset));
4137 __ Ldrb(second_type, FieldMemOperand(second_type, Map::kInstanceTypeOffset));
4138 }
4139
4140
4141 void StringHelper::GenerateHashInit(MacroAssembler* masm, 3952 void StringHelper::GenerateHashInit(MacroAssembler* masm,
4142 Register hash, 3953 Register hash,
4143 Register character) { 3954 Register character) {
4144 ASSERT(!AreAliased(hash, character)); 3955 ASSERT(!AreAliased(hash, character));
4145 3956
4146 // hash = character + (character << 10); 3957 // hash = character + (character << 10);
4147 __ LoadRoot(hash, Heap::kHashSeedRootIndex); 3958 __ LoadRoot(hash, Heap::kHashSeedRootIndex);
4148 // Untag smi seed and add the character. 3959 // Untag smi seed and add the character.
4149 __ Add(hash, character, Operand(hash, LSR, kSmiShift)); 3960 __ Add(hash, character, Operand(hash, LSR, kSmiShift));
4150 3961
(...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after
4606 // sp[0] = right string 4417 // sp[0] = right string
4607 // sp[8] = left string. 4418 // sp[8] = left string.
4608 __ Push(left, right); 4419 __ Push(left, right);
4609 4420
4610 // Call the runtime. 4421 // Call the runtime.
4611 // Returns -1 (less), 0 (equal), or 1 (greater) tagged as a small integer. 4422 // Returns -1 (less), 0 (equal), or 1 (greater) tagged as a small integer.
4612 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 4423 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
4613 } 4424 }
4614 4425
4615 4426
4427 void ArrayPushStub::Generate(MacroAssembler* masm) {
4428 Register receiver = x0;
4429
4430 int argc = arguments_count();
4431
4432 if (argc == 0) {
4433 // Nothing to do, just return the length.
4434 __ Ldr(x0, FieldMemOperand(receiver, JSArray::kLengthOffset));
4435 __ Drop(argc + 1);
4436 __ Ret();
4437 return;
4438 }
4439
4440 Isolate* isolate = masm->isolate();
4441
4442 if (argc != 1) {
4443 __ TailCallExternalReference(
4444 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
4445 return;
4446 }
4447
4448 Label call_builtin, attempt_to_grow_elements, with_write_barrier;
4449
4450 Register elements_length = x8;
4451 Register length = x7;
4452 Register elements = x6;
4453 Register end_elements = x5;
4454 Register value = x4;
4455 // Get the elements array of the object.
4456 __ Ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
4457
4458 if (IsFastSmiOrObjectElementsKind(elements_kind())) {
4459 // Check that the elements are in fast mode and writable.
4460 __ CheckMap(elements,
4461 x10,
4462 Heap::kFixedArrayMapRootIndex,
4463 &call_builtin,
4464 DONT_DO_SMI_CHECK);
4465 }
4466
4467 // Get the array's length and calculate new length.
4468 __ Ldr(length, FieldMemOperand(receiver, JSArray::kLengthOffset));
4469 STATIC_ASSERT(kSmiTag == 0);
4470 __ Add(length, length, Operand(Smi::FromInt(argc)));
4471
4472 // Check if we could survive without allocation.
4473 __ Ldr(elements_length,
4474 FieldMemOperand(elements, FixedArray::kLengthOffset));
4475 __ Cmp(length, elements_length);
4476
4477 const int kEndElementsOffset =
4478 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
4479
4480 if (IsFastSmiOrObjectElementsKind(elements_kind())) {
4481 __ B(gt, &attempt_to_grow_elements);
4482
4483 // Check if value is a smi.
4484 __ Peek(value, (argc - 1) * kPointerSize);
4485 __ JumpIfNotSmi(value, &with_write_barrier);
4486
4487 // Store the value.
4488 // We may need a register containing the address end_elements below,
4489 // so write back the value in end_elements.
4490 __ Add(end_elements, elements,
4491 Operand::UntagSmiAndScale(length, kPointerSizeLog2));
4492 __ Str(value, MemOperand(end_elements, kEndElementsOffset, PreIndex));
4493 } else {
4494 // TODO(all): ARM has a redundant cmp here.
4495 __ B(gt, &call_builtin);
4496
4497 __ Peek(value, (argc - 1) * kPointerSize);
4498 __ StoreNumberToDoubleElements(value, length, elements, x10, d0, d1,
4499 &call_builtin, argc * kDoubleSize);
4500 }
4501
4502 // Save new length.
4503 __ Str(length, FieldMemOperand(receiver, JSArray::kLengthOffset));
4504
4505 // Return length.
4506 __ Drop(argc + 1);
4507 __ Mov(x0, length);
4508 __ Ret();
4509
4510 if (IsFastDoubleElementsKind(elements_kind())) {
4511 __ Bind(&call_builtin);
4512 __ TailCallExternalReference(
4513 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
4514 return;
4515 }
4516
4517 __ Bind(&with_write_barrier);
4518
4519 if (IsFastSmiElementsKind(elements_kind())) {
4520 if (FLAG_trace_elements_transitions) {
4521 __ B(&call_builtin);
4522 }
4523
4524 __ Ldr(x10, FieldMemOperand(value, HeapObject::kMapOffset));
4525 __ JumpIfHeapNumber(x10, &call_builtin);
4526
4527 ElementsKind target_kind = IsHoleyElementsKind(elements_kind())
4528 ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS;
4529 __ Ldr(x10, GlobalObjectMemOperand());
4530 __ Ldr(x10, FieldMemOperand(x10, GlobalObject::kNativeContextOffset));
4531 __ Ldr(x10, ContextMemOperand(x10, Context::JS_ARRAY_MAPS_INDEX));
4532 const int header_size = FixedArrayBase::kHeaderSize;
4533 // Verify that the object can be transitioned in place.
4534 const int origin_offset = header_size + elements_kind() * kPointerSize;
4535 __ ldr(x11, FieldMemOperand(receiver, origin_offset));
4536 __ ldr(x12, FieldMemOperand(x10, HeapObject::kMapOffset));
4537 __ cmp(x11, x12);
4538 __ B(ne, &call_builtin);
4539
4540 const int target_offset = header_size + target_kind * kPointerSize;
4541 __ Ldr(x10, FieldMemOperand(x10, target_offset));
4542 __ Mov(x11, receiver);
4543 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
4544 masm, DONT_TRACK_ALLOCATION_SITE, NULL);
4545 }
4546
4547 // Save new length.
4548 __ Str(length, FieldMemOperand(receiver, JSArray::kLengthOffset));
4549
4550 // Store the value.
4551 // We may need a register containing the address end_elements below,
4552 // so write back the value in end_elements.
4553 __ Add(end_elements, elements,
4554 Operand::UntagSmiAndScale(length, kPointerSizeLog2));
4555 __ Str(value, MemOperand(end_elements, kEndElementsOffset, PreIndex));
4556
4557 __ RecordWrite(elements,
4558 end_elements,
4559 value,
4560 kLRHasNotBeenSaved,
4561 kDontSaveFPRegs,
4562 EMIT_REMEMBERED_SET,
4563 OMIT_SMI_CHECK);
4564 __ Drop(argc + 1);
4565 __ Mov(x0, length);
4566 __ Ret();
4567
4568 __ Bind(&attempt_to_grow_elements);
4569
4570 if (!FLAG_inline_new) {
4571 __ B(&call_builtin);
4572 }
4573
4574 Register argument = x2;
4575 __ Peek(argument, (argc - 1) * kPointerSize);
4576 // Growing elements that are SMI-only requires special handling in case
4577 // the new element is non-Smi. For now, delegate to the builtin.
4578 if (IsFastSmiElementsKind(elements_kind())) {
4579 __ JumpIfNotSmi(argument, &call_builtin);
4580 }
4581
4582 // We could be lucky and the elements array could be at the top of new-space.
4583 // In this case we can just grow it in place by moving the allocation pointer
4584 // up.
4585 ExternalReference new_space_allocation_top =
4586 ExternalReference::new_space_allocation_top_address(isolate);
4587 ExternalReference new_space_allocation_limit =
4588 ExternalReference::new_space_allocation_limit_address(isolate);
4589
4590 const int kAllocationDelta = 4;
4591 ASSERT(kAllocationDelta >= argc);
4592 Register allocation_top_addr = x5;
4593 Register allocation_top = x9;
4594 // Load top and check if it is the end of elements.
4595 __ Add(end_elements, elements,
4596 Operand::UntagSmiAndScale(length, kPointerSizeLog2));
4597 __ Add(end_elements, end_elements, kEndElementsOffset);
4598 __ Mov(allocation_top_addr, Operand(new_space_allocation_top));
4599 __ Ldr(allocation_top, MemOperand(allocation_top_addr));
4600 __ Cmp(end_elements, allocation_top);
4601 __ B(ne, &call_builtin);
4602
4603 __ Mov(x10, Operand(new_space_allocation_limit));
4604 __ Ldr(x10, MemOperand(x10));
4605 __ Add(allocation_top, allocation_top, kAllocationDelta * kPointerSize);
4606 __ Cmp(allocation_top, x10);
4607 __ B(hi, &call_builtin);
4608
4609 // We fit and could grow elements.
4610 // Update new_space_allocation_top.
4611 __ Str(allocation_top, MemOperand(allocation_top_addr));
4612 // Push the argument.
4613 __ Str(argument, MemOperand(end_elements));
4614 // Fill the rest with holes.
4615 __ LoadRoot(x10, Heap::kTheHoleValueRootIndex);
4616 for (int i = 1; i < kAllocationDelta; i++) {
4617 // TODO(all): Try to use stp here.
4618 __ Str(x10, MemOperand(end_elements, i * kPointerSize));
4619 }
4620
4621 // Update elements' and array's sizes.
4622 __ Str(length, FieldMemOperand(receiver, JSArray::kLengthOffset));
4623 __ Add(elements_length,
4624 elements_length,
4625 Operand(Smi::FromInt(kAllocationDelta)));
4626 __ Str(elements_length,
4627 FieldMemOperand(elements, FixedArray::kLengthOffset));
4628
4629 // Elements are in new space, so write barrier is not required.
4630 __ Drop(argc + 1);
4631 __ Mov(x0, length);
4632 __ Ret();
4633
4634 __ Bind(&call_builtin);
4635 __ TailCallExternalReference(
4636 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
4637 }
4638
4639
4616 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) { 4640 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
4617 // ----------- S t a t e ------------- 4641 // ----------- S t a t e -------------
4618 // -- x1 : left 4642 // -- x1 : left
4619 // -- x0 : right 4643 // -- x0 : right
4620 // -- lr : return address 4644 // -- lr : return address
4621 // ----------------------------------- 4645 // -----------------------------------
4622 Isolate* isolate = masm->isolate(); 4646 Isolate* isolate = masm->isolate();
4623 4647
4624 // Load x2 with the allocation site. We stick an undefined dummy value here 4648 // Load x2 with the allocation site. We stick an undefined dummy value here
4625 // and replace it with the real allocation site later when we instantiate this 4649 // and replace it with the real allocation site later when we instantiate this
4626 // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate(). 4650 // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
4627 __ LoadObject(x2, handle(isolate->heap()->undefined_value())); 4651 __ LoadObject(x2, handle(isolate->heap()->undefined_value()));
4628 4652
4629 // Make sure that we actually patched the allocation site. 4653 // Make sure that we actually patched the allocation site.
4630 if (FLAG_debug_code) { 4654 if (FLAG_debug_code) {
4631 __ AssertNotSmi(x2, kExpectedAllocationSite); 4655 __ AssertNotSmi(x2, kExpectedAllocationSite);
4632 __ Ldr(x10, FieldMemOperand(x2, HeapObject::kMapOffset)); 4656 __ Ldr(x10, FieldMemOperand(x2, HeapObject::kMapOffset));
4633 __ AssertRegisterIsRoot(x10, Heap::kAllocationSiteMapRootIndex, 4657 __ AssertRegisterIsRoot(x10, Heap::kAllocationSiteMapRootIndex,
4634 kExpectedAllocationSite); 4658 kExpectedAllocationSite);
4635 } 4659 }
4636 4660
4637 // Tail call into the stub that handles binary operations with allocation 4661 // Tail call into the stub that handles binary operations with allocation
4638 // sites. 4662 // sites.
4639 BinaryOpWithAllocationSiteStub stub(state_); 4663 BinaryOpWithAllocationSiteStub stub(state_);
4640 __ TailCallStub(&stub); 4664 __ TailCallStub(&stub);
4641 } 4665 }
4642 4666
4643 4667
4644 void StringAddStub::Generate(MacroAssembler* masm) {
4645 Label call_runtime, call_builtin;
4646 Builtins::JavaScript builtin_id = Builtins::ADD;
4647
4648 Counters* counters = masm->isolate()->counters();
4649
4650 // Stack on entry:
4651 // sp[0]: second argument (right).
4652 // sp[8]: first argument (left).
4653
4654 Register result = x0;
4655 Register left = x10;
4656 Register right = x11;
4657 Register left_type = x12;
4658 Register right_type = x13;
4659
4660 // Pop the two arguments from the stack.
4661 __ Pop(right, left);
4662
4663 // Make sure that both arguments are strings if not known in advance.
4664 // Otherwise, at least one of the arguments is definitely a string,
4665 // and we convert the one that is not known to be a string.
4666 if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) {
4667 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT);
4668 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT);
4669 __ JumpIfEitherSmi(right, left, &call_runtime);
4670 // Load instance types.
4671 StringHelper::LoadPairInstanceTypes(masm, left_type, right_type, left,
4672 right);
4673 STATIC_ASSERT(kStringTag == 0);
4674 // If either is not a string, go to runtime.
4675 __ Tbnz(left_type, MaskToBit(kIsNotStringMask), &call_runtime);
4676 __ Tbnz(right_type, MaskToBit(kIsNotStringMask), &call_runtime);
4677 } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) {
4678 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0);
4679 GenerateConvertArgument(masm, left, x12, x13, x14, x15, &call_builtin);
4680 builtin_id = Builtins::STRING_ADD_RIGHT;
4681 } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) {
4682 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0);
4683 GenerateConvertArgument(masm, right, x12, x13, x14, x15, &call_builtin);
4684 builtin_id = Builtins::STRING_ADD_LEFT;
4685 }
4686
4687 // Both arguments are strings.
4688 // x0 result pointer to result string object (uninit)
4689 // x10 left pointer to first string object
4690 // x11 right pointer to second string object
4691 // x12 left_type first string instance type (if STRING_ADD_CHECK_BOTH)
4692 // x13 right_type second string instance type (if STRING_ADD_CHECK_BOTH)
4693 Register left_len = x14;
4694 Register right_len = x15;
4695 {
4696 Label strings_not_empty;
4697 // Speculatively move pointer to left string into the result register.
4698 __ Mov(result, left);
4699 // Check if either of the strings are empty. In that case return the other.
4700 __ Ldrsw(left_len, UntagSmiFieldMemOperand(left, String::kLengthOffset));
4701 __ Ldrsw(right_len, UntagSmiFieldMemOperand(right, String::kLengthOffset));
4702 // Test if first string is empty.
4703 __ Cmp(left_len, 0);
4704 // If first is empty, return second.
4705 __ CmovX(result, right, eq);
4706 // Else test if second string is empty.
4707 __ Ccmp(right_len, 0, ZFlag, ne);
4708 // If either string was empty, return result.
4709 __ B(ne, &strings_not_empty);
4710
4711 __ IncrementCounter(counters->string_add_native(), 1, x3, x4);
4712 __ Ret();
4713
4714 __ Bind(&strings_not_empty);
4715 }
4716
4717 // Load string instance types.
4718 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) {
4719 StringHelper::LoadPairInstanceTypes(masm, left_type, right_type, left,
4720 right);
4721 }
4722
4723 // Both strings are non-empty.
4724 // x10 left first string
4725 // x11 right second string
4726 // x12 left_type first string instance type
4727 // x13 right_type second string instance type
4728 // x14 left_len length of first string
4729 // x15 right_len length of second string
4730 Label string_add_flat_result, longer_than_two;
4731 // Adding two lengths can't overflow
4732 STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2);
4733 Register length = x1;
4734 __ Add(length, left_len, right_len);
4735 // Use the string table when adding two one character strings, as it helps
4736 // later optimizations to return a string here.
4737 __ Cmp(length, 2);
4738 __ B(ne, &longer_than_two);
4739
4740 // Check that both strings are non-external ASCII strings.
4741 __ JumpIfBothInstanceTypesAreNotSequentialAscii(left_type, right_type, x2,
4742 x3, &call_runtime);
4743
4744 Register left_char = x6;
4745 Register right_char = x7;
4746 // Get the two characters forming the sub string.
4747 __ Ldrb(left_char, FieldMemOperand(left, SeqOneByteString::kHeaderSize));
4748 __ Ldrb(right_char, FieldMemOperand(right, SeqOneByteString::kHeaderSize));
4749
4750 // Try to lookup two character string in string table. If it is not found
4751 // just allocate a new one.
4752 // x0 result pointer to result string (uninit)
4753 // x1 length sum of lengths of strings
4754 // x6 left_char first character of first string
4755 // x7 right_char first character of second string
4756 // x10 left pointer to first string object
4757 // x11 right pointer to second string object
4758 // x12 left_type first string instance type
4759 // x13 right_type second string instance type
4760 // x14 left_len length of first string
4761 // x15 right_len length of second string
4762 Label make_two_character_string;
4763 StringHelper::GenerateTwoCharacterStringTableProbe(
4764 masm,
4765 left_char,
4766 right_char,
4767 x2, x3, x4, x5, x8,
4768 &make_two_character_string);
4769 // Result register will be initialised with pointer to probed string, if
4770 // found.
4771 __ IncrementCounter(counters->string_add_native(), 1, x3, x4);
4772 __ Ret();
4773
4774 __ Bind(&make_two_character_string);
4775 // Resulting string has length two and first chars of two strings are
4776 // combined into single halfword in left_char(x6) by
4777 // GenerateTwoCharacterStringTableProbe().
4778 // Store the result to a newly-allocated string using a halfword store.
4779 // This assumes the processor is little endian.
4780 __ Mov(length, 2);
4781 __ AllocateAsciiString(result, length, x12, x13, x14, &call_runtime);
4782 __ Strh(left_char, FieldMemOperand(result, SeqOneByteString::kHeaderSize));
4783 __ IncrementCounter(counters->string_add_native(), 1, x3, x4);
4784 __ Ret();
4785
4786 __ Bind(&longer_than_two);
4787 // x0 result pointer to result string (uninit)
4788 // x1 length sum of lengths of strings
4789 // x10 left pointer to first string object
4790 // x11 right pointer to second string object
4791 // x12 left_type first string instance type
4792 // x13 right_type second string instance type
4793 // x14 left_len length of first string
4794 // x15 right_len length of second string
4795
4796 // Check if resulting string will be flat.
4797 __ Cmp(length, ConsString::kMinLength);
4798 __ B(lt, &string_add_flat_result);
4799 // Handle exceptionally long strings in the runtime system.
4800 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0);
4801 ASSERT(IsPowerOf2(String::kMaxLength + 1));
4802
4803 // (kMaxLength + 1) is a single bit, so if it's set, string length is >=
4804 // kMaxLength + 1, and the string must be handled by the runtime.
4805 __ Tbnz(length, MaskToBit(String::kMaxLength + 1), &call_runtime);
4806
4807 // If result is not supposed to be flat, allocate a cons string object.
4808 // If both strings are ASCII the result is an ASCII cons string.
4809 Label non_ascii, allocated, ascii_data;
4810 STATIC_ASSERT(kTwoByteStringTag == 0);
4811 Register combined_type = x2;
4812 __ And(combined_type, left_type, right_type);
4813 __ Tbz(combined_type, MaskToBit(kStringEncodingMask), &non_ascii);
4814
4815 // Allocate an ASCII cons string.
4816 __ Bind(&ascii_data);
4817 __ AllocateAsciiConsString(result, length, x12, x13, &call_runtime);
4818 __ Bind(&allocated);
4819 // Fill the fields of the cons string.
4820 Label skip_write_barrier, after_writing;
4821 ExternalReference high_promotion_mode = ExternalReference::
4822 new_space_high_promotion_mode_active_address(masm->isolate());
4823 __ Mov(x3, Operand(high_promotion_mode));
4824 __ Ldr(x3, MemOperand(x3));
4825 __ Cbz(x3, &skip_write_barrier);
4826
4827 __ Str(left, FieldMemOperand(result, ConsString::kFirstOffset));
4828 __ RecordWriteField(result,
4829 ConsString::kFirstOffset,
4830 left,
4831 x3,
4832 kLRHasNotBeenSaved,
4833 kDontSaveFPRegs,
4834 EMIT_REMEMBERED_SET,
4835 INLINE_SMI_CHECK);
4836 __ Str(right, FieldMemOperand(result, ConsString::kSecondOffset));
4837 __ RecordWriteField(result,
4838 ConsString::kSecondOffset,
4839 right,
4840 x3,
4841 kLRHasNotBeenSaved,
4842 kDontSaveFPRegs,
4843 EMIT_REMEMBERED_SET,
4844 INLINE_SMI_CHECK);
4845 __ B(&after_writing);
4846 __ Bind(&skip_write_barrier);
4847
4848 __ Str(left, FieldMemOperand(result, ConsString::kFirstOffset));
4849 __ Str(right, FieldMemOperand(result, ConsString::kSecondOffset));
4850 __ Bind(&after_writing);
4851
4852 __ IncrementCounter(counters->string_add_native(), 1, x3, x4);
4853 __ Ret();
4854
4855 __ Bind(&non_ascii);
4856 // At least one of the strings has a two-byte encoding. Check whether it
4857 // happens to contain only one-byte characters.
4858 // x2 combined_type bitwise-and of first and second string instance types
4859 // x12 left_type first string instance type
4860 // x13 right_type second string instance type
4861 __ Tbnz(combined_type, MaskToBit(kOneByteDataHintMask), &ascii_data);
4862
4863 // If one string has one-byte encoding, and the other is an ASCII string with
4864 // two-byte encoding, the result can still be an ASCII string.
4865 STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0);
4866 __ Eor(x2, left_type, right_type);
4867 __ And(x2, x2, kOneByteStringTag | kOneByteDataHintTag);
4868 __ Cmp(x2, kOneByteStringTag | kOneByteDataHintTag);
4869 __ B(eq, &ascii_data);
4870
4871 // Allocate a two byte cons string.
4872 __ AllocateTwoByteConsString(result, length, x12, x13, &call_runtime);
4873 __ B(&allocated);
4874
4875 // We cannot encounter sliced strings or cons strings here since:
4876 STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength);
4877 // Handle creating a flat result from either external or sequential strings.
4878 // Locate the first characters' locations.
4879 Label first_prepared, second_prepared;
4880 __ Bind(&string_add_flat_result);
4881
4882 Register temp = x5;
4883 // Check whether both strings have same encoding
4884 // x1 length sum of string lengths
4885 // x5 temp temporary register (uninit)
4886 // x6 left_char pointer to first character of first string (uninit)
4887 // x7 right_char pointer to first character of second string (uninit)
4888 // x10 left first string
4889 // x11 right second string
4890 // x12 left_type first string instance type
4891 // x13 right_type second string instance type
4892 // x14 left_len length of first string
4893 // x15 right_len length of second string
4894 __ Eor(temp, left_type, right_type);
4895 __ Tbnz(temp, MaskToBit(kStringEncodingMask), &call_runtime);
4896
4897 STATIC_ASSERT(kSeqStringTag == 0);
4898 STATIC_ASSERT(kShortExternalStringTag != 0);
4899 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
4900
4901 __ Tst(left_type, kStringRepresentationMask);
4902 __ Add(left_char, left, SeqOneByteString::kHeaderSize - kHeapObjectTag);
4903 __ B(eq, &first_prepared);
4904 // External string: rule out short external string and load string resource.
4905 __ Tbnz(left_type, MaskToBit(kShortExternalStringMask), &call_runtime);
4906 __ Ldr(left_char, FieldMemOperand(left, ExternalString::kResourceDataOffset));
4907 __ Bind(&first_prepared);
4908
4909 __ Tst(right_type, kStringRepresentationMask);
4910 __ Add(right_char, right, SeqOneByteString::kHeaderSize - kHeapObjectTag);
4911 __ B(eq, &second_prepared);
4912 // External string: rule out short external string and load string resource.
4913 __ Tbnz(right_type, MaskToBit(kShortExternalStringMask), &call_runtime);
4914 __ Ldr(right_char,
4915 FieldMemOperand(right, ExternalString::kResourceDataOffset));
4916 __ Bind(&second_prepared);
4917
4918 Label non_ascii_string_add_flat_result;
4919 // x0 result pointer to result string (uninit)
4920 // x1 length sum of string lengths
4921 // x6 left_char pointer to first character of first string
4922 // x7 right_char pointer to first character of second string
4923 // x12 left_type first string instance type
4924 // x13 right_type second string instance type
4925 // x14 left_len length of first string
4926 // x15 right_len length of second string
4927
4928 // Both strings have the same encoding.
4929 STATIC_ASSERT(kTwoByteStringTag == 0);
4930 __ Tbz(right_type, MaskToBit(kStringEncodingMask),
4931 &non_ascii_string_add_flat_result);
4932
4933 Register result_char = x10;
4934 __ AllocateAsciiString(result, length, x3, x12, x13, &call_runtime);
4935 __ Add(result_char, result, SeqOneByteString::kHeaderSize - kHeapObjectTag);
4936 // x0 result pointer to result ascii string object
4937 // x1 length sum of string lengths
4938 // x6 left_char pointer to first character of first string
4939 // x7 right_char pointer to first character of second string
4940 // x10 result_char pointer to first character of result string
4941 // x14 left_len length of first string
4942 // x15 right_len length of second string
4943 __ CopyBytes(result_char, left_char, left_len, temp, kCopyShort);
4944 // x10 result_char pointer to next character of result string
4945 __ CopyBytes(result_char, right_char, right_len, temp, kCopyShort);
4946 __ IncrementCounter(counters->string_add_native(), 1, x3, x4);
4947 __ Ret();
4948
4949
4950 __ Bind(&non_ascii_string_add_flat_result);
4951 __ AllocateTwoByteString(result, length, x3, x12, x13, &call_runtime);
4952 __ Add(result_char, result, SeqTwoByteString::kHeaderSize - kHeapObjectTag);
4953 // x0 result pointer to result two byte string object
4954 // x1 length sum of string lengths
4955 // x6 left_char pointer to first character of first string
4956 // x7 right_char pointer to first character of second string
4957 // x10 result_char pointer to first character of result string
4958 // x14 left_len length of first string
4959 // x15 right_len length of second string
4960 __ Add(left_len, left_len, left_len);
4961 __ CopyBytes(result_char, left_char, left_len, temp, kCopyShort);
4962
4963 // x10 result_char pointer to next character of result string
4964 __ Add(right_len, right_len, right_len);
4965 __ CopyBytes(result_char, right_char, right_len, temp, kCopyShort);
4966 __ IncrementCounter(counters->string_add_native(), 1, x3, x4);
4967 __ Ret();
4968
4969
4970 // Just jump to runtime to add the two strings.
4971 __ Bind(&call_runtime);
4972 // Restore stack arguments.
4973 __ Push(left, right);
4974 __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
4975
4976 if (call_builtin.is_linked()) {
4977 __ Bind(&call_builtin);
4978 // Restore stack arguments.
4979 __ Push(left, right);
4980 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
4981 }
4982 }
4983
4984
4985 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
4986 Register arg,
4987 Register scratch1,
4988 Register scratch2,
4989 Register scratch3,
4990 Register scratch4,
4991 Label* slow) {
4992 ASSERT(!AreAliased(arg, scratch1, scratch2, scratch3, scratch4));
4993
4994 // First check if the argument is already a string.
4995 Label not_string, done;
4996 __ JumpIfSmi(arg, &not_string);
4997 __ JumpIfObjectType(arg, scratch1, scratch1, FIRST_NONSTRING_TYPE, &done, lt);
4998
4999 // Check the number to string cache.
5000 __ Bind(&not_string);
5001 // Puts the cache result into scratch1.
5002 __ LookupNumberStringCache(arg, scratch1, scratch2, scratch3, scratch4, slow);
5003 __ Mov(arg, scratch1);
5004
5005 __ Bind(&done);
5006 }
5007
5008
5009 void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
5010 __ Push(x0, x1);
5011 }
5012
5013
5014 void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm) {
5015 __ Pop(x1, x0);
5016 }
5017
5018
5019 bool CodeStub::CanUseFPRegisters() { 4668 bool CodeStub::CanUseFPRegisters() {
5020 // FP registers always available on A64. 4669 // FP registers always available on A64.
5021 return true; 4670 return true;
5022 } 4671 }
5023 4672
5024 4673
5025 void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) { 4674 void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
5026 // We need some extra registers for this stub, they have been allocated 4675 // We need some extra registers for this stub, they have been allocated
5027 // but we need to save them before using them. 4676 // but we need to save them before using them.
5028 regs_.Save(masm); 4677 regs_.Save(masm);
(...skipping 634 matching lines...) Expand 10 before | Expand all | Expand 10 after
5663 } 5312 }
5664 } 5313 }
5665 5314
5666 5315
5667 // TODO(jbramley): If this needs to be a special case, make it a proper template 5316 // TODO(jbramley): If this needs to be a special case, make it a proper template
5668 // specialization, and not a separate function. 5317 // specialization, and not a separate function.
5669 static void CreateArrayDispatchOneArgument(MacroAssembler* masm, 5318 static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
5670 AllocationSiteOverrideMode mode) { 5319 AllocationSiteOverrideMode mode) {
5671 // x0 - argc 5320 // x0 - argc
5672 // x1 - constructor? 5321 // x1 - constructor?
5673 // x2 - type info cell (if mode != DISABLE_ALLOCATION_SITES) 5322 // x2 - allocation site (if mode != DISABLE_ALLOCATION_SITES)
5674 // x3 - kind (if mode != DISABLE_ALLOCATION_SITES) 5323 // x3 - kind (if mode != DISABLE_ALLOCATION_SITES)
5675 // sp[0] - last argument 5324 // sp[0] - last argument
5676 5325
5677 Register type_info_cell = x2; 5326 Register allocation_site = x2;
5678 Register kind = x3; 5327 Register kind = x3;
5679 5328
5680 Label normal_sequence; 5329 Label normal_sequence;
5681 if (mode == DONT_OVERRIDE) { 5330 if (mode == DONT_OVERRIDE) {
5682 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); 5331 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
5683 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 5332 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
5684 STATIC_ASSERT(FAST_ELEMENTS == 2); 5333 STATIC_ASSERT(FAST_ELEMENTS == 2);
5685 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); 5334 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
5686 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS == 4); 5335 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS == 4);
5687 STATIC_ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5); 5336 STATIC_ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
(...skipping 17 matching lines...) Expand all
5705 5354
5706 __ Bind(&normal_sequence); 5355 __ Bind(&normal_sequence);
5707 ArraySingleArgumentConstructorStub stub(initial, 5356 ArraySingleArgumentConstructorStub stub(initial,
5708 DISABLE_ALLOCATION_SITES); 5357 DISABLE_ALLOCATION_SITES);
5709 __ TailCallStub(&stub); 5358 __ TailCallStub(&stub);
5710 } else if (mode == DONT_OVERRIDE) { 5359 } else if (mode == DONT_OVERRIDE) {
5711 // We are going to create a holey array, but our kind is non-holey. 5360 // We are going to create a holey array, but our kind is non-holey.
5712 // Fix kind and retry (only if we have an allocation site in the cell). 5361 // Fix kind and retry (only if we have an allocation site in the cell).
5713 __ Orr(kind, kind, 1); 5362 __ Orr(kind, kind, 1);
5714 5363
5715 __ Ldr(x10, FieldMemOperand(type_info_cell, Cell::kValueOffset));
5716
5717 if (FLAG_debug_code) { 5364 if (FLAG_debug_code) {
5718 __ Ldr(x10, FieldMemOperand(x10, 0)); 5365 __ Ldr(x10, FieldMemOperand(allocation_site, 0));
5719 __ JumpIfNotRoot(x10, Heap::kAllocationSiteMapRootIndex, 5366 __ JumpIfNotRoot(x10, Heap::kAllocationSiteMapRootIndex,
5720 &normal_sequence); 5367 &normal_sequence);
5721 __ Assert(eq, kExpectedAllocationSiteInCell); 5368 __ Assert(eq, kExpectedAllocationSite);
5722 __ Ldr(x10, FieldMemOperand(type_info_cell, Cell::kValueOffset));
5723 } 5369 }
5724 5370
5725 // Save the resulting elements kind in type info. We can't just store 'kind' 5371 // Save the resulting elements kind in type info. We can't just store 'kind'
5726 // in the AllocationSite::transition_info field because elements kind is 5372 // in the AllocationSite::transition_info field because elements kind is
5727 // restricted to a portion of the field; upper bits need to be left alone. 5373 // restricted to a portion of the field; upper bits need to be left alone.
5728 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); 5374 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
5729 __ Ldr(x11, FieldMemOperand(x10, AllocationSite::kTransitionInfoOffset)); 5375 __ Ldr(x11, FieldMemOperand(allocation_site,
5376 AllocationSite::kTransitionInfoOffset));
5730 __ Add(x11, x11, Operand(Smi::FromInt(kFastElementsKindPackedToHoley))); 5377 __ Add(x11, x11, Operand(Smi::FromInt(kFastElementsKindPackedToHoley)));
5731 __ Str(x11, FieldMemOperand(x10, AllocationSite::kTransitionInfoOffset)); 5378 __ Str(x11, FieldMemOperand(allocation_site,
5379 AllocationSite::kTransitionInfoOffset));
5732 5380
5733 __ Bind(&normal_sequence); 5381 __ Bind(&normal_sequence);
5734 int last_index = 5382 int last_index =
5735 GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND); 5383 GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
5736 for (int i = 0; i <= last_index; ++i) { 5384 for (int i = 0; i <= last_index; ++i) {
5737 Label next; 5385 Label next;
5738 ElementsKind candidate_kind = GetFastElementsKindFromSequenceIndex(i); 5386 ElementsKind candidate_kind = GetFastElementsKindFromSequenceIndex(i);
5739 // TODO(jbramley): Is this the best way to handle this? Can we make the 5387 // TODO(jbramley): Is this the best way to handle this? Can we make the
5740 // tail calls conditional, rather than hopping over each one? 5388 // tail calls conditional, rather than hopping over each one?
5741 __ CompareAndBranch(kind, candidate_kind, ne, &next); 5389 __ CompareAndBranch(kind, candidate_kind, ne, &next);
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
5855 // In type_info_cell, we expect either undefined or a valid Cell. 5503 // In type_info_cell, we expect either undefined or a valid Cell.
5856 Label okay_here; 5504 Label okay_here;
5857 Handle<Map> cell_map = masm->isolate()->factory()->cell_map(); 5505 Handle<Map> cell_map = masm->isolate()->factory()->cell_map();
5858 __ JumpIfRoot(type_info_cell, Heap::kUndefinedValueRootIndex, &okay_here); 5506 __ JumpIfRoot(type_info_cell, Heap::kUndefinedValueRootIndex, &okay_here);
5859 __ Ldr(x10, FieldMemOperand(type_info_cell, Cell::kMapOffset)); 5507 __ Ldr(x10, FieldMemOperand(type_info_cell, Cell::kMapOffset));
5860 __ Cmp(x10, Operand(cell_map)); 5508 __ Cmp(x10, Operand(cell_map));
5861 __ Assert(eq, kExpectedPropertyCellInTypeInfoCell); 5509 __ Assert(eq, kExpectedPropertyCellInTypeInfoCell);
5862 __ Bind(&okay_here); 5510 __ Bind(&okay_here);
5863 } 5511 }
5864 5512
5513 Register allocation_site = x2; // Overwrites type_info_cell.
5865 Register kind = x3; 5514 Register kind = x3;
5866 Label no_info; 5515 Label no_info;
5867 // Get the elements kind and case on that. 5516 // Get the elements kind and case on that.
5868 __ JumpIfRoot(type_info_cell, Heap::kUndefinedValueRootIndex, &no_info); 5517 __ JumpIfRoot(type_info_cell, Heap::kUndefinedValueRootIndex, &no_info);
5869 __ Ldr(kind, FieldMemOperand(type_info_cell, PropertyCell::kValueOffset)); 5518 __ Ldr(allocation_site, FieldMemOperand(type_info_cell,
5519 PropertyCell::kValueOffset));
5870 5520
5871 // If the type cell is undefined, or contains anything other than an 5521 // If the type cell is undefined, or contains anything other than an
5872 // AllocationSite, call an array constructor that doesn't use AllocationSites. 5522 // AllocationSite, call an array constructor that doesn't use AllocationSites.
5873 __ Ldr(x10, FieldMemOperand(kind, AllocationSite::kMapOffset)); 5523 __ Ldr(x10, FieldMemOperand(allocation_site, AllocationSite::kMapOffset));
5874 __ JumpIfNotRoot(x10, Heap::kAllocationSiteMapRootIndex, &no_info); 5524 __ JumpIfNotRoot(x10, Heap::kAllocationSiteMapRootIndex, &no_info);
5875 5525
5876 __ Ldrsw(kind, 5526 __ Ldrsw(kind,
5877 UntagSmiFieldMemOperand(kind, 5527 UntagSmiFieldMemOperand(allocation_site,
5878 AllocationSite::kTransitionInfoOffset)); 5528 AllocationSite::kTransitionInfoOffset));
5879 __ And(kind, kind, AllocationSite::ElementsKindBits::kMask); 5529 __ And(kind, kind, AllocationSite::ElementsKindBits::kMask);
5880 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE); 5530 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
5881 5531
5882 __ Bind(&no_info); 5532 __ Bind(&no_info);
5883 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES); 5533 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
5884 } 5534 }
5885 5535
5886 5536
5887 void InternalArrayConstructorStub::GenerateCase( 5537 void InternalArrayConstructorStub::GenerateCase(
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
5975 __ Bind(&fast_elements_case); 5625 __ Bind(&fast_elements_case);
5976 GenerateCase(masm, FAST_ELEMENTS); 5626 GenerateCase(masm, FAST_ELEMENTS);
5977 } 5627 }
5978 5628
5979 5629
5980 #undef __ 5630 #undef __
5981 5631
5982 } } // namespace v8::internal 5632 } } // namespace v8::internal
5983 5633
5984 #endif // V8_TARGET_ARCH_A64 5634 #endif // V8_TARGET_ARCH_A64
OLDNEW
« no previous file with comments | « src/a64/code-stubs-a64.h ('k') | src/a64/codegen-a64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698