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

Side by Side Diff: src/x64/builtins-x64.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/runtime.js ('k') | src/x64/codegen-x64.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 2009 the V8 project authors. All rights reserved. 1 // Copyright 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 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 // ------------------------------------------- 178 // -------------------------------------------
179 // Dont adapt arguments. 179 // Dont adapt arguments.
180 // ------------------------------------------- 180 // -------------------------------------------
181 __ bind(&dont_adapt_arguments); 181 __ bind(&dont_adapt_arguments);
182 __ jmp(rdx); 182 __ jmp(rdx);
183 } 183 }
184 184
185 185
186 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { 186 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
187 // Stack Layout: 187 // Stack Layout:
188 // rsp: return address 188 // rsp[0]: Return address
189 // +1: Argument n 189 // rsp[1]: Argument n
190 // +2: Argument n-1 190 // rsp[2]: Argument n-1
191 // ... 191 // ...
192 // +n: Argument 1 = receiver 192 // rsp[n]: Argument 1
193 // +n+1: Argument 0 = function to call 193 // rsp[n+1]: Receiver (function to call)
194 // 194 //
195 // rax contains the number of arguments, n, not counting the function. 195 // rax contains the number of arguments, n, not counting the receiver.
196 // 196 //
197 // 1. Make sure we have at least one argument. 197 // 1. Make sure we have at least one argument.
198 { Label done; 198 { Label done;
199 __ testq(rax, rax); 199 __ testq(rax, rax);
200 __ j(not_zero, &done); 200 __ j(not_zero, &done);
201 __ pop(rbx); 201 __ pop(rbx);
202 __ Push(Factory::undefined_value()); 202 __ Push(Factory::undefined_value());
203 __ push(rbx); 203 __ push(rbx);
204 __ incq(rax); 204 __ incq(rax);
205 __ bind(&done); 205 __ bind(&done);
206 } 206 }
207 207
208 // 2. Get the function to call from the stack. 208 // 2. Get the function to call (passed as receiver) from the stack, check
209 { Label done, non_function, function; 209 // if it is a function.
210 Label non_function;
211 { Label function;
210 // The function to call is at position n+1 on the stack. 212 // The function to call is at position n+1 on the stack.
211 __ movq(rdi, Operand(rsp, rax, times_pointer_size, +1 * kPointerSize)); 213 __ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize));
212 __ JumpIfSmi(rdi, &non_function); 214 __ JumpIfSmi(rdi, &non_function);
213 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); 215 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
214 __ j(equal, &function); 216 __ j(not_equal, &non_function);
217 __ bind(&function);
218 }
215 219
216 // Non-function called: Clear the function to force exception. 220 // 3a. Patch the first argument if necessary when calling a function.
217 __ bind(&non_function); 221 Label shift_arguments;
218 __ xor_(rdi, rdi); 222 { Label convert_to_object, use_global_receiver, patch_receiver;
219 __ jmp(&done); 223 // Change context eagerly in case we need the global receiver.
220
221 // Function called: Change context eagerly to get the right global object.
222 __ bind(&function);
223 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); 224 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
224 225
225 __ bind(&done);
226 }
227
228 // 3. Make sure first argument is an object; convert if necessary.
229 { Label call_to_object, use_global_receiver, patch_receiver, done;
230 __ movq(rbx, Operand(rsp, rax, times_pointer_size, 0)); 226 __ movq(rbx, Operand(rsp, rax, times_pointer_size, 0));
231 227 __ JumpIfSmi(rbx, &convert_to_object);
232 __ JumpIfSmi(rbx, &call_to_object);
233 228
234 __ CompareRoot(rbx, Heap::kNullValueRootIndex); 229 __ CompareRoot(rbx, Heap::kNullValueRootIndex);
235 __ j(equal, &use_global_receiver); 230 __ j(equal, &use_global_receiver);
236 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); 231 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
237 __ j(equal, &use_global_receiver); 232 __ j(equal, &use_global_receiver);
238 233
239 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx); 234 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx);
240 __ j(below, &call_to_object); 235 __ j(below, &convert_to_object);
241 __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE); 236 __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE);
242 __ j(below_equal, &done); 237 __ j(below_equal, &shift_arguments);
243 238
244 __ bind(&call_to_object); 239 __ bind(&convert_to_object);
245 __ EnterInternalFrame(); // preserves rax, rbx, rdi 240 __ EnterInternalFrame(); // In order to preserve argument count.
246
247 // Store the arguments count on the stack (smi tagged).
248 __ Integer32ToSmi(rax, rax); 241 __ Integer32ToSmi(rax, rax);
249 __ push(rax); 242 __ push(rax);
250 243
251 __ push(rdi); // save edi across the call
252 __ push(rbx); 244 __ push(rbx);
253 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 245 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
254 __ movq(rbx, rax); 246 __ movq(rbx, rax);
255 __ pop(rdi); // restore edi after the call
256 247
257 // Get the arguments count and untag it.
258 __ pop(rax); 248 __ pop(rax);
259 __ SmiToInteger32(rax, rax); 249 __ SmiToInteger32(rax, rax);
260
261 __ LeaveInternalFrame(); 250 __ LeaveInternalFrame();
251 // Restore the function to rdi.
252 __ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize));
262 __ jmp(&patch_receiver); 253 __ jmp(&patch_receiver);
263 254
264 // Use the global receiver object from the called function as the receiver. 255 // Use the global receiver object from the called function as the
256 // receiver.
265 __ bind(&use_global_receiver); 257 __ bind(&use_global_receiver);
266 const int kGlobalIndex = 258 const int kGlobalIndex =
267 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; 259 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
268 __ movq(rbx, FieldOperand(rsi, kGlobalIndex)); 260 __ movq(rbx, FieldOperand(rsi, kGlobalIndex));
269 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalContextOffset)); 261 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalContextOffset));
270 __ movq(rbx, FieldOperand(rbx, kGlobalIndex)); 262 __ movq(rbx, FieldOperand(rbx, kGlobalIndex));
271 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); 263 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
272 264
273 __ bind(&patch_receiver); 265 __ bind(&patch_receiver);
274 __ movq(Operand(rsp, rax, times_pointer_size, 0), rbx); 266 __ movq(Operand(rsp, rax, times_pointer_size, 0), rbx);
275 267
276 __ bind(&done); 268 __ jmp(&shift_arguments);
277 } 269 }
278 270
279 // 4. Check that the function really is a function.
280 { Label real_function;
281 __ testq(rdi, rdi);
282 __ j(not_zero, &real_function);
283 __ xor_(rbx, rbx);
284 // CALL_NON_FUNCTION will expect to find the non-function callee on the
285 // expression stack of the caller. Transfer it from receiver to the
286 // caller's expression stack (and make the first argument the receiver
287 // for CALL_NON_FUNCTION) by decrementing the argument count.
288 __ decq(rax);
289 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
290 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
291 RelocInfo::CODE_TARGET);
292 271
293 __ bind(&real_function); 272 // 3b. Patch the first argument when calling a non-function. The
294 } 273 // CALL_NON_FUNCTION builtin expects the non-function callee as
274 // receiver, so overwrite the first argument which will ultimately
275 // become the receiver.
276 __ bind(&non_function);
277 __ movq(Operand(rsp, rax, times_pointer_size, 0), rdi);
278 __ xor_(rdi, rdi);
295 279
296 // 5. Shift arguments and return address one slot down on the stack 280 // 4. Shift arguments and return address one slot down on the stack
297 // (overwriting the receiver). 281 // (overwriting the original receiver). Adjust argument count to make
282 // the original first argument the new receiver.
283 __ bind(&shift_arguments);
298 { Label loop; 284 { Label loop;
299 __ movq(rcx, rax); 285 __ movq(rcx, rax);
300 __ bind(&loop); 286 __ bind(&loop);
301 __ movq(rbx, Operand(rsp, rcx, times_pointer_size, 0)); 287 __ movq(rbx, Operand(rsp, rcx, times_pointer_size, 0));
302 __ movq(Operand(rsp, rcx, times_pointer_size, 1 * kPointerSize), rbx); 288 __ movq(Operand(rsp, rcx, times_pointer_size, 1 * kPointerSize), rbx);
303 __ decq(rcx); 289 __ decq(rcx);
304 __ j(not_sign, &loop); 290 __ j(not_sign, &loop); // While non-negative (to copy return address).
305 __ pop(rbx); // Discard copy of return address. 291 __ pop(rbx); // Discard copy of return address.
306 __ decq(rax); // One fewer argument (first argument is new receiver). 292 __ decq(rax); // One fewer argument (first argument is new receiver).
307 } 293 }
308 294
309 // 6. Get the code to call from the function and check that the number of 295 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
310 // expected arguments matches what we're providing. 296 { Label function;
297 __ testq(rdi, rdi);
298 __ j(not_zero, &function);
299 __ xor_(rbx, rbx);
300 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
301 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
302 RelocInfo::CODE_TARGET);
303 __ bind(&function);
304 }
305
306 // 5b. Get the code to call from the function and check that the number of
307 // expected arguments matches what we're providing. If so, jump
308 // (tail-call) to the code in register edx without checking arguments.
311 __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); 309 __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
312 __ movsxlq(rbx, 310 __ movsxlq(rbx,
313 FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset)); 311 FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset));
314 __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset)); 312 __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset));
315 __ lea(rdx, FieldOperand(rdx, Code::kHeaderSize)); 313 __ lea(rdx, FieldOperand(rdx, Code::kHeaderSize));
316 __ cmpq(rax, rbx); 314 __ cmpq(rax, rbx);
317 __ j(not_equal, 315 __ j(not_equal,
318 Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), 316 Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
319 RelocInfo::CODE_TARGET); 317 RelocInfo::CODE_TARGET);
320 318
321 // 7. Jump (tail-call) to the code in register edx without checking arguments.
322 ParameterCount expected(0); 319 ParameterCount expected(0);
323 __ InvokeCode(rdx, expected, expected, JUMP_FUNCTION); 320 __ InvokeCode(rdx, expected, expected, JUMP_FUNCTION);
324 } 321 }
325 322
326 323
327 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { 324 void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
328 // Stack at entry: 325 // Stack at entry:
329 // rsp: return address 326 // rsp: return address
330 // rsp+8: arguments 327 // rsp+8: arguments
331 // rsp+16: receiver ("this") 328 // rsp+16: receiver ("this")
(...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after
898 895
899 // Jump to the function-specific construct stub. 896 // Jump to the function-specific construct stub.
900 __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); 897 __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
901 __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kConstructStubOffset)); 898 __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kConstructStubOffset));
902 __ lea(rbx, FieldOperand(rbx, Code::kHeaderSize)); 899 __ lea(rbx, FieldOperand(rbx, Code::kHeaderSize));
903 __ jmp(rbx); 900 __ jmp(rbx);
904 901
905 // edi: called object 902 // edi: called object
906 // eax: number of arguments 903 // eax: number of arguments
907 __ bind(&non_function_call); 904 __ bind(&non_function_call);
908 // Set expected number of arguments to zero (not changing eax). 905 // CALL_NON_FUNCTION expects the non-function constructor as receiver
906 // (instead of the original receiver from the call site). The receiver is
907 // stack element argc+1.
908 __ movq(Operand(rsp, rax, times_pointer_size, kPointerSize), rdi);
909 // Set expected number of arguments to zero (not changing rax).
909 __ movq(rbx, Immediate(0)); 910 __ movq(rbx, Immediate(0));
910 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); 911 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
911 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), 912 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
912 RelocInfo::CODE_TARGET); 913 RelocInfo::CODE_TARGET);
913 } 914 }
914 915
915 916
916 static void Generate_JSConstructStubHelper(MacroAssembler* masm, 917 static void Generate_JSConstructStubHelper(MacroAssembler* masm,
917 bool is_api_function) { 918 bool is_api_function) {
918 // Enter a construct frame. 919 // Enter a construct frame.
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after
1291 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { 1292 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
1292 Generate_JSEntryTrampolineHelper(masm, false); 1293 Generate_JSEntryTrampolineHelper(masm, false);
1293 } 1294 }
1294 1295
1295 1296
1296 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { 1297 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
1297 Generate_JSEntryTrampolineHelper(masm, true); 1298 Generate_JSEntryTrampolineHelper(masm, true);
1298 } 1299 }
1299 1300
1300 } } // namespace v8::internal 1301 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/runtime.js ('k') | src/x64/codegen-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698