Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 46 // Store the arguments adaptor context sentinel. | 46 // Store the arguments adaptor context sentinel. |
| 47 __ push(Immediate(ArgumentsAdaptorFrame::SENTINEL)); | 47 __ push(Immediate(ArgumentsAdaptorFrame::SENTINEL)); |
| 48 | 48 |
| 49 // Push the function on the stack. | 49 // Push the function on the stack. |
| 50 __ push(rdi); | 50 __ push(rdi); |
| 51 | 51 |
| 52 // Preserve the number of arguments on the stack. Must preserve both | 52 // Preserve the number of arguments on the stack. Must preserve both |
| 53 // eax and ebx because these registers are used when copying the | 53 // eax and ebx because these registers are used when copying the |
| 54 // arguments and the receiver. | 54 // arguments and the receiver. |
| 55 ASSERT(kSmiTagSize == 1); | 55 ASSERT(kSmiTagSize == 1); |
| 56 __ lea(rcx, Operand(rax, rax, kTimes1, kSmiTag)); | 56 __ lea(rcx, Operand(rax, rax, times_1, kSmiTag)); |
| 57 __ push(rcx); | 57 __ push(rcx); |
| 58 } | 58 } |
| 59 | 59 |
| 60 | 60 |
| 61 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { | 61 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { |
| 62 // Retrieve the number of arguments from the stack. Number is a Smi. | 62 // Retrieve the number of arguments from the stack. Number is a Smi. |
| 63 __ movq(rbx, Operand(rbp, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 63 __ movq(rbx, Operand(rbp, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 64 | 64 |
| 65 // Leave the frame. | 65 // Leave the frame. |
| 66 __ movq(rsp, rbp); | 66 __ movq(rsp, rbp); |
| 67 __ pop(rbp); | 67 __ pop(rbp); |
| 68 | 68 |
| 69 // Remove caller arguments from the stack. | 69 // Remove caller arguments from the stack. |
| 70 // rbx holds a Smi, so we convery to dword offset by multiplying by 4. | 70 // rbx holds a Smi, so we convery to dword offset by multiplying by 4. |
| 71 ASSERT_EQ(kSmiTagSize, 1 && kSmiTag == 0); | 71 ASSERT_EQ(kSmiTagSize, 1 && kSmiTag == 0); |
| 72 ASSERT_EQ(kPointerSize, (1 << kSmiTagSize) * 4); | 72 ASSERT_EQ(kPointerSize, (1 << kSmiTagSize) * 4); |
| 73 __ pop(rcx); | 73 __ pop(rcx); |
| 74 __ lea(rsp, Operand(rsp, rbx, kTimes4, 1 * kPointerSize)); // 1 ~ receiver | 74 __ lea(rsp, Operand(rsp, rbx, times_4, 1 * kPointerSize)); // 1 ~ receiver |
| 75 __ push(rcx); | 75 __ push(rcx); |
| 76 } | 76 } |
| 77 | 77 |
| 78 | 78 |
| 79 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { | 79 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { |
| 80 // ----------- S t a t e ------------- | 80 // ----------- S t a t e ------------- |
| 81 // -- rax : actual number of arguments | 81 // -- rax : actual number of arguments |
| 82 // -- rbx : expected number of arguments | 82 // -- rbx : expected number of arguments |
| 83 // -- rdx : code entry to call | 83 // -- rdx : code entry to call |
| 84 // ----------------------------------- | 84 // ----------------------------------- |
| 85 | 85 |
| 86 Label invoke, dont_adapt_arguments; | 86 Label invoke, dont_adapt_arguments; |
| 87 __ IncrementCounter(&Counters::arguments_adaptors, 1); | 87 __ IncrementCounter(&Counters::arguments_adaptors, 1); |
| 88 | 88 |
| 89 Label enough, too_few; | 89 Label enough, too_few; |
| 90 __ cmpq(rax, rbx); | 90 __ cmpq(rax, rbx); |
| 91 __ j(less, &too_few); | 91 __ j(less, &too_few); |
| 92 __ cmpq(rbx, Immediate(SharedFunctionInfo::kDontAdaptArgumentsSentinel)); | 92 __ cmpq(rbx, Immediate(SharedFunctionInfo::kDontAdaptArgumentsSentinel)); |
| 93 __ j(equal, &dont_adapt_arguments); | 93 __ j(equal, &dont_adapt_arguments); |
| 94 | 94 |
| 95 { // Enough parameters: Actual >= expected. | 95 { // Enough parameters: Actual >= expected. |
| 96 __ bind(&enough); | 96 __ bind(&enough); |
| 97 EnterArgumentsAdaptorFrame(masm); | 97 EnterArgumentsAdaptorFrame(masm); |
| 98 | 98 |
| 99 // Copy receiver and all expected arguments. | 99 // Copy receiver and all expected arguments. |
| 100 const int offset = StandardFrameConstants::kCallerSPOffset; | 100 const int offset = StandardFrameConstants::kCallerSPOffset; |
| 101 __ lea(rax, Operand(rbp, rax, kTimesPointerSize, offset)); | 101 __ lea(rax, Operand(rbp, rax, times_pointer_size, offset)); |
| 102 __ movq(rcx, Immediate(-1)); // account for receiver | 102 __ movq(rcx, Immediate(-1)); // account for receiver |
| 103 | 103 |
| 104 Label copy; | 104 Label copy; |
| 105 __ bind(©); | 105 __ bind(©); |
| 106 __ incq(rcx); | 106 __ incq(rcx); |
| 107 __ push(Operand(rax, 0)); | 107 __ push(Operand(rax, 0)); |
| 108 __ subq(rax, Immediate(kPointerSize)); | 108 __ subq(rax, Immediate(kPointerSize)); |
| 109 __ cmpq(rcx, rbx); | 109 __ cmpq(rcx, rbx); |
| 110 __ j(less, ©); | 110 __ j(less, ©); |
| 111 __ jmp(&invoke); | 111 __ jmp(&invoke); |
| 112 } | 112 } |
| 113 | 113 |
| 114 { // Too few parameters: Actual < expected. | 114 { // Too few parameters: Actual < expected. |
| 115 __ bind(&too_few); | 115 __ bind(&too_few); |
| 116 EnterArgumentsAdaptorFrame(masm); | 116 EnterArgumentsAdaptorFrame(masm); |
| 117 | 117 |
| 118 // Copy receiver and all actual arguments. | 118 // Copy receiver and all actual arguments. |
| 119 const int offset = StandardFrameConstants::kCallerSPOffset; | 119 const int offset = StandardFrameConstants::kCallerSPOffset; |
| 120 __ lea(rdi, Operand(rbp, rax, kTimesPointerSize, offset)); | 120 __ lea(rdi, Operand(rbp, rax, times_pointer_size, offset)); |
| 121 __ movq(rcx, Immediate(-1)); // account for receiver | 121 __ movq(rcx, Immediate(-1)); // account for receiver |
| 122 | 122 |
| 123 Label copy; | 123 Label copy; |
| 124 __ bind(©); | 124 __ bind(©); |
| 125 __ incq(rcx); | 125 __ incq(rcx); |
| 126 __ push(Operand(rdi, 0)); | 126 __ push(Operand(rdi, 0)); |
| 127 __ subq(rdi, Immediate(kPointerSize)); | 127 __ subq(rdi, Immediate(kPointerSize)); |
| 128 __ cmpq(rcx, rax); | 128 __ cmpq(rcx, rax); |
| 129 __ j(less, ©); | 129 __ j(less, ©); |
| 130 | 130 |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 160 | 160 |
| 161 | 161 |
| 162 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { | 162 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
| 163 masm->int3(); // UNIMPLEMENTED. | 163 masm->int3(); // UNIMPLEMENTED. |
| 164 } | 164 } |
| 165 | 165 |
| 166 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { | 166 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { |
| 167 masm->int3(); // UNIMPLEMENTED. | 167 masm->int3(); // UNIMPLEMENTED. |
| 168 } | 168 } |
| 169 | 169 |
| 170 | |
| 170 void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { | 171 void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { |
| 171 masm->int3(); // UNIMPLEMENTED. | 172 // ----------- S t a t e ------------- |
| 173 // -- rax: number of arguments | |
| 174 // -- rdi: constructor function | |
| 175 // ----------------------------------- | |
| 176 | |
| 177 Label non_function_call; | |
| 178 // Check that function is not a smi. | |
| 179 __ testl(rdi, Immediate(kSmiTagMask)); | |
| 180 __ j(zero, &non_function_call); | |
| 181 // Check that function is a JSFunction. | |
| 182 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); | |
| 183 __ j(not_equal, &non_function_call); | |
| 184 | |
| 185 // Jump to the function-specific construct stub. | |
| 186 __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); | |
| 187 __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kConstructStubOffset)); | |
| 188 __ lea(rbx, FieldOperand(rbx, Code::kHeaderSize)); | |
| 189 __ jmp(rbx); | |
| 190 | |
| 191 // edi: called object | |
| 192 // eax: number of arguments | |
| 193 __ bind(&non_function_call); | |
| 194 | |
| 195 // Set expected number of arguments to zero (not changing eax). | |
| 196 __ movq(rbx, Immediate(0)); | |
| 197 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); | |
| 198 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), | |
| 199 RelocInfo::CODE_TARGET); | |
| 172 } | 200 } |
| 173 | 201 |
| 202 | |
| 174 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { | 203 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { |
| 175 masm->int3(); // UNIMPLEMENTED. | 204 // Enter a construct frame. |
| 205 __ EnterConstructFrame(); | |
|
William Hesse
2009/06/24 07:55:57
What is the calling convention of this function on
Mads Ager (chromium)
2009/06/24 08:18:50
rax: number of arguments
rdi: constructor function
| |
| 206 | |
| 207 // Store a smi-tagged arguments count on the stack. | |
| 208 __ shl(rax, Immediate(kSmiTagSize)); | |
| 209 __ push(rax); | |
| 210 | |
| 211 // Push the function to invoke on the stack. | |
| 212 __ push(rdi); | |
| 213 | |
| 214 // Try to allocate the object without transitioning into C code. If any of the | |
| 215 // preconditions is not met, the code bails out to the runtime call. | |
| 216 Label rt_call, allocated; | |
| 217 | |
| 218 // TODO(x64): Implement inlined allocation. | |
| 219 | |
| 220 // Allocate the new receiver object using the runtime call. | |
| 221 // rdi: function (constructor) | |
| 222 __ bind(&rt_call); | |
| 223 // Must restore edi (constructor) before calling runtime. | |
| 224 __ movq(rdi, Operand(rsp, 0)); | |
| 225 __ push(rdi); | |
| 226 __ CallRuntime(Runtime::kNewObject, 1); | |
| 227 __ movq(rbx, rax); // store result in ebx | |
|
William Hesse
2009/06/24 07:55:57
rbx, not ebx
Mads Ager (chromium)
2009/06/24 08:18:50
Done.
| |
| 228 | |
| 229 // New object allocated. | |
| 230 // ebx: newly allocated object | |
|
William Hesse
2009/06/24 07:55:57
rbx
Mads Ager (chromium)
2009/06/24 08:18:50
Done.
| |
| 231 __ bind(&allocated); | |
| 232 // Retrieve the function from the stack. | |
| 233 __ pop(rdi); | |
| 234 | |
| 235 // Retrieve smi-tagged arguments count from the stack. | |
| 236 __ movq(rax, Operand(rsp, 0)); | |
| 237 __ shr(rax, Immediate(kSmiTagSize)); | |
| 238 | |
| 239 // Push the allocated receiver to the stack. We need two copies | |
| 240 // because we may have to return the original one and the calling | |
| 241 // conventions dictate that the called function pops the receiver. | |
| 242 __ push(rbx); | |
| 243 __ push(rbx); | |
| 244 | |
| 245 // Setup pointer to last argument. | |
| 246 __ lea(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset)); | |
| 247 | |
| 248 // Copy arguments and receiver to the expression stack. | |
| 249 Label loop, entry; | |
| 250 __ movq(rcx, rax); | |
| 251 __ jmp(&entry); | |
| 252 __ bind(&loop); | |
| 253 __ push(Operand(rbx, rcx, times_pointer_size, 0)); | |
|
William Hesse
2009/06/24 07:55:57
Isn't there a three-argument version of Operand(Re
Mads Ager (chromium)
2009/06/24 08:18:50
There isn't no, and I'm not sure it adds much to h
| |
| 254 __ bind(&entry); | |
| 255 __ decq(rcx); | |
| 256 __ j(greater_equal, &loop); | |
| 257 | |
| 258 // Call the function. | |
| 259 ParameterCount actual(rax); | |
| 260 __ InvokeFunction(rdi, actual, CALL_FUNCTION); | |
| 261 | |
| 262 // Restore context from the frame. | |
| 263 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | |
| 264 | |
| 265 // If the result is an object (in the ECMA sense), we should get rid | |
| 266 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 | |
| 267 // on page 74. | |
| 268 Label use_receiver, exit; | |
| 269 // If the result is a smi, it is *not* an object in the ECMA sense. | |
| 270 __ testl(rax, Immediate(kSmiTagMask)); | |
| 271 __ j(zero, &use_receiver); | |
| 272 | |
| 273 // If the type of the result (stored in its map) is less than | |
| 274 // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense. | |
| 275 __ movq(rcx, FieldOperand(rax, HeapObject::kMapOffset)); | |
| 276 __ CmpInstanceType(rcx, FIRST_JS_OBJECT_TYPE); | |
|
William Hesse
2009/06/24 07:55:57
CmpInstanceType can now be written inline as a sin
Mads Ager (chromium)
2009/06/24 08:18:50
CmpInstanceType does the one instruction compare.
| |
| 277 __ j(greater_equal, &exit); | |
| 278 | |
| 279 // Throw away the result of the constructor invocation and use the | |
| 280 // on-stack receiver as the result. | |
| 281 __ bind(&use_receiver); | |
| 282 __ movq(rax, Operand(rsp, 0)); | |
| 283 | |
| 284 // Restore the arguments count and leave the construct frame. | |
| 285 __ bind(&exit); | |
| 286 __ movq(rbx, Operand(rsp, kPointerSize)); // get arguments count | |
| 287 __ LeaveConstructFrame(); | |
| 288 | |
| 289 // Remove caller arguments from the stack and return. | |
| 290 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | |
| 291 __ pop(rcx); | |
| 292 __ lea(rsp, Operand(rsp, rbx, times_4, 1 * kPointerSize)); // 1 ~ receiver | |
| 293 __ push(rcx); | |
| 294 __ ret(0); | |
| 176 } | 295 } |
| 177 | 296 |
| 297 | |
| 178 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, | 298 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, |
| 179 bool is_construct) { | 299 bool is_construct) { |
| 180 // Expects five C++ function parameters. | 300 // Expects five C++ function parameters. |
| 181 // - Address entry (ignored) | 301 // - Address entry (ignored) |
| 182 // - JSFunction* function ( | 302 // - JSFunction* function ( |
| 183 // - Object* receiver | 303 // - Object* receiver |
| 184 // - int argc | 304 // - int argc |
| 185 // - Object*** argv | 305 // - Object*** argv |
| 186 // (see Handle::Invoke in execution.cc). | 306 // (see Handle::Invoke in execution.cc). |
| 187 | 307 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 251 // rsi : context | 371 // rsi : context |
| 252 // rdi : function | 372 // rdi : function |
| 253 | 373 |
| 254 // Copy arguments to the stack in a loop. | 374 // Copy arguments to the stack in a loop. |
| 255 // Register rbx points to array of pointers to handle locations. | 375 // Register rbx points to array of pointers to handle locations. |
| 256 // Push the values of these handles. | 376 // Push the values of these handles. |
| 257 Label loop, entry; | 377 Label loop, entry; |
| 258 __ xor_(rcx, rcx); // Set loop variable to 0. | 378 __ xor_(rcx, rcx); // Set loop variable to 0. |
| 259 __ jmp(&entry); | 379 __ jmp(&entry); |
| 260 __ bind(&loop); | 380 __ bind(&loop); |
| 261 __ movq(kScratchRegister, Operand(rbx, rcx, kTimesPointerSize, 0)); | 381 __ movq(kScratchRegister, Operand(rbx, rcx, times_pointer_size, 0)); |
| 262 __ push(Operand(kScratchRegister, 0)); // dereference handle | 382 __ push(Operand(kScratchRegister, 0)); // dereference handle |
| 263 __ addq(rcx, Immediate(1)); | 383 __ addq(rcx, Immediate(1)); |
| 264 __ bind(&entry); | 384 __ bind(&entry); |
| 265 __ cmpq(rcx, rax); | 385 __ cmpq(rcx, rax); |
| 266 __ j(not_equal, &loop); | 386 __ j(not_equal, &loop); |
| 267 | 387 |
| 268 // Invoke the code. | 388 // Invoke the code. |
| 269 if (is_construct) { | 389 if (is_construct) { |
| 270 // Expects rdi to hold function pointer. | 390 // Expects rdi to hold function pointer. |
| 271 __ movq(kScratchRegister, | 391 __ movq(kScratchRegister, |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 290 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { | 410 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { |
| 291 Generate_JSEntryTrampolineHelper(masm, false); | 411 Generate_JSEntryTrampolineHelper(masm, false); |
| 292 } | 412 } |
| 293 | 413 |
| 294 | 414 |
| 295 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { | 415 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { |
| 296 Generate_JSEntryTrampolineHelper(masm, true); | 416 Generate_JSEntryTrampolineHelper(masm, true); |
| 297 } | 417 } |
| 298 | 418 |
| 299 } } // namespace v8::internal | 419 } } // namespace v8::internal |
| OLD | NEW |