| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 __ bx(R0); | 213 __ bx(R0); |
| 214 } | 214 } |
| 215 | 215 |
| 216 | 216 |
| 217 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { | 217 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { |
| 218 __ Unimplemented("FixCallersTarget stub"); | 218 __ Unimplemented("FixCallersTarget stub"); |
| 219 } | 219 } |
| 220 | 220 |
| 221 | 221 |
| 222 // Input parameters: | 222 // Input parameters: |
| 223 // R2: Smi-tagged argument count, may be zero. | 223 // R2: smi-tagged argument count, may be zero. |
| 224 // FP[kLastParamSlotIndex]: Last argument. | 224 // FP[kLastParamSlotIndex]: last argument. |
| 225 static void PushArgumentsArray(Assembler* assembler) { | 225 static void PushArgumentsArray(Assembler* assembler) { |
| 226 // Allocate array to store arguments of caller. | 226 // Allocate array to store arguments of caller. |
| 227 __ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null())); | 227 __ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null())); |
| 228 // R1: Null element type for raw Array. | 228 // R1: null element type for raw Array. |
| 229 // R2: Smi-tagged argument count, may be zero. | 229 // R2: smi-tagged argument count, may be zero. |
| 230 __ BranchLink(&StubCode::AllocateArrayLabel()); | 230 __ BranchLink(&StubCode::AllocateArrayLabel()); |
| 231 // R0: newly allocated array. | 231 // R0: newly allocated array. |
| 232 // R2: Smi-tagged argument count, may be zero (was preserved by the stub). | 232 // R2: smi-tagged argument count, may be zero (was preserved by the stub). |
| 233 __ Push(R0); // Array is in R0 and on top of stack. | 233 __ Push(R0); // Array is in R0 and on top of stack. |
| 234 __ add(R1, FP, ShifterOperand(R2, LSL, 1)); | 234 __ add(R1, FP, ShifterOperand(R2, LSL, 1)); |
| 235 __ AddImmediate(R1, (kLastParamSlotIndex - 1) * kWordSize); | 235 __ AddImmediate(R1, (kLastParamSlotIndex - 1) * kWordSize); |
| 236 __ AddImmediate(R3, R0, Array::data_offset() - kHeapObjectTag); | 236 __ AddImmediate(R3, R0, Array::data_offset() - kHeapObjectTag); |
| 237 Label loop, loop_condition; | 237 // R1: address of first argument on stack. |
| 238 __ b(&loop_condition); | 238 // R3: address of first argument in array. |
| 239 Label loop; |
| 239 __ Bind(&loop); | 240 __ Bind(&loop); |
| 240 __ ldr(IP, Address(R1, 0)); | |
| 241 __ str(IP, Address(R3, 0)); | |
| 242 __ AddImmediate(R1, -kWordSize); | |
| 243 __ AddImmediate(R3, kWordSize); | |
| 244 __ Bind(&loop_condition); | |
| 245 __ subs(R2, R2, ShifterOperand(Smi::RawValue(1))); // R2 is Smi. | 241 __ subs(R2, R2, ShifterOperand(Smi::RawValue(1))); // R2 is Smi. |
| 242 __ ldr(IP, Address(R1, 0), PL); |
| 243 __ str(IP, Address(R3, 0), PL); |
| 244 __ AddImmediate(R1, -kWordSize, PL); |
| 245 __ AddImmediate(R3, kWordSize, PL); |
| 246 __ b(&loop, PL); | 246 __ b(&loop, PL); |
| 247 } | 247 } |
| 248 | 248 |
| 249 | 249 |
| 250 void StubCode::GenerateInstanceFunctionLookupStub(Assembler* assembler) { | 250 void StubCode::GenerateInstanceFunctionLookupStub(Assembler* assembler) { |
| 251 __ Unimplemented("InstanceFunctionLookup stub"); | 251 __ Unimplemented("InstanceFunctionLookup stub"); |
| 252 } | 252 } |
| 253 | 253 |
| 254 | 254 |
| 255 void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { | 255 void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { |
| 256 __ Unimplemented("DeoptimizeLazy stub"); | 256 __ Unimplemented("DeoptimizeLazy stub"); |
| 257 } | 257 } |
| 258 | 258 |
| 259 | 259 |
| 260 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { | 260 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { |
| 261 __ Unimplemented("Deoptimize stub"); | 261 __ Unimplemented("Deoptimize stub"); |
| 262 } | 262 } |
| 263 | 263 |
| 264 | 264 |
| 265 void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { | 265 void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { |
| 266 __ Unimplemented("MegamorphicMiss stub"); | 266 __ Unimplemented("MegamorphicMiss stub"); |
| 267 } | 267 } |
| 268 | 268 |
| 269 | 269 |
| 270 // Called for inline allocation of arrays. | 270 // Called for inline allocation of arrays. |
| 271 // Input parameters: | 271 // Input parameters: |
| 272 // LR: return address. | 272 // LR: return address. |
| 273 // R2: Array length as Smi. | 273 // R2: array length as Smi. |
| 274 // R1: array element type (either NULL or an instantiated type). | 274 // R1: array element type (either NULL or an instantiated type). |
| 275 // NOTE: R2 cannot be clobbered here as the caller relies on it being saved. | 275 // NOTE: R2 cannot be clobbered here as the caller relies on it being saved. |
| 276 // The newly allocated object is returned in R0. | 276 // The newly allocated object is returned in R0. |
| 277 void StubCode::GenerateAllocateArrayStub(Assembler* assembler) { | 277 void StubCode::GenerateAllocateArrayStub(Assembler* assembler) { |
| 278 Label slow_case; | 278 Label slow_case; |
| 279 if (FLAG_inline_alloc) { | 279 if (FLAG_inline_alloc) { |
| 280 // Compute the size to be allocated, it is based on the array length | 280 // Compute the size to be allocated, it is based on the array length |
| 281 // and is computed as: | 281 // and is computed as: |
| 282 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). | 282 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). |
| 283 // Assert that length is a Smi. | 283 // Assert that length is a Smi. |
| 284 __ tst(R2, ShifterOperand(kSmiTagMask)); | 284 __ tst(R2, ShifterOperand(kSmiTagMask)); |
| 285 if (FLAG_use_slow_path) { | 285 if (FLAG_use_slow_path) { |
| 286 __ b(&slow_case); | 286 __ b(&slow_case); |
| 287 } else { | 287 } else { |
| 288 __ b(&slow_case, NE); | 288 __ b(&slow_case, NE); |
| 289 } | 289 } |
| 290 __ ldr(R8, FieldAddress(CTX, Context::isolate_offset())); | 290 __ ldr(R8, FieldAddress(CTX, Context::isolate_offset())); |
| 291 __ LoadFromOffset(kLoadWord, R8, R8, Isolate::heap_offset()); | 291 __ LoadFromOffset(kLoadWord, R8, R8, Isolate::heap_offset()); |
| 292 __ LoadFromOffset(kLoadWord, R8, R8, Heap::new_space_offset()); | 292 __ LoadFromOffset(kLoadWord, R8, R8, Heap::new_space_offset()); |
| 293 | 293 |
| 294 // Calculate and align allocation size. | 294 // Calculate and align allocation size. |
| 295 // Load new object start and calculate next object start. | 295 // Load new object start and calculate next object start. |
| 296 // R1: array element type. | 296 // R1: array element type. |
| 297 // R2: Array length as Smi. | 297 // R2: array length as Smi. |
| 298 // R8: Points to new space object. | 298 // R8: points to new space object. |
| 299 __ LoadFromOffset(kLoadWord, R0, R8, Scavenger::top_offset()); | 299 __ LoadFromOffset(kLoadWord, R0, R8, Scavenger::top_offset()); |
| 300 intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1; | 300 intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1; |
| 301 __ LoadImmediate(R7, fixed_size); | 301 __ LoadImmediate(R3, fixed_size); |
| 302 __ add(R7, R7, ShifterOperand(R2, LSL, 1)); // R2 is Smi. | 302 __ add(R3, R3, ShifterOperand(R2, LSL, 1)); // R2 is Smi. |
| 303 ASSERT(kSmiTagShift == 1); | 303 ASSERT(kSmiTagShift == 1); |
| 304 __ bic(R7, R7, ShifterOperand(kObjectAlignment - 1)); | 304 __ bic(R3, R3, ShifterOperand(kObjectAlignment - 1)); |
| 305 __ add(R7, R7, ShifterOperand(R0)); | 305 __ add(R7, R3, ShifterOperand(R0)); |
| 306 | 306 |
| 307 // Check if the allocation fits into the remaining space. | 307 // Check if the allocation fits into the remaining space. |
| 308 // R0: potential new object start. | 308 // R0: potential new object start. |
| 309 // R1: array element type. | 309 // R1: array element type. |
| 310 // R2: Array length as Smi. | 310 // R2: array length as Smi. |
| 311 // R3: array size. |
| 311 // R7: potential next object start. | 312 // R7: potential next object start. |
| 312 // R8: Points to new space object. | 313 // R8: points to new space object. |
| 313 __ LoadFromOffset(kLoadWord, IP, R8, Scavenger::end_offset()); | 314 __ LoadFromOffset(kLoadWord, IP, R8, Scavenger::end_offset()); |
| 314 __ cmp(R7, ShifterOperand(IP)); | 315 __ cmp(R7, ShifterOperand(IP)); |
| 315 __ b(&slow_case, CS); // Branch if unsigned higher or equal. | 316 __ b(&slow_case, CS); // Branch if unsigned higher or equal. |
| 316 | 317 |
| 317 // Successfully allocated the object(s), now update top to point to | 318 // Successfully allocated the object(s), now update top to point to |
| 318 // next object start and initialize the object. | 319 // next object start and initialize the object. |
| 319 // R0: potential new object start. | 320 // R0: potential new object start. |
| 320 // R7: potential next object start. | 321 // R7: potential next object start. |
| 321 // R8: Points to new space object. | 322 // R8: Points to new space object. |
| 322 __ StoreToOffset(kStoreWord, R7, R8, Scavenger::top_offset()); | 323 __ StoreToOffset(kStoreWord, R7, R8, Scavenger::top_offset()); |
| 323 __ add(R0, R0, ShifterOperand(kHeapObjectTag)); | 324 __ add(R0, R0, ShifterOperand(kHeapObjectTag)); |
| 324 | 325 |
| 325 // R0: new object start as a tagged pointer. | 326 // R0: new object start as a tagged pointer. |
| 326 // R1: array element type. | 327 // R1: array element type. |
| 327 // R2: Array length as Smi. | 328 // R2: array length as Smi. |
| 329 // R3: array size. |
| 328 // R7: new object end address. | 330 // R7: new object end address. |
| 329 | 331 |
| 330 // Store the type argument field. | 332 // Store the type argument field. |
| 331 __ StoreIntoObjectNoBarrier( | 333 __ StoreIntoObjectNoBarrier( |
| 332 R0, | 334 R0, |
| 333 FieldAddress(R0, Array::type_arguments_offset()), | 335 FieldAddress(R0, Array::type_arguments_offset()), |
| 334 R1); | 336 R1); |
| 335 | 337 |
| 336 // Set the length field. | 338 // Set the length field. |
| 337 __ StoreIntoObjectNoBarrier( | 339 __ StoreIntoObjectNoBarrier( |
| 338 R0, | 340 R0, |
| 339 FieldAddress(R0, Array::length_offset()), | 341 FieldAddress(R0, Array::length_offset()), |
| 340 R2); | 342 R2); |
| 341 | 343 |
| 342 // Calculate the size tag. | 344 // Calculate the size tag. |
| 343 // R0: new object start as a tagged pointer. | 345 // R0: new object start as a tagged pointer. |
| 344 // R2: Array length as Smi. | 346 // R2: array length as Smi. |
| 347 // R3: array size. |
| 345 // R7: new object end address. | 348 // R7: new object end address. |
| 346 __ LoadImmediate(R1, fixed_size); | |
| 347 __ add(R1, R1, ShifterOperand(R2, LSL, 1)); // R2 is Smi. | |
| 348 ASSERT(kSmiTagShift == 1); | |
| 349 __ bic(R1, R1, ShifterOperand(kObjectAlignment - 1)); | |
| 350 const intptr_t shift = RawObject::kSizeTagBit - kObjectAlignmentLog2; | 349 const intptr_t shift = RawObject::kSizeTagBit - kObjectAlignmentLog2; |
| 351 __ CompareImmediate(R1, RawObject::SizeTag::kMaxSizeTag); | 350 __ CompareImmediate(R3, RawObject::SizeTag::kMaxSizeTag); |
| 352 // If no size tag overflow, shift R1 left, else set R1 to zero. | 351 // If no size tag overflow, shift R1 left, else set R1 to zero. |
| 353 __ mov(R1, ShifterOperand(R1, LSL, shift), LS); | 352 __ mov(R1, ShifterOperand(R3, LSL, shift), LS); |
| 354 __ mov(R1, ShifterOperand(0), HI); | 353 __ mov(R1, ShifterOperand(0), HI); |
| 355 | 354 |
| 356 // Get the class index and insert it into the tags. | 355 // Get the class index and insert it into the tags. |
| 357 __ LoadImmediate(IP, RawObject::ClassIdTag::encode(kArrayCid)); | 356 __ LoadImmediate(IP, RawObject::ClassIdTag::encode(kArrayCid)); |
| 358 __ orr(R1, R1, ShifterOperand(IP)); | 357 __ orr(R1, R1, ShifterOperand(IP)); |
| 359 __ str(R1, FieldAddress(R0, Array::tags_offset())); | 358 __ str(R1, FieldAddress(R0, Array::tags_offset())); |
| 360 | 359 |
| 361 // Initialize all array elements to raw_null. | 360 // Initialize all array elements to raw_null. |
| 362 // R0: new object start as a tagged pointer. | 361 // R0: new object start as a tagged pointer. |
| 363 // R7: new object end address. | 362 // R7: new object end address. |
| 364 // R2: Array length as Smi. | 363 // R2: array length as Smi. |
| 365 __ AddImmediate(R1, R0, Array::data_offset() - kHeapObjectTag); | 364 __ AddImmediate(R1, R0, Array::data_offset() - kHeapObjectTag); |
| 366 // R1: iterator which initially points to the start of the variable | 365 // R1: iterator which initially points to the start of the variable |
| 367 // data area to be initialized. | 366 // data area to be initialized. |
| 368 __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null())); | 367 __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null())); |
| 369 Label loop, test; | 368 Label loop; |
| 370 __ b(&test); | |
| 371 __ Bind(&loop); | 369 __ Bind(&loop); |
| 372 // TODO(cshapiro): StoreIntoObjectNoBarrier | 370 // TODO(cshapiro): StoreIntoObjectNoBarrier |
| 373 __ str(IP, Address(R1, 0)); | |
| 374 __ AddImmediate(R1, kWordSize); | |
| 375 __ Bind(&test); | |
| 376 __ cmp(R1, ShifterOperand(R7)); | 371 __ cmp(R1, ShifterOperand(R7)); |
| 377 __ b(&loop, NE); | 372 __ str(IP, Address(R1, 0), CC); // Store if unsigned lower. |
| 373 __ AddImmediate(R1, kWordSize, CC); |
| 374 __ b(&loop, CS); |
| 378 | 375 |
| 379 // Done allocating and initializing the array. | 376 // Done allocating and initializing the array. |
| 380 // R0: new object. | 377 // R0: new object. |
| 381 // R2: Array length as Smi (preserved for the caller.) | 378 // R2: array length as Smi (preserved for the caller.) |
| 382 __ Ret(); | 379 __ Ret(); |
| 383 } | 380 } |
| 384 | 381 |
| 385 // Unable to allocate the array using the fast inline code, just call | 382 // Unable to allocate the array using the fast inline code, just call |
| 386 // into the runtime. | 383 // into the runtime. |
| 387 __ Bind(&slow_case); | 384 __ Bind(&slow_case); |
| 388 // Create a stub frame as we are pushing some objects on the stack before | 385 // Create a stub frame as we are pushing some objects on the stack before |
| 389 // calling into the runtime. | 386 // calling into the runtime. |
| 390 __ EnterStubFrame(); | 387 __ EnterStubFrame(); |
| 391 __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null())); | 388 __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null())); |
| 392 // Setup space on stack for return value. | 389 // Setup space on stack for return value. |
| 393 // Push array length as Smi and element type. | 390 // Push array length as Smi and element type. |
| 394 __ PushList((1 << R1) | (1 << R2) | (1 << IP)); | 391 __ PushList((1 << R1) | (1 << R2) | (1 << IP)); |
| 395 __ CallRuntime(kAllocateArrayRuntimeEntry); | 392 __ CallRuntime(kAllocateArrayRuntimeEntry); |
| 396 // Pop arguments; result is popped in IP. | 393 // Pop arguments; result is popped in IP. |
| 397 __ PopList((1 << R1) | (1 << R2) | (1 << IP)); // R2 is restored. | 394 __ PopList((1 << R1) | (1 << R2) | (1 << IP)); // R2 is restored. |
| 398 __ mov(R0, ShifterOperand(IP)); | 395 __ mov(R0, ShifterOperand(IP)); |
| 399 __ LeaveStubFrame(); | 396 __ LeaveStubFrame(); |
| 400 __ Ret(); | 397 __ Ret(); |
| 401 } | 398 } |
| 402 | 399 |
| 403 | 400 |
| 404 // Input parameters: | 401 // Input parameters: |
| 405 // LR: return address. | 402 // LR: return address. |
| 406 // SP: address of last argument. | 403 // SP: address of last argument. |
| 407 // R4: Arguments descriptor array. | 404 // R4: arguments descriptor array. |
| 408 // Note: The closure object is the first argument to the function being | 405 // Note: The closure object is the first argument to the function being |
| 409 // called, the stub accesses the closure from this location directly | 406 // called, the stub accesses the closure from this location directly |
| 410 // when trying to resolve the call. | 407 // when trying to resolve the call. |
| 411 void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) { | 408 void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) { |
| 412 // Load num_args. | 409 // Load num_args. |
| 413 __ ldr(R0, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | 410 __ ldr(R0, FieldAddress(R4, ArgumentsDescriptor::count_offset())); |
| 414 __ sub(R0, R0, ShifterOperand(Smi::RawValue(1))); | 411 __ sub(R0, R0, ShifterOperand(Smi::RawValue(1))); |
| 415 // Load closure object in R1. | 412 // Load closure object in R1. |
| 416 __ ldr(R1, Address(SP, R0, LSL, 1)); // R0 (num_args - 1) is a Smi. | 413 __ ldr(R1, Address(SP, R0, LSL, 1)); // R0 (num_args - 1) is a Smi. |
| 417 | 414 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 452 __ CallRuntime(kCompileFunctionRuntimeEntry); | 449 __ CallRuntime(kCompileFunctionRuntimeEntry); |
| 453 // Restore arguments descriptor array and read-only function object argument. | 450 // Restore arguments descriptor array and read-only function object argument. |
| 454 __ PopList((1 << R2) | (1 << R4)); | 451 __ PopList((1 << R2) | (1 << R4)); |
| 455 // Restore R0. | 452 // Restore R0. |
| 456 __ ldr(R0, FieldAddress(R2, Function::code_offset())); | 453 __ ldr(R0, FieldAddress(R2, Function::code_offset())); |
| 457 | 454 |
| 458 // Remove the stub frame as we are about to jump to the closure function. | 455 // Remove the stub frame as we are about to jump to the closure function. |
| 459 __ LeaveStubFrame(); | 456 __ LeaveStubFrame(); |
| 460 | 457 |
| 461 __ Bind(&function_compiled); | 458 __ Bind(&function_compiled); |
| 462 // R0: Code. | 459 // R0: code. |
| 463 // R4: Arguments descriptor array. | 460 // R4: arguments descriptor array. |
| 464 __ ldr(R0, FieldAddress(R0, Code::instructions_offset())); | 461 __ ldr(R0, FieldAddress(R0, Code::instructions_offset())); |
| 465 __ AddImmediate(R0, Instructions::HeaderSize() - kHeapObjectTag); | 462 __ AddImmediate(R0, Instructions::HeaderSize() - kHeapObjectTag); |
| 466 __ bx(R0); | 463 __ bx(R0); |
| 467 | 464 |
| 468 __ Bind(¬_closure); | 465 __ Bind(¬_closure); |
| 469 // Call runtime to attempt to resolve and invoke a call method on a | 466 // Call runtime to attempt to resolve and invoke a call method on a |
| 470 // non-closure object, passing the non-closure object and its arguments array, | 467 // non-closure object, passing the non-closure object and its arguments array, |
| 471 // returning here. | 468 // returning here. |
| 472 // If no call method exists, throw a NoSuchMethodError. | 469 // If no call method exists, throw a NoSuchMethodError. |
| 473 // R1: non-closure object. | 470 // R1: non-closure object. |
| 474 // R4: arguments descriptor array. | 471 // R4: arguments descriptor array. |
| 475 | 472 |
| 476 // Create a stub frame as we are pushing some objects on the stack before | 473 // Create a stub frame as we are pushing some objects on the stack before |
| 477 // calling into the runtime. | 474 // calling into the runtime. |
| 478 __ EnterStubFrame(); | 475 __ EnterStubFrame(); |
| 479 | 476 |
| 480 // Setup space on stack for result from error reporting. | 477 // Setup space on stack for result from error reporting. |
| 481 __ PushList((1 << R4) | (1 << R8)); // Arguments descriptor and raw null. | 478 __ PushList((1 << R4) | (1 << R8)); // Arguments descriptor and raw null. |
| 482 | 479 |
| 483 // Load smi-tagged arguments array length, including the non-closure. | 480 // Load smi-tagged arguments array length, including the non-closure. |
| 484 __ ldr(R2, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | 481 __ ldr(R2, FieldAddress(R4, ArgumentsDescriptor::count_offset())); |
| 485 PushArgumentsArray(assembler); | 482 PushArgumentsArray(assembler); |
| 486 | 483 |
| 487 // Stack: | 484 // Stack: |
| 488 // TOS + 0: Argument array. | 485 // TOS + 0: argument array. |
| 489 // TOS + 1: Arguments descriptor array. | 486 // TOS + 1: arguments descriptor array. |
| 490 // TOS + 2: Place for result from the call. | 487 // TOS + 2: place for result from the call. |
| 491 // TOS + 3: Saved FP of previous frame. | 488 // TOS + 3: saved FP of previous frame. |
| 492 // TOS + 4: Dart code return address | 489 // TOS + 4: dart code return address |
| 493 // TOS + 5: PC marker (0 for stub). | 490 // TOS + 5: pc marker (0 for stub). |
| 494 // TOS + 6: Last argument of caller. | 491 // TOS + 6: last argument of caller. |
| 495 // .... | 492 // .... |
| 496 __ CallRuntime(kInvokeNonClosureRuntimeEntry); | 493 __ CallRuntime(kInvokeNonClosureRuntimeEntry); |
| 497 // Remove arguments. | 494 // Remove arguments. |
| 498 __ Drop(2); | 495 __ Drop(2); |
| 499 __ Pop(R0); // Get result into R0. | 496 __ Pop(R0); // Get result into R0. |
| 500 | 497 |
| 501 // Remove the stub frame as we are about to return. | 498 // Remove the stub frame as we are about to return. |
| 502 __ LeaveStubFrame(); | 499 __ LeaveStubFrame(); |
| 503 __ Ret(); | 500 __ Ret(); |
| 504 } | 501 } |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 674 // Setup up number of context variables field. | 671 // Setup up number of context variables field. |
| 675 // R0: new object. | 672 // R0: new object. |
| 676 // R1: number of context variables as integer value (not object). | 673 // R1: number of context variables as integer value (not object). |
| 677 __ str(R1, FieldAddress(R0, Context::num_variables_offset())); | 674 __ str(R1, FieldAddress(R0, Context::num_variables_offset())); |
| 678 | 675 |
| 679 // Setup isolate field. | 676 // Setup isolate field. |
| 680 // Load Isolate pointer from Context structure into R2. | 677 // Load Isolate pointer from Context structure into R2. |
| 681 // R0: new object. | 678 // R0: new object. |
| 682 // R1: number of context variables. | 679 // R1: number of context variables. |
| 683 __ ldr(R2, FieldAddress(CTX, Context::isolate_offset())); | 680 __ ldr(R2, FieldAddress(CTX, Context::isolate_offset())); |
| 684 // R2: Isolate, not an object. | 681 // R2: isolate, not an object. |
| 685 __ str(R2, FieldAddress(R0, Context::isolate_offset())); | 682 __ str(R2, FieldAddress(R0, Context::isolate_offset())); |
| 686 | 683 |
| 687 // Setup the parent field. | 684 // Setup the parent field. |
| 688 // R0: new object. | 685 // R0: new object. |
| 689 // R1: number of context variables. | 686 // R1: number of context variables. |
| 690 __ LoadImmediate(R2, reinterpret_cast<intptr_t>(Object::null())); | 687 __ LoadImmediate(R2, reinterpret_cast<intptr_t>(Object::null())); |
| 691 __ str(R2, FieldAddress(R0, Context::parent_offset())); | 688 __ str(R2, FieldAddress(R0, Context::parent_offset())); |
| 692 | 689 |
| 693 // Initialize the context variables. | 690 // Initialize the context variables. |
| 694 // R0: new object. | 691 // R0: new object. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 721 // Restore the frame pointer. | 718 // Restore the frame pointer. |
| 722 __ LeaveStubFrame(); | 719 __ LeaveStubFrame(); |
| 723 __ Ret(); | 720 __ Ret(); |
| 724 } | 721 } |
| 725 | 722 |
| 726 | 723 |
| 727 DECLARE_LEAF_RUNTIME_ENTRY(void, StoreBufferBlockProcess, Isolate* isolate); | 724 DECLARE_LEAF_RUNTIME_ENTRY(void, StoreBufferBlockProcess, Isolate* isolate); |
| 728 | 725 |
| 729 // Helper stub to implement Assembler::StoreIntoObject. | 726 // Helper stub to implement Assembler::StoreIntoObject. |
| 730 // Input parameters: | 727 // Input parameters: |
| 731 // R0: Address (i.e. object) being stored into. | 728 // R0: address (i.e. object) being stored into. |
| 732 void StubCode::GenerateUpdateStoreBufferStub(Assembler* assembler) { | 729 void StubCode::GenerateUpdateStoreBufferStub(Assembler* assembler) { |
| 733 // Save values being destroyed. | 730 // Save values being destroyed. |
| 734 __ PushList((1 << R1) | (1 << R2) | (1 << R3)); | 731 __ PushList((1 << R1) | (1 << R2) | (1 << R3)); |
| 735 | 732 |
| 736 // Load the isolate out of the context. | 733 // Load the isolate out of the context. |
| 737 // Spilled: R1, R2, R3. | 734 // Spilled: R1, R2, R3. |
| 738 // R0: Address being stored. | 735 // R0: address being stored. |
| 739 __ ldr(R1, FieldAddress(CTX, Context::isolate_offset())); | 736 __ ldr(R1, FieldAddress(CTX, Context::isolate_offset())); |
| 740 | 737 |
| 741 // Load top_ out of the StoreBufferBlock and add the address to the pointers_. | 738 // Load top_ out of the StoreBufferBlock and add the address to the pointers_. |
| 742 // R1: Isolate. | 739 // R1: isolate. |
| 743 intptr_t store_buffer_offset = Isolate::store_buffer_block_offset(); | 740 intptr_t store_buffer_offset = Isolate::store_buffer_block_offset(); |
| 744 __ LoadFromOffset(kLoadWord, R2, R1, | 741 __ LoadFromOffset(kLoadWord, R2, R1, |
| 745 store_buffer_offset + StoreBufferBlock::top_offset()); | 742 store_buffer_offset + StoreBufferBlock::top_offset()); |
| 746 __ add(R3, R1, ShifterOperand(R2, LSL, 2)); | 743 __ add(R3, R1, ShifterOperand(R2, LSL, 2)); |
| 747 __ StoreToOffset(kStoreWord, R0, R3, | 744 __ StoreToOffset(kStoreWord, R0, R3, |
| 748 store_buffer_offset + StoreBufferBlock::pointers_offset()); | 745 store_buffer_offset + StoreBufferBlock::pointers_offset()); |
| 749 | 746 |
| 750 // Increment top_ and check for overflow. | 747 // Increment top_ and check for overflow. |
| 751 // R2: top_ | 748 // R2: top_. |
| 752 // R1: Isolate | 749 // R1: isolate. |
| 753 Label L; | 750 Label L; |
| 754 __ add(R2, R2, ShifterOperand(1)); | 751 __ add(R2, R2, ShifterOperand(1)); |
| 755 __ StoreToOffset(kStoreWord, R2, R1, | 752 __ StoreToOffset(kStoreWord, R2, R1, |
| 756 store_buffer_offset + StoreBufferBlock::top_offset()); | 753 store_buffer_offset + StoreBufferBlock::top_offset()); |
| 757 __ CompareImmediate(R2, StoreBufferBlock::kSize); | 754 __ CompareImmediate(R2, StoreBufferBlock::kSize); |
| 758 // Restore values. | 755 // Restore values. |
| 759 __ PopList((1 << R1) | (1 << R2) | (1 << R3)); | 756 __ PopList((1 << R1) | (1 << R2) | (1 << R3)); |
| 760 __ b(&L, EQ); | 757 __ b(&L, EQ); |
| 761 __ Ret(); | 758 __ Ret(); |
| 762 | 759 |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1120 // but only at exit so that we have collected all type feedback before | 1117 // but only at exit so that we have collected all type feedback before |
| 1121 // optimizing. | 1118 // optimizing. |
| 1122 } | 1119 } |
| 1123 __ add(R7, R7, ShifterOperand(1)); | 1120 __ add(R7, R7, ShifterOperand(1)); |
| 1124 __ str(R7, FieldAddress(func_reg, Function::usage_counter_offset())); | 1121 __ str(R7, FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1125 __ Bind(&is_hot); | 1122 __ Bind(&is_hot); |
| 1126 } | 1123 } |
| 1127 | 1124 |
| 1128 | 1125 |
| 1129 // Generate inline cache check for 'num_args'. | 1126 // Generate inline cache check for 'num_args'. |
| 1130 // LR: return address | 1127 // LR: return address. |
| 1131 // R5: Inline cache data object. | 1128 // R5: inline cache data object. |
| 1132 // R4: Arguments descriptor array. | 1129 // R4: arguments descriptor array. |
| 1133 // Control flow: | 1130 // Control flow: |
| 1134 // - If receiver is null -> jump to IC miss. | 1131 // - If receiver is null -> jump to IC miss. |
| 1135 // - If receiver is Smi -> load Smi class. | 1132 // - If receiver is Smi -> load Smi class. |
| 1136 // - If receiver is not-Smi -> load receiver's class. | 1133 // - If receiver is not-Smi -> load receiver's class. |
| 1137 // - Check if 'num_args' (including receiver) match any IC data group. | 1134 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1138 // - Match found -> jump to target. | 1135 // - Match found -> jump to target. |
| 1139 // - Match not found -> jump to IC miss. | 1136 // - Match not found -> jump to IC miss. |
| 1140 void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler, | 1137 void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler, |
| 1141 intptr_t num_args) { | 1138 intptr_t num_args) { |
| 1142 ASSERT(num_args > 0); | 1139 ASSERT(num_args > 0); |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1251 __ CompareImmediate(R0, reinterpret_cast<intptr_t>(Object::null())); | 1248 __ CompareImmediate(R0, reinterpret_cast<intptr_t>(Object::null())); |
| 1252 __ b(&call_target_function, NE); | 1249 __ b(&call_target_function, NE); |
| 1253 // NoSuchMethod or closure. | 1250 // NoSuchMethod or closure. |
| 1254 // Mark IC call that it may be a closure call that does not collect | 1251 // Mark IC call that it may be a closure call that does not collect |
| 1255 // type feedback. | 1252 // type feedback. |
| 1256 __ mov(IP, ShifterOperand(1)); | 1253 __ mov(IP, ShifterOperand(1)); |
| 1257 __ strb(IP, FieldAddress(R5, ICData::is_closure_call_offset())); | 1254 __ strb(IP, FieldAddress(R5, ICData::is_closure_call_offset())); |
| 1258 __ Branch(&StubCode::InstanceFunctionLookupLabel()); | 1255 __ Branch(&StubCode::InstanceFunctionLookupLabel()); |
| 1259 | 1256 |
| 1260 __ Bind(&found); | 1257 __ Bind(&found); |
| 1261 // R6: Pointer to an IC data check group. | 1258 // R6: pointer to an IC data check group. |
| 1262 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; | 1259 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; |
| 1263 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; | 1260 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; |
| 1264 __ LoadFromOffset(kLoadWord, R0, R6, target_offset); | 1261 __ LoadFromOffset(kLoadWord, R0, R6, target_offset); |
| 1265 __ LoadFromOffset(kLoadWord, R1, R6, count_offset); | 1262 __ LoadFromOffset(kLoadWord, R1, R6, count_offset); |
| 1266 __ adds(R1, R1, ShifterOperand(Smi::RawValue(1))); | 1263 __ adds(R1, R1, ShifterOperand(Smi::RawValue(1))); |
| 1267 __ StoreToOffset(kStoreWord, R1, R6, count_offset); | 1264 __ StoreToOffset(kStoreWord, R1, R6, count_offset); |
| 1268 __ b(&call_target_function, VC); // No overflow. | 1265 __ b(&call_target_function, VC); // No overflow. |
| 1269 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue)); | 1266 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue)); |
| 1270 __ StoreToOffset(kStoreWord, R1, R6, count_offset); | 1267 __ StoreToOffset(kStoreWord, R1, R6, count_offset); |
| 1271 | 1268 |
| 1272 __ Bind(&call_target_function); | 1269 __ Bind(&call_target_function); |
| 1273 // R0: Target function. | 1270 // R0: target function. |
| 1274 __ ldr(R0, FieldAddress(R0, Function::code_offset())); | 1271 __ ldr(R0, FieldAddress(R0, Function::code_offset())); |
| 1275 __ ldr(R0, FieldAddress(R0, Code::instructions_offset())); | 1272 __ ldr(R0, FieldAddress(R0, Code::instructions_offset())); |
| 1276 __ AddImmediate(R0, Instructions::HeaderSize() - kHeapObjectTag); | 1273 __ AddImmediate(R0, Instructions::HeaderSize() - kHeapObjectTag); |
| 1277 __ bx(R0); | 1274 __ bx(R0); |
| 1278 | 1275 |
| 1279 // Instance in R0, return its class-id in R0 as Smi. | 1276 // Instance in R0, return its class-id in R0 as Smi. |
| 1280 __ Bind(&get_class_id_as_smi); | 1277 __ Bind(&get_class_id_as_smi); |
| 1281 | 1278 |
| 1282 // Test if Smi -> load Smi class for comparison. | 1279 // Test if Smi -> load Smi class for comparison. |
| 1283 __ tst(R0, ShifterOperand(kSmiTagMask)); | 1280 __ tst(R0, ShifterOperand(kSmiTagMask)); |
| 1284 __ mov(R0, ShifterOperand(Smi::RawValue(kSmiCid)), EQ); | 1281 __ mov(R0, ShifterOperand(Smi::RawValue(kSmiCid)), EQ); |
| 1285 __ bx(LR, EQ); | 1282 __ bx(LR, EQ); |
| 1286 __ LoadClassId(R0, R0); | 1283 __ LoadClassId(R0, R0); |
| 1287 __ SmiTag(R0); | 1284 __ SmiTag(R0); |
| 1288 __ bx(LR); | 1285 __ bx(LR); |
| 1289 } | 1286 } |
| 1290 | 1287 |
| 1291 | 1288 |
| 1292 // Use inline cache data array to invoke the target or continue in inline | 1289 // Use inline cache data array to invoke the target or continue in inline |
| 1293 // cache miss handler. Stub for 1-argument check (receiver class). | 1290 // cache miss handler. Stub for 1-argument check (receiver class). |
| 1294 // LR: Return address. | 1291 // LR: return address. |
| 1295 // R5: Inline cache data object. | 1292 // R5: inline cache data object. |
| 1296 // R4: Arguments descriptor array. | 1293 // R4: arguments descriptor array. |
| 1297 // Inline cache data object structure: | 1294 // Inline cache data object structure: |
| 1298 // 0: function-name | 1295 // 0: function-name |
| 1299 // 1: N, number of arguments checked. | 1296 // 1: N, number of arguments checked. |
| 1300 // 2 .. (length - 1): group of checks, each check containing: | 1297 // 2 .. (length - 1): group of checks, each check containing: |
| 1301 // - N classes. | 1298 // - N classes. |
| 1302 // - 1 target function. | 1299 // - 1 target function. |
| 1303 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1300 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1304 GenerateUsageCounterIncrement(assembler, R6); | 1301 GenerateUsageCounterIncrement(assembler, R6); |
| 1305 GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1302 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1306 } | 1303 } |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1389 __ LoadClassId(R3, R0); | 1386 __ LoadClassId(R3, R0); |
| 1390 // R0: instance. | 1387 // R0: instance. |
| 1391 // R1: instantiator type arguments or NULL. | 1388 // R1: instantiator type arguments or NULL. |
| 1392 // R2: SubtypeTestCache. | 1389 // R2: SubtypeTestCache. |
| 1393 // R3: instance class id. | 1390 // R3: instance class id. |
| 1394 // R4: instance type arguments (null if none), used only if n > 1. | 1391 // R4: instance type arguments (null if none), used only if n > 1. |
| 1395 __ ldr(R2, FieldAddress(R2, SubtypeTestCache::cache_offset())); | 1392 __ ldr(R2, FieldAddress(R2, SubtypeTestCache::cache_offset())); |
| 1396 __ AddImmediate(R2, Array::data_offset() - kHeapObjectTag); | 1393 __ AddImmediate(R2, Array::data_offset() - kHeapObjectTag); |
| 1397 | 1394 |
| 1398 Label loop, found, not_found, next_iteration; | 1395 Label loop, found, not_found, next_iteration; |
| 1399 // R2: Entry start. | 1396 // R2: entry start. |
| 1400 // R3: instance class id. | 1397 // R3: instance class id. |
| 1401 // R4: instance type arguments. | 1398 // R4: instance type arguments. |
| 1402 __ SmiTag(R3); | 1399 __ SmiTag(R3); |
| 1403 __ Bind(&loop); | 1400 __ Bind(&loop); |
| 1404 __ ldr(R5, Address(R2, kWordSize * SubtypeTestCache::kInstanceClassId)); | 1401 __ ldr(R5, Address(R2, kWordSize * SubtypeTestCache::kInstanceClassId)); |
| 1405 __ CompareImmediate(R5, reinterpret_cast<intptr_t>(Object::null())); | 1402 __ CompareImmediate(R5, reinterpret_cast<intptr_t>(Object::null())); |
| 1406 __ b(¬_found, EQ); | 1403 __ b(¬_found, EQ); |
| 1407 __ cmp(R5, ShifterOperand(R3)); | 1404 __ cmp(R5, ShifterOperand(R3)); |
| 1408 if (n == 1) { | 1405 if (n == 1) { |
| 1409 __ b(&found, EQ); | 1406 __ b(&found, EQ); |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1597 __ Bind(&reference_compare); | 1594 __ Bind(&reference_compare); |
| 1598 __ cmp(left, ShifterOperand(right)); | 1595 __ cmp(left, ShifterOperand(right)); |
| 1599 __ Bind(&done); | 1596 __ Bind(&done); |
| 1600 __ PopList((1 << R0) | (1 << R1) | (1 << R2)); | 1597 __ PopList((1 << R0) | (1 << R1) | (1 << R2)); |
| 1601 __ Ret(); | 1598 __ Ret(); |
| 1602 } | 1599 } |
| 1603 | 1600 |
| 1604 } // namespace dart | 1601 } // namespace dart |
| 1605 | 1602 |
| 1606 #endif // defined TARGET_ARCH_ARM | 1603 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |