OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 25 matching lines...) Expand all Loading... |
36 | 36 |
37 #define __ masm-> | 37 #define __ masm-> |
38 | 38 |
39 | 39 |
40 void Builtins::Generate_Adaptor(MacroAssembler* masm, | 40 void Builtins::Generate_Adaptor(MacroAssembler* masm, |
41 int argc, | 41 int argc, |
42 CFunctionId id) { | 42 CFunctionId id) { |
43 // r0 contains the number of arguments excluding the receiver. | 43 // r0 contains the number of arguments excluding the receiver. |
44 // JumpToBuiltin expects r0 to contains the number of arguments | 44 // JumpToBuiltin expects r0 to contains the number of arguments |
45 // including the receiver. | 45 // including the receiver. |
46 __ add(r0, r0, Operand(1)); | 46 __ mov(r0, Operand(argc + 1)); |
| 47 __ mov(ip, Operand(ExternalReference::builtin_passed_function())); |
| 48 __ str(r1, MemOperand(ip, 0)); |
47 __ JumpToBuiltin(ExternalReference(id)); | 49 __ JumpToBuiltin(ExternalReference(id)); |
48 } | 50 } |
49 | 51 |
50 | 52 |
51 void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { | 53 void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { |
52 // r0: number of arguments | 54 // ----------- S t a t e ------------- |
| 55 // -- r0 : number of arguments |
| 56 // -- r1 : constructor function |
| 57 // -- lr : return address |
| 58 // -- sp[...]: constructor arguments |
| 59 // ----------------------------------- |
53 | 60 |
54 __ EnterJSFrame(0); | 61 // Enter an internal frame. |
| 62 __ EnterInternalFrame(); |
| 63 |
| 64 // Preserve the two incoming parameters |
| 65 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); |
| 66 __ push(r0); // smi-tagged arguments count |
| 67 __ push(r1); // constructor function |
55 | 68 |
56 // Allocate the new receiver object. | 69 // Allocate the new receiver object. |
57 __ ldr(r0, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset)); | 70 __ push(r1); // argument for Runtime_NewObject |
58 __ push(r0); | |
59 __ CallRuntime(Runtime::kNewObject, 1); | 71 __ CallRuntime(Runtime::kNewObject, 1); |
60 __ push(r0); // save the receiver | 72 __ push(r0); // save the receiver |
61 | 73 |
62 // Push the function and the allocated receiver from the stack. | 74 // Push the function and the allocated receiver from the stack. |
63 __ ldr(r1, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset)); | 75 // sp[0]: receiver (newly allocated object) |
| 76 // sp[1]: constructor function |
| 77 // sp[2]: number of arguments (smi-tagged) |
| 78 __ ldr(r1, MemOperand(sp, kPointerSize)); |
64 __ push(r1); // function | 79 __ push(r1); // function |
65 __ push(r0); // receiver | 80 __ push(r0); // receiver |
66 | 81 |
67 // Restore the arguments length from the stack. | 82 // Reload the number of arguments from the stack. |
68 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset)); | 83 // r1: constructor function |
| 84 // sp[0]: receiver |
| 85 // sp[1]: constructor function |
| 86 // sp[2]: receiver |
| 87 // sp[3]: constructor function |
| 88 // sp[4]: number of arguments (smi-tagged) |
| 89 __ ldr(r3, MemOperand(sp, 4 * kPointerSize)); |
69 | 90 |
70 // Setup pointer to last argument - receiver is not counted. | 91 // Setup pointer to last argument. |
71 __ sub(r2, pp, Operand(r0, LSL, kPointerSizeLog2)); | 92 __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset)); |
72 __ sub(r2, r2, Operand(kPointerSize)); | 93 |
| 94 // Setup number of arguments for function call below |
| 95 __ mov(r0, Operand(r3, LSR, kSmiTagSize)); |
73 | 96 |
74 // Copy arguments and receiver to the expression stack. | 97 // Copy arguments and receiver to the expression stack. |
| 98 // r0: number of arguments |
| 99 // r2: address of last argument (caller sp) |
| 100 // r1: constructor function |
| 101 // r3: number of arguments (smi-tagged) |
| 102 // sp[0]: receiver |
| 103 // sp[1]: constructor function |
| 104 // sp[2]: receiver |
| 105 // sp[3]: constructor function |
| 106 // sp[4]: number of arguments (smi-tagged) |
75 Label loop, entry; | 107 Label loop, entry; |
76 __ mov(r1, Operand(r0)); | |
77 __ b(&entry); | 108 __ b(&entry); |
78 __ bind(&loop); | 109 __ bind(&loop); |
79 __ ldr(r3, MemOperand(r2, r1, LSL, kPointerSizeLog2)); | 110 __ ldr(ip, MemOperand(r2, r3, LSL, kPointerSizeLog2 - 1)); |
80 __ push(r3); | 111 __ push(ip); |
81 __ bind(&entry); | 112 __ bind(&entry); |
82 __ sub(r1, r1, Operand(1), SetCC); | 113 __ sub(r3, r3, Operand(2), SetCC); |
83 __ b(ge, &loop); | 114 __ b(ge, &loop); |
84 | 115 |
85 // Get the function to call from the stack. | |
86 __ ldr(r1, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset)); | |
87 | |
88 // Call the function. | 116 // Call the function. |
| 117 // r0: number of arguments |
| 118 // r1: constructor function |
89 Label return_site; | 119 Label return_site; |
90 __ RecordPosition(position); | 120 __ RecordPosition(position); |
91 ParameterCount actual(r0); | 121 ParameterCount actual(r0); |
92 __ InvokeFunction(r1, actual, CALL_FUNCTION); | 122 __ InvokeFunction(r1, actual, CALL_FUNCTION); |
93 __ bind(&return_site); | 123 __ bind(&return_site); |
94 | 124 |
95 // Restore context from the frame and discard the function. | 125 // Pop the function from the stack. |
| 126 // sp[0]: constructor function |
| 127 // sp[2]: receiver |
| 128 // sp[3]: constructor function |
| 129 // sp[4]: number of arguments (smi-tagged) |
| 130 __ pop(); |
| 131 |
| 132 // Restore context from the frame. |
| 133 // r0: result |
| 134 // sp[0]: receiver |
| 135 // sp[1]: constructor function |
| 136 // sp[2]: number of arguments (smi-tagged) |
96 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 137 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
97 __ pop(); | |
98 | 138 |
99 // If the result is an object (in the ECMA sense), we should get rid | 139 // If the result is an object (in the ECMA sense), we should get rid |
100 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 | 140 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 |
101 // on page 74. | 141 // on page 74. |
102 Label use_receiver, exit; | 142 Label use_receiver, exit; |
103 | 143 |
104 // If the result is a smi, it is *not* an object in the ECMA sense. | 144 // If the result is a smi, it is *not* an object in the ECMA sense. |
| 145 // r0: result |
| 146 // sp[0]: receiver (newly allocated object) |
| 147 // sp[1]: constructor function |
| 148 // sp[2]: number of arguments (smi-tagged) |
105 __ tst(r0, Operand(kSmiTagMask)); | 149 __ tst(r0, Operand(kSmiTagMask)); |
106 __ b(eq, &use_receiver); | 150 __ b(eq, &use_receiver); |
107 | 151 |
108 // If the type of the result (stored in its map) is less than | 152 // If the type of the result (stored in its map) is less than |
109 // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense. | 153 // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense. |
110 __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); | 154 __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset)); |
111 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | 155 __ ldrb(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset)); |
112 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE)); | 156 __ cmp(r3, Operand(FIRST_JS_OBJECT_TYPE)); |
113 __ b(ge, &exit); | 157 __ b(ge, &exit); |
114 | 158 |
115 // Throw away the result of the constructor invocation and use the | 159 // Throw away the result of the constructor invocation and use the |
116 // on-stack receiver as the result. | 160 // on-stack receiver as the result. |
117 __ bind(&use_receiver); | 161 __ bind(&use_receiver); |
118 __ ldr(r0, MemOperand(sp)); | 162 __ ldr(r0, MemOperand(sp)); |
119 | 163 |
120 // Remove receiver from the stack, remove caller arguments, and | 164 // Remove receiver from the stack, remove caller arguments, and |
121 // return. | 165 // return. |
122 __ bind(&exit); | 166 __ bind(&exit); |
123 __ ExitJSFrame(RETURN); | 167 // r0: result |
| 168 // sp[0]: receiver (newly allocated object) |
| 169 // sp[1]: constructor function |
| 170 // sp[2]: number of arguments (smi-tagged) |
| 171 __ ldr(r1, MemOperand(sp, 2 * kPointerSize)); |
| 172 __ ExitInternalFrame(); |
| 173 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1)); |
| 174 __ add(sp, sp, Operand(kPointerSize)); |
| 175 __ mov(pc, Operand(lr)); |
124 | 176 |
125 // Compute the offset from the beginning of the JSConstructCall | 177 // Compute the offset from the beginning of the JSConstructCall |
126 // builtin code object to the return address after the call. | 178 // builtin code object to the return address after the call. |
127 ASSERT(return_site.is_bound()); | 179 ASSERT(return_site.is_bound()); |
128 construct_call_pc_offset_ = return_site.pos() + Code::kHeaderSize; | 180 construct_call_pc_offset_ = return_site.pos() + Code::kHeaderSize; |
129 } | 181 } |
130 | 182 |
131 | 183 |
132 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, | 184 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, |
133 bool is_construct) { | 185 bool is_construct) { |
134 // Called from Generate_JS_Entry | 186 // Called from Generate_JS_Entry |
135 // r0: code entry | 187 // r0: code entry |
136 // r1: function | 188 // r1: function |
137 // r2: receiver | 189 // r2: receiver |
138 // r3: argc | 190 // r3: argc |
139 // r4: argv | 191 // r4: argv |
140 // r5-r7, cp may be clobbered | 192 // r5-r7, cp may be clobbered |
141 | 193 |
142 // Enter the JS frame | 194 // Clear the context before we push it when entering the JS frame. |
143 // compute parameter pointer before making changes | 195 __ mov(cp, Operand(0)); |
144 __ mov(ip, Operand(sp)); // ip == caller_sp == new pp | |
145 | 196 |
146 __ mov(r5, Operand(0)); // spare slot to store caller code object during GC | 197 // Enter an internal frame. |
147 __ mov(r6, Operand(0)); // no context | 198 __ EnterInternalFrame(); |
148 __ mov(r7, Operand(0)); // no incoming parameters | |
149 __ mov(r8, Operand(0)); // caller_pp == NULL for trampoline frames | |
150 ASSERT(cp.bit() == r8.bit()); // adjust the code otherwise | |
151 | |
152 // push in reverse order: | |
153 // code (r5==0), context (r6==0), args_len (r7==0), caller_pp (r8==0), | |
154 // caller_fp, sp_on_exit (caller_sp), caller_pc | |
155 __ stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | r8.bit() | | |
156 fp.bit() | ip.bit() | lr.bit()); | |
157 // Setup new frame pointer. | |
158 __ add(fp, sp, Operand(-StandardFrameConstants::kCodeOffset)); | |
159 __ mov(pp, Operand(ip)); // setup new parameter pointer | |
160 | 199 |
161 // Setup the context from the function argument. | 200 // Setup the context from the function argument. |
162 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); | 201 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); |
163 | 202 |
164 // Push the function and the receiver onto the stack. | 203 // Push the function and the receiver onto the stack. |
165 __ push(r1); | 204 __ push(r1); |
166 __ push(r2); | 205 __ push(r2); |
167 | 206 |
168 // Copy arguments to the stack in a loop. | 207 // Copy arguments to the stack in a loop. |
169 // r1: function | 208 // r1: function |
(...skipping 14 matching lines...) Expand all Loading... |
184 // Initialize all JavaScript callee-saved registers, since they will be seen | 223 // Initialize all JavaScript callee-saved registers, since they will be seen |
185 // by the garbage collector as part of handlers. | 224 // by the garbage collector as part of handlers. |
186 __ mov(r4, Operand(Factory::undefined_value())); | 225 __ mov(r4, Operand(Factory::undefined_value())); |
187 __ mov(r5, Operand(r4)); | 226 __ mov(r5, Operand(r4)); |
188 __ mov(r6, Operand(r4)); | 227 __ mov(r6, Operand(r4)); |
189 __ mov(r7, Operand(r4)); | 228 __ mov(r7, Operand(r4)); |
190 if (kR9Available == 1) | 229 if (kR9Available == 1) |
191 __ mov(r9, Operand(r4)); | 230 __ mov(r9, Operand(r4)); |
192 | 231 |
193 // Invoke the code and pass argc as r0. | 232 // Invoke the code and pass argc as r0. |
| 233 __ mov(r0, Operand(r3)); |
194 if (is_construct) { | 234 if (is_construct) { |
195 __ mov(r0, Operand(r3)); | |
196 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), | 235 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), |
197 code_target); | 236 code_target); |
198 } else { | 237 } else { |
199 ParameterCount actual(r3); | 238 ParameterCount actual(r0); |
200 __ InvokeFunction(r1, actual, CALL_FUNCTION); | 239 __ InvokeFunction(r1, actual, CALL_FUNCTION); |
201 } | 240 } |
202 | 241 |
203 // Exit the JS frame and remove the parameters (except function), and return. | 242 // Exit the JS frame and remove the parameters (except function), and return. |
204 // Respect ABI stack constraint. | 243 // Respect ABI stack constraint. |
205 __ add(sp, fp, Operand(StandardFrameConstants::kCallerFPOffset)); | 244 __ ExitInternalFrame(); |
206 __ ldm(ia, sp, fp.bit() | sp.bit() | pc.bit()); | 245 __ mov(pc, lr); |
207 | 246 |
208 // r0: result | 247 // r0: result |
209 // pp: not restored, should not be used anymore | |
210 } | 248 } |
211 | 249 |
212 | 250 |
213 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { | 251 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { |
214 Generate_JSEntryTrampolineHelper(masm, false); | 252 Generate_JSEntryTrampolineHelper(masm, false); |
215 } | 253 } |
216 | 254 |
217 | 255 |
218 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { | 256 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { |
219 Generate_JSEntryTrampolineHelper(masm, true); | 257 Generate_JSEntryTrampolineHelper(masm, true); |
220 } | 258 } |
221 | 259 |
222 | 260 |
223 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { | 261 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
224 // TODO(1233523): Implement. Unused for now. | 262 const int kIndexOffset = -5 * kPointerSize; |
225 __ stop("Builtins::Generate_FunctionApply"); | 263 const int kLimitOffset = -4 * kPointerSize; |
| 264 const int kArgsOffset = 2 * kPointerSize; |
| 265 const int kRecvOffset = 3 * kPointerSize; |
| 266 const int kFunctionOffset = 4 * kPointerSize; |
| 267 |
| 268 __ EnterInternalFrame(); |
| 269 |
| 270 __ ldr(r0, MemOperand(fp, kFunctionOffset)); // get the function |
| 271 __ push(r0); |
| 272 __ ldr(r0, MemOperand(fp, kArgsOffset)); // get the args array |
| 273 __ push(r0); |
| 274 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_JS); |
| 275 |
| 276 // Eagerly check for stack-overflow before starting to push the arguments. |
| 277 // r0: number of arguments |
| 278 Label okay; |
| 279 { Label L; |
| 280 __ mov(r1, Operand(391864 << kSmiTagSize)); |
| 281 __ cmp(r0, r1); |
| 282 __ b(cc, &L); |
| 283 __ bind(&L); |
| 284 } |
| 285 ExternalReference stack_guard_limit_address = |
| 286 ExternalReference::address_of_stack_guard_limit(); |
| 287 __ mov(r2, Operand(stack_guard_limit_address)); |
| 288 __ ldr(r2, MemOperand(r2)); |
| 289 __ sub(r2, sp, r2); |
| 290 __ sub(r2, r2, Operand(3 * kPointerSize)); // limit, index, receiver |
| 291 |
| 292 __ cmp(r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); |
| 293 __ b(hi, &okay); |
| 294 |
| 295 // Out of stack space. |
| 296 __ ldr(r1, MemOperand(fp, kFunctionOffset)); |
| 297 __ push(r1); |
| 298 __ push(r0); |
| 299 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_JS); |
| 300 |
| 301 // Push current limit and index. |
| 302 __ bind(&okay); |
| 303 __ push(r0); // limit |
| 304 __ mov(r1, Operand(0)); // initial index |
| 305 __ push(r1); |
| 306 |
| 307 // Change context eagerly to get the right global object if necessary. |
| 308 __ ldr(r0, MemOperand(fp, kFunctionOffset)); |
| 309 __ ldr(cp, FieldMemOperand(r0, JSFunction::kContextOffset)); |
| 310 |
| 311 // Compute the receiver. |
| 312 Label call_to_object, use_global_receiver, push_receiver; |
| 313 __ ldr(r0, MemOperand(fp, kRecvOffset)); |
| 314 __ tst(r0, Operand(kSmiTagMask)); |
| 315 __ b(eq, &call_to_object); |
| 316 __ mov(r1, Operand(Factory::null_value())); |
| 317 __ cmp(r0, r1); |
| 318 __ b(eq, &use_global_receiver); |
| 319 __ mov(r1, Operand(Factory::undefined_value())); |
| 320 __ cmp(r0, r1); |
| 321 __ b(eq, &use_global_receiver); |
| 322 |
| 323 // Check if the receiver is already a JavaScript object. |
| 324 // r0: receiver |
| 325 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 326 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
| 327 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); |
| 328 __ b(lt, &call_to_object); |
| 329 __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE)); |
| 330 __ b(le, &push_receiver); |
| 331 |
| 332 // Convert the receiver to a regular object. |
| 333 // r0: receiver |
| 334 __ bind(&call_to_object); |
| 335 __ push(r0); |
| 336 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); |
| 337 __ b(&push_receiver); |
| 338 |
| 339 // Use the current global object as the receiver. |
| 340 __ bind(&use_global_receiver); |
| 341 __ ldr(r0, FieldMemOperand(cp, Context::kHeaderSize + |
| 342 Context::GLOBAL_INDEX * kPointerSize)); |
| 343 |
| 344 // Push the receiver. |
| 345 // r0: receiver |
| 346 __ bind(&push_receiver); |
| 347 __ push(r0); |
| 348 |
| 349 // Copy all arguments from the array to the stack. |
| 350 Label entry, loop; |
| 351 __ ldr(r0, MemOperand(fp, kIndexOffset)); |
| 352 __ b(&entry); |
| 353 |
| 354 // Load the current argument from the arguments array and push it to the |
| 355 // stack. |
| 356 // r0: current argument index |
| 357 __ bind(&loop); |
| 358 __ ldr(r1, MemOperand(fp, kArgsOffset)); |
| 359 __ push(r1); |
| 360 __ push(r0); |
| 361 |
| 362 // Call the runtime to access the property in the arguments array. |
| 363 __ CallRuntime(Runtime::kGetProperty, 2); |
| 364 __ push(r0); |
| 365 |
| 366 // Use inline caching to access the arguments. |
| 367 __ ldr(r0, MemOperand(fp, kIndexOffset)); |
| 368 __ add(r0, r0, Operand(1 << kSmiTagSize)); |
| 369 __ str(r0, MemOperand(fp, kIndexOffset)); |
| 370 |
| 371 // Test if the copy loop has finished copying all the elements from the |
| 372 // arguments object. |
| 373 __ bind(&entry); |
| 374 __ ldr(r1, MemOperand(fp, kLimitOffset)); |
| 375 __ cmp(r0, r1); |
| 376 __ b(ne, &loop); |
| 377 |
| 378 // Invoke the function. |
| 379 ParameterCount actual(r0); |
| 380 __ mov(r0, Operand(r0, ASR, kSmiTagSize)); |
| 381 __ ldr(r1, MemOperand(fp, kFunctionOffset)); |
| 382 __ InvokeFunction(r1, actual, CALL_FUNCTION); |
| 383 |
| 384 // Tear down the internal frame and remove function, receiver and args. |
| 385 __ ExitInternalFrame(); |
| 386 __ add(sp, sp, Operand(3 * kPointerSize)); |
| 387 __ mov(pc, lr); |
226 } | 388 } |
227 | 389 |
228 | 390 |
| 391 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { |
| 392 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); |
| 393 __ mov(r4, Operand(ArgumentsAdaptorFrame::SENTINEL)); |
| 394 __ stm(db_w, sp, r0.bit() | r1.bit() | r4.bit() | fp.bit() | lr.bit()); |
| 395 __ add(fp, sp, Operand(3 * kPointerSize)); |
| 396 } |
| 397 |
| 398 |
| 399 static void ExitArgumentsAdaptorFrame(MacroAssembler* masm) { |
| 400 // ----------- S t a t e ------------- |
| 401 // -- r0 : result being passed through |
| 402 // ----------------------------------- |
| 403 // Get the number of arguments passed (as a smi), tear down the frame and |
| 404 // then tear down the parameters. |
| 405 __ ldr(r1, MemOperand(fp, -3 * kPointerSize)); |
| 406 __ mov(sp, fp); |
| 407 __ ldm(ia_w, sp, fp.bit() | lr.bit()); |
| 408 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); |
| 409 __ add(sp, sp, Operand(kPointerSize)); // adjust for receiver |
| 410 } |
| 411 |
| 412 |
229 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { | 413 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { |
230 // TODO(1233523): Implement. Unused for now. | 414 // ----------- S t a t e ------------- |
231 __ stop("Builtins::Generate_ArgumentsAdaptorTrampoline"); | 415 // -- r0 : actual number of arguments |
232 | 416 // -- r1 : function (passed through to callee) |
| 417 // -- r2 : expected number of arguments |
| 418 // -- r3 : code entry to call |
| 419 // ----------------------------------- |
| 420 |
| 421 Label entry, invoke, function_prototype_call; |
| 422 __ bind(&entry); |
| 423 |
| 424 Label enough, too_few; |
| 425 __ cmp(r0, Operand(r2)); |
| 426 __ b(lt, &too_few); |
| 427 __ cmp(r2, Operand(-1)); |
| 428 __ b(eq, &function_prototype_call); |
| 429 |
| 430 { // Enough parameters: actual >= excpected |
| 431 __ bind(&enough); |
| 432 EnterArgumentsAdaptorFrame(masm); |
| 433 |
| 434 // Calculate copy start address into r0 and copy end address into r2. |
| 435 // r0: actual number of arguments as a smi |
| 436 // r1: function |
| 437 // r2: expected number of arguments |
| 438 // r3: code entry to call |
| 439 __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); |
| 440 // adjust for return address and receiver |
| 441 __ add(r0, r0, Operand(2 * kPointerSize)); |
| 442 __ sub(r2, r0, Operand(r2, LSL, kPointerSizeLog2)); |
| 443 |
| 444 // Copy the arguments (including the receiver) to the new stack frame. |
| 445 // r0: copy start address |
| 446 // r1: function |
| 447 // r2: copy end address |
| 448 // r3: code entry to call |
| 449 |
| 450 Label copy; |
| 451 __ bind(©); |
| 452 __ ldr(ip, MemOperand(r0, 0)); |
| 453 __ push(ip); |
| 454 __ cmp(r0, r2); // Compare before moving to next argument. |
| 455 __ sub(r0, r0, Operand(kPointerSize)); |
| 456 __ b(ne, ©); |
| 457 |
| 458 __ b(&invoke); |
| 459 } |
| 460 |
| 461 { // Too few parameters: Actual < expected |
| 462 __ bind(&too_few); |
| 463 EnterArgumentsAdaptorFrame(masm); |
| 464 |
| 465 // Calculate copy start address into r0 and copy end address is fp. |
| 466 // r0: actual number of arguments as a smi |
| 467 // r1: function |
| 468 // r2: expected number of arguments |
| 469 // r3: code entry to call |
| 470 __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); |
| 471 |
| 472 // Copy the arguments (including the receiver) to the new stack frame. |
| 473 // r0: copy start address |
| 474 // r1: function |
| 475 // r2: expected number of arguments |
| 476 // r3: code entry to call |
| 477 Label copy; |
| 478 __ bind(©); |
| 479 // Adjust load for return address and receiver. |
| 480 __ ldr(ip, MemOperand(r0, 2 * kPointerSize)); |
| 481 __ push(ip); |
| 482 __ cmp(r0, fp); // Compare before moving to next argument. |
| 483 __ sub(r0, r0, Operand(kPointerSize)); |
| 484 __ b(ne, ©); |
| 485 |
| 486 // Fill the remaining expected arguments with undefined. |
| 487 // r1: function |
| 488 // r2: expected number of arguments |
| 489 // r3: code entry to call |
| 490 __ mov(ip, Operand(Factory::undefined_value())); |
| 491 __ sub(r2, fp, Operand(r2, LSL, kPointerSizeLog2)); |
| 492 __ sub(r2, r2, Operand(4 * kPointerSize)); // Adjust for frame. |
| 493 |
| 494 Label fill; |
| 495 __ bind(&fill); |
| 496 __ push(ip); |
| 497 __ cmp(sp, r2); |
| 498 __ b(ne, &fill); |
| 499 } |
| 500 |
| 501 // Call the entry point. |
233 Label return_site; | 502 Label return_site; |
| 503 __ bind(&invoke); |
| 504 |
| 505 // TODO(iposva): remove compatibility layer using r0 |
| 506 __ ldr(r0, MemOperand(fp, -3 * kPointerSize)); |
| 507 __ mov(r0, Operand(r0, LSR, kSmiTagSize)); |
| 508 |
| 509 __ Call(r3); |
234 __ bind(&return_site); | 510 __ bind(&return_site); |
235 | 511 |
| 512 ExitArgumentsAdaptorFrame(masm); |
| 513 __ mov(pc, lr); |
| 514 |
236 // Compute the offset from the beginning of the ArgumentsAdaptorTrampoline | 515 // Compute the offset from the beginning of the ArgumentsAdaptorTrampoline |
237 // builtin code object to the return address after the call. | 516 // builtin code object to the return address after the call. |
238 ASSERT(return_site.is_bound()); | 517 ASSERT(return_site.is_bound()); |
239 arguments_adaptor_call_pc_offset_ = return_site.pos() + Code::kHeaderSize; | 518 arguments_adaptor_call_pc_offset_ = return_site.pos() + Code::kHeaderSize; |
| 519 |
| 520 |
| 521 // ------------------------------------------- |
| 522 // Function.prototype.call implementation. |
| 523 // ------------------------------------------- |
| 524 // r0: actual number of argument |
| 525 __ bind(&function_prototype_call); |
| 526 |
| 527 // 1. Make sure we have at least one argument. |
| 528 // r0: actual number of argument |
| 529 { Label done; |
| 530 __ tst(r0, Operand(r0)); |
| 531 __ b(ne, &done); |
| 532 __ mov(r2, Operand(Factory::undefined_value())); |
| 533 __ push(r2); |
| 534 __ add(r0, r0, Operand(1)); |
| 535 __ bind(&done); |
| 536 } |
| 537 |
| 538 // 2. Get the function to call. Already in r1. |
| 539 // r0: actual number of argument |
| 540 { Label done, non_function, function; |
| 541 __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); |
| 542 __ tst(r1, Operand(kSmiTagMask)); |
| 543 __ b(eq, &non_function); |
| 544 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 545 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| 546 __ cmp(r2, Operand(JS_FUNCTION_TYPE)); |
| 547 __ b(eq, &function); |
| 548 |
| 549 // Non-function called: Clear the function to force exception. |
| 550 __ bind(&non_function); |
| 551 __ mov(r1, Operand(0)); |
| 552 __ b(&done); |
| 553 |
| 554 // Change the context eagerly because it will be used below to get the |
| 555 // right global object. |
| 556 __ bind(&function); |
| 557 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); |
| 558 |
| 559 __ bind(&done); |
| 560 } |
| 561 |
| 562 // 3. Make sure first argument is an object; convert if necessary. |
| 563 // r0: actual number of arguments |
| 564 // r1: function |
| 565 { Label call_to_object, use_global_receiver, patch_receiver, done; |
| 566 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); |
| 567 __ ldr(r2, MemOperand(r2, -kPointerSize)); |
| 568 |
| 569 // r0: actual number of arguments |
| 570 // r1: function |
| 571 // r2: first argument |
| 572 __ tst(r2, Operand(kSmiTagMask)); |
| 573 __ b(eq, &call_to_object); |
| 574 |
| 575 __ mov(r3, Operand(Factory::null_value())); |
| 576 __ cmp(r2, r3); |
| 577 __ b(eq, &use_global_receiver); |
| 578 __ mov(r3, Operand(Factory::undefined_value())); |
| 579 __ cmp(r2, r3); |
| 580 __ b(eq, &use_global_receiver); |
| 581 |
| 582 __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset)); |
| 583 __ ldrb(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset)); |
| 584 __ cmp(r3, Operand(FIRST_JS_OBJECT_TYPE)); |
| 585 __ b(lt, &call_to_object); |
| 586 __ cmp(r3, Operand(LAST_JS_OBJECT_TYPE)); |
| 587 __ b(le, &done); |
| 588 |
| 589 __ bind(&call_to_object); |
| 590 __ EnterInternalFrame(); |
| 591 |
| 592 // Store number of arguments and function across the call into the runtime. |
| 593 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); |
| 594 __ push(r0); |
| 595 __ push(r1); |
| 596 |
| 597 __ push(r2); |
| 598 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); |
| 599 __ mov(r2, r0); |
| 600 |
| 601 // Restore number of arguments and function. |
| 602 __ pop(r1); |
| 603 __ pop(r0); |
| 604 __ mov(r0, Operand(r0, ASR, kSmiTagSize)); |
| 605 |
| 606 __ ExitInternalFrame(); |
| 607 __ b(&patch_receiver); |
| 608 |
| 609 // Use the global object from the called function as the receiver. |
| 610 __ bind(&use_global_receiver); |
| 611 const int kGlobalIndex = |
| 612 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; |
| 613 __ ldr(r2, FieldMemOperand(cp, kGlobalIndex)); |
| 614 |
| 615 __ bind(&patch_receiver); |
| 616 __ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2)); |
| 617 __ str(r2, MemOperand(r3, -kPointerSize)); |
| 618 |
| 619 __ bind(&done); |
| 620 } |
| 621 |
| 622 // 4. Shift stuff one slot down the stack |
| 623 // r0: actual number of arguments (including call() receiver) |
| 624 // r1: function |
| 625 { Label loop; |
| 626 // Calculate the copy start address (destination). Copy end address is sp. |
| 627 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); |
| 628 |
| 629 __ bind(&loop); |
| 630 __ ldr(ip, MemOperand(r2, -kPointerSize)); |
| 631 __ str(ip, MemOperand(r2)); |
| 632 __ sub(r2, r2, Operand(kPointerSize)); |
| 633 __ cmp(r2, sp); |
| 634 __ b(ne, &loop); |
| 635 } |
| 636 |
| 637 // 5. Adjust the actual number of arguments and remove the top element. |
| 638 // r0: actual number of arguments (including call() receiver) |
| 639 // r1: function |
| 640 __ sub(r0, r0, Operand(1)); |
| 641 __ add(sp, sp, Operand(kPointerSize)); |
| 642 |
| 643 // 6. Get the code for the function or the non-function builtin. |
| 644 // If number of expected arguments matches, then call. Otherwise restart |
| 645 // the arguments adaptor stub. |
| 646 // r0: actual number of arguments |
| 647 // r1: function |
| 648 { Label invoke; |
| 649 __ tst(r1, r1); |
| 650 __ b(ne, &invoke); |
| 651 __ stop("Generate_ArgumentsAdaptorTrampoline - non-function call"); |
| 652 __ mov(r2, Operand(0)); // expected arguments is 0 for CALL_NON_FUNCTION |
| 653 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); |
| 654 __ b(&enough); |
| 655 |
| 656 __ bind(&invoke); |
| 657 __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); |
| 658 __ ldr(r2, |
| 659 FieldMemOperand(r3, |
| 660 SharedFunctionInfo::kFormalParameterCountOffset)); |
| 661 __ ldr(r3, |
| 662 MemOperand(r3, SharedFunctionInfo::kCodeOffset - kHeapObjectTag)); |
| 663 __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); |
| 664 __ cmp(r2, r0); // Check formal and actual parameter counts. |
| 665 __ b(ne, &entry); |
| 666 |
| 667 // 7. Jump to the code in r3 without checking arguments. |
| 668 ParameterCount expected(0); |
| 669 __ InvokeCode(r3, expected, expected, JUMP_FUNCTION); |
| 670 } |
240 } | 671 } |
241 | 672 |
242 | 673 |
243 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, | 674 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, |
244 RegList pointer_regs) { | 675 RegList pointer_regs) { |
245 // Save the content of all general purpose registers in memory. This copy in | 676 // Save the content of all general purpose registers in memory. This copy in |
246 // memory is later pushed onto the JS expression stack for the fake JS frame | 677 // memory is later pushed onto the JS expression stack for the fake JS frame |
247 // generated and also to the C frame generated on top of that. In the JS | 678 // generated and also to the C frame generated on top of that. In the JS |
248 // frame ONLY the registers containing pointers will be pushed on the | 679 // frame ONLY the registers containing pointers will be pushed on the |
249 // expression stack. This causes the GC to update these pointers so that | 680 // expression stack. This causes the GC to update these pointers so that |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 } | 830 } |
400 | 831 |
401 void Builtins::Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) { | 832 void Builtins::Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) { |
402 // Generate nothing as CodeStub CallFunction is not used on ARM. | 833 // Generate nothing as CodeStub CallFunction is not used on ARM. |
403 } | 834 } |
404 | 835 |
405 | 836 |
406 #undef __ | 837 #undef __ |
407 | 838 |
408 } } // namespace v8::internal | 839 } } // namespace v8::internal |
OLD | NEW |