| OLD | NEW |
| 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 20 matching lines...) Expand all Loading... |
| 31 | 31 |
| 32 #include "bootstrapper.h" | 32 #include "bootstrapper.h" |
| 33 #include "code-stubs.h" | 33 #include "code-stubs.h" |
| 34 #include "regexp-macro-assembler.h" | 34 #include "regexp-macro-assembler.h" |
| 35 #include "stub-cache.h" | 35 #include "stub-cache.h" |
| 36 | 36 |
| 37 namespace v8 { | 37 namespace v8 { |
| 38 namespace internal { | 38 namespace internal { |
| 39 | 39 |
| 40 | 40 |
| 41 void FastNewClosureStub::InitializeInterfaceDescriptor( |
| 42 Isolate* isolate, |
| 43 CodeStubInterfaceDescriptor* descriptor) { |
| 44 // x2: function info |
| 45 static Register registers[] = { x2 }; |
| 46 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); |
| 47 descriptor->register_params_ = registers; |
| 48 descriptor->deoptimization_handler_ = |
| 49 Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry; |
| 50 } |
| 51 |
| 52 |
| 41 void ToNumberStub::InitializeInterfaceDescriptor( | 53 void ToNumberStub::InitializeInterfaceDescriptor( |
| 42 Isolate* isolate, | 54 Isolate* isolate, |
| 43 CodeStubInterfaceDescriptor* descriptor) { | 55 CodeStubInterfaceDescriptor* descriptor) { |
| 44 // x0: value | 56 // x0: value |
| 45 static Register registers[] = { x0 }; | 57 static Register registers[] = { x0 }; |
| 46 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); | 58 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); |
| 47 descriptor->register_params_ = registers; | 59 descriptor->register_params_ = registers; |
| 48 descriptor->deoptimization_handler_ = NULL; | 60 descriptor->deoptimization_handler_ = NULL; |
| 49 } | 61 } |
| 50 | 62 |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 312 __ Push(descriptor->register_params_[i]); | 324 __ Push(descriptor->register_params_[i]); |
| 313 } | 325 } |
| 314 ExternalReference miss = descriptor->miss_handler(); | 326 ExternalReference miss = descriptor->miss_handler(); |
| 315 __ CallExternalReference(miss, descriptor->register_param_count_); | 327 __ CallExternalReference(miss, descriptor->register_param_count_); |
| 316 } | 328 } |
| 317 | 329 |
| 318 __ Ret(); | 330 __ Ret(); |
| 319 } | 331 } |
| 320 | 332 |
| 321 | 333 |
| 322 void FastNewClosureStub::Generate(MacroAssembler* masm) { | |
| 323 // Create a new closure from the given function info in new space. Set the | |
| 324 // context to the current context in cp. | |
| 325 Register new_fn = x0; | |
| 326 Register function = x1; | |
| 327 | |
| 328 Counters* counters = masm->isolate()->counters(); | |
| 329 | |
| 330 Label gc; | |
| 331 | |
| 332 // Pop the function info from the stack. | |
| 333 __ Pop(function); | |
| 334 | |
| 335 // Attempt to allocate new JSFunction in new space. | |
| 336 __ Allocate(JSFunction::kSize, new_fn, x6, x7, &gc, TAG_OBJECT); | |
| 337 | |
| 338 __ IncrementCounter(counters->fast_new_closure_total(), 1, x6, x7); | |
| 339 | |
| 340 int map_index = Context::FunctionMapIndex(language_mode_, is_generator_); | |
| 341 | |
| 342 // Compute the function map in the current native context and set that as the | |
| 343 // map of the allocated object. | |
| 344 Register global_object = x2; | |
| 345 Register global_ctx = x5; | |
| 346 Register global_fn_map = x2; | |
| 347 __ Ldr(global_object, GlobalObjectMemOperand()); | |
| 348 __ Ldr(global_ctx, FieldMemOperand(global_object, | |
| 349 GlobalObject::kNativeContextOffset)); | |
| 350 __ Ldr(global_fn_map, ContextMemOperand(global_ctx, map_index)); | |
| 351 __ Str(global_fn_map, FieldMemOperand(new_fn, HeapObject::kMapOffset)); | |
| 352 | |
| 353 // Initialize the rest of the function. We don't have to update the write | |
| 354 // barrier because the allocated object is in new space. | |
| 355 Register empty_array = x2; | |
| 356 Register the_hole = x3; | |
| 357 __ LoadRoot(empty_array, Heap::kEmptyFixedArrayRootIndex); | |
| 358 __ LoadRoot(the_hole, Heap::kTheHoleValueRootIndex); | |
| 359 | |
| 360 __ Str(empty_array, FieldMemOperand(new_fn, JSObject::kPropertiesOffset)); | |
| 361 __ Str(empty_array, FieldMemOperand(new_fn, JSObject::kElementsOffset)); | |
| 362 __ Str(the_hole, FieldMemOperand(new_fn, | |
| 363 JSFunction::kPrototypeOrInitialMapOffset)); | |
| 364 __ Str(function, FieldMemOperand(new_fn, | |
| 365 JSFunction::kSharedFunctionInfoOffset)); | |
| 366 __ Str(cp, FieldMemOperand(new_fn, JSFunction::kContextOffset)); | |
| 367 __ Str(empty_array, FieldMemOperand(new_fn, JSFunction::kLiteralsOffset)); | |
| 368 | |
| 369 // Initialize the code pointer in the new function to be the one found in the | |
| 370 // shared function info object. | |
| 371 // But first check if there is an optimized version for our context. | |
| 372 Label check_optimized; | |
| 373 Label install_unoptimized; | |
| 374 Register opt_code_map = x4; | |
| 375 if (FLAG_cache_optimized_code) { | |
| 376 __ Ldr(opt_code_map, | |
| 377 FieldMemOperand(function, | |
| 378 SharedFunctionInfo::kOptimizedCodeMapOffset)); | |
| 379 __ Cbnz(opt_code_map, &check_optimized); | |
| 380 } | |
| 381 | |
| 382 __ Bind(&install_unoptimized); | |
| 383 Register undef = x4; | |
| 384 __ LoadRoot(undef, Heap::kUndefinedValueRootIndex); | |
| 385 __ Str(undef, FieldMemOperand(new_fn, JSFunction::kNextFunctionLinkOffset)); | |
| 386 | |
| 387 Register fn_code = x2; | |
| 388 __ Ldr(fn_code, FieldMemOperand(function, SharedFunctionInfo::kCodeOffset)); | |
| 389 __ Add(fn_code, fn_code, Code::kHeaderSize - kHeapObjectTag); | |
| 390 __ Str(fn_code, FieldMemOperand(new_fn, JSFunction::kCodeEntryOffset)); | |
| 391 | |
| 392 // Return result. The argument function info has been popped already. | |
| 393 __ Ret(); | |
| 394 | |
| 395 // This code is never reached if FLAG_cache_optimized_code is false. | |
| 396 __ Bind(&check_optimized); | |
| 397 | |
| 398 __ IncrementCounter(counters->fast_new_closure_try_optimized(), 1, x6, x7); | |
| 399 | |
| 400 // x4 opt_code_map pointer to optimized code map | |
| 401 // x5 global_ctx pointer to global context | |
| 402 | |
| 403 // The optimized code map must never be empty, so check the first elements. | |
| 404 Label install_optimized; | |
| 405 // Speculatively move code object into opt_code. | |
| 406 Register opt_code = x11; | |
| 407 Register opt_code_ctx = x12; | |
| 408 __ Ldr(opt_code, FieldMemOperand(opt_code_map, | |
| 409 SharedFunctionInfo::kFirstCodeSlot)); | |
| 410 __ Ldr(opt_code_ctx, FieldMemOperand(opt_code_map, | |
| 411 SharedFunctionInfo::kFirstContextSlot)); | |
| 412 __ Cmp(opt_code_ctx, global_ctx); | |
| 413 __ B(eq, &install_optimized); | |
| 414 | |
| 415 // Iterate through the rest of the map backwards. | |
| 416 Label loop; | |
| 417 Register index = x10; | |
| 418 Register array_base = x13; | |
| 419 Register entry = x14; | |
| 420 __ Ldrsw(index, UntagSmiFieldMemOperand(opt_code_map, | |
| 421 FixedArray::kLengthOffset)); | |
| 422 __ Add(array_base, opt_code_map, FixedArray::kHeaderSize - kHeapObjectTag); | |
| 423 __ Bind(&loop); | |
| 424 | |
| 425 // Do not double check first entry. | |
| 426 __ Cmp(index, SharedFunctionInfo::kSecondEntryIndex); | |
| 427 __ B(eq, &install_unoptimized); | |
| 428 // TODO(all) Optimise this to use addressing mode to update the pointer. | |
| 429 __ Sub(index, index, SharedFunctionInfo::kEntryLength); | |
| 430 __ Add(entry, array_base, Operand(index, LSL, kPointerSizeLog2)); | |
| 431 __ Ldr(opt_code_ctx, MemOperand(entry)); | |
| 432 __ Cmp(global_ctx, opt_code_ctx); | |
| 433 __ B(ne, &loop); | |
| 434 | |
| 435 // Hit: fetch the optimized code. Register entry already contains pointer to | |
| 436 // the first element (context) of the triple. | |
| 437 __ Ldr(opt_code, MemOperand(entry, kPointerSize)); | |
| 438 | |
| 439 __ Bind(&install_optimized); | |
| 440 __ IncrementCounter(counters->fast_new_closure_install_optimized(), | |
| 441 1, x6, x7); | |
| 442 | |
| 443 Register opt_code_entry = x10; | |
| 444 __ Add(opt_code_entry, opt_code, Code::kHeaderSize - kHeapObjectTag); | |
| 445 __ Str(opt_code_entry, FieldMemOperand(new_fn, JSFunction::kCodeEntryOffset)); | |
| 446 | |
| 447 // Now link a function into a list of optimized functions. | |
| 448 Register opt_fn_list = x10; | |
| 449 __ Ldr(opt_fn_list, ContextMemOperand(global_ctx, | |
| 450 Context::OPTIMIZED_FUNCTIONS_LIST)); | |
| 451 __ Str(opt_fn_list, FieldMemOperand(new_fn, | |
| 452 JSFunction::kNextFunctionLinkOffset)); | |
| 453 // No need for write barrier as JSFunction is in the new space. | |
| 454 | |
| 455 // Store JSFunction before issuing write barrier as it clobbers all of the | |
| 456 // registers passed. | |
| 457 __ Str(new_fn, ContextMemOperand(global_ctx, | |
| 458 Context::OPTIMIZED_FUNCTIONS_LIST)); | |
| 459 | |
| 460 // Move value to a temporary, to prevent RecordWriteContextSlot() | |
| 461 // corrupting the return value. | |
| 462 __ Mov(x4, new_fn); | |
| 463 __ RecordWriteContextSlot( | |
| 464 global_ctx, | |
| 465 Context::SlotOffset(Context::OPTIMIZED_FUNCTIONS_LIST), | |
| 466 x4, | |
| 467 x1, | |
| 468 kLRHasNotBeenSaved, | |
| 469 kDontSaveFPRegs); | |
| 470 | |
| 471 // Return result. The argument function info has been popped already. | |
| 472 __ Ret(); | |
| 473 | |
| 474 // Create a new closure through the slower runtime call. | |
| 475 __ Bind(&gc); | |
| 476 Register false_val = x2; | |
| 477 __ LoadRoot(false_val, Heap::kFalseValueRootIndex); | |
| 478 __ Push(cp, function, false_val); | |
| 479 __ TailCallRuntime(Runtime::kNewClosure, 3, 1); | |
| 480 } | |
| 481 | |
| 482 | |
| 483 void FastNewContextStub::Generate(MacroAssembler* masm) { | 334 void FastNewContextStub::Generate(MacroAssembler* masm) { |
| 484 Register function = x0; | 335 Register function = x0; |
| 485 Register allocated = x1; | 336 Register allocated = x1; |
| 486 Label gc; | 337 Label gc; |
| 487 | 338 |
| 488 // Pop the function from the stack. | 339 // Pop the function from the stack. |
| 489 __ Pop(function); | 340 __ Pop(function); |
| 490 | 341 |
| 491 // Attempt to allocate the context in new space. | 342 // Attempt to allocate the context in new space. |
| 492 int context_length = slots_ + Context::MIN_CONTEXT_SLOTS; | 343 int context_length = slots_ + Context::MIN_CONTEXT_SLOTS; |
| (...skipping 6566 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7059 __ Bind(&fast_elements_case); | 6910 __ Bind(&fast_elements_case); |
| 7060 GenerateCase(masm, FAST_ELEMENTS); | 6911 GenerateCase(masm, FAST_ELEMENTS); |
| 7061 } | 6912 } |
| 7062 | 6913 |
| 7063 | 6914 |
| 7064 #undef __ | 6915 #undef __ |
| 7065 | 6916 |
| 7066 } } // namespace v8::internal | 6917 } } // namespace v8::internal |
| 7067 | 6918 |
| 7068 #endif // V8_TARGET_ARCH_A64 | 6919 #endif // V8_TARGET_ARCH_A64 |
| OLD | NEW |