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

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

Issue 8139027: Version 3.6.5 (Closed) Base URL: http://v8.googlecode.com/svn/trunk/
Patch Set: '' Created 9 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « src/ia32/assembler-ia32-inl.h ('k') | src/ia32/code-stubs-ia32.h » ('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 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 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 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 Register scratch = ebx; 62 Register scratch = ebx;
63 __ pop(scratch); // Save return address. 63 __ pop(scratch); // Save return address.
64 __ push(edi); 64 __ push(edi);
65 __ push(scratch); // Restore return address. 65 __ push(scratch); // Restore return address.
66 } else { 66 } else {
67 ASSERT(extra_args == NO_EXTRA_ARGUMENTS); 67 ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
68 } 68 }
69 69
70 // JumpToExternalReference expects eax to contain the number of arguments 70 // JumpToExternalReference expects eax to contain the number of arguments
71 // including the receiver and the extra arguments. 71 // including the receiver and the extra arguments.
72 __ add(Operand(eax), Immediate(num_extra_args + 1)); 72 __ add(eax, Immediate(num_extra_args + 1));
73 __ JumpToExternalReference(ExternalReference(id, masm->isolate())); 73 __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
74 } 74 }
75 75
76 76
77 void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { 77 void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
78 // ----------- S t a t e ------------- 78 // ----------- S t a t e -------------
79 // -- eax: number of arguments 79 // -- eax: number of arguments
80 // -- edi: constructor function 80 // -- edi: constructor function
81 // ----------------------------------- 81 // -----------------------------------
82 82
83 Label non_function_call; 83 Label slow, non_function_call;
84 // Check that function is not a smi. 84 // Check that function is not a smi.
85 __ JumpIfSmi(edi, &non_function_call); 85 __ JumpIfSmi(edi, &non_function_call);
86 // Check that function is a JSFunction. 86 // Check that function is a JSFunction.
87 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 87 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
88 __ j(not_equal, &non_function_call); 88 __ j(not_equal, &slow);
89 89
90 // Jump to the function-specific construct stub. 90 // Jump to the function-specific construct stub.
91 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 91 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
92 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset)); 92 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset));
93 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize)); 93 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
94 __ jmp(Operand(ebx)); 94 __ jmp(ebx);
95 95
96 // edi: called object 96 // edi: called object
97 // eax: number of arguments 97 // eax: number of arguments
98 // ecx: object map
99 Label do_call;
100 __ bind(&slow);
101 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
102 __ j(not_equal, &non_function_call);
103 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
104 __ jmp(&do_call);
105
98 __ bind(&non_function_call); 106 __ bind(&non_function_call);
107 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
108 __ bind(&do_call);
99 // Set expected number of arguments to zero (not changing eax). 109 // Set expected number of arguments to zero (not changing eax).
100 __ Set(ebx, Immediate(0)); 110 __ Set(ebx, Immediate(0));
101 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
102 Handle<Code> arguments_adaptor = 111 Handle<Code> arguments_adaptor =
103 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); 112 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
104 __ SetCallKind(ecx, CALL_AS_METHOD); 113 __ SetCallKind(ecx, CALL_AS_METHOD);
105 __ jmp(arguments_adaptor, RelocInfo::CODE_TARGET); 114 __ jmp(arguments_adaptor, RelocInfo::CODE_TARGET);
106 } 115 }
107 116
108 117
109 static void Generate_JSConstructStubHelper(MacroAssembler* masm, 118 static void Generate_JSConstructStubHelper(MacroAssembler* masm,
110 bool is_api_function, 119 bool is_api_function,
111 bool count_constructions) { 120 bool count_constructions) {
112 // Should never count constructions for api objects. 121 // Should never count constructions for api objects.
113 ASSERT(!is_api_function || !count_constructions); 122 ASSERT(!is_api_function || !count_constructions);
114 123
115 // Enter a construct frame. 124 // Enter a construct frame.
116 __ EnterConstructFrame(); 125 {
117 126 FrameScope scope(masm, StackFrame::CONSTRUCT);
118 // Store a smi-tagged arguments count on the stack. 127
119 __ SmiTag(eax); 128 // Store a smi-tagged arguments count on the stack.
120 __ push(eax); 129 __ SmiTag(eax);
121 130 __ push(eax);
122 // Push the function to invoke on the stack. 131
123 __ push(edi); 132 // Push the function to invoke on the stack.
124 133 __ push(edi);
125 // Try to allocate the object without transitioning into C code. If any of the 134
126 // preconditions is not met, the code bails out to the runtime call. 135 // Try to allocate the object without transitioning into C code. If any of
127 Label rt_call, allocated; 136 // the preconditions is not met, the code bails out to the runtime call.
128 if (FLAG_inline_new) { 137 Label rt_call, allocated;
129 Label undo_allocation; 138 if (FLAG_inline_new) {
139 Label undo_allocation;
130 #ifdef ENABLE_DEBUGGER_SUPPORT 140 #ifdef ENABLE_DEBUGGER_SUPPORT
131 ExternalReference debug_step_in_fp = 141 ExternalReference debug_step_in_fp =
132 ExternalReference::debug_step_in_fp_address(masm->isolate()); 142 ExternalReference::debug_step_in_fp_address(masm->isolate());
133 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0)); 143 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
134 __ j(not_equal, &rt_call); 144 __ j(not_equal, &rt_call);
135 #endif 145 #endif
136 146
137 // Verified that the constructor is a JSFunction. 147 // Verified that the constructor is a JSFunction.
138 // Load the initial map and verify that it is in fact a map. 148 // Load the initial map and verify that it is in fact a map.
139 // edi: constructor 149 // edi: constructor
140 __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); 150 __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
141 // Will both indicate a NULL and a Smi 151 // Will both indicate a NULL and a Smi
142 __ JumpIfSmi(eax, &rt_call); 152 __ JumpIfSmi(eax, &rt_call);
143 // edi: constructor 153 // edi: constructor
144 // eax: initial map (if proven valid below) 154 // eax: initial map (if proven valid below)
145 __ CmpObjectType(eax, MAP_TYPE, ebx); 155 __ CmpObjectType(eax, MAP_TYPE, ebx);
146 __ j(not_equal, &rt_call); 156 __ j(not_equal, &rt_call);
147 157
148 // Check that the constructor is not constructing a JSFunction (see comments 158 // Check that the constructor is not constructing a JSFunction (see
149 // in Runtime_NewObject in runtime.cc). In which case the initial map's 159 // comments in Runtime_NewObject in runtime.cc). In which case the
150 // instance type would be JS_FUNCTION_TYPE. 160 // initial map's instance type would be JS_FUNCTION_TYPE.
151 // edi: constructor 161 // edi: constructor
152 // eax: initial map 162 // eax: initial map
153 __ CmpInstanceType(eax, JS_FUNCTION_TYPE); 163 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
154 __ j(equal, &rt_call); 164 __ j(equal, &rt_call);
155 165
156 if (count_constructions) { 166 if (count_constructions) {
157 Label allocate; 167 Label allocate;
158 // Decrease generous allocation count. 168 // Decrease generous allocation count.
159 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 169 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
160 __ dec_b(FieldOperand(ecx, SharedFunctionInfo::kConstructionCountOffset)); 170 __ dec_b(FieldOperand(ecx,
161 __ j(not_zero, &allocate); 171 SharedFunctionInfo::kConstructionCountOffset));
162 172 __ j(not_zero, &allocate);
163 __ push(eax); 173
164 __ push(edi); 174 __ push(eax);
165 175 __ push(edi);
166 __ push(edi); // constructor 176
167 // The call will replace the stub, so the countdown is only done once. 177 __ push(edi); // constructor
168 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1); 178 // The call will replace the stub, so the countdown is only done once.
169 179 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
170 __ pop(edi); 180
171 __ pop(eax); 181 __ pop(edi);
172 182 __ pop(eax);
173 __ bind(&allocate); 183
184 __ bind(&allocate);
185 }
186
187 // Now allocate the JSObject on the heap.
188 // edi: constructor
189 // eax: initial map
190 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
191 __ shl(edi, kPointerSizeLog2);
192 __ AllocateInNewSpace(
193 edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
194 // Allocated the JSObject, now initialize the fields.
195 // eax: initial map
196 // ebx: JSObject
197 // edi: start of next object
198 __ mov(Operand(ebx, JSObject::kMapOffset), eax);
199 Factory* factory = masm->isolate()->factory();
200 __ mov(ecx, factory->empty_fixed_array());
201 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
202 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
203 // Set extra fields in the newly allocated object.
204 // eax: initial map
205 // ebx: JSObject
206 // edi: start of next object
207 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
208 __ mov(edx, factory->undefined_value());
209 if (count_constructions) {
210 __ movzx_b(esi,
211 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
212 __ lea(esi,
213 Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize));
214 // esi: offset of first field after pre-allocated fields
215 if (FLAG_debug_code) {
216 __ cmp(esi, edi);
217 __ Assert(less_equal,
218 "Unexpected number of pre-allocated property fields.");
219 }
220 __ InitializeFieldsWithFiller(ecx, esi, edx);
221 __ mov(edx, factory->one_pointer_filler_map());
222 }
223 __ InitializeFieldsWithFiller(ecx, edi, edx);
224
225 // Add the object tag to make the JSObject real, so that we can continue
226 // and jump into the continuation code at any time from now on. Any
227 // failures need to undo the allocation, so that the heap is in a
228 // consistent state and verifiable.
229 // eax: initial map
230 // ebx: JSObject
231 // edi: start of next object
232 __ or_(ebx, Immediate(kHeapObjectTag));
233
234 // Check if a non-empty properties array is needed.
235 // Allocate and initialize a FixedArray if it is.
236 // eax: initial map
237 // ebx: JSObject
238 // edi: start of next object
239 // Calculate the total number of properties described by the map.
240 __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
241 __ movzx_b(ecx,
242 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
243 __ add(edx, ecx);
244 // Calculate unused properties past the end of the in-object properties.
245 __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
246 __ sub(edx, ecx);
247 // Done if no extra properties are to be allocated.
248 __ j(zero, &allocated);
249 __ Assert(positive, "Property allocation count failed.");
250
251 // Scale the number of elements by pointer size and add the header for
252 // FixedArrays to the start of the next object calculation from above.
253 // ebx: JSObject
254 // edi: start of next object (will be start of FixedArray)
255 // edx: number of elements in properties array
256 __ AllocateInNewSpace(FixedArray::kHeaderSize,
257 times_pointer_size,
258 edx,
259 edi,
260 ecx,
261 no_reg,
262 &undo_allocation,
263 RESULT_CONTAINS_TOP);
264
265 // Initialize the FixedArray.
266 // ebx: JSObject
267 // edi: FixedArray
268 // edx: number of elements
269 // ecx: start of next object
270 __ mov(eax, factory->fixed_array_map());
271 __ mov(Operand(edi, FixedArray::kMapOffset), eax); // setup the map
272 __ SmiTag(edx);
273 __ mov(Operand(edi, FixedArray::kLengthOffset), edx); // and length
274
275 // Initialize the fields to undefined.
276 // ebx: JSObject
277 // edi: FixedArray
278 // ecx: start of next object
279 { Label loop, entry;
280 __ mov(edx, factory->undefined_value());
281 __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
282 __ jmp(&entry);
283 __ bind(&loop);
284 __ mov(Operand(eax, 0), edx);
285 __ add(eax, Immediate(kPointerSize));
286 __ bind(&entry);
287 __ cmp(eax, ecx);
288 __ j(below, &loop);
289 }
290
291 // Store the initialized FixedArray into the properties field of
292 // the JSObject
293 // ebx: JSObject
294 // edi: FixedArray
295 __ or_(edi, Immediate(kHeapObjectTag)); // add the heap tag
296 __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
297
298
299 // Continue with JSObject being successfully allocated
300 // ebx: JSObject
301 __ jmp(&allocated);
302
303 // Undo the setting of the new top so that the heap is verifiable. For
304 // example, the map's unused properties potentially do not match the
305 // allocated objects unused properties.
306 // ebx: JSObject (previous new top)
307 __ bind(&undo_allocation);
308 __ UndoAllocationInNewSpace(ebx);
174 } 309 }
175 310
176 // Now allocate the JSObject on the heap. 311 // Allocate the new receiver object using the runtime call.
177 // edi: constructor 312 __ bind(&rt_call);
178 // eax: initial map 313 // Must restore edi (constructor) before calling runtime.
179 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset)); 314 __ mov(edi, Operand(esp, 0));
180 __ shl(edi, kPointerSizeLog2); 315 // edi: function (constructor)
181 __ AllocateInNewSpace(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS); 316 __ push(edi);
182 // Allocated the JSObject, now initialize the fields. 317 __ CallRuntime(Runtime::kNewObject, 1);
183 // eax: initial map 318 __ mov(ebx, eax); // store result in ebx
184 // ebx: JSObject 319
185 // edi: start of next object 320 // New object allocated.
186 __ mov(Operand(ebx, JSObject::kMapOffset), eax); 321 // ebx: newly allocated object
187 Factory* factory = masm->isolate()->factory(); 322 __ bind(&allocated);
188 __ mov(ecx, factory->empty_fixed_array()); 323 // Retrieve the function from the stack.
189 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx); 324 __ pop(edi);
190 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx); 325
191 // Set extra fields in the newly allocated object. 326 // Retrieve smi-tagged arguments count from the stack.
192 // eax: initial map 327 __ mov(eax, Operand(esp, 0));
193 // ebx: JSObject 328 __ SmiUntag(eax);
194 // edi: start of next object 329
195 { Label loop, entry; 330 // Push the allocated receiver to the stack. We need two copies
196 // To allow for truncation. 331 // because we may have to return the original one and the calling
197 if (count_constructions) { 332 // conventions dictate that the called function pops the receiver.
198 __ mov(edx, factory->one_pointer_filler_map()); 333 __ push(ebx);
199 } else { 334 __ push(ebx);
200 __ mov(edx, factory->undefined_value()); 335
201 } 336 // Setup pointer to last argument.
202 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize)); 337 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
203 __ jmp(&entry); 338
204 __ bind(&loop); 339 // Copy arguments and receiver to the expression stack.
205 __ mov(Operand(ecx, 0), edx); 340 Label loop, entry;
206 __ add(Operand(ecx), Immediate(kPointerSize)); 341 __ mov(ecx, eax);
207 __ bind(&entry); 342 __ jmp(&entry);
208 __ cmp(ecx, Operand(edi)); 343 __ bind(&loop);
209 __ j(less, &loop); 344 __ push(Operand(ebx, ecx, times_4, 0));
345 __ bind(&entry);
346 __ dec(ecx);
347 __ j(greater_equal, &loop);
348
349 // Call the function.
350 if (is_api_function) {
351 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
352 Handle<Code> code =
353 masm->isolate()->builtins()->HandleApiCallConstruct();
354 ParameterCount expected(0);
355 __ InvokeCode(code, expected, expected, RelocInfo::CODE_TARGET,
356 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
357 } else {
358 ParameterCount actual(eax);
359 __ InvokeFunction(edi, actual, CALL_FUNCTION,
360 NullCallWrapper(), CALL_AS_METHOD);
210 } 361 }
211 362
212 // Add the object tag to make the JSObject real, so that we can continue and 363 // Restore context from the frame.
213 // jump into the continuation code at any time from now on. Any failures 364 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
214 // need to undo the allocation, so that the heap is in a consistent state 365
215 // and verifiable. 366 // If the result is an object (in the ECMA sense), we should get rid
216 // eax: initial map 367 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
217 // ebx: JSObject 368 // on page 74.
218 // edi: start of next object 369 Label use_receiver, exit;
219 __ or_(Operand(ebx), Immediate(kHeapObjectTag)); 370
220 371 // If the result is a smi, it is *not* an object in the ECMA sense.
221 // Check if a non-empty properties array is needed. 372 __ JumpIfSmi(eax, &use_receiver);
222 // Allocate and initialize a FixedArray if it is. 373
223 // eax: initial map 374 // If the type of the result (stored in its map) is less than
224 // ebx: JSObject 375 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
225 // edi: start of next object 376 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
226 // Calculate the total number of properties described by the map. 377 __ j(above_equal, &exit);
227 __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset)); 378
228 __ movzx_b(ecx, FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset)); 379 // Throw away the result of the constructor invocation and use the
229 __ add(edx, Operand(ecx)); 380 // on-stack receiver as the result.
230 // Calculate unused properties past the end of the in-object properties. 381 __ bind(&use_receiver);
231 __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset)); 382 __ mov(eax, Operand(esp, 0));
232 __ sub(edx, Operand(ecx)); 383
233 // Done if no extra properties are to be allocated. 384 // Restore the arguments count and leave the construct frame.
234 __ j(zero, &allocated); 385 __ bind(&exit);
235 __ Assert(positive, "Property allocation count failed."); 386 __ mov(ebx, Operand(esp, kPointerSize)); // Get arguments count.
236 387
237 // Scale the number of elements by pointer size and add the header for 388 // Leave construct frame.
238 // FixedArrays to the start of the next object calculation from above.
239 // ebx: JSObject
240 // edi: start of next object (will be start of FixedArray)
241 // edx: number of elements in properties array
242 __ AllocateInNewSpace(FixedArray::kHeaderSize,
243 times_pointer_size,
244 edx,
245 edi,
246 ecx,
247 no_reg,
248 &undo_allocation,
249 RESULT_CONTAINS_TOP);
250
251 // Initialize the FixedArray.
252 // ebx: JSObject
253 // edi: FixedArray
254 // edx: number of elements
255 // ecx: start of next object
256 __ mov(eax, factory->fixed_array_map());
257 __ mov(Operand(edi, FixedArray::kMapOffset), eax); // setup the map
258 __ SmiTag(edx);
259 __ mov(Operand(edi, FixedArray::kLengthOffset), edx); // and length
260
261 // Initialize the fields to undefined.
262 // ebx: JSObject
263 // edi: FixedArray
264 // ecx: start of next object
265 { Label loop, entry;
266 __ mov(edx, factory->undefined_value());
267 __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
268 __ jmp(&entry);
269 __ bind(&loop);
270 __ mov(Operand(eax, 0), edx);
271 __ add(Operand(eax), Immediate(kPointerSize));
272 __ bind(&entry);
273 __ cmp(eax, Operand(ecx));
274 __ j(below, &loop);
275 }
276
277 // Store the initialized FixedArray into the properties field of
278 // the JSObject
279 // ebx: JSObject
280 // edi: FixedArray
281 __ or_(Operand(edi), Immediate(kHeapObjectTag)); // add the heap tag
282 __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
283
284
285 // Continue with JSObject being successfully allocated
286 // ebx: JSObject
287 __ jmp(&allocated);
288
289 // Undo the setting of the new top so that the heap is verifiable. For
290 // example, the map's unused properties potentially do not match the
291 // allocated objects unused properties.
292 // ebx: JSObject (previous new top)
293 __ bind(&undo_allocation);
294 __ UndoAllocationInNewSpace(ebx);
295 } 389 }
296 390
297 // Allocate the new receiver object using the runtime call.
298 __ bind(&rt_call);
299 // Must restore edi (constructor) before calling runtime.
300 __ mov(edi, Operand(esp, 0));
301 // edi: function (constructor)
302 __ push(edi);
303 __ CallRuntime(Runtime::kNewObject, 1);
304 __ mov(ebx, Operand(eax)); // store result in ebx
305
306 // New object allocated.
307 // ebx: newly allocated object
308 __ bind(&allocated);
309 // Retrieve the function from the stack.
310 __ pop(edi);
311
312 // Retrieve smi-tagged arguments count from the stack.
313 __ mov(eax, Operand(esp, 0));
314 __ SmiUntag(eax);
315
316 // Push the allocated receiver to the stack. We need two copies
317 // because we may have to return the original one and the calling
318 // conventions dictate that the called function pops the receiver.
319 __ push(ebx);
320 __ push(ebx);
321
322 // Setup pointer to last argument.
323 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
324
325 // Copy arguments and receiver to the expression stack.
326 Label loop, entry;
327 __ mov(ecx, Operand(eax));
328 __ jmp(&entry);
329 __ bind(&loop);
330 __ push(Operand(ebx, ecx, times_4, 0));
331 __ bind(&entry);
332 __ dec(ecx);
333 __ j(greater_equal, &loop);
334
335 // Call the function.
336 if (is_api_function) {
337 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
338 Handle<Code> code =
339 masm->isolate()->builtins()->HandleApiCallConstruct();
340 ParameterCount expected(0);
341 __ InvokeCode(code, expected, expected, RelocInfo::CODE_TARGET,
342 CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
343 } else {
344 ParameterCount actual(eax);
345 __ InvokeFunction(edi, actual, CALL_FUNCTION,
346 NullCallWrapper(), CALL_AS_METHOD);
347 }
348
349 // Restore context from the frame.
350 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
351
352 // If the result is an object (in the ECMA sense), we should get rid
353 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
354 // on page 74.
355 Label use_receiver, exit;
356
357 // If the result is a smi, it is *not* an object in the ECMA sense.
358 __ JumpIfSmi(eax, &use_receiver);
359
360 // If the type of the result (stored in its map) is less than
361 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
362 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
363 __ j(above_equal, &exit);
364
365 // Throw away the result of the constructor invocation and use the
366 // on-stack receiver as the result.
367 __ bind(&use_receiver);
368 __ mov(eax, Operand(esp, 0));
369
370 // Restore the arguments count and leave the construct frame.
371 __ bind(&exit);
372 __ mov(ebx, Operand(esp, kPointerSize)); // get arguments count
373 __ LeaveConstructFrame();
374
375 // Remove caller arguments from the stack and return. 391 // Remove caller arguments from the stack and return.
376 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 392 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
377 __ pop(ecx); 393 __ pop(ecx);
378 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver 394 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
379 __ push(ecx); 395 __ push(ecx);
380 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1); 396 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
381 __ ret(0); 397 __ ret(0);
382 } 398 }
383 399
384 400
385 void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) { 401 void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) {
386 Generate_JSConstructStubHelper(masm, false, true); 402 Generate_JSConstructStubHelper(masm, false, true);
387 } 403 }
388 404
389 405
390 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { 406 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
391 Generate_JSConstructStubHelper(masm, false, false); 407 Generate_JSConstructStubHelper(masm, false, false);
392 } 408 }
393 409
394 410
395 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { 411 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
396 Generate_JSConstructStubHelper(masm, true, false); 412 Generate_JSConstructStubHelper(masm, true, false);
397 } 413 }
398 414
399 415
400 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, 416 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
401 bool is_construct) { 417 bool is_construct) {
402 // Clear the context before we push it when entering the JS frame. 418 // Clear the context before we push it when entering the internal frame.
403 __ Set(esi, Immediate(0)); 419 __ Set(esi, Immediate(0));
404 420
405 // Enter an internal frame. 421 {
406 __ EnterInternalFrame(); 422 FrameScope scope(masm, StackFrame::INTERNAL);
407 423
408 // Load the previous frame pointer (ebx) to access C arguments 424 // Load the previous frame pointer (ebx) to access C arguments
409 __ mov(ebx, Operand(ebp, 0)); 425 __ mov(ebx, Operand(ebp, 0));
410 426
411 // Get the function from the frame and setup the context. 427 // Get the function from the frame and setup the context.
412 __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset)); 428 __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
413 __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset)); 429 __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
414 430
415 // Push the function and the receiver onto the stack. 431 // Push the function and the receiver onto the stack.
416 __ push(ecx); 432 __ push(ecx);
417 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset)); 433 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
418 434
419 // Load the number of arguments and setup pointer to the arguments. 435 // Load the number of arguments and setup pointer to the arguments.
420 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset)); 436 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
421 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset)); 437 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
422 438
423 // Copy arguments to the stack in a loop. 439 // Copy arguments to the stack in a loop.
424 Label loop, entry; 440 Label loop, entry;
425 __ Set(ecx, Immediate(0)); 441 __ Set(ecx, Immediate(0));
426 __ jmp(&entry); 442 __ jmp(&entry);
427 __ bind(&loop); 443 __ bind(&loop);
428 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv 444 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
429 __ push(Operand(edx, 0)); // dereference handle 445 __ push(Operand(edx, 0)); // dereference handle
430 __ inc(Operand(ecx)); 446 __ inc(ecx);
431 __ bind(&entry); 447 __ bind(&entry);
432 __ cmp(ecx, Operand(eax)); 448 __ cmp(ecx, eax);
433 __ j(not_equal, &loop); 449 __ j(not_equal, &loop);
434 450
435 // Get the function from the stack and call it. 451 // Get the function from the stack and call it.
436 __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize)); // +1 ~ receiver 452 // kPointerSize for the receiver.
453 __ mov(edi, Operand(esp, eax, times_4, kPointerSize));
437 454
438 // Invoke the code. 455 // Invoke the code.
439 if (is_construct) { 456 if (is_construct) {
440 __ call(masm->isolate()->builtins()->JSConstructCall(), 457 __ call(masm->isolate()->builtins()->JSConstructCall(),
441 RelocInfo::CODE_TARGET); 458 RelocInfo::CODE_TARGET);
442 } else { 459 } else {
443 ParameterCount actual(eax); 460 ParameterCount actual(eax);
444 __ InvokeFunction(edi, actual, CALL_FUNCTION, 461 __ InvokeFunction(edi, actual, CALL_FUNCTION,
445 NullCallWrapper(), CALL_AS_METHOD); 462 NullCallWrapper(), CALL_AS_METHOD);
463 }
464
465 // Exit the internal frame. Notice that this also removes the empty.
466 // context and the function left on the stack by the code
467 // invocation.
446 } 468 }
447 469 __ ret(kPointerSize); // Remove receiver.
448 // Exit the JS frame. Notice that this also removes the empty
449 // context and the function left on the stack by the code
450 // invocation.
451 __ LeaveInternalFrame();
452 __ ret(1 * kPointerSize); // remove receiver
453 } 470 }
454 471
455 472
456 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { 473 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
457 Generate_JSEntryTrampolineHelper(masm, false); 474 Generate_JSEntryTrampolineHelper(masm, false);
458 } 475 }
459 476
460 477
461 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { 478 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
462 Generate_JSEntryTrampolineHelper(masm, true); 479 Generate_JSEntryTrampolineHelper(masm, true);
463 } 480 }
464 481
465 482
466 void Builtins::Generate_LazyCompile(MacroAssembler* masm) { 483 void Builtins::Generate_LazyCompile(MacroAssembler* masm) {
467 // Enter an internal frame. 484 {
468 __ EnterInternalFrame(); 485 FrameScope scope(masm, StackFrame::INTERNAL);
469 486
470 // Push a copy of the function. 487 // Push a copy of the function.
471 __ push(edi); 488 __ push(edi);
472 // Push call kind information. 489 // Push call kind information.
473 __ push(ecx); 490 __ push(ecx);
474 491
475 __ push(edi); // Function is also the parameter to the runtime call. 492 __ push(edi); // Function is also the parameter to the runtime call.
476 __ CallRuntime(Runtime::kLazyCompile, 1); 493 __ CallRuntime(Runtime::kLazyCompile, 1);
477 494
478 // Restore call kind information. 495 // Restore call kind information.
479 __ pop(ecx); 496 __ pop(ecx);
480 // Restore receiver. 497 // Restore receiver.
481 __ pop(edi); 498 __ pop(edi);
482 499
483 // Tear down temporary frame. 500 // Tear down internal frame.
484 __ LeaveInternalFrame(); 501 }
485 502
486 // Do a tail-call of the compiled function. 503 // Do a tail-call of the compiled function.
487 __ lea(eax, FieldOperand(eax, Code::kHeaderSize)); 504 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
488 __ jmp(Operand(eax)); 505 __ jmp(eax);
489 } 506 }
490 507
491 508
492 void Builtins::Generate_LazyRecompile(MacroAssembler* masm) { 509 void Builtins::Generate_LazyRecompile(MacroAssembler* masm) {
493 // Enter an internal frame. 510 {
494 __ EnterInternalFrame(); 511 FrameScope scope(masm, StackFrame::INTERNAL);
495 512
496 // Push a copy of the function onto the stack. 513 // Push a copy of the function onto the stack.
497 __ push(edi); 514 __ push(edi);
498 // Push call kind information. 515 // Push call kind information.
499 __ push(ecx); 516 __ push(ecx);
500 517
501 __ push(edi); // Function is also the parameter to the runtime call. 518 __ push(edi); // Function is also the parameter to the runtime call.
502 __ CallRuntime(Runtime::kLazyRecompile, 1); 519 __ CallRuntime(Runtime::kLazyRecompile, 1);
503 520
504 // Restore call kind information. 521 // Restore call kind information.
505 __ pop(ecx); 522 __ pop(ecx);
506 // Restore receiver. 523 // Restore receiver.
507 __ pop(edi); 524 __ pop(edi);
508 525
509 // Tear down temporary frame. 526 // Tear down internal frame.
510 __ LeaveInternalFrame(); 527 }
511 528
512 // Do a tail-call of the compiled function. 529 // Do a tail-call of the compiled function.
513 __ lea(eax, FieldOperand(eax, Code::kHeaderSize)); 530 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
514 __ jmp(Operand(eax)); 531 __ jmp(eax);
515 } 532 }
516 533
517 534
518 static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm, 535 static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
519 Deoptimizer::BailoutType type) { 536 Deoptimizer::BailoutType type) {
520 // Enter an internal frame. 537 {
521 __ EnterInternalFrame(); 538 FrameScope scope(masm, StackFrame::INTERNAL);
522 539
523 // Pass the function and deoptimization type to the runtime system. 540 // Pass the function and deoptimization type to the runtime system.
524 __ push(Immediate(Smi::FromInt(static_cast<int>(type)))); 541 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
525 __ CallRuntime(Runtime::kNotifyDeoptimized, 1); 542 __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
526 543
527 // Tear down temporary frame. 544 // Tear down internal frame.
528 __ LeaveInternalFrame(); 545 }
529 546
530 // Get the full codegen state from the stack and untag it. 547 // Get the full codegen state from the stack and untag it.
531 __ mov(ecx, Operand(esp, 1 * kPointerSize)); 548 __ mov(ecx, Operand(esp, 1 * kPointerSize));
532 __ SmiUntag(ecx); 549 __ SmiUntag(ecx);
533 550
534 // Switch on the state. 551 // Switch on the state.
535 Label not_no_registers, not_tos_eax; 552 Label not_no_registers, not_tos_eax;
536 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS); 553 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
537 __ j(not_equal, &not_no_registers, Label::kNear); 554 __ j(not_equal, &not_no_registers, Label::kNear);
538 __ ret(1 * kPointerSize); // Remove state. 555 __ ret(1 * kPointerSize); // Remove state.
(...skipping 20 matching lines...) Expand all
559 576
560 577
561 void Builtins::Generate_NotifyOSR(MacroAssembler* masm) { 578 void Builtins::Generate_NotifyOSR(MacroAssembler* masm) {
562 // TODO(kasperl): Do we need to save/restore the XMM registers too? 579 // TODO(kasperl): Do we need to save/restore the XMM registers too?
563 580
564 // For now, we are relying on the fact that Runtime::NotifyOSR 581 // For now, we are relying on the fact that Runtime::NotifyOSR
565 // doesn't do any garbage collection which allows us to save/restore 582 // doesn't do any garbage collection which allows us to save/restore
566 // the registers without worrying about which of them contain 583 // the registers without worrying about which of them contain
567 // pointers. This seems a bit fragile. 584 // pointers. This seems a bit fragile.
568 __ pushad(); 585 __ pushad();
569 __ EnterInternalFrame(); 586 {
570 __ CallRuntime(Runtime::kNotifyOSR, 0); 587 FrameScope scope(masm, StackFrame::INTERNAL);
571 __ LeaveInternalFrame(); 588 __ CallRuntime(Runtime::kNotifyOSR, 0);
589 }
572 __ popad(); 590 __ popad();
573 __ ret(0); 591 __ ret(0);
574 } 592 }
575 593
576 594
577 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { 595 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
578 Factory* factory = masm->isolate()->factory(); 596 Factory* factory = masm->isolate()->factory();
579 597
580 // 1. Make sure we have at least one argument. 598 // 1. Make sure we have at least one argument.
581 { Label done; 599 { Label done;
582 __ test(eax, Operand(eax)); 600 __ test(eax, eax);
583 __ j(not_zero, &done); 601 __ j(not_zero, &done);
584 __ pop(ebx); 602 __ pop(ebx);
585 __ push(Immediate(factory->undefined_value())); 603 __ push(Immediate(factory->undefined_value()));
586 __ push(ebx); 604 __ push(ebx);
587 __ inc(eax); 605 __ inc(eax);
588 __ bind(&done); 606 __ bind(&done);
589 } 607 }
590 608
591 // 2. Get the function to call (passed as receiver) from the stack, check 609 // 2. Get the function to call (passed as receiver) from the stack, check
592 // if it is a function. 610 // if it is a function.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
624 __ JumpIfSmi(ebx, &convert_to_object); 642 __ JumpIfSmi(ebx, &convert_to_object);
625 __ cmp(ebx, factory->null_value()); 643 __ cmp(ebx, factory->null_value());
626 __ j(equal, &use_global_receiver); 644 __ j(equal, &use_global_receiver);
627 __ cmp(ebx, factory->undefined_value()); 645 __ cmp(ebx, factory->undefined_value());
628 __ j(equal, &use_global_receiver); 646 __ j(equal, &use_global_receiver);
629 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); 647 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
630 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx); 648 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
631 __ j(above_equal, &shift_arguments); 649 __ j(above_equal, &shift_arguments);
632 650
633 __ bind(&convert_to_object); 651 __ bind(&convert_to_object);
634 __ EnterInternalFrame(); // In order to preserve argument count.
635 __ SmiTag(eax);
636 __ push(eax);
637 652
638 __ push(ebx); 653 { // In order to preserve argument count.
639 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 654 FrameScope scope(masm, StackFrame::INTERNAL);
640 __ mov(ebx, eax); 655 __ SmiTag(eax);
641 __ Set(edx, Immediate(0)); // restore 656 __ push(eax);
642 657
643 __ pop(eax); 658 __ push(ebx);
644 __ SmiUntag(eax); 659 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
645 __ LeaveInternalFrame(); 660 __ mov(ebx, eax);
661 __ Set(edx, Immediate(0)); // restore
662
663 __ pop(eax);
664 __ SmiUntag(eax);
665 }
666
646 // Restore the function to edi. 667 // Restore the function to edi.
647 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); 668 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
648 __ jmp(&patch_receiver); 669 __ jmp(&patch_receiver);
649 670
650 // Use the global receiver object from the called function as the 671 // Use the global receiver object from the called function as the
651 // receiver. 672 // receiver.
652 __ bind(&use_global_receiver); 673 __ bind(&use_global_receiver);
653 const int kGlobalIndex = 674 const int kGlobalIndex =
654 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; 675 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
655 __ mov(ebx, FieldOperand(esi, kGlobalIndex)); 676 __ mov(ebx, FieldOperand(esi, kGlobalIndex));
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
688 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); 709 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
689 __ dec(ecx); 710 __ dec(ecx);
690 __ j(not_sign, &loop); // While non-negative (to copy return address). 711 __ j(not_sign, &loop); // While non-negative (to copy return address).
691 __ pop(ebx); // Discard copy of return address. 712 __ pop(ebx); // Discard copy of return address.
692 __ dec(eax); // One fewer argument (first argument is new receiver). 713 __ dec(eax); // One fewer argument (first argument is new receiver).
693 } 714 }
694 715
695 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin, 716 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
696 // or a function proxy via CALL_FUNCTION_PROXY. 717 // or a function proxy via CALL_FUNCTION_PROXY.
697 { Label function, non_proxy; 718 { Label function, non_proxy;
698 __ test(edx, Operand(edx)); 719 __ test(edx, edx);
699 __ j(zero, &function); 720 __ j(zero, &function);
700 __ Set(ebx, Immediate(0)); 721 __ Set(ebx, Immediate(0));
701 __ SetCallKind(ecx, CALL_AS_METHOD); 722 __ SetCallKind(ecx, CALL_AS_METHOD);
702 __ cmp(Operand(edx), Immediate(1)); 723 __ cmp(edx, Immediate(1));
703 __ j(not_equal, &non_proxy); 724 __ j(not_equal, &non_proxy);
704 725
705 __ pop(edx); // return address 726 __ pop(edx); // return address
706 __ push(edi); // re-add proxy object as additional argument 727 __ push(edi); // re-add proxy object as additional argument
707 __ push(edx); 728 __ push(edx);
708 __ inc(eax); 729 __ inc(eax);
709 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY); 730 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
710 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), 731 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
711 RelocInfo::CODE_TARGET); 732 RelocInfo::CODE_TARGET);
712 733
713 __ bind(&non_proxy); 734 __ bind(&non_proxy);
714 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); 735 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
715 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), 736 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
716 RelocInfo::CODE_TARGET); 737 RelocInfo::CODE_TARGET);
717 __ bind(&function); 738 __ bind(&function);
718 } 739 }
719 740
720 // 5b. Get the code to call from the function and check that the number of 741 // 5b. Get the code to call from the function and check that the number of
721 // expected arguments matches what we're providing. If so, jump 742 // expected arguments matches what we're providing. If so, jump
722 // (tail-call) to the code in register edx without checking arguments. 743 // (tail-call) to the code in register edx without checking arguments.
723 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 744 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
724 __ mov(ebx, 745 __ mov(ebx,
725 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); 746 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
726 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset)); 747 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
727 __ SmiUntag(ebx); 748 __ SmiUntag(ebx);
728 __ SetCallKind(ecx, CALL_AS_METHOD); 749 __ SetCallKind(ecx, CALL_AS_METHOD);
729 __ cmp(eax, Operand(ebx)); 750 __ cmp(eax, ebx);
730 __ j(not_equal, 751 __ j(not_equal,
731 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline()); 752 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline());
732 753
733 ParameterCount expected(0); 754 ParameterCount expected(0);
734 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION, 755 __ InvokeCode(edx, expected, expected, JUMP_FUNCTION, NullCallWrapper(),
735 NullCallWrapper(), CALL_AS_METHOD); 756 CALL_AS_METHOD);
736 } 757 }
737 758
738 759
739 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { 760 void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
740 static const int kArgumentsOffset = 2 * kPointerSize; 761 static const int kArgumentsOffset = 2 * kPointerSize;
741 static const int kReceiverOffset = 3 * kPointerSize; 762 static const int kReceiverOffset = 3 * kPointerSize;
742 static const int kFunctionOffset = 4 * kPointerSize; 763 static const int kFunctionOffset = 4 * kPointerSize;
764 {
765 FrameScope frame_scope(masm, StackFrame::INTERNAL);
743 766
744 __ EnterInternalFrame(); 767 __ push(Operand(ebp, kFunctionOffset)); // push this
768 __ push(Operand(ebp, kArgumentsOffset)); // push arguments
769 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
745 770
746 __ push(Operand(ebp, kFunctionOffset)); // push this 771 // Check the stack for overflow. We are not trying to catch
747 __ push(Operand(ebp, kArgumentsOffset)); // push arguments 772 // interruptions (e.g. debug break and preemption) here, so the "real stack
748 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); 773 // limit" is checked.
774 Label okay;
775 ExternalReference real_stack_limit =
776 ExternalReference::address_of_real_stack_limit(masm->isolate());
777 __ mov(edi, Operand::StaticVariable(real_stack_limit));
778 // Make ecx the space we have left. The stack might already be overflowed
779 // here which will cause ecx to become negative.
780 __ mov(ecx, esp);
781 __ sub(ecx, edi);
782 // Make edx the space we need for the array when it is unrolled onto the
783 // stack.
784 __ mov(edx, eax);
785 __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
786 // Check if the arguments will overflow the stack.
787 __ cmp(ecx, edx);
788 __ j(greater, &okay); // Signed comparison.
749 789
750 // Check the stack for overflow. We are not trying to catch 790 // Out of stack space.
751 // interruptions (e.g. debug break and preemption) here, so the "real stack 791 __ push(Operand(ebp, 4 * kPointerSize)); // push this
752 // limit" is checked. 792 __ push(eax);
753 Label okay; 793 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
754 ExternalReference real_stack_limit = 794 __ bind(&okay);
755 ExternalReference::address_of_real_stack_limit(masm->isolate()); 795 // End of stack check.
756 __ mov(edi, Operand::StaticVariable(real_stack_limit));
757 // Make ecx the space we have left. The stack might already be overflowed
758 // here which will cause ecx to become negative.
759 __ mov(ecx, Operand(esp));
760 __ sub(ecx, Operand(edi));
761 // Make edx the space we need for the array when it is unrolled onto the
762 // stack.
763 __ mov(edx, Operand(eax));
764 __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
765 // Check if the arguments will overflow the stack.
766 __ cmp(ecx, Operand(edx));
767 __ j(greater, &okay); // Signed comparison.
768 796
769 // Out of stack space. 797 // Push current index and limit.
770 __ push(Operand(ebp, 4 * kPointerSize)); // push this 798 const int kLimitOffset =
771 __ push(eax); 799 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
772 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION); 800 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
773 __ bind(&okay); 801 __ push(eax); // limit
774 // End of stack check. 802 __ push(Immediate(0)); // index
775 803
776 // Push current index and limit. 804 // Get the receiver.
777 const int kLimitOffset = 805 __ mov(ebx, Operand(ebp, kReceiverOffset));
778 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
779 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
780 __ push(eax); // limit
781 __ push(Immediate(0)); // index
782 806
783 // Get the receiver. 807 // Check that the function is a JS function (otherwise it must be a proxy).
784 __ mov(ebx, Operand(ebp, kReceiverOffset)); 808 Label push_receiver;
809 __ mov(edi, Operand(ebp, kFunctionOffset));
810 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
811 __ j(not_equal, &push_receiver);
785 812
786 // Check that the function is a JS function (otherwise it must be a proxy). 813 // Change context eagerly to get the right global object if necessary.
787 Label push_receiver; 814 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
788 __ mov(edi, Operand(ebp, kFunctionOffset));
789 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
790 __ j(not_equal, &push_receiver);
791 815
792 // Change context eagerly to get the right global object if necessary. 816 // Compute the receiver.
793 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 817 // Do not transform the receiver for strict mode functions.
818 Label call_to_object, use_global_receiver;
819 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
820 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
821 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
822 __ j(not_equal, &push_receiver);
794 823
795 // Compute the receiver. 824 Factory* factory = masm->isolate()->factory();
796 // Do not transform the receiver for strict mode functions.
797 Label call_to_object, use_global_receiver;
798 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
799 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
800 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
801 __ j(not_equal, &push_receiver);
802 825
803 Factory* factory = masm->isolate()->factory(); 826 // Do not transform the receiver for natives (shared already in ecx).
827 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
828 1 << SharedFunctionInfo::kNativeBitWithinByte);
829 __ j(not_equal, &push_receiver);
804 830
805 // Do not transform the receiver for natives (shared already in ecx). 831 // Compute the receiver in non-strict mode.
806 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset), 832 // Call ToObject on the receiver if it is not an object, or use the
807 1 << SharedFunctionInfo::kNativeBitWithinByte); 833 // global object if it is null or undefined.
808 __ j(not_equal, &push_receiver); 834 __ JumpIfSmi(ebx, &call_to_object);
835 __ cmp(ebx, factory->null_value());
836 __ j(equal, &use_global_receiver);
837 __ cmp(ebx, factory->undefined_value());
838 __ j(equal, &use_global_receiver);
839 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
840 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
841 __ j(above_equal, &push_receiver);
809 842
810 // Compute the receiver in non-strict mode. 843 __ bind(&call_to_object);
811 // Call ToObject on the receiver if it is not an object, or use the 844 __ push(ebx);
812 // global object if it is null or undefined. 845 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
813 __ JumpIfSmi(ebx, &call_to_object); 846 __ mov(ebx, eax);
814 __ cmp(ebx, factory->null_value()); 847 __ jmp(&push_receiver);
815 __ j(equal, &use_global_receiver);
816 __ cmp(ebx, factory->undefined_value());
817 __ j(equal, &use_global_receiver);
818 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
819 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
820 __ j(above_equal, &push_receiver);
821 848
822 __ bind(&call_to_object); 849 // Use the current global receiver object as the receiver.
823 __ push(ebx); 850 __ bind(&use_global_receiver);
824 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 851 const int kGlobalOffset =
825 __ mov(ebx, Operand(eax)); 852 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
826 __ jmp(&push_receiver); 853 __ mov(ebx, FieldOperand(esi, kGlobalOffset));
854 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset));
855 __ mov(ebx, FieldOperand(ebx, kGlobalOffset));
856 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
827 857
828 // Use the current global receiver object as the receiver. 858 // Push the receiver.
829 __ bind(&use_global_receiver); 859 __ bind(&push_receiver);
830 const int kGlobalOffset = 860 __ push(ebx);
831 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
832 __ mov(ebx, FieldOperand(esi, kGlobalOffset));
833 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset));
834 __ mov(ebx, FieldOperand(ebx, kGlobalOffset));
835 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
836 861
837 // Push the receiver. 862 // Copy all arguments from the array to the stack.
838 __ bind(&push_receiver); 863 Label entry, loop;
839 __ push(ebx); 864 __ mov(eax, Operand(ebp, kIndexOffset));
865 __ jmp(&entry);
866 __ bind(&loop);
867 __ mov(edx, Operand(ebp, kArgumentsOffset)); // load arguments
840 868
841 // Copy all arguments from the array to the stack. 869 // Use inline caching to speed up access to arguments.
842 Label entry, loop; 870 Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
843 __ mov(eax, Operand(ebp, kIndexOffset)); 871 __ call(ic, RelocInfo::CODE_TARGET);
844 __ jmp(&entry); 872 // It is important that we do not have a test instruction after the
845 __ bind(&loop); 873 // call. A test instruction after the call is used to indicate that
846 __ mov(edx, Operand(ebp, kArgumentsOffset)); // load arguments 874 // we have generated an inline version of the keyed load. In this
875 // case, we know that we are not generating a test instruction next.
847 876
848 // Use inline caching to speed up access to arguments. 877 // Push the nth argument.
849 Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize(); 878 __ push(eax);
850 __ call(ic, RelocInfo::CODE_TARGET);
851 // It is important that we do not have a test instruction after the
852 // call. A test instruction after the call is used to indicate that
853 // we have generated an inline version of the keyed load. In this
854 // case, we know that we are not generating a test instruction next.
855 879
856 // Push the nth argument. 880 // Update the index on the stack and in register eax.
857 __ push(eax); 881 __ mov(eax, Operand(ebp, kIndexOffset));
882 __ add(eax, Immediate(1 << kSmiTagSize));
883 __ mov(Operand(ebp, kIndexOffset), eax);
858 884
859 // Update the index on the stack and in register eax. 885 __ bind(&entry);
860 __ mov(eax, Operand(ebp, kIndexOffset)); 886 __ cmp(eax, Operand(ebp, kLimitOffset));
861 __ add(Operand(eax), Immediate(1 << kSmiTagSize)); 887 __ j(not_equal, &loop);
862 __ mov(Operand(ebp, kIndexOffset), eax);
863 888
864 __ bind(&entry); 889 // Invoke the function.
865 __ cmp(eax, Operand(ebp, kLimitOffset)); 890 Label call_proxy;
866 __ j(not_equal, &loop); 891 ParameterCount actual(eax);
892 __ SmiUntag(eax);
893 __ mov(edi, Operand(ebp, kFunctionOffset));
894 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
895 __ j(not_equal, &call_proxy);
896 __ InvokeFunction(edi, actual, CALL_FUNCTION,
897 NullCallWrapper(), CALL_AS_METHOD);
867 898
868 // Invoke the function. 899 frame_scope.GenerateLeaveFrame();
869 Label call_proxy; 900 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
870 ParameterCount actual(eax);
871 __ SmiUntag(eax);
872 __ mov(edi, Operand(ebp, kFunctionOffset));
873 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
874 __ j(not_equal, &call_proxy);
875 __ InvokeFunction(edi, actual, CALL_FUNCTION,
876 NullCallWrapper(), CALL_AS_METHOD);
877 901
878 __ LeaveInternalFrame(); 902 // Invoke the function proxy.
879 __ ret(3 * kPointerSize); // remove this, receiver, and arguments 903 __ bind(&call_proxy);
904 __ push(edi); // add function proxy as last argument
905 __ inc(eax);
906 __ Set(ebx, Immediate(0));
907 __ SetCallKind(ecx, CALL_AS_METHOD);
908 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
909 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
910 RelocInfo::CODE_TARGET);
880 911
881 // Invoke the function proxy. 912 // Leave internal frame.
882 __ bind(&call_proxy); 913 }
883 __ push(edi); // add function proxy as last argument
884 __ inc(eax);
885 __ Set(ebx, Immediate(0));
886 __ SetCallKind(ecx, CALL_AS_METHOD);
887 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
888 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
889 RelocInfo::CODE_TARGET);
890
891 __ LeaveInternalFrame();
892 __ ret(3 * kPointerSize); // remove this, receiver, and arguments 914 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
893 } 915 }
894 916
895 917
896 // Number of empty elements to allocate for an empty array. 918 // Number of empty elements to allocate for an empty array.
897 static const int kPreallocatedArrayElements = 4; 919 static const int kPreallocatedArrayElements = 4;
898 920
899 921
900 // Allocate an empty JSArray. The allocated array is put into the result 922 // Allocate an empty JSArray. The allocated array is put into the result
901 // register. If the parameter initial_capacity is larger than zero an elements 923 // register. If the parameter initial_capacity is larger than zero an elements
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
976 for (int i = 0; i < initial_capacity; i++) { 998 for (int i = 0; i < initial_capacity; i++) {
977 __ mov(FieldOperand(scratch1, 999 __ mov(FieldOperand(scratch1,
978 FixedArray::kHeaderSize + i * kPointerSize), 1000 FixedArray::kHeaderSize + i * kPointerSize),
979 scratch3); 1001 scratch3);
980 } 1002 }
981 } else { 1003 } else {
982 Label loop, entry; 1004 Label loop, entry;
983 __ jmp(&entry); 1005 __ jmp(&entry);
984 __ bind(&loop); 1006 __ bind(&loop);
985 __ mov(Operand(scratch1, 0), factory->the_hole_value()); 1007 __ mov(Operand(scratch1, 0), factory->the_hole_value());
986 __ add(Operand(scratch1), Immediate(kPointerSize)); 1008 __ add(scratch1, Immediate(kPointerSize));
987 __ bind(&entry); 1009 __ bind(&entry);
988 __ cmp(scratch1, Operand(scratch2)); 1010 __ cmp(scratch1, scratch2);
989 __ j(below, &loop); 1011 __ j(below, &loop);
990 } 1012 }
991 } 1013 }
992 1014
993 1015
994 // Allocate a JSArray with the number of elements stored in a register. The 1016 // Allocate a JSArray with the number of elements stored in a register. The
995 // register array_function holds the built-in Array function and the register 1017 // register array_function holds the built-in Array function and the register
996 // array_size holds the size of the array as a smi. The allocated array is put 1018 // array_size holds the size of the array as a smi. The allocated array is put
997 // into the result register and beginning and end of the FixedArray elements 1019 // into the result register and beginning and end of the FixedArray elements
998 // storage is put into registers elements_array and elements_array_end (see 1020 // storage is put into registers elements_array and elements_array_end (see
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
1075 // words. 1097 // words.
1076 const int kRepStosThreshold = 16; 1098 const int kRepStosThreshold = 16;
1077 Label loop, entry, done; 1099 Label loop, entry, done;
1078 __ cmp(ecx, kRepStosThreshold); 1100 __ cmp(ecx, kRepStosThreshold);
1079 __ j(below, &loop); // Note: ecx > 0. 1101 __ j(below, &loop); // Note: ecx > 0.
1080 __ rep_stos(); 1102 __ rep_stos();
1081 __ jmp(&done); 1103 __ jmp(&done);
1082 __ bind(&loop); 1104 __ bind(&loop);
1083 __ stos(); 1105 __ stos();
1084 __ bind(&entry); 1106 __ bind(&entry);
1085 __ cmp(edi, Operand(elements_array_end)); 1107 __ cmp(edi, elements_array_end);
1086 __ j(below, &loop); 1108 __ j(below, &loop);
1087 __ bind(&done); 1109 __ bind(&done);
1088 } 1110 }
1089 } 1111 }
1090 1112
1091 1113
1092 // Create a new array for the built-in Array function. This function allocates 1114 // Create a new array for the built-in Array function. This function allocates
1093 // the JSArray object and the FixedArray elements array and initializes these. 1115 // the JSArray object and the FixedArray elements array and initializes these.
1094 // If the Array cannot be constructed in native code the runtime is called. This 1116 // If the Array cannot be constructed in native code the runtime is called. This
1095 // function assumes the following state: 1117 // function assumes the following state:
(...skipping 17 matching lines...) Expand all
1113 // be no garbage collection with this on the stack. 1135 // be no garbage collection with this on the stack.
1114 int push_count = 0; 1136 int push_count = 0;
1115 if (construct_call) { 1137 if (construct_call) {
1116 push_count++; 1138 push_count++;
1117 __ push(edi); 1139 __ push(edi);
1118 } 1140 }
1119 push_count++; 1141 push_count++;
1120 __ push(eax); 1142 __ push(eax);
1121 1143
1122 // Check for array construction with zero arguments. 1144 // Check for array construction with zero arguments.
1123 __ test(eax, Operand(eax)); 1145 __ test(eax, eax);
1124 __ j(not_zero, &argc_one_or_more); 1146 __ j(not_zero, &argc_one_or_more);
1125 1147
1126 __ bind(&empty_array); 1148 __ bind(&empty_array);
1127 // Handle construction of an empty array. 1149 // Handle construction of an empty array.
1128 AllocateEmptyJSArray(masm, 1150 AllocateEmptyJSArray(masm,
1129 edi, 1151 edi,
1130 eax, 1152 eax,
1131 ebx, 1153 ebx,
1132 ecx, 1154 ecx,
1133 edi, 1155 edi,
1134 kPreallocatedArrayElements, 1156 kPreallocatedArrayElements,
1135 &prepare_generic_code_call); 1157 &prepare_generic_code_call);
1136 __ IncrementCounter(masm->isolate()->counters()->array_function_native(), 1); 1158 __ IncrementCounter(masm->isolate()->counters()->array_function_native(), 1);
1137 __ pop(ebx); 1159 __ pop(ebx);
1138 if (construct_call) { 1160 if (construct_call) {
1139 __ pop(edi); 1161 __ pop(edi);
1140 } 1162 }
1141 __ ret(kPointerSize); 1163 __ ret(kPointerSize);
1142 1164
1143 // Check for one argument. Bail out if argument is not smi or if it is 1165 // Check for one argument. Bail out if argument is not smi or if it is
1144 // negative. 1166 // negative.
1145 __ bind(&argc_one_or_more); 1167 __ bind(&argc_one_or_more);
1146 __ cmp(eax, 1); 1168 __ cmp(eax, 1);
1147 __ j(not_equal, &argc_two_or_more); 1169 __ j(not_equal, &argc_two_or_more);
1148 STATIC_ASSERT(kSmiTag == 0); 1170 STATIC_ASSERT(kSmiTag == 0);
1149 __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize)); 1171 __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize));
1150 __ test(ecx, Operand(ecx)); 1172 __ test(ecx, ecx);
1151 __ j(not_zero, &not_empty_array); 1173 __ j(not_zero, &not_empty_array);
1152 1174
1153 // The single argument passed is zero, so we jump to the code above used to 1175 // The single argument passed is zero, so we jump to the code above used to
1154 // handle the case of no arguments passed. To adapt the stack for that we move 1176 // handle the case of no arguments passed. To adapt the stack for that we move
1155 // the return address and the pushed constructor (if pushed) one stack slot up 1177 // the return address and the pushed constructor (if pushed) one stack slot up
1156 // thereby removing the passed argument. Argc is also on the stack - at the 1178 // thereby removing the passed argument. Argc is also on the stack - at the
1157 // bottom - and it needs to be changed from 1 to 0 to have the call into the 1179 // bottom - and it needs to be changed from 1 to 0 to have the call into the
1158 // runtime system work in case a GC is required. 1180 // runtime system work in case a GC is required.
1159 for (int i = push_count; i > 0; i--) { 1181 for (int i = push_count; i > 0; i--) {
1160 __ mov(eax, Operand(esp, i * kPointerSize)); 1182 __ mov(eax, Operand(esp, i * kPointerSize));
1161 __ mov(Operand(esp, (i + 1) * kPointerSize), eax); 1183 __ mov(Operand(esp, (i + 1) * kPointerSize), eax);
1162 } 1184 }
1163 __ add(Operand(esp), Immediate(2 * kPointerSize)); // Drop two stack slots. 1185 __ add(esp, Immediate(2 * kPointerSize)); // Drop two stack slots.
1164 __ push(Immediate(0)); // Treat this as a call with argc of zero. 1186 __ push(Immediate(0)); // Treat this as a call with argc of zero.
1165 __ jmp(&empty_array); 1187 __ jmp(&empty_array);
1166 1188
1167 __ bind(&not_empty_array); 1189 __ bind(&not_empty_array);
1168 __ test(ecx, Immediate(kIntptrSignBit | kSmiTagMask)); 1190 __ test(ecx, Immediate(kIntptrSignBit | kSmiTagMask));
1169 __ j(not_zero, &prepare_generic_code_call); 1191 __ j(not_zero, &prepare_generic_code_call);
1170 1192
1171 // Handle construction of an empty array of a certain size. Get the size from 1193 // Handle construction of an empty array of a certain size. Get the size from
1172 // the stack and bail out if size is to large to actually allocate an elements 1194 // the stack and bail out if size is to large to actually allocate an elements
1173 // array. 1195 // array.
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
1243 // edi: location of the last argument 1265 // edi: location of the last argument
1244 // esp[0]: JSArray 1266 // esp[0]: JSArray
1245 // esp[4]: return address 1267 // esp[4]: return address
1246 // esp[8]: last argument 1268 // esp[8]: last argument
1247 Label loop, entry; 1269 Label loop, entry;
1248 __ mov(ecx, ebx); 1270 __ mov(ecx, ebx);
1249 __ jmp(&entry); 1271 __ jmp(&entry);
1250 __ bind(&loop); 1272 __ bind(&loop);
1251 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0)); 1273 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0));
1252 __ mov(Operand(edx, 0), eax); 1274 __ mov(Operand(edx, 0), eax);
1253 __ add(Operand(edx), Immediate(kPointerSize)); 1275 __ add(edx, Immediate(kPointerSize));
1254 __ bind(&entry); 1276 __ bind(&entry);
1255 __ dec(ecx); 1277 __ dec(ecx);
1256 __ j(greater_equal, &loop); 1278 __ j(greater_equal, &loop);
1257 1279
1258 // Remove caller arguments from the stack and return. 1280 // Remove caller arguments from the stack and return.
1259 // ebx: argc 1281 // ebx: argc
1260 // esp[0]: JSArray 1282 // esp[0]: JSArray
1261 // esp[4]: return address 1283 // esp[4]: return address
1262 // esp[8]: last argument 1284 // esp[8]: last argument
1263 __ pop(eax); 1285 __ pop(eax);
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
1349 // -- edi : constructor function 1371 // -- edi : constructor function
1350 // -- esp[0] : return address 1372 // -- esp[0] : return address
1351 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1373 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1352 // -- esp[(argc + 1) * 4] : receiver 1374 // -- esp[(argc + 1) * 4] : receiver
1353 // ----------------------------------- 1375 // -----------------------------------
1354 Counters* counters = masm->isolate()->counters(); 1376 Counters* counters = masm->isolate()->counters();
1355 __ IncrementCounter(counters->string_ctor_calls(), 1); 1377 __ IncrementCounter(counters->string_ctor_calls(), 1);
1356 1378
1357 if (FLAG_debug_code) { 1379 if (FLAG_debug_code) {
1358 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx); 1380 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
1359 __ cmp(edi, Operand(ecx)); 1381 __ cmp(edi, ecx);
1360 __ Assert(equal, "Unexpected String function"); 1382 __ Assert(equal, "Unexpected String function");
1361 } 1383 }
1362 1384
1363 // Load the first argument into eax and get rid of the rest 1385 // Load the first argument into eax and get rid of the rest
1364 // (including the receiver). 1386 // (including the receiver).
1365 Label no_arguments; 1387 Label no_arguments;
1366 __ test(eax, Operand(eax)); 1388 __ test(eax, eax);
1367 __ j(zero, &no_arguments); 1389 __ j(zero, &no_arguments);
1368 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0)); 1390 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1369 __ pop(ecx); 1391 __ pop(ecx);
1370 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); 1392 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1371 __ push(ecx); 1393 __ push(ecx);
1372 __ mov(eax, ebx); 1394 __ mov(eax, ebx);
1373 1395
1374 // Lookup the argument in the number to string cache. 1396 // Lookup the argument in the number to string cache.
1375 Label not_cached, argument_is_string; 1397 Label not_cached, argument_is_string;
1376 NumberToStringStub::GenerateLookupNumberStringCache( 1398 NumberToStringStub::GenerateLookupNumberStringCache(
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
1432 __ JumpIfSmi(eax, &convert_argument); 1454 __ JumpIfSmi(eax, &convert_argument);
1433 Condition is_string = masm->IsObjectStringType(eax, ebx, ecx); 1455 Condition is_string = masm->IsObjectStringType(eax, ebx, ecx);
1434 __ j(NegateCondition(is_string), &convert_argument); 1456 __ j(NegateCondition(is_string), &convert_argument);
1435 __ mov(ebx, eax); 1457 __ mov(ebx, eax);
1436 __ IncrementCounter(counters->string_ctor_string_value(), 1); 1458 __ IncrementCounter(counters->string_ctor_string_value(), 1);
1437 __ jmp(&argument_is_string); 1459 __ jmp(&argument_is_string);
1438 1460
1439 // Invoke the conversion builtin and put the result into ebx. 1461 // Invoke the conversion builtin and put the result into ebx.
1440 __ bind(&convert_argument); 1462 __ bind(&convert_argument);
1441 __ IncrementCounter(counters->string_ctor_conversions(), 1); 1463 __ IncrementCounter(counters->string_ctor_conversions(), 1);
1442 __ EnterInternalFrame(); 1464 {
1443 __ push(edi); // Preserve the function. 1465 FrameScope scope(masm, StackFrame::INTERNAL);
1444 __ push(eax); 1466 __ push(edi); // Preserve the function.
1445 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION); 1467 __ push(eax);
1446 __ pop(edi); 1468 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
1447 __ LeaveInternalFrame(); 1469 __ pop(edi);
1470 }
1448 __ mov(ebx, eax); 1471 __ mov(ebx, eax);
1449 __ jmp(&argument_is_string); 1472 __ jmp(&argument_is_string);
1450 1473
1451 // Load the empty string into ebx, remove the receiver from the 1474 // Load the empty string into ebx, remove the receiver from the
1452 // stack, and jump back to the case where the argument is a string. 1475 // stack, and jump back to the case where the argument is a string.
1453 __ bind(&no_arguments); 1476 __ bind(&no_arguments);
1454 __ Set(ebx, Immediate(factory->empty_string())); 1477 __ Set(ebx, Immediate(factory->empty_string()));
1455 __ pop(ecx); 1478 __ pop(ecx);
1456 __ lea(esp, Operand(esp, kPointerSize)); 1479 __ lea(esp, Operand(esp, kPointerSize));
1457 __ push(ecx); 1480 __ push(ecx);
1458 __ jmp(&argument_is_string); 1481 __ jmp(&argument_is_string);
1459 1482
1460 // At this point the argument is already a string. Call runtime to 1483 // At this point the argument is already a string. Call runtime to
1461 // create a string wrapper. 1484 // create a string wrapper.
1462 __ bind(&gc_required); 1485 __ bind(&gc_required);
1463 __ IncrementCounter(counters->string_ctor_gc_required(), 1); 1486 __ IncrementCounter(counters->string_ctor_gc_required(), 1);
1464 __ EnterInternalFrame(); 1487 {
1465 __ push(ebx); 1488 FrameScope scope(masm, StackFrame::INTERNAL);
1466 __ CallRuntime(Runtime::kNewStringWrapper, 1); 1489 __ push(ebx);
1467 __ LeaveInternalFrame(); 1490 __ CallRuntime(Runtime::kNewStringWrapper, 1);
1491 }
1468 __ ret(0); 1492 __ ret(0);
1469 } 1493 }
1470 1494
1471 1495
1472 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { 1496 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1473 __ push(ebp); 1497 __ push(ebp);
1474 __ mov(ebp, Operand(esp)); 1498 __ mov(ebp, esp);
1475 1499
1476 // Store the arguments adaptor context sentinel. 1500 // Store the arguments adaptor context sentinel.
1477 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 1501 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1478 1502
1479 // Push the function on the stack. 1503 // Push the function on the stack.
1480 __ push(edi); 1504 __ push(edi);
1481 1505
1482 // Preserve the number of arguments on the stack. Must preserve eax, 1506 // Preserve the number of arguments on the stack. Must preserve eax,
1483 // ebx and ecx because these registers are used when copying the 1507 // ebx and ecx because these registers are used when copying the
1484 // arguments and the receiver. 1508 // arguments and the receiver.
(...skipping 23 matching lines...) Expand all
1508 // -- eax : actual number of arguments 1532 // -- eax : actual number of arguments
1509 // -- ebx : expected number of arguments 1533 // -- ebx : expected number of arguments
1510 // -- ecx : call kind information 1534 // -- ecx : call kind information
1511 // -- edx : code entry to call 1535 // -- edx : code entry to call
1512 // ----------------------------------- 1536 // -----------------------------------
1513 1537
1514 Label invoke, dont_adapt_arguments; 1538 Label invoke, dont_adapt_arguments;
1515 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1); 1539 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
1516 1540
1517 Label enough, too_few; 1541 Label enough, too_few;
1518 __ cmp(eax, Operand(ebx)); 1542 __ cmp(eax, ebx);
1519 __ j(less, &too_few); 1543 __ j(less, &too_few);
1520 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel); 1544 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1521 __ j(equal, &dont_adapt_arguments); 1545 __ j(equal, &dont_adapt_arguments);
1522 1546
1523 { // Enough parameters: Actual >= expected. 1547 { // Enough parameters: Actual >= expected.
1524 __ bind(&enough); 1548 __ bind(&enough);
1525 EnterArgumentsAdaptorFrame(masm); 1549 EnterArgumentsAdaptorFrame(masm);
1526 1550
1527 // Copy receiver and all expected arguments. 1551 // Copy receiver and all expected arguments.
1528 const int offset = StandardFrameConstants::kCallerSPOffset; 1552 const int offset = StandardFrameConstants::kCallerSPOffset;
1529 __ lea(eax, Operand(ebp, eax, times_4, offset)); 1553 __ lea(eax, Operand(ebp, eax, times_4, offset));
1530 __ mov(edi, -1); // account for receiver 1554 __ mov(edi, -1); // account for receiver
1531 1555
1532 Label copy; 1556 Label copy;
1533 __ bind(&copy); 1557 __ bind(&copy);
1534 __ inc(edi); 1558 __ inc(edi);
1535 __ push(Operand(eax, 0)); 1559 __ push(Operand(eax, 0));
1536 __ sub(Operand(eax), Immediate(kPointerSize)); 1560 __ sub(eax, Immediate(kPointerSize));
1537 __ cmp(edi, Operand(ebx)); 1561 __ cmp(edi, ebx);
1538 __ j(less, &copy); 1562 __ j(less, &copy);
1539 __ jmp(&invoke); 1563 __ jmp(&invoke);
1540 } 1564 }
1541 1565
1542 { // Too few parameters: Actual < expected. 1566 { // Too few parameters: Actual < expected.
1543 __ bind(&too_few); 1567 __ bind(&too_few);
1544 EnterArgumentsAdaptorFrame(masm); 1568 EnterArgumentsAdaptorFrame(masm);
1545 1569
1546 // Copy receiver and all actual arguments. 1570 // Copy receiver and all actual arguments.
1547 const int offset = StandardFrameConstants::kCallerSPOffset; 1571 const int offset = StandardFrameConstants::kCallerSPOffset;
1548 __ lea(edi, Operand(ebp, eax, times_4, offset)); 1572 __ lea(edi, Operand(ebp, eax, times_4, offset));
1549 // ebx = expected - actual. 1573 // ebx = expected - actual.
1550 __ sub(ebx, Operand(eax)); 1574 __ sub(ebx, eax);
1551 // eax = -actual - 1 1575 // eax = -actual - 1
1552 __ neg(eax); 1576 __ neg(eax);
1553 __ sub(Operand(eax), Immediate(1)); 1577 __ sub(eax, Immediate(1));
1554 1578
1555 Label copy; 1579 Label copy;
1556 __ bind(&copy); 1580 __ bind(&copy);
1557 __ inc(eax); 1581 __ inc(eax);
1558 __ push(Operand(edi, 0)); 1582 __ push(Operand(edi, 0));
1559 __ sub(Operand(edi), Immediate(kPointerSize)); 1583 __ sub(edi, Immediate(kPointerSize));
1560 __ test(eax, Operand(eax)); 1584 __ test(eax, eax);
1561 __ j(not_zero, &copy); 1585 __ j(not_zero, &copy);
1562 1586
1563 // Fill remaining expected arguments with undefined values. 1587 // Fill remaining expected arguments with undefined values.
1564 Label fill; 1588 Label fill;
1565 __ bind(&fill); 1589 __ bind(&fill);
1566 __ inc(eax); 1590 __ inc(eax);
1567 __ push(Immediate(masm->isolate()->factory()->undefined_value())); 1591 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
1568 __ cmp(eax, Operand(ebx)); 1592 __ cmp(eax, ebx);
1569 __ j(less, &fill); 1593 __ j(less, &fill);
1570 } 1594 }
1571 1595
1572 // Call the entry point. 1596 // Call the entry point.
1573 __ bind(&invoke); 1597 __ bind(&invoke);
1574 // Restore function pointer. 1598 // Restore function pointer.
1575 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 1599 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1576 __ call(Operand(edx)); 1600 __ call(edx);
1577 1601
1578 // Leave frame and return. 1602 // Leave frame and return.
1579 LeaveArgumentsAdaptorFrame(masm); 1603 LeaveArgumentsAdaptorFrame(masm);
1580 __ ret(0); 1604 __ ret(0);
1581 1605
1582 // ------------------------------------------- 1606 // -------------------------------------------
1583 // Dont adapt arguments. 1607 // Dont adapt arguments.
1584 // ------------------------------------------- 1608 // -------------------------------------------
1585 __ bind(&dont_adapt_arguments); 1609 __ bind(&dont_adapt_arguments);
1586 __ jmp(Operand(edx)); 1610 __ jmp(edx);
1587 } 1611 }
1588 1612
1589 1613
1590 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) { 1614 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
1591 CpuFeatures::TryForceFeatureScope scope(SSE2); 1615 CpuFeatures::TryForceFeatureScope scope(SSE2);
1592 if (!CpuFeatures::IsSupported(SSE2)) { 1616 if (!CpuFeatures::IsSupported(SSE2) && FLAG_debug_code) {
1593 __ Abort("Unreachable code: Cannot optimize without SSE2 support."); 1617 __ Abort("Unreachable code: Cannot optimize without SSE2 support.");
1594 return; 1618 return;
1595 } 1619 }
1596 1620
1597 // Get the loop depth of the stack guard check. This is recorded in 1621 // Get the loop depth of the stack guard check. This is recorded in
1598 // a test(eax, depth) instruction right after the call. 1622 // a test(eax, depth) instruction right after the call.
1599 Label stack_check; 1623 Label stack_check;
1600 __ mov(ebx, Operand(esp, 0)); // return address 1624 __ mov(ebx, Operand(esp, 0)); // return address
1601 if (FLAG_debug_code) { 1625 if (FLAG_debug_code) {
1602 __ cmpb(Operand(ebx, 0), Assembler::kTestAlByte); 1626 __ cmpb(Operand(ebx, 0), Assembler::kTestAlByte);
1603 __ Assert(equal, "test eax instruction not found after loop stack check"); 1627 __ Assert(equal, "test eax instruction not found after loop stack check");
1604 } 1628 }
1605 __ movzx_b(ebx, Operand(ebx, 1)); // depth 1629 __ movzx_b(ebx, Operand(ebx, 1)); // depth
1606 1630
1607 // Get the loop nesting level at which we allow OSR from the 1631 // Get the loop nesting level at which we allow OSR from the
1608 // unoptimized code and check if we want to do OSR yet. If not we 1632 // unoptimized code and check if we want to do OSR yet. If not we
1609 // should perform a stack guard check so we can get interrupts while 1633 // should perform a stack guard check so we can get interrupts while
1610 // waiting for on-stack replacement. 1634 // waiting for on-stack replacement.
1611 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 1635 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1612 __ mov(ecx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); 1636 __ mov(ecx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
1613 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kCodeOffset)); 1637 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kCodeOffset));
1614 __ cmpb(ebx, FieldOperand(ecx, Code::kAllowOSRAtLoopNestingLevelOffset)); 1638 __ cmpb(ebx, FieldOperand(ecx, Code::kAllowOSRAtLoopNestingLevelOffset));
1615 __ j(greater, &stack_check); 1639 __ j(greater, &stack_check);
1616 1640
1617 // Pass the function to optimize as the argument to the on-stack 1641 // Pass the function to optimize as the argument to the on-stack
1618 // replacement runtime function. 1642 // replacement runtime function.
1619 __ EnterInternalFrame(); 1643 {
1620 __ push(eax); 1644 FrameScope scope(masm, StackFrame::INTERNAL);
1621 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1); 1645 __ push(eax);
1622 __ LeaveInternalFrame(); 1646 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
1647 }
1623 1648
1624 // If the result was -1 it means that we couldn't optimize the 1649 // If the result was -1 it means that we couldn't optimize the
1625 // function. Just return and continue in the unoptimized version. 1650 // function. Just return and continue in the unoptimized version.
1626 Label skip; 1651 Label skip;
1627 __ cmp(Operand(eax), Immediate(Smi::FromInt(-1))); 1652 __ cmp(eax, Immediate(Smi::FromInt(-1)));
1628 __ j(not_equal, &skip, Label::kNear); 1653 __ j(not_equal, &skip, Label::kNear);
1629 __ ret(0); 1654 __ ret(0);
1630 1655
1631 // If we decide not to perform on-stack replacement we perform a 1656 // If we decide not to perform on-stack replacement we perform a
1632 // stack guard check to enable interrupts. 1657 // stack guard check to enable interrupts.
1633 __ bind(&stack_check); 1658 __ bind(&stack_check);
1634 Label ok; 1659 Label ok;
1635 ExternalReference stack_limit = 1660 ExternalReference stack_limit =
1636 ExternalReference::address_of_stack_limit(masm->isolate()); 1661 ExternalReference::address_of_stack_limit(masm->isolate());
1637 __ cmp(esp, Operand::StaticVariable(stack_limit)); 1662 __ cmp(esp, Operand::StaticVariable(stack_limit));
1638 __ j(above_equal, &ok, Label::kNear); 1663 __ j(above_equal, &ok, Label::kNear);
1639 StackCheckStub stub; 1664 StackCheckStub stub;
1640 __ TailCallStub(&stub); 1665 __ TailCallStub(&stub);
1641 __ Abort("Unreachable code: returned from tail call."); 1666 if (FLAG_debug_code) {
1667 __ Abort("Unreachable code: returned from tail call.");
1668 }
1642 __ bind(&ok); 1669 __ bind(&ok);
1643 __ ret(0); 1670 __ ret(0);
1644 1671
1645 __ bind(&skip); 1672 __ bind(&skip);
1646 // Untag the AST id and push it on the stack. 1673 // Untag the AST id and push it on the stack.
1647 __ SmiUntag(eax); 1674 __ SmiUntag(eax);
1648 __ push(eax); 1675 __ push(eax);
1649 1676
1650 // Generate the code for doing the frame-to-frame translation using 1677 // Generate the code for doing the frame-to-frame translation using
1651 // the deoptimizer infrastructure. 1678 // the deoptimizer infrastructure.
1652 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR); 1679 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR);
1653 generator.Generate(); 1680 generator.Generate();
1654 } 1681 }
1655 1682
1656 1683
1657 #undef __ 1684 #undef __
1658 } 1685 }
1659 } // namespace v8::internal 1686 } // namespace v8::internal
1660 1687
1661 #endif // V8_TARGET_ARCH_IA32 1688 #endif // V8_TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « src/ia32/assembler-ia32-inl.h ('k') | src/ia32/code-stubs-ia32.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698