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

Side by Side Diff: src/arm/builtins-arm.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 | « no previous file | src/arm/codegen-arm.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 481 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 __ b(ne, &non_function_call); 492 __ b(ne, &non_function_call);
493 493
494 // Jump to the function-specific construct stub. 494 // Jump to the function-specific construct stub.
495 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); 495 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
496 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kConstructStubOffset)); 496 __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kConstructStubOffset));
497 __ add(pc, r2, Operand(Code::kHeaderSize - kHeapObjectTag)); 497 __ add(pc, r2, Operand(Code::kHeaderSize - kHeapObjectTag));
498 498
499 // r0: number of arguments 499 // r0: number of arguments
500 // r1: called object 500 // r1: called object
501 __ bind(&non_function_call); 501 __ bind(&non_function_call);
502 502 // CALL_NON_FUNCTION expects the non-function constructor as receiver
503 // (instead of the original receiver from the call site). The receiver is
504 // stack element argc.
505 __ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
503 // Set expected number of arguments to zero (not changing r0). 506 // Set expected number of arguments to zero (not changing r0).
504 __ mov(r2, Operand(0)); 507 __ mov(r2, Operand(0));
505 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); 508 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
506 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), 509 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
507 RelocInfo::CODE_TARGET); 510 RelocInfo::CODE_TARGET);
508 } 511 }
509 512
510 513
511 static void Generate_JSConstructStubHelper(MacroAssembler* masm, 514 static void Generate_JSConstructStubHelper(MacroAssembler* masm,
512 bool is_api_function) { 515 bool is_api_function) {
(...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after
897 } 900 }
898 901
899 902
900 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { 903 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
901 Generate_JSEntryTrampolineHelper(masm, true); 904 Generate_JSEntryTrampolineHelper(masm, true);
902 } 905 }
903 906
904 907
905 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { 908 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
906 // 1. Make sure we have at least one argument. 909 // 1. Make sure we have at least one argument.
907 // r0: actual number of argument 910 // r0: actual number of arguments
908 { Label done; 911 { Label done;
909 __ tst(r0, Operand(r0)); 912 __ tst(r0, Operand(r0));
910 __ b(ne, &done); 913 __ b(ne, &done);
911 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); 914 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
912 __ push(r2); 915 __ push(r2);
913 __ add(r0, r0, Operand(1)); 916 __ add(r0, r0, Operand(1));
914 __ bind(&done); 917 __ bind(&done);
915 } 918 }
916 919
917 // 2. Get the function to call from the stack. 920 // 2. Get the function to call (passed as receiver) from the stack, check
921 // if it is a function.
918 // r0: actual number of arguments 922 // r0: actual number of arguments
919 { Label done, non_function, function; 923 Label non_function;
924 { Label function;
920 __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); 925 __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
921 __ tst(r1, Operand(kSmiTagMask)); 926 __ tst(r1, Operand(kSmiTagMask));
922 __ b(eq, &non_function); 927 __ b(eq, &non_function);
923 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); 928 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
924 __ b(eq, &function); 929 __ b(ne, &non_function);
930 __ bind(&function);
931 }
925 932
926 // Non-function called: Clear the function to force exception. 933 // 3a. Patch the first argument if necessary when calling a function.
927 __ bind(&non_function); 934 // r0: actual number of arguments
928 __ mov(r1, Operand(0)); 935 // r1: function
929 __ b(&done); 936 Label shift_arguments;
930 937 { Label convert_to_object, use_global_receiver, patch_receiver;
931 // Change the context eagerly because it will be used below to get the 938 // Change context eagerly in case we need the global receiver.
932 // right global object.
933 __ bind(&function);
934 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); 939 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
935 940
936 __ bind(&done);
937 }
938
939 // 3. Make sure first argument is an object; convert if necessary.
940 // r0: actual number of arguments
941 // r1: function
942 { Label call_to_object, use_global_receiver, patch_receiver, done;
943 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); 941 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
944 __ ldr(r2, MemOperand(r2, -kPointerSize)); 942 __ ldr(r2, MemOperand(r2, -kPointerSize));
945
946 // r0: actual number of arguments 943 // r0: actual number of arguments
947 // r1: function 944 // r1: function
948 // r2: first argument 945 // r2: first argument
949 __ tst(r2, Operand(kSmiTagMask)); 946 __ tst(r2, Operand(kSmiTagMask));
950 __ b(eq, &call_to_object); 947 __ b(eq, &convert_to_object);
951 948
952 __ LoadRoot(r3, Heap::kNullValueRootIndex); 949 __ LoadRoot(r3, Heap::kNullValueRootIndex);
953 __ cmp(r2, r3); 950 __ cmp(r2, r3);
954 __ b(eq, &use_global_receiver); 951 __ b(eq, &use_global_receiver);
955 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); 952 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
956 __ cmp(r2, r3); 953 __ cmp(r2, r3);
957 __ b(eq, &use_global_receiver); 954 __ b(eq, &use_global_receiver);
958 955
959 __ CompareObjectType(r2, r3, r3, FIRST_JS_OBJECT_TYPE); 956 __ CompareObjectType(r2, r3, r3, FIRST_JS_OBJECT_TYPE);
960 __ b(lt, &call_to_object); 957 __ b(lt, &convert_to_object);
961 __ cmp(r3, Operand(LAST_JS_OBJECT_TYPE)); 958 __ cmp(r3, Operand(LAST_JS_OBJECT_TYPE));
962 __ b(le, &done); 959 __ b(le, &shift_arguments);
963 960
964 __ bind(&call_to_object); 961 __ bind(&convert_to_object);
965 __ EnterInternalFrame(); 962 __ EnterInternalFrame(); // In order to preserve argument count.
966 963 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); // Smi-tagged.
967 // Store number of arguments and function across the call into the runtime.
968 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
969 __ push(r0); 964 __ push(r0);
970 __ push(r1);
971 965
972 __ push(r2); 966 __ push(r2);
973 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); 967 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
974 __ mov(r2, r0); 968 __ mov(r2, r0);
975 969
976 // Restore number of arguments and function.
977 __ pop(r1);
978 __ pop(r0); 970 __ pop(r0);
979 __ mov(r0, Operand(r0, ASR, kSmiTagSize)); 971 __ mov(r0, Operand(r0, ASR, kSmiTagSize));
972 __ LeaveInternalFrame();
973 // Restore the function to r1.
974 __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
975 __ jmp(&patch_receiver);
980 976
981 __ LeaveInternalFrame(); 977 // Use the global receiver object from the called function as the
982 __ b(&patch_receiver); 978 // receiver.
983
984 // Use the global receiver object from the called function as the receiver.
985 __ bind(&use_global_receiver); 979 __ bind(&use_global_receiver);
986 const int kGlobalIndex = 980 const int kGlobalIndex =
987 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; 981 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
988 __ ldr(r2, FieldMemOperand(cp, kGlobalIndex)); 982 __ ldr(r2, FieldMemOperand(cp, kGlobalIndex));
989 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalContextOffset)); 983 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalContextOffset));
990 __ ldr(r2, FieldMemOperand(r2, kGlobalIndex)); 984 __ ldr(r2, FieldMemOperand(r2, kGlobalIndex));
991 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); 985 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
992 986
993 __ bind(&patch_receiver); 987 __ bind(&patch_receiver);
994 __ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2)); 988 __ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2));
995 __ str(r2, MemOperand(r3, -kPointerSize)); 989 __ str(r2, MemOperand(r3, -kPointerSize));
996 990
997 __ bind(&done); 991 __ jmp(&shift_arguments);
998 } 992 }
999 993
1000 // 4. Handle non-functions. 994 // 3b. Patch the first argument when calling a non-function. The
1001 // r0: actual number of arguments (including call() receiver) 995 // CALL_NON_FUNCTION builtin expects the non-function callee as
996 // receiver, so overwrite the first argument which will ultimately
997 // become the receiver.
998 // r0: actual number of arguments
1002 // r1: function 999 // r1: function
1003 { Label done; 1000 __ bind(&non_function);
1004 __ tst(r1, r1); 1001 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
1005 __ b(ne, &done); 1002 __ str(r1, MemOperand(r2, -kPointerSize));
1006 __ mov(r2, Operand(0)); // expected arguments is 0 for CALL_NON_FUNCTION 1003 // Clear r1 to indicate a non-function being called.
1007 // Transfer the receiver from the first argument to the top of the 1004 __ mov(r1, Operand(0));
1008 // caller's expression stack simply by decrementing argc.
1009 __ sub(r0, r0, Operand(1));
1010 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
1011 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
1012 RelocInfo::CODE_TARGET);
1013 __ bind(&done);
1014 }
1015 1005
1016 // 5. Shift arguments one slot toward the bottom of the 1006 // 4. Shift arguments and return address one slot down on the stack
1017 // stack, overwriting the receiver. 1007 // (overwriting the original receiver). Adjust argument count to make
1008 // the original first argument the new receiver.
1009 // r0: actual number of arguments
1010 // r1: function
1011 __ bind(&shift_arguments);
1018 { Label loop; 1012 { Label loop;
1019 // Calculate the copy start address (destination). Copy end address is sp. 1013 // Calculate the copy start address (destination). Copy end address is sp.
1020 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); 1014 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
1021 1015
1022 __ bind(&loop); 1016 __ bind(&loop);
1023 __ ldr(ip, MemOperand(r2, -kPointerSize)); 1017 __ ldr(ip, MemOperand(r2, -kPointerSize));
1024 __ str(ip, MemOperand(r2)); 1018 __ str(ip, MemOperand(r2));
1025 __ sub(r2, r2, Operand(kPointerSize)); 1019 __ sub(r2, r2, Operand(kPointerSize));
1026 __ cmp(r2, sp); 1020 __ cmp(r2, sp);
1027 __ b(ne, &loop); 1021 __ b(ne, &loop);
1028 // Adjust the actual number of arguments and remove the top element. 1022 // Adjust the actual number of arguments and remove the top element
1023 // (which is a copy of the last argument).
1029 __ sub(r0, r0, Operand(1)); 1024 __ sub(r0, r0, Operand(1));
1030 __ pop(); 1025 __ pop();
1031 } 1026 }
1032 1027
1033 // 6. Get the code for the function or the non-function builtin. 1028 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
1034 // If number of expected arguments matches, then call. Otherwise restart 1029 // r0: actual number of arguments
1035 // the arguments adaptor stub. 1030 // r1: function
1031 { Label function;
1032 __ tst(r1, r1);
1033 __ b(ne, &function);
1034 __ mov(r2, Operand(0)); // expected arguments is 0 for CALL_NON_FUNCTION
1035 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
1036 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
1037 RelocInfo::CODE_TARGET);
1038 __ bind(&function);
1039 }
1040
1041 // 5b. Get the code to call from the function and check that the number of
1042 // expected arguments matches what we're providing. If so, jump
1043 // (tail-call) to the code in register edx without checking arguments.
1036 // r0: actual number of arguments 1044 // r0: actual number of arguments
1037 // r1: function 1045 // r1: function
1038 __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); 1046 __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
1039 __ ldr(r2, 1047 __ ldr(r2,
1040 FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset)); 1048 FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset));
1041 __ ldr(r3, FieldMemOperand(r3, SharedFunctionInfo::kCodeOffset)); 1049 __ ldr(r3, FieldMemOperand(r3, SharedFunctionInfo::kCodeOffset));
1042 __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); 1050 __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag));
1043 __ cmp(r2, r0); // Check formal and actual parameter counts. 1051 __ cmp(r2, r0); // Check formal and actual parameter counts.
1044 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), 1052 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
1045 RelocInfo::CODE_TARGET, ne); 1053 RelocInfo::CODE_TARGET, ne);
1046 1054
1047 // 7. Jump (tail-call) to the code in r3 without checking arguments.
1048 ParameterCount expected(0); 1055 ParameterCount expected(0);
1049 __ InvokeCode(r3, expected, expected, JUMP_FUNCTION); 1056 __ InvokeCode(r3, expected, expected, JUMP_FUNCTION);
1050 } 1057 }
1051 1058
1052 1059
1053 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { 1060 void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
1054 const int kIndexOffset = -5 * kPointerSize; 1061 const int kIndexOffset = -5 * kPointerSize;
1055 const int kLimitOffset = -4 * kPointerSize; 1062 const int kLimitOffset = -4 * kPointerSize;
1056 const int kArgsOffset = 2 * kPointerSize; 1063 const int kArgsOffset = 2 * kPointerSize;
1057 const int kRecvOffset = 3 * kPointerSize; 1064 const int kRecvOffset = 3 * kPointerSize;
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after
1298 // Dont adapt arguments. 1305 // Dont adapt arguments.
1299 // ------------------------------------------- 1306 // -------------------------------------------
1300 __ bind(&dont_adapt_arguments); 1307 __ bind(&dont_adapt_arguments);
1301 __ Jump(r3); 1308 __ Jump(r3);
1302 } 1309 }
1303 1310
1304 1311
1305 #undef __ 1312 #undef __
1306 1313
1307 } } // namespace v8::internal 1314 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | src/arm/codegen-arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698