| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #if V8_TARGET_ARCH_ARM64 | 5 #if V8_TARGET_ARCH_ARM64 |
| 6 | 6 |
| 7 #include "src/arm64/frames-arm64.h" | 7 #include "src/arm64/frames-arm64.h" |
| 8 #include "src/codegen.h" | 8 #include "src/codegen.h" |
| 9 #include "src/debug/debug.h" | 9 #include "src/debug/debug.h" |
| 10 #include "src/deoptimizer.h" | 10 #include "src/deoptimizer.h" |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 235 __ JumpIfSmi(x2, &convert); | 235 __ JumpIfSmi(x2, &convert); |
| 236 __ JumpIfObjectType(x2, x4, x4, FIRST_NONSTRING_TYPE, &done_convert, lo); | 236 __ JumpIfObjectType(x2, x4, x4, FIRST_NONSTRING_TYPE, &done_convert, lo); |
| 237 __ Bind(&convert); | 237 __ Bind(&convert); |
| 238 { | 238 { |
| 239 FrameScope scope(masm, StackFrame::INTERNAL); | 239 FrameScope scope(masm, StackFrame::INTERNAL); |
| 240 ToStringStub stub(masm->isolate()); | 240 ToStringStub stub(masm->isolate()); |
| 241 __ Push(x1, x3); | 241 __ Push(x1, x3); |
| 242 __ Move(x0, x2); | 242 __ Move(x0, x2); |
| 243 __ CallStub(&stub); | 243 __ CallStub(&stub); |
| 244 __ Move(x2, x0); | 244 __ Move(x2, x0); |
| 245 __ Pop(x1, x3); | 245 __ Pop(x3, x1); |
| 246 } | 246 } |
| 247 __ Bind(&done_convert); | 247 __ Bind(&done_convert); |
| 248 } | 248 } |
| 249 | 249 |
| 250 // 3. Check if new target and constructor differ. | 250 // 3. Check if new target and constructor differ. |
| 251 Label new_object; | 251 Label new_object; |
| 252 __ Cmp(x1, x3); | 252 __ Cmp(x1, x3); |
| 253 __ B(ne, &new_object); | 253 __ B(ne, &new_object); |
| 254 | 254 |
| 255 // 4. Allocate a JSValue wrapper for the string. | 255 // 4. Allocate a JSValue wrapper for the string. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 270 __ Str(x3, FieldMemOperand(x0, JSObject::kElementsOffset)); | 270 __ Str(x3, FieldMemOperand(x0, JSObject::kElementsOffset)); |
| 271 __ Str(x2, FieldMemOperand(x0, JSValue::kValueOffset)); | 271 __ Str(x2, FieldMemOperand(x0, JSValue::kValueOffset)); |
| 272 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); | 272 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); |
| 273 __ Ret(); | 273 __ Ret(); |
| 274 } | 274 } |
| 275 | 275 |
| 276 // 5. Fallback to the runtime to create new object. | 276 // 5. Fallback to the runtime to create new object. |
| 277 __ bind(&new_object); | 277 __ bind(&new_object); |
| 278 { | 278 { |
| 279 FrameScope scope(masm, StackFrame::INTERNAL); | 279 FrameScope scope(masm, StackFrame::INTERNAL); |
| 280 __ Push(x2, x1); // first argument, constructor | 280 __ Push(x2, x1, x3); // first argument, constructor, new target |
| 281 __ Push(x1, x3); // constructor, new target | |
| 282 __ CallRuntime(Runtime::kNewObject, 2); | 281 __ CallRuntime(Runtime::kNewObject, 2); |
| 283 __ Pop(x1, x2); | 282 __ Pop(x2); |
| 284 } | 283 } |
| 285 __ Str(x2, FieldMemOperand(x0, JSValue::kValueOffset)); | 284 __ Str(x2, FieldMemOperand(x0, JSValue::kValueOffset)); |
| 286 __ Ret(); | 285 __ Ret(); |
| 287 } | 286 } |
| 288 | 287 |
| 289 | 288 |
| 290 static void CallRuntimePassFunction(MacroAssembler* masm, | 289 static void CallRuntimePassFunction(MacroAssembler* masm, |
| 291 Runtime::FunctionId function_id) { | 290 Runtime::FunctionId function_id) { |
| 292 FrameScope scope(masm, StackFrame::INTERNAL); | 291 FrameScope scope(masm, StackFrame::INTERNAL); |
| 293 // - Push a copy of the function onto the stack. | 292 // - Push a copy of the function onto the stack. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 | 326 |
| 328 CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode); | 327 CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode); |
| 329 GenerateTailCallToReturnedCode(masm); | 328 GenerateTailCallToReturnedCode(masm); |
| 330 | 329 |
| 331 __ Bind(&ok); | 330 __ Bind(&ok); |
| 332 GenerateTailCallToSharedCode(masm); | 331 GenerateTailCallToSharedCode(masm); |
| 333 } | 332 } |
| 334 | 333 |
| 335 | 334 |
| 336 static void Generate_JSConstructStubHelper(MacroAssembler* masm, | 335 static void Generate_JSConstructStubHelper(MacroAssembler* masm, |
| 337 bool is_api_function) { | 336 bool is_api_function, |
| 337 bool create_implicit_receiver) { |
| 338 // ----------- S t a t e ------------- | 338 // ----------- S t a t e ------------- |
| 339 // -- x0 : number of arguments | 339 // -- x0 : number of arguments |
| 340 // -- x1 : constructor function | 340 // -- x1 : constructor function |
| 341 // -- x2 : allocation site or undefined | 341 // -- x2 : allocation site or undefined |
| 342 // -- x3 : new target | 342 // -- x3 : new target |
| 343 // -- lr : return address | 343 // -- lr : return address |
| 344 // -- sp[...]: constructor arguments | 344 // -- sp[...]: constructor arguments |
| 345 // ----------------------------------- | 345 // ----------------------------------- |
| 346 | 346 |
| 347 ASM_LOCATION("Builtins::Generate_JSConstructStubHelper"); | 347 ASM_LOCATION("Builtins::Generate_JSConstructStubHelper"); |
| 348 | 348 |
| 349 Isolate* isolate = masm->isolate(); | 349 Isolate* isolate = masm->isolate(); |
| 350 | 350 |
| 351 // Enter a construct frame. | 351 // Enter a construct frame. |
| 352 { | 352 { |
| 353 FrameScope scope(masm, StackFrame::CONSTRUCT); | 353 FrameScope scope(masm, StackFrame::CONSTRUCT); |
| 354 | 354 |
| 355 // Preserve the four incoming parameters on the stack. | 355 // Preserve the four incoming parameters on the stack. |
| 356 Register argc = x0; | 356 Register argc = x0; |
| 357 Register constructor = x1; | 357 Register constructor = x1; |
| 358 Register allocation_site = x2; | 358 Register allocation_site = x2; |
| 359 Register new_target = x3; | 359 Register new_target = x3; |
| 360 | 360 |
| 361 // Preserve the incoming parameters on the stack. | 361 // Preserve the incoming parameters on the stack. |
| 362 __ AssertUndefinedOrAllocationSite(allocation_site, x10); | 362 __ AssertUndefinedOrAllocationSite(allocation_site, x10); |
| 363 __ SmiTag(argc); | 363 __ SmiTag(argc); |
| 364 __ Push(allocation_site, argc, constructor, new_target); | 364 if (create_implicit_receiver) { |
| 365 // sp[0]: new.target | 365 __ Push(allocation_site, argc, constructor, new_target); |
| 366 // sp[1]: Constructor function. | 366 } else { |
| 367 // sp[2]: number of arguments (smi-tagged) | 367 __ Push(allocation_site, argc); |
| 368 // sp[3]: allocation site | 368 } |
| 369 | 369 |
| 370 // Try to allocate the object without transitioning into C code. If any of | 370 if (create_implicit_receiver) { |
| 371 // the preconditions is not met, the code bails out to the runtime call. | 371 // sp[0]: new.target |
| 372 Label rt_call, allocated; | 372 // sp[1]: Constructor function. |
| 373 if (FLAG_inline_new) { | 373 // sp[2]: number of arguments (smi-tagged) |
| 374 // Verify that the new target is a JSFunction. | 374 // sp[3]: allocation site |
| 375 __ JumpIfNotObjectType(new_target, x10, x11, JS_FUNCTION_TYPE, &rt_call); | 375 // Try to allocate the object without transitioning into C code. If any of |
| 376 | 376 // the preconditions is not met, the code bails out to the runtime call. |
| 377 // Load the initial map and verify that it is in fact a map. | 377 Label rt_call, allocated; |
| 378 Register init_map = x2; | 378 if (FLAG_inline_new) { |
| 379 __ Ldr(init_map, | 379 // Verify that the new target is a JSFunction. |
| 380 FieldMemOperand(new_target, | 380 __ JumpIfNotObjectType(new_target, x10, x11, JS_FUNCTION_TYPE, |
| 381 JSFunction::kPrototypeOrInitialMapOffset)); | 381 &rt_call); |
| 382 __ JumpIfSmi(init_map, &rt_call); | 382 |
| 383 __ JumpIfNotObjectType(init_map, x10, x11, MAP_TYPE, &rt_call); | 383 // Load the initial map and verify that it is in fact a map. |
| 384 | 384 Register init_map = x2; |
| 385 // Fall back to runtime if the expected base constructor and base | 385 __ Ldr(init_map, |
| 386 // constructor differ. | 386 FieldMemOperand(new_target, |
| 387 __ Ldr(x10, | 387 JSFunction::kPrototypeOrInitialMapOffset)); |
| 388 FieldMemOperand(init_map, Map::kConstructorOrBackPointerOffset)); | 388 __ JumpIfSmi(init_map, &rt_call); |
| 389 __ Cmp(constructor, x10); | 389 __ JumpIfNotObjectType(init_map, x10, x11, MAP_TYPE, &rt_call); |
| 390 __ B(ne, &rt_call); | 390 |
| 391 | 391 // Fall back to runtime if the expected base constructor and base |
| 392 // Check that the constructor is not constructing a JSFunction (see | 392 // constructor differ. |
| 393 // comments in Runtime_NewObject in runtime.cc). In which case the initial | 393 __ Ldr(x10, |
| 394 // map's instance type would be JS_FUNCTION_TYPE. | 394 FieldMemOperand(init_map, Map::kConstructorOrBackPointerOffset)); |
| 395 __ CompareInstanceType(init_map, x10, JS_FUNCTION_TYPE); | 395 __ Cmp(constructor, x10); |
| 396 __ B(eq, &rt_call); | 396 __ B(ne, &rt_call); |
| 397 | 397 |
| 398 Register constructon_count = x14; | 398 // Check that the constructor is not constructing a JSFunction (see |
| 399 if (!is_api_function) { | 399 // comments in Runtime_NewObject in runtime.cc). In which case the |
| 400 Label allocate; | 400 // initial |
| 401 MemOperand bit_field3 = | 401 // map's instance type would be JS_FUNCTION_TYPE. |
| 402 FieldMemOperand(init_map, Map::kBitField3Offset); | 402 __ CompareInstanceType(init_map, x10, JS_FUNCTION_TYPE); |
| 403 // Check if slack tracking is enabled. | 403 __ B(eq, &rt_call); |
| 404 __ Ldr(x4, bit_field3); | 404 |
| 405 __ DecodeField<Map::Counter>(constructon_count, x4); | 405 Register constructon_count = x14; |
| 406 __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd)); | 406 if (!is_api_function) { |
| 407 __ B(lt, &allocate); | 407 Label allocate; |
| 408 // Decrease generous allocation count. | 408 MemOperand bit_field3 = |
| 409 __ Subs(x4, x4, Operand(1 << Map::Counter::kShift)); | 409 FieldMemOperand(init_map, Map::kBitField3Offset); |
| 410 __ Str(x4, bit_field3); | 410 // Check if slack tracking is enabled. |
| 411 __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd)); | 411 __ Ldr(x4, bit_field3); |
| 412 __ B(ne, &allocate); | 412 __ DecodeField<Map::Counter>(constructon_count, x4); |
| 413 | 413 __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd)); |
| 414 // Push the constructor and map to the stack, and the map again | 414 __ B(lt, &allocate); |
| 415 // as argument to the runtime call. | 415 // Decrease generous allocation count. |
| 416 __ Push(constructor, init_map, init_map); | 416 __ Subs(x4, x4, Operand(1 << Map::Counter::kShift)); |
| 417 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1); | 417 __ Str(x4, bit_field3); |
| 418 __ Pop(init_map, constructor); | 418 __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd)); |
| 419 __ Mov(constructon_count, Operand(Map::kSlackTrackingCounterEnd - 1)); | 419 __ B(ne, &allocate); |
| 420 __ Bind(&allocate); | 420 |
| 421 // Push the constructor and map to the stack, and the map again |
| 422 // as argument to the runtime call. |
| 423 __ Push(constructor, init_map, init_map); |
| 424 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1); |
| 425 __ Pop(init_map, constructor); |
| 426 __ Mov(constructon_count, Operand(Map::kSlackTrackingCounterEnd - 1)); |
| 427 __ Bind(&allocate); |
| 428 } |
| 429 |
| 430 // Now allocate the JSObject on the heap. |
| 431 Label rt_call_reload_new_target; |
| 432 Register obj_size = x3; |
| 433 Register new_obj = x4; |
| 434 __ Ldrb(obj_size, FieldMemOperand(init_map, Map::kInstanceSizeOffset)); |
| 435 __ Allocate(obj_size, new_obj, x10, x11, &rt_call_reload_new_target, |
| 436 SIZE_IN_WORDS); |
| 437 |
| 438 // Allocated the JSObject, now initialize the fields. Map is set to |
| 439 // initial map and properties and elements are set to empty fixed array. |
| 440 // NB. the object pointer is not tagged, so MemOperand is used. |
| 441 Register empty = x5; |
| 442 __ LoadRoot(empty, Heap::kEmptyFixedArrayRootIndex); |
| 443 __ Str(init_map, MemOperand(new_obj, JSObject::kMapOffset)); |
| 444 STATIC_ASSERT(JSObject::kElementsOffset == |
| 445 (JSObject::kPropertiesOffset + kPointerSize)); |
| 446 __ Stp(empty, empty, MemOperand(new_obj, JSObject::kPropertiesOffset)); |
| 447 |
| 448 Register first_prop = x5; |
| 449 __ Add(first_prop, new_obj, JSObject::kHeaderSize); |
| 450 |
| 451 // Fill all of the in-object properties with the appropriate filler. |
| 452 Register filler = x7; |
| 453 __ LoadRoot(filler, Heap::kUndefinedValueRootIndex); |
| 454 |
| 455 // Obtain number of pre-allocated property fields and in-object |
| 456 // properties. |
| 457 Register unused_props = x10; |
| 458 Register inobject_props = x11; |
| 459 Register inst_sizes_or_attrs = x11; |
| 460 Register prealloc_fields = x10; |
| 461 __ Ldr(inst_sizes_or_attrs, |
| 462 FieldMemOperand(init_map, Map::kInstanceAttributesOffset)); |
| 463 __ Ubfx(unused_props, inst_sizes_or_attrs, |
| 464 Map::kUnusedPropertyFieldsByte * kBitsPerByte, kBitsPerByte); |
| 465 __ Ldr(inst_sizes_or_attrs, |
| 466 FieldMemOperand(init_map, Map::kInstanceSizesOffset)); |
| 467 __ Ubfx(inobject_props, inst_sizes_or_attrs, |
| 468 Map::kInObjectPropertiesOrConstructorFunctionIndexByte * |
| 469 kBitsPerByte, |
| 470 kBitsPerByte); |
| 471 __ Sub(prealloc_fields, inobject_props, unused_props); |
| 472 |
| 473 // Calculate number of property fields in the object. |
| 474 Register prop_fields = x6; |
| 475 __ Sub(prop_fields, obj_size, JSObject::kHeaderSize / kPointerSize); |
| 476 |
| 477 if (!is_api_function) { |
| 478 Label no_inobject_slack_tracking; |
| 479 |
| 480 // Check if slack tracking is enabled. |
| 481 __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd)); |
| 482 __ B(lt, &no_inobject_slack_tracking); |
| 483 constructon_count = NoReg; |
| 484 |
| 485 // Fill the pre-allocated fields with undef. |
| 486 __ FillFields(first_prop, prealloc_fields, filler); |
| 487 |
| 488 // Update first_prop register to be the offset of the first field |
| 489 // after |
| 490 // pre-allocated fields. |
| 491 __ Add(first_prop, first_prop, |
| 492 Operand(prealloc_fields, LSL, kPointerSizeLog2)); |
| 493 |
| 494 if (FLAG_debug_code) { |
| 495 Register obj_end = x14; |
| 496 __ Add(obj_end, new_obj, Operand(obj_size, LSL, kPointerSizeLog2)); |
| 497 __ Cmp(first_prop, obj_end); |
| 498 __ Assert(le, kUnexpectedNumberOfPreAllocatedPropertyFields); |
| 499 } |
| 500 |
| 501 // Fill the remaining fields with one pointer filler map. |
| 502 __ LoadRoot(filler, Heap::kOnePointerFillerMapRootIndex); |
| 503 __ Sub(prop_fields, prop_fields, prealloc_fields); |
| 504 |
| 505 __ bind(&no_inobject_slack_tracking); |
| 506 } |
| 507 |
| 508 // Fill all of the property fields with undef. |
| 509 __ FillFields(first_prop, prop_fields, filler); |
| 510 first_prop = NoReg; |
| 511 prop_fields = NoReg; |
| 512 |
| 513 // Add the object tag to make the JSObject real, so that we can continue |
| 514 // and jump into the continuation code at any time from now on. |
| 515 __ Add(new_obj, new_obj, kHeapObjectTag); |
| 516 |
| 517 // Continue with JSObject being successfully allocated. |
| 518 __ B(&allocated); |
| 519 |
| 520 // Reload the new target and fall-through. |
| 521 __ Bind(&rt_call_reload_new_target); |
| 522 __ Peek(x3, 0 * kXRegSize); |
| 421 } | 523 } |
| 422 | 524 |
| 423 // Now allocate the JSObject on the heap. | 525 // Allocate the new receiver object using the runtime call. |
| 424 Label rt_call_reload_new_target; | 526 // x1: constructor function |
| 425 Register obj_size = x3; | 527 // x3: new target |
| 426 Register new_obj = x4; | 528 __ Bind(&rt_call); |
| 427 __ Ldrb(obj_size, FieldMemOperand(init_map, Map::kInstanceSizeOffset)); | 529 __ Push(constructor, new_target); // arguments 1-2 |
| 428 __ Allocate(obj_size, new_obj, x10, x11, &rt_call_reload_new_target, | 530 __ CallRuntime(Runtime::kNewObject, 2); |
| 429 SIZE_IN_WORDS); | 531 __ Mov(x4, x0); |
| 430 | 532 |
| 431 // Allocated the JSObject, now initialize the fields. Map is set to | 533 // Receiver for constructor call allocated. |
| 432 // initial map and properties and elements are set to empty fixed array. | 534 // x4: JSObject |
| 433 // NB. the object pointer is not tagged, so MemOperand is used. | 535 __ Bind(&allocated); |
| 434 Register empty = x5; | 536 |
| 435 __ LoadRoot(empty, Heap::kEmptyFixedArrayRootIndex); | 537 // Restore the parameters. |
| 436 __ Str(init_map, MemOperand(new_obj, JSObject::kMapOffset)); | 538 __ Pop(new_target); |
| 437 STATIC_ASSERT(JSObject::kElementsOffset == | 539 __ Pop(constructor); |
| 438 (JSObject::kPropertiesOffset + kPointerSize)); | 540 |
| 439 __ Stp(empty, empty, MemOperand(new_obj, JSObject::kPropertiesOffset)); | 541 // Reload the number of arguments from the stack. |
| 440 | 542 // Set it up in x0 for the function call below. |
| 441 Register first_prop = x5; | 543 // jssp[0]: number of arguments (smi-tagged) |
| 442 __ Add(first_prop, new_obj, JSObject::kHeaderSize); | 544 __ Peek(argc, 0); // Load number of arguments. |
| 443 | |
| 444 // Fill all of the in-object properties with the appropriate filler. | |
| 445 Register filler = x7; | |
| 446 __ LoadRoot(filler, Heap::kUndefinedValueRootIndex); | |
| 447 | |
| 448 // Obtain number of pre-allocated property fields and in-object | |
| 449 // properties. | |
| 450 Register unused_props = x10; | |
| 451 Register inobject_props = x11; | |
| 452 Register inst_sizes_or_attrs = x11; | |
| 453 Register prealloc_fields = x10; | |
| 454 __ Ldr(inst_sizes_or_attrs, | |
| 455 FieldMemOperand(init_map, Map::kInstanceAttributesOffset)); | |
| 456 __ Ubfx(unused_props, inst_sizes_or_attrs, | |
| 457 Map::kUnusedPropertyFieldsByte * kBitsPerByte, kBitsPerByte); | |
| 458 __ Ldr(inst_sizes_or_attrs, | |
| 459 FieldMemOperand(init_map, Map::kInstanceSizesOffset)); | |
| 460 __ Ubfx( | |
| 461 inobject_props, inst_sizes_or_attrs, | |
| 462 Map::kInObjectPropertiesOrConstructorFunctionIndexByte * kBitsPerByte, | |
| 463 kBitsPerByte); | |
| 464 __ Sub(prealloc_fields, inobject_props, unused_props); | |
| 465 | |
| 466 // Calculate number of property fields in the object. | |
| 467 Register prop_fields = x6; | |
| 468 __ Sub(prop_fields, obj_size, JSObject::kHeaderSize / kPointerSize); | |
| 469 | |
| 470 if (!is_api_function) { | |
| 471 Label no_inobject_slack_tracking; | |
| 472 | |
| 473 // Check if slack tracking is enabled. | |
| 474 __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd)); | |
| 475 __ B(lt, &no_inobject_slack_tracking); | |
| 476 constructon_count = NoReg; | |
| 477 | |
| 478 // Fill the pre-allocated fields with undef. | |
| 479 __ FillFields(first_prop, prealloc_fields, filler); | |
| 480 | |
| 481 // Update first_prop register to be the offset of the first field after | |
| 482 // pre-allocated fields. | |
| 483 __ Add(first_prop, first_prop, | |
| 484 Operand(prealloc_fields, LSL, kPointerSizeLog2)); | |
| 485 | |
| 486 if (FLAG_debug_code) { | |
| 487 Register obj_end = x14; | |
| 488 __ Add(obj_end, new_obj, Operand(obj_size, LSL, kPointerSizeLog2)); | |
| 489 __ Cmp(first_prop, obj_end); | |
| 490 __ Assert(le, kUnexpectedNumberOfPreAllocatedPropertyFields); | |
| 491 } | |
| 492 | |
| 493 // Fill the remaining fields with one pointer filler map. | |
| 494 __ LoadRoot(filler, Heap::kOnePointerFillerMapRootIndex); | |
| 495 __ Sub(prop_fields, prop_fields, prealloc_fields); | |
| 496 | |
| 497 __ bind(&no_inobject_slack_tracking); | |
| 498 } | |
| 499 | |
| 500 // Fill all of the property fields with undef. | |
| 501 __ FillFields(first_prop, prop_fields, filler); | |
| 502 first_prop = NoReg; | |
| 503 prop_fields = NoReg; | |
| 504 | |
| 505 // Add the object tag to make the JSObject real, so that we can continue | |
| 506 // and jump into the continuation code at any time from now on. | |
| 507 __ Add(new_obj, new_obj, kHeapObjectTag); | |
| 508 | |
| 509 // Continue with JSObject being successfully allocated. | |
| 510 __ B(&allocated); | |
| 511 | |
| 512 // Reload the new target and fall-through. | |
| 513 __ Bind(&rt_call_reload_new_target); | |
| 514 __ Peek(x3, 0 * kXRegSize); | |
| 515 } | 545 } |
| 516 | 546 |
| 517 // Allocate the new receiver object using the runtime call. | |
| 518 // x1: constructor function | |
| 519 // x3: new target | |
| 520 __ Bind(&rt_call); | |
| 521 __ Push(constructor, new_target); // arguments 1-2 | |
| 522 __ CallRuntime(Runtime::kNewObject, 2); | |
| 523 __ Mov(x4, x0); | |
| 524 | |
| 525 // Receiver for constructor call allocated. | |
| 526 // x4: JSObject | |
| 527 __ Bind(&allocated); | |
| 528 | |
| 529 // Restore the parameters. | |
| 530 __ Pop(new_target); | |
| 531 __ Pop(constructor); | |
| 532 | |
| 533 // Reload the number of arguments from the stack. | |
| 534 // Set it up in x0 for the function call below. | |
| 535 // jssp[0]: number of arguments (smi-tagged) | |
| 536 __ Peek(argc, 0); // Load number of arguments. | |
| 537 __ SmiUntag(argc); | 547 __ SmiUntag(argc); |
| 538 | 548 |
| 539 __ Push(new_target, x4, x4); | 549 // Push new.target onto the construct frame. This is stored just below the |
| 550 // receiver on the stack. |
| 551 if (create_implicit_receiver) { |
| 552 // Push the allocated receiver to the stack. We need two copies |
| 553 // because we may have to return the original one and the calling |
| 554 // conventions dictate that the called function pops the receiver. |
| 555 __ Push(new_target, x4, x4); |
| 556 } else { |
| 557 __ push(new_target); |
| 558 __ PushRoot(Heap::kTheHoleValueRootIndex); |
| 559 } |
| 540 | 560 |
| 541 // Set up pointer to last argument. | 561 // Set up pointer to last argument. |
| 542 __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset); | 562 __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset); |
| 543 | 563 |
| 544 // Copy arguments and receiver to the expression stack. | 564 // Copy arguments and receiver to the expression stack. |
| 545 // Copy 2 values every loop to use ldp/stp. | 565 // Copy 2 values every loop to use ldp/stp. |
| 546 // x0: number of arguments | 566 // x0: number of arguments |
| 547 // x1: constructor function | 567 // x1: constructor function |
| 548 // x2: address of last argument (caller sp) | 568 // x2: address of last argument (caller sp) |
| 549 // jssp[0]: receiver | 569 // jssp[0]: receiver |
| (...skipping 23 matching lines...) Expand all Loading... |
| 573 __ Ldr(cp, FieldMemOperand(constructor, JSFunction::kContextOffset)); | 593 __ Ldr(cp, FieldMemOperand(constructor, JSFunction::kContextOffset)); |
| 574 Handle<Code> code = | 594 Handle<Code> code = |
| 575 masm->isolate()->builtins()->HandleApiCallConstruct(); | 595 masm->isolate()->builtins()->HandleApiCallConstruct(); |
| 576 __ Call(code, RelocInfo::CODE_TARGET); | 596 __ Call(code, RelocInfo::CODE_TARGET); |
| 577 } else { | 597 } else { |
| 578 ParameterCount actual(argc); | 598 ParameterCount actual(argc); |
| 579 __ InvokeFunction(constructor, actual, CALL_FUNCTION, NullCallWrapper()); | 599 __ InvokeFunction(constructor, actual, CALL_FUNCTION, NullCallWrapper()); |
| 580 } | 600 } |
| 581 | 601 |
| 582 // Store offset of return address for deoptimizer. | 602 // Store offset of return address for deoptimizer. |
| 583 if (!is_api_function) { | 603 if (create_implicit_receiver && !is_api_function) { |
| 584 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); | 604 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); |
| 585 } | 605 } |
| 586 | 606 |
| 587 // Restore the context from the frame. | 607 // Restore the context from the frame. |
| 588 // x0: result | 608 // x0: result |
| 589 // jssp[0]: receiver | 609 // jssp[0]: receiver |
| 590 // jssp[1]: new.target | 610 // jssp[1]: new.target |
| 591 // jssp[2]: number of arguments (smi-tagged) | 611 // jssp[2]: number of arguments (smi-tagged) |
| 592 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 612 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 593 | 613 |
| 594 // If the result is an object (in the ECMA sense), we should get rid | 614 if (create_implicit_receiver) { |
| 595 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 | 615 // If the result is an object (in the ECMA sense), we should get rid |
| 596 // on page 74. | 616 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 |
| 597 Label use_receiver, exit; | 617 // on page 74. |
| 618 Label use_receiver, exit; |
| 598 | 619 |
| 599 // If the result is a smi, it is *not* an object in the ECMA sense. | 620 // If the result is a smi, it is *not* an object in the ECMA sense. |
| 600 // x0: result | 621 // x0: result |
| 601 // jssp[0]: receiver (newly allocated object) | 622 // jssp[0]: receiver (newly allocated object) |
| 602 // jssp[1]: number of arguments (smi-tagged) | 623 // jssp[1]: number of arguments (smi-tagged) |
| 603 __ JumpIfSmi(x0, &use_receiver); | 624 __ JumpIfSmi(x0, &use_receiver); |
| 604 | 625 |
| 605 // If the type of the result (stored in its map) is less than | 626 // If the type of the result (stored in its map) is less than |
| 606 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense. | 627 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense. |
| 607 __ JumpIfObjectType(x0, x1, x3, FIRST_SPEC_OBJECT_TYPE, &exit, ge); | 628 __ JumpIfObjectType(x0, x1, x3, FIRST_SPEC_OBJECT_TYPE, &exit, ge); |
| 608 | 629 |
| 609 // Throw away the result of the constructor invocation and use the | 630 // Throw away the result of the constructor invocation and use the |
| 610 // on-stack receiver as the result. | 631 // on-stack receiver as the result. |
| 611 __ Bind(&use_receiver); | 632 __ Bind(&use_receiver); |
| 612 __ Peek(x0, 0); | 633 __ Peek(x0, 0); |
| 613 | 634 |
| 614 // Remove the receiver from the stack, remove caller arguments, and | 635 // Remove the receiver from the stack, remove caller arguments, and |
| 615 // return. | 636 // return. |
| 616 __ Bind(&exit); | 637 __ Bind(&exit); |
| 617 // x0: result | 638 // x0: result |
| 618 // jssp[0]: receiver (newly allocated object) | 639 // jssp[0]: receiver (newly allocated object) |
| 619 // jssp[1]: new target | 640 // jssp[1]: new target |
| 620 // jssp[2]: number of arguments (smi-tagged) | 641 // jssp[2]: number of arguments (smi-tagged) |
| 621 __ Peek(x1, 2 * kXRegSize); | 642 __ Peek(x1, 2 * kXRegSize); |
| 643 } else { |
| 644 __ Peek(x1, kXRegSize); |
| 645 } |
| 622 | 646 |
| 623 // Leave construct frame. | 647 // Leave construct frame. |
| 624 } | 648 } |
| 625 | 649 |
| 626 __ DropBySMI(x1); | 650 __ DropBySMI(x1); |
| 627 __ Drop(1); | 651 __ Drop(1); |
| 628 __ IncrementCounter(isolate->counters()->constructed_objects(), 1, x1, x2); | 652 if (create_implicit_receiver) { |
| 653 __ IncrementCounter(isolate->counters()->constructed_objects(), 1, x1, x2); |
| 654 } |
| 629 __ Ret(); | 655 __ Ret(); |
| 630 } | 656 } |
| 631 | 657 |
| 632 | 658 |
| 633 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { | 659 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { |
| 634 Generate_JSConstructStubHelper(masm, false); | 660 Generate_JSConstructStubHelper(masm, false, true); |
| 635 } | 661 } |
| 636 | 662 |
| 637 | 663 |
| 638 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { | 664 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { |
| 639 Generate_JSConstructStubHelper(masm, true); | 665 Generate_JSConstructStubHelper(masm, true, true); |
| 640 } | 666 } |
| 641 | 667 |
| 642 | 668 |
| 643 void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) { | 669 void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) { |
| 644 // ----------- S t a t e ------------- | 670 Generate_JSConstructStubHelper(masm, false, false); |
| 645 // -- x0 : number of arguments | |
| 646 // -- x1 : constructor function | |
| 647 // -- x2 : allocation site or undefined | |
| 648 // -- x3 : new target | |
| 649 // -- lr : return address | |
| 650 // -- sp[...]: constructor arguments | |
| 651 // ----------------------------------- | |
| 652 ASM_LOCATION("Builtins::Generate_JSConstructStubForDerived"); | |
| 653 | |
| 654 { | |
| 655 FrameScope frame_scope(masm, StackFrame::CONSTRUCT); | |
| 656 | |
| 657 __ AssertUndefinedOrAllocationSite(x2, x10); | |
| 658 __ Mov(x4, x0); | |
| 659 __ SmiTag(x4); | |
| 660 __ LoadRoot(x10, Heap::kTheHoleValueRootIndex); | |
| 661 __ Push(x2, x4, x3, x10); | |
| 662 // sp[0]: receiver (the hole) | |
| 663 // sp[1]: new.target | |
| 664 // sp[2]: number of arguments | |
| 665 // sp[3]: allocation site | |
| 666 | |
| 667 // Set up pointer to last argument. | |
| 668 __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset); | |
| 669 | |
| 670 // Copy arguments and receiver to the expression stack. | |
| 671 // Copy 2 values every loop to use ldp/stp. | |
| 672 // x0: number of arguments | |
| 673 // x1: constructor function | |
| 674 // x2: address of last argument (caller sp) | |
| 675 // jssp[0]: receiver | |
| 676 // jssp[1]: new.target | |
| 677 // jssp[2]: number of arguments (smi-tagged) | |
| 678 // Compute the start address of the copy in x4. | |
| 679 __ Add(x4, x2, Operand(x0, LSL, kPointerSizeLog2)); | |
| 680 Label loop, entry, done_copying_arguments; | |
| 681 __ B(&entry); | |
| 682 __ Bind(&loop); | |
| 683 __ Ldp(x10, x11, MemOperand(x4, -2 * kPointerSize, PreIndex)); | |
| 684 __ Push(x11, x10); | |
| 685 __ Bind(&entry); | |
| 686 __ Cmp(x4, x2); | |
| 687 __ B(gt, &loop); | |
| 688 // Because we copied values 2 by 2 we may have copied one extra value. | |
| 689 // Drop it if that is the case. | |
| 690 __ B(eq, &done_copying_arguments); | |
| 691 __ Drop(1); | |
| 692 __ Bind(&done_copying_arguments); | |
| 693 | |
| 694 // Call the function. | |
| 695 // x0: number of arguments | |
| 696 // x1: constructor function | |
| 697 ParameterCount actual(x0); | |
| 698 __ InvokeFunction(x1, actual, CALL_FUNCTION, NullCallWrapper()); | |
| 699 | |
| 700 // Restore the context from the frame. | |
| 701 // x0: result | |
| 702 // jssp[0]: number of arguments (smi-tagged) | |
| 703 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | |
| 704 | |
| 705 // Load number of arguments (smi), skipping over new.target. | |
| 706 __ Peek(x1, kPointerSize); | |
| 707 | |
| 708 // Leave construct frame | |
| 709 } | |
| 710 | |
| 711 __ DropBySMI(x1); | |
| 712 __ Drop(1); | |
| 713 __ Ret(); | |
| 714 } | 671 } |
| 715 | 672 |
| 716 | 673 |
| 717 enum IsTagged { kArgcIsSmiTagged, kArgcIsUntaggedInt }; | 674 enum IsTagged { kArgcIsSmiTagged, kArgcIsUntaggedInt }; |
| 718 | 675 |
| 719 | 676 |
| 720 // Clobbers x10, x15; preserves all other registers. | 677 // Clobbers x10, x15; preserves all other registers. |
| 721 static void Generate_CheckStackOverflow(MacroAssembler* masm, Register argc, | 678 static void Generate_CheckStackOverflow(MacroAssembler* masm, Register argc, |
| 722 IsTagged argc_is_tagged) { | 679 IsTagged argc_is_tagged) { |
| 723 // Check the stack for overflow. | 680 // Check the stack for overflow. |
| (...skipping 1274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1998 } | 1955 } |
| 1999 } | 1956 } |
| 2000 | 1957 |
| 2001 | 1958 |
| 2002 #undef __ | 1959 #undef __ |
| 2003 | 1960 |
| 2004 } // namespace internal | 1961 } // namespace internal |
| 2005 } // namespace v8 | 1962 } // namespace v8 |
| 2006 | 1963 |
| 2007 #endif // V8_TARGET_ARCH_ARM | 1964 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |