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

Side by Side Diff: src/ia32/builtins-ia32.cc

Issue 604064: Fix stack corruption when calling non-function. (Closed)
Patch Set: Created 10 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/arm/codegen-arm.cc ('k') | src/ia32/codegen-ia32.cc » ('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 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 86
87 // Jump to the function-specific construct stub. 87 // Jump to the function-specific construct stub.
88 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 88 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
89 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset)); 89 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset));
90 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize)); 90 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
91 __ jmp(Operand(ebx)); 91 __ jmp(Operand(ebx));
92 92
93 // edi: called object 93 // edi: called object
94 // eax: number of arguments 94 // eax: number of arguments
95 __ bind(&non_function_call); 95 __ bind(&non_function_call);
96 96 // CALL_NON_FUNCTION expects the non-function constructor as receiver
97 // (instead of the original receiver from the call site). The receiver is
98 // stack element argc+1.
99 __ mov(Operand(esp, eax, times_4, kPointerSize), edi);
97 // Set expected number of arguments to zero (not changing eax). 100 // Set expected number of arguments to zero (not changing eax).
98 __ Set(ebx, Immediate(0)); 101 __ Set(ebx, Immediate(0));
99 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); 102 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
100 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), 103 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
101 RelocInfo::CODE_TARGET); 104 RelocInfo::CODE_TARGET);
102 } 105 }
103 106
104 107
105 static void Generate_JSConstructStubHelper(MacroAssembler* masm, 108 static void Generate_JSConstructStubHelper(MacroAssembler* masm,
106 bool is_api_function) { 109 bool is_api_function) {
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 { Label done; 433 { Label done;
431 __ test(eax, Operand(eax)); 434 __ test(eax, Operand(eax));
432 __ j(not_zero, &done, taken); 435 __ j(not_zero, &done, taken);
433 __ pop(ebx); 436 __ pop(ebx);
434 __ push(Immediate(Factory::undefined_value())); 437 __ push(Immediate(Factory::undefined_value()));
435 __ push(ebx); 438 __ push(ebx);
436 __ inc(eax); 439 __ inc(eax);
437 __ bind(&done); 440 __ bind(&done);
438 } 441 }
439 442
440 // 2. Get the function to call from the stack. 443 // 2. Get the function to call (passed as receiver) from the stack, check
441 { Label done, non_function, function; 444 // if it is a function.
442 // +1 ~ return address. 445 Label non_function;
443 __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize)); 446 { Label function;
447 // 1 ~ return address.
448 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
444 __ test(edi, Immediate(kSmiTagMask)); 449 __ test(edi, Immediate(kSmiTagMask));
445 __ j(zero, &non_function, not_taken); 450 __ j(zero, &non_function, not_taken);
446 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 451 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
447 __ j(equal, &function, taken); 452 __ j(not_equal, &non_function, not_taken);
453 __ bind(&function);
454 }
448 455
449 // Non-function called: Clear the function to force exception. 456 // 3a. Patch the first argument if necessary when calling a function.
450 __ bind(&non_function); 457 Label shift_arguments;
451 __ xor_(edi, Operand(edi)); 458 { Label convert_to_object, use_global_receiver, patch_receiver;
452 __ jmp(&done); 459 // Change context eagerly in case we need the global receiver.
453
454 // Function called: Change context eagerly to get the right global object.
455 __ bind(&function);
456 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 460 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
457 461
458 __ bind(&done); 462 __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument.
459 }
460
461 // 3. Make sure first argument is an object; convert if necessary.
462 { Label call_to_object, use_global_receiver, patch_receiver, done;
463 __ mov(ebx, Operand(esp, eax, times_4, 0));
464
465 __ test(ebx, Immediate(kSmiTagMask)); 463 __ test(ebx, Immediate(kSmiTagMask));
466 __ j(zero, &call_to_object); 464 __ j(zero, &convert_to_object);
467 465
468 __ cmp(ebx, Factory::null_value()); 466 __ cmp(ebx, Factory::null_value());
469 __ j(equal, &use_global_receiver); 467 __ j(equal, &use_global_receiver);
470 __ cmp(ebx, Factory::undefined_value()); 468 __ cmp(ebx, Factory::undefined_value());
471 __ j(equal, &use_global_receiver); 469 __ j(equal, &use_global_receiver);
472 470
473 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); 471 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
474 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 472 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
475 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); 473 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
476 __ j(less, &call_to_object); 474 __ j(below, &convert_to_object);
477 __ cmp(ecx, LAST_JS_OBJECT_TYPE); 475 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
478 __ j(less_equal, &done); 476 __ j(below_equal, &shift_arguments);
479 477
480 __ bind(&call_to_object); 478 __ bind(&convert_to_object);
481 __ EnterInternalFrame(); // preserves eax, ebx, edi 479 __ EnterInternalFrame(); // In order to preserve argument count.
482
483 // Store the arguments count on the stack (smi tagged).
484 __ SmiTag(eax); 480 __ SmiTag(eax);
485 __ push(eax); 481 __ push(eax);
486 482
487 __ push(edi); // save edi across the call
488 __ push(ebx); 483 __ push(ebx);
489 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 484 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
490 __ mov(ebx, eax); 485 __ mov(ebx, eax);
491 __ pop(edi); // restore edi after the call
492 486
493 // Get the arguments count and untag it.
494 __ pop(eax); 487 __ pop(eax);
495 __ SmiUntag(eax); 488 __ SmiUntag(eax);
496
497 __ LeaveInternalFrame(); 489 __ LeaveInternalFrame();
490 // Restore the function to edi.
491 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
498 __ jmp(&patch_receiver); 492 __ jmp(&patch_receiver);
499 493
500 // Use the global receiver object from the called function as the receiver. 494 // Use the global receiver object from the called function as the
495 // receiver.
501 __ bind(&use_global_receiver); 496 __ bind(&use_global_receiver);
502 const int kGlobalIndex = 497 const int kGlobalIndex =
503 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; 498 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
504 __ mov(ebx, FieldOperand(esi, kGlobalIndex)); 499 __ mov(ebx, FieldOperand(esi, kGlobalIndex));
505 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset)); 500 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset));
506 __ mov(ebx, FieldOperand(ebx, kGlobalIndex)); 501 __ mov(ebx, FieldOperand(ebx, kGlobalIndex));
507 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); 502 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
508 503
509 __ bind(&patch_receiver); 504 __ bind(&patch_receiver);
510 __ mov(Operand(esp, eax, times_4, 0), ebx); 505 __ mov(Operand(esp, eax, times_4, 0), ebx);
511 506
512 __ bind(&done); 507 __ jmp(&shift_arguments);
513 } 508 }
514 509
515 // 4. Check that the function really is a function. 510 // 3b. Patch the first argument when calling a non-function. The
516 { Label done; 511 // CALL_NON_FUNCTION builtin expects the non-function callee as
517 __ test(edi, Operand(edi)); 512 // receiver, so overwrite the first argument which will ultimately
518 __ j(not_zero, &done, taken); 513 // become the receiver.
519 __ xor_(ebx, Operand(ebx)); 514 __ bind(&non_function);
520 // CALL_NON_FUNCTION will expect to find the non-function callee on the 515 __ mov(Operand(esp, eax, times_4, 0), edi);
521 // expression stack of the caller. Transfer it from receiver to the 516 // Clear edi to indicate a non-function being called.
522 // caller's expression stack (and make the first argument the receiver 517 __ xor_(edi, Operand(edi));
523 // for CALL_NON_FUNCTION) by decrementing the argument count.
524 __ dec(eax);
525 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
526 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
527 RelocInfo::CODE_TARGET);
528 __ bind(&done);
529 }
530 518
531 // 5. Shift arguments and return address one slot down on the stack 519 // 4. Shift arguments and return address one slot down on the stack
532 // (overwriting the receiver). 520 // (overwriting the original receiver). Adjust argument count to make
521 // the original first argument the new receiver.
522 __ bind(&shift_arguments);
533 { Label loop; 523 { Label loop;
534 __ mov(ecx, eax); 524 __ mov(ecx, eax);
535 __ bind(&loop); 525 __ bind(&loop);
536 __ mov(ebx, Operand(esp, ecx, times_4, 0)); 526 __ mov(ebx, Operand(esp, ecx, times_4, 0));
537 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); 527 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
538 __ dec(ecx); 528 __ dec(ecx);
539 __ j(not_sign, &loop); 529 __ j(not_sign, &loop); // While non-negative (to copy return address).
540 __ pop(ebx); // Discard copy of return address. 530 __ pop(ebx); // Discard copy of return address.
541 __ dec(eax); // One fewer argument (first argument is new receiver). 531 __ dec(eax); // One fewer argument (first argument is new receiver).
542 } 532 }
543 533
544 // 6. Get the code to call from the function and check that the number of 534 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
545 // expected arguments matches what we're providing. 535 { Label function;
546 { __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 536 __ test(edi, Operand(edi));
547 __ mov(ebx, 537 __ j(not_zero, &function, taken);
548 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); 538 __ xor_(ebx, Operand(ebx));
549 __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); 539 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
550 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); 540 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
551 __ cmp(eax, Operand(ebx)); 541 RelocInfo::CODE_TARGET);
552 __ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline))); 542 __ bind(&function);
553 } 543 }
554 544
555 // 7. Jump (tail-call) to the code in register edx without checking arguments. 545 // 5b. Get the code to call from the function and check that the number of
546 // expected arguments matches what we're providing. If so, jump
547 // (tail-call) to the code in register edx without checking arguments.
548 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
549 __ mov(ebx,
550 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
551 __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
552 __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
553 __ cmp(eax, Operand(ebx));
554 __ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline)));
555
556 ParameterCount expected(0); 556 ParameterCount expected(0);
557 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION); 557 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION);
558 } 558 }
559 559
560 560
561 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { 561 void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
562 __ EnterInternalFrame(); 562 __ EnterInternalFrame();
563 563
564 __ push(Operand(ebp, 4 * kPointerSize)); // push this 564 __ push(Operand(ebp, 4 * kPointerSize)); // push this
565 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments 565 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments
(...skipping 688 matching lines...) Expand 10 before | Expand all | Expand 10 after
1254 // Dont adapt arguments. 1254 // Dont adapt arguments.
1255 // ------------------------------------------- 1255 // -------------------------------------------
1256 __ bind(&dont_adapt_arguments); 1256 __ bind(&dont_adapt_arguments);
1257 __ jmp(Operand(edx)); 1257 __ jmp(Operand(edx));
1258 } 1258 }
1259 1259
1260 1260
1261 #undef __ 1261 #undef __
1262 1262
1263 } } // namespace v8::internal 1263 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/arm/codegen-arm.cc ('k') | src/ia32/codegen-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698